[interp] Use alloca for InterpFrame (#32720)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Mon, 24 Feb 2020 09:31:31 +0000 (04:31 -0500)
committerGitHub <noreply@github.com>
Mon, 24 Feb 2020 09:31:31 +0000 (10:31 +0100)
This is like https://github.com/mono/mono/pull/19002 but next_free is initialized upon allocation instead of `pop_frame` which is a slight optimization, if it works.

Co-authored-by: Jay Krell <jay.krell@cornell.edu>
src/mono/mono/eglib/glib.h
src/mono/mono/mini/ee.h
src/mono/mono/mini/interp-stubs.c
src/mono/mono/mini/interp/interp-internals.h
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/mini-exceptions.c

index 2026f09..073edfc 100644 (file)
@@ -291,6 +291,7 @@ gpointer g_try_realloc (gpointer obj, gsize size);
 #define g_new(type,size)        ((type *) g_malloc (sizeof (type) * (size)))
 #define g_new0(type,size)       ((type *) g_malloc0 (sizeof (type)* (size)))
 #define g_newa(type,size)       ((type *) alloca (sizeof (type) * (size)))
+#define g_newa0(type,size)      ((type *) memset (alloca (sizeof (type) * (size)), 0, sizeof (type) * (size)))
 
 #define g_memmove(dest,src,len) memmove (dest, src, len)
 #define g_renew(struct_type, mem, n_structs) ((struct_type*)g_realloc (mem, sizeof (struct_type) * n_structs))
index 1b1bd5a..55efe53 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef __MONO_EE_H__
 #define __MONO_EE_H__
 
-#define MONO_EE_API_VERSION 0xe
+#define MONO_EE_API_VERSION 0xf
 
 typedef struct _MonoInterpStackIter MonoInterpStackIter;
 
@@ -51,7 +51,6 @@ typedef gpointer MonoInterpFrameHandle;
        MONO_EE_CALLBACK (gpointer, frame_get_local, (MonoInterpFrameHandle frame, int pos)) \
        MONO_EE_CALLBACK (gpointer, frame_get_this, (MonoInterpFrameHandle frame)) \
        MONO_EE_CALLBACK (gpointer, frame_get_res, (MonoInterpFrameHandle frame)) \
-       MONO_EE_CALLBACK (gpointer, frame_get_native_stack_addr, (MonoInterpFrameHandle frame)) \
        MONO_EE_CALLBACK (void, frame_arg_to_data, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)) \
        MONO_EE_CALLBACK (void, data_to_frame_arg, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)) \
        MONO_EE_CALLBACK (gpointer, frame_arg_to_storage, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)) \
index 233dda1..3a3db0e 100644 (file)
@@ -71,13 +71,6 @@ stub_frame_get_res (MonoInterpFrameHandle frame)
        return NULL;
 }
 
-static gpointer
-stub_frame_get_native_stack_addr (MonoInterpFrameHandle frame)
-{
-       g_assert_not_reached ();
-       return NULL;
-}
-
 static void
 stub_start_single_stepping (void)
 {
index 93b1290..1396dd7 100644 (file)
@@ -114,7 +114,7 @@ typedef struct {
        } data;
 } stackval;
 
-typedef struct _InterpFrame InterpFrame;
+typedef struct InterpFrame InterpFrame;
 
 typedef void (*MonoFuncV) (void);
 typedef void (*MonoPIFunc) (void *callme, void *margs);
@@ -199,16 +199,15 @@ typedef struct {
        gboolean is_void : 1;
 } InterpState;
 
