[profiler] Split method_leave callback into a method_tail_call callback.
authorAlex Rønne Petersen <alpeters@microsoft.com>
Mon, 7 Aug 2017 20:30:59 +0000 (22:30 +0200)
committerAlex Rønne Petersen <alpeters@microsoft.com>
Mon, 7 Aug 2017 20:47:55 +0000 (22:47 +0200)
With this, profilers can distinguish between the two, and also know what the
target method of a tail call is.

The call instrumentation flags have been renamed accordingly and a new flag has
been added for instrumenting tail calls. I've also added a flag for exceptional
leave events, and method_exception_leave is only raised if this flag is given
for a method.

Also refactored the relevant JIT code a bit so it's easier to follow.

mono/metadata/profiler-events.h
mono/metadata/profiler.h
mono/mini/interp/interp.c
mono/mini/interp/transform.c
mono/mini/method-to-ir.c
mono/mini/mini-exceptions.c
mono/mini/mini-profiler.c
mono/mini/mini-runtime.c
mono/mini/mini.h
mono/profiler/log.c
samples/profiler/sample.c

index 1a7e0b25ef9e3cb2178565ca4e84b5cb4bf36318..f0681a6b456f78bc91c020de3254381d0bb68485 100644 (file)
@@ -56,6 +56,7 @@ MONO_PROFILER_EVENT_1(assembly_unloaded, AssemblyLUnloaded, MonoAssembly *, asse
 
 MONO_PROFILER_EVENT_2(method_enter, MethodEnter, MonoMethod *, method, MonoProfilerCallContext *, context)
 MONO_PROFILER_EVENT_2(method_leave, MethodLeave, MonoMethod *, method, MonoProfilerCallContext *, context)
+MONO_PROFILER_EVENT_2(method_tail_call, MethodTailCall, MonoMethod *, method, MonoMethod *, target)
 MONO_PROFILER_EVENT_2(method_exception_leave, MethodExceptionLeave, MonoMethod *, method, MonoObject *, exception)
 MONO_PROFILER_EVENT_1(method_free, MethodFree, MonoMethod *, method)
 MONO_PROFILER_EVENT_1(method_begin_invoke, MethodBeginInvoke, MonoMethod *, method)
index e20dc34c85472d8929d6a512356351e519e680a3..b6e836d3638b6d0912666f3fec8a33adf2788671 100644 (file)
@@ -200,14 +200,18 @@ MONO_API mono_bool mono_profiler_enable_allocations (void);
 typedef enum {
        /* Do not instrument calls. */
        MONO_PROFILER_CALL_INSTRUMENTATION_NONE = 0,
-       /* Instrument method prologues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE = 1 << 1,
-       /* Also capture a call context for prologues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT = 1 << 2,
-       /* Instrument method epilogues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE = 1 << 3,
-       /* Also capture a call context for epilogues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT = 1 << 4,
+       /* Instrument method entries. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_ENTER = 1 << 1,
+       /* Also capture a call context for method entries. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT = 1 << 2,
+       /* Instrument method exits. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE = 1 << 3,
+       /* Also capture a call context for method exits. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT = 1 << 4,
+       /* Instrument method exits as a result of a tail call. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL = 1 << 5,
+       /* Instrument exceptional method exits. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE = 1 << 6,
 } MonoProfilerCallInstrumentationFlags;
 
 typedef MonoProfilerCallInstrumentationFlags (*MonoProfilerCallInstrumentationFilterCallback) (MonoProfiler *prof, MonoMethod *method);
index fdbbe262ba4f2bb6d3e0fb1b6617b0a84511abdf..f09df220599504afa287a8721f1038197b05da23 100644 (file)
@@ -2436,6 +2436,10 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign
                }
                MINT_IN_CASE(MINT_JMP) {
                        InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
+
+                       if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
+                               MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
+
                        if (!new_method->transformed) {
                                frame->ip = ip;
                                frame->ex = mono_interp_transform_method (new_method, context);
@@ -4769,7 +4773,7 @@ array_constructed:
                        if (MONO_PROFILER_ENABLED (method_enter)) {
                                MonoProfilerCallContext *prof_ctx = NULL;
 
-                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT) {
+                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
                                        prof_ctx = g_new0 (MonoProfilerCallContext, 1);
                                        prof_ctx->interp_frame = frame;
                                        prof_ctx->method = frame->imethod->method;
@@ -5140,35 +5144,34 @@ die_on_ex:
        }
 exit_frame:
 
-       if (!frame->ex) {
-               if (MONO_PROFILER_ENABLED (method_leave) && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE) {
-                       MonoProfilerCallContext *prof_ctx = NULL;
-
-                       if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT) {
-                               prof_ctx = g_new0 (MonoProfilerCallContext, 1);
-                               prof_ctx->interp_frame = frame;
-                               prof_ctx->method = frame->imethod->method;
-
-                               MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
-
-                               switch (rtype->type) {
-                               case MONO_TYPE_VOID:
-                                       break;
-                               case MONO_TYPE_VALUETYPE:
-                                       prof_ctx->return_value = frame->retval->data.p;
-                                       break;
-                               default:
-                                       prof_ctx->return_value = frame->retval;
-                                       break;
-                               }
-                       }
+       if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
+           frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
+               MonoProfilerCallContext *prof_ctx = NULL;
 
-                       MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
+                       prof_ctx = g_new0 (MonoProfilerCallContext, 1);
+                       prof_ctx->interp_frame = frame;
+                       prof_ctx->method = frame->imethod->method;
 
-                       g_free (prof_ctx);
+                       MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
+
+                       switch (rtype->type) {
+                       case MONO_TYPE_VOID:
+                               break;
+                       case MONO_TYPE_VALUETYPE:
+                               prof_ctx->return_value = frame->retval->data.p;
+                               break;
+                       default:
+                               prof_ctx->return_value = frame->retval;
+                               break;
+                       }
                }
-       } else
-               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, (MonoObject *) frame->ex));
+
+               MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+
+               g_free (prof_ctx);
+       } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
+               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
 
        DEBUG_LEAVE ();
 }
index 790f8b191d2ea048eeeaf1424f6d45477ea57212..f8144e1952ee2187b519ae719f1f8995dce8168b 100644 (file)
@@ -1514,7 +1514,7 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon
                }
        }
 
-       if (rtm->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE)
+       if (rtm->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER)
                ADD_CODE (td, MINT_PROF_ENTER);
 
        if (sym_seq_points) {
@@ -3753,6 +3753,7 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon
                        case CEE_TAIL_:
                                ++td->ip;
                                /* FIX: should do something? */;
+                               // TODO: This should raise a method_tail_call profiler event.
                                break;
                        case CEE_INITOBJ:
                                CHECK_STACK(td, 1);
index 84c019460517374d6282b9245232d5c246680b22..a1f6e1fa9eee4b9f5cb060545bcf67a0c7b48e20 100644 (file)
@@ -2217,7 +2217,7 @@ check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_
 
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
-                                        MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
+                                        MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline, MonoMethod *target)
 {
        MonoType *sig_ret;
        MonoCallInst *call;
@@ -2229,7 +2229,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
                tail = FALSE;
 
        if (tail) {
-               mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, NULL, NULL);
+               mini_profiler_emit_tail_call (cfg, target);
 
                MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
        } else
@@ -2362,7 +2362,7 @@ mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
                MONO_ADD_INS (cfg->cbb, ins);
        }
 
