aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/beam_emu.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/beam_emu.c')
-rw-r--r--erts/emulator/beam/beam_emu.c69
1 files changed, 57 insertions, 12 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 145ae48590..8661d7cbf5 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -228,9 +228,10 @@ BeamInstr* em_call_traced_function;
** for the refering variable (one of these), and rouge references
** will most likely cause chaos.
*/
-BeamInstr beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
-BeamInstr beam_return_trace[1]; /* OpCode(i_return_trace) */
-BeamInstr beam_exception_trace[1]; /* UGLY also OpCode(i_return_trace) */
+BeamInstr beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
+BeamInstr beam_return_trace[1]; /* OpCode(i_return_trace) */
+BeamInstr beam_exception_trace[1]; /* UGLY also OpCode(i_return_trace) */
+BeamInstr beam_time_return_trace[1]; /* OpCode(i_time_return_trace) */
/*
* All Beam instructions in numerical order.
@@ -4411,6 +4412,7 @@ apply_bif_or_nif_epilogue:
OpCase(i_time_breakpoint): {
BeamInstr real_I;
BpDataTime *bdt = (BpDataTime *) (I)[-4];
+ Uint tail_call = 0;
ASSERT((I)[-5] == (Uint) BeamOp(op_i_func_info_IaaI));
ASSERT(bdt);
@@ -4418,12 +4420,53 @@ apply_bif_or_nif_epilogue:
ASSERT(bdt);
(I)[-4] = (Uint) bdt;
real_I = bdt->orig_instr;
- erts_do_time_break(c_p, bdt);
-
ASSERT(VALID_INSTR(real_I));
+
+ if (IS_TRACED_FL(c_p, F_TRACE_CALLS) && !(bdt->pause)) {
+ if (*cp_val((Eterm)c_p->cp) == (BeamInstr) OpCode(i_time_return_trace)) {
+ tail_call = 1;
+ }
+
+ if (tail_call) {
+ /* This _IS_ a tail recursive call */
+ SWAPOUT;
+ erts_do_time_break(c_p, bdt, ERTS_BP_CALL_TIME_TAIL_CALL);
+ SWAPIN;
+ } else {
+ SWAPOUT;
+ erts_do_time_break(c_p, bdt, ERTS_BP_CALL_TIME_CALL);
+
+ ASSERT(c_p->htop <= E && E <= c_p->hend);
+ if (E - 2 < HTOP) {
+ PROCESS_MAIN_CHK_LOCKS(c_p);
+ FCALLS -= erts_garbage_collect(c_p, 2, reg, I[-1]);
+ PROCESS_MAIN_CHK_LOCKS(c_p);
+ }
+ SWAPIN;
+
+ ASSERT(c_p->htop <= E && E <= c_p->hend);
+
+ E -= 2;
+ E[1] = make_cp(c_p->cp); /* original return address */
+ E[0] = make_cp((Uint *)bdt); /* make sure bdt is allocated in low mem (for halfword) */
+ c_p->cp = (Eterm *) make_cp(beam_time_return_trace);
+ }
+ }
+
Goto(real_I);
}
+ OpCase(i_time_return_trace): {
+ BpDataTime *bdt = (BpDataTime *) cp_val((E)[0]);
+ SWAPOUT;
+ erts_do_time_break(c_p, bdt, ERTS_BP_CALL_TIME_RETURN);
+ SWAPIN;
+ c_p->cp = NULL;
+ SET_I((Eterm *) E[1]);
+ E += 2;
+ Goto(*I);
+ }
+
OpCase(i_trace_breakpoint):
if (! IS_TRACED_FL(c_p, F_TRACE_CALLS)) {
BeamInstr real_I;
@@ -4973,13 +5016,15 @@ apply_bif_or_nif_epilogue:
em_call_error_handler = OpCode(call_error_handler);
em_call_traced_function = OpCode(call_traced_function);
em_apply_bif = OpCode(apply_bif);
- beam_apply[0] = (BeamInstr) OpCode(i_apply);
- beam_apply[1] = (BeamInstr) OpCode(normal_exit);
- beam_exit[0] = (BeamInstr) OpCode(error_action_code);
- beam_continue_exit[0] = (BeamInstr) OpCode(continue_exit);
- beam_return_to_trace[0] = (BeamInstr) OpCode(i_return_to_trace);
- beam_return_trace[0] = (BeamInstr) OpCode(return_trace);
- beam_exception_trace[0] = (BeamInstr) OpCode(return_trace); /* UGLY */
+
+ beam_apply[0] = (BeamInstr) OpCode(i_apply);
+ beam_apply[1] = (BeamInstr) OpCode(normal_exit);
+ beam_exit[0] = (BeamInstr) OpCode(error_action_code);
+ beam_continue_exit[0] = (BeamInstr) OpCode(continue_exit);
+ beam_return_to_trace[0] = (BeamInstr) OpCode(i_return_to_trace);
+ beam_return_trace[0] = (BeamInstr) OpCode(return_trace);
+ beam_exception_trace[0] = (BeamInstr) OpCode(return_trace); /* UGLY */
+ beam_time_return_trace[0] = (BeamInstr) OpCode(i_time_return_trace);
/*
* Enter all BIFs into the export table.