aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2017-11-28 07:28:25 +0100
committerBjörn Gustavsson <[email protected]>2018-01-22 14:23:52 +0100
commit9b0122b65bdcafbae2a3cfd3299903da0948acab (patch)
tree59405671dad4d8240978faaf4ea8e3dcdff289b5 /lib/hipe
parentb7ff9c0d76372f16d14ecaac04c6fbbbadaf9435 (diff)
downloadotp-9b0122b65bdcafbae2a3cfd3299903da0948acab.tar.gz
otp-9b0122b65bdcafbae2a3cfd3299903da0948acab.tar.bz2
otp-9b0122b65bdcafbae2a3cfd3299903da0948acab.zip
Don't build a stacktrace if it's only passed to erlang:raise/3
Consider the following function: function({function,Name,Arity,CLabel,Is0}, Lc0) -> try %% Optimize the code for the function. catch Class:Error:Stack -> io:format("Function: ~w/~w\n", [Name,Arity]), erlang:raise(Class, Error, Stack) end. The stacktrace is retrieved, but it is only used in the call to erlang:raise/3. There is no need to build a stacktrace in this function. We can avoid the building if we introduce an instruction called raw_raise/3 that works exactly like the erlang:raise/3 BIF except that its third argument must be a raw stacktrace.
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl6
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl5
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl3
-rw-r--r--lib/hipe/rtl/hipe_rtl_primops.erl2
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_exceptions.erl97
5 files changed, 112 insertions, 1 deletions
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 7ff9fd83eb..6e66ec057c 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -1164,6 +1164,12 @@ trans_fun([build_stacktrace|Instructions], Env) ->
Vars = [mk_var({x,0})], %{x,0} is implict arg and dst
[hipe_icode:mk_primop(Vars,build_stacktrace,Vars),
trans_fun(Instructions, Env)];
+%%--- raw_raise ---
+trans_fun([raw_raise|Instructions], Env) ->
+ Vars = [mk_var({x,0}),mk_var({x,1}),mk_var({x,2})],
+ Dst = [mk_var({x,0})],
+ [hipe_icode:mk_primop(Dst,raw_raise,Vars) |
+ trans_fun(Instructions, Env)];
%%--------------------------------------------------------------------
%%--- ERROR HANDLING ---
%%--------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
index 941516e8b1..a1f1128124 100644
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ b/lib/hipe/icode/hipe_icode_primops.erl
@@ -236,6 +236,7 @@ fails({hipe_bs_primop, {bs_append, _, _, _, _}}) -> true;
fails({hipe_bs_primop, {bs_private_append, _, _}}) -> true;
fails({hipe_bs_primop, bs_init_writable}) -> true;
fails(build_stacktrace) -> false;
+fails(raw_raise) -> true;
fails(#mkfun{}) -> false;
fails(#unsafe_element{}) -> false;
fails(#unsafe_update_element{}) -> false;
@@ -735,6 +736,8 @@ type(Primop, Args) ->
erl_types:t_any();
build_stacktrace ->
erl_types:t_list();
+ raw_raise ->
+ erl_types:t_atom();
{M, F, A} ->
erl_bif_types:type(M, F, A, Args)
end.
@@ -909,6 +912,8 @@ type(Primop) ->
%%% Other
build_stacktrace ->
erl_types:t_any();
+ raw_raise ->
+ erl_types:t_any();
#closure_element{} ->
erl_types:t_any();
redtest ->
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
index cf74c1eb5b..34b18acccd 100644
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ b/lib/hipe/icode/hipe_icode_range.erl
@@ -1187,7 +1187,8 @@ basic_type(unsafe_tl) -> not_int;
basic_type(#element{}) -> not_analysed;
basic_type(#unsafe_element{}) -> not_analysed;
basic_type(#unsafe_update_element{}) -> not_analysed;
-basic_type(build_stacktrace) -> not_int.
+basic_type(build_stacktrace) -> not_int;
+basic_type(raw_raise) -> not_int.
-spec analyse_bs_get_integer(integer(), integer(), boolean()) -> range_tuple().
diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl
index d646b78a3d..ce5433379e 100644
--- a/lib/hipe/rtl/hipe_rtl_primops.erl
+++ b/lib/hipe/rtl/hipe_rtl_primops.erl
@@ -396,6 +396,8 @@ gen_primop({Op,Dst,Args,Cont,Fail}, IsGuard, ConstTab) ->
[hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
build_stacktrace ->
[hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
+ raw_raise ->
+ [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
%% Only names listed above are accepted! MFA:s are not primops!
_ ->
diff --git a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
index d71b924d22..ba9c03d4ba 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
@@ -24,6 +24,7 @@ test() ->
ok = test_bad_fun_call(),
ok = test_guard_bif(),
ok = test_eclectic(),
+ ok = test_raise(),
ok.
%%--------------------------------------------------------------------
@@ -579,3 +580,99 @@ my_add(A, B) ->
my_abs(X) ->
abs(X).
+
+test_raise() ->
+ test_raise(fun() -> exit({exit,tuple}) end),
+ test_raise(fun() -> abs(id(x)) end),
+ test_raise(fun() -> throw({was,thrown}) end),
+
+ badarg = bad_raise(fun() -> abs(id(x)) end),
+
+ ok.
+
+bad_raise(Expr) ->
+ try
+ Expr()
+ catch
+ _:E:Stk ->
+ erlang:raise(bad_class, E, Stk)
+ end.
+
+test_raise(Expr) ->
+ test_raise_1(Expr),
+ test_raise_2(Expr),
+ test_raise_3(Expr).
+
+test_raise_1(Expr) ->
+ erase(exception),
+ try
+ do_test_raise_1(Expr)
+ catch
+ C:E:Stk ->
+ {C,E,Stk} = erase(exception)
+ end.
+
+do_test_raise_1(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here the stacktrace must be built.
+ put(exception, {C,E,Stk}),
+ erlang:raise(C, E, Stk)
+ end.
+
+test_raise_2(Expr) ->
+ erase(exception),
+ try
+ do_test_raise_2(Expr)
+ catch
+ C:E:Stk ->
+ {C,E} = erase(exception),
+ try
+ Expr()
+ catch
+ _:_:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_2(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here it is possible to replace erlang:raise/3 with
+ %% the raw_raise/3 instruction since the stacktrace is
+ %% not actually used.
+ put(exception, {C,E}),
+ erlang:raise(C, E, Stk)
+ end.
+
+test_raise_3(Expr) ->
+ try
+ do_test_raise_3(Expr)
+ catch
+ exit:{exception,C,E}:Stk ->
+ try
+ Expr()
+ catch
+ C:E:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_3(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here it is possible to replace erlang:raise/3 with
+ %% the raw_raise/3 instruction since the stacktrace is
+ %% not actually used.
+ erlang:raise(exit, {exception,C,E}, Stk)
+ end.
+
+id(I) -> I.