aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/doc/src/notes.xml213
-rw-r--r--lib/compiler/src/beam_asm.erl4
-rw-r--r--lib/compiler/src/beam_jump.erl65
-rw-r--r--lib/compiler/src/sys_core_fold.erl37
-rw-r--r--lib/compiler/src/sys_core_inline.erl4
-rw-r--r--lib/compiler/test/core_SUITE.erl5
-rw-r--r--lib/compiler/test/core_SUITE_data/name_capture.core110
-rw-r--r--lib/compiler/vsn.mk2
8 files changed, 154 insertions, 286 deletions
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 357a940f24..bc1f68337b 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,219 +32,6 @@
<p>This document describes the changes made to the Compiler
application.</p>
-<section><title>Compiler 7.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>Fixed an error in an optimization pass that caused
- impossible tuple matching.</p>
- <p>
- Own Id: OTP-14855 Aux Id: ERL-549 </p>
- </item>
- <item>
- <p>The exception thrown when a list comprehension was
- given a non-list term was not always correct.</p>
- <p>
- Own Id: OTP-14992 Aux Id: ERL-572 </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Changed the default behaviour of <c>.erlang</c>
- loading: <c>.erlang</c> is no longer loaded from the
- current directory. <c>c:erlangrc(PathList)</c> can be
- used to search and load an <c>.erlang</c> file from user
- specified directories.</p> <p><c>escript</c>,
- <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
- load an <c>.erlang</c> at all.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-14439</p>
- </item>
- <item>
- <p>Support for "tuple calls" have been removed from the
- run-time system. Tuple calls was an undocumented and
- unsupported feature which allowed the module argument for
- an apply operation to be a tuple: <c>Var = dict:new(),
- Var:size()</c>. This "feature" frequently caused
- confusion, especially when such call failed. The
- stacktrace would point out functions that don't exist in
- the source code.</p>
- <p>For legacy code that need to use parameterized modules
- or tuple calls for some other reason, there is a new
- compiler option called <c>tuple_calls</c>. When this
- option is given, the compiler will generate extra code
- that emulates the old behavior for calls where the module
- is a variable.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-14497</p>
- </item>
- <item>
- <p>In code such as <c>example({ok, Val}) -&gt; {ok,
- Val}.</c> a tuple would be built. The compiler will now
- automatically rewrite the code to
- <c>example({ok,Val}=Tuple) -&gt; Tuple.</c> which will
- reduce code size, execution time, and remove GC
- pressure.</p>
- <p>
- Own Id: OTP-14505</p>
- </item>
- <item>
- <p>The optimization of <c>case</c> expression where only
- one of the case arms can execute successfully has been
- improved.</p>
- <p>
- Own Id: OTP-14525</p>
- </item>
- <item>
- <p>Some uses of binary matching has been slightly
- improved, eliminating unnecessary register shuffling.</p>
- <p>
- Own Id: OTP-14594 Aux Id: ERL-444 </p>
- </item>
- <item>
- <p>There is a new <c>{compile_info,Info}</c> option for
- the compiler that allows BEAM-based languages such as
- Elixir and LFE to add their own compiler versions.</p>
- <p>
- Own Id: OTP-14615 Aux Id: PR-1558 </p>
- </item>
- <item>
- <p>Loaded BEAM code in a 64-bit system requires less
- memory because of better packing of operands for
- instructions.</p>
- <p>These memory savings were achieved by major
- improvements to the <c>beam_makeops</c> scripts used when
- building the run time system and BEAM compiler. There is
- also new for documentation for <c>beam_makeops</c> that
- describes how new BEAM instructions and loader
- transformations can be implemented. The documentation is
- found in here in a source directory or git repository:
- erts/emulator/internal_doc/beam_makeops.md. An online
- version can be found here:
- https://github.com/erlang/otp/blob/master/erts/emulator/internal_doc/beam_makeops.md</p>
- <p>
- Own Id: OTP-14626</p>
- </item>
- <item>
- <p>Size calculations for binary constructions has been
- somewhat optimized, producing smaller code.</p>
- <p>
- Own Id: OTP-14654</p>
- </item>
- <item>
- <p>When the value returned from a '<c>catch</c>'
- expression is ignored, no stacktrace will be built if an
- exception is caught. That will save time and produce less
- garbage. There are also some minor optimizations of
- '<c>try</c>/<c>catch</c>' both in the compiler and
- run-time system.</p>
- <p>
- Own Id: OTP-14683</p>
- </item>
- <item>
- <p>There is a new syntax in '<c>try/catch</c>' for
- retrieving the stacktrace without calling
- '<c>erlang:get_stacktrace/0</c>'. See the reference
- manual for a description of the new syntax. The
- '<c>erlang:get_stacktrace/0</c>' BIF is now
- deprecated.</p>
- <p>
- Own Id: OTP-14692</p>
- </item>
- <item>
- <p>The following is an internal change in the compiler,
- that is not noticeable for normal use of the compiler:
- The module <c>v3_life</c> has been removed. Its
- functionality has been simplified and integrated into
- <c>v3_codegen</c>.</p>
- <p>
- Own Id: OTP-14712</p>
- </item>
- <item>
- <p>The optimization of binary matching that delays
- creation of sub binaries (see the Efficiency Guide) could
- be thwarted by the argument order and could be necessary
- to change the argument order. The compiler has now become
- smarter and can handle any argument order.</p>
- <p>
- Own Id: OTP-14774</p>
- </item>
- <item>
- <p>When the compiler was faced with complex case
- expressions it would unnecessarily allocate stack
- elements and shuffle data between x and y registers.
- Improved code generation to only allocate a stack frame
- when strictly necessary.</p>
- <p>
- Own Id: OTP-14808 Aux Id: ERL-514 </p>
- </item>
- <item>
- <p>There is a new option '<c>makedep_side_effect</c>' for
- the compiler and <c>-MMD</c> for '<c>erlc</c>' that
- generates dependencies and continues to compile as
- normal.</p>
- <p>
- Own Id: OTP-14830</p>
- </item>
- <item>
- <p>When compiling modules with huge functions, the
- compiler would generate a lot of atoms for its internal,
- sometimes so many that the atom table would overflow. The
- compiler has been rewritten to generate far less internal
- atoms to avoid filling the atom table.</p>
- <p>
- Own Id: OTP-14968 Aux Id: ERL-563 </p>
- </item>
- <item>
- <p>External funs with literal values for module, name,
- and arity (e.g. <c>erlang:abs/1</c>) are now treated as
- literals. That means more efficient code that produces
- less garbage on the heap.</p>
- <p>
- Own Id: OTP-15003</p>
- </item>
- <item>
- <p>Two new guards BIFs operating on maps have been added:
- <c>map_get/2</c> and <c>is_map_key/2</c>. They do the
- same as <c>maps:get/2</c> and <c>maps:is_key/2</c>,
- respectively, except that they are allowed to be used in
- guards.</p>
- <p>
- Own Id: OTP-15037 Aux Id: PR-1784, PR-1802 </p>
- </item>
- <item>
- <p>A call or apply of a literal external fun will be
- replaced with a direct call.</p>
- <p>
- Own Id: OTP-15044 Aux Id: ERL-614 </p>
- </item>
- <item>
- <p>Part of EEP-44 has been implemented.</p>
- <p>There is a new predefined macro called
- <c>OTP_RELEASE</c> which is an integer indicating the OTP
- release number (its value is <c>21</c> in this
- release).</p>
- <p>There are new preprocessor directives
- <c>-if(Condition).</c> and <c>-elif(Condition).</c>. The
- <c>if/elif</c> supports the builtin function
- <c>defined(Symbol)</c>.</p>
- <p>
- Own Id: OTP-15087 Aux Id: PR-1810 </p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Compiler 7.1.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl
index 5ef340c831..df0321e85a 100644
--- a/lib/compiler/src/beam_asm.erl
+++ b/lib/compiler/src/beam_asm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. 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.
@@ -475,7 +475,7 @@ encode_alloc_list_1([{floats,Floats}|T], Dict, Acc0) ->
encode_alloc_list_1([], Dict, Acc) ->
{iolist_to_binary(Acc),Dict}.
--spec encode(non_neg_integer(), integer()) -> iodata().
+-spec encode(non_neg_integer(), integer()) -> iolist() | integer().
encode(Tag, N) when N < 0 ->
encode1(Tag, negative_to_bytes(N));
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index c33de217bd..576d20505d 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -156,46 +156,41 @@ function({function,Name,Arity,CLabel,Asm0}) ->
%%%
share(Is0) ->
- Is1 = eliminate_fallthroughs(Is0, []),
- Is2 = find_fixpoint(fun(Is) ->
- share_1(Is, #{}, #{}, [], [])
- end, Is1),
- reverse(Is2).
+ %% We will get more sharing if we never fall through to a label.
+ Is = eliminate_fallthroughs(Is0, []),
+ share_1(Is, #{}, [], []).
-share_1([{label,L}=Lbl|Is], Dict0, Lbls0, [_|_]=Seq, Acc) ->
+share_1([{label,L}=Lbl|Is], Dict0, [_|_]=Seq, Acc) ->
case maps:find(Seq, Dict0) of
error ->
Dict = maps:put(Seq, L, Dict0),
- share_1(Is, Dict, Lbls0, [], [Lbl|Seq ++ Acc]);
+ share_1(Is, Dict, [], [Lbl|Seq ++ Acc]);
{ok,Label} ->
- Lbls = maps:put(L, Label, Lbls0),
- share_1(Is, Dict0, Lbls, [], [Lbl,{jump,{f,Label}}|Acc])
+ share_1(Is, Dict0, [], [Lbl,{jump,{f,Label}}|Acc])
end;
-share_1([{func_info,_,_,_}|_]=Is, _, Lbls, [], Acc) when Lbls =/= #{} ->
- beam_utils:replace_labels(Acc, Is, Lbls, fun(Old) -> Old end);
-share_1([{func_info,_,_,_}|_]=Is, _, Lbls, [], Acc) when Lbls =:= #{} ->
- reverse(Acc, Is);
-share_1([{'catch',_,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
- {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
- share_1(Is, Dict, Lbls, [I|Seq], Acc);
-share_1([{'try',_,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
- {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
- share_1(Is, Dict, Lbls, [I|Seq], Acc);
-share_1([{try_case,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
- {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
- share_1(Is, Dict, Lbls, [I|Seq], Acc);
-share_1([{catch_end,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
- {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
- share_1(Is, Dict, Lbls, [I|Seq], Acc);
-share_1([I|Is], Dict, Lbls, Seq, Acc) ->
+share_1([{func_info,_,_,_}=I|Is], _, [], Acc) ->
+ reverse(Is, [I|Acc]);
+share_1([{'catch',_,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
+share_1([{'try',_,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
+share_1([{try_case,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
+share_1([{catch_end,_}=I|Is], Dict0, Seq, Acc) ->
+ Dict = clean_non_sharable(Dict0),
+ share_1(Is, Dict, [I|Seq], Acc);
+share_1([I|Is], Dict, Seq, Acc) ->
case is_unreachable_after(I) of
false ->
- share_1(Is, Dict, Lbls, [I|Seq], Acc);
+ share_1(Is, Dict, [I|Seq], Acc);
true ->
- share_1(Is, Dict, Lbls, [I], Acc)
+ share_1(Is, Dict, [I], Acc)
end.
-clean_non_sharable(Dict0, Lbls0) ->
+clean_non_sharable(Dict) ->
%% We are passing in or out of a 'catch' or 'try' block. Remove
%% sequences that should not be shared over the boundaries of the
%% block. Since the end of the sequence must match, the only
@@ -203,17 +198,7 @@ clean_non_sharable(Dict0, Lbls0) ->
%% the 'catch'/'try' block is a sequence that ends with an
%% instruction that causes an exception. Any sequence that causes
%% an exception must contain a line/1 instruction.
- Dict1 = maps:to_list(Dict0),
- Lbls1 = maps:to_list(Lbls0),
- {Dict2,Lbls2} = foldl(fun({K, V}, {Dict,Lbls}) ->
- case sharable_with_try(K) of
- true ->
- {[{K,V}|Dict],lists:keydelete(V, 2, Lbls)};
- false ->
- {Dict,Lbls}
- end
- end, {[],Lbls1}, Dict1),
- {maps:from_list(Dict2),maps:from_list(Lbls2)}.
+ maps:filter(fun(K, _V) -> sharable_with_try(K) end, Dict).
sharable_with_try([{line,_}|_]) ->
%% This sequence may cause an exception and may potentially
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index a13bdedaf9..47042c2393 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1275,13 +1275,18 @@ let_subst_list([], [], _) -> {[],[],[]}.
%%pattern(Pat, Sub) -> pattern(Pat, Sub, Sub).
pattern(#c_var{}=Pat, Isub, Osub) ->
- case sub_is_val(Pat, Isub) of
+ case sub_is_in_scope(Pat, Isub) of
true ->
+ %% This variable either has a substitution or is used in
+ %% the variable list of an enclosing `let`. In either
+ %% case, it must be renamed to an unused name to avoid
+ %% name capture problems.
V1 = make_var_name(),
Pat1 = #c_var{name=V1},
{Pat1,sub_set_var(Pat, Pat1, sub_add_scope([V1], Osub))};
false ->
- {Pat,sub_del_var(Pat, Osub)}
+ %% This variable has never been used. Add it to the scope.
+ {Pat,sub_add_scope([Pat#c_var.name], Osub)}
end;
pattern(#c_literal{}=Pat, _, Osub) -> {Pat,Osub};
pattern(#c_cons{anno=Anno,hd=H0,tl=T0}, Isub, Osub0) ->
@@ -1460,8 +1465,8 @@ is_subst(_) -> false.
%% sub_set_name(Name, Value, #sub{}) -> #sub{}.
%% sub_del_var(Var, #sub{}) -> #sub{}.
%% sub_subst_var(Var, Value, #sub{}) -> [{Name,Value}].
-%% sub_is_val(Var, #sub{}) -> boolean().
-%% sub_add_scope(#sub{}) -> #sub{}
+%% sub_is_in_scope(Var, #sub{}) -> boolean().
+%% sub_add_scope([Var], #sub{}) -> #sub{}
%% sub_subst_scope(#sub{}) -> #sub{}
%%
%% We use the variable name as key so as not have problems with
@@ -1496,18 +1501,6 @@ sub_set_name(V, Val, #sub{v=S,s=Scope,t=Tdb0}=Sub) ->
Tdb = copy_type(V, Val, Tdb1),
Sub#sub{v=orddict:store(V, Val, S),s=cerl_sets:add_element(V, Scope),t=Tdb}.
-sub_del_var(#c_var{name=V}, #sub{v=S,s=Scope,t=Tdb}=Sub) ->
- %% Profiling shows that for programs with many record operations,
- %% sub_del_var/2 is a bottleneck. Since the scope contains all
- %% variables that are live, we know that V cannot be present in S
- %% if it is not in the scope.
- case cerl_sets:is_element(V, Scope) of
- false ->
- Sub#sub{s=cerl_sets:add_element(V, Scope)};
- true ->
- Sub#sub{v=orddict:erase(V, S),t=kill_types(V, Tdb)}
- end.
-
sub_subst_var(#c_var{name=V}, Val, #sub{v=S0}) ->
%% Fold chained substitutions.
[{V,Val}] ++ [ {K,Val} || {K,#c_var{name=V1}} <- S0, V1 =:= V].
@@ -1533,16 +1526,8 @@ sub_subst_scope_1([H|T], Key, Acc) ->
sub_subst_scope_1(T, Key-1, [{Key,#c_var{name=H}}|Acc]);
sub_subst_scope_1([], _, Acc) -> Acc.
-sub_is_val(#c_var{name=V}, #sub{v=S,s=Scope}) ->
- %% When the bottleneck in sub_del_var/2 was eliminated, this
- %% became the new bottleneck. Since the scope contains all
- %% live variables, a variable V can only be the target for
- %% a substitution if it is in the scope.
- cerl_sets:is_element(V, Scope) andalso v_is_value(V, S).
-
-v_is_value(Var, [{_,#c_var{name=Var}}|_]) -> true;
-v_is_value(Var, [_|T]) -> v_is_value(Var, T);
-v_is_value(_, []) -> false.
+sub_is_in_scope(#c_var{name=V}, #sub{s=Scope}) ->
+ cerl_sets:is_element(V, Scope).
%% warn_no_clause_match(CaseOrig, CaseOpt) -> ok
%% Generate a warning if none of the user-specified clauses
diff --git a/lib/compiler/src/sys_core_inline.erl b/lib/compiler/src/sys_core_inline.erl
index 8c1f69d5de..eee3594922 100644
--- a/lib/compiler/src/sys_core_inline.erl
+++ b/lib/compiler/src/sys_core_inline.erl
@@ -143,7 +143,7 @@ inline_inline(#ifun{body=B,weight=Iw}=If, Is) ->
case find_inl(F, A, Is) of
#ifun{vars=Vs,body=B2,weight=W} when W < Iw ->
#c_let{vars=Vs,
- arg=core_lib:make_values(As),
+ arg=kill_id_anns(core_lib:make_values(As)),
body=kill_id_anns(B2)};
_Other -> Call
end;
@@ -160,7 +160,7 @@ inline_func(#fstat{def={Name,F0}}=Fstat, Is) ->
case find_inl(F, A, Is) of
#ifun{vars=Vs,body=B} ->
{#c_let{vars=Vs,
- arg=core_lib:make_values(As),
+ arg=kill_id_anns(core_lib:make_values(As)),
body=kill_id_anns(B)},
true}; %Have modified
_Other -> {Call,Mod}
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 0e07e8dd2e..d07cd3b8b7 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -29,7 +29,7 @@
bs_shadowed_size_var/1,
cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1,
cover_v3_kernel_4/1,cover_v3_kernel_5/1,
- non_variable_apply/1]).
+ non_variable_apply/1,name_capture/1]).
-include_lib("common_test/include/ct.hrl").
@@ -58,7 +58,7 @@ groups() ->
bs_shadowed_size_var,
cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3,
cover_v3_kernel_4,cover_v3_kernel_5,
- non_variable_apply
+ non_variable_apply,name_capture
]}].
@@ -93,6 +93,7 @@ end_per_group(_GroupName, Config) ->
?comp(cover_v3_kernel_4).
?comp(cover_v3_kernel_5).
?comp(non_variable_apply).
+?comp(name_capture).
try_it(Mod, Conf) ->
Src = filename:join(proplists:get_value(data_dir, Conf),
diff --git a/lib/compiler/test/core_SUITE_data/name_capture.core b/lib/compiler/test/core_SUITE_data/name_capture.core
new file mode 100644
index 0000000000..0969f95b72
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/name_capture.core
@@ -0,0 +1,110 @@
+module 'name_capture' ['module_info'/0,
+ 'module_info'/1,
+ 'name_capture'/0]
+ attributes ['compile' =
+ [{'inline',[{'badarg_exit',2}]}]]
+'name_capture'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ let <_0> =
+ catch
+ apply 'first'/1
+ ('badarg')
+ in case _0 of
+ <{'EXIT',{'badarg',_7}}> when 'true' ->
+ let <Seq> =
+ call 'lists':'seq'
+ (7, 17)
+ in case apply 'first'/1
+ ({'ok',Seq}) of
+ <_8>
+ when call 'erlang':'=:='
+ (_8,
+ Seq) ->
+ let <SomeOtherTerm> =
+ {'some','other','term'}
+ in let <_5> =
+ catch
+ apply 'first'/1
+ (SomeOtherTerm)
+ in case _5 of
+ <{'EXIT',_9}>
+ when call 'erlang':'=:='
+ (_9,
+ SomeOtherTerm) ->
+ 'ok'
+ <_6> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_6})
+ end
+ <_3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_3})
+ end
+ <_1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_1})
+ end
+ <> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause'})
+ end
+'first'/1 =
+ fun (_0) ->
+ case _0 of
+ <Tab> when 'true' ->
+ let <_1> =
+ apply 'treq'/2
+ (Tab, 'first')
+ %% The _1 variable in the `let` must be renamed
+ %% to avoid a name capture problem.
+ in let <_0,_1> =
+ <_1,[Tab|[]]>
+ in case <_0,_1> of
+ <'badarg',A> when 'true' ->
+ call 'erlang':'error'
+ ('badarg', A)
+ <{'ok',Reply},_X_A> when 'true' ->
+ Reply
+ <Reply,_X_A> when 'true' ->
+ call 'erlang':'exit'
+ (Reply)
+ <_3,_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_3,_2})
+ end
+ <_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_2})
+ end
+'treq'/2 =
+ fun (_0,_1) ->
+ case <_0,_1> of
+ <Action,_4> when 'true' ->
+ Action
+ <_3,_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_3,_2})
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('name_capture')
+ <> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause'})
+ end
+'module_info'/1 =
+ fun (_0) ->
+ case _0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('name_capture', X)
+ <_1> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_1})
+ end
+end
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index a26cb09dff..ee75ee27fd 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.2
+COMPILER_VSN = 7.1.5