Age | Commit message (Collapse) | Author |
|
|
|
Commits 53bd4974a101 and 726f6e4c7afe simplified the handling of
match_fail (used to generated exceptions such as 'function_clause')
by first rewriting them to a call to erlang/error{1,2} and later
rewriting them to specialized BEAM instructions (to reduce the
code size).
There was one flaw, though, which only was exposed when more
aggressive optimizations were added in c3b60f86c622. Here is an
example to explain it:
t(V) ->
fun(get) -> V end.
The following BEAM code will be initially generated for the fun:
{function, '-t/1-fun-0-', 2, 5}.
{label,1}.
{line,[{location,"t.erl",5}]}.
{func_info,{atom,t},{atom,'-t/1-fun-0-'},2}.
{label,2}.
{test,is_eq_exact,{f,2},[{x,0},{atom,get}]}.
{move,{x,1},{x,0}}.
return.
{label,2}.
{test_heap,2,1}.
{put_list,{x,0},nil,{x,1}}.
{move,{atom,function_clause},{x,0}}.
{line,[{location,"t.erl",5}]}.
{call_ext_only,2,{extfunc,erlang,error,2}}.
Translating back to Erlang code, that would be roughly:
'-t/1-fun-0-'(get, V) -> V;
'-t/1-fun-0-'(Arg1, _) -> erlang:error(function_clause, [Arg1]).
Note that the second argument (the free variable V) is not included
in the call to erlang:error/2.
The beam_except pass will simplify the code to:
{function, '-t/1-fun-0-', 2, 8}.
{label,1}.
{line,[{location,"t.erl",5}]}.
{func_info,{atom,t},{atom,'-t/1-fun-0-'},2}.
{label,2}.
{test,is_eq_exact,{f,1},[{x,0},{atom,get}]}.
{move,{x,1},{x,0}}.
return.
The code has been shortened by jumping to the func_info/3 instruction.
Translating back to Erlang:
'-t/1-fun-0-'(get, V) -> V;
'-t/1-fun-0-'(Arg1, Arg2) -> erlang:error(function_clause, [Arg1,Arg2]).
it is clear that both arguments are now included in the
'function_clause' exception, even though the initially generated
code only included the first argument.
That is no problem in this particular case, but for some more complex
funs, optimizing the first version based on variable usage could make
the second version unsafe.
I rejected the following potential solutions:
- Including the free arguments in the call to erlang:error/2:
'-t/1-fun-0-'(get, V) -> V;
'-t/1-fun-0-'(Arg1, Arg2) -> erlang:error(function_clause, [Arg1,Arg2]).
Unfortunately, that is tricky. The free variables are only known
after the second pass in v3_kernel when variable usage has been
calculated. We would need to add a third pass (only for funs) that
would the free arguments to the second argument for erlang:error/2
*and* update the variable usage information.
- Calling beam_except earlier, from within beam_block before any
optimizations based on variable usages are done. But means that the
problem could reappear in some other form in the future when other
updates are done to the code generator and/or optimization passes.
The solution I have chosen is to modify beam_except to only replace
a call to erlang:error(function_class, Args) if the length of Args
is the same as the arity in the func_info/3 instruction. The code
will be slightly larger. Also, the free variables for funs and list
comprehensions will no longer be included in the function_clause
exception (that could be less confusing, but it also means less
information during debugging).
|
|
|
|
Run testcases in parallel will make the test suite run slightly
faster. Another reason for this change is that we want more testing
of parallel testcase support in common_test.
|
|
The bs_match_string instruction is used to speed up matching of
binary literals. For example, given this source code:
foo1(<<1,2,3>>) -> ok.
The matching part of the code will look like:
{test,bs_start_match2,{f,1},1,[{x,0},0],{x,0}}.
{test,bs_match_string,{f,3},[{x,0},24,{string,[1,2,3]}]}.
{test,bs_test_tail2,{f,3},[{x,0},0]}.
Nice. However, if we do a simple change to the source code:
foo2(<<1,2,3>>) -> ok;
foo2(<<>>) -> error.
the resulting matching code will look like (sligthly simplified):
{test,bs_start_match2,{f,4},1,[{x,0},0],{x,0}}.
{test,bs_get_integer2,{f,7},1,[{x,0},{integer,8},1,Flags],{x,1}}.
{test,is_eq_exact,{f,8},[{x,1},{integer,1}]}.
{test,bs_match_string,{f,6},[{x,0},16,{string,[2,3]}]}.
{test,bs_test_tail2,{f,6},[{x,0},0]}.
{move,{atom,ok},{x,0}}.
return.
{label,6}.
{bs_restore2,{x,0},{atom,start}}.
{label,7}.
{test,bs_test_tail2,{f,8},[{x,0},0]}.
That is, matching of the first byte is not combined into the
bs_match_string instruction that follows.
Fix this problem by allowing a bs_match_string instruction to be
used if all clauses will match either the same integer literal or
the empty binary.
|
|
|
|
The inliner was ignorant of on_load functions and would discard them
(unless they were exported or referenced).
Noticed-by: Yiannis Tsiouris <[email protected]>
|
|
On my Mac Pro with 8 cores, this change make self_compile/1 more
than twice as fast, and self_compile_old_inliner/1 more than 4 times
faster.
|
|
In the self compilation test cases, the compiler compiles itself
and runs the newly compiled version on a slave node. Having the
cover server starting on the slave node defeats the purpose of
the test, since it will load the SAME cover-compiled code on the
slave node. (It will also be slower, but will not improve coverage
since it compiles the same source files again.)
Use a shielded node to prevent the cover server from getting
started on the slave node.
|
|
In the v3_life pass, it is assumed that a 'match_fail' primop
only occur at the top-level and at the end of a function.
But this code:
do_split_cases(A) ->
case A of
x ->
Z = dummy1;
_ ->
Z = dummy2,
a=b
end,
Z.
will be optimized by sys_core_fold to the following code:
'split_cases'/1 =
fun (_cor0) ->
let <_cor7,Z> =
case _cor0 of
<'x'> when 'true' ->
< 'dummy1','dummy1' >
<_cor6> when 'true' ->
%% Here follows a 'match_fail' primop inside
%% multiple return values:
< primop 'match_fail'({'badmatch','b'}),'dummy2' >
end
in
Z
moving the 'match_fail' primop into a "values" construction.
In the future, we would like to get rid of the v3_life pass (it is
there for historical reasons), so in the mean-time we prefer to not
add more code to it by generalizing the handling of 'match_fail'.
Since the 'match_fail' primop can be simulated by erlang:error/{1,2},
the simplest solution is to translate 'match_fail' to a call to
erlang:error/{1,2} in v3_kernel and remove the handling of
'match_fail' in v3_life and v3_codegen.
It is tempting to get rid of 'match_fail' also in the Core Erlang
format, but there are two issues:
- Removing the support for 'match_fail' completely may break tools
that generate Core Erlang code. We should not do that in a minor
release.
- There is no easy way to generate a 'function_clause' exception
that will remain correct if it will be inlined into another
function. (Calling "erlang:error(function_clause, Args)" is
fine only if it is not inlined into another function.) A good
solution probably involves introducing new instructions, which
is better done in a major release.
Noticed-by: Håkan Matsson
Minimized-test-case-by: Erik Søe Sørensen
|
|
In 3d0f4a3085f11389e5b22d10f96f0cbf08c9337f (an update to conform
with common_test), in all test_lib:recompile(?MODULE) calls, ?MODULE
was changed to the actual name of the module. That would cause
test_lib:recompile/1 to compile the module with the incorrect
compiler options in cloned modules such as record_no_opt_SUITE,
causing worse coverage.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sometimes the beam_bool pass wants to know whether an
y register will be killed by the code that follows and
will do (effectively):
beam_utils:is_killed({y,Y}, Code, L)
When asked to calculate the liveness for an y register,
beam_utils:is_killed/3 will loop forever if the code
includes a receive loop.
Since this rarely occurs, fix the problem in the simplest
and most conservative way.
Reported-by: Christopher Williams
|
|
When gc_bif instructions occurred outside of a block,
beam_utils:check_liveness/3 did not take into account
that the instruction could do a garbage collection, and
could falsely report that an x register would be killed.
That could cause the beam_dead pass to make the code
unsafe by removing the assignment to an x register that
would subsequently be referenced by the garbage collector.
Reported-by: Christopher Williams
|
|
The code for generating the string table (which is now
only used for bit syntax matching) in a BEAM file is quite
complicated and potentially expensive when compiling modules
with many thousands of clauses doing bit syntax matching.
Simplify and optimize the code using bit syntax and
binary:match/2 instead of the list operations in the
original code.
|
|
|