[interp/tramp] use MONO_STRUCT_OFFSET infrastructure and extract constants
[mono.git] / mono / mini / interp / interp.c
index 8d2a26859053f0830db1a8e3416508db811b7a86..8cf7bec464ca320de00f1ab8ef38f8ef6dd6e57b 100644 (file)
@@ -57,6 +57,7 @@
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/mono-debug.h>
+#include <mono/utils/atomic.h>
 
 #include "interp.h"
 #include "interp-internals.h"
@@ -106,7 +107,7 @@ void ves_exec_method (MonoInvocation *frame);
 static char* dump_stack (stackval *stack, stackval *sp);
 static char* dump_frame (MonoInvocation *inv);
 static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
-static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
+static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally);
 
 typedef void (*ICallMethod) (MonoInvocation *frame);
 
@@ -147,7 +148,8 @@ db_match_method (gpointer data, gpointer user_data)
                break_on_method = 1;
 }
 
-static void debug_enter (MonoInvocation *frame, int *tracing)
+static void
+debug_enter (MonoInvocation *frame, int *tracing)
 {
        if (db_methods) {
                g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
@@ -197,6 +199,17 @@ static void debug_enter (MonoInvocation *frame, int *tracing)
 
 #endif
 
+/* Set the current execution state to the resume state in context */
+#define SET_RESUME_STATE(context) do { \
+               ip = (context)->handler_ip;                                             \
+               sp->data.p = frame->ex;                                                                                 \
+               ++sp;                                                                                                                   \
+               frame->ex = NULL;                                                                                               \
+               (context)->has_resume_state = 0;                                                                \
+               (context)->handler_frame = NULL;                                                                \
+               goto main_loop;                                                                                                 \
+       } while (0)
+
 static void
 interp_ex_handler (MonoException *ex) {
        MonoError error;
@@ -205,7 +218,8 @@ interp_ex_handler (MonoException *ex) {
        if (context == NULL)
                return;
        stack_trace = dump_frame (context->current_frame);
-       ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
+       ex->stack_trace = mono_string_new_checked (mono_domain_get(), stack_trace, &error);
+       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        g_free (stack_trace);
        if (context->current_env == NULL || strcmp(ex->object.vtable->klass->name, "ExecutionEngineException") == 0) {
                char *strace = mono_string_to_utf8_checked (ex->stack_trace, &error);
@@ -529,9 +543,16 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
                } else
                        mono_value_copy (data, val->data.vt, type->data.klass);
                return;
-       case MONO_TYPE_GENERICINST:
+       case MONO_TYPE_GENERICINST: {
+               MonoClass *container_class = type->data.generic_class->container_class;
+
+               if (container_class->valuetype && !container_class->enumtype) {
+                       mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
+                       return;
+               }
                stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
                return;
+       }
        default:
                g_warning ("got type %x", type->type);
                g_assert_not_reached ();
@@ -541,9 +562,11 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
 static void
 fill_in_trace (MonoException *exception, MonoInvocation *frame)
 {
+       MonoError error;
        char *stack_trace = dump_frame (frame);
        MonoDomain *domain = mono_domain_get();
-       (exception)->stack_trace = mono_string_new (domain, stack_trace);
+       (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
+       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        (exception)->trace_ips = get_trace_ips (domain, frame);
        g_free (stack_trace);
 }
@@ -700,6 +723,9 @@ interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUn
        MonoError error;
        ThreadContext *context = mono_native_tls_get_value (thread_context_id);
 
+       if (!context)
+               return;
+
        MonoInvocation *frame = context->current_frame;
 
        while (frame) {
@@ -732,22 +758,10 @@ interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUn
 
 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
 
-struct _MethodArguments {
-       size_t ilen;
-       gpointer *iargs;
-       size_t flen;
-       double *fargs;
-       gpointer *retval;
-       size_t is_float_ret;
-};
-
-typedef struct _MethodArguments MethodArguments;
-
 // TODO: this function is also arch dependent (register width).
-static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
+static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
 {
-       // TODO: don't malloc this data structure.
-       MethodArguments *margs = g_malloc0 (sizeof (MethodArguments));
+       InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
 
        if (sig->hasthis)
                margs->ilen++;
@@ -790,10 +804,10 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
        if (margs->flen > 0)
                margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
 
-       if (margs->ilen > 12)
+       if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
                g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
 
-       if (margs->flen > 3)
+       if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
                g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
 
 
@@ -891,6 +905,7 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
        MonoInvocation *old_frame = context->current_frame;
        MonoInvocation *old_env_frame = context->env_frame;
        jmp_buf *old_env = context->current_env;
+       MonoLMFExt ext;
 
        if (setjmp (env)) {
                context->current_frame = old_frame;
@@ -912,7 +927,7 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
                // mono_tramp_info_register (info, NULL);
        }
 
-       MethodArguments *margs = build_args_from_sig (sig, frame);
+       InterpMethodArguments *margs = build_args_from_sig (sig, frame);
 #if DEBUG_INTERP
        g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
        g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
@@ -921,8 +936,20 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
        context->current_frame = frame;
        context->managed_code = 0;
 
+       /*
+        * Push an LMF frame on the LMF stack
+        * to mark the transition to native code.
+        */
+       memset (&ext, 0, sizeof (ext));
+       ext.interp_exit = TRUE;
+       ext.interp_exit_data = frame;
+
+       mono_push_lmf (&ext);
+
        mono_interp_enter_icall_trampoline (addr, margs);
 
+       mono_pop_lmf (&ext.lmf);
+
        context->managed_code = 1;
        /* domain can only be changed by native code */
        context->domain = mono_domain_get ();
@@ -1290,12 +1317,10 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
 
        if (context == NULL) {
                context = &context_struct;
+               memset (context, 0, sizeof (ThreadContext));
                context_struct.base_frame = &frame;
-               context_struct.current_frame = NULL;
                context_struct.env_frame = &frame;
                context_struct.current_env = &env;
-               context_struct.search_for_handler = 0;
-               context_struct.managed_code = 0;
                mono_native_tls_set_value (thread_context_id, context);
        }
        else
@@ -1416,7 +1441,7 @@ handle_enum:
        if (exc)
                frame.invoke_trap = 1;
        context->managed_code = 1;
-       ves_exec_method_with_context (&frame, context);
+       ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
        context->managed_code = 0;
        if (context == &context_struct)
                mono_native_tls_set_value (thread_context_id, NULL);
@@ -1556,7 +1581,7 @@ interp_entry (InterpEntryData *data)
                }
        }
 
-       init_frame (&frame, context->current_frame, data->rmethod, args, &result);
+       init_frame (&frame, NULL, data->rmethod, args, &result);
        context->managed_code = 1;
 
        type = rmethod->rtype;
@@ -1572,7 +1597,7 @@ interp_entry (InterpEntryData *data)
                break;
        }
 
-       ves_exec_method_with_context (&frame, context);
+       ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
        context->managed_code = 0;
        if (context == &context_struct)
                mono_native_tls_set_value (thread_context_id, NULL);
@@ -1903,8 +1928,9 @@ mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
        MonoMethod *wrapper;
        RuntimeMethod *rmethod;
 
-       if (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
-               return NULL;
+       /* HACK: method_ptr of delegate should point to a runtime method*/
+       if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+               return mono_interp_get_runtime_method (mono_domain_get (), method, error);
 
        rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
        if (rmethod->jit_entry)
@@ -2001,11 +2027,11 @@ static int opcode_counts[512];
 #define MINT_IN_DEFAULT default:
 #endif
 
-static void
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
-
+/*
+ * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
+ */
 static void 
-ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception)
+ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally)
 {
        MonoInvocation child_frame;
        GSList *finally_ips = NULL;
@@ -2257,10 +2283,17 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                }
                        }
 
-                       ves_exec_method_with_context (&child_frame, context);
+                       ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -2301,6 +2334,13 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -2341,10 +2381,17 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
 
-                       ves_exec_method_with_context (&child_frame, context);
+                       ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -2381,10 +2428,17 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
 
-                       ves_exec_method_with_context (&child_frame, context);
+                       ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -2401,6 +2455,7 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                        MonoFtnDesc ftndesc;
                        guint8 res_buf [256];
                        MonoType *type;
+                       MonoLMFExt ext;
 
                        //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
 
@@ -2497,6 +2552,16 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                }
                        }
 
