diff options
-rw-r--r-- | lib/compiler/src/beam_disasm.erl | 41 | ||||
-rw-r--r-- | lib/compiler/src/beam_validator.erl | 49 |
2 files changed, 70 insertions, 20 deletions
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl index 3f5e9df5fd..363989f4c9 100644 --- a/lib/compiler/src/beam_disasm.erl +++ b/lib/compiler/src/beam_disasm.erl @@ -366,9 +366,13 @@ disasm_instr(B, Bs, Atoms, Literals) -> select_tuple_arity -> disasm_select_inst(select_tuple_arity, Bs, Atoms, Literals); put_map_assoc -> - disasm_map_inst(put_map_assoc, Bs, Atoms, Literals); + disasm_map_inst(put_map_assoc, Arity, Bs, Atoms, Literals); put_map_exact -> - disasm_map_inst(put_map_exact, Bs, Atoms, Literals); + disasm_map_inst(put_map_exact, Arity, Bs, Atoms, Literals); + get_map_elements -> + disasm_map_inst(get_map_elements, Arity, Bs, Atoms, Literals); + has_map_fields -> + disasm_map_inst(has_map_fields, Arity, Bs, Atoms, Literals); _ -> try decode_n_args(Arity, Bs, Atoms, Literals) of {Args, RestBs} -> @@ -399,16 +403,15 @@ disasm_select_inst(Inst, Bs, Atoms, Literals) -> {List, RestBs} = decode_n_args(Len, Bs4, Atoms, Literals), {{Inst, [X,F,{Z,U,List}]}, RestBs}. -disasm_map_inst(Inst, Bs0, Atoms, Literals) -> - {F, Bs1} = decode_arg(Bs0, Atoms, Literals), - {S, Bs2} = decode_arg(Bs1, Atoms, Literals), - {X, Bs3} = decode_arg(Bs2, Atoms, Literals), - {N, Bs4} = decode_arg(Bs3, Atoms, Literals), - {Z, Bs5} = decode_arg(Bs4, Atoms, Literals), - {U, Bs6} = decode_arg(Bs5, Atoms, Literals), - {u, Len} = U, - {List, RestBs} = decode_n_args(Len, Bs6, Atoms, Literals), - {{Inst, [F,S,X,N,{Z,U,List}]}, RestBs}. +disasm_map_inst(Inst, Arity, Bs0, Atoms, Literals) -> + {Args0,Bs1} = decode_n_args(Arity, Bs0, Atoms, Literals), + %% no droplast .. + [Z|Args1] = lists:reverse(Args0), + Args = lists:reverse(Args1), + {U, Bs2} = decode_arg(Bs1, Atoms, Literals), + {u, Len} = U, + {List, RestBs} = decode_n_args(Len, Bs2, Atoms, Literals), + {{Inst, Args ++ [{Z,U,List}]}, RestBs}. %%----------------------------------------------------------------------- %% decode_arg([Byte]) -> {Arg, [Byte]} @@ -1150,13 +1153,15 @@ resolve_inst({is_map,Args0},_,_,_) -> [FLbl|Args] = resolve_args(Args0), {test, is_map, FLbl, Args}; -resolve_inst({has_map_field,Args0},_,_,_) -> - [FLbl,Src,{u,_Len}|Args] = resolve_args(Args0), - {test,has_map_field,FLbl,Src,{list,Args}}; +resolve_inst({has_map_fields,Args0},_,_,_) -> + [FLbl,Src,{{z,1},{u,_Len},List0}] = Args0, + List = resolve_args(List0), + {test,has_map_fields,FLbl,Src,{list,List}}; -resolve_inst({get_map_element,Args0},_,_,_) -> - [FLbl,Src,{u,_Len}|Args] = resolve_args(Args0), - {get_map_element,FLbl,Src,{list,Args}}; +resolve_inst({get_map_elements,Args0},_,_,_) -> + [FLbl,Src,{{z,1},{u,_Len},List0}] = Args0, + List = resolve_args(List0), + {get_map_elements,FLbl,Src,{list,List}}; %% %% Catches instructions that are not yet handled. diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 9f8f1cd3f5..6feab29d33 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -770,8 +770,9 @@ valfun_4({test,is_nonempty_list,{f,Lbl},[Cons]}, Vst) -> valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) -> assert_type(tuple, Tuple, Vst), set_type_reg({tuple,Sz}, Tuple, branch_state(Lbl, Vst)); -valfun_4({test,_Op,{f,Lbl},Src,{list,_}}, Vst) -> +valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) -> validate_src([Src], Vst), + assert_strict_literal_termorder(List), branch_state(Lbl, Vst); valfun_4({test,_Op,{f,Lbl},Src}, Vst) -> validate_src(Src, Vst), @@ -882,6 +883,8 @@ valfun_4(_, _) -> verify_get_map(Fail, Src, List, Vst0) -> assert_term(Src, Vst0), Vst1 = branch_state(Fail, Vst0), + Lits = mmap(fun(L,_R) -> [L] end, List), + assert_strict_literal_termorder(Lits), verify_get_map_pair(List,Vst0,Vst1). verify_get_map_pair([],_,Vst) -> Vst; @@ -1109,6 +1112,39 @@ assert_freg_set({fr,Fr}=Freg, #vst{current=#st{f=Fregs}}) end; assert_freg_set(Fr, _) -> error({bad_source,Fr}). +%%% Maps + +%% ensure that a list of literals has a strict +%% ascending term order (also meaning unique literals) +assert_strict_literal_termorder(Ls) -> + Vs = lists:map(fun (L) -> get_literal(L) end, Ls), + case check_strict_value_termorder(Vs) of + true -> ok; + false -> error({not_strict_order, Ls}) + end. + +%% usage: +%% mmap(fun(A,B) -> [{A,B}] end, [1,2,3,4]), +%% [{1,2},{3,4}] + +mmap(F,List) -> + {arity,Ar} = erlang:fun_info(F,arity), + mmap(F,Ar,List). +mmap(_F,_,[]) -> []; +mmap(F,Ar,List) -> + {Hd,Tl} = lists:split(Ar,List), + apply(F,Hd) ++ mmap(F,Ar,Tl). + +check_strict_value_termorder([]) -> true; +check_strict_value_termorder([_]) -> true; +check_strict_value_termorder([V1,V2]) -> + erts_internal:cmp_term(V1,V2) < 0; +check_strict_value_termorder([V1,V2|Vs]) -> + case erts_internal:cmp_term(V1,V2) < 0 of + true -> check_strict_value_termorder([V2|Vs]); + false -> false + end. + %%% %%% Binary matching. %%% @@ -1344,6 +1380,7 @@ assert_term(Src, Vst) -> %% number Integer or Float of unknown value %% + assert_type(WantedType, Term, Vst) -> assert_type(WantedType, get_term_type(Term, Vst)). @@ -1359,7 +1396,6 @@ assert_type({tuple_element,I}, {tuple,Sz}) assert_type(Needed, Actual) -> error({bad_type,{needed,Needed},{actual,Actual}}). - %% upgrade_tuple_type(NewTupleType, OldType) -> TupleType. %% upgrade_tuple_type/2 is used when linear code finds out more and %% more information about a tuple type, so that the type gets more @@ -1440,6 +1476,15 @@ get_term_type_1({y,Y}=Reg, #vst{current=#st{y=Ys}}) when is_integer(Y) -> get_term_type_1(Src, _) -> error({bad_source,Src}). +%% get_literal(Src) -> literal_value(). +get_literal(nil) -> []; +get_literal({atom,A}) when is_atom(A) -> A; +get_literal({float,F}) when is_float(F) -> F; +get_literal({integer,I}) when is_integer(I) -> I; +get_literal({literal,L}) -> L; +get_literal(T) -> error({not_literal,T}). + + branch_arities([], _, #vst{}=Vst) -> Vst; branch_arities([Sz,{f,L}|T], Tuple, #vst{current=St}=Vst0) when is_integer(Sz) -> |