-struct _InterpFrame {
+struct InterpFrame {
        InterpFrame *parent; /* parent */
        InterpMethod  *imethod; /* parent */
-       stackval       *retval; /* parent */
        stackval       *stack_args; /* parent */
+       stackval       *retval; /* parent */
        stackval       *stack;
-       /* An address on the native stack associated with the frame, used during EH */
-       gpointer       native_stack_addr;
+       InterpFrame    *next_free;
        /* Stack fragments this frame was allocated from */
-       StackFragment *iframe_frag, *data_frag;
+       StackFragment *data_frag;
        /* exception info */
        const unsigned short  *ip;
        /* State saved before calls */
@@ -229,8 +228,6 @@ typedef struct {
        MonoJitExceptionInfo *handler_ei;
        /* Exception that is being thrown. Set with rest of resume state */
        guint32 exc_gchandle;
-       /* Stack of InterpFrames */
-       FrameStack iframe_stack;
        /* Stack of frame data */
        FrameStack data_stack;
 } ThreadContext;
index bb0df2d..874abbe 100644 (file)
@@ -220,30 +220,20 @@ frame_stack_free (FrameStack *stack)
 }
 
 /*
- * alloc_frame:
+ * reinit_frame:
  *
- *   Allocate a new frame from the frame stack.
+ *   Reinitialize a frame.
  */
-static InterpFrame*
-alloc_frame (ThreadContext *ctx, gpointer native_stack_addr, InterpFrame *parent, InterpMethod *imethod, stackval *stack_args, stackval *retval)
+static void
+reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *stack_args, stackval *retval)
 {
-       StackFragment *frag;
-       InterpFrame *frame;
-
-       // FIXME: Add stack overflow checks
-       frame = (InterpFrame*)frame_stack_alloc (&ctx->iframe_stack, sizeof (InterpFrame), &frag);
-
-       frame->iframe_frag = frag;
        frame->parent = parent;
-       frame->native_stack_addr = native_stack_addr;
        frame->imethod = imethod;
        frame->stack_args = stack_args;
        frame->retval = retval;
        frame->stack = NULL;
        frame->ip = NULL;
        frame->state.ip = NULL;
-
-       return frame;
 }
 
 /*
@@ -255,9 +245,7 @@ static MONO_ALWAYS_INLINE void
 alloc_stack_data (ThreadContext *ctx, InterpFrame *frame, int size)
 {
        StackFragment *frag;
-       gpointer res;
-
-       res = frame_stack_alloc (&ctx->data_stack, size, &frag);
+       gpointer res = frame_stack_alloc (&ctx->data_stack, size, &frag);
 
        frame->stack = (stackval*)res;
        frame->data_frag = frag;
@@ -282,11 +270,8 @@ pop_frame (ThreadContext *context, InterpFrame *frame)
 {
        if (frame->stack)
                frame_stack_pop (&context->data_stack, frame->data_frag, frame->stack);
-       frame_stack_pop (&context->iframe_stack, frame->iframe_frag, frame);
 }
 
-#define interp_exec_method(frame, context, error) interp_exec_method_full ((frame), (context), NULL, error)
-
 /*
  * List of classes whose methods will be executed by transitioning to JITted code.
  * Used for testing.
@@ -299,7 +284,8 @@ static gboolean ss_enabled;
 
 static gboolean interp_init_done = FALSE;
 
-static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
+static void
+interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error);
 
 static InterpMethod* lookup_method_pointer (gpointer addr);
 
@@ -453,10 +439,12 @@ get_context (void)
        if (context == NULL) {
                context = g_new0 (ThreadContext, 1);
                /*
-                * Use two stacks, one for InterpFrame structures, one for data.
-                * This is useful because InterpFrame structures don't need to be GC tracked.
+                * Initialize data stack.
+                * There are multiple advantages to this being separate from the frame stack.
+                * Frame stack can be alloca.
+                * Frame stack can be perfectly fit (if heap).
+                * Frame stack can skip GC tracking.
                 */
-               frame_stack_init (&context->iframe_stack, 8192);
                frame_stack_init (&context->data_stack, 8192);
                set_context (context);
        }
@@ -468,7 +456,6 @@ interp_free_context (gpointer ctx)
 {
        ThreadContext *context = (ThreadContext*)ctx;
 
-       frame_stack_free (&context->iframe_stack);
        frame_stack_free (&context->data_stack);
        g_free (context);
 }
@@ -1108,7 +1095,7 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con
 
        MonoContext ctx;
        memset (&ctx, 0, sizeof (MonoContext));