-       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE, NULL);
 
        call->inst.sreg1 = addr->dreg;
 
@@ -2456,7 +2456,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
        need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline, method);
 
 #ifndef DISABLE_REMOTING
        if (might_be_remote)
@@ -2586,7 +2586,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
 
        g_assert (sig);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE, NULL);
        call->fptr = func;
 
        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -8030,7 +8030,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->gshared && mono_method_check_context_used (cmethod))
                                GENERIC_SHARING_FAILURE (CEE_JMP);
 
-                       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, NULL, NULL);
+                       mini_profiler_emit_tail_call (cfg, cmethod);
 
                        fsig = mono_method_signature (cmethod);
                        n = fsig->param_count + fsig->hasthis;
@@ -8972,7 +8972,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        /* Handle tail calls similarly to normal calls */
                                        tail_call = TRUE;
                                } else {
-                                       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, NULL, NULL);
+                                       mini_profiler_emit_tail_call (cfg, cmethod);
 
                                        MONO_INST_NEW_CALL (cfg, call, OP_JMP);
                                        call->tail_call = TRUE;
@@ -9083,7 +9083,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                }
                case CEE_RET:
-                       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, sp - 1, sig->ret);
+                       mini_profiler_emit_leave (cfg, sig->ret->type != MONO_TYPE_VOID ? sp [-1] : NULL);
 
                        if (cfg->method != method) {
                                /* return from inlined method */
@@ -12635,7 +12635,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
 
        cfg->cbb = init_localsbb;
-       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_enter, TRUE, NULL, NULL);
+       mini_profiler_emit_enter (cfg);
 
        if (seq_points) {
                MonoBasicBlock *bb;
index 348bc3948c5a30575db3dc0836e9b501c5a12380..4f81d7c4c37c42793c25b489ae438325e5c68dd7 100644 (file)
@@ -2230,9 +2230,12 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        }
                }
 
