aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2017-07-10 08:42:57 +0200
committerGitHub <[email protected]>2017-07-10 08:42:57 +0200
commitb805af3e618175ac78b39ce6f60aa6d63e865198 (patch)
tree90e68e05c7376b2175e3fe124a12f2c8ceb7e6dc /erts
parent522e9e8fbcef3102293af23a0d05b106126789aa (diff)
parente8d45ae14c6c3bdfcbbc7964228b004ef4f11ea6 (diff)
downloadotp-b805af3e618175ac78b39ce6f60aa6d63e865198.tar.gz
otp-b805af3e618175ac78b39ce6f60aa6d63e865198.tar.bz2
otp-b805af3e618175ac78b39ce6f60aa6d63e865198.zip
josevalim/jv-op-stacktrace-entry/PR-1478/OTP-14508
Add stacktrace entries to BIF calls from emulator
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/beam_emu.c66
-rw-r--r--erts/emulator/test/exception_SUITE.erl82
2 files changed, 109 insertions, 39 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 507aa7636c..c7503aff71 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -204,6 +204,21 @@ do { \
#define ISCATCHEND(instr) ((Eterm *) *(instr) == OpCode(catch_end_y))
+#define BIF_ERROR_ARITY_1(Op1, BIF) \
+ if (Arg(0) != 0) goto jump_f; \
+ reg[0] = Op1; \
+ SWAPOUT; \
+ I = handle_error(c_p, I, reg, &bif_export[BIF]->info.mfa); \
+ goto post_error_handling
+
+#define BIF_ERROR_ARITY_2(Op1, Op2, BIF) \
+ if (Arg(0) != 0) goto jump_f; \
+ reg[0] = Op1; \
+ reg[1] = Op2; \
+ SWAPOUT; \
+ I = handle_error(c_p, I, reg, &bif_export[BIF]->info.mfa); \
+ goto post_error_handling
+
/*
* Special Beam instructions.
*/
@@ -1486,7 +1501,7 @@ void process_main(Eterm * x_reg_array, FloatDef* f_reg_array)
goto find_func_info;
}
-#define DO_OUTLINED_ARITH_2(name, Op1, Op2) \
+#define DO_OUTLINED_ARITH_2(name, Op1, Op2, BIF)\
do { \
Eterm result; \
Uint live = Arg(1); \
@@ -1500,7 +1515,7 @@ void process_main(Eterm * x_reg_array, FloatDef* f_reg_array)
if (is_value(result)) { \
StoreBifResult(4, result); \
} \
- goto lb_Cl_error; \
+ BIF_ERROR_ARITY_2(reg[live], reg[live+1], BIF);\
} while (0)
{
@@ -1530,7 +1545,7 @@ void process_main(Eterm * x_reg_array, FloatDef* f_reg_array)
StoreBifResult(4, result);
}
}
- DO_OUTLINED_ARITH_2(mixed_plus, PlusOp1, PlusOp2);
+ DO_OUTLINED_ARITH_2(mixed_plus, PlusOp1, PlusOp2, BIF_splus_2);
}
{
@@ -1555,7 +1570,7 @@ void process_main(Eterm * x_reg_array, FloatDef* f_reg_array)
StoreBifResult(4, result);
}
}
- DO_OUTLINED_ARITH_2(mixed_minus, MinusOp1, MinusOp2);
+ DO_OUTLINED_ARITH_2(mixed_minus, MinusOp1, MinusOp2, BIF_sminus_2);
}
{
@@ -1771,8 +1786,9 @@ void process_main(Eterm * x_reg_array, FloatDef* f_reg_array)
StoreBifResult(3, result);
}
}
+ c_p->freason = BADARG;
+ BIF_ERROR_ARITY_2(element_index, element_tuple, BIF_element_2);
}
- /* Fall through */
OpCase(badarg_j):
badarg:
@@ -1799,7 +1815,8 @@ void process_main(Eterm * x_reg_array, FloatDef* f_reg_array)
StoreBifResult(3, result);
}
}
- goto badarg;
+ c_p->freason = BADARG;
+ BIF_ERROR_ARITY_2(make_small(Arg(2)), fast_element_tuple, BIF_element_2);
}
OpCase(catch_yf):
@@ -2941,14 +2958,14 @@ do { \
{
Eterm Op1, Op2;
GetArg2(2, Op1, Op2);
- DO_OUTLINED_ARITH_2(mixed_times, Op1, Op2);
+ DO_OUTLINED_ARITH_2(mixed_times, Op1, Op2, BIF_stimes_2);
}
OpCase(i_m_div_jIssd):
{
Eterm Op1, Op2;
GetArg2(2, Op1, Op2);
- DO_OUTLINED_ARITH_2(mixed_div, Op1, Op2);
+ DO_OUTLINED_ARITH_2(mixed_div, Op1, Op2, BIF_div_2);
}
OpCase(i_int_div_jIssd):
@@ -2957,7 +2974,8 @@ do { \
GetArg2(2, Op1, Op2);
if (Op2 == SMALL_ZERO) {
- goto badarith;
+ c_p->freason = BADARITH;
+ BIF_ERROR_ARITY_2(Op1, Op2, BIF_intdiv_2);
} else if (is_both_small(Op1, Op2)) {
Sint ires = signed_val(Op1) / signed_val(Op2);
if (MY_IS_SSMALL(ires)) {
@@ -2965,7 +2983,7 @@ do { \
StoreBifResult(4, result);
}
}
- DO_OUTLINED_ARITH_2(int_div, Op1, Op2);
+ DO_OUTLINED_ARITH_2(int_div, Op1, Op2, BIF_intdiv_2);
}
{
@@ -2982,12 +3000,13 @@ do { \
do_rem:
if (RemOp2 == SMALL_ZERO) {
- goto badarith;
+ c_p->freason = BADARITH;
+ BIF_ERROR_ARITY_2(RemOp1, RemOp2, BIF_rem_2);
} else if (is_both_small(RemOp1, RemOp2)) {
Eterm result = make_small(signed_val(RemOp1) % signed_val(RemOp2));
StoreBifResult(4, result);
} else {
- DO_OUTLINED_ARITH_2(int_rem, RemOp1, RemOp2);
+ DO_OUTLINED_ARITH_2(int_rem, RemOp1, RemOp2, BIF_rem_2);
}
}
@@ -3011,7 +3030,7 @@ do { \
Eterm result = BandOp1 & BandOp2;
StoreBifResult(4, result);
}
- DO_OUTLINED_ARITH_2(band, BandOp1, BandOp2);
+ DO_OUTLINED_ARITH_2(band, BandOp1, BandOp2, BIF_band_2);
}
/*
@@ -3044,7 +3063,7 @@ do { \
Eterm result = Op1 | Op2;
StoreBifResult(4, result);
}
- DO_OUTLINED_ARITH_2(bor, Op1, Op2);
+ DO_OUTLINED_ARITH_2(bor, Op1, Op2, BIF_bor_2);
}
OpCase(i_bxor_jIssd):
@@ -3062,7 +3081,7 @@ do { \
Eterm result = (Op1 ^ Op2) | make_small(0);
StoreBifResult(4, result);
}
- DO_OUTLINED_ARITH_2(bxor, Op1, Op2);
+ DO_OUTLINED_ARITH_2(bxor, Op1, Op2, BIF_bxor_2);
}
{
@@ -3093,8 +3112,9 @@ do { \
Op2 = make_small(bignum_header_is_neg(*big_val(Op2)) ?
MAX_SMALL : MIN_SMALL);
goto do_bsl;
- }
- goto badarith;
+ }
+ c_p->freason = BADARITH;
+ BIF_ERROR_ARITY_2(Op1, Op2, BIF_bsr_2);
OpCase(i_bsl_jIssd):
GetArg2(2, Op1, Op2);
@@ -3194,10 +3214,8 @@ do { \
}
/* Fall through if the left argument is not an integer. */
}
- /*
- * One or more non-integer arguments.
- */
- goto badarith;
+ c_p->freason = BADARITH;
+ BIF_ERROR_ARITY_2(Op1, Op2, BIF_bsl_2);
}
OpCase(i_int_bnot_jsId):
@@ -3215,16 +3233,12 @@ do { \
HEAVY_SWAPIN;
ERTS_HOLE_CHECK(c_p);
if (is_nil(bnot_val)) {
- goto lb_Cl_error;
+ BIF_ERROR_ARITY_1(reg[live], BIF_bnot_1);
}
}
StoreBifResult(3, bnot_val);
}
- badarith:
- c_p->freason = BADARITH;
- goto lb_Cl_error;
-
OpCase(i_apply): {
BeamInstr *next;
HEAVY_SWAPOUT;
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index aaca522da6..e473a10be7 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -21,7 +21,7 @@
-module(exception_SUITE).
-export([all/0, suite/0,
- badmatch/1, pending_errors/1, nil_arith/1,
+ badmatch/1, pending_errors/1, nil_arith/1, top_of_stacktrace/1,
stacktrace/1, nested_stacktrace/1, raise/1, gunilla/1, per/1,
exception_with_heap_frag/1, line_numbers/1]).
@@ -36,8 +36,8 @@ suite() ->
{timetrap, {minutes, 1}}].
all() ->
- [badmatch, pending_errors, nil_arith, stacktrace,
- nested_stacktrace, raise, gunilla, per,
+ [badmatch, pending_errors, nil_arith, top_of_stacktrace,
+ stacktrace, nested_stacktrace, raise, gunilla, per,
exception_with_heap_frag, line_numbers].
-define(try_match(E),
@@ -241,7 +241,54 @@ ba_bnot(A) ->
io:format("bnot ~p", [A]),
{'EXIT', {badarith, _}} = (catch bnot A).
+%% Test that BIFs are added to the top of the stacktrace.
+
+top_of_stacktrace(Conf) when is_list(Conf) ->
+ %% Arithmetic operators
+ {'EXIT', {badarith, [{erlang, '+', [1, ok], _} | _]}} = (catch my_add(1, ok)),
+ {'EXIT', {badarith, [{erlang, '-', [1, ok], _} | _]}} = (catch my_minus(1, ok)),
+ {'EXIT', {badarith, [{erlang, '*', [1, ok], _} | _]}} = (catch my_times(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'div', [1, ok], _} | _]}} = (catch my_div(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'div', [1, 0], _} | _]}} = (catch my_div(1, 0)),
+ {'EXIT', {badarith, [{erlang, 'rem', [1, ok], _} | _]}} = (catch my_rem(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'rem', [1, 0], _} | _]}} = (catch my_rem(1, 0)),
+
+ %% Bit operators
+ {'EXIT', {badarith, [{erlang, 'band', [1, ok], _} | _]}} = (catch my_band(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'bor', [1, ok], _} | _]}} = (catch my_bor(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'bsl', [1, ok], _} | _]}} = (catch my_bsl(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'bsr', [1, ok], _} | _]}} = (catch my_bsr(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'bxor', [1, ok], _} | _]}} = (catch my_bxor(1, ok)),
+ {'EXIT', {badarith, [{erlang, 'bnot', [ok], _} | _]}} = (catch my_bnot(ok)),
+
+ %% Tuples
+ {'EXIT', {badarg, [{erlang, element, [1, ok], _} | _]}} = (catch my_element(1, ok)),
+ {'EXIT', {badarg, [{erlang, element, [ok, {}], _} | _]}} = (catch my_element(ok, {})),
+ {'EXIT', {badarg, [{erlang, element, [1, {}], _} | _]}} = (catch my_element(1, {})),
+ {'EXIT', {badarg, [{erlang, element, [1, {}], _} | _]}} = (catch element(1, erlang:make_tuple(0, ok))),
+
+ %% System limits
+ Maxbig = maxbig(),
+ MinusMaxbig = -Maxbig,
+ {'EXIT', {system_limit, [{erlang, '+', [Maxbig, 1], _} | _]}} = (catch my_add(Maxbig, 1)),
+ {'EXIT', {system_limit, [{erlang, '+', [Maxbig, 1], _} | _]}} = (catch my_add(maxbig_gc(), 1)),
+ {'EXIT', {system_limit, [{erlang, '-', [MinusMaxbig, 1], _} | _]}} = (catch my_minus(-Maxbig, 1)),
+ {'EXIT', {system_limit, [{erlang, '-', [MinusMaxbig, 1], _} | _]}} = (catch my_minus(-maxbig_gc(), 1)),
+ {'EXIT', {system_limit, [{erlang, '*', [Maxbig, 2], _} | _]}} = (catch my_times(Maxbig, 2)),
+ {'EXIT', {system_limit, [{erlang, '*', [Maxbig, 2], _} | _]}} = (catch my_times(maxbig_gc(), 2)),
+ {'EXIT', {system_limit, [{erlang, 'bnot', [Maxbig], _} | _]}} = (catch my_bnot(Maxbig)),
+ {'EXIT', {system_limit, [{erlang, 'bnot', [Maxbig], _} | _]}} = (catch my_bnot(maxbig_gc())),
+ ok.
+
+maxbig() ->
+ %% We assume that the maximum arity is (1 bsl 19) - 1.
+ Ws = erlang:system_info(wordsize),
+ (((1 bsl ((16777184 * (Ws div 4))-1)) - 1) bsl 1) + 1.
+maxbig_gc() ->
+ Maxbig = maxbig(),
+ erlang:garbage_collect(),
+ Maxbig.
stacktrace(Conf) when is_list(Conf) ->
Tag = make_ref(),
@@ -253,9 +300,9 @@ stacktrace(Conf) when is_list(Conf) ->
St1 = erase(stacktrace1),
St1 = erase(stacktrace2),
St1 = erlang:get_stacktrace(),
- {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]=St2} =
+ {caught2,{error,badarith},[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]=St2} =
stacktrace_1({'div',{1,0}}, error, {'add',{0,a}}),
- [{?MODULE,my_div,2,_}|_] = erase(stacktrace1),
+ [{erlang,'div',[1,0],_},{?MODULE,my_div,2,_}|_] = erase(stacktrace1),
St2 = erase(stacktrace2),
St2 = erlang:get_stacktrace(),
{caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]=St3} =
@@ -308,13 +355,13 @@ nested_stacktrace(Conf) when is_list(Conf) ->
nested_stacktrace_1({{value,{V,x1}},void,{V,x1}},
{void,void,void}),
{caught1,
- [{?MODULE,my_add,2,_}|_],
+ [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
value2,
- [{?MODULE,my_add,2,_}|_]} =
+ [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_]} =
nested_stacktrace_1({{'add',{V,x1}},error,badarith},
{{value,{V,x2}},void,{V,x2}}),
{caught1,
- [{?MODULE,my_add,2,_}|_],
+ [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
{caught2,[{erlang,abs,[V],_}|_]},
[{erlang,abs,[V],_}|_]} =
nested_stacktrace_1({{'add',{V,x1}},error,badarith},
@@ -355,7 +402,7 @@ raise(Conf) when is_list(Conf) ->
end,
A = erlang:get_stacktrace(),
A = get(raise),
- [{?MODULE,my_div,2,_}|_] = A,
+ [{erlang,'div',[1, 0], _},{?MODULE,my_div,2,_}|_] = A,
%%
N = 8, % Must be even
N = erlang:system_flag(backtrace_depth, N),
@@ -404,11 +451,20 @@ foo({raise,{Class,Reason,Stacktrace}}) ->
erlang:raise(Class, Reason, Stacktrace).
%%foo(function_clause) -> % must not be defined!
-my_div(A, B) ->
- A div B.
+my_add(A, B) -> A + B.
+my_minus(A, B) -> A - B.
+my_times(A, B) -> A * B.
+my_div(A, B) -> A div B.
+my_rem(A, B) -> A rem B.
+
+my_band(A, B) -> A band B.
+my_bor(A, B) -> A bor B.
+my_bsl(A, B) -> A bsl B.
+my_bsr(A, B) -> A bsr B.
+my_bxor(A, B) -> A bxor B.
+my_bnot(A) -> bnot A.
-my_add(A, B) ->
- A + B.
+my_element(A, B) -> element(A, B).
my_abs(X) -> abs(X).