-       MONO_CONTEXT_SET_SP (&ctx, frame->native_stack_addr);
+       MONO_CONTEXT_SET_SP (&ctx, frame);
 
        /*
         * Call the JIT EH code. The EH code will call back to us using:
@@ -1527,17 +1514,26 @@ interp_to_native_trampoline (gpointer addr, gpointer ccontext)
        get_interp_to_native_trampoline () (addr, ccontext);
 }
 
-/* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
+/* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
 #ifdef _MSC_VER
 #pragma optimize ("", off)
 #endif
 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void
-ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, ThreadContext *context, gboolean save_last_error)
+ves_pinvoke_method (
+       MonoMethodSignature *sig,
+       MonoFuncV addr,
+       ThreadContext *context,
+       InterpFrame *parent_frame,
+       stackval *retval,
+       gboolean save_last_error,
+       stackval *sp)
 {
+       InterpFrame frame = {parent_frame, NULL, sp, retval};
+
        MonoLMFExt ext;
        gpointer args;
 
-       g_assert (!frame->imethod);
+       g_assert (!frame.imethod);
 
        static MonoPIFunc entry_func = NULL;
        if (!entry_func) {
@@ -1560,15 +1556,15 @@ ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr
 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
        CallContext ccontext;
        MONO_ENTER_GC_UNSAFE;
-       mono_arch_set_native_call_context_args (&ccontext, frame, sig);
+       mono_arch_set_native_call_context_args (&ccontext, &frame, sig);
        MONO_EXIT_GC_UNSAFE;
        args = &ccontext;
 #else
-       InterpMethodArguments *margs = build_args_from_sig (sig, frame);
+       InterpMethodArguments *margs = build_args_from_sig (sig, &frame);
        args = margs;
 #endif
 
-       INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_pinvoke);
+       INTERP_PUSH_LMF_WITH_CTX (&frame, ext, exit_pinvoke);
        entry_func ((gpointer) addr, args);
        if (save_last_error)
                mono_marshal_set_last_error ();
@@ -1577,15 +1573,14 @@ ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr
 #ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
        if (!context->has_resume_state) {
                MONO_ENTER_GC_UNSAFE;
-               mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
+               mono_arch_get_native_call_context_ret (&ccontext, &frame, sig);
                MONO_EXIT_GC_UNSAFE;
        }
 
-       if (ccontext.stack != NULL)
-               g_free (ccontext.stack);
+       g_free (ccontext.stack);
 #else
        if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
-               stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
+               stackval_from_data (sig->ret, frame.retval, (char*)&frame.retval->data.p, sig->pinvoke);
 
        g_free (margs->iargs);
        g_free (margs->fargs);
@@ -1876,10 +1871,10 @@ dump_args (InterpFrame *inv)
 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
 #endif
 
-static MonoObject*
+// Do not inline in case order of frame addresses matters.
+static MONO_NEVER_INLINE MonoObject*
 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
 {
-       InterpFrame *frame;
        ThreadContext *context = get_context ();
        MonoMethodSignature *sig = mono_method_signature_internal (method);
        MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
@@ -1911,9 +1906,10 @@ interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject
 
        InterpMethod *imethod = mono_interp_get_imethod (domain, invoke_wrapper, error);
        mono_error_assert_ok (error);
-       frame = alloc_frame (context, &result, NULL, imethod, args, &result);
 
-       interp_exec_method (frame, context, error);
+       InterpFrame frame = {NULL, imethod, args, &result};
+
+       interp_exec_method (&frame, context, NULL, error);
 
        if (context->has_resume_state) {
                // This can happen on wasm !?
@@ -1936,10 +1932,10 @@ typedef struct {
 } InterpEntryData;
 
 /* Main function for entering the interpreter from compiled code */
-static void
+// Do not inline in case order of frame addresses matters.
+static MONO_NEVER_INLINE void
 interp_entry (InterpEntryData *data)
 {
-       InterpFrame *frame;
        InterpMethod *rmethod;
        ThreadContext *context;
        stackval result;
@@ -2002,7 +1998,8 @@ interp_entry (InterpEntryData *data)
        }
 
        memset (&result, 0, sizeof (result));
-       frame = alloc_frame (context, &result, NULL, data->rmethod, args, &result);
+
+       InterpFrame frame = {NULL, data->rmethod, args, &result};
 
        type = rmethod->rtype;
        switch (type->type) {
@@ -2018,7 +2015,7 @@ interp_entry (InterpEntryData *data)
        }
 
        ERROR_DECL (error);
-       interp_exec_method (frame, context, error);
+       interp_exec_method (&frame, context, NULL, error);
 
        g_assert (!context->has_resume_state);
 
@@ -2175,10 +2172,11 @@ do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean
        return sp;
 }
 
-/* MONO_NO_OPTIMIATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
+/* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */
 #ifdef _MSC_VER
 #pragma optimize ("", off)
 #endif
