From 9528e7a5de22ffa8ce2557e45fb744d2c3548bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 25 Jan 2019 15:26:57 +0100 Subject: Fix crash in beam_ssa_type To improve compilation times, beam_ssa_type keeps track of variables that are only used once and don't keep types for those variables. As currently implemented, it turns to be unsafe. Change it to only keep track of variables that are only used in the terminator of the block they are defined in. https://bugs.erlang.org/browse/ERL-840 --- lib/compiler/src/beam_ssa_type.erl | 24 ++++++++++++++---------- lib/compiler/test/beam_type_SUITE.erl | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl index 38ea5e6914..8bd6772ac5 100644 --- a/lib/compiler/src/beam_ssa_type.erl +++ b/lib/compiler/src/beam_ssa_type.erl @@ -1072,15 +1072,23 @@ simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds) -> %%% %%% Calculate the set of variables that are only used once in the -%%% block that they are defined in. That will allow us to discard type -%%% information for variables that will never be referenced by the -%%% successor blocks, potentially improving compilation times. +%%% terminator of the block that defines them. That will allow us to +%%% discard type information for variables that will never be +%%% referenced by the successor blocks, potentially improving +%%% compilation times. %%% used_once(Linear, Args) -> Map0 = used_once_1(reverse(Linear), #{}), Map = maps:without(Args, Map0), - cerl_sets:from_list(maps:keys(Map)). + Used0 = cerl_sets:from_list(maps:keys(Map)), + Used1 = used_in_terminators(Linear, []), + cerl_sets:intersection(Used0, Used1). + +used_in_terminators([{_,#b_blk{last=Last}}|Bs], Acc) -> + used_in_terminators(Bs, beam_ssa:used(Last) ++ Acc); +used_in_terminators([], Acc) -> + cerl_sets:from_list(Acc). used_once_1([{L,#b_blk{is=Is,last=Last}}|Bs], Uses0) -> Uses = used_once_2([Last|reverse(Is)], L, Uses0), @@ -1177,7 +1185,7 @@ get_type(#b_literal{val=Val}, _Ts) -> %% failed and that L is not 'cons'. 'cons' can be subtracted from the %% previously known type for L and the result put in FailTypes. -infer_types(#b_var{}=V, Ts, #d{ds=Ds,once=Once}) -> +infer_types(#b_var{}=V, Ts, #d{ds=Ds}) -> #{V:=#b_set{op=Op,args=Args}} = Ds, Types0 = infer_type(Op, Args, Ds), @@ -1195,11 +1203,7 @@ infer_types(#b_var{}=V, Ts, #d{ds=Ds,once=Once}) -> is_singleton_type(T) end, EqTypes0), - %% Don't bother updating the types for variables that - %% are never used again. - Types2 = Types1 ++ Types0, - Types = [P || {InfV,_}=P <- Types2, not cerl_sets:is_element(InfV, Once)], - + Types = Types1 ++ Types0, {meet_types(EqTypes++Types, Ts),subtract_types(Types, Ts)}. infer_eq_type({bif,'=:='}, [#b_var{}=Src,#b_literal{}=Lit], Ts, Ds) -> diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index 6efa98de44..a7ffc3f60a 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -222,6 +222,9 @@ coverage(Config) -> booleans(_Config) -> {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)), + ok = do_booleans_2(42, 41), + error = do_booleans_2(42, 42), + AnyAtom = id(atom), true = is_atom(AnyAtom), false = is_boolean(AnyAtom), @@ -250,6 +253,19 @@ do_booleans_1(B) -> no -> no end. +do_booleans_2(A, B) -> + Not = not do_booleans_cmp(A, B), + case Not of + true -> + case Not of + true -> error; + false -> ok + end; + false -> ok + end. + +do_booleans_cmp(A, B) -> A > B. + setelement(_Config) -> T0 = id({a,42}), {a,_} = T0, -- cgit v1.2.3