-               jit_tls->orig_ex_ctx_set = TRUE;
-               MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
-               jit_tls->orig_ex_ctx_set = FALSE;
+               if (MONO_PROFILER_ENABLED (method_exception_leave) &&
+                   mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
+                       jit_tls->orig_ex_ctx_set = TRUE;
+                       MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
+                       jit_tls->orig_ex_ctx_set = FALSE;
+               }
 
                *ctx = new_ctx;
        }
index 33d39e26df6dfd138048a92d165837685dc546ea..c6c6158866223fe69f8b0664f722595d24136bd4 100644 (file)
 
 #ifndef DISABLE_JIT
 
-void
-mini_profiler_emit_instrumentation_call (MonoCompile *cfg, void *func, gboolean entry, MonoInst **ret, MonoType *rtype)
+static MonoInst *
+emit_fill_call_ctx (MonoCompile *cfg, MonoInst *method, MonoInst *ret)
 {
-       gboolean instrument, capture;
+       cfg->flags |= MONO_CFG_HAS_ALLOCA;
 
-       /*
-        * Do not instrument an inlined method - it becomes
-        * part of the current method.
-        */
-       if (cfg->current_method != cfg->method)
-               return;
+       MonoInst *alloc, *size, *fill_ctx;
+
+       EMIT_NEW_ICONST (cfg, size, sizeof (MonoProfilerCallContext));
+       MONO_INST_NEW (cfg, alloc, OP_LOCALLOC);
+       alloc->dreg = alloc_preg (cfg);
+       alloc->sreg1 = size->dreg;
+       alloc->flags |= MONO_INST_INIT;
+       MONO_ADD_INS (cfg->cbb, alloc);
+       MONO_INST_NEW (cfg, fill_ctx, OP_FILL_PROF_CALL_CTX);
+       fill_ctx->sreg1 = alloc->dreg;
+       MONO_ADD_INS (cfg->cbb, fill_ctx);
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, alloc->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, method), method->dreg);
+
+       if (ret) {
+               MonoInst *var = mono_compile_create_var (cfg, mono_method_signature (cfg->method)->ret, OP_LOCAL);
 
-       if (entry) {
-               instrument = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE;
-               capture = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT;
-       } else {
-               instrument = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
-               capture = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT;
+               MonoInst *store, *addr;
+
+               EMIT_NEW_TEMPSTORE (cfg, store, var->inst_c0, ret);
+               EMIT_NEW_VARLOADA (cfg, addr, var, NULL);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, alloc->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, return_value), addr->dreg);
        }
 
