aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/doc/src/notes.xml77
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl18
-rw-r--r--lib/compiler/src/beam_ssa_type.erl25
-rw-r--r--lib/compiler/src/beam_validator.erl12
-rw-r--r--lib/compiler/test/beam_ssa_SUITE.erl60
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl21
-rw-r--r--lib/compiler/test/match_SUITE.erl26
-rw-r--r--lib/compiler/vsn.mk2
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