From 23362aeb8f364adb64a0825ea40dcb1158babe13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 22 Apr 2010 09:15:45 +0200 Subject: gen: Inline wait_resp_mon/2 to help the compiler optimize We are about to introduce a new optimization that requires the creation of a monitor and the following receive statement to be in the same function. --- lib/stdlib/src/gen.erl | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 5aab547644..30f48d39b7 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -212,7 +212,22 @@ do_call(Process, Label, Request, Timeout) -> catch erlang:send(Process, {Label, {self(), Mref}, Request}, [noconnect]), - wait_resp_mon(Node, Mref, Timeout) + receive + {Mref, Reply} -> + erlang:demonitor(Mref, [flush]), + {ok, Reply}; + {'DOWN', Mref, _, _, noconnection} -> + exit({nodedown, Node}); + {'DOWN', Mref, _, _, Reason} -> + exit(Reason) + after Timeout -> + erlang:demonitor(Mref), + receive + {'DOWN', Mref, _, _, _} -> true + after 0 -> true + end, + exit(timeout) + end catch error:_ -> %% Node (C/Java?) is not supporting the monitor. @@ -233,24 +248,6 @@ do_call(Process, Label, Request, Timeout) -> end end. -wait_resp_mon(Node, Mref, Timeout) -> - receive - {Mref, Reply} -> - erlang:demonitor(Mref, [flush]), - {ok, Reply}; - {'DOWN', Mref, _, _, noconnection} -> - exit({nodedown, Node}); - {'DOWN', Mref, _, _, Reason} -> - exit(Reason) - after Timeout -> - erlang:demonitor(Mref), - receive - {'DOWN', Mref, _, _, _} -> true - after 0 -> true - end, - exit(timeout) - end. - wait_resp(Node, Tag, Timeout) -> receive {Tag, Reply} -> -- cgit v1.2.3 From f0d8728a851901e9080eb35aee0b6b8e24b2d91e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 22 Apr 2010 13:39:30 +0200 Subject: Move p_run/2 to test_lib It can be useful for other test suites. --- lib/compiler/test/compile_SUITE.erl | 36 ++---------------------------------- lib/compiler/test/test_lib.erl | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 7c3990a855..bba0d3fb48 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -625,7 +625,7 @@ core(Config) when is_list(Config) -> {raw_abstract_v1,Abstr}}]}} = beam_lib:chunks(Beam, [abstract_code]), {Mod,Abstr} end || Beam <- TestBeams], - ?line Res = p_run(fun(F) -> do_core(F, Outdir) end, Abstr), + ?line Res = test_lib:p_run(fun(F) -> do_core(F, Outdir) end, Abstr), ?line test_server:timetrap_cancel(Dog), Res. @@ -661,7 +661,7 @@ asm(Config) when is_list(Config) -> ?line Wc = filename:join(filename:dirname(code:which(?MODULE)), "*.beam"), ?line TestBeams = filelib:wildcard(Wc), - ?line Res = p_run(fun(F) -> do_asm(F, Outdir) end, TestBeams), + ?line Res = test_lib:p_run(fun(F) -> do_asm(F, Outdir) end, TestBeams), ?line test_server:timetrap_cancel(Dog), Res. @@ -688,35 +688,3 @@ do_asm(Beam, Outdir) -> [M,Class,Error,erlang:get_stacktrace()]), error end. - -%% p_run(fun() -> ok|error, List) -> ok -%% Will fail the test case if there were any errors. - -p_run(Test, List) -> - N = erlang:system_info(schedulers) + 1, - p_run_loop(Test, List, N, [], 0, 0). - -p_run_loop(_, [], _, [], Errors, Ws) -> - case Errors of - 0 -> - case Ws of - 0 -> ok; - 1 -> {comment,"1 core_lint failure"}; - N -> {comment,integer_to_list(N)++" core_lint failures"} - end; - N -> ?t:fail({N,errors}) - end; -p_run_loop(Test, [H|T], N, Refs, Errors, Ws) when length(Refs) < N -> - {_,Ref} = erlang:spawn_monitor(fun() -> exit(Test(H)) end), - p_run_loop(Test, T, N, [Ref|Refs], Errors, Ws); -p_run_loop(Test, List, N, Refs0, Errors0, Ws0) -> - receive - {'DOWN',Ref,process,_,Res} -> - {Errors,Ws} = case Res of - ok -> {Errors0,Ws0}; - error -> {Errors0+1,Ws0}; - warning -> {Errors0,Ws0+1} - end, - Refs = Refs0 -- [Ref], - p_run_loop(Test, List, N, Refs, Errors, Ws) - end. diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl index 844bbfc4b9..05236ee010 100644 --- a/lib/compiler/test/test_lib.erl +++ b/lib/compiler/test/test_lib.erl @@ -20,7 +20,7 @@ -include("test_server.hrl"). --export([recompile/1,opt_opts/1,get_data_dir/1,smoke_disasm/1]). +-export([recompile/1,opt_opts/1,get_data_dir/1,smoke_disasm/1,p_run/2]). recompile(Mod) when is_atom(Mod) -> case whereis(cover_server) of @@ -72,3 +72,35 @@ get_data_dir(Config) -> {ok,Data2,_} = regexp:sub(Data1, "_post_opt_SUITE", "_SUITE"), {ok,Data,_} = regexp:sub(Data2, "_inline_SUITE", "_SUITE"), Data. + +%% p_run(fun(Data) -> ok|error, List) -> ok +%% Will fail the test case if there were any errors. + +p_run(Test, List) -> + N = erlang:system_info(schedulers) + 1, + p_run_loop(Test, List, N, [], 0, 0). + +p_run_loop(_, [], _, [], Errors, Ws) -> + case Errors of + 0 -> + case Ws of + 0 -> ok; + 1 -> {comment,"1 warning"}; + N -> {comment,integer_to_list(N)++" warnings"} + end; + N -> ?t:fail({N,errors}) + end; +p_run_loop(Test, [H|T], N, Refs, Errors, Ws) when length(Refs) < N -> + {_,Ref} = erlang:spawn_monitor(fun() -> exit(Test(H)) end), + p_run_loop(Test, T, N, [Ref|Refs], Errors, Ws); +p_run_loop(Test, List, N, Refs0, Errors0, Ws0) -> + receive + {'DOWN',Ref,process,_,Res} -> + {Errors,Ws} = case Res of + ok -> {Errors0,Ws0}; + error -> {Errors0+1,Ws0}; + warning -> {Errors0,Ws0+1} + end, + Refs = Refs0 -- [Ref], + p_run_loop(Test, List, N, Refs, Errors, Ws) + end. -- cgit v1.2.3 From ea0f50dfbc8ec99820b81f99be81ada727bb3cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 11 May 2010 08:42:25 +0200 Subject: Compile tests that communicate with R12 nodes with the r12 option R12 nodes cannot load code that use the optimized receive that we are about to implement. --- erts/emulator/test/distribution_SUITE.erl | 1 + erts/emulator/test/fun_r12_SUITE.erl | 1 + lib/stdlib/test/io_proto_SUITE.erl | 1 + lib/stdlib/test/qlc_SUITE.erl | 1 + lib/test_server/src/test_server_node.erl | 1 + 5 files changed, 5 insertions(+) diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index 8f48d8a992..be9694f26f 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -18,6 +18,7 @@ %% -module(distribution_SUITE). +-compile(r12). %% Tests distribution and the tcp driver. diff --git a/erts/emulator/test/fun_r12_SUITE.erl b/erts/emulator/test/fun_r12_SUITE.erl index f21299ba67..9262731dcb 100644 --- a/erts/emulator/test/fun_r12_SUITE.erl +++ b/erts/emulator/test/fun_r12_SUITE.erl @@ -18,6 +18,7 @@ %% -module(fun_r12_SUITE). +-compile(r12). -export([all/1,init_per_testcase/2,fin_per_testcase/2,dist_old_release/1]). diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index 93159fbd5b..d9672a8c7b 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -17,6 +17,7 @@ %% %CopyrightEnd% %% -module(io_proto_SUITE). +-compile(r12). -export([all/1]). diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index ff11ebc6bf..ec014052f4 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -20,6 +20,7 @@ %%% Purpose:Test Suite for the 'qlc' module. %%%----------------------------------------------------------------- -module(qlc_SUITE). +-compile(r12). -define(QLC, qlc). -define(QLCs, "qlc"). diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl index 32886b6765..49025b1a3d 100644 --- a/lib/test_server/src/test_server_node.erl +++ b/lib/test_server/src/test_server_node.erl @@ -17,6 +17,7 @@ %% %CopyrightEnd% %% -module(test_server_node). +-compile(r12). %%% %%% The same compiled code for this module must be possible to load -- cgit v1.2.3 From d60f055697cfe8e7f94be4d291d49bb00a66bc52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 22 Apr 2010 15:18:13 +0200 Subject: Introduce the new recv_mark/1 and recv_mark/1 instructions Make the recv_mark/1 and recv_mark/1 instructions known to the compiler and run-time system. For the moment, make the loader ignore any occurrences of those instructions in BEAM files. Also update hipe_beam_to_icode to ignore those instructions. --- erts/emulator/beam/ops.tab | 6 ++++++ lib/compiler/src/beam_disasm.erl | 8 ++++++++ lib/compiler/src/beam_validator.erl | 5 +++++ lib/compiler/src/genop.tab | 5 +++++ lib/hipe/icode/hipe_beam_to_icode.erl | 5 +++++ 5 files changed, 29 insertions(+) diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index 9e8ac74f40..ef6062203e 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1421,3 +1421,9 @@ i_gc_bif1 j I s I d # R13B03 # on_load + +# +# R14A. +# +recv_mark Lbl => +recv_set Lbl => diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl index c956f2f000..a66bd2a23a 100644 --- a/lib/compiler/src/beam_disasm.erl +++ b/lib/compiler/src/beam_disasm.erl @@ -1095,6 +1095,14 @@ resolve_inst({bs_put_utf32=I,[Lbl,{u,U},Arg3]},_,_,_) -> resolve_inst({on_load,[]},_,_,_) -> on_load; +%% +%% R14A. +%% +resolve_inst({recv_mark,[Lbl]},_,_,_) -> + {recv_mark,Lbl}; +resolve_inst({recv_set,[Lbl]},_,_,_) -> + {recv_set,Lbl}; + %% %% Catches instructions that are not yet handled. %% diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 1fd61831e0..34065cfdce 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -416,6 +416,11 @@ valfun_1({put,Src}, Vst) -> valfun_1({put_string,Sz,_,Dst}, Vst0) when is_integer(Sz) -> Vst = eat_heap(2*Sz, Vst0), set_type_reg(cons, Dst, Vst); +%% Instructions for optimization of selective receives. +valfun_1({recv_mark,{f,Fail}}, Vst) when is_integer(Fail) -> + Vst; +valfun_1({recv_set,{f,Fail}}, Vst) when is_integer(Fail) -> + Vst; %% Misc. valfun_1({'%live',Live}, Vst) -> verify_live(Live, Vst), diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab index 47e6e72402..b57508ea8e 100644 --- a/lib/compiler/src/genop.tab +++ b/lib/compiler/src/genop.tab @@ -274,3 +274,8 @@ BEAM_FORMAT_NUMBER=0 # R13B03 149: on_load/0 + +# R14A + +150: recv_mark/1 +151: recv_set/1 diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index 3923e98673..f24cf90ae2 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -431,6 +431,11 @@ trans_fun([{wait_timeout,{_,Lbl},Reg}|Instructions], Env) -> SuspTmout = hipe_icode:mk_if(suspend_msg_timeout,[], map_label(Lbl),hipe_icode:label_name(DoneLbl)), Movs ++ [SetTmout, SuspTmout, DoneLbl | trans_fun(Instructions,Env1)]; +%%--- mark_recv/1 & mark_set/1 --- +trans_fun([{mark_recv,{f,_}}|Instructions], Env) -> + trans_fun(Instructions,Env); +trans_fun([{mark_set,{f,_}}|Instructions], Env) -> + trans_fun(Instructions,Env); %%-------------------------------------------------------------------- %%--- Translation of arithmetics {bif,ArithOp, ...} --- %%-------------------------------------------------------------------- -- cgit v1.2.3 From 1d3148a8532b9319265fbe4107cdde81b554b3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 22 Apr 2010 10:07:18 +0200 Subject: Optimize selective receives in the presence of a large message queue If a gen_server process has many messages in its message queue and calls another gen_server process, the selective receive in gen_server:call() will have to go through the entire message queue. Have the compiler generate the new mark_recv/1 and mark_recv/1 instructions that can avoid going through the entire message queue. --- lib/compiler/src/Makefile | 1 + lib/compiler/src/beam_receive.erl | 388 ++++++++++++++++++++++++++++++++++++++ lib/compiler/src/compile.erl | 6 + lib/compiler/src/compiler.app.src | 1 + 4 files changed, 396 insertions(+) create mode 100644 lib/compiler/src/beam_receive.erl diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile index 70ddd54145..0f6d2f6193 100644 --- a/lib/compiler/src/Makefile +++ b/lib/compiler/src/Makefile @@ -58,6 +58,7 @@ MODULES = \ beam_listing \ beam_opcodes \ beam_peep \ + beam_receive \ beam_trim \ beam_type \ beam_utils \ diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl new file mode 100644 index 0000000000..9ed44ad5d7 --- /dev/null +++ b/lib/compiler/src/beam_receive.erl @@ -0,0 +1,388 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(beam_receive). +-export([module/2]). +-import(lists, [foldl/3,reverse/1,reverse/2]). + +%%% +%%% In code such as: +%%% +%%% Ref = make_ref(), %Or erlang:monitor(process, Pid) +%%% . +%%% . +%%% . +%%% receive +%%% {Ref,Reply} -> Reply +%%% end. +%%% +%%% we know that none of the messages that exist in the message queue +%%% before the call to make_ref/0 can be matched out in the receive +%%% statement. Therefore we can avoid going through the entire message +%%% queue if we introduce two new instructions (here written as +%%% BIFs in pseudo-Erlang): +%%% +%%% recv_mark(SomeUniqInteger), +%%% Ref = make_ref(), +%%% . +%%% . +%%% . +%%% recv_set(SomeUniqInteger), +%%% receive +%%% {Ref,Reply} -> Reply +%%% end. +%%% +%%% The recv_mark/1 instruction will save the current position and +%%% SomeUniqInteger in the process context. The recv_set +%%% instruction will verify that SomeUniqInteger is still stored +%%% in the process context. If it is, it will set the current pointer +%%% for the message queue (the next message to be read out) to the +%%% position that was saved by recv_mark/1. +%%% +%%% The remove_message instruction must be modified to invalidate +%%% the information stored by the previous recv_mark/1, in case there +%%% is another receive executed between the calls to recv_mark/1 and +%%% recv_set/1. +%%% +%%% We use a reference to a label (i.e. a position in the loaded code) +%%% as the SomeUniqInteger. +%%% + +module({Mod,Exp,Attr,Fs0,Lc}, _Opts) -> + Fs = [function(F) || F <- Fs0], + Code = {Mod,Exp,Attr,Fs,Lc}, + {ok,Code}. + +%%% +%%% Local functions. +%%% + +function({function,Name,Arity,Entry,Is}) -> + try + D = beam_utils:index_labels(Is), + {function,Name,Arity,Entry,opt(Is, D, [])} + catch + Class:Error -> + Stack = erlang:get_stacktrace(), + io:fwrite("Function: ~w/~w\n", [Name,Arity]), + erlang:raise(Class, Error, Stack) + end. + +opt([{call_ext,Arity,{extfunc,erlang,Name,Arity}}=I|Is0], D, Acc) -> + case creates_new_ref(Name, Arity) of + true -> + %% The call creates a brand new reference. Now + %% search for a receive statement in the same + %% function that will match against the reference. + case opt_recv(Is0, D) of + no -> + opt(Is0, D, [I|Acc]); + {yes,Is,Lbl} -> + opt(Is, D, [I,{recv_mark,{f,Lbl}}|Acc]) + end; + false -> + opt(Is0, D, [I|Acc]) + end; +opt([I|Is], D, Acc) -> + opt(Is, D, [I|Acc]); +opt([], _, Acc) -> + reverse(Acc). + +%% creates_new_ref(Name, Arity) -> true|false. +%% Return 'true' if the BIF Name/Arity will create a new reference. +creates_new_ref(monitor, 2) -> true; +creates_new_ref(make_ref, 0) -> true; +creates_new_ref(_, _) -> false. + +%% opt_recv([Instruction], LabelIndex) -> no|{yes,[Instruction]} +%% Search for a receive statement that will only retrieve messages +%% that contain the newly created reference (which is currently in {x,0}). +opt_recv(Is, D) -> + R = regs_init_x0(), + L = gb_sets:empty(), + opt_recv(Is, D, R, L, []). + +opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) -> + R = regs_kill_not_live(0, R0), + case regs_to_list(R) of + [{y,_}=RefReg] -> + %% We now have the new reference in the Y register RefReg + %% and the current instruction is the beginning of a + %% receive statement. We must now verify that only messages + %% that contain the reference will be matched. + case opt_ref_used(Is, RefReg, Fail, D) of + false -> + no; + true -> + RecvSet = {recv_set,{f,L}}, + {yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L} + end; + [] -> + no + end; +opt_recv([I|Is], D, R0, L0, Acc) -> + {R,L} = opt_update_regs(I, R0, L0), + case regs_empty(R) of + true -> + %% The reference is no longer alive. There is no + %% point in continuing the search. + no; + false -> + opt_recv(Is, D, R, L, [I|Acc]) + end. + +opt_update_regs({block,Bl}, R, L) -> + {opt_update_regs_bl(Bl, R),L}; +opt_update_regs({call,_,_}, R, L) -> + {regs_kill_not_live(0, R),L}; +opt_update_regs({call_ext,_,_}, R, L) -> + {regs_kill_not_live(0, R),L}; +opt_update_regs({call_fun,_}, R, L) -> + {regs_kill_not_live(0, R),L}; +opt_update_regs({kill,Y}, R, L) -> + {regs_kill([Y], R),L}; +opt_update_regs(send, R, L) -> + {regs_kill_not_live(0, R),L}; +opt_update_regs({'catch',_,{f,Lbl}}, R, L) -> + {R,gb_sets:add(Lbl, L)}; +opt_update_regs({catch_end,_}, R, L) -> + {R,L}; +opt_update_regs({label,Lbl}, R, L) -> + case gb_sets:is_member(Lbl, L) of + false -> + %% We can't allow arbitrary labels (since the receive + %% could be entered without first creating the reference). + {regs_init(),L}; + true -> + %% A catch label for a previously seen catch instruction is OK. + {R,L} + end; +opt_update_regs({try_end,_}, R, L) -> + {R,L}; +opt_update_regs(_I, _R, L) -> + %% Unrecognized instruction. Abort the search. + {regs_init(),L}. + +opt_update_regs_bl([{set,Ds,_,{alloc,Live,_}}|Is], Regs0) -> + Regs1 = regs_kill_not_live(Live, Regs0), + Regs = regs_kill(Ds, Regs1), + opt_update_regs_bl(Is, Regs); +opt_update_regs_bl([{set,[Dst]=Ds,[Src],move}|Is], Regs0) -> + Regs1 = regs_kill(Ds, Regs0), + Regs = case regs_is_member(Src, Regs1) of + false -> Regs1; + true -> regs_add(Dst, Regs1) + end, + opt_update_regs_bl(Is, Regs); +opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) -> + Regs = regs_kill(Ds, Regs0), + opt_update_regs_bl(Is, Regs); +opt_update_regs_bl([], Regs) -> Regs. + +%% opt_ref_used([Instruction], RefRegister, FailLabel, LabelIndex) -> true|false +%% Return 'true' if it is certain that only messages that contain the same +%% reference as in RefRegister can be matched out. Otherwise return 'false'. +%% +%% Basically, we follow all possible paths through the receive statement. +%% If all paths are safe, we return 'true'. +%% +%% A branch to FailLabel is safe, because it exits the receive statement +%% and no further message may be matched out. +%% +%% If a path hits an comparision between RefRegister and part of the message, +%% that path is safe (any messages that may be matched further down the +%% path is guaranteed to contain the reference). +%% +%% Otherwise, if we hit a 'remove_message' instruction, we give up +%% and return 'false' (the optimization is definitely unsafe). If +%% we hit an unrecognized instruction, we also give up and return +%% 'false' (the optimization may be unsafe). + +opt_ref_used(Is, RefReg, Fail, D) -> + Done = gb_sets:singleton(Fail), + Regs = regs_init_x0(), + try + opt_ref_used_1(Is, RefReg, D, Done, Regs), + true + catch + throw:not_used -> + false + end. + +%% This functions only returns if all paths through the receive +%% statement are safe, and throws an 'not_used' term otherwise. +opt_ref_used_1([{block,Bl}|Is], RefReg, D, Done, Regs0) -> + Regs = opt_ref_used_bl(Bl, Regs0), + opt_ref_used_1(Is, RefReg, D, Done, Regs); +opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) -> + Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs), + case is_ref_msg_comparison(Args, RefReg, Regs) of + false -> + opt_ref_used_1(Is, RefReg, D, Done, Regs); + true -> + %% The instructions that follow (Is) can only be executed + %% if the message contains the same reference as in RefReg. + Done + end; +opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) -> + Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs), + case is_ref_msg_comparison(Args, RefReg, Regs) of + false -> + opt_ref_used_at(Fail, RefReg, D, Done, Regs); + true -> + Done + end; +opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) -> + Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs), + opt_ref_used_1(Is, RefReg, D, Done, Regs); +opt_ref_used_1([{select_tuple_arity,_,{f,Fail},{list,List}}|_], RefReg, D, Done, Regs) -> + Lbls = [F || {f,F} <- List] ++ [Fail], + opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs); +opt_ref_used_1([{select_val,_,{f,Fail},{list,List}}|_], RefReg, D, Done, Regs) -> + Lbls = [F || {f,F} <- List] ++ [Fail], + opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs); +opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) -> + case gb_sets:is_member(Lbl, Done) of + true -> Done; + false -> opt_ref_used_1(Is, RefReg, D, Done, Regs) + end; +opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) -> + Done; +opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) -> + %% The optimization may be unsafe. + throw(not_used). + +%% is_ref_msg_comparison(Args, RefReg, RegisterSet) -> true|false. +%% Return 'true' if Args denotes a comparison between the +%% reference and message or part of the message. +is_ref_msg_comparison([R,RefReg], RefReg, Regs) -> + regs_is_member(R, Regs); +is_ref_msg_comparison([RefReg,R], RefReg, Regs) -> + regs_is_member(R, Regs); +is_ref_msg_comparison([_,_], _, _) -> false. + +opt_ref_used_in_all([L|Ls], RefReg, D, Done0, Regs) -> + Done = opt_ref_used_at(L, RefReg, D, Done0, Regs), + opt_ref_used_in_all(Ls, RefReg, D, Done, Regs); +opt_ref_used_in_all([], _, _, Done, _) -> Done. + +opt_ref_used_at(Fail, RefReg, D, Done0, Regs) -> + case gb_sets:is_member(Fail, Done0) of + true -> + Done0; + false -> + Is = beam_utils:code_at(Fail, D), + Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs), + gb_sets:add(Fail, Done) + end. + +opt_ref_used_bl([{set,[],[],remove_message}|_], _) -> + %% We have proved that a message that does not depend on the + %% reference can be matched out. + throw(not_used); +opt_ref_used_bl([{set,Ds,Ss,_}|Is], Regs0) -> + case regs_all_members(Ss, Regs0) of + false -> + %% The destination registers may be assigned values that + %% are not dependent on the message being matched. + Regs = regs_kill(Ds, Regs0), + opt_ref_used_bl(Is, Regs); + true -> + %% All the sources depend on the message directly or + %% indirectly. + Regs = regs_add_list(Ds, Regs0), + opt_ref_used_bl(Is, Regs) + end; +opt_ref_used_bl([], Regs) -> Regs. + +%%% +%%% Functions for keeping track of a set of registers. +%%% + +%% regs_init() -> RegisterSet +%% Return an empty set of registers. + +regs_init() -> + {0,0}. + +%% regs_init_x0() -> RegisterSet +%% Return a set that only contains the {x,0} register. + +regs_init_x0() -> + {1 bsl 0,0}. + +%% regs_empty(Register) -> true|false +%% Test whether the register set is empty. + +regs_empty(R) -> + R =:= {0,0}. + +%% regs_kill_not_live(Live, RegisterSet) -> RegisterSet' +%% Kill all registers indicated not live by Live. + +regs_kill_not_live(Live, {Xregs,Yregs}) -> + {Xregs band ((1 bsl Live)-1),Yregs}. + +%% regs_kill([Register], RegisterSet) -> RegisterSet' +%% Kill all registers mentioned in the list of registers. + +regs_kill([{x,N}|Rs], {Xregs,Yregs}) -> + regs_kill(Rs, {Xregs band (bnot (1 bsl N)),Yregs}); +regs_kill([{y,N}|Rs], {Xregs,Yregs}) -> + regs_kill(Rs, {Xregs,Yregs band (bnot (1 bsl N))}); +regs_kill([{fr,_}|Rs], Regs) -> + regs_kill(Rs, Regs); +regs_kill([], Regs) -> Regs. + +regs_add_list(List, Regs) -> + foldl(fun(R, A) -> regs_add(R, A) end, Regs, List). + +%% regs_add(Register, RegisterSet) -> RegisterSet' +%% Add a new register to the set of registers. + +regs_add({x,N}, {Xregs,Yregs}) -> + {Xregs bor (1 bsl N),Yregs}; +regs_add({y,N}, {Xregs,Yregs}) -> + {Xregs,Yregs bor (1 bsl N)}. + +%% regs_all_members([Register], RegisterSet) -> true|false +%% Test whether all of the registers are part of the register set. + +regs_all_members([R|Rs], Regs) -> + regs_is_member(R, Regs) andalso regs_all_members(Rs, Regs); +regs_all_members([], _) -> true. + +%% regs_is_member(Register, RegisterSet) -> true|false +%% Test whether Register is part of the register set. + +regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0; +regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0; +regs_is_member(_, _) -> false. + +%% regs_to_list(RegisterSet) -> [Register] +%% Convert the register set to an explicit list of registers. +regs_to_list({Xregs,Yregs}) -> + regs_to_list_1(Xregs, 0, x, regs_to_list_1(Yregs, 0, y, [])). + +regs_to_list_1(0, _, _, Acc) -> + Acc; +regs_to_list_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 -> + regs_to_list_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]); +regs_to_list_1(Regs, N, Tag, Acc) -> + regs_to_list_1(Regs bsr 1, N+1, Tag, Acc). diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 5017fd2c23..3f250a6d5a 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -162,6 +162,10 @@ expand_opt(report, Os) -> [report_errors,report_warnings|Os]; expand_opt(return, Os) -> [return_errors,return_warnings|Os]; +expand_opt(r12, Os) -> + [no_recv_opt|Os]; +expand_opt(r13, Os) -> + [no_recv_opt|Os]; expand_opt({debug_info_key,_}=O, Os) -> [encrypt_debug_info,O|Os]; expand_opt(no_float_opt, Os) -> @@ -621,6 +625,8 @@ asm_passes() -> {iff,dclean,{listing,"clean"}}, {unless,no_bsm_opt,{pass,beam_bsm}}, {iff,dbsm,{listing,"bsm"}}, + {unless,no_recv_opt,{pass,beam_receive}}, + {iff,drecv,{listing,"recv"}}, {unless,no_stack_trimming,{pass,beam_trim}}, {iff,dtrim,{listing,"trim"}}, {pass,beam_flatten}]}, diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src index b0311365c4..1bb62f41cf 100644 --- a/lib/compiler/src/compiler.app.src +++ b/lib/compiler/src/compiler.app.src @@ -33,6 +33,7 @@ beam_listing, beam_opcodes, beam_peep, + beam_receive, beam_trim, beam_type, beam_utils, -- cgit v1.2.3 From f39e0b6bbc5f5d9f6a55b87847bcad7707309883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 22 Apr 2010 13:37:18 +0200 Subject: compiler test: Test optimization of receive statements We don't attempt to run the generated code, but use beam_disasm and check for the presence or absence (as appropriate) of the recv_mark/1 and recv_set/1 instructions. --- lib/compiler/test/receive_SUITE.erl | 53 +++++++++++- .../test/receive_SUITE_data/ref_opt/no_1.erl | 99 ++++++++++++++++++++++ .../test/receive_SUITE_data/ref_opt/no_2.erl | 26 ++++++ .../test/receive_SUITE_data/ref_opt/no_3.erl | 14 +++ .../test/receive_SUITE_data/ref_opt/yes_1.erl | 12 +++ .../test/receive_SUITE_data/ref_opt/yes_2.erl | 13 +++ .../test/receive_SUITE_data/ref_opt/yes_3.erl | 16 ++++ .../test/receive_SUITE_data/ref_opt/yes_4.erl | 16 ++++ .../test/receive_SUITE_data/ref_opt/yes_5.erl | 46 ++++++++++ .../test/receive_SUITE_data/ref_opt/yes_6.erl | 15 ++++ .../test/receive_SUITE_data/ref_opt/yes_7.erl | 12 +++ .../test/receive_SUITE_data/ref_opt/yes_8.erl | 15 ++++ .../test/receive_SUITE_data/ref_opt/yes_9.erl | 13 +++ 13 files changed, 347 insertions(+), 3 deletions(-) create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/no_1.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/no_2.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/no_3.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_1.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_2.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_3.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_4.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_6.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_7.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_8.erl create mode 100644 lib/compiler/test/receive_SUITE_data/ref_opt/yes_9.erl diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index cb8833759a..3cfc22ddc9 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -21,7 +21,7 @@ -module(receive_SUITE). -export([all/1,init_per_testcase/2,fin_per_testcase/2, - recv/1,coverage/1,otp_7980/1]). + recv/1,coverage/1,otp_7980/1,ref_opt/1]). -include("test_server.hrl"). @@ -36,7 +36,7 @@ fin_per_testcase(_Case, Config) -> all(suite) -> test_lib:recompile(?MODULE), - [recv,coverage,otp_7980]. + [recv,coverage,otp_7980,ref_opt]. -record(state, {ena = true}). @@ -157,5 +157,52 @@ otp_7980_add_clients(Count) -> end, N - 1 end, Count, [1,2,3]). - + +ref_opt(Config) when is_list(Config) -> + case ?MODULE of + receive_SUITE -> ref_opt_1(Config); + _ -> {skip,"Enough to run this case once."} + end. + +ref_opt_1(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line PrivDir = ?config(priv_dir, Config), + ?line Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.erl"])), + ?line test_lib:p_run(fun(Src) -> + do_ref_opt(Src, PrivDir) + end, Sources), + ok. + +do_ref_opt(Source, PrivDir) -> + try + {ok,Mod} = c:c(Source, [{outdir,PrivDir}]), + ok = Mod:Mod(), + Base = filename:rootname(filename:basename(Source), ".erl"), + BeamFile = filename:join(PrivDir, Base), + {beam_file,Mod,_,_,_,Code} = beam_disasm:file(BeamFile), + case Base of + "no_"++_ -> + [] = collect_recv_opt_instrs(Code); + "yes_"++_ -> + [{recv_mark,{f,L}},{recv_set,{f,L}}] = + collect_recv_opt_instrs(Code) + end, + ok + catch Class:Error -> + io:format("~s: ~p ~p\n~p\n", + [Source,Class,Error,erlang:get_stacktrace()]), + error + end. + +collect_recv_opt_instrs(Code) -> + L = [ [I || I <- Is, + begin + case I of + {recv_mark,{f,_}} -> true; + {recv_set,{f,_}} -> true; + _ -> false + end + end] || {function,_,_,_,Is} <- Code], + lists:append(L). + id(I) -> I. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_1.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_1.erl new file mode 100644 index 0000000000..bc63dac437 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_1.erl @@ -0,0 +1,99 @@ +-module(no_1). +-compile(export_all). + +?MODULE() -> + ok. + +f1(X) -> + Ref = make_ref(), + receive + _ when [X] =:= Ref -> + ok + end. + +f2(X, Y) -> + _Ref = make_ref(), + receive + _ when X =:= Y -> + ok + end. + +f3(X) -> + Ref = make_ref(), + receive + _ when X =:= Ref -> + ok + end. + +f4(X) -> + Ref = make_ref(), + receive + {X,_} when not X =:= Ref -> + ok + end. + +f5(X) -> + Ref = make_ref(), + receive + {Y,_} when X =:= Y; Y =:= Ref -> + ok + end. + +f6(X) -> + Ref = make_ref(), + receive + {Y,_} when Y =:= Ref; Ref =:= X -> + ok + end. + +f7(X) -> + Ref = make_ref(), + receive + {Y,_} when Y =:= Ref; not (X =:= Ref) -> + ok + end. + +f8(X) -> + Ref = make_ref(), + receive + {Y,_} when not (X =:= Ref); Y =:= Ref -> + ok + end. + +f9(X) -> + Ref = make_ref(), + receive + {Y,_} when (not (X =:= Ref)) or (Y =:= Ref) -> + ok + end. + +f10(X, Y) -> + Ref = make_ref(), + receive + {Z,_} when not (X =:= Y andalso Z =:= Ref) -> + ok + end. + +f11(X, Y) -> + Ref = make_ref(), + receive + {Z,_} when not ((X =:= Y) and (Z =:= Ref)) -> + ok + end. + +f12(X, Y) -> + Ref = make_ref(), + receive + {Z,_} when not ((Z =:= Ref) and (X =:= Y)) -> + ok + end. + +f13() -> + Ref = make_ref(), + RefCopy = id(Ref), + receive + _ when hd([RefCopy]) =:= Ref -> + ok + end. + +id(I) -> I. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_2.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_2.erl new file mode 100644 index 0000000000..bc8d30c2ac --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_2.erl @@ -0,0 +1,26 @@ +-module(no_2). +-compile(export_all). + +?MODULE() -> + ok. + +f1() -> + Ref = make_ref(), + receive + {'DOWN',Ref} -> + ok; + {'DOWN',_} -> + ok + end. + +f2(Pid, Msg) -> + Ref = erlang:monitor(process, Pid), + Pid ! Msg, + receive + {ok,Ref,Reply} -> + {ok,Reply}; + {error,Ref,Reply} -> + {error,Reply}; + {error,A,B} -> + {error,A,B} + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_3.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_3.erl new file mode 100644 index 0000000000..44cf8d7f71 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_3.erl @@ -0,0 +1,14 @@ +-module(no_3). +-compile(export_all). + +?MODULE() -> + ok. + +f(X) -> + Ref = case X of + false -> ref; + true -> make_ref() + end, + receive + Ref -> ok + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_1.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_1.erl new file mode 100644 index 0000000000..e2ebe234c1 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_1.erl @@ -0,0 +1,12 @@ +-module(yes_1). +-compile(export_all). + +?MODULE() -> + ok. + +f() -> + Ref = make_ref(), + receive + {Ref,Reply} -> + Reply + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_2.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_2.erl new file mode 100644 index 0000000000..6077cdcab9 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_2.erl @@ -0,0 +1,13 @@ +-module(yes_2). +-compile(export_all). + +?MODULE() -> + ok. + +f(Pid, Msg) -> + Ref = make_ref(), + Pid ! Msg, + receive + {Ref,Reply} -> + Reply + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_3.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_3.erl new file mode 100644 index 0000000000..28efc542ae --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_3.erl @@ -0,0 +1,16 @@ +-module(yes_3). +-compile(export_all). + +?MODULE() -> + ok. + +f(Pid, Msg) -> + Ref = make_ref(), + do_send(Pid, Msg), + receive + {Ref,Reply} -> + Reply + end. + +do_send(Pid, Msg) -> + Pid ! Msg. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_4.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_4.erl new file mode 100644 index 0000000000..d1ba4832c7 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_4.erl @@ -0,0 +1,16 @@ +-module(yes_4). +-compile(export_all). + +?MODULE() -> + ok. + +f(Pid, Msg) -> + Ref = make_ref(), + catch do_send(Pid, Msg), + receive + {Ref,Reply} -> + Reply + end. + +do_send(Pid, Msg) -> + Pid ! Msg. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl new file mode 100644 index 0000000000..3f02fba6a6 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl @@ -0,0 +1,46 @@ +-module(yes_5). +-compile(export_all). + +?MODULE() -> + ok. + +do_call(Process, Label, Request, Timeout) -> + Node = case Process of + {_S, N} when is_atom(N) -> + N; + _ when is_pid(Process) -> + node(Process) + end, + try erlang:monitor(process, Process) of + Mref -> + catch erlang:send(Process, {Label, {self(), Mref}, Request}, + [noconnect]), + receive + {Mref, Reply} -> + erlang:demonitor(Mref, [flush]), + {ok, Reply}; + {'DOWN', Mref, _, _, noconnection} -> + exit({nodedown, Node}); + {'DOWN', Mref, _, _, Reason} -> + exit(Reason) + after Timeout -> + erlang:demonitor(Mref), + receive + {'DOWN', Mref, _, _, _} -> true + after 0 -> true + end, + exit(timeout) + end + catch + error:_ -> + monitor_node(Node, true), + receive + {nodedown, Node} -> + monitor_node(Node, false), + exit({nodedown, Node}) + after 0 -> + Tag = make_ref(), + Process ! {Label, {self(), Tag}, Request}, + ?MODULE:wait_resp(Node, Tag, Timeout) + end + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_6.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_6.erl new file mode 100644 index 0000000000..c54b636aa6 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_6.erl @@ -0,0 +1,15 @@ +-module(yes_6). +-compile(export_all). + +?MODULE() -> + ok. + +f(Pid, Msg) -> + Ref = erlang:monitor(process, Pid), + Pid ! Msg, + receive + {ok,Ref,Reply} -> + {ok,Reply}; + {error,Ref,Reply} -> + {error,Reply} + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_7.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_7.erl new file mode 100644 index 0000000000..849eab1746 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_7.erl @@ -0,0 +1,12 @@ +-module(yes_7). +-compile(export_all). + +?MODULE() -> + ok. + +f(X, Y) -> + Ref = make_ref(), + receive + {Z,_} when X =:= Y, Ref =:= Z -> + ok + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_8.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_8.erl new file mode 100644 index 0000000000..a47fe8cfbf --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_8.erl @@ -0,0 +1,15 @@ +-module(yes_8). +-compile(export_all). + +?MODULE() -> + ok. + +%% Cover use of floating point registers. + +f(Pid, X) when is_float(X) -> + Ref = make_ref(), + Pid ! {X+3}, + receive + Ref -> + ok + end. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_9.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_9.erl new file mode 100644 index 0000000000..97fce5e734 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_9.erl @@ -0,0 +1,13 @@ +-module(yes_9). +-compile(export_all). + +?MODULE() -> + ok. + +f(Fun) -> + Ref = make_ref(), + Fun(), + receive + {Ref,Reply} -> + Reply + end. -- cgit v1.2.3 From f7829c91d742f1daea27b7ff5d8dcb5f262fd3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Sat, 24 Apr 2010 07:57:44 +0200 Subject: compiler tests: Cover the error handling code in beam_receive --- lib/compiler/test/misc_SUITE.erl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index e096571d50..df8a0ffe6f 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -154,6 +154,17 @@ silly_coverage(Config) when is_list(Config) -> {test,bs_get_binary2,{f,99},0,[{x,0},{atom,all},1,[]],{x,0}}, {block,[a|b]}]}],0}, ?line expect_error(fun() -> beam_bsm:module(BsmInput, []) end), + + %% beam_receive. + ReceiveInput = {?MODULE,[{foo,0}],[], + [{function,foo,0,2, + [{label,1}, + {func_info,{atom,?MODULE},{atom,foo},0}, + {label,2}, + {call_ext,0,{extfunc,erlang,make_ref,0}}, + {block,[a|b]}]}],0}, + ?line expect_error(fun() -> beam_receive:module(ReceiveInput, []) end), + ok. expect_error(Fun) -> -- cgit v1.2.3 From 9c91901e8e57fd6366fd966e754a62a8a205c000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 23 Apr 2010 10:04:42 +0200 Subject: erts: Implement recv_mark/1 and recv_set/1 for real The recv_mark/1 instruction will both save the current position in the message queue and a mark (the address of the loop_rec/2 instruction just following the recv_set/1 instruction). The recv_mark/1 instruction will only use the saved position if the mark is correct. The reason for saving and verifying the mark is that the compiler does not need to guarantee that no other receive instruction can be executed in between the recv_mark/1 and recv_set/1 instructions (the mark will be cleared by the remove_message/0 instruction when a message is removed from the message queue). That means that arbitrary function calls in between those instruction can be allowed. --- erts/emulator/beam/beam_emu.c | 32 ++++++++++++++++++++++++++++++++ erts/emulator/beam/erl_message.h | 8 ++++++++ erts/emulator/beam/ops.tab | 7 +++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 5b2f032afc..ee8ba54cb8 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1539,6 +1539,10 @@ void process_main(void) /* * Skeleton for receive statement: * + * recv_mark L1 Optional + * call make_ref/monitor Optional + * ... + * recv_set L1 Optional * L1: <-------------------+ * <-----------+ | * | | @@ -1557,6 +1561,34 @@ void process_main(void) * */ + OpCase(recv_mark_f): { + /* + * Save the current position in message buffer and the + * the label for the loop_rec/2 instruction for the + * the receive statement. + */ + c_p->msg.mark = (BeamInstr *) Arg(0); + c_p->msg.saved_last = c_p->msg.last; + Next(1); + } + + OpCase(i_recv_set): { + /* + * If the mark is valid (points to the loop_rec/2 + * instruction that follows), we know that the saved + * position points to the first message that could + * possibly be matched out. + * + * If the mark is invalid, we do nothing, meaning that + * we will look through all messages in the message queue. + */ + if (c_p->msg.mark == (BeamInstr *) (I+1)) { + c_p->msg.save = c_p->msg.saved_last; + } + I++; + /* Fall through to the loop_rec/2 instruction */ + } + /* * Pick up the next message and place it in x(0). * If no message, jump to a wait or wait_timeout instruction. diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index 459c6363aa..489dee7b37 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -75,6 +75,13 @@ typedef struct { ErlMessage** last; /* point to the last next pointer */ ErlMessage** save; int len; /* queue length */ + + /* + * The following two fields are used by the recv_mark/1 and + * recv_set/1 instructions. + */ + BeamInstr* mark; /* address to rec_loop/2 instruction */ + ErlMessage** saved_last; /* saved last pointer */ } ErlMessageQueue; #ifdef ERTS_SMP @@ -137,6 +144,7 @@ do { \ (p)->msg.len--; \ if (__mp == NULL) \ (p)->msg.last = (p)->msg.save; \ + (p)->msg.mark = 0; \ } while(0) /* Reset message save point (after receive match) */ diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index ef6062203e..49280a60e0 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1425,5 +1425,8 @@ on_load # # R14A. # -recv_mark Lbl => -recv_set Lbl => +recv_mark f + +recv_set Fail | label Lbl | loop_rec Lf Reg => \ + i_recv_set | label Lbl | loop_rec Lf Reg +i_recv_set -- cgit v1.2.3 From cdd4f992ec0c64c086255f87f1c6282d2a0a7a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 10 May 2010 07:19:53 +0200 Subject: Update primary bootstrap --- bootstrap/bin/start.script | 2 +- bootstrap/bin/start_clean.script | 2 +- bootstrap/lib/compiler/ebin/beam_disasm.beam | Bin 23216 -> 23300 bytes bootstrap/lib/compiler/ebin/beam_opcodes.beam | Bin 6652 -> 6748 bytes bootstrap/lib/compiler/ebin/beam_receive.beam | Bin 0 -> 5388 bytes bootstrap/lib/compiler/ebin/beam_validator.beam | Bin 31480 -> 31536 bytes bootstrap/lib/compiler/ebin/compile.beam | Bin 31748 -> 31804 bytes bootstrap/lib/compiler/ebin/compiler.app | 11 +- bootstrap/lib/compiler/egen/beam_opcodes.erl | 8 +- bootstrap/lib/compiler/egen/core_parse.erl | 6 +- bootstrap/lib/kernel/ebin/code_server.beam | Bin 23784 -> 23788 bytes bootstrap/lib/kernel/ebin/global.beam | Bin 29500 -> 29508 bytes bootstrap/lib/kernel/ebin/inet_gethost_native.beam | Bin 9716 -> 9724 bytes bootstrap/lib/kernel/ebin/pg2.beam | Bin 6948 -> 6956 bytes bootstrap/lib/stdlib/ebin/epp.beam | Bin 21920 -> 21924 bytes bootstrap/lib/stdlib/ebin/gen.beam | Bin 3456 -> 3408 bytes bootstrap/lib/stdlib/ebin/gen_server.beam | Bin 11716 -> 11720 bytes bootstrap/lib/stdlib/egen/erl_parse.erl | 174 ++++++++++----------- 18 files changed, 104 insertions(+), 99 deletions(-) create mode 100644 bootstrap/lib/compiler/ebin/beam_receive.beam diff --git a/bootstrap/bin/start.script b/bootstrap/bin/start.script index 590af335ce..08ed9939f7 100644 --- a/bootstrap/bin/start.script +++ b/bootstrap/bin/start.script @@ -1,4 +1,4 @@ -%% script generated at {2010,5,10} {6,51,10} +%% script generated at {2010,5,11} {9,2,55} {script, {"OTP APN 181 01","R14A"}, [{preLoaded, diff --git a/bootstrap/bin/start_clean.script b/bootstrap/bin/start_clean.script index 590af335ce..08ed9939f7 100644 --- a/bootstrap/bin/start_clean.script +++ b/bootstrap/bin/start_clean.script @@ -1,4 +1,4 @@ -%% script generated at {2010,5,10} {6,51,10} +%% script generated at {2010,5,11} {9,2,55} {script, {"OTP APN 181 01","R14A"}, [{preLoaded, diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam index c1fe43b398..b58b44c68c 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_disasm.beam and b/bootstrap/lib/compiler/ebin/beam_disasm.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_opcodes.beam b/bootstrap/lib/compiler/ebin/beam_opcodes.beam index 34327c700e..8c5378e05e 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_opcodes.beam and b/bootstrap/lib/compiler/ebin/beam_opcodes.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam new file mode 100644 index 0000000000..ef7afd8113 Binary files /dev/null and b/bootstrap/lib/compiler/ebin/beam_receive.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam index 2edf5f226e..e04c9efa69 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_validator.beam and b/bootstrap/lib/compiler/ebin/beam_validator.beam differ diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam index f989cdc1df..3d44822af6 100644 Binary files a/bootstrap/lib/compiler/ebin/compile.beam and b/bootstrap/lib/compiler/ebin/compile.beam differ diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index 497d1873d8..28f6143d59 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -1,19 +1,19 @@ % This is an -*- erlang -*- file. %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% {application, compiler, @@ -33,6 +33,7 @@ beam_listing, beam_opcodes, beam_peep, + beam_receive, beam_trim, beam_type, beam_utils, diff --git a/bootstrap/lib/compiler/egen/beam_opcodes.erl b/bootstrap/lib/compiler/egen/beam_opcodes.erl index 83cdaa4d48..05587800b4 100644 --- a/bootstrap/lib/compiler/egen/beam_opcodes.erl +++ b/bootstrap/lib/compiler/egen/beam_opcodes.erl @@ -8,7 +8,7 @@ -spec format_number() -> 0. format_number() -> 0. --spec opcode(atom(), 0..8) -> 1..149. +-spec opcode(atom(), 0..8) -> 1..151. opcode(label, 1) -> 1; opcode(func_info, 3) -> 2; opcode(int_code_end, 0) -> 3; @@ -158,9 +158,11 @@ opcode(bs_utf16_size, 3) -> 146; opcode(bs_put_utf16, 3) -> 147; opcode(bs_put_utf32, 3) -> 148; opcode(on_load, 0) -> 149; +opcode(recv_mark, 1) -> 150; +opcode(recv_set, 1) -> 151; opcode(Name, Arity) -> erlang:error(badarg, [Name,Arity]). --spec opname(1..149) -> {atom(),0..8}. +-spec opname(1..151) -> {atom(),0..8}. opname(1) -> {label,1}; opname(2) -> {func_info,3}; opname(3) -> {int_code_end,0}; @@ -310,4 +312,6 @@ opname(146) -> {bs_utf16_size,3}; opname(147) -> {bs_put_utf16,3}; opname(148) -> {bs_put_utf32,3}; opname(149) -> {on_load,0}; +opname(150) -> {recv_mark,1}; +opname(151) -> {recv_set,1}; opname(Number) -> erlang:error(badarg, [Number]). diff --git a/bootstrap/lib/compiler/egen/core_parse.erl b/bootstrap/lib/compiler/egen/core_parse.erl index 05624beb14..02b3458ebb 100644 --- a/bootstrap/lib/compiler/egen/core_parse.erl +++ b/bootstrap/lib/compiler/egen/core_parse.erl @@ -13,11 +13,11 @@ tok_val(T) -> element(3, T). tok_line(T) -> element(2, T). --file("/usr/local/otp/releases/sles10_32_R13B04_patched/lib/parsetools-2.0.2/include/yeccpre.hrl", 0). +-file("/usr/local/lib/erlang/lib/parsetools-2.0.2/include/yeccpre.hrl", 0). %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -194,7 +194,7 @@ yecctoken2string(Other) -> --file("/clearcase/otp/erts/bootstrap/lib/compiler/egen/core_parse.erl", 197). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/compiler/egen/core_parse.erl", 197). yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam index 894e6ca2ea..5bf9b13367 100644 Binary files a/bootstrap/lib/kernel/ebin/code_server.beam and b/bootstrap/lib/kernel/ebin/code_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam index b16334d8a2..4dc43450f0 100644 Binary files a/bootstrap/lib/kernel/ebin/global.beam and b/bootstrap/lib/kernel/ebin/global.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam index b46fd6ba87..e712d25405 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam and b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam differ diff --git a/bootstrap/lib/kernel/ebin/pg2.beam b/bootstrap/lib/kernel/ebin/pg2.beam index 38870b0f43..51912f2263 100644 Binary files a/bootstrap/lib/kernel/ebin/pg2.beam and b/bootstrap/lib/kernel/ebin/pg2.beam differ diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam index e9a9d4a8f0..71e0d21db1 100644 Binary files a/bootstrap/lib/stdlib/ebin/epp.beam and b/bootstrap/lib/stdlib/ebin/epp.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam index bf09b84de6..4b047eb838 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen.beam and b/bootstrap/lib/stdlib/ebin/gen.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam index f3373cf593..8d76d138f1 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen_server.beam and b/bootstrap/lib/stdlib/ebin/gen_server.beam differ diff --git a/bootstrap/lib/stdlib/egen/erl_parse.erl b/bootstrap/lib/stdlib/egen/erl_parse.erl index 8c215d81c0..86f116f1ac 100644 --- a/bootstrap/lib/stdlib/egen/erl_parse.erl +++ b/bootstrap/lib/stdlib/egen/erl_parse.erl @@ -547,11 +547,11 @@ get_attribute(L, Name) -> get_attributes(L) -> erl_scan:attributes_info(L). --file("/usr/local/otp/releases/sles10_32_R13B04_patched/lib/parsetools-2.0.2/include/yeccpre.hrl", 0). +-file("/usr/local/lib/erlang/lib/parsetools-2.0.2/include/yeccpre.hrl", 0). %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -728,7 +728,7 @@ yecctoken2string(Other) -> --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 731). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 731). yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); @@ -7636,7 +7636,7 @@ yeccpars2_39_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7639). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7639). -compile({inline,yeccpars2_46_/1}). -file("erl_parse.yrl", 423). yeccpars2_46_(__Stack0) -> @@ -7645,7 +7645,7 @@ yeccpars2_46_(__Stack0) -> { [ ] , ? line ( __1 ) } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7648). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7648). -compile({inline,yeccpars2_70_/1}). -file("erl_parse.yrl", 314). yeccpars2_70_(__Stack0) -> @@ -7654,7 +7654,7 @@ yeccpars2_70_(__Stack0) -> { tuple , ? line ( __1 ) , [ ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7657). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7657). -compile({inline,yeccpars2_71_/1}). -file("erl_parse.yrl", 315). yeccpars2_71_(__Stack0) -> @@ -7663,7 +7663,7 @@ yeccpars2_71_(__Stack0) -> { tuple , ? line ( __1 ) , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7666). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7666). -compile({inline,yeccpars2_73_/1}). -file("erl_parse.yrl", 397). yeccpars2_73_(__Stack0) -> @@ -7695,7 +7695,7 @@ yeccpars2_81_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7698). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7698). -compile({inline,yeccpars2_82_/1}). -file("erl_parse.yrl", 395). yeccpars2_82_(__Stack0) -> @@ -7728,7 +7728,7 @@ yeccpars2_88_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7731). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7731). -compile({inline,yeccpars2_89_/1}). -file("erl_parse.yrl", 370). yeccpars2_89_(__Stack0) -> @@ -7767,7 +7767,7 @@ yeccpars2_98_(__Stack0) -> [ ] end | __Stack0]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7770). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7770). -compile({inline,yeccpars2_100_/1}). -file("erl_parse.yrl", 416). yeccpars2_100_(__Stack0) -> @@ -7784,7 +7784,7 @@ yeccpars2_102_(__Stack0) -> [ ] end | __Stack0]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7787). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7787). -compile({inline,yeccpars2_104_/1}). -file("erl_parse.yrl", 413). yeccpars2_104_(__Stack0) -> @@ -7794,7 +7794,7 @@ yeccpars2_104_(__Stack0) -> { clause , L , [ { tuple , L , [ __1 , __3 , { var , L , '_' } ] } ] , __4 , __5 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7797). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7797). -compile({inline,yeccpars2_106_/1}). -file("erl_parse.yrl", 410). yeccpars2_106_(__Stack0) -> @@ -7836,7 +7836,7 @@ yeccpars2_114_(__Stack0) -> { [ ] , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7839). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7839). -compile({inline,yeccpars2_115_/1}). -file("erl_parse.yrl", 441). yeccpars2_115_(__Stack0) -> @@ -7845,7 +7845,7 @@ yeccpars2_115_(__Stack0) -> { string , ? line ( __1 ) , element ( 3 , __1 ) ++ element ( 3 , __2 ) } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7848). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7848). -compile({inline,yeccpars2_120_/1}). -file("erl_parse.yrl", 375). yeccpars2_120_(__Stack0) -> @@ -7854,7 +7854,7 @@ yeccpars2_120_(__Stack0) -> { 'receive' , ? line ( __1 ) , [ ] , __3 , __4 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7857). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7857). -compile({inline,yeccpars2_122_/1}). -file("erl_parse.yrl", 373). yeccpars2_122_(__Stack0) -> @@ -7863,7 +7863,7 @@ yeccpars2_122_(__Stack0) -> { 'receive' , ? line ( __1 ) , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7866). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7866). -compile({inline,yeccpars2_125_/1}). -file("erl_parse.yrl", 377). yeccpars2_125_(__Stack0) -> @@ -7880,7 +7880,7 @@ yeccpars2_131_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7883). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7883). -compile({inline,yeccpars2_135_/1}). -file("erl_parse.yrl", 312). yeccpars2_135_(__Stack0) -> @@ -7889,7 +7889,7 @@ yeccpars2_135_(__Stack0) -> { b_generate , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7892). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7892). -compile({inline,yeccpars2_137_/1}). -file("erl_parse.yrl", 311). yeccpars2_137_(__Stack0) -> @@ -7906,7 +7906,7 @@ yeccpars2_139_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7909). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7909). -compile({inline,yeccpars2_140_/1}). -file("erl_parse.yrl", 304). yeccpars2_140_(__Stack0) -> @@ -7915,7 +7915,7 @@ yeccpars2_140_(__Stack0) -> { lc , ? line ( __1 ) , __2 , __4 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7918). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7918). -compile({inline,yeccpars2_141_/1}). -file("erl_parse.yrl", 420). yeccpars2_141_(__Stack0) -> @@ -7932,7 +7932,7 @@ yeccpars2_143_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7935). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7935). -compile({inline,yeccpars2_145_/1}). -file("erl_parse.yrl", 360). yeccpars2_145_(__Stack0) -> @@ -7949,7 +7949,7 @@ yeccpars2_147_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7952). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7952). -compile({inline,yeccpars2_148_/1}). -file("erl_parse.yrl", 354). yeccpars2_148_(__Stack0) -> @@ -7973,7 +7973,7 @@ yeccpars2_151_(__Stack0) -> [ ] end | __Stack0]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7976). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7976). -compile({inline,yeccpars2_157_/1}). -file("erl_parse.yrl", 383). yeccpars2_157_(__Stack0) -> @@ -7982,7 +7982,7 @@ yeccpars2_157_(__Stack0) -> { 'fun' , ? line ( __1 ) , { function , element ( 3 , __2 ) , element ( 3 , __4 ) , element ( 3 , __6 ) } } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7985). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7985). -compile({inline,yeccpars2_158_/1}). -file("erl_parse.yrl", 381). yeccpars2_158_(__Stack0) -> @@ -8008,7 +8008,7 @@ yeccpars2_162_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8011). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8011). -compile({inline,yeccpars2_163_/1}). -file("erl_parse.yrl", 385). yeccpars2_163_(__Stack0) -> @@ -8017,7 +8017,7 @@ yeccpars2_163_(__Stack0) -> build_fun ( ? line ( __1 ) , __2 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8020). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8020). -compile({inline,yeccpars2_164_/1}). -file("erl_parse.yrl", 203). yeccpars2_164_(__Stack0) -> @@ -8026,7 +8026,7 @@ yeccpars2_164_(__Stack0) -> { 'catch' , ? line ( __1 ) , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8029). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8029). -compile({inline,yeccpars2_168_/1}). -file("erl_parse.yrl", 364). yeccpars2_168_(__Stack0) -> @@ -8035,7 +8035,7 @@ yeccpars2_168_(__Stack0) -> { 'case' , ? line ( __1 ) , __2 , __4 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8038). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8038). -compile({inline,yeccpars2_170_/1}). -file("erl_parse.yrl", 259). yeccpars2_170_(__Stack0) -> @@ -8044,7 +8044,7 @@ yeccpars2_170_(__Stack0) -> { block , ? line ( __1 ) , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8047). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8047). -compile({inline,yeccpars2_172_/1}). -file("erl_parse.yrl", 268). yeccpars2_172_(__Stack0) -> @@ -8053,7 +8053,7 @@ yeccpars2_172_(__Stack0) -> { nil , ? line ( __1 ) } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8056). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8056). -compile({inline,yeccpars2_173_/1}). -file("erl_parse.yrl", 269). yeccpars2_173_(__Stack0) -> @@ -8062,7 +8062,7 @@ yeccpars2_173_(__Stack0) -> { cons , ? line ( __1 ) , __2 , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8065). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8065). -compile({inline,yeccpars2_175_/1}). -file("erl_parse.yrl", 271). yeccpars2_175_(__Stack0) -> @@ -8079,7 +8079,7 @@ yeccpars2_178_(__Stack0) -> __2 end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8082). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8082). -compile({inline,yeccpars2_180_/1}). -file("erl_parse.yrl", 273). yeccpars2_180_(__Stack0) -> @@ -8103,7 +8103,7 @@ yeccpars2_186_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8106). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8106). -compile({inline,yeccpars2_187_/1}). -file("erl_parse.yrl", 276). yeccpars2_187_(__Stack0) -> @@ -8120,7 +8120,7 @@ yeccpars2_189_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8123). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8123). -compile({inline,yeccpars2_190_/1}). -file("erl_parse.yrl", 277). yeccpars2_190_(__Stack0) -> @@ -8129,7 +8129,7 @@ yeccpars2_190_(__Stack0) -> { bin , ? line ( __1 ) , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8132). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8132). -compile({inline,yeccpars2_193_/1}). -file("erl_parse.yrl", 306). yeccpars2_193_(__Stack0) -> @@ -8153,7 +8153,7 @@ yeccpars2_197_(__Stack0) -> __2 end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8156). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8156). -compile({inline,yeccpars2_198_/1}). -file("erl_parse.yrl", 283). yeccpars2_198_(__Stack0) -> @@ -8202,7 +8202,7 @@ yeccpars2_206_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8205). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8205). -compile({inline,yeccpars2_207_/1}). -file("erl_parse.yrl", 285). yeccpars2_207_(__Stack0) -> @@ -8211,7 +8211,7 @@ yeccpars2_207_(__Stack0) -> ? mkop1 ( __1 , __2 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8214). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8214). -compile({inline,yeccpars2_208_/1}). -file("erl_parse.yrl", 245). yeccpars2_208_(__Stack0) -> @@ -8228,7 +8228,7 @@ yeccpars2_210_(__Stack0) -> __2 end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8231). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8231). -compile({inline,yeccpars2_212_/1}). -file("erl_parse.yrl", 329). yeccpars2_212_(__Stack0) -> @@ -8253,7 +8253,7 @@ yeccpars2_219_(__Stack0) -> [ ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8256). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8256). -compile({inline,yeccpars2_221_/1}). -file("erl_parse.yrl", 345). yeccpars2_221_(__Stack0) -> @@ -8262,7 +8262,7 @@ yeccpars2_221_(__Stack0) -> { record_field , ? line ( __1 ) , __1 , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8265). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8265). -compile({inline,yeccpars2_223_/1}). -file("erl_parse.yrl", 346). yeccpars2_223_(__Stack0) -> @@ -8287,7 +8287,7 @@ yeccpars2_226_(__Stack0) -> __2 end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8290). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8290). -compile({inline,yeccpars2_227_/1}). -file("erl_parse.yrl", 327). yeccpars2_227_(__Stack0) -> @@ -8304,7 +8304,7 @@ yeccpars2_229_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8307). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8307). -compile({inline,yeccpars2_232_/1}). -file("erl_parse.yrl", 206). yeccpars2_232_(__Stack0) -> @@ -8313,7 +8313,7 @@ yeccpars2_232_(__Stack0) -> { match , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8316). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8316). -compile({inline,yeccpars2_233_/1}). -file("erl_parse.yrl", 207). yeccpars2_233_(__Stack0) -> @@ -8322,7 +8322,7 @@ yeccpars2_233_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8325). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8325). -compile({inline,yeccpars2_235_/1}). -file("erl_parse.yrl", 210). yeccpars2_235_(__Stack0) -> @@ -8331,7 +8331,7 @@ yeccpars2_235_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8334). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8334). -compile({inline,yeccpars2_237_/1}). -file("erl_parse.yrl", 213). yeccpars2_237_(__Stack0) -> @@ -8340,7 +8340,7 @@ yeccpars2_237_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8343). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8343). -compile({inline,yeccpars2_247_/1}). -file("erl_parse.yrl", 217). yeccpars2_247_(__Stack0) -> @@ -8349,7 +8349,7 @@ yeccpars2_247_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8352). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8352). -compile({inline,yeccpars2_260_/1}). -file("erl_parse.yrl", 225). yeccpars2_260_(__Stack0) -> @@ -8358,7 +8358,7 @@ yeccpars2_260_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8361). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8361). -compile({inline,yeccpars2_268_/1}). -file("erl_parse.yrl", 229). yeccpars2_268_(__Stack0) -> @@ -8367,7 +8367,7 @@ yeccpars2_268_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8370). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8370). -compile({inline,yeccpars2_269_/1}). -file("erl_parse.yrl", 221). yeccpars2_269_(__Stack0) -> @@ -8376,7 +8376,7 @@ yeccpars2_269_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8379). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8379). -compile({inline,yeccpars2_270_/1}). -file("erl_parse.yrl", 351). yeccpars2_270_(__Stack0) -> @@ -8385,7 +8385,7 @@ yeccpars2_270_(__Stack0) -> { call , ? line ( __1 ) , __1 , element ( 1 , __2 ) } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8388). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8388). -compile({inline,yeccpars2_273_/1}). -file("erl_parse.yrl", 241). yeccpars2_273_(__Stack0) -> @@ -8394,7 +8394,7 @@ yeccpars2_273_(__Stack0) -> { remote , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8397). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8397). -compile({inline,yeccpars2_274_/1}). -file("erl_parse.yrl", 247). yeccpars2_274_(__Stack0) -> @@ -8403,7 +8403,7 @@ yeccpars2_274_(__Stack0) -> { record_field , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8406). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8406). -compile({inline,yeccpars2_277_/1}). -file("erl_parse.yrl", 333). yeccpars2_277_(__Stack0) -> @@ -8412,7 +8412,7 @@ yeccpars2_277_(__Stack0) -> { record , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __4 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8415). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8415). -compile({inline,yeccpars2_279_/1}). -file("erl_parse.yrl", 331). yeccpars2_279_(__Stack0) -> @@ -8421,7 +8421,7 @@ yeccpars2_279_(__Stack0) -> { record_field , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __5 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8424). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8424). -compile({inline,yeccpars2_280_/1}). -file("erl_parse.yrl", 424). yeccpars2_280_(__Stack0) -> @@ -8430,7 +8430,7 @@ yeccpars2_280_(__Stack0) -> { __2 , ? line ( __1 ) } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8433). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8433). -compile({inline,yeccpars2_281_/1}). -file("erl_parse.yrl", 233). yeccpars2_281_(__Stack0) -> @@ -8439,7 +8439,7 @@ yeccpars2_281_(__Stack0) -> ? mkop1 ( __1 , __2 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8442). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8442). -compile({inline,yeccpars2_284_/1}). -file("erl_parse.yrl", 337). yeccpars2_284_(__Stack0) -> @@ -8448,7 +8448,7 @@ yeccpars2_284_(__Stack0) -> { record , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __4 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8451). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8451). -compile({inline,yeccpars2_286_/1}). -file("erl_parse.yrl", 335). yeccpars2_286_(__Stack0) -> @@ -8457,7 +8457,7 @@ yeccpars2_286_(__Stack0) -> { record_field , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __5 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8460). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8460). -compile({inline,yeccpars2_288_/1}). -file("erl_parse.yrl", 482). yeccpars2_288_(__Stack0) -> @@ -8466,7 +8466,7 @@ yeccpars2_288_(__Stack0) -> { clause , ? line ( __1 ) , element ( 3 , __1 ) , __2 , __3 , __4 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8469). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8469). -compile({inline,yeccpars2_289_/1}). -file("erl_parse.yrl", 192). yeccpars2_289_(__Stack0) -> @@ -8531,7 +8531,7 @@ yeccpars2_314_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8534). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8534). -compile({inline,yeccpars2_329_/1}). -file("erl_parse.yrl", 135). yeccpars2_329_(__Stack0) -> @@ -8540,7 +8540,7 @@ yeccpars2_329_(__Stack0) -> { type , ? line ( __1 ) , tuple , [ ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8543). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8543). -compile({inline,yeccpars2_330_/1}). -file("erl_parse.yrl", 136). yeccpars2_330_(__Stack0) -> @@ -8549,7 +8549,7 @@ yeccpars2_330_(__Stack0) -> { type , ? line ( __1 ) , tuple , __2 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8552). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8552). -compile({inline,yeccpars2_332_/1}). -file("erl_parse.yrl", 115). yeccpars2_332_(__Stack0) -> @@ -8558,7 +8558,7 @@ yeccpars2_332_(__Stack0) -> { ann_type , ? line ( __1 ) , [ __1 , __3 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8561). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8561). -compile({inline,yeccpars2_338_/1}). -file("erl_parse.yrl", 144). yeccpars2_338_(__Stack0) -> @@ -8567,7 +8567,7 @@ yeccpars2_338_(__Stack0) -> { type , ? line ( __1 ) , 'fun' , [ ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8570). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8570). -compile({inline,yeccpars2_344_/1}). -file("erl_parse.yrl", 152). yeccpars2_344_(__Stack0) -> @@ -8585,7 +8585,7 @@ yeccpars2_345_(__Stack0) -> __3 end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8588). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8588). -compile({inline,yeccpars2_351_/1}). -file("erl_parse.yrl", 127). yeccpars2_351_(__Stack0) -> @@ -8595,7 +8595,7 @@ yeccpars2_351_(__Stack0) -> [ __1 , __3 , [ ] ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8598). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8598). -compile({inline,yeccpars2_352_/1}). -file("erl_parse.yrl", 129). yeccpars2_352_(__Stack0) -> @@ -8613,7 +8613,7 @@ yeccpars2_354_(__Stack0) -> build_gen_type ( __1 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8616). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8616). -compile({inline,yeccpars2_355_/1}). -file("erl_parse.yrl", 125). yeccpars2_355_(__Stack0) -> @@ -8623,7 +8623,7 @@ yeccpars2_355_(__Stack0) -> normalise ( __1 ) , __3 } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8626). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8626). -compile({inline,yeccpars2_357_/1}). -file("erl_parse.yrl", 131). yeccpars2_357_(__Stack0) -> @@ -8632,7 +8632,7 @@ yeccpars2_357_(__Stack0) -> { type , ? line ( __1 ) , nil , [ ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8635). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8635). -compile({inline,yeccpars2_359_/1}). -file("erl_parse.yrl", 132). yeccpars2_359_(__Stack0) -> @@ -8641,7 +8641,7 @@ yeccpars2_359_(__Stack0) -> { type , ? line ( __1 ) , list , [ __2 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8644). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8644). -compile({inline,yeccpars2_363_/1}). -file("erl_parse.yrl", 133). yeccpars2_363_(__Stack0) -> @@ -8651,7 +8651,7 @@ yeccpars2_363_(__Stack0) -> nonempty_list , [ __2 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8654). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8654). -compile({inline,yeccpars2_366_/1}). -file("erl_parse.yrl", 168). yeccpars2_366_(__Stack0) -> @@ -8678,7 +8678,7 @@ yeccpars2_372_(__Stack0) -> build_bin_type ( [ __1 , __3 ] , __5 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8681). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8681). -compile({inline,yeccpars2_374_/1}). -file("erl_parse.yrl", 171). yeccpars2_374_(__Stack0) -> @@ -8688,7 +8688,7 @@ yeccpars2_374_(__Stack0) -> [ __2 , abstract ( 0 , ? line ( __1 ) ) ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8691). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8691). -compile({inline,yeccpars2_378_/1}). -file("erl_parse.yrl", 176). yeccpars2_378_(__Stack0) -> @@ -8697,7 +8697,7 @@ yeccpars2_378_(__Stack0) -> { type , ? line ( __1 ) , binary , [ __2 , __4 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8700). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8700). -compile({inline,yeccpars2_379_/1}). -file("erl_parse.yrl", 173). yeccpars2_379_(__Stack0) -> @@ -8707,7 +8707,7 @@ yeccpars2_379_(__Stack0) -> [ abstract ( 0 , ? line ( __1 ) ) , __2 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8710). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8710). -compile({inline,yeccpars2_380_/1}). -file("erl_parse.yrl", 148). yeccpars2_380_(__Stack0) -> @@ -8717,7 +8717,7 @@ yeccpars2_380_(__Stack0) -> ? line ( __2 ) ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8720). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8720). -compile({inline,yeccpars2_382_/1}). -file("erl_parse.yrl", 156). yeccpars2_382_(__Stack0) -> @@ -8727,7 +8727,7 @@ yeccpars2_382_(__Stack0) -> [ { type , ? line ( __1 ) , product , [ ] } , __4 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8730). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8730). -compile({inline,yeccpars2_384_/1}). -file("erl_parse.yrl", 121). yeccpars2_384_(__Stack0) -> @@ -8744,7 +8744,7 @@ yeccpars2_388_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8747). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8747). -compile({inline,yeccpars2_390_/1}). -file("erl_parse.yrl", 137). yeccpars2_390_(__Stack0) -> @@ -8753,7 +8753,7 @@ yeccpars2_390_(__Stack0) -> { type , ? line ( __1 ) , record , [ __2 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8756). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8756). -compile({inline,yeccpars2_392_/1}). -file("erl_parse.yrl", 165). yeccpars2_392_(__Stack0) -> @@ -8771,7 +8771,7 @@ yeccpars2_394_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8774). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8774). -compile({inline,yeccpars2_395_/1}). -file("erl_parse.yrl", 138). yeccpars2_395_(__Stack0) -> @@ -8781,7 +8781,7 @@ yeccpars2_395_(__Stack0) -> record , [ __2 | __4 ] } end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8784). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8784). -compile({inline,yeccpars2_398_/1}). -file("erl_parse.yrl", 142). yeccpars2_398_(__Stack0) -> @@ -8799,7 +8799,7 @@ yeccpars2_400_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8802). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8802). -compile({inline,yeccpars2_403_/1}). -file("erl_parse.yrl", 159). yeccpars2_403_(__Stack0) -> @@ -8817,7 +8817,7 @@ yeccpars2_405_(__Stack0) -> lift_unions ( __1 , __3 ) end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8820). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8820). -compile({inline,yeccpars2_407_/1}). -file("erl_parse.yrl", 103). yeccpars2_407_(__Stack0) -> @@ -8835,7 +8835,7 @@ yeccpars2_408_(__Stack0) -> [ __1 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8838). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8838). -compile({inline,yeccpars2_412_/1}). -file("erl_parse.yrl", 109). yeccpars2_412_(__Stack0) -> @@ -8965,7 +8965,7 @@ yeccpars2_440_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8968). +-file("/Users/bjorng/Downloads/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8968). -compile({inline,yeccpars2_441_/1}). -file("erl_parse.yrl", 90). yeccpars2_441_(__Stack0) -> -- cgit v1.2.3 From c8c736e24cd92f1ec36645fe69deb48bea56b50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 23 Apr 2010 11:46:53 +0200 Subject: erts: Add tests for the receive optimization --- erts/emulator/test/Makefile | 1 + erts/emulator/test/receive_SUITE.erl | 113 +++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 erts/emulator/test/receive_SUITE.erl diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index df2faf1450..2424fedbed 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -81,6 +81,7 @@ MODULES= \ port_bif_SUITE \ process_SUITE \ pseudoknot_SUITE \ + receive_SUITE \ ref_SUITE \ register_SUITE \ save_calls_SUITE \ diff --git a/erts/emulator/test/receive_SUITE.erl b/erts/emulator/test/receive_SUITE.erl new file mode 100644 index 0000000000..40ebf2bd21 --- /dev/null +++ b/erts/emulator/test/receive_SUITE.erl @@ -0,0 +1,113 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(receive_SUITE). + +%% Tests receive after. + +-include("test_server.hrl"). + +-export([all/1, + call_with_huge_message_queue/1,receive_in_between/1]). + +-export([init_per_testcase/2,fin_per_testcase/2]). + +all(suite) -> + [call_with_huge_message_queue,receive_in_between]. + +init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> + Dog=?t:timetrap(?t:minutes(3)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Func, Config) -> + Dog=?config(watchdog, Config), + ?t:timetrap_cancel(Dog). + +call_with_huge_message_queue(Config) when is_list(Config) -> + ?line Pid = spawn_link(fun echo_loop/0), + + ?line {Time,ok} = tc(fun() -> calls(10, Pid) end), + + ?line [self() ! {msg,N} || N <- lists:seq(1, 500000)], + erlang:garbage_collect(), + ?line {NewTime,ok} = tc(fun() -> calls(10, Pid) end), + io:format("Time for empty message queue: ~p", [Time]), + io:format("Time for huge message queue: ~p", [NewTime]), + + case (NewTime+1) / (Time+1) of + Q when Q < 10 -> + ok; + Q -> + io:format("Q = ~p", [Q]), + ?line ?t:fail() + end, + ok. + +calls(0, _) -> ok; +calls(N, Pid) -> + {ok,{ultimate_answer,42}} = call(Pid, {ultimate_answer,42}), + calls(N-1, Pid). + +call(Pid, Msg) -> + Mref = erlang:monitor(process, Pid), + Pid ! {Mref,{self(),Msg}}, + receive + {Mref, Reply} -> + erlang:demonitor(Mref, [flush]), + {ok, Reply}; + {'DOWN', Mref, _, _, Reason} -> + exit(Reason) + end. + +receive_in_between(Config) when is_list(Config) -> + ?line Pid = spawn_link(fun echo_loop/0), + ?line [{ok,{a,b}} = call2(Pid, {a,b}) || _ <- lists:seq(1, 100000)], + ok. + +call2(Pid, Msg) -> + self() ! dummy, + Mref = erlang:monitor(process, Pid), + Pid ! {Mref,{self(),Msg}}, + receive_one(), + receive + {Mref,Reply} -> + erlang:demonitor(Mref, [flush]), + {ok,Reply}; + {'DOWN',Mref,_,_,Reason} -> + exit(Reason) + end. + +receive_one() -> + receive + dummy -> ok + end. + +%%% +%%% Common helpers. +%%% + +echo_loop() -> + receive + {Ref,{Pid,Msg}} -> + Pid ! {Ref,Msg}, + echo_loop() + end. + +tc(Fun) -> + timer:tc(erlang, apply, [Fun,[]]). -- cgit v1.2.3 From 84f65232d00de87042b11b07db4dad30cc7e1fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 23 Apr 2010 12:02:12 +0200 Subject: Test that gen_server:call/2,3 are fast even with a huge message queue --- lib/stdlib/test/gen_server_SUITE.erl | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 6efdce78a1..f753ebc534 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -30,7 +30,8 @@ call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1, spec_init_local_registered_parent/1, spec_init_global_registered_parent/1, - otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1 + otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1, + call_with_huge_message_queue/1 ]). % spawn export @@ -51,7 +52,8 @@ all(suite) -> call_remote_n2, call_remote_n3, spec_init, spec_init_local_registered_parent, spec_init_global_registered_parent, - otp_5854, hibernate, otp_7669, call_format_status]. + otp_5854, hibernate, otp_7669, call_format_status, + call_with_huge_message_queue]. -define(default_timeout, ?t:minutes(1)). @@ -904,6 +906,45 @@ call_format_status(Config) when is_list(Config) -> ?line [format_status_called | _] = lists:reverse(Data2), ok. +%% Test that the time for a huge message queue is not +%% significantly slower than with an empty message queue. +call_with_huge_message_queue(Config) when is_list(Config) -> + ?line Pid = spawn_link(fun echo_loop/0), + + ?line {Time,ok} = tc(fun() -> calls(10, Pid) end), + + ?line [self() ! {msg,N} || N <- lists:seq(1, 500000)], + erlang:garbage_collect(), + ?line {NewTime,ok} = tc(fun() -> calls(10, Pid) end), + io:format("Time for empty message queue: ~p", [Time]), + io:format("Time for huge message queue: ~p", [NewTime]), + + case (NewTime+1) / (Time+1) of + Q when Q < 10 -> + ok; + Q -> + io:format("Q = ~p", [Q]), + ?line ?t:fail() + end, + ok. + +calls(0, _) -> ok; +calls(N, Pid) -> + {ultimate_answer,42} = call(Pid, {ultimate_answer,42}), + calls(N-1, Pid). + +call(Pid, Msg) -> + gen_server:call(Pid, Msg, infinity). + +tc(Fun) -> + timer:tc(erlang, apply, [Fun,[]]). + +echo_loop() -> + receive + {'$gen_call',{Pid,Ref},Msg} -> + Pid ! {Ref,Msg}, + echo_loop() + end. %%-------------------------------------------------------------- %% Help functions to spec_init_* -- cgit v1.2.3