aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <egil@erlang.org>2014-02-13 15:47:40 +0100
committerBjörn-Egil Dahlberg <egil@erlang.org>2014-02-19 15:32:17 +0100
commitbf21750a8af22b1ad10eab41ea48a7ae6efec7f5 (patch)
treed8edbd15fac8889f4d9197c34ab1f7d395653a5a
parent3e206565c2032a24b03ca13c313d1879d74dfec6 (diff)
downloadotp-bf21750a8af22b1ad10eab41ea48a7ae6efec7f5.tar.gz
otp-bf21750a8af22b1ad10eab41ea48a7ae6efec7f5.tar.bz2
otp-bf21750a8af22b1ad10eab41ea48a7ae6efec7f5.zip
compiler: Check literal order in beam_validator
-rw-r--r--lib/compiler/src/beam_disasm.erl41
-rw-r--r--lib/compiler/src/beam_validator.erl49
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) ->