summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/bif.c
diff options
context:
space:
mode:
authorJohn Högberg <john@erlang.org>2019-08-27 13:11:25 +0200
committerJohn Högberg <john@erlang.org>2019-09-16 14:21:25 +0200
commit40356bd2ae0e4f4c31204b3dd13d14541442f1a1 (patch)
treec3845959870988c148b2fbade94808bd1ebc0ae8 /erts/emulator/beam/bif.c
parent20cf78bed119da47c66c3efd77c8199b424582b7 (diff)
downloaderlang-40356bd2ae0e4f4c31204b3dd13d14541442f1a1.tar.gz
erts: Refactor BIF tracing
This commit replaces our current BIF-specific tracing functionality with the general function/export tracing used for everything else, fixing a few longstanding issues: * BIFs that trapped to themselves, for example lists:reverse/2, would generate a call trace message for each trap but only a single return trace message. * BIFs that trapped elsewhere, like erlang:delete_module/1, would lose their return trace messages altogether. * Return/exception trace messages on tail calls would point at the function "above" the caller. * Call count tracing simply didn't work.
Diffstat (limited to 'erts/emulator/beam/bif.c')
-rw-r--r--erts/emulator/beam/bif.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index aba3af3424..593ddf9a29 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4982,7 +4982,17 @@ void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a,
ep->info.mfa.function = f;
ep->info.mfa.arity = a;
ep->trampoline.op = BeamOpCodeAddr(op_apply_bif);
- ep->trampoline.bif.func = (BeamInstr) bif;
+ ep->trampoline.raw[1] = (BeamInstr)bif;
+}
+
+/*
+ * Writes a BIF call wrapper to the given address.
+ */
+void erts_write_bif_wrapper(Export *export, BeamInstr *address) {
+ BifEntry *entry = &bif_table[export->bif_table_index];
+
+ address[0] = BeamOpCodeAddr(op_apply_bif);
+ address[1] = (BeamInstr)entry->f;
}
void erts_init_bif(void)
@@ -5073,7 +5083,7 @@ static BIF_RETTYPE dirty_bif_trap(BIF_ALIST)
* correct by call to dirty_bif_trap()...
*/
- ASSERT(BIF_P->arity == nep->exp.info.mfa.arity);
+ ASSERT(BIF_P->arity == nep->trampoline.info.mfa.arity);
erts_nif_export_restore(BIF_P, nep, THE_NON_VALUE);
@@ -5129,6 +5139,7 @@ erts_schedule_bif(Process *proc,
if (!ERTS_PROC_IS_EXITING(c_p)) {
Export *exp;
BifFunction dbif, ibif;
+ BeamInstr call_instr;
BeamInstr *pc;
/*
@@ -5163,27 +5174,40 @@ erts_schedule_bif(Process *proc,
if (i == NULL) {
ERTS_INTERNAL_ERROR("Missing instruction pointer");
}
+
+ if (BeamIsOpCode(*i, op_i_generic_breakpoint)) {
+ ErtsCodeInfo *ci;
+ GenericBp *bp;
+
+ ci = erts_code_to_codeinfo(i);
+ bp = ci->u.gen_bp;
+
+ call_instr = bp->orig_instr;
+ } else {
+ call_instr = *i;
+ }
+
#ifdef HIPE
- else if (proc->flags & F_HIPE_MODE) {
+ if (proc->flags & F_HIPE_MODE) {
/* Pointer to bif export in i */
exp = (Export *) i;
pc = cp_val(c_p->stop[0]);
mfa = &exp->info.mfa;
- }
+ } else /* !! This is part of the if clause below !! */
#endif
- else if (BeamIsOpCode(*i, op_call_bif_e)) {
- /* Pointer to bif export in i+1 */
- exp = (Export *) i[1];
+ if (BeamIsOpCode(call_instr, op_call_light_bif_be)) {
+ /* Pointer to bif export in i+2 */
+ exp = (Export *) i[2];
pc = i;
mfa = &exp->info.mfa;
}
- else if (BeamIsOpCode(*i, op_call_bif_only_e)) {
- /* Pointer to bif export in i+1 */
- exp = (Export *) i[1];
+ else if (BeamIsOpCode(call_instr, op_call_light_bif_only_be)) {
+ /* Pointer to bif export in i+2 */
+ exp = (Export *) i[2];
pc = i;
mfa = &exp->info.mfa;
}
- else if (BeamIsOpCode(*i, op_apply_bif)) {
+ else if (BeamIsOpCode(call_instr, op_apply_bif)) {
pc = cp_val(c_p->stop[0]);
mfa = erts_code_to_codemfa(i);
}