-       if (!instrument)
+       return alloc;
+}
+
+void
+mini_profiler_emit_enter (MonoCompile *cfg)
+{
+       if (!MONO_CFG_PROFILE (cfg, ENTER) || cfg->current_method != cfg->method)
+               return;
+
+       MonoInst *iargs [2];
+
+       EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
+
+       if (MONO_CFG_PROFILE (cfg, ENTER_CONTEXT) && !cfg->llvm_only)
+               iargs [1] = emit_fill_call_ctx (cfg, iargs [0], NULL);
+       else
+               EMIT_NEW_PCONST (cfg, iargs [1], NULL);
+
+       /* void mono_profiler_raise_method_enter (MonoMethod *method, MonoProfilerCallContext *ctx) */
+       mono_emit_jit_icall (cfg, mono_profiler_raise_method_enter, iargs);
+}
+
+void
+mini_profiler_emit_leave (MonoCompile *cfg, MonoInst *ret)
+{
+       if (!MONO_CFG_PROFILE (cfg, LEAVE) || cfg->current_method != cfg->method)
                return;
 
        MonoInst *iargs [2];
 
        EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
 
-       if (capture && !cfg->llvm_only) {
-               cfg->flags |= MONO_CFG_HAS_ALLOCA;
+       if (MONO_CFG_PROFILE (cfg, LEAVE_CONTEXT) && !cfg->llvm_only)
+               iargs [1] = emit_fill_call_ctx (cfg, iargs [0], ret);
+       else
+               EMIT_NEW_PCONST (cfg, iargs [1], NULL);
 
-               MonoInst *size, *fill_ctx;
+       /* void mono_profiler_raise_method_leave (MonoMethod *method, MonoProfilerCallContext *ctx) */
+       mono_emit_jit_icall (cfg, mono_profiler_raise_method_leave, iargs);
+}
 
-               EMIT_NEW_ICONST (cfg, size, sizeof (MonoProfilerCallContext));
-               MONO_INST_NEW (cfg, iargs [1], OP_LOCALLOC);
-               iargs [1]->dreg = alloc_preg (cfg);
-               iargs [1]->sreg1 = size->dreg;
-               iargs [1]->flags |= MONO_INST_INIT;
-               MONO_ADD_INS (cfg->cbb, iargs [1]);
-               MONO_INST_NEW (cfg, fill_ctx, OP_FILL_PROF_CALL_CTX);
-               fill_ctx->sreg1 = iargs [1]->dreg;
-               MONO_ADD_INS (cfg->cbb, fill_ctx);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, iargs [1]->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, method), iargs [0]->dreg);
+void
+mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target)
+{
+       if (!MONO_CFG_PROFILE (cfg, TAIL_CALL) || cfg->current_method != cfg->method)
+               return;
 
-               if (rtype && rtype->type != MONO_TYPE_VOID) {
-                       MonoInst *var = mono_compile_create_var (cfg, rtype, OP_LOCAL);
+       g_assert (cfg->current_method == cfg->method);
 
-                       MonoInst *store, *addr;
+       MonoInst *iargs [2];
 
-                       EMIT_NEW_TEMPSTORE (cfg, store, var->inst_c0, *ret);
-                       EMIT_NEW_VARLOADA (cfg, addr, var, NULL);
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, iargs [1]->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, return_value), addr->dreg);
-               }
-       else
+       EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
+
+       if (target)
+               EMIT_NEW_METHODCONST (cfg, iargs [1], target);
+       else
                EMIT_NEW_PCONST (cfg, iargs [1], NULL);
 
-       mono_emit_jit_icall (cfg, func, iargs);
+       /* void mono_profiler_raise_method_tail_call (MonoMethod *method, MonoMethod *target) */
+       mono_emit_jit_icall (cfg, mono_profiler_raise_method_tail_call, iargs);
 }
 
 #endif
index 745ede4dea08a2ce6f4e8a3ceaf84d03e1a39fcd..b839e49f09637e9d1314e10c13815ced0435d885 100644 (file)
@@ -4059,6 +4059,7 @@ register_icalls (void)
         */
        register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
        register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
+       register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr 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);
index 7d681122d43c3b3aa212a18cc74e77f265966a02..f0d1bb7fc525f44f146c3fa2190a127a833a4031 100644 (file)
@@ -1920,8 +1920,11 @@ typedef struct {
        MonoProfilerCallInstrumentationFlags prof_flags;
 } MonoCompile;
 
