From a2c88ff1875a2039c987c1099e6d911f1b6dfce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 18 Mar 2010 11:18:11 +0100 Subject: sys_core_inline: Don't generated multiple compiler_generated annos Multiple compiler_generated annotations are harmless, but makes listing files harder to read during debugging. --- lib/compiler/src/sys_core_inline.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/compiler/src/sys_core_inline.erl b/lib/compiler/src/sys_core_inline.erl index c8d75b80c6..06696e5950 100644 --- a/lib/compiler/src/sys_core_inline.erl +++ b/lib/compiler/src/sys_core_inline.erl @@ -201,7 +201,7 @@ kill_id_anns(Body) -> (Expr) -> %% Mark everything as compiler generated to suppress %% bogus warnings. - A = [compiler_generated|core_lib:get_anno(Expr)], + A = compiler_generated(core_lib:get_anno(Expr)), core_lib:set_anno(Expr, A) end, Body). @@ -210,3 +210,8 @@ kill_id_anns_1([{'id',_}|As]) -> kill_id_anns_1([A|As]) -> [A|kill_id_anns_1(As)]; kill_id_anns_1([]) -> []. + +compiler_generated([compiler_generated|_]=Anno) -> + Anno; +compiler_generated(Anno) -> + [compiler_generated|Anno -- [compiler_generated]]. -- cgit v1.2.3 From e2074da57e6dd9b68a39ae71771b28c8f704196f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 17 Mar 2010 16:04:52 +0100 Subject: compiler: Fix binary matching bug in the inliner The inliner incorrectly assumes that a literal cannot match a binary in code such as: t() -> bc(<<"string">>). bc(<>) -> [A|bc(T)]; bc(<<>>) -> []. The bug was introduced when binary literals were introduced. --- lib/compiler/src/cerl_clauses.erl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/compiler/src/cerl_clauses.erl b/lib/compiler/src/cerl_clauses.erl index 5f111a5e05..bb0f998931 100644 --- a/lib/compiler/src/cerl_clauses.erl +++ b/lib/compiler/src/cerl_clauses.erl @@ -338,10 +338,19 @@ match(P, E, Bs) -> if E =:= any -> {false, Bs}; true -> - case is_data(E) of - true -> + case type(E) of + literal -> + case is_bitstring(concrete(E)) of + false -> + none; + true -> + {false, Bs} + end; + cons -> none; - false -> + tuple -> + none; + _ -> {false, Bs} end end; -- cgit v1.2.3 From 57cb16f84fd21443d3ad9951473f1e0960c6a26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 17 Mar 2010 16:09:48 +0100 Subject: compiler: Suppress bs_context_to_binary/1 for a literal operand The inliner can cause illegal uses of the bs_context_to_binary/1 instruction, such as: bs_context_to_binary {literal,"string"} or bs_context_to_binary {integer,1} Remove the bs_context_to_binary/1 instruction if the operand is not a register (it is clearly not needed). --- lib/compiler/src/v3_codegen.erl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index 1f05b4f6b4..948937c438 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -1190,7 +1190,12 @@ trap_bif(_, _, _) -> false. bif_cg(bs_context_to_binary=Instr, [Src0], [], Le, Vdb, Bef, St0) -> [Src] = cg_reg_args([Src0], Bef), - {[{Instr,Src}],clear_dead(Bef, Le#l.i, Vdb), St0}; + case is_register(Src) of + false -> + {[],clear_dead(Bef, Le#l.i, Vdb), St0}; + true -> + {[{Instr,Src}],clear_dead(Bef, Le#l.i, Vdb), St0} + end; bif_cg(dsetelement, [Index0,Tuple0,New0], _Rs, Le, Vdb, Bef, St0) -> [New,Tuple,{integer,Index1}] = cg_reg_args([New0,Tuple0,Index0], Bef), Index = Index1-1, @@ -2019,6 +2024,10 @@ fetch_stack(V, [_|Stk], I) -> fetch_stack(V, Stk, I+1). on_stack(V, Stk) -> keymember(V, 1, Stk). +is_register({x,_}) -> true; +is_register({yy,_}) -> true; +is_register(_) -> false. + %% put_catch(CatchTag, Stack) -> Stack' %% drop_catch(CatchTag, Stack) -> Stack' %% Special interface for putting and removing catch tags, to ensure that -- cgit v1.2.3 From e74235df989995f5bd2b66b7102857446ff10d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 17 Mar 2010 16:02:18 +0100 Subject: compiler tests: Test the 'inline' option better Clone some test suites and compile them with the 'inline' option to test inlining more thorughly. --- .gitignore | 1 + lib/compiler/test/Makefile | 26 ++++++++++++++++++++++++-- lib/compiler/test/test_lib.erl | 4 +++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 556114d488..c10a1aa73b 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,7 @@ a.out.dSYM/ /lib/compiler/test/*_no_opt_SUITE.erl /lib/compiler/test/*_post_opt_SUITE.erl +/lib/compiler/test/*_inline_SUITE.erl # debugger diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index 4d3b4c98f1..961b589035 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -53,6 +53,21 @@ NO_OPT= \ record \ trycatch +INLINE= \ + andor \ + apply \ + bs_bincomp \ + bs_bit_binaries \ + bs_construct \ + core_fold \ + float \ + fun \ + match \ + misc \ + num_bif \ + receive \ + record + CORE_MODULES = \ bs_shadowed_size_var \ nested_call_in_case @@ -62,6 +77,8 @@ NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE) NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl) POST_OPT_MODULES= $(NO_OPT:%=%_post_opt_SUITE) POST_OPT_ERL_FILES= $(POST_OPT_MODULES:%=%.erl) +INLINE_MODULES= $(INLINE:%=%_inline_SUITE) +INLINE_ERL_FILES= $(INLINE_MODULES:%=%.erl) ERL_FILES= $(MODULES:%=%.erl) @@ -90,13 +107,15 @@ EBIN = . # Targets # ---------------------------------------------------- -make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) +make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(INLINE_ERL_FILES) $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \ > $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt $(ERL_COMPILE_FLAGS) \ -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +no_copt $(ERL_COMPILE_FLAGS) \ -o$(EBIN) $(POST_OPT_MODULES) >> $(EMAKEFILE) + $(ERL_TOP)/make/make_emakefile +inline $(ERL_COMPILE_FLAGS) \ + -o$(EBIN) $(INLINE_MODULES) >> $(EMAKEFILE) tests debug opt: make_emakefile erl $(ERL_MAKE_FLAGS) -make @@ -118,6 +137,9 @@ docs: %_post_opt_SUITE.erl: %_SUITE.erl sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ +%_inline_SUITE.erl: %_SUITE.erl + sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- @@ -130,7 +152,7 @@ release_tests_spec: make_emakefile $(INSTALL_DATA) compiler.dynspec compiler.cover \ $(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \ - $(RELSYSDIR) + $(INLINE_ERL_FILES) $(RELSYSDIR) chmod -f -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl index 231b86b0b6..844bbfc4b9 100644 --- a/lib/compiler/test/test_lib.erl +++ b/lib/compiler/test/test_lib.erl @@ -58,6 +58,7 @@ opt_opts(Mod) -> (no_gc_bifs) -> true; (no_stack_trimming) -> true; (debug_info) -> true; + (inline) -> true; (_) -> false end, Opts). @@ -68,5 +69,6 @@ opt_opts(Mod) -> get_data_dir(Config) -> Data0 = ?config(data_dir, Config), {ok,Data1,_} = regexp:sub(Data0, "_no_opt_SUITE", "_SUITE"), - {ok,Data,_} = regexp:sub(Data1, "_post_opt_SUITE", "_SUITE"), + {ok,Data2,_} = regexp:sub(Data1, "_post_opt_SUITE", "_SUITE"), + {ok,Data,_} = regexp:sub(Data2, "_inline_SUITE", "_SUITE"), Data. -- cgit v1.2.3 From 0320836d1b58438ef4467832b00306672d22f8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 18 Mar 2010 08:45:03 +0100 Subject: Consistently rewrite an inlined function_clause exception to case_clause A function_clause exception is generated by jumping to a func_info/3 instruction at the beginning of the function. The x registers are assumed to contain the arguments for the function. That means that a func_info/3 instruction copied from another function (or even from the same function if not at the top level) will not work, so it must be replaced with an instruction that generates a case_clause exception. In Core Erlang, a func_info/3 instruction is represented as a the primop match_fail({function_clause,Arg1,...ArgN}). The current mechanism that is supposed to replace the primop match_fail(function_clause) with match_fail(case_clause) will fail to do that in the following circumstances: 1. If the inliner has inlined a function into itself. Fix that by having the inliner clear the function_name annotations on all match_fail primops in functions that are inlined. (To simplify doing that, the annotation is now on the primop node itself and not on the 'function_clause' atom inside it.) 2. If the inliner has rewritten the tuple node in the primop node to a literal (when inlining a function call with literal arguments), v3_kernel would not recognize the match_fail(function_clause) primop and would not rewrite it. Fix it by making v3_kernel smarter. Also simplify the "old" inliner (sys_core_inline) to only clear the function_name annotations instead of rewriting function_clause execptions to case_clause execptions itself. --- lib/compiler/src/cerl_inline.erl | 32 ++++++++++++++--- lib/compiler/src/sys_core_inline.erl | 12 +++---- lib/compiler/src/v3_core.erl | 22 +++++++----- lib/compiler/src/v3_kernel.erl | 66 ++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 44 deletions(-) diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl index 191efa3032..f4eaa17e72 100644 --- a/lib/compiler/src/cerl_inline.erl +++ b/lib/compiler/src/cerl_inline.erl @@ -1429,17 +1429,26 @@ inline(E, #app{opnds = Opnds, ctxt = Ctxt, loc = L}, Ren, Env, S) -> {E, S}; true -> %% Create local bindings for the parameters to their - %% respective operand structures from the app-structure, and - %% visit the body in the context saved in the structure. + %% respective operand structures from the app-structure. {Rs, Ren1, Env1, S1} = bind_locals(Vs, Opnds, Ren, Env, S), - {E1, S2} = i(fun_body(E), Ctxt, Ren1, Env1, S1), + + %% function_clause exceptions that have been inlined + %% into another function (or even into the same function) + %% will not work properly. The v3_kernel pass will + %% take care of it, but we will need to help it by + %% removing any function_name annotations on match_fail + %% primops that we inline. + E1 = kill_function_name_anns(fun_body(E)), + + %% Visit the body in the context saved in the structure. + {E2, S2} = i(E1, Ctxt, Ren1, Env1, S1), %% Create necessary bindings and/or set flags. - {E2, S3} = make_let_bindings(Rs, E1, S2), + {E3, S3} = make_let_bindings(Rs, E2, S2), %% Lastly, flag the application as inlined, since the inlining %% attempt was not aborted before we reached this point. - {E2, st__set_app_inlined(L, S3)} + {E3, st__set_app_inlined(L, S3)} end. %% For the (possibly renamed) argument variables to an inlined call, @@ -2370,6 +2379,19 @@ kill_id_anns([A | As]) -> kill_id_anns([]) -> []. +kill_function_name_anns(Body) -> + F = fun(P) -> + case type(P) of + primop -> + Ann = get_ann(P), + Ann1 = lists:keydelete(function_name, 1, Ann), + set_ann(P, Ann1); + _ -> + P + end + end, + cerl_trees:map(F, Body). + %% ===================================================================== %% General utilities diff --git a/lib/compiler/src/sys_core_inline.erl b/lib/compiler/src/sys_core_inline.erl index 06696e5950..c644b9e015 100644 --- a/lib/compiler/src/sys_core_inline.erl +++ b/lib/compiler/src/sys_core_inline.erl @@ -41,11 +41,9 @@ -module(sys_core_inline). -%%-compile({inline,{match_fail_fun,0}}). - -export([module/2]). --import(lists, [member/2,map/2,foldl/3,mapfoldl/3]). +-import(lists, [member/2,map/2,foldl/3,mapfoldl/3,keydelete/3]). -include("core_parse.hrl"). @@ -178,11 +176,9 @@ weight_func(_Core, Acc) -> Acc + 1. %% function_clause match_fail (if they have one). match_fail_fun() -> - fun (#c_primop{name=#c_literal{val=match_fail}, - args=[#c_tuple{es=[#c_literal{val=function_clause}|As]}]}=P) -> - Fail = #c_tuple{es=[#c_literal{val=case_clause}, - #c_tuple{es=As}]}, - P#c_primop{args=[Fail]}; + fun (#c_primop{anno=Anno0,name=#c_literal{val=match_fail}}=P) -> + Anno = keydelete(function_name, 1, Anno0), + P#c_primop{anno=Anno}; (Other) -> Other end. diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 8b04969b05..4ac2196d79 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -1542,17 +1542,21 @@ new_vars_1(N, Anno, St0, Vs) when N > 0 -> new_vars_1(0, _, St, Vs) -> {Vs,St}. function_clause(Ps, Name) -> - fail_clause(Ps, c_tuple([#c_literal{anno=[{name,Name}], - val=function_clause}|Ps])). -function_clause(Ps, Anno, Name) -> - fail_clause(Ps, ann_c_tuple(Anno, - [#c_literal{anno=[{name,Name}], - val=function_clause}|Ps])). - -fail_clause(Pats, A) -> + function_clause(Ps, [], Name). + +function_clause(Ps, LineAnno, Name) -> + FcAnno = [{function_name,Name}], + fail_clause(Ps, FcAnno, + ann_c_tuple(LineAnno, [#c_literal{val=function_clause}|Ps])). + +fail_clause(Pats, Arg) -> + fail_clause(Pats, [], Arg). + +fail_clause(Pats, Anno, Arg) -> #iclause{anno=#a{anno=[compiler_generated]}, pats=Pats,guard=[], - body=[#iprimop{anno=#a{},name=#c_literal{val=match_fail},args=[A]}]}. + body=[#iprimop{anno=#a{anno=Anno},name=#c_literal{val=match_fail}, + args=[Arg]}]}. ubody(B, St) -> uexpr(B, [], St). diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index f1215e8a35..974c64a8bc 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -80,7 +80,8 @@ -export([module/2,format_error/1]). --import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,keymember/3]). +-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2, + keymember/3,keyfind/3]). -import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]). -compile({nowarn_deprecated_function, {erlang,hash,2}}). @@ -408,7 +409,7 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) -> {Call,Ap,St} end; expr(#c_primop{anno=A,name=#c_literal{val=match_fail},args=Cargs0}, Sub, St0) -> - Cargs = translate_match_fail(Cargs0, Sub, St0), + Cargs = translate_match_fail(Cargs0, Sub, A, St0), %% This special case will disappear. {Kargs,Ap,St} = atomic_list(Cargs, Sub, St0), Ar = length(Cargs), @@ -435,32 +436,53 @@ expr(#c_catch{anno=A,body=Cb}, Sub, St0) -> %% Handle internal expressions. expr(#ireceive_accept{anno=A}, _Sub, St) -> {#k_receive_accept{anno=A},[],St}. -%% Translate a function_clause to case_clause if it has been moved into -%% another function. -translate_match_fail([#c_tuple{es=[#c_literal{anno=A0, - val=function_clause}|As]}]=Args, - Sub, - #kern{ff=FF}) -> - A = case A0 of - [{name,{Func0,Arity0}}] -> - [{name,{get_fsub(Func0, Arity0, Sub),Arity0}}]; - _ -> - A0 - end, - case {A,FF} of - {[{name,Same}],Same} -> +%% Translate a function_clause exception to a case_clause exception if +%% it has been moved into another function. (A function_clause exception +%% will not work correctly if it is moved into another function, or +%% even if it is invoked not from the top level in the correct function.) +translate_match_fail(Args, Sub, Anno, St) -> + case Args of + [#c_tuple{es=[#c_literal{val=function_clause}|As]}] -> + translate_match_fail_1(Anno, Args, As, Sub, St); + [#c_literal{val=Tuple}] when is_tuple(Tuple) -> + %% The inliner may have created a literal out of + %% the original #c_tuple{}. + case tuple_to_list(Tuple) of + [function_clause|As0] -> + As = [#c_literal{val=E} || E <- As0], + translate_match_fail_1(Anno, Args, As, Sub, St); + _ -> + Args + end; + _ -> + %% Not a function_clause exception. + Args + end. + +translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> + AnnoFunc = case keyfind(function_name, 1, Anno) of + false -> + none; %Force rewrite. + {function_name,{Name,Arity}} -> + {get_fsub(Name, Arity, Sub),Arity} + end, + case {AnnoFunc,FF} of + {Same,Same} -> %% Still in the correct function. Args; - {[{name,{F,_}}],F} -> + {{F,_},F} -> %% Still in the correct function. Args; _ -> - %% Inlining has probably moved the function_clause into another - %% function (where it will not work correctly). - %% Rewrite to a case_clause. + %% Wrong function or no function_name annotation. + %% + %% The inliner has copied the match_fail(function_clause) + %% primop from another function (or from another instance of + %% the current function). match_fail(function_clause) will + %% only work at the top level of the function it was originally + %% defined in, so we will need to rewrite it to a case_clause. [#c_tuple{es=[#c_literal{val=case_clause},#c_tuple{es=As}]}] - end; -translate_match_fail(Args, _, _) -> Args. + end. %% call_type(Module, Function, Arity) -> call | bif | apply | error. %% Classify the call. -- cgit v1.2.3 From f1e60ef101b6bb6e262c2387cf1b408c66b94c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 18 Mar 2010 13:51:28 +0100 Subject: compiler tests: Compile a few more modules with 'inline' Since a function_clause exception in an inlined function will be changed to a case_clause exception, we must test for both. --- lib/compiler/test/Makefile | 4 ++ lib/compiler/test/bs_match_SUITE.erl | 75 +++++++++++++++++------------------- lib/compiler/test/bs_utf_SUITE.erl | 4 +- lib/compiler/test/guard_SUITE.erl | 11 ++++-- lib/compiler/test/lc_SUITE.erl | 7 +++- 5 files changed, 55 insertions(+), 46 deletions(-) diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index 961b589035..2d08e71e09 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -59,9 +59,13 @@ INLINE= \ bs_bincomp \ bs_bit_binaries \ bs_construct \ + bs_match \ + bs_utf \ core_fold \ float \ fun \ + guard \ + lc \ match \ misc \ num_bif \ diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 5c2797170b..0451e7e9e2 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -302,15 +302,15 @@ partitioned_bs_match(Config) when is_list(Config) -> ?line error = partitioned_bs_match(10, <<7,8,15,13>>), ?line error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}), ?line ok = partitioned_bs_match(0, <<>>), - ?line {'EXIT',{function_clause,[{?MODULE,partitioned_bs_match,[-1,blurf]}|_]}} = - (catch partitioned_bs_match(-1, blurf)), - ?line {'EXIT',{function_clause,[{?MODULE,partitioned_bs_match,[-1,<<1,2,3>>]}|_]}} = - (catch partitioned_bs_match(-1, <<1,2,3>>)), - + ?line fc(partitioned_bs_match, [-1,blurf], + catch partitioned_bs_match(-1, blurf)), + ?line fc(partitioned_bs_match, [-1,<<1,2,3>>], + catch partitioned_bs_match(-1, <<1,2,3>>)), ?line {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>), ?line {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>), - ?line {'EXIT',{function_clause,[{?MODULE,partitioned_bs_match_2,[4,<<0:17>>]}|_]}} = - (catch partitioned_bs_match_2(4, <<0:17>>)), + + ?line fc(partitioned_bs_match_2, [4,<<0:17>>], + catch partitioned_bs_match_2(4, <<0:17>>)), ok. partitioned_bs_match(_, <<42:8,T/binary>>) -> @@ -327,12 +327,10 @@ partitioned_bs_match_2(Len, <<_:8,T/binary>>) -> function_clause(Config) when is_list(Config) -> ?line ok = function_clause_1(<<0,7,0,7,42>>), - ?line {'EXIT',{function_clause, - [{?MODULE,function_clause_1,[<<0,1,2,3>>]}|_]}} = - (catch function_clause_1(<<0,1,2,3>>)), - ?line {'EXIT',{function_clause, - [{?MODULE,function_clause_1,[<<0,1,2,3>>]}|_]}} = - (catch function_clause_1(<<0,7,0,1,2,3>>)), + ?line fc(function_clause_1, [<<0,1,2,3>>], + catch function_clause_1(<<0,1,2,3>>)), + ?line fc(function_clause_1, [<<0,1,2,3>>], + catch function_clause_1(<<0,7,0,1,2,3>>)), ok. function_clause_1(<<0:8,7:8,T/binary>>) -> @@ -349,22 +347,17 @@ unit(Config) when is_list(Config) -> ?line 99 = peek8(<<99>>), ?line 100 = peek8(<<100,101>>), - ?line {'EXIT',{function_clause,[{?MODULE,peek8,[<<100,101,0:1>>]}|_]}} = - (catch peek8(<<100,101,0:1>>)), + ?line fc(peek8, [<<100,101,0:1>>], catch peek8(<<100,101,0:1>>)), ?line 37484 = peek16(<<37484:16>>), ?line 37489 = peek16(<<37489:16,5566:16>>), - ?line {'EXIT',{function_clause,[{?MODULE,peek16,[<<8>>]}|_]}} = - (catch peek16(<<8>>)), - ?line {'EXIT',{function_clause,[{?MODULE,peek16,[<<42:15>>]}|_]}} = - (catch peek16(<<42:15>>)), - ?line {'EXIT',{function_clause,[{?MODULE,peek16,[<<1,2,3,4,5>>]}|_]}} = - (catch peek16(<<1,2,3,4,5>>)), + ?line fc(peek16, [<<8>>], catch peek16(<<8>>)), + ?line fc(peek16, [<<42:15>>], catch peek16(<<42:15>>)), + ?line fc(peek16, [<<1,2,3,4,5>>], catch peek16(<<1,2,3,4,5>>)), ?line 127 = peek7(<<127:7>>), ?line 100 = peek7(<<100:7,19:7>>), - ?line {'EXIT',{function_clause,[{?MODULE,peek7,[<<1,2>>]}|_]}} = - (catch peek7(<<1,2>>)), + ?line fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)), ok. peek1(<>) -> B. @@ -533,15 +526,13 @@ bs_sum(Config) when is_list(Config) -> ?line 6 = bs_sum_1([1,2,3|0]), ?line 7 = bs_sum_1([1,2,3|one]), - ?line {'EXIT',{function_clause,_}} = (catch bs_sum_1({too,big,tuple})), - ?line {'EXIT',{function_clause,_}} = (catch bs_sum_1([1,2,3|{too,big,tuple}])), + ?line fc(catch bs_sum_1({too,big,tuple})), + ?line fc(catch bs_sum_1([1,2,3|{too,big,tuple}])), ?line [] = sneaky_alias(<<>>), ?line [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)), - ?line {'EXIT',{function_clause,[{?MODULE,sneaky_alias,[<<1>>]}|_]}} = - (catch sneaky_alias(id(<<1>>))), - ?line {'EXIT',{function_clause,[{?MODULE,sneaky_alias,[[1,2,3,4]]}|_]}} = - (catch sneaky_alias(lists:seq(1, 4))), + ?line fc(sneaky_alias, [<<1>>], catch sneaky_alias(id(<<1>>))), + ?line fc(sneaky_alias, [[1,2,3,4]], catch sneaky_alias(lists:seq(1, 4))), ok. bs_sum_1(<>) -> H+bs_sum_1(T); @@ -559,9 +550,9 @@ sneaky_alias(<>) -> [From|sneaky_alias(L)]. coverage(Config) when is_list(Config) -> ?line 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>), ?line 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>), - ?line {'EXIT',{function_clause,_}} = (catch coverage_fold(fun(B, A) -> - A+B - end, 0, [a,b,c])), + ?line fc(catch coverage_fold(fun(B, A) -> + A+B + end, 0, [a,b,c])), ?line {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple), ?line {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} = @@ -573,9 +564,8 @@ coverage(Config) when is_list(Config) -> ?line do_coverage_bin_to_term_list([]), ?line do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]), - ?line {'EXIT',{function_clause, - [{?MODULE,coverage_bin_to_term_list,[<<0,0,0,7>>]}|_]}} = - (catch do_coverage_bin_to_term_list_1(<<7:32>>)), + ?line fc(coverage_bin_to_term_list, [<<0,0,0,7>>], + catch do_coverage_bin_to_term_list_1(<<7:32>>)), ?line <<>> = coverage_per_key(<<4:32>>), ?line <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>), @@ -731,13 +721,12 @@ encode_octet_string(<>, Len) -> simon(Config) when is_list(Config) -> ?line one = simon(blurf, <<>>), ?line two = simon(0, <<42>>), - ?line {'EXIT',{function_clause,[{?MODULE,simon,[17,<<1>>]}|_]}} = (catch simon(17, <<1>>)), - ?line {'EXIT',{function_clause,[{?MODULE,simon,[0,<<1,2,3>>]}|_]}} = (catch simon(0, <<1,2,3>>)), + ?line fc(simon, [17,<<1>>], catch simon(17, <<1>>)), + ?line fc(simon, [0,<<1,2,3>>], catch simon(0, <<1,2,3>>)), ?line one = simon2(blurf, <<9>>), ?line two = simon2(0, <<9,1>>), - ?line {'EXIT',{function_clause,[{?MODULE,simon2,[0,<<9,10,11>>]}|_]}} = - (catch simon2(0, <<9,10,11>>)), + ?line fc(simon2, [0,<<9,10,11>>], catch simon2(0, <<9,10,11>>)), ok. simon(_, <<>>) -> one; @@ -985,6 +974,14 @@ haystack_2(Haystack) -> B end || {X,Y} <- Subs ]. +fc({'EXIT',{function_clause,_}}) -> ok; +fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_match_inline_SUITE -> ok. + +fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args}|_]}}) -> ok; +fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}}) + when ?MODULE =:= bs_match_inline_SUITE -> + Args = tuple_to_list(ActualArgs). + check(F, R) -> R = F(). diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl index d93bdef73d..d1a74f4393 100644 --- a/lib/compiler/test/bs_utf_SUITE.erl +++ b/lib/compiler/test/bs_utf_SUITE.erl @@ -314,7 +314,7 @@ coverage(Config) when is_list(Config) -> ?line 0 = coverage_2(<<4096/utf8,65536/utf8,0>>), ?line 1 = coverage_2(<<1024/utf8,1025/utf8,1>>), - ?line {'EXIT',{function_clause,_}} = (catch coverage_3(1)), + ?line fc(catch coverage_3(1)), %% Cover beam_flatten (combining the heap allocation in %% a subsequent test_heap instruction into the bs_init2 @@ -394,3 +394,5 @@ utf32_data() -> <<16#41:32/little,NotIdentical:32/little, 16#0391:32/little,16#2E:32/little>>}. +fc({'EXIT',{function_clause,_}}) -> ok; +fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_utf_inline_SUITE -> ok. diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index 5ae41f13e7..7343d0f8ca 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -1316,11 +1316,11 @@ cqlc(M, F, As, St) -> andalso_semi(Config) when is_list(Config) -> ?line ok = andalso_semi_foo(0), ?line ok = andalso_semi_foo(1), - ?line {'EXIT',{function_clause,_}} = (catch andalso_semi_foo(2)), + ?line fc(catch andalso_semi_foo(2)), ?line ok = andalso_semi_bar([a,b,c]), ?line ok = andalso_semi_bar(1), - ?line {'EXIT',{function_clause,_}} = (catch andalso_semi_bar([a,b])), + ?line fc(catch andalso_semi_bar([a,b])), ok. andalso_semi_foo(Bar) when is_integer(Bar) andalso Bar =:= 0; Bar =:= 1 -> @@ -1332,8 +1332,8 @@ andalso_semi_bar(Bar) when is_list(Bar) andalso length(Bar) =:= 3; Bar =:= 1 -> tuple_size(Config) when is_list(Config) -> ?line 10 = do_tuple_size({1,2,3,4}), - ?line {'EXIT',{function_clause,_}} = (catch do_tuple_size({1,2,3})), - ?line {'EXIT',{function_clause,_}} = (catch do_tuple_size(42)), + ?line fc(catch do_tuple_size({1,2,3})), + ?line fc(catch do_tuple_size(42)), ?line error = ludicrous_tuple_size({a,b,c}), ?line error = ludicrous_tuple_size([a,b,c]), @@ -1374,3 +1374,6 @@ check(F, Result) -> io:format(" Got: ~p\n", [Other]), test_server:fail() end. + +fc({'EXIT',{function_clause,_}}) -> ok; +fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= guard_inline_SUITE -> ok. diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl index e62b2cd77e..2960615b7e 100644 --- a/lib/compiler/test/lc_SUITE.erl +++ b/lib/compiler/test/lc_SUITE.erl @@ -66,8 +66,7 @@ basic(Config) when is_list(Config) -> ?line {'EXIT',_} = (catch [X || X <- L1, list_to_atom(X) == dum]), ?line [] = [X || X <- L1, X+1 < 2], ?line {'EXIT',_} = (catch [X || X <- L1, odd(X)]), - ?line {'EXIT',{function_clause,[{?MODULE,_,[x]}|_]}} = - (catch [E || E <- id(x)]), + ?line fc([x], catch [E || E <- id(x)]), ok. tuple_list() -> @@ -160,3 +159,7 @@ empty_generator(Config) when is_list(Config) -> id(I) -> I. +fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args}|_]}}) -> ok; +fc(Args, {'EXIT',{{case_clause,ActualArgs},_}}) + when ?MODULE =:= lc_inline_SUITE -> + Args = tuple_to_list(ActualArgs). -- cgit v1.2.3 From 7832064bf7783f2f00e4e2cdc460a05d4f075146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 18 Mar 2010 15:48:28 +0100 Subject: compiler tests: Cope with missing args in function_clause for native code Native-compiled code generates a different stack trace for function_clause exceptions - instead of the arguments for the function, only the arity is reported. Accept missing arguments if the test suite is native-compiled. --- lib/compiler/test/bs_match_SUITE.erl | 3 +++ lib/compiler/test/lc_SUITE.erl | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 0451e7e9e2..e729367a81 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -978,6 +978,9 @@ fc({'EXIT',{function_clause,_}}) -> ok; fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_match_inline_SUITE -> ok. fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args}|_]}}) -> ok; +fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity}|_]}}) + when length(Args) =:= Arity -> + true = test_server:is_native(?MODULE); fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}}) when ?MODULE =:= bs_match_inline_SUITE -> Args = tuple_to_list(ActualArgs). diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl index 2960615b7e..0c1373924c 100644 --- a/lib/compiler/test/lc_SUITE.erl +++ b/lib/compiler/test/lc_SUITE.erl @@ -160,6 +160,9 @@ empty_generator(Config) when is_list(Config) -> id(I) -> I. fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args}|_]}}) -> ok; +fc(Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity}|_]}}) + when length(Args) =:= Arity -> + true = test_server:is_native(?MODULE); fc(Args, {'EXIT',{{case_clause,ActualArgs},_}}) when ?MODULE =:= lc_inline_SUITE -> Args = tuple_to_list(ActualArgs). -- cgit v1.2.3 From f958b8bdbc63c5cbc60502047a4fab548fe9fd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 19 Mar 2010 16:30:00 +0100 Subject: pmod_SUITE: Again test inlining parameterized modules Commit 91de9d0670c6fe1cff08cefa6e1c396effba47b8 stopped testing inlining of parameterized modules, because of a bug in the inliner. --- lib/compiler/test/pmod_SUITE.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compiler/test/pmod_SUITE.erl b/lib/compiler/test/pmod_SUITE.erl index 293e110c45..13503ce905 100644 --- a/lib/compiler/test/pmod_SUITE.erl +++ b/lib/compiler/test/pmod_SUITE.erl @@ -38,8 +38,8 @@ fin_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> basic(Config) when is_list(Config) -> ?line basic_1(Config, []), -% ?line basic_1(Config, [inline]), -% ?line basic_1(Config, [{inline,500},inline]), + ?line basic_1(Config, [inline]), + ?line basic_1(Config, [{inline,500},inline]), ok. basic_1(Config, Opts) -> -- cgit v1.2.3