diff options
Diffstat (limited to 'lib/compiler')
42 files changed, 1227 insertions, 219 deletions
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_asm.erl b/lib/compiler/src/beam_asm.erl index 497c4fa07b..89d64834cf 100644 --- a/lib/compiler/src/beam_asm.erl +++ b/lib/compiler/src/beam_asm.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. 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 %% 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% %% %% Purpose : Assembler for threaded Beam. @@ -23,7 +23,7 @@ -export([module/4]). -export([encode/2]). --import(lists, [map/2,member/2,keymember/3,duplicate/2,filter/2]). +-import(lists, [map/2,member/2,keymember/3,duplicate/2]). -include("beam_opcodes.hrl"). module(Code, Abst, SourceFile, Opts) -> @@ -191,11 +191,7 @@ flatten_exports(Exps) -> flatten_imports(Imps) -> list_to_binary(map(fun({M,F,A}) -> <<M:32,F:32,A:32>> end, Imps)). -build_attributes(Opts, SourceFile, Attr0, Essentials) -> - Attr = filter(fun({type,_}) -> false; - ({spec,_}) -> false; - (_) -> true - end, Attr0), +build_attributes(Opts, SourceFile, Attr, Essentials) -> Misc = case member(slim, Opts) of false -> {{Y,Mo,D},{H,Mi,S}} = erlang:universaltime(), @@ -265,7 +261,8 @@ make_op({gc_bif,Bif,Fail,Live,Args,Dest}, Dict) -> Arity = length(Args), BifOp = case Arity of 1 -> gc_bif1; - 2 -> gc_bif2 + 2 -> gc_bif2; + 3 -> gc_bif3 end, encode_op(BifOp, [Fail,Live,{extfunc,erlang,Bif,Arity}|Args++[Dest]],Dict); make_op({bs_add=Op,Fail,[Src1,Src2,Unit],Dest}, Dict) -> diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl index 32703b4dd1..9c6f835ab0 100644 --- a/lib/compiler/src/beam_block.erl +++ b/lib/compiler/src/beam_block.erl @@ -201,7 +201,6 @@ move_allocates_2(Alloc, [], Acc) -> alloc_may_pass({set,_,_,{alloc,_,_}}) -> false; alloc_may_pass({set,_,_,{set_tuple_element,_}}) -> false; alloc_may_pass({set,_,_,put_list}) -> false; -alloc_may_pass({set,_,_,{put_tuple,_}}) -> false; alloc_may_pass({set,_,_,put}) -> false; alloc_may_pass({set,_,_,_}) -> true. diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index dcc6ad4c7c..d9ea6f5a70 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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% %% %% Purpose: Optimizes booleans in guards. @@ -631,10 +631,10 @@ fetch_reg(V, [{I,V}|_]) -> {x,I}; fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs). live_regs(Regs) -> - foldl(fun ({I,_}, _) -> I; - ([], Max) -> Max end, - -1, Regs)+1. - + foldl(fun ({I,_}, _) -> + I + end, -1, Regs)+1. + %%% %%% Convert a block to Static Single Assignment (SSA) form. @@ -748,8 +748,7 @@ initialized_regs([{bs_context_to_binary,Src}|Is], Regs) -> initialized_regs([{label,_},{func_info,_,_,Arity}|_], Regs) -> InitRegs = free_vars_regs(Arity), add_init_regs(InitRegs, Regs); -initialized_regs([_|_], Regs) -> Regs; -initialized_regs([], Regs) -> Regs. +initialized_regs([_|_], Regs) -> Regs. add_init_regs([{x,_}=X|T], Regs) -> add_init_regs(T, ordsets:add_element(X, Regs)); diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl index c956f2f000..017ca129b0 100644 --- a/lib/compiler/src/beam_disasm.erl +++ b/lib/compiler/src/beam_disasm.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-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% %%======================================================================= %% Notes: @@ -621,8 +621,7 @@ resolve_names(Fun, Imports, Str, Lbls, Lambdas, Literals, M) -> %% %% New make_fun2/4 instruction added in August 2001 (R8). -%% New put_literal/2 instruction added in Feb 2006 R11B-4. -%% We handle them specially here to avoid adding an argument to +%% We handle it specially here to avoid adding an argument to %% the clause for every instruction. %% @@ -631,8 +630,6 @@ resolve_inst({make_fun2,Args}, _, _, _, Lambdas, _, M) -> {OldIndex,{F,A,_Lbl,_Index,NumFree,OldUniq}} = lists:keyfind(OldIndex, 1, Lambdas), {make_fun2,{M,F,A},OldIndex,OldUniq,NumFree}; -resolve_inst({put_literal,[{u,Index},Dst]},_,_,_,_,Literals,_) -> - {put_literal,{literal,gb_trees:get(Index, Literals)},Dst}; resolve_inst(Instr, Imports, Str, Lbls, _Lambdas, _Literals, _M) -> %% io:format(?MODULE_STRING":resolve_inst ~p.~n", [Instr]), resolve_inst(Instr, Imports, Str, Lbls). @@ -1004,13 +1001,17 @@ resolve_inst({gc_bif2,Args},Imports,_,_) -> [F,Live,Bif,A1,A2,Reg] = resolve_args(Args), {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), {gc_bif,BifName,F,Live,[A1,A2],Reg}; +%% +%% New instruction in R14, gc_bif with 3 arguments +%% +resolve_inst({gc_bif3,Args},Imports,_,_) -> + [F,Live,Bif,A1,A2,A3,Reg] = resolve_args(Args), + {extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports), + {gc_bif,BifName,F,Live,[A1,A2,A3],Reg}; %% %% New instructions for creating non-byte aligned binaries. %% -resolve_inst({bs_bits_to_bytes2,[_Arg2,_Arg3]=Args},_,_,_) -> - [A2,A3] = resolve_args(Args), - {bs_bits_to_bytes2,A2,A3}; resolve_inst({bs_final2,[X,Y]},_,_,_) -> {bs_final2,X,Y}; @@ -1096,6 +1097,14 @@ 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. %% resolve_inst(X,_,_,_) -> ?exit({resolve_inst,X}). 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/beam_type.erl b/lib/compiler/src/beam_type.erl index 3729ccb0da..f83f73b224 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -76,9 +76,6 @@ simplify_basic_1([{set,[D],[{integer,Index},Reg],{bif,element,_}}=I0|Is], Ts0, A end, Ts = update(I, Ts0), simplify_basic_1(Is, Ts, [I|Acc]); -simplify_basic_1([{set,[_],[_],{bif,_,{f,0}}}=I|Is], Ts0, Acc) -> - Ts = update(I, Ts0), - simplify_basic_1(Is, Ts, [I|Acc]); simplify_basic_1([{set,[D],[TupleReg],{get_tuple_element,0}}=I|Is0], Ts0, Acc) -> case tdb_find(TupleReg, Ts0) of {tuple,_,[Contents]} -> @@ -118,7 +115,6 @@ simplify_basic_1([{test,is_record,_,[R,{atom,_}=Tag,{integer,Arity}]}=I|Is], Ts0 Ts = update(I, Ts0), simplify_basic_1(Is, Ts, [I|Acc]) end; - simplify_basic_1([I|Is], Ts0, Acc) -> Ts = update(I, Ts0), simplify_basic_1(Is, Ts, [I|Acc]); diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index ac249e6672..761d4ffec0 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-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% %% %% Purpose : Common utilities used by several optimization passes. @@ -424,12 +424,6 @@ check_liveness(R, [{bs_add,{f,0},Ss,D}|Is], St) -> false when R =:= D -> {killed,St}; false -> check_liveness(R, Is, St) end; -check_liveness(R, [{bs_bits_to_bytes2,Src,Dst}|Is], St) -> - case R of - Src -> {used,St}; - Dst -> {killed,St}; - _ -> check_liveness(R, Is, St) - end; check_liveness(R, [{bs_put_binary,{f,0},Sz,_,_,Src}|Is], St) -> case member(R, [Sz,Src]) of true -> {used,St}; diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 1fd61831e0..dc5a1068db 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), @@ -752,9 +757,6 @@ valfun_4({bs_utf8_size,{f,Fail},A,Dst}, Vst) -> valfun_4({bs_utf16_size,{f,Fail},A,Dst}, Vst) -> assert_term(A, Vst), set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst)); -valfun_4({bs_bits_to_bytes2,Src,Dst}, Vst) -> - assert_term(Src, Vst), - set_type_reg({integer,[]}, Dst, Vst); valfun_4({bs_bits_to_bytes,{f,Fail},Src,Dst}, Vst) -> assert_term(Src, Vst), set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst)); diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 5017fd2c23..08de3059c9 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) -> @@ -290,15 +294,6 @@ fold_comp([{Name,Pass}|Ps], Run, St0) -> end; fold_comp([], _Run, St) -> {ok,St}. -os_process_size() -> - case os:type() of - {unix, sunos} -> - Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"), - list_to_integer(lib:nonl(Size)); - _ -> - 0 - end. - run_tc({Name,Fun}, St) -> Before0 = statistics(runtime), Val = (catch Fun(St)), @@ -307,9 +302,8 @@ run_tc({Name,Fun}, St) -> {After_c, _} = After0, Mem0 = erts_debug:flat_size(Val)*erlang:system_info(wordsize), Mem = lists:flatten(io_lib:format("~.1f kB", [Mem0/1024])), - Sz = lists:flatten(io_lib:format("~.1f MB", [os_process_size()/1024])), - io:format(" ~-30s: ~10.2f s ~12s ~10s\n", - [Name,(After_c-Before_c) / 1000,Mem,Sz]), + io:format(" ~-30s: ~10.2f s ~12s\n", + [Name,(After_c-Before_c) / 1000,Mem]), Val. comp_ret_ok(#compile{code=Code,warnings=Warn0,module=Mod,options=Opts}=St) -> @@ -621,6 +615,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..4ac879c9a4 100644 --- a/lib/compiler/src/compiler.app.src +++ b/lib/compiler/src/compiler.app.src @@ -1,19 +1,19 @@ % This is an -*- erlang -*- file. %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-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% {application, compiler, @@ -33,6 +33,7 @@ beam_listing, beam_opcodes, beam_peep, + beam_receive, beam_trim, beam_type, beam_utils, diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl index e87bb276de..f8128702dd 100644 --- a/lib/compiler/src/erl_bifs.erl +++ b/lib/compiler/src/erl_bifs.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-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% %% %% Purpose: Information about the Erlang built-in functions. @@ -65,6 +65,8 @@ is_pure(erlang, 'xor', 2) -> true; is_pure(erlang, abs, 1) -> true; is_pure(erlang, atom_to_binary, 2) -> true; is_pure(erlang, atom_to_list, 1) -> true; +is_pure(erlang, binary_part, 2) -> true; +is_pure(erlang, binary_part, 3) -> true; is_pure(erlang, binary_to_atom, 2) -> true; is_pure(erlang, binary_to_list, 1) -> true; is_pure(erlang, binary_to_list, 3) -> true; diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab index 47e6e72402..63527bda8f 100644 --- a/lib/compiler/src/genop.tab +++ b/lib/compiler/src/genop.tab @@ -208,7 +208,7 @@ BEAM_FORMAT_NUMBER=0 # New instructions in R10B. 109: bs_init2/6 -110: bs_bits_to_bytes/3 +110: -bs_bits_to_bytes/3 111: bs_add/5 112: apply/1 113: apply_last/2 @@ -274,3 +274,9 @@ BEAM_FORMAT_NUMBER=0 # R13B03 149: on_load/0 + +# R14A + +150: recv_mark/1 +151: recv_set/1 +152: gc_bif3/7 diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 068478496b..6202f07479 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-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% %% %% Purpose : Constant folding optimisation for Core @@ -602,15 +602,23 @@ count_bits_1(Int, Bits) -> count_bits_1(Int bsr 64, Bits+64). %% a rewritten expression consisting of a sequence of %% the arguments only is returned. -useless_call(effect, #c_call{module=#c_literal{val=Mod}, +useless_call(effect, #c_call{anno=Anno, + module=#c_literal{val=Mod}, name=#c_literal{val=Name}, args=Args}=Call) -> A = length(Args), case erl_bifs:is_safe(Mod, Name, A) of false -> case erl_bifs:is_pure(Mod, Name, A) of - true -> add_warning(Call, result_ignored); - false -> ok + true -> + case member(result_not_wanted, Anno) of + false -> + add_warning(Call, result_ignored); + true -> + ok + end; + false -> + ok end, no; true -> @@ -2806,7 +2814,8 @@ format_error({no_effect,{erlang,F,A}}) -> end, flatten(io_lib:format(Fmt, Args)); format_error(result_ignored) -> - "the result of the expression is ignored"; + "the result of the expression is ignored " + "(suppress the warning by assigning the expression to the _ variable)"; format_error(useless_building) -> "a term is constructed, but never used"; format_error(bin_opt_alias) -> diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 4ac2196d79..16c5b6b415 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -128,8 +128,8 @@ -record(core, {vcount=0 :: non_neg_integer(), %Variable counter fcount=0 :: non_neg_integer(), %Function counter in_guard=false :: boolean(), %In guard or not. + wanted=true :: boolean(), %Result wanted or not. opts :: [compile:option()], %Options. - es=[] :: [error()], %Errors. ws=[] :: [warning()], %Warnings. file=[{file,""}]}). %File @@ -144,42 +144,37 @@ module({Mod,Exp,Forms}, Opts) -> Cexp = map(fun ({_N,_A} = NA) -> #c_var{name=NA} end, Exp), - {Kfs0,As0,Es,Ws,_File} = foldl(fun (F, Acc) -> - form(F, Acc, Opts) - end, {[],[],[],[],[]}, Forms), + {Kfs0,As0,Ws,_File} = foldl(fun (F, Acc) -> + form(F, Acc, Opts) + end, {[],[],[],[]}, Forms), Kfs = reverse(Kfs0), As = reverse(As0), - case Es of - [] -> - {ok,#c_module{name=#c_literal{val=Mod},exports=Cexp,attrs=As,defs=Kfs},Ws}; - _ -> - {error,Es,Ws} - end. + {ok,#c_module{name=#c_literal{val=Mod},exports=Cexp,attrs=As,defs=Kfs},Ws}. -form({function,_,_,_,_}=F0, {Fs,As,Es0,Ws0,File}, Opts) -> - {F,Es,Ws} = function(F0, Es0, Ws0, File, Opts), - {[F|Fs],As,Es,Ws,File}; -form({attribute,_,file,{File,_Line}}, {Fs,As,Es,Ws,_}, _Opts) -> - {Fs,As,Es,Ws,File}; -form({attribute,_,_,_}=F, {Fs,As,Es,Ws,File}, _Opts) -> - {Fs,[attribute(F)|As],Es,Ws,File}. +form({function,_,_,_,_}=F0, {Fs,As,Ws0,File}, Opts) -> + {F,Ws} = function(F0, Ws0, File, Opts), + {[F|Fs],As,Ws,File}; +form({attribute,_,file,{File,_Line}}, {Fs,As,Ws,_}, _Opts) -> + {Fs,As,Ws,File}; +form({attribute,_,_,_}=F, {Fs,As,Ws,File}, _Opts) -> + {Fs,[attribute(F)|As],Ws,File}. attribute({attribute,Line,Name,Val}) -> {#c_literal{val=Name, anno=[Line]}, #c_literal{val=Val, anno=[Line]}}. -function({function,_,Name,Arity,Cs0}, Es0, Ws0, File, Opts) -> +function({function,_,Name,Arity,Cs0}, Ws0, File, Opts) -> %%ok = io:fwrite("~p - ", [{Name,Arity}]), - St0 = #core{vcount=0,opts=Opts,es=Es0,ws=Ws0,file=[{file,File}]}, + St0 = #core{vcount=0,opts=Opts,ws=Ws0,file=[{file,File}]}, {B0,St1} = body(Cs0, Name, Arity, St0), %%ok = io:fwrite("1", []), %%ok = io:fwrite("~w:~p~n", [?LINE,B0]), {B1,St2} = ubody(B0, St1), %%ok = io:fwrite("2", []), %%ok = io:fwrite("~w:~p~n", [?LINE,B1]), - {B2,#core{es=Es,ws=Ws}} = cbody(B1, St2), + {B2,#core{ws=Ws}} = cbody(B1, St2), %%ok = io:fwrite("3~n", []), %%ok = io:fwrite("~w:~p~n", [?LINE,B2]), - {{#c_var{name={Name,Arity}},B2},Es,Ws}. + {{#c_var{name={Name,Arity}},B2},Ws}. body(Cs0, Name, Arity, St0) -> Anno = lineno_anno(element(2, hd(Cs0)), St0), @@ -580,10 +575,14 @@ expr({'fun',L,{function,F,A},{_,_,_}=Id}, St) -> {#c_var{anno=Lanno++[{id,Id}],name={F,A}},[],St}; expr({'fun',L,{clauses,Cs},Id}, St) -> fun_tq(Id, Cs, L, St); -expr({call,L,{remote,_,M,F},As0}, St0) -> +expr({call,L,{remote,_,M,F},As0}, #core{wanted=Wanted}=St0) -> {[M1,F1|As1],Aps,St1} = safe_list([M,F|As0], St0), Lanno = lineno_anno(L, St1), - {#icall{anno=#a{anno=Lanno},module=M1,name=F1,args=As1},Aps,St1}; + Anno = case Wanted of + false -> [result_not_wanted|Lanno]; + true -> Lanno + end, + {#icall{anno=#a{anno=Anno},module=M1,name=F1,args=As1},Aps,St1}; expr({call,Lc,{atom,Lf,F},As0}, St0) -> {As1,Aps,St1} = safe_list(As0, St0), Op = #c_var{anno=lineno_anno(Lf, St1),name={F,length(As1)}}, @@ -596,23 +595,28 @@ expr({call,L,FunExp,As0}, St0) -> expr({match,L,P0,E0}, St0) -> %% First fold matches together to create aliases. {P1,E1} = fold_match(E0, P0), - {E2,Eps,St1} = novars(E1, St0), + St1 = case P1 of + {var,_,'_'} -> St0#core{wanted=false}; + _ -> St0 + end, + {E2,Eps,St2} = novars(E1, St1), + St3 = St2#core{wanted=St0#core.wanted}, P2 = try - pattern(P1, St1) + pattern(P1, St3) catch throw:Thrown -> Thrown end, - {Fpat,St2} = new_var(St1), + {Fpat,St4} = new_var(St3), Fc = fail_clause([Fpat], c_tuple([#c_literal{val=badmatch},Fpat])), - Lanno = lineno_anno(L, St2), + Lanno = lineno_anno(L, St4), case P2 of nomatch -> - St = add_warning(L, nomatch, St2), + St = add_warning(L, nomatch, St4), {#icase{anno=#a{anno=Lanno}, args=[E2],clauses=[],fc=Fc},Eps,St}; Other when not is_atom(Other) -> - {#imatch{anno=#a{anno=Lanno},pat=P2,arg=E2,fc=Fc},Eps,St2} + {#imatch{anno=#a{anno=Lanno},pat=P2,arg=E2,fc=Fc},Eps,St4} end; expr({op,_,'++',{lc,Llc,E,Qs},More}, St0) -> %% Optimise '++' here because of the list comprehension algorithm. @@ -2086,20 +2090,12 @@ is_simple(#c_literal{}) -> true; is_simple(#c_cons{hd=H,tl=T}) -> is_simple(H) andalso is_simple(T); is_simple(#c_tuple{es=Es}) -> is_simple_list(Es); -is_simple(#c_binary{segments=Es}) -> is_simp_bin(Es); is_simple(_) -> false. -spec is_simple_list([cerl:cerl()]) -> boolean(). is_simple_list(Es) -> lists:all(fun is_simple/1, Es). --spec is_simp_bin([cerl:cerl()]) -> boolean(). - -is_simp_bin(Es) -> - lists:all(fun (#c_bitstr{val=E,size=S}) -> - is_simple(E) andalso is_simple(S) - end, Es). - %%% %%% Handling of warnings. %%% diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 974c64a8bc..fbe4d8617e 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -128,14 +128,27 @@ copy_anno(Kdst, Ksrc) -> {'ok', #k_mdef{}, [warning()]}. module(#c_module{anno=A,name=M,exports=Es,attrs=As,defs=Fs}, _Options) -> + Kas = attributes(As), + Kes = map(fun (#c_var{name={_,_}=Fname}) -> Fname end, Es), St0 = #kern{lit=dict:new()}, {Kfs,St} = mapfoldl(fun function/2, St0, Fs), - Kes = map(fun (#c_var{name={_,_}=Fname}) -> Fname end, Es), - Kas = map(fun ({#c_literal{val=N},V}) -> - {N,core_lib:literal_value(V)} end, As), {ok,#k_mdef{anno=A,name=M#c_literal.val,exports=Kes,attributes=Kas, body=Kfs ++ St#kern.funs},lists:sort(St#kern.ws)}. +attributes([{#c_literal{val=Name},Val}|As]) -> + case include_attribute(Name) of + false -> + attributes(As); + true -> + [{Name,core_lib:literal_value(Val)}|attributes(As)] + end; +attributes([]) -> []. + +include_attribute(type) -> false; +include_attribute(spec) -> false; +include_attribute(opaque) -> false; +include_attribute(_) -> true. + function({#c_var{name={F,Arity}=FA},Body}, St0) -> try St1 = St0#kern{func=FA,ff=undefined,vcount=0,fcount=0,ds=sets:new()}, diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl index 9fda37530b..a7a4d4dc91 100644 --- a/lib/compiler/src/v3_life.erl +++ b/lib/compiler/src/v3_life.erl @@ -361,8 +361,6 @@ match_fail(#k_literal{anno=Anno,val={Atom,Val}}, I, A) when is_atom(Atom) -> match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom},#k_literal{val=Val}]}, I, A); match_fail(#k_literal{anno=Anno,val={Atom}}, I, A) when is_atom(Atom) -> match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom}]}, I, A); -match_fail(#k_literal{anno=Anno,val=Atom}, I, A) when is_atom(Atom) -> - match_fail(#k_atom{anno=Anno,val=Atom}, I, A); match_fail(#k_tuple{es=[#k_atom{val=function_clause}|As]}, I, A) -> #l{ke={match_fail,{function_clause,literal_list(As, [])}},i=I,a=A}; match_fail(#k_tuple{es=[#k_atom{val=badmatch},Val]}, I, A) -> diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl index a460d54239..84cfd16e60 100644 --- a/lib/compiler/test/andor_SUITE.erl +++ b/lib/compiler/test/andor_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2001-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(andor_SUITE). @@ -141,6 +141,10 @@ t_and_or(Config) when is_list(Config) -> ok. +-define(GUARD(E), if E -> true; + true -> false + end). + t_andalso(Config) when is_list(Config) -> Bs = [true,false], Ps = [{X,Y} || X <- Bs, Y <- Bs], @@ -151,6 +155,11 @@ t_andalso(Config) when is_list(Config) -> ?line false = false andalso true, ?line false = false andalso false, + ?line true = ?GUARD(true andalso true), + ?line false = ?GUARD(true andalso false), + ?line false = ?GUARD(false andalso true), + ?line false = ?GUARD(false andalso false), + ?line false = false andalso glurf, ?line false = false andalso exit(exit_now), @@ -176,6 +185,11 @@ t_orelse(Config) when is_list(Config) -> ?line true = false orelse true, ?line false = false orelse false, + ?line true = ?GUARD(true orelse true), + ?line true = ?GUARD(true orelse false), + ?line true = ?GUARD(false orelse true), + ?line false = ?GUARD(false orelse false), + ?line true = true orelse glurf, ?line true = true orelse exit(exit_now), diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 75b6f801e7..caaa587006 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -30,7 +30,8 @@ multiple_uses/1,zero_label/1,followed_by_catch/1, matching_meets_construction/1,simon/1,matching_and_andalso/1, otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1, - match_string/1,zero_width/1,bad_size/1,haystack/1]). + match_string/1,zero_width/1,bad_size/1,haystack/1, + cover_beam_bool/1]). -export([coverage_id/1]). @@ -45,7 +46,7 @@ all(suite) -> wfbm,degenerated_match,bs_sum,coverage,multiple_uses,zero_label, followed_by_catch,matching_meets_construction,simon,matching_and_andalso, otp_7188,otp_7233,otp_7240,otp_7498,match_string,zero_width,bad_size, - haystack]. + haystack,cover_beam_bool]. init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> Dog = test_server:timetrap(?t:minutes(1)), @@ -985,6 +986,25 @@ fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}}) when ?MODULE =:= bs_match_inline_SUITE -> Args = tuple_to_list(ActualArgs). +%% Cover the clause handling bs_context to binary in +%% beam_block:initialized_regs/2. +cover_beam_bool(Config) when is_list(Config) -> + ?line ok = do_cover_beam_bool(<<>>, 3), + ?line <<19>> = do_cover_beam_bool(<<19>>, 2), + ?line <<42>> = do_cover_beam_bool(<<42>>, 1), + ?line <<17>> = do_cover_beam_bool(<<13,17>>, 0), + ok. + +do_cover_beam_bool(Bin, X) when X > 0 -> + if + X =:= 1; X =:= 2 -> + Bin; + true -> + ok + end; +do_cover_beam_bool(<<_,Bin/binary>>, X) -> + do_cover_beam_bool(Bin, X+1). + check(F, R) -> R = F(). diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 7c3990a855..e1cc5dafb5 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-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(compile_SUITE). @@ -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/compiler.cover b/lib/compiler/test/compiler.cover index 5ec2408a35..69d284ea6c 100644 --- a/lib/compiler/test/compiler.cover +++ b/lib/compiler/test/compiler.cover @@ -1,3 +1,3 @@ %% -*- erlang -*- -{exclude,[sys_pre_attributes,core_parse]}. +{exclude,[sys_pre_attributes,core_scan,core_parse]}. diff --git a/lib/compiler/test/core_SUITE_data/.gitignore b/lib/compiler/test/core_SUITE_data/.gitignore new file mode 100644 index 0000000000..d11d93d37f --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/.gitignore @@ -0,0 +1 @@ +!*.core diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl index 3d2dbf47e9..b48b1daa32 100644 --- a/lib/compiler/test/float_SUITE.erl +++ b/lib/compiler/test/float_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2002-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(float_SUITE). @@ -41,7 +41,7 @@ float_sub(A)-> float_mul(0, _, _)-> ok; float_mul(Iter, A, B) when is_float(A), is_float(B) -> - A*B, + _ = A*B, float_mul(Iter-1, A, B). %% Thanks to Mikael Pettersson and Tobias Lindahl (HiPE). @@ -82,6 +82,14 @@ bad_negate(X, Y) when is_float(X) -> Y1 = -Y, %BIF call. {X2, Y1}. +%% Some math functions are not implemented on all platforms. +-define(OPTIONAL(Expected, Expr), + try + Expected = Expr + catch + error:undef -> ok + end). + math_functions(Config) when is_list(Config) -> %% Mostly silly coverage. ?line 0.0 = math:tan(0), @@ -93,6 +101,14 @@ math_functions(Config) when is_list(Config) -> ?line -1.0 = math:cos(math:pi()), ?line 1.0 = math:exp(0), ?line 1.0 = math:pow(math:pi(), 0), + ?line 0.0 = math:log(1), + ?line 0.0 = math:asin(0), + ?line 0.0 = math:acos(1), + ?line ?OPTIONAL(0.0, math:asinh(0)), + ?line ?OPTIONAL(0.0, math:acosh(1)), + ?line ?OPTIONAL(0.0, math:atanh(0)), + ?line ?OPTIONAL(0.0, math:erf(0)), + ?line ?OPTIONAL(1.0, math:erfc(0)), ?line 0.0 = math:tan(id(0)), ?line 0.0 = math:atan2(id(0), 1), @@ -101,6 +117,14 @@ math_functions(Config) when is_list(Config) -> ?line 0.0 = math:tanh(id(0)), ?line 1.0 = math:log10(id(10)), ?line 1.0 = math:exp(id(0)), + ?line 0.0 = math:log(id(1)), + ?line 0.0 = math:asin(id(0)), + ?line 0.0 = math:acos(id(1)), + ?line ?OPTIONAL(0.0, math:asinh(id(0))), + ?line ?OPTIONAL(0.0, math:acosh(id(1))), + ?line ?OPTIONAL(0.0, math:atanh(id(0))), + ?line ?OPTIONAL(0.0, math:erf(id(0))), + ?line ?OPTIONAL(1.0, math:erfc(id(0))), %% Only for coverage (of beam_type.erl). ?line {'EXIT',{undef,_}} = (catch math:fnurfla(0)), diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index f3960b28c3..aa1b3b16dc 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -31,7 +31,7 @@ t_is_boolean/1,is_function_2/1, tricky/1,rel_ops/1,literal_type_tests/1, basic_andalso_orelse/1,traverse_dcd/1, - check_qlc_hrl/1,andalso_semi/1,tuple_size/1]). + check_qlc_hrl/1,andalso_semi/1,tuple_size/1,binary_part/1]). all(suite) -> test_lib:recompile(?MODULE), @@ -43,7 +43,7 @@ all(suite) -> build_in_guard,old_guard_tests,gbif, t_is_boolean,is_function_2,tricky,rel_ops,literal_type_tests, basic_andalso_orelse,traverse_dcd,check_qlc_hrl,andalso_semi, - tuple_size]. + tuple_size,binary_part]. misc(Config) when is_list(Config) -> ?line 42 = case id(42) of @@ -1362,6 +1362,146 @@ ludicrous_tuple_size(T) when tuple_size(T) =:= 16#FFFFFFFFFFFFFFFF -> ok; ludicrous_tuple_size(_) -> error. +%% +%% The binary_part/2,3 guard BIFs +%% +-define(MASK_ERROR(EXPR),mask_error((catch (EXPR)))). +mask_error({'EXIT',{Err,_}}) -> + Err; +mask_error(Else) -> + Else. + +binary_part(doc) -> + ["Tests the binary_part/2,3 guard (GC) bif's"]; +binary_part(Config) when is_list(Config) -> + %% This is more or less a copy of what the guard_SUITE in emulator + %% does to cover the guard bif's + ?line 1 = bptest(<<1,2,3>>), + ?line 2 = bptest(<<2,1,3>>), + ?line error = bptest(<<1>>), + ?line error = bptest(<<>>), + ?line error = bptest(apa), + ?line 3 = bptest(<<2,3,3>>), + % With one variable (pos) + ?line 1 = bptest(<<1,2,3>>,1), + ?line 2 = bptest(<<2,1,3>>,1), + ?line error = bptest(<<1>>,1), + ?line error = bptest(<<>>,1), + ?line error = bptest(apa,1), + ?line 3 = bptest(<<2,3,3>>,1), + % With one variable (length) + ?line 1 = bptesty(<<1,2,3>>,1), + ?line 2 = bptesty(<<2,1,3>>,1), + ?line error = bptesty(<<1>>,1), + ?line error = bptesty(<<>>,1), + ?line error = bptesty(apa,1), + ?line 3 = bptesty(<<2,3,3>>,2), + % With one variable (whole tuple) + ?line 1 = bptestx(<<1,2,3>>,{1,1}), + ?line 2 = bptestx(<<2,1,3>>,{1,1}), + ?line error = bptestx(<<1>>,{1,1}), + ?line error = bptestx(<<>>,{1,1}), + ?line error = bptestx(apa,{1,1}), + ?line 3 = bptestx(<<2,3,3>>,{1,2}), + % With two variables + ?line 1 = bptest(<<1,2,3>>,1,1), + ?line 2 = bptest(<<2,1,3>>,1,1), + ?line error = bptest(<<1>>,1,1), + ?line error = bptest(<<>>,1,1), + ?line error = bptest(apa,1,1), + ?line 3 = bptest(<<2,3,3>>,1,2), + % Direct (autoimported) call, these will be evaluated by the compiler... + ?line <<2>> = binary_part(<<1,2,3>>,1,1), + ?line <<1>> = binary_part(<<2,1,3>>,1,1), + % Compiler warnings due to constant evaluation expected (3) + ?line badarg = ?MASK_ERROR(binary_part(<<1>>,1,1)), + ?line badarg = ?MASK_ERROR(binary_part(<<>>,1,1)), + ?line badarg = ?MASK_ERROR(binary_part(apa,1,1)), + ?line <<3,3>> = binary_part(<<2,3,3>>,1,2), + % Direct call through apply + ?line <<2>> = apply(erlang,binary_part,[<<1,2,3>>,1,1]), + ?line <<1>> = apply(erlang,binary_part,[<<2,1,3>>,1,1]), + % Compiler warnings due to constant evaluation expected (3) + ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<1>>,1,1])), + ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<>>,1,1])), + ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[apa,1,1])), + ?line <<3,3>> = apply(erlang,binary_part,[<<2,3,3>>,1,2]), + % Constant propagation + ?line Bin = <<1,2,3>>, + ?line ok = if + binary_part(Bin,1,1) =:= <<2>> -> + ok; + %% Compiler warning, clause cannot match (expected) + true -> + error + end, + ?line ok = if + binary_part(Bin,{1,1}) =:= <<2>> -> + ok; + %% Compiler warning, clause cannot match (expected) + true -> + error + end, + ok. + + +bptest(B) when length(B) =:= 1337 -> + 1; +bptest(B) when binary_part(B,{1,1}) =:= <<2>> -> + 1; +bptest(B) when erlang:binary_part(B,1,1) =:= <<1>> -> + 2; +bptest(B) when erlang:binary_part(B,{1,2}) =:= <<3,3>> -> + 3; +bptest(_) -> + error. + +bptest(B,A) when length(B) =:= A -> + 1; +bptest(B,A) when binary_part(B,{A,1}) =:= <<2>> -> + 1; +bptest(B,A) when erlang:binary_part(B,A,1) =:= <<1>> -> + 2; +bptest(B,A) when erlang:binary_part(B,{A,2}) =:= <<3,3>> -> + 3; +bptest(_,_) -> + error. + +bptestx(B,A) when length(B) =:= A -> + 1; +bptestx(B,A) when binary_part(B,A) =:= <<2>> -> + 1; +bptestx(B,A) when erlang:binary_part(B,A) =:= <<1>> -> + 2; +bptestx(B,A) when erlang:binary_part(B,A) =:= <<3,3>> -> + 3; +bptestx(_,_) -> + error. + +bptesty(B,A) when length(B) =:= A -> + 1; +bptesty(B,A) when binary_part(B,{1,A}) =:= <<2>> -> + 1; +bptesty(B,A) when erlang:binary_part(B,1,A) =:= <<1>> -> + 2; +bptesty(B,A) when erlang:binary_part(B,{1,A}) =:= <<3,3>> -> + 3; +bptesty(_,_) -> + error. + +bptest(B,A,_C) when length(B) =:= A -> + 1; +bptest(B,A,C) when binary_part(B,{A,C}) =:= <<2>> -> + 1; +bptest(B,A,C) when erlang:binary_part(B,A,C) =:= <<1>> -> + 2; +bptest(B,A,C) when erlang:binary_part(B,{A,C}) =:= <<3,3>> -> + 3; +bptest(_,_,_) -> + error. + + + %% Call this function to turn off constant propagation. id(I) -> I. diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl index 20969c0b26..fd51b777ac 100644 --- a/lib/compiler/test/match_SUITE.erl +++ b/lib/compiler/test/match_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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(match_SUITE). @@ -21,14 +21,14 @@ -export([all/1, pmatch/1,mixed/1,aliases/1,match_in_call/1, untuplify/1,shortcut_boolean/1,letify_guard/1, - selectify/1]). + selectify/1,underscore/1]). -include("test_server.hrl"). all(suite) -> test_lib:recompile(?MODULE), [pmatch,mixed,aliases,match_in_call,untuplify,shortcut_boolean, - letify_guard,selectify]. + letify_guard,selectify,underscore]. pmatch(Config) when is_list(Config) -> ?line ok = doit(1), @@ -112,6 +112,12 @@ aliases(Config) when is_list(Config) -> ?line {42,42,42,42} = multiple_aliases_1(42), ?line {7,7,7} = multiple_aliases_2(7), ?line {{a,b},{a,b},{a,b}} = multiple_aliases_3({a,b}), + + %% Lists/literals. + ?line {a,b} = list_alias1([a,b]), + ?line {a,b} = list_alias2([a,b]), + ?line {a,b} = list_alias3([a,b]), + ok. str_alias(V) -> @@ -206,6 +212,15 @@ multiple_aliases_2((A=B)=(A=C)) -> multiple_aliases_3((A={_,_}=B)={_,_}=C) -> {A,B,C}. +list_alias1([a,b]=[X,Y]) -> + {X,Y}. + +list_alias2([X,Y]=[a,b]) -> + {X,Y}. + +list_alias3([X,b]=[a,Y]) -> + {X,Y}. + %% OTP-7018. match_in_call(Config) when is_list(Config) -> @@ -352,4 +367,16 @@ sel_same_value2(V) when V =:= 42; V =:= 43 -> sel_same_value2(_) -> error. +underscore(Config) when is_list(Config) -> + case Config of + [] -> + %% Assignment to _ at the end of a construct. + _ = length(Config); + [_|_] -> + %% Assignment to _ at the end of a construct. + _ = list_to_tuple(Config) + end, + _ = is_list(Config), + ok. + id(I) -> I. diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index e096571d50..126a679724 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2006-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(misc_SUITE). @@ -24,6 +24,10 @@ -include("test_server.hrl"). +%% Include an opaque declaration to cover the stripping of +%% opaque types from attributes in v3_kernel. +-opaque misc_SUITE_test_cases() :: [atom()]. + init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> Dog = test_server:timetrap(?t:minutes(10)), [{watchdog,Dog}|Config]. @@ -33,6 +37,8 @@ fin_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> ?t:timetrap_cancel(Dog), ok. +-spec all(any()) -> misc_SUITE_test_cases(). + all(suite) -> test_lib:recompile(?MODULE), [tobias,empty_string,md5,silly_coverage,confused_literals, @@ -92,13 +98,23 @@ md5_1(Beam) -> silly_coverage(Config) when is_list(Config) -> %% sys_core_fold, sys_core_setel, v3_kernel BadCoreErlang = {c_module,[], - name,exports,attrs, + name,[],[], [{{c_var,[],{foo,2}},seriously_bad_body}]}, ?line expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end), ?line expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end), ?line expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end), - %% v3_codgen + %% v3_life + BadKernel = {k_mdef,[],?MODULE, + [{foo,0}], + [], + [{k_fdef, + {k,[],[],[]}, + f,0,[], + seriously_bad_body}]}, + ?line expect_error(fun() -> v3_life:module(BadKernel, []) end), + + %% v3_codegen CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b}]}, ?line expect_error(fun() -> v3_codegen:module(CodegenInput, []) end), @@ -154,6 +170,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) -> diff --git a/lib/compiler/test/num_bif_SUITE.erl b/lib/compiler/test/num_bif_SUITE.erl index c246f56611..912f7366dd 100644 --- a/lib/compiler/test/num_bif_SUITE.erl +++ b/lib/compiler/test/num_bif_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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(num_bif_SUITE). @@ -166,7 +166,7 @@ t_list_to_float_safe(Config) when is_list(Config) -> t_list_to_float_risky(Config) when is_list(Config) -> ?line Many_Ones = lists:duplicate(25000, $1), - ?line list_to_float("2."++Many_Ones), + ?line _ = list_to_float("2."++Many_Ones), ?line {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)), ok. @@ -186,7 +186,7 @@ t_list_to_integer(Config) when is_list(Config) -> %% Bignums. ?line 123456932798748738738 = list_to_integer("123456932798748738738"), - ?line list_to_integer(lists:duplicate(2000, $1)), + ?line _ = list_to_integer(lists:duplicate(2000, $1)), ok. %% Tests round/1. diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index cb8833759a..fca3f0387b 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2004-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% %% %%% Purpose : Compiles various modules with tough code @@ -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. 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. diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index 6e60ab88cb..5ed8836c70 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-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(warnings_SUITE). @@ -375,7 +375,12 @@ effect(Config) when is_list(Config) -> comp_op -> X =:= 2; cookie -> - erlang:get_cookie() + erlang:get_cookie(); + result_ignore -> + _ = list_to_integer(X); + warn_lc_4 -> + %% No warning because of assignment to _. + [_ = abs(Z) || Z <- [1,2,3]] end, ok. |