}
}
+static void
+emit_instrumentation_call (MonoCompile *cfg, void *func)
+{
+ MonoInst *iargs [1];
+
+ /*
+ * Avoid instrumenting inlined methods since it can
+ * distort profiling results.
+ */
+ if (cfg->method != cfg->current_method)
+ return;
+
+ if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
+ EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
+ mono_emit_jit_icall (cfg, func, iargs);
+ }
+}
+
static int
ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
{
int i;
#endif
- if (tail)
+ if (tail) {
+ emit_instrumentation_call (cfg, mono_profiler_method_leave);
+
MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
- else
+ } else
MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
call->args = args;
if (mono_security_cas_enabled ())
CHECK_CFG_EXCEPTION;
+ emit_instrumentation_call (cfg, mono_profiler_method_leave);
+
if (ARCH_HAVE_OP_TAIL_CALL) {
MonoMethodSignature *fsig = mono_method_signature (cmethod);
int i, n;
/* Handle tail calls similarly to normal calls */
tail_call = TRUE;
} else {
+ emit_instrumentation_call (cfg, mono_profiler_method_leave);
+
MONO_INST_NEW_CALL (cfg, call, OP_JMP);
call->tail_call = TRUE;
call->method = cmethod;
cfg->ret_var_set = TRUE;
}
} else {
+ emit_instrumentation_call (cfg, mono_profiler_method_leave);
+
if (cfg->lmf_var && cfg->cbb->in_count)
emit_pop_lmf (cfg);
emit_push_lmf (cfg);
}
+ cfg->cbb = init_localsbb;
+ emit_instrumentation_call (cfg, mono_profiler_method_enter);
+
if (seq_points) {
MonoBasicBlock *bb;
MonoCallInst *call = (MonoCallInst*)ins;
int i, save_area_offset;
- /* FIXME: no tracing support... */
- if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
- code = mono_arch_instrument_epilog_full (cfg, mono_profiler_method_leave, code, FALSE, TRUE);
-
g_assert (!cfg->method->save_lmf);
/* Restore callee saved registers */
ins->flags |= MONO_INST_GC_CALLSITE;
ins->backend.pc_offset = code - cfg->native_code;
- /* FIXME: no tracing support... */
- if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
- code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
/* reset offset to make max_len work */
offset = code - cfg->native_code;
code = mono_arch_emit_prolog (cfg);
- if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
- code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
-
cfg->code_len = code - cfg->native_code;
cfg->prolog_end = cfg->code_len;
if (bb == cfg->bb_exit) {
cfg->epilog_begin = cfg->code_len;
-
- if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
- code = cfg->native_code + cfg->code_len;
- code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
- cfg->code_len = code - cfg->native_code;
- g_assert (cfg->code_len < cfg->code_size);
- }
-
mono_arch_emit_epilog (cfg);
}
}
mono_marshal_init ();
mono_arch_register_lowlevel_calls ();
- register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
- register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
+
+ /*
+ * It's important that we pass `TRUE` as the last argument here, as
+ * it causes the JIT to omit a wrapper for these icalls. If the JIT
+ * *did* emit a wrapper, we'd be looking at infinite recursion since
+ * the wrapper would call the icall which would call the wrapper and
+ * so on.
+ */
+ register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
+ register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
+
register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);