+                       /*
+                        * Push an LMF frame on the LMF stack
+                        * to mark the transition to compiled code.
+                        */
+                       memset (&ext, 0, sizeof (ext));
+                       ext.interp_exit = TRUE;
+                       ext.interp_exit_data = frame;
+
+                       mono_push_lmf (&ext);
+
                        switch (pindex) {
                        case 0: {
                                void (*func)(gpointer) = rmethod->jit_wrapper;
@@ -2551,6 +2616,21 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                break;
                        }
 
+                       mono_pop_lmf (&ext.lmf);
+
+                       if (context->has_resume_state) {
+                               /*
+                                * If this bit is set, it means the call has thrown the exception, and we
+                                * reached this point because the EH code in mono_handle_exception ()
+                                * unwound all the JITted frames below us. mono_interp_set_resume_state ()
+                                * has set the fields in context to indicate where we have to resume execution.
+                                */
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        MonoType *rtype = rmethod->rtype;
                        switch (rtype->type) {
                        case MONO_TYPE_VOID:
@@ -2631,10 +2711,17 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                sp [0].data.p = unboxed;
                        }
 
-                       ves_exec_method_with_context (&child_frame, context);
+                       ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -2678,10 +2765,17 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                                sp [0].data.p = unboxed;
                        }
 
-                       ves_exec_method_with_context (&child_frame, context);
+                       ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -3090,6 +3184,11 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
                        sp -= 2;
                        * (double *) sp->data.p = sp[1].data.f;
                        MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
+                       ++ip;
+                       sp -= 2;
+                       InterlockedWrite ((gint32 *) sp->data.p, sp [1].data.i);
+                       MINT_IN_BREAK;
 #define BINOP(datamem, op) \
        --sp; \
        sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
@@ -3463,10 +3562,17 @@ ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *cont
 
                        g_assert (csig->call_convention == MONO_CALL_DEFAULT);
 
-                       ves_exec_method_with_context (&child_frame, context);
+                       ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
 
                        context->current_frame = frame;
 
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
                        if (child_frame.ex) {
                                /*
                                 * An exception occurred, need to run finally, fault and catch handlers..
@@ -3989,6 +4095,7 @@ array_constructed:
                MINT_IN_CASE(MINT_STELEM_I1) /* fall through */ 
                MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
                MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
+               MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
                MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
                MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
                MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
@@ -4020,6 +4127,9 @@ array_constructed:
                        case MINT_STELEM_I2:
                                mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
                                break;
+                       case MINT_STELEM_U2:
+                               mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
+                               break;
                        case MINT_STELEM_I4:
                                mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
                                break;
@@ -4169,17 +4279,50 @@ array_constructed:
                MINT_IN_CASE(MINT_LDELEM) 
                MINT_IN_CASE(MINT_STELEM) 
                MINT_IN_CASE(MINT_UNBOX_ANY) 
-
-               MINT_IN_CASE(MINT_REFANYVAL) ves_abort(); MINT_IN_BREAK;
 #endif
                MINT_IN_CASE(MINT_CKFINITE)
                        if (!isfinite(sp [-1].data.f))
                                THROW_EX (mono_get_exception_arithmetic (), ip);
                        ++ip;
                        MINT_IN_BREAK;
-#if 0
-               MINT_IN_CASE(MINT_MKREFANY) ves_abort(); MINT_IN_BREAK;
-#endif
+               MINT_IN_CASE(MINT_MKREFANY) {
+                       c = rtm->data_items [*(guint16 *)(ip + 1)];
+
+                       /* The value address is on the stack */
+                       gpointer addr = sp [-1].data.p;
+                       /* Push the typedref value on the stack */
+                       sp [-1].data.p = vt_sp;
+                       vt_sp += sizeof (MonoTypedRef);
+
+                       MonoTypedRef *tref = sp [-1].data.p;
+                       tref->klass = c;
+                       tref->type = &c->byval_arg;
+                       tref->value = addr;
+
+                       ip += 2;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_REFANYTYPE) {
+                       MonoTypedRef *tref = sp [-1].data.p;
+                       MonoType *type = tref->type;
+
+                       vt_sp -= sizeof (MonoTypedRef);
+                       sp [-1].data.p = vt_sp;
+                       vt_sp += 8;
+                       *(gpointer*)sp [-1].data.p = type;
+                       ip ++;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_REFANYVAL) {
+                       MonoTypedRef *tref = sp [-1].data.p;
+                       gpointer addr = tref->value;
+
+                       vt_sp -= sizeof (MonoTypedRef);
+
+                       sp [-1].data.p = addr;
+                       ip ++;
+                       MINT_IN_BREAK;
+               }
                MINT_IN_CASE(MINT_LDTOKEN)
                        sp->data.p = vt_sp;
                        vt_sp += 8;
@@ -4248,6 +4391,10 @@ array_constructed:
                        BINOP_CAST(l, -, guint64);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ENDFINALLY)
+                       ip ++;
+                       int clause_index = *ip;
+                       if (clause_index == exit_at_finally)
+                               goto exit_frame;
                        while (sp > frame->stack) {
                                --sp;
                        }
@@ -4289,6 +4436,13 @@ array_constructed:
                MINT_IN_CASE(MINT_ICALL_PPP_V)
                MINT_IN_CASE(MINT_ICALL_PPI_V)
                        sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
+                       if (*mono_thread_interruption_request_flag ()) {
+                               MonoException *exc = mono_thread_interruption_checkpoint ();
+                               if (exc) {
+                                       frame->ex = exc;
+                                       context->search_for_handler = 1;
+                               }
+                       }
                        if (frame->ex != NULL)
                                goto handle_exception;
                        ip += 2;
@@ -4318,6 +4472,28 @@ array_constructed:
                        if (sp > frame->stack)
                                g_warning ("retobj: more values on stack: %d", sp-frame->stack);
                        goto exit_frame;
+               MINT_IN_CASE(MINT_MONO_TLS) {
+                       MonoTlsKey key = *(gint32 *)(ip + 1);
+                       sp->data.p = ((gpointer (*)()) mono_tls_get_tls_getter (key, FALSE)) ();
+                       sp++;
+                       ip += 3;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
+                       ++ip;
+
+                       context->original_domain = NULL;
+                       MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
+                       gpointer tls_jit = ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
+
+                       if (tls_domain != context->domain || !tls_jit)
+                               context->original_domain = mono_jit_thread_attach (context->domain);
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_MONO_JIT_DETACH)
+                       ++ip;
+                       mono_jit_set_domain (context->original_domain);
+                       MINT_IN_BREAK;
 
 #define RELOP(datamem, op) \
        --sp; \
@@ -4572,7 +4748,7 @@ array_constructed:
                        sp [-1].data.p = alloca (len);
                        MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
                        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       if (header->init_locals)
+                       if (header && header->init_locals)
                                memset (sp [-1].data.p, 0, len);
                        ++ip;
                        MINT_IN_BREAK;
@@ -4692,7 +4868,7 @@ array_constructed:
                                        stackval retval;
                                        memcpy (&dup_frame, inv, sizeof (MonoInvocation));
                                        dup_frame.retval = &retval;
-                                       ves_exec_method_with_context_with_ip (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex);
+                                       ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex, -1);
                                        if (dup_frame.retval->data.i) {
 #if DEBUG_INTERP
                                                if (tracing)
@@ -4840,12 +5016,6 @@ exit_frame:
        DEBUG_LEAVE ();
 }
 