+// Do not inline in case order of frame addresses matters, and maybe other reasons.
 static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval *
 do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error)
 {
@@ -2704,10 +2702,10 @@ interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer
                }                                                                                       \
        } while (0)
 
-static void
+// Do not inline in case order of frame addresses matters.
+static MONO_NEVER_INLINE void
 interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untyped)
 {
-       InterpFrame *frame;
        ThreadContext *context;
        stackval result;
        stackval *args;
@@ -2734,22 +2732,22 @@ interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untype
 
        args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
 
-       frame = alloc_frame (context, &result, NULL, rmethod, args, &result);
-
        /* Allocate storage for value types */
        for (i = 0; i < sig->param_count; i++) {
                MonoType *type = sig->params [i];
-               alloc_storage_for_stackval (&frame->stack_args [i + sig->hasthis], type, sig->pinvoke);
+               alloc_storage_for_stackval (&args [i + sig->hasthis], type, sig->pinvoke);
        }
 
        if (sig->ret->type != MONO_TYPE_VOID)
-               alloc_storage_for_stackval (frame->retval, sig->ret, sig->pinvoke);
+               alloc_storage_for_stackval (&result, sig->ret, sig->pinvoke);
+
+       InterpFrame frame = {NULL, rmethod, args, &result};
 
        /* Copy the args saved in the trampoline to the frame stack */
-       mono_arch_get_native_call_context_args (ccontext, frame, sig);
+       mono_arch_get_native_call_context_args (ccontext, &frame, sig);
 
        ERROR_DECL (error);
-       interp_exec_method (frame, context, error);
+       interp_exec_method (&frame, context, NULL, error);
 
        g_assert (!context->has_resume_state);
 
@@ -2758,7 +2756,7 @@ interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untype
 
        /* Write back the return value */
        /* 'frame' is still valid */
-       mono_arch_set_native_call_context_ret (ccontext, frame, sig);
+       mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
 }
 
 #else
@@ -3144,23 +3142,27 @@ mono_interp_isinst (MonoObject* object, MonoClass* klass)
 }
 
 // Do not inline use of alloca.
