diff options
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_block.erl | 10 | ||||
-rw-r--r-- | lib/compiler/src/v3_core.erl | 40 | ||||
-rw-r--r-- | lib/compiler/test/Makefile | 3 | ||||
-rw-r--r-- | lib/compiler/test/beam_block_SUITE.erl | 66 | ||||
-rw-r--r-- | lib/compiler/test/bs_bincomp_SUITE.erl | 46 |
5 files changed, 154 insertions, 11 deletions
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl index 10dbaf462c..d1052303e0 100644 --- a/lib/compiler/src/beam_block.erl +++ b/lib/compiler/src/beam_block.erl @@ -58,6 +58,13 @@ blockify(Is) -> blockify([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_Lbl},{label,Fail}|Is], Acc) -> %% Useless instruction sequence. blockify(Is, Acc); +blockify([{get_map_elements,F,S,{list,Gets}}|Is0], Acc) -> + %% A get_map_elements instruction is only safe at the beginning of + %% a block because of the failure label. + {Ss,Ds} = beam_utils:split_even(Gets), + I = {set,Ds,[S|Ss],{get_map_elements,F}}, + {Block,Is} = collect_block(Is0, [I]), + blockify(Is, [{block,Block}|Acc]); blockify([I|Is0]=IsAll, Acc) -> case collect(I) of error -> blockify(Is0, [I|Acc]); @@ -101,9 +108,6 @@ collect({get_list,S,D1,D2}) -> {set,[D1,D2],[S],get_list}; collect(remove_message) -> {set,[],[],remove_message}; collect({put_map,F,Op,S,D,R,{list,Puts}}) -> {set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}}; -collect({get_map_elements,F,S,{list,Gets}}) -> - {Ss,Ds} = beam_utils:split_even(Gets), - {set,Ds,[S|Ss],{get_map_elements,F}}; collect({'catch'=Op,R,L}) -> {set,[R],[],{try_catch,Op,L}}; collect({'try'=Op,R,L}) -> diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 68c9f964d8..830dd9973a 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -1080,13 +1080,39 @@ bc_tq1(Line, E, [#igen{anno=GAnno,ceps=Ceps, bc_tq1(Line, E, [#ifilter{}=Filter|Qs], Mc, St) -> filter_tq(Line, E, Filter, Mc, St, Qs, fun bc_tq1/5); bc_tq1(_, {bin,Bl,Elements}, [], AccVar, St0) -> - {E,Pre,St} = expr({bin,Bl,[{bin_element,Bl, - {var,Bl,AccVar#c_var.name}, - {atom,Bl,all}, - [binary,{unit,1}]}|Elements]}, St0), + bc_tq_build(Bl, [], AccVar, Elements, St0); +bc_tq1(Line, E0, [], AccVar, St0) -> + BsFlags = [binary,{unit,1}], + BsSize = {atom,Line,all}, + {E1,Pre0,St1} = safe(E0, St0), + case E1 of + #c_var{name=VarName} -> + Var = {var,Line,VarName}, + Els = [{bin_element,Line,Var,BsSize,BsFlags}], + bc_tq_build(Line, Pre0, AccVar, Els, St1); + #c_literal{val=Val} when is_bitstring(Val) -> + Bits = bit_size(Val), + <<Int0:Bits>> = Val, + Int = {integer,Line,Int0}, + Sz = {integer,Line,Bits}, + Els = [{bin_element,Line,Int,Sz,[integer,{unit,1},big]}], + bc_tq_build(Line, Pre0, AccVar, Els, St1); + _ -> + %% Any other safe (cons, tuple, literal) is not a + %% bitstring. Force the evaluation to fail (and + %% generate a warning). + Els = [{bin_element,Line,{atom,Line,bad_value},BsSize,BsFlags}], + bc_tq_build(Line, Pre0, AccVar, Els, St1) + end. + +bc_tq_build(Line, Pre0, #c_var{name=AccVar}, Elements0, St0) -> + Elements = [{bin_element,Line,{var,Line,AccVar},{atom,Line,all}, + [binary,{unit,1}]}|Elements0], + {E,Pre,St} = expr({bin,Line,Elements}, St0), #a{anno=A} = Anno0 = get_anno(E), Anno = Anno0#a{anno=[compiler_generated,single_use|A]}, - {set_anno(E, Anno),Pre,St}. + {set_anno(E, Anno),Pre0++Pre,St}. + %% filter_tq(Line, Expr, Filter, Mc, State, [Qualifier], TqFun) -> %% {Case,[PreExpr],State}. @@ -1307,7 +1333,9 @@ bc_elem_size({bin,_,El}, St0) -> Vs = [V || {_,#c_var{name=V}} <- Vars0], {E,Pre,St} = bc_mul_pairs(F, #c_literal{val=Bits}, [], St0), {E,Pre,Vs,St} - end. + end; +bc_elem_size(_, _) -> + throw(impossible). bc_elem_size_1([{bin_element,_,_,{integer,_,N},Flags}|Es], Bits, Vars) -> {unit,U} = keyfind(unit, 1, Flags), diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index c2d757da4d..85118502e3 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -8,6 +8,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk MODULES= \ andor_SUITE \ apply_SUITE \ + beam_block_SUITE \ beam_validator_SUITE \ beam_disasm_SUITE \ beam_except_SUITE \ @@ -44,6 +45,7 @@ MODULES= \ NO_OPT= \ andor \ apply \ + beam_block \ beam_except \ beam_reorder \ beam_type \ @@ -67,6 +69,7 @@ NO_OPT= \ INLINE= \ andor \ apply \ + beam_block \ beam_utils \ bs_bincomp \ bs_bit_binaries \ diff --git a/lib/compiler/test/beam_block_SUITE.erl b/lib/compiler/test/beam_block_SUITE.erl new file mode 100644 index 0000000000..7b6f2066be --- /dev/null +++ b/lib/compiler/test/beam_block_SUITE.erl @@ -0,0 +1,66 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(beam_block_SUITE). + +-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1, + init_per_group/2,end_per_group/2, + get_map_elements/1]). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + test_lib:recompile(?MODULE), + [{group,p}]. + +groups() -> + [{p,[parallel], + [get_map_elements + ]}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +get_map_elements(_Config) -> + [{pred,var}] = get_map_elements([{pred,var}], #{}, []), + [{pred,var}] = get_map_elements([{pred,var}], #{pred=>[]}, []), + acc = get_map_elements([], #{pred=>[]}, acc), + ok. + +get_map_elements([{Pred,Var}|Left], Map, Acc) -> + case Map of + #{Var := List} -> + case lists:keyfind(Pred, 1, List) of + false -> + get_map_elements(Left, Map, [{Pred,Var}|Acc]) + end; + #{} -> + get_map_elements(Left, Map, [{Pred,Var}|Acc]) + end; +get_map_elements([], _Map, Acc) -> + Acc. diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl index 93bce5c1f6..5e5f6e2169 100644 --- a/lib/compiler/test/bs_bincomp_SUITE.erl +++ b/lib/compiler/test/bs_bincomp_SUITE.erl @@ -26,7 +26,7 @@ init_per_group/2,end_per_group/2, byte_aligned/1,bit_aligned/1,extended_byte_aligned/1, extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1, - nomatch/1,sizes/1]). + nomatch/1,sizes/1,general_expressions/1]). -include_lib("common_test/include/ct.hrl"). @@ -36,7 +36,7 @@ all() -> test_lib:recompile(?MODULE), [byte_aligned, bit_aligned, extended_byte_aligned, extended_bit_aligned, mixed, filters, trim_coverage, - nomatch, sizes]. + nomatch, sizes, general_expressions]. groups() -> []. @@ -295,6 +295,48 @@ sizes(Config) when is_list(Config) -> cs_end(), ok. +-define(BAD(E), {'EXIT',{badarg,_}} = (catch << (E) || _ <- [1,2,3] >>)). +-define(BAD_V(E), {'EXIT',{badarg,_}} = (catch << (E) || I <- [1,2,3] >>)). + +general_expressions(_) -> + <<1,2,3>> = << begin <<1,2,3>> end || _ <- [1] >>, + <<"abc">> = << begin <<"abc">> end || _ <- [1] >>, + <<1,2,3>> = << begin + I = <<(I0+1)>>, + id(I) + end || <<I0>> <= <<0,1,2>> >>, + <<1,2,3>> = << I || I <- [<<1,2>>,<<3>>] >>, + <<1,2,3>> = << (id(<<I>>)) || I <- [1,2,3] >>, + <<2,4>> = << case I rem 2 of + 0 -> <<I>>; + 1 -> <<>> + end || I <- [1,2,3,4,5] >>, + <<2,3,4,5,6,7>> = << << (id(<<J>>)) || J <- [2*I,2*I+1] >> || + I <- [1,2,3] >>, + <<1,2,2,3,4,4>> = << if + I rem 2 =:= 0 -> <<I,I>>; + true -> <<I>> + end || I <- [1,2,3,4] >>, + self() ! <<42>>, + <<42>> = << receive B -> B end || _ <- [1] >>, + <<10,5,3>> = << try + <<(10 div I)>> + catch _:_ -> + <<>> + end || I <- [0,1,2,3] >>, + + %% Failing expressions. + ?BAD(bad_atom), + ?BAD(42), + ?BAD(42.0), + ?BAD_V({ok,I}), + ?BAD_V([I]), + ?BAD_V(fun() -> I end), + + ok. + +-undef(BAD). + cs_init() -> erts_debug:set_internal_state(available_internal_state, true), ok. |