-static void
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
-{
-       ves_exec_method_with_context_with_ip (frame, context, NULL, NULL);
-}
-
 void
 ves_exec_method (MonoInvocation *frame)
 {
@@ -4876,7 +5046,7 @@ ves_exec_method (MonoInvocation *frame)
        frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        context->managed_code = 1;
-       ves_exec_method_with_context (frame, context);
+       ves_exec_method_with_context (frame, context, NULL, NULL, -1);
        context->managed_code = 0;
        if (frame->ex) {
                if (context != &context_struct && context->current_env) {
@@ -4974,8 +5144,10 @@ interp_ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
        if (need_file_info) {
                if (column)
                        *column = 0;
-               if (file)
-                       *file = mono_string_new (mono_domain_get (), "unknown");
+               if (file) {
+                       *file = mono_string_new_checked (mono_domain_get (), "unknown", &error);
+                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+               }
        }
 
        return TRUE;
@@ -5022,7 +5194,11 @@ interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_fi
                        
                        filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
 
-                       sf->filename = filename? mono_string_new (domain, filename): NULL;
+                       sf->filename = NULL;
+                       if (filename) {
+                               sf->filename = mono_string_new_checked (domain, filename, &error);
+                               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+                       }
                        sf->column = 0;
 
                        g_free (filename);
@@ -5223,3 +5399,77 @@ mono_interp_regression_list (int verbose, int count, char *images [])
        return total;
 }
 
+/*
+ * mono_interp_set_resume_state:
+ *
+ *   Set the state the interpeter will continue to execute from after execution returns to the interpreter.
+ */
+void
+mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip)
+{
+       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+
+       context->has_resume_state = TRUE;
+       context->handler_frame = frame->interp_frame;
+       /* This is on the stack, so it doesn't need a wbarrier */
+       context->handler_frame->ex = ex;
+       context->handler_ip = handler_ip;
+}
+
+/*
+ * mono_interp_run_finally:
+ *
+ *   Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
+ * frame->interp_frame.
+ */
+void
+mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
+{
+       MonoInvocation *iframe = frame->interp_frame;
+       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+
+       ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index);
+}
+
+typedef struct {
+       MonoInvocation *current;
+} StackIter;
+
+/*
+ * mono_interp_frame_iter_init:
+ *
+ *   Initialize an iterator for iterating through interpreted frames.
+ */
+void
+mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
+{
+       StackIter *stack_iter = (StackIter*)iter;
+
+       stack_iter->current = (MonoInvocation*)interp_exit_data;
+}
+
+gboolean
+mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
+{
+       StackIter *stack_iter = (StackIter*)iter;
+       MonoInvocation *iframe = stack_iter->current;
+
+       memset (frame, 0, sizeof (StackFrameInfo));
+       /* pinvoke frames doesn't have runtime_method set */
+       while (iframe && !iframe->runtime_method)
+               iframe = iframe->parent;
+       if (!iframe)
+               return FALSE;
+
+       frame->type = FRAME_TYPE_INTERP;
+       frame->interp_frame = iframe;
+       frame->method = iframe->runtime_method->method;
+       frame->actual_method = frame->method;
+       /* This is the offset in the interpreter IR */
+       frame->native_offset = iframe->ip - iframe->runtime_method->code;
+       frame->ji = iframe->runtime_method->jinfo;
+
+       stack_iter->current = iframe->parent;
+
+       return TRUE;
+}