+// Do not inline in case order of frame addresses matters.
 static MONO_NEVER_INLINE void
 mono_interp_calli_nat_dynamic_pinvoke (
        // Parameters are sorted by name.
-       InterpFrame* child_frame,
        guchar* code,
        ThreadContext* context,
        MonoMethodSignature* csignature,
-       MonoError* error)
+       MonoError* error,
+       InterpFrame *parent_frame,
+       stackval *retval,
+       stackval *sp)
 {
+       InterpFrame frame = {parent_frame, NULL, sp, retval};
+
        // Recompute to limit parameters, which can also contribute to caller stack.
-       InterpMethod* const imethod = child_frame->parent->imethod;
+       InterpMethod* const imethod = parent_frame->imethod;
 
        g_assert (imethod->method->dynamic && csignature->pinvoke);
 
        /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */
-       MonoMarshalSpec** mspecs = g_newa (MonoMarshalSpec*, csignature->param_count + 1);
-       memset (mspecs, 0, sizeof (MonoMarshalSpec*) * (csignature->param_count + 1));
+       MonoMarshalSpec** mspecs = g_newa0 (MonoMarshalSpec*, csignature->param_count + 1);
 
        MonoMethodPInvoke iinfo;
        memset (&iinfo, 0, sizeof (iinfo));
@@ -3173,23 +3175,26 @@ mono_interp_calli_nat_dynamic_pinvoke (
 
        {
                ERROR_DECL (error);
-               child_frame->imethod = mono_interp_get_imethod (imethod->domain, m, error);
+               frame.imethod = mono_interp_get_imethod (imethod->domain, m, error);
                mono_error_cleanup (error); /* FIXME: don't swallow the error */
        }
 
-       interp_exec_method (child_frame, context, error);
+       interp_exec_method (&frame, context, NULL, error);
 }
 
-static MonoException*
-mono_interp_leave (InterpFrame* child_frame)
+// Do not inline in case order of frame addresses matters.
+static MONO_NEVER_INLINE MonoException*
+mono_interp_leave (InterpFrame* parent_frame)
 {
+       InterpFrame frame = {parent_frame};
+
        stackval tmp_sp;
        /*
         * We need for mono_thread_get_undeniable_exception to be able to unwind
-        * to check the abort threshold. For this to work we use child_frame as a
+        * to check the abort threshold. For this to work we use frame as a
         * dummy frame that is stored in the lmf and serves as the transition frame
         */
-       do_icall_wrapper (child_frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
+       do_icall_wrapper (&frame, NULL, MINT_ICALL_V_P, &tmp_sp, (gpointer)mono_thread_get_undeniable_exception, FALSE);
 
        return (MonoException*)tmp_sp.data.p;
 }
@@ -3377,7 +3382,7 @@ method_entry (ThreadContext *context, InterpFrame *frame,
  * FRAME is only valid until the next call to alloc_frame ().
  */
 static MONO_NEVER_INLINE void
-interp_exec_method_full (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
+interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs *clause_args, MonoError *error)
 {
        InterpMethod *cmethod;
        MonoException *ex;
@@ -3682,17 +3687,13 @@ main_loop:
                        if (csignature->hasthis)
                                --sp;
 
-                       InterpFrame* const child_frame = alloc_frame (context, &retval, frame, NULL, sp, retval);
-
                        if (frame->imethod->method->dynamic && csignature->pinvoke) {
-                               mono_interp_calli_nat_dynamic_pinvoke (child_frame, code, context, csignature, error);
+                               mono_interp_calli_nat_dynamic_pinvoke (code, context, csignature, error, frame, retval, sp);
                        } else {
                                const gboolean save_last_error = ip [-3 + 2];
-                               ves_pinvoke_method (child_frame, csignature, (MonoFuncV) code, context, save_last_error);
+                               ves_pinvoke_method (csignature, (MonoFuncV)code, context, frame, retval, save_last_error, sp);
                        }
 
-                       pop_frame (context, child_frame);
-
                        CHECK_RESUME_STATE (context);
 
                        if (csignature->ret->type != MONO_TYPE_VOID) {
@@ -3825,17 +3826,24 @@ main_loop:
                        ip += 3;
 #endif
 call:;
-                       // FIXME This assumes a grow-down stack.
-                       gpointer native_stack_addr = frame->native_stack_addr ? (gpointer)((guint8*)frame->native_stack_addr - 1) : (gpointer)&retval;
-
                        /*
                         * Make a non-recursive call by loading the new interpreter state based on child frame,
                         * and going back to the main loop.
                         */
                        SAVE_INTERP_STATE (frame);
 
-                       frame = alloc_frame (context, native_stack_addr, frame, cmethod, sp, retval);
-
+                       // Allocate child frame.
+                       // FIXME: Add stack overflow checks
+                       {
+                               InterpFrame *child_frame = frame->next_free;
+                               if (!child_frame) {
+                                       child_frame = g_newa0 (InterpFrame, 1);
+                                       // Not free currently, but will be when allocation attempted.
+                                       frame->next_free = child_frame;
+                               }
+                               reinit_frame (child_frame, frame, cmethod, sp, retval);
+                               frame = child_frame;
+                       }
 #if DEBUG_INTERP
                        int tracing;
 #endif
@@ -6274,9 +6282,6 @@ call_newobj:
                MINT_IN_CASE(MINT_LEAVE_S)
                MINT_IN_CASE(MINT_LEAVE_CHECK)
                MINT_IN_CASE(MINT_LEAVE_S_CHECK) {
-                       int dummy;
-                       // Leave is split into pieces in order to consume less stack,
-                       // but not have to change how exception handling macros access labels and locals.
 
                        g_assert (sp >= frame->stack);
                        sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
@@ -6287,9 +6292,7 @@ call_newobj:
                        gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK;
 
                        if (check && frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
-                               InterpFrame* const child_frame = alloc_frame (context, &dummy, frame, NULL, NULL, NULL);
-                               MonoException *abort_exc = mono_interp_leave (child_frame);
-                               pop_frame (context, child_frame);
+                               MonoException *abort_exc = mono_interp_leave (frame);
                                if (abort_exc)
                                        THROW_EX (abort_exc, frame->ip);
                        }
@@ -6393,7 +6396,7 @@ call_newobj:
                        ++ip;
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_MONO_GET_SP)
-                       sp->data.p = &frame;
+                       sp->data.p = frame;
                        ++sp;
                        ++ip;
                        MINT_IN_BREAK;
@@ -7135,19 +7138,24 @@ interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip
        ThreadContext *context = get_context ();
        const unsigned short *old_ip = iframe->ip;
        FrameClauseArgs clause_args;
-       const guint16 *saved_ip;
+       const guint16 *state_ip;
 
        memset (&clause_args, 0, sizeof (FrameClauseArgs));
        clause_args.start_with_ip = (const guint16*)handler_ip;
        clause_args.end_at_ip = (const guint16*)handler_ip_end;
        clause_args.exit_clause = clause_index;
 
-       saved_ip = iframe->state.ip;
+       state_ip = iframe->state.ip;
        iframe->state.ip = NULL;
 
+       InterpFrame* const next_free = iframe->next_free;
+       iframe->next_free = NULL;
+
        ERROR_DECL (error);
-       interp_exec_method_full (iframe, context, &clause_args, error);
-       iframe->state.ip = saved_ip;
+       interp_exec_method (iframe, context, &clause_args, error);
+
+       iframe->next_free = next_free;
+       iframe->state.ip = state_ip;
        iframe->state.clause_args = NULL;
        if (context->has_resume_state) {
                return TRUE;
@@ -7163,12 +7171,12 @@ interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip
  *   Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
  * frame->interp_frame.
  */
-static gboolean
+// Do not inline in case order of frame addresses matters.
+static MONO_NEVER_INLINE gboolean
 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
 {
        InterpFrame *iframe = (InterpFrame*)frame->interp_frame;
        ThreadContext *context = get_context ();
-       InterpFrame *child_frame;
        stackval retval;
        FrameClauseArgs clause_args;
 
@@ -7176,7 +7184,7 @@ interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, g
         * Have to run the clause in a new frame which is a copy of IFRAME, since
         * during debugging, there are two copies of the frame on the stack.
         */
-       child_frame = alloc_frame (context, &retval, iframe, iframe->imethod, iframe->stack_args, &retval);
+       InterpFrame child_frame = {iframe, iframe->imethod, iframe->stack_args, &retval};
 
        memset (&clause_args, 0, sizeof (FrameClauseArgs));
        clause_args.start_with_ip = (const guint16*)handler_ip;
@@ -7185,7 +7193,8 @@ interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, g
        clause_args.base_frame = iframe;
 
        ERROR_DECL (error);
-       interp_exec_method_full (child_frame, context, &clause_args, error);
+       interp_exec_method (&child_frame, context, &clause_args, error);
+
        /* ENDFILTER stores the result into child_frame->retval */
        return retval.data.i ? TRUE : FALSE;
 }
@@ -7241,7 +7250,7 @@ interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
                        frame->managed = TRUE;
        }
        frame->ji = iframe->imethod->jinfo;
-       frame->frame_addr = iframe->native_stack_addr;
+       frame->frame_addr = iframe;
 
        stack_iter->current = iframe->parent;
 
@@ -7348,14 +7357,6 @@ interp_frame_get_res (MonoInterpFrameHandle frame)
                return stackval_to_data_addr (sig->ret, iframe->retval);
 }
 
-static gpointer
-interp_frame_get_native_stack_addr (MonoInterpFrameHandle frame)
-{
-       InterpFrame *iframe = (InterpFrame*)frame;
-
-       return iframe->native_stack_addr;
-}
-
 static void
 interp_start_single_stepping (void)
 {
index 993fe25..3bcebae 100644 (file)
@@ -741,7 +741,6 @@ unwinder_unwind_frame (Unwinder *unwinder,
                                           host_mgreg_t **save_locations,
                                           StackFrameInfo *frame)
 {
-       gpointer parent;
        if (unwinder->in_interp) {
                memcpy (new_ctx, ctx, sizeof (MonoContext));
 
@@ -760,12 +759,10 @@ unwinder_unwind_frame (Unwinder *unwinder,
 
                unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
                if (frame->type == FRAME_TYPE_INTERP) {
-                       parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
-                       if (parent)
-                               unwinder->last_frame_addr = mini_get_interp_callbacks ()->frame_get_native_stack_addr (parent);
-                       else
-                               unwinder->last_frame_addr = NULL;
+                       const gpointer parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
+                       unwinder->last_frame_addr = parent;
                }
+
                if (!unwinder->in_interp)
                        return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
                return TRUE;