diff options
Diffstat (limited to 'lib/compiler')
| -rw-r--r-- | lib/compiler/doc/src/notes.xml | 77 | ||||
| -rw-r--r-- | lib/compiler/src/beam_ssa_dead.erl | 18 | ||||
| -rw-r--r-- | lib/compiler/src/beam_ssa_type.erl | 25 | ||||
| -rw-r--r-- | lib/compiler/src/beam_validator.erl | 12 | ||||
| -rw-r--r-- | lib/compiler/test/beam_ssa_SUITE.erl | 60 | ||||
| -rw-r--r-- | lib/compiler/test/beam_type_SUITE.erl | 21 | ||||
| -rw-r--r-- | lib/compiler/test/match_SUITE.erl | 26 | ||||
| -rw-r--r-- | lib/compiler/vsn.mk | 2 | 
8 files changed, 213 insertions, 28 deletions
| diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index 275c6268fa..f0d869381b 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -32,6 +32,83 @@    <p>This document describes the changes made to the Compiler      application.</p> +<section><title>Compiler 7.4.2</title> + +    <section><title>Fixed Bugs and Malfunctions</title> +      <list> +        <item> +	    <p>Fixed an incorrect type determination for constructed +	    binaries, which could cause <c>is_binary</c> checks to +	    succeed when they shouldn't have.</p> +          <p> +	    Own Id: OTP-15872</p> +        </item> +      </list> +    </section> + +</section> + +<section><title>Compiler 7.4.1</title> + +    <section><title>Fixed Bugs and Malfunctions</title> +      <list> +        <item> +	    <p>The type optimization pass of the compiler could hang +	    or loop for a long time when analyzing a +	    <c>setelement/3</c> call with a varible position.</p> +          <p> +	    Own Id: OTP-15828 Aux Id: ERL-948 </p> +        </item> +        <item> +	    <p>Certain complex receive statements would result in an +	    internal compiler failure.</p> +          <p> +	    Own Id: OTP-15832 Aux Id: ERL-950 </p> +        </item> +        <item> +	    <p>Fixed an unsafe type optimization.</p> +          <p> +	    Own Id: OTP-15838</p> +        </item> +        <item> +	    <p>Fixed a crash when optimizing compiler-generated +	    exceptions (like badmatch) whose offending term was a +	    constructed binary.</p> +          <p> +	    Own Id: OTP-15839 Aux Id: ERL-954 </p> +        </item> +        <item> +	    <p>Fixed a bad optimization related to the <c>++/2</c> +	    operator, where the compiler assumed that it always +	    produced a list (<c>[] ++ RHS</c> returns <c>RHS</c> +	    verbatim, even if it's not a list).</p> +          <p> +	    Own Id: OTP-15841</p> +        </item> +        <item> +	    <p>An <c>is_binary/1</c> test followed by +	    <c>is_bitstring/1</c> (or vice versa) could fail because +	    of an usafe optimization.</p> +          <p> +	    Own Id: OTP-15845</p> +        </item> +        <item> +	    <p>A Core Erlang module where the last clause in a +	    <c>case</c> matched a map would fail to load.</p> +          <p> +	    Own Id: OTP-15846 Aux Id: ERL-955 </p> +        </item> +        <item> +	    <p>Fixed a bug that could cause the compiler to crash +	    when compiling complex nested case expressions.</p> +          <p> +	    Own Id: OTP-15848 Aux Id: ERL-956 </p> +        </item> +      </list> +    </section> + +</section> +  <section><title>Compiler 7.4</title>      <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl index e220a89ded..64b9b3e222 100644 --- a/lib/compiler/src/beam_ssa_dead.erl +++ b/lib/compiler/src/beam_ssa_dead.erl @@ -436,8 +436,22 @@ get_phi_arg([{Val,From}|_], From) -> Val;  get_phi_arg([_|As], From) -> get_phi_arg(As, From).  eval_terminator(#b_br{bool=#b_var{}=Bool}=Br, Bs, _St) -> -    Val = get_value(Bool, Bs), -    beam_ssa:normalize(Br#b_br{bool=Val}); +    case get_value(Bool, Bs) of +        #b_literal{val=Val}=Lit -> +            case is_boolean(Val) of +                true -> +                    beam_ssa:normalize(Br#b_br{bool=Lit}); +                false -> +                    %% Non-boolean literal. This means that this `br` +                    %% terminator will never actually be reached with +                    %% these bindings. (There must be a previous two-way +                    %% branch that branches the other way when Bool +                    %% is bound to a non-boolean literal.) +                    none +            end; +        #b_var{}=Var -> +            beam_ssa:normalize(Br#b_br{bool=Var}) +    end;  eval_terminator(#b_br{bool=#b_literal{}}=Br, _Bs, _St) ->      beam_ssa:normalize(Br);  eval_terminator(#b_switch{arg=Arg,fail=Fail,list=List}=Sw, Bs, St) -> diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl index 417addf921..68920e7dd3 100644 --- a/lib/compiler/src/beam_ssa_type.erl +++ b/lib/compiler/src/beam_ssa_type.erl @@ -840,15 +840,8 @@ type({bif,Bif}, Args, Ts, _Ds) ->          Type ->              Type      end; -type(bs_init, [#b_literal{val=Type}|Args], _Ts, _Ds) -> -    case {Type,Args} of -        {new,[_,#b_literal{val=Unit}]} -> -            {binary,Unit}; -        {append,[_,_,#b_literal{val=Unit}]} -> -            {binary,Unit}; -        {private_append,[_,_,#b_literal{val=Unit}]} -> -            {binary,Unit} -    end; +type(bs_init, _Args, _Ts, _Ds) -> +    {binary, 1};  type(bs_extract, [Ctx], Ts, _Ds) ->      #t_bs_match{type=Type} = get_type(Ctx, Ts),      Type; @@ -896,11 +889,15 @@ type(call, [#b_remote{mod=#b_literal{val=Mod},                  {_,_} ->                      #t_tuple{}              end; -        {erlang,'++',[List1,List2]} -> -            case get_type(List1, Ts) =:= cons orelse -                get_type(List2, Ts) =:= cons of -                true -> cons; -                false -> list +        {erlang,'++',[LHS,RHS]} -> +            LType = get_type(LHS, Ts), +            RType = get_type(RHS, Ts), +            case LType =:= cons orelse RType =:= cons of +                true -> +                    cons; +                false -> +                    %% `[] ++ RHS` yields RHS, even if RHS is not a list. +                    join(list, RType)              end;          {erlang,'--',[_,_]} ->              list; diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 09a5a6c104..ebe9631e09 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -2844,10 +2844,14 @@ call_return_type_1(erlang, setelement, 3, Vst) ->              setelement(3, TupleType, #{})      end;  call_return_type_1(erlang, '++', 2, Vst) -> -    case get_term_type({x,0}, Vst) =:= cons orelse -        get_term_type({x,1}, Vst) =:= cons of -        true -> cons; -        false -> list +    LType = get_term_type({x,0}, Vst), +    RType = get_term_type({x,1}, Vst), +    case LType =:= cons orelse RType =:= cons of +        true -> +            cons; +        false -> +            %% `[] ++ RHS` yields RHS, even if RHS is not a list +            join(list, RType)      end;  call_return_type_1(erlang, '--', 2, _Vst) ->      list; diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl index 15cf9bcbf3..a741ebbdf9 100644 --- a/lib/compiler/test/beam_ssa_SUITE.erl +++ b/lib/compiler/test/beam_ssa_SUITE.erl @@ -22,7 +22,8 @@  -export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,  	 init_per_group/2,end_per_group/2,           calls/1,tuple_matching/1,recv/1,maps/1, -         cover_ssa_dead/1,combine_sw/1,share_opt/1]). +         cover_ssa_dead/1,combine_sw/1,share_opt/1, +         beam_ssa_dead_crash/1]).  suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -37,7 +38,8 @@ groups() ->         maps,         cover_ssa_dead,         combine_sw, -       share_opt +       share_opt, +       beam_ssa_dead_crash        ]}].  init_per_suite(Config) -> @@ -492,6 +494,60 @@ do_share_opt(A) ->      end,      receive after 1 -> ok end. +beam_ssa_dead_crash(_Config) -> +    not_A_B = do_beam_ssa_dead_crash(id(false), id(true)), +    not_A_not_B = do_beam_ssa_dead_crash(false, false), +    neither = do_beam_ssa_dead_crash(true, false), +    neither = do_beam_ssa_dead_crash(true, true), +    ok. + +do_beam_ssa_dead_crash(A, B) -> +    %% beam_ssa_dead attempts to shortcut branches that branch other +    %% branches. When a two-way branch is encountered, beam_ssa_dead +    %% will simulate execution along both paths, in the hope that both +    %% paths happens to end up in the same place. +    %% +    %% During the simulated execution of this function, the boolean +    %% varible for a `br` instruction would be replaced with the +    %% literal atom `nil`, which is not allowed, and would crash the +    %% compiler. In practice, during the actual execution, control +    %% would never be transferred to that `br` instruction when the +    %% variable in question had the value `nil`. +    %% +    %% beam_ssa_dead has been updated to immediately abort the search +    %% along the current path if there is an attempt to substitute a +    %% non-boolean value into a `br` instruction. + +    case +        case not A of +            false -> +                false; +            true -> +                B +        end +    of +        V +            when +                V /= nil +                andalso +                V /= false -> +            not_A_B; +        _ -> +            case +                case not A of +                    false -> +                        false; +                    true -> +                        not B +                end +            of +                true -> +                    not_A_not_B; +                false -> +                    neither +            end +    end. +  %% The identity function.  id(I) -> I. diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index 0d1680fb15..076a604aa4 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -24,7 +24,7 @@  	 integers/1,numbers/1,coverage/1,booleans/1,setelement/1,  	 cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,  	 arity_checks/1,elixir_binaries/1,find_best/1, -         test_size/1,cover_lists_functions/1]). +         test_size/1,cover_lists_functions/1,list_append/1,bad_binary_unit/1]).  suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -47,7 +47,9 @@ groups() ->         elixir_binaries,         find_best,         test_size, -       cover_lists_functions +       cover_lists_functions, +       list_append, +       bad_binary_unit        ]}].  init_per_suite(Config) -> @@ -501,5 +503,20 @@ cover_lists_functions(Config) ->      true = is_list(Zipped),      ok. +list_append(_Config) -> +    %% '++'/2 has a quirk where it returns the right-hand argument as-is when +    %% the left-hand is []. +    hello = id([]) ++ id(hello), +    ok. + +%% OTP-15872: The compiler would treat the "Unit" of bs_init instructions as +%% the unit of the result instead of the required unit of the input, causing +%% is_binary checks to be wrongly optimized away. +bad_binary_unit(_Config) -> +    Bin = id(<<1,2,3>>), +    Bitstring = <<Bin/binary,1:1>>, +    false = is_binary(Bitstring), +    ok. +  id(I) ->      I. diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl index 94bfbb0efe..aac9de278d 100644 --- a/lib/compiler/test/match_SUITE.erl +++ b/lib/compiler/test/match_SUITE.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2004-2018. All Rights Reserved. +%% Copyright Ericsson AB 2004-2019. 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. @@ -25,7 +25,7 @@  	 match_in_call/1,untuplify/1,shortcut_boolean/1,letify_guard/1,  	 selectify/1,deselectify/1,underscore/1,match_map/1,map_vars_used/1,  	 coverage/1,grab_bag/1,literal_binary/1, -         unary_op/1,eq_types/1,match_after_return/1]). +         unary_op/1,eq_types/1,match_after_return/1,match_right_tuple/1]).  -include_lib("common_test/include/ct.hrl"). @@ -41,7 +41,7 @@ groups() ->         shortcut_boolean,letify_guard,selectify,deselectify,         underscore,match_map,map_vars_used,coverage,         grab_bag,literal_binary,unary_op,eq_types, -       match_after_return]}]. +       match_after_return,match_right_tuple]}].  init_per_suite(Config) -> @@ -902,4 +902,24 @@ match_after_return(Config) when is_list(Config) ->  mar_test_tuple(I) -> {gurka, I}. +match_right_tuple(Config) when is_list(Config) -> +    %% The loader wrongly coalesced certain get_tuple_element sequences, fusing +    %% the code below into a single i_get_tuple_element2 operating on {x,0} +    %% even though the first one overwrites it. +    %% +    %%    {get_tuple_element,{x,0},0,{x,0}}. +    %%    {get_tuple_element,{x,0},1,{x,1}}. + +    Inner = {id(wrong_element), id(ok)}, +    Outer = {Inner, id(wrong_tuple)}, +    ok = match_right_tuple_1(Outer). + +match_right_tuple_1(T) -> +    {A, _} = T, +    {_, B} = A, +    %% The call ensures that A is in {x,0} and B is in {x,1} +    id(force_succ_regs(A, B)). + +force_succ_regs(_A, B) -> B. +  id(I) -> I. diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 494de072ff..508bbc902c 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 7.4 +COMPILER_VSN = 7.4.2 | 