+#define MONO_CFG_PROFILE(cfg, flag) \
+       G_UNLIKELY ((cfg)->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ ## flag)
+
 #define MONO_CFG_PROFILE_CALL_CONTEXT(cfg) \
-       ((cfg)->prof_flags & (MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT))
+       (MONO_CFG_PROFILE (cfg, ENTER_CONTEXT) || MONO_CFG_PROFILE (cfg, LEAVE_CONTEXT))
 
 typedef enum {
        MONO_CFG_HAS_ALLOCA = 1 << 0,
@@ -2357,8 +2360,12 @@ MonoDomain* mini_init                      (const char *filename, const char *ru
 void        mini_cleanup                   (MonoDomain *domain);
 MONO_API MonoDebugOptions *mini_get_debug_options   (void);
 MONO_API gboolean    mini_parse_debug_option (const char *option);
+
+/* profiler support */
 void        mini_add_profiler_argument (const char *desc);
-void        mini_profiler_emit_instrumentation_call (MonoCompile *cfg, void *func, gboolean entry, MonoInst **ret, MonoType *rtype);
+void        mini_profiler_emit_enter (MonoCompile *cfg);
+void        mini_profiler_emit_leave (MonoCompile *cfg, MonoInst *ret);
+void        mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target);
 void        mini_profiler_context_enable (void);
 gpointer    mini_profiler_context_get_this (MonoProfilerCallContext *ctx);
 gpointer    mini_profiler_context_get_argument (MonoProfilerCallContext *ctx, guint32 pos);
index 3d4c147cdaebf2d55c27fc10b6bc1b6b64382632..8a3790aac248ed44baa2d156137da838cfb65e42 100644 (file)
@@ -1791,6 +1791,12 @@ method_leave (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *c
        }
 }
 
+static void
+tail_call (MonoProfiler *prof, MonoMethod *method, MonoMethod *target)
+{
+       method_leave (prof, method, NULL);
+}
+
 static void
 method_exc_leave (MonoProfiler *prof, MonoMethod *method, MonoObject *exc)
 {
@@ -1810,7 +1816,10 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method, MonoObject *exc)
 static MonoProfilerCallInstrumentationFlags
 method_filter (MonoProfiler *prof, MonoMethod *method)
 {
-       return MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
+       return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER |
+              MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE |
+              MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL |
+              MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE;
 }
 
 static void
@@ -4735,6 +4744,7 @@ mono_profiler_init_log (const char *desc)
                mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter);
                mono_profiler_set_method_enter_callback (handle, method_enter);
                mono_profiler_set_method_leave_callback (handle, method_leave);
+               mono_profiler_set_method_tail_call_callback (handle, tail_call);
                mono_profiler_set_method_exception_leave_callback (handle, method_exc_leave);
        }
 
index a5ee4435ea6843b554b986cf344e6276d833619d..a210317e913b7740b4d564c94849c82c21902d8f 100644 (file)
@@ -2,9 +2,9 @@
 
 /*
  * Bare bones profiler. Compile with:
- * 
+ *
  * linux : gcc -fPIC -shared -o libmono-profiler-sample.so sample.c `pkg-config --cflags --libs mono-2`
- * mac : gcc sample.c -o mono-profiler-sample.dylib -Dmono_free=free -lz `pkg-config --cflags mono-2` -undefined suppress -flat_namespace  
+ * mac : gcc -o mono-profiler-sample.dylib sample.c -lz `pkg-config --cflags mono-2` -undefined suppress -flat_namespace
  * linux with a custom prefix (e.g. --prefix=/opt/my-mono-build):
  *     gcc -fPIC -shared -o libmono-profiler-sample.so sample.c `PKG_CONFIG_PATH=/opt/my-mono-build/lib/pkgconfig/ pkg-config --cflags --libs mono-2`
  *
@@ -35,15 +35,10 @@ sample_method_enter (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallCon
        prof->ncalls++;
 }
 
-static void
-sample_method_leave (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *ctx)
-{
-}
-
 static MonoProfilerCallInstrumentationFlags
 sample_instrumentation_filter (MonoProfiler *prof, MonoMethod *method)
 {
-       return MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
+       return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER;
 }
 
 /* the entry point */
@@ -56,7 +51,6 @@ mono_profiler_init_sample (const char *desc)
        mono_profiler_set_runtime_shutdown_end_callback (handle, sample_shutdown);
        mono_profiler_set_call_instrumentation_filter_callback (handle, sample_instrumentation_filter);
        mono_profiler_set_method_enter_callback (handle, sample_method_enter);
-       mono_profiler_set_method_leave_callback (handle, sample_method_leave);
 }