aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/beam_receive.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src/beam_receive.erl')
-rw-r--r--lib/compiler/src/beam_receive.erl54
1 files changed, 43 insertions, 11 deletions
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index bd1f44f66b..fe95a7e35b 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -84,13 +84,29 @@ function({function,Name,Arity,Entry,Is}) ->
erlang:raise(Class, Error, Stack)
end.
+opt([{call_ext,A,{extfunc,erlang,spawn_monitor,A}}=I0|Is0], D, Acc)
+ when A =:= 1; A =:= 3 ->
+ case ref_in_tuple(Is0) of
+ no ->
+ opt(Is0, D, [I0|Acc]);
+ {yes,Regs,Is1,MatchReversed} ->
+ %% 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(Is1, Regs, D) of
+ no ->
+ opt(Is0, D, [I0|Acc]);
+ {yes,Is,Lbl} ->
+ opt(Is, D, MatchReversed++[I0,{recv_mark,{f,Lbl}}|Acc])
+ end
+ 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
+ case opt_recv(Is0, regs_init_x0(), D) of
no ->
opt(Is0, D, [I|Acc]);
{yes,Is,Lbl} ->
@@ -104,19 +120,34 @@ opt([I|Is], D, Acc) ->
opt([], _, Acc) ->
reverse(Acc).
+ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
+ {test,test_arity,_,[{x,0},2]}=I2,
+ {block,[{set,[_],[{x,0}],{get_tuple_element,0}},
+ {set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
+ ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
+ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
+ {test,test_arity,_,[{x,0},2]}=I2,
+ {block,[{set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
+ ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
+ref_in_tuple(_) -> no.
+
+ref_in_tuple_1(Bl, Dst, Is, MatchReversed) ->
+ Regs0 = regs_init_singleton(Dst),
+ Regs = opt_update_regs_bl(Bl, Regs0),
+ {yes,Regs,Is,MatchReversed}.
+
%% 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]}
+%% opt_recv([Instruction], Regs, 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(),
+opt_recv(Is, Regs, D) ->
L = gb_sets:empty(),
- opt_recv(Is, D, R, L, []).
+ opt_recv(Is, D, Regs, L, []).
opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
R = regs_kill_not_live(0, R0),
@@ -157,8 +188,6 @@ 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) ->
@@ -253,10 +282,7 @@ opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
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) ->
+opt_ref_used_1([{select,_,_,{f,Fail},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) ->
@@ -323,6 +349,12 @@ opt_ref_used_bl([], Regs) -> Regs.
regs_init() ->
{0,0}.
+%% regs_init_singleton(Register) -> RegisterSet
+%% Return a set that only contains one register.
+
+regs_init_singleton(Reg) ->
+ regs_add(Reg, regs_init()).
+
%% regs_init_x0() -> RegisterSet
%% Return a set that only contains the {x,0} register.