[profiler] Implement call context introspection for enter/leave events.
[mono.git] / mono / mini / interp / interp.c
index ef55ca088195ffa2f86979ee9b53190181ca5882..fdbbe262ba4f2bb6d3e0fb1b6617b0a84511abdf 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"
 
 #include <mono/mini/mini.h>
 #include <mono/mini/jit-icalls.h>
+#include <mono/mini/debugger-agent.h>
 
+#ifdef TARGET_ARM
+#include <mono/mini/mini-arm.h>
+#endif
 
 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
 #ifdef _WIN32
 #endif
 #endif
 
-#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error)      \
-       do {    \
-               (frame)->parent = (parent_frame);       \
-               (frame)->stack_args = (method_args);    \
-               (frame)->retval = (method_retval);      \
-               (frame)->runtime_method = mono_interp_get_runtime_method ((domain), (mono_method), (error));    \
-               (frame)->ex = NULL;     \
-               (frame)->ip = NULL;     \
-               (frame)->invoke_trap = 0;       \
+static inline void
+init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
+{
+       frame->parent = parent_frame;
+       frame->stack_args = method_args;
+       frame->retval = method_retval;
+       frame->imethod = rmethod;
+       frame->ex = NULL;
+       frame->ip = NULL;
+       frame->invoke_trap = 0;
+}
+
+#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
+       InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error));    \
+       init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
        } while (0)
 
-void ves_exec_method (MonoInvocation *frame);
+/*
+ * List of classes whose methods will be executed by transitioning to JITted code.
+ * Used for testing.
+ */
+GSList *jit_classes;
+/* If TRUE, interpreted code will be interrupted at function entry/backward branches */
+static gboolean ss_enabled;
+
+void ves_exec_method (InterpFrame *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 char* dump_frame (InterpFrame *inv);
+static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top);
+static void ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally);
 
-typedef void (*ICallMethod) (MonoInvocation *frame);
+typedef void (*ICallMethod) (InterpFrame *frame);
 
 static guint32 die_on_exception = 0;
 static MonoNativeTlsKey thread_context_id;
 
-static char* dump_args (MonoInvocation *inv);
+static char* dump_args (InterpFrame *inv);
 
 #define DEBUG_INTERP 0
 #define COUNT_OPS 0
@@ -135,16 +153,17 @@ db_match_method (gpointer data, gpointer user_data)
                break_on_method = 1;
 }
 
-static void debug_enter (MonoInvocation *frame, int *tracing)
+static void
+debug_enter (InterpFrame *frame, int *tracing)
 {
        if (db_methods) {
-               g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
+               g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
                if (break_on_method)
                        *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
                break_on_method = 0;
        }
        if (*tracing) {
-               MonoMethod *method = frame->runtime_method->method;
+               MonoMethod *method = frame->imethod->method;
                char *mn, *args = dump_args (frame);
                debug_indent_level++;
                output_indent ();
@@ -154,8 +173,6 @@ static void debug_enter (MonoInvocation *frame, int *tracing)
                g_print  ("%s)\n", args);
                g_free (args);
        }
-       if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)
-               mono_profiler_method_enter (frame->runtime_method->method);
 }
 
 
@@ -164,72 +181,47 @@ static void debug_enter (MonoInvocation *frame, int *tracing)
                char *mn, *args;        \
                args = dump_retval (frame);     \
                output_indent ();       \
-               mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
+               mn = mono_method_full_name (frame->imethod->method, FALSE); \
                g_print  ("(%p) Leaving %s", mono_thread_internal_current (),  mn);     \
                g_free (mn); \
                g_print  (" => %s\n", args);    \
                g_free (args);  \
                debug_indent_level--;   \
                if (tracing == 3) global_tracing = 0; \
-       }       \
-       if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)    \
-               mono_profiler_method_leave (frame->runtime_method->method);
+       }
 
 #else
 
 int mono_interp_traceopt = 0;
-static void debug_enter (MonoInvocation *frame, int *tracing)
+static void debug_enter (InterpFrame *frame, int *tracing)
 {
 }
 #define DEBUG_LEAVE()
 
 #endif
 
+/* Set the current execution state to the resume state in context */
+#define SET_RESUME_STATE(context) do { \
+               ip = (context)->handler_ip;                                             \
+               if (frame->ex) { \
+               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;
-       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
-       char *stack_trace;
-       if (context == NULL)
-               return;
-       stack_trace = dump_frame (context->current_frame);
-       ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
-       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);
-               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-               fprintf(stderr, "Nothing can catch this exception: ");
-               fprintf(stderr, "%s", ex->object.vtable->klass->name);
-               if (ex->message != NULL) {
-                       char *m = mono_string_to_utf8_checked (ex->message, &error);
-                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       fprintf(stderr, ": %s", m);
-                       g_free(m);
-               }
-               fprintf(stderr, "\n%s\n", strace);
-               g_free (strace);
-               if (ex->inner_ex != NULL) {
-                       ex = (MonoException *)ex->inner_ex;
-                       fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name);
-                       if (ex->message != NULL) {
-                               char *m = mono_string_to_utf8_checked (ex->message, &error);
-                               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                               fprintf(stderr, ": %s", m);
-                               g_free(m);
-                       }
-                       strace = mono_string_to_utf8_checked (ex->stack_trace, &error);
-                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       fprintf(stderr, "\n");
-                       fprintf(stderr, "%s\n", strace);
-                       g_free (strace);
-               }
-               /* wait for other threads to also collapse */
-               // Sleep(1000); // TODO: proper sleep
-               exit(1);
-       }
-       context->env_frame->ex = ex;
-       context->search_for_handler = 1;
-       longjmp (*context->current_env, 1);
+set_context (ThreadContext *context)
+{
+       MonoJitTlsData *jit_tls;
+
+       mono_native_tls_set_value (thread_context_id, context);
+       jit_tls = mono_tls_get_jit_tls ();
+       if (jit_tls)
+               jit_tls->interp_context = context;
 }
 
 static void
@@ -250,28 +242,59 @@ ves_real_abort (int line, MonoMethod *mh,
 
 #define ves_abort() \
        do {\
-               ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
+               ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
                THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
        } while (0);
 
-RuntimeMethod*
-mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
+static InterpMethod*
+lookup_imethod (MonoDomain *domain, MonoMethod *method)
+{
+       InterpMethod *rtm;
+       MonoJitDomainInfo *info;
+
+       info = domain_jit_info (domain);
+       mono_domain_jit_code_hash_lock (domain);
+       rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
+       mono_domain_jit_code_hash_unlock (domain);
+       return rtm;
+}
+
+InterpMethod*
+mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
 {
-       RuntimeMethod *rtm;
+       InterpMethod *rtm;
+       MonoJitDomainInfo *info;
+       MonoMethodSignature *sig;
+       int i;
+
        error_init (error);
 
+       info = domain_jit_info (domain);
        mono_domain_jit_code_hash_lock (domain);
-       if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) {
-               mono_domain_jit_code_hash_unlock (domain);
+       rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
+       mono_domain_jit_code_hash_unlock (domain);
+       if (rtm)
                return rtm;
-       }
-       rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
+
+       sig = mono_method_signature (method);
+
+       rtm = mono_domain_alloc0 (domain, sizeof (InterpMethod));
        rtm->method = method;
-       rtm->param_count = mono_method_signature (method)->param_count;
-       rtm->hasthis = mono_method_signature (method)->hasthis;
-       mono_internal_hash_table_insert (&domain->jit_code_hash, method, rtm);
+       rtm->domain = domain;
+       rtm->param_count = sig->param_count;
+       rtm->hasthis = sig->hasthis;
+       rtm->rtype = mini_get_underlying_type (sig->ret);
+       rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
+       for (i = 0; i < sig->param_count; ++i)
+               rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
+
+       mono_domain_jit_code_hash_lock (domain);
+       if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
+               mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
        mono_domain_jit_code_hash_unlock (domain);
 
+       rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method);
+
        return rtm;
 }
 
@@ -280,25 +303,55 @@ mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError
 {
        if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
                method = mono_marshal_get_synchronized_wrapper (method);
-       return mono_interp_get_runtime_method (domain, method, error);
+       return mono_interp_get_imethod (domain, method, error);
+}
+
+/*
+ * interp_push_lmf:
+ *
+ * Push an LMF frame on the LMF stack
+ * to mark the transition to native code.
+ * This is needed for the native code to
+ * be able to do stack walks.
+ */
+static void
+interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
+{
+       memset (ext, 0, sizeof (MonoLMFExt));
+       ext->interp_exit = TRUE;
+       ext->interp_exit_data = frame;
+
+       mono_push_lmf (ext);
+}
+
+static void
+interp_pop_lmf (MonoLMFExt *ext)
+{
+       mono_pop_lmf (&ext->lmf);
 }
 
-static inline RuntimeMethod*
-get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
+static inline InterpMethod*
+get_virtual_method (InterpMethod *imethod, MonoObject *obj)
 {
-       MonoMethod *m = runtime_method->method;
+       MonoMethod *m = imethod->method;
+       MonoDomain *domain = imethod->domain;
+       InterpMethod *ret = NULL;
        MonoError error;
 
+#ifndef DISABLE_REMOTING
+       if (mono_object_is_transparent_proxy (obj)) {
+               ret = mono_interp_get_imethod (domain, mono_marshal_get_remoting_invoke (m), &error);
+               mono_error_assert_ok (&error);
+               return ret;
+       }
+#endif
+
        if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-               RuntimeMethod *ret = NULL;
-               if (mono_object_is_transparent_proxy (obj)) {
-                       ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
-                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-               } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
-                       ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
+               if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+                       ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), &error);
                        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                } else {
-                       ret = runtime_method;
+                       ret = imethod;
                }
                return ret;
        }
@@ -331,9 +384,9 @@ get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObjec
                virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
        }
 
-       RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
+       InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, &error);
        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-       return virtual_runtime_method;
+       return virtual_imethod;
 }
 
 static void inline
@@ -383,15 +436,19 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo
        case MONO_TYPE_U4:
                result->data.i = *(guint32*)data;
                return;
-       case MONO_TYPE_R4:
-               result->data.f = *(float*)data;
+       case MONO_TYPE_R4: {
+               float tmp;
+               /* memmove handles unaligned case */
+               memmove (&tmp, data, sizeof (float));
+               result->data.f = tmp;
                return;
+    }
        case MONO_TYPE_I8:
        case MONO_TYPE_U8:
-               result->data.l = *(gint64*)data;
+               memmove (&result->data.l, data, sizeof (gint64));
                return;
        case MONO_TYPE_R8:
-               result->data.f = *(double*)data;
+               memmove (&result->data.f, data, sizeof (double));
                return;
        case MONO_TYPE_STRING:
        case MONO_TYPE_SZARRAY:
@@ -407,9 +464,14 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo
                } else
                        mono_value_copy (result->data.vt, data, type->data.klass);
                return;
-       case MONO_TYPE_GENERICINST:
+       case MONO_TYPE_GENERICINST: {
+               if (mono_type_generic_inst_is_valuetype (type)) {
+                       mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
+                       return;
+               }
                stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
                return;
+       }
        default:
                g_warning ("got type 0x%02x", type->type);
                g_assert_not_reached ();
@@ -502,9 +564,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 ();
@@ -512,27 +581,34 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
 }
 
 static void
-fill_in_trace (MonoException *exception, MonoInvocation *frame)
+fill_in_trace (MonoException *exception, InterpFrame *frame)
 {
+       MonoError error;
        char *stack_trace = dump_frame (frame);
-       MonoDomain *domain = mono_domain_get();
-       (exception)->stack_trace = mono_string_new (domain, stack_trace);
+       MonoDomain *domain = frame->imethod->domain;
+       (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);
 }
 
 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
 
-#define THROW_EX(exception,ex_ip)      \
+#define THROW_EX_GENERAL(exception,ex_ip,rethrow)              \
        do {\
                frame->ip = (ex_ip);            \
                frame->ex = (MonoException*)(exception);        \
-               FILL_IN_TRACE(frame->ex, frame); \
+               if (!rethrow) { \
+                       FILL_IN_TRACE(frame->ex, frame);        \
+               } \
+               MONO_PROFILER_RAISE (exception_throw, ((MonoObject *) exception));      \
                goto handle_exception;  \
        } while (0)
 
+#define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
+
 static MonoObject*
-ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
+ves_array_create (InterpFrame *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
 {
        uintptr_t *lengths;
        intptr_t *lower_bounds;
@@ -563,7 +639,7 @@ ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, M
 }
 
 static gint32
-ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
+ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
 {
        g_assert (!frame->ex);
        MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
@@ -574,7 +650,7 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
                        guint32 idx = sp [i].data.i;
                        guint32 lower = ao->bounds [i].lower_bound;
                        guint32 len = ao->bounds [i].length;
-                       if (idx < lower || (idx - lower) >= len) {
+                       if (safe && (idx < lower || (idx - lower) >= len)) {
                                frame->ex = mono_get_exception_index_out_of_range ();
                                FILL_IN_TRACE (frame->ex, frame);
                                return -1;
@@ -583,7 +659,7 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
                }
        } else {
                pos = sp [0].data.i;
-               if (pos >= ao->max_length) {
+               if (safe && pos >= ao->max_length) {
                        frame->ex = mono_get_exception_index_out_of_range ();
                        FILL_IN_TRACE (frame->ex, frame);
                        return -1;
@@ -593,7 +669,7 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
 }
 
 static void
-ves_array_set (MonoInvocation *frame)
+ves_array_set (InterpFrame *frame)
 {
        stackval *sp = frame->stack_args + 1;
 
@@ -603,7 +679,7 @@ ves_array_set (MonoInvocation *frame)
 
        g_assert (ac->rank >= 1);
 
-       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
        if (frame->ex)
                return;
 
@@ -621,12 +697,12 @@ ves_array_set (MonoInvocation *frame)
        gint32 esize = mono_array_element_size (ac);
        gpointer ea = mono_array_addr_with_size (ao, esize, pos);
 
-       MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
+       MonoType *mt = mono_method_signature (frame->imethod->method)->params [ac->rank];
        stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
 }
 
 static void
-ves_array_get (MonoInvocation *frame)
+ves_array_get (InterpFrame *frame, gboolean safe)
 {
        stackval *sp = frame->stack_args + 1;
 
@@ -636,25 +712,25 @@ ves_array_get (MonoInvocation *frame)
 
        g_assert (ac->rank >= 1);
 
-       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
        if (frame->ex)
                return;
 
        gint32 esize = mono_array_element_size (ac);
        gpointer ea = mono_array_addr_with_size (ao, esize, pos);
 
-       MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret;
+       MonoType *mt = mono_method_signature (frame->imethod->method)->ret;
        stackval_from_data (mt, frame->retval, ea, FALSE);
 }
 
 static gpointer
-ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
+ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
 {
        MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
 
        g_assert (ac->rank >= 1);
 
-       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
        if (frame->ex)
                return NULL;
 
@@ -673,17 +749,20 @@ interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUn
        MonoError error;
        ThreadContext *context = mono_native_tls_get_value (thread_context_id);
 
-       MonoInvocation *frame = context->current_frame;
+       if (!context)
+               return;
+
+       InterpFrame *frame = context->current_frame;
 
        while (frame) {
                MonoStackFrameInfo fi;
                memset (&fi, 0, sizeof (MonoStackFrameInfo));
 
                /* TODO: hack to make some asserts happy. */
-               fi.ji = (MonoJitInfo *) frame->runtime_method;
+               fi.ji = (MonoJitInfo *) frame->imethod;
 
-               if (frame->runtime_method)
-                       fi.method = fi.actual_method = frame->runtime_method->method;
+               if (frame->imethod)
+                       fi.method = fi.actual_method = frame->imethod->method;
 
                if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
                        fi.il_offset = -1;
@@ -705,22 +784,14 @@ 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, InterpFrame *frame)
 {
-       // TODO: don't malloc this data structure.
-       MethodArguments *margs = g_malloc0 (sizeof (MethodArguments));
+       InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
+
+#ifdef TARGET_ARM
+       g_assert (mono_arm_eabi_supported ());
+       int i8_align = mono_arm_i8_align ();
+#endif
 
        if (sig->hasthis)
                margs->ilen++;
@@ -743,15 +814,34 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
                case MONO_TYPE_STRING:
-               case MONO_TYPE_I8:
                case MONO_TYPE_VALUETYPE:
                case MONO_TYPE_GENERICINST:
+#if SIZEOF_VOID_P == 8
+               case MONO_TYPE_I8:
+#endif
                        margs->ilen++;
                        break;
+#if SIZEOF_VOID_P == 4
+               case MONO_TYPE_I8:
+#ifdef TARGET_ARM
+                       /* pairs begin at even registers */
+                       if (i8_align == 8 && margs->ilen & 1)
+                               margs->ilen++;
+#endif
+                       margs->ilen += 2;
+                       break;
+#endif
                case MONO_TYPE_R4:
+#if SIZEOF_VOID_P == 8
                case MONO_TYPE_R8:
+#endif
                        margs->flen++;
                        break;
+#if SIZEOF_VOID_P == 4
+               case MONO_TYPE_R8:
+                       margs->flen += 2;
+                       break;
+#endif
                default:
                        g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
                }
@@ -763,10 +853,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 > 8)
+       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);
 
 
@@ -796,15 +886,35 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
                case MONO_TYPE_STRING:
-               case MONO_TYPE_I8:
                case MONO_TYPE_VALUETYPE:
                case MONO_TYPE_GENERICINST:
+#if SIZEOF_VOID_P == 8
+               case MONO_TYPE_I8:
+#endif
                        margs->iargs [int_i] = frame->stack_args [i].data.p;
 #if DEBUG_INTERP
                        g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
 #endif
                        int_i++;
                        break;
+#if SIZEOF_VOID_P == 4
+               case MONO_TYPE_I8: {
+                       stackval *sarg = &frame->stack_args [i];
+#ifdef TARGET_ARM
+                       /* pairs begin at even registers */
+                       if (i8_align == 8 && int_i & 1)
+                               int_i++;
+#endif
+                       margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
+                       int_i++;
+                       margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
+#if DEBUG_INTERP
+                       g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
+#endif
+                       int_i++;
+                       break;
+               }
+#endif
                case MONO_TYPE_R4:
                case MONO_TYPE_R8:
                        if (ptype == MONO_TYPE_R4)
@@ -814,7 +924,11 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
 #if DEBUG_INTERP
                        g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i);
 #endif
+#if SIZEOF_VOID_P == 4
+                       int_f += 2;
+#else
                        int_f++;
+#endif
                        break;
                default:
                        g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
@@ -841,6 +955,7 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
                case MONO_TYPE_VALUETYPE:
                case MONO_TYPE_GENERICINST:
                        margs->retval = &(frame->retval->data.p);
+                       margs->is_float_ret = 0;
                        break;
                case MONO_TYPE_R4:
                case MONO_TYPE_R8:
@@ -858,12 +973,13 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
 }
 
 static void 
-ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
+ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
 {
        jmp_buf env;
-       MonoInvocation *old_frame = context->current_frame;
-       MonoInvocation *old_env_frame = context->env_frame;
+       InterpFrame *old_frame = context->current_frame;
+       InterpFrame *old_env_frame = context->env_frame;
        jmp_buf *old_env = context->current_env;
+       MonoLMFExt ext;
 
        if (setjmp (env)) {
                context->current_frame = old_frame;
@@ -877,15 +993,19 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
        context->env_frame = frame;
        context->current_env = &env;
 
-       g_assert (!frame->runtime_method);
+       g_assert (!frame->imethod);
        if (!mono_interp_enter_icall_trampoline) {
-               MonoTrampInfo *info;
-               mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
-               // TODO:
-               // mono_tramp_info_register (info, NULL);
+               if (mono_aot_only) {
+                       mono_interp_enter_icall_trampoline = mono_aot_get_trampoline ("enter_icall_trampoline");
+               } else {
+                       MonoTrampInfo *info;
+                       mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
+                       // TODO:
+                       // 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);
@@ -894,11 +1014,13 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
        context->current_frame = frame;
        context->managed_code = 0;
 
+       interp_push_lmf (&ext, frame);
+
        mono_interp_enter_icall_trampoline (addr, margs);
 
+       interp_pop_lmf (&ext);
+
        context->managed_code = 1;
-       /* domain can only be changed by native code */
-       context->domain = mono_domain_get ();
 
        if (*mono_thread_interruption_request_flag ()) {
                MonoException *exc = mono_thread_interruption_checkpoint ();
@@ -926,7 +1048,7 @@ mono_interp_init_delegate (MonoDelegate *del)
        if (del->method)
                return;
        /* shouldn't need a write barrier because we don't write a MonoObject into the field */
-       del->method = ((RuntimeMethod *) del->method_ptr)->method;
+       del->method = ((InterpMethod *) del->method_ptr)->method;
 }
 
 /*
@@ -935,9 +1057,9 @@ mono_interp_init_delegate (MonoDelegate *del)
  * provided by the runtime and is primarily used for the methods of delegates.
  */
 static void
-ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
+ves_imethod (InterpFrame *frame, ThreadContext *context)
 {
-       MonoMethod *method = frame->runtime_method->method;
+       MonoMethod *method = frame->imethod->method;
        const char *name = method->name;
        MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
        MonoObject *isinst_obj;
@@ -952,6 +1074,10 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
                        stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
                        return;
                }
+               if (!strcmp (method->name, "UnsafeLoad")) {
+                       ves_array_get (frame, FALSE);
+                       return;
+               }
        }
 
        isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
@@ -962,7 +1088,7 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
                        return;
                }
                if (*name == 'G' && (strcmp (name, "Get") == 0)) {
-                       ves_array_get (frame);
+                       ves_array_get (frame, TRUE);
                        return;
                }
        }
@@ -972,6 +1098,7 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
                        method->name);
 }
 
+#if DEBUG_INTERP
 static char*
 dump_stack (stackval *stack, stackval *sp)
 {
@@ -987,6 +1114,7 @@ dump_stack (stackval *stack, stackval *sp)
        }
        return g_string_free (str, FALSE);
 }
+#endif
 
 static void
 dump_stackval (GString *str, stackval *s, MonoType *type)
@@ -1034,18 +1162,32 @@ dump_stackval (GString *str, stackval *s, MonoType *type)
        }
 }
 
+#if DEBUG_INTERP
 static char*
-dump_args (MonoInvocation *inv)
+dump_retval (InterpFrame *inv)
+{
+       GString *str = g_string_new ("");
+       MonoType *ret = mono_method_signature (inv->imethod->method)->ret;
+
+       if (ret->type != MONO_TYPE_VOID)
+               dump_stackval (str, inv->retval, ret);
+
+       return g_string_free (str, FALSE);
+}
+#endif
+
+static char*
+dump_args (InterpFrame *inv)
 {
        GString *str = g_string_new ("");
        int i;
-       MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method);
+       MonoMethodSignature *signature = mono_method_signature (inv->imethod->method);
        
        if (signature->param_count == 0 && !signature->hasthis)
                return g_string_free (str, FALSE);
 
        if (signature->hasthis) {
-               MonoMethod *method = inv->runtime_method->method;
+               MonoMethod *method = inv->imethod->method;
                dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
        }
 
@@ -1054,21 +1196,9 @@ dump_args (MonoInvocation *inv)
 
        return g_string_free (str, FALSE);
 }
-
-static char*
-dump_retval (MonoInvocation *inv)
-{
-       GString *str = g_string_new ("");
-       MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
-
-       if (ret->type != MONO_TYPE_VOID)
-               dump_stackval (str, inv->retval, ret);
-
-       return g_string_free (str, FALSE);
-}
  
 static char*
-dump_frame (MonoInvocation *inv)
+dump_frame (InterpFrame *inv)
 {
        GString *str = g_string_new ("");
        int i;
@@ -1076,8 +1206,8 @@ dump_frame (MonoInvocation *inv)
        MonoError error;
 
        for (i = 0; inv; inv = inv->parent) {
-               if (inv->runtime_method != NULL) {
-                       MonoMethod *method = inv->runtime_method->method;
+               if (inv->imethod != NULL) {
+                       MonoMethod *method = inv->imethod->method;
                        MonoClass *k;
 
                        int codep = 0;
@@ -1095,7 +1225,7 @@ dump_frame (MonoInvocation *inv)
                                if (hd != NULL) {
                                        if (inv->ip) {
                                                opname = mono_interp_opname [*inv->ip];
-                                               codep = inv->ip - inv->runtime_method->code;
+                                               codep = inv->ip - inv->imethod->code;
                                                source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
                                        } else 
                                                opname = "";
@@ -1122,23 +1252,23 @@ dump_frame (MonoInvocation *inv)
 }
 
 static MonoArray *
-get_trace_ips (MonoDomain *domain, MonoInvocation *top)
+get_trace_ips (MonoDomain *domain, InterpFrame *top)
 {
        int i;
        MonoArray *res;
-       MonoInvocation *inv;
+       InterpFrame *inv;
        MonoError error;
 
        for (i = 0, inv = top; inv; inv = inv->parent)
-               if (inv->runtime_method != NULL)
+               if (inv->imethod != NULL)
                        ++i;
 
        res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error);
        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
 
        for (i = 0, inv = top; inv; inv = inv->parent)
-               if (inv->runtime_method != NULL) {
-                       mono_array_set (res, gpointer, i, inv->runtime_method);
+               if (inv->imethod != NULL) {
+                       mono_array_set (res, gpointer, i, inv->imethod);
                        ++i;
                        mono_array_set (res, gpointer, i, (gpointer)inv->ip);
                        ++i;
@@ -1230,17 +1360,15 @@ get_trace_ips (MonoDomain *domain, MonoInvocation *top)
 MonoObject*
 mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
 {
-       MonoInvocation frame;
+       InterpFrame frame;
        ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
        MonoObject *retval = NULL;
        MonoMethodSignature *sig = mono_method_signature (method);
        MonoClass *klass = mono_class_from_mono_type (sig->ret);
-       int i, type, isobject = 0;
-       void *ret = NULL;
        stackval result;
-       stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
+       stackval *args;
        ThreadContext context_struct;
-       MonoInvocation *old_frame = NULL;
+       InterpFrame *old_frame = NULL;
        jmp_buf env;
 
        error_init (error);
@@ -1251,11 +1379,10 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
 
        if (setjmp(env)) {
                if (context != &context_struct) {
-                       context->domain = mono_domain_get ();
                        context->current_frame = old_frame;
                        context->managed_code = 0;
-               } else 
-                       mono_native_tls_set_value (thread_context_id, NULL);
+               } else
+                       set_context (NULL);
                if (exc != NULL)
                        *exc = (MonoObject *)frame.ex;
                return retval;
@@ -1263,157 +1390,265 @@ 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);
+               set_context (context);
        }
        else
                old_frame = context->current_frame;
 
-       context->domain = mono_domain_get ();
+       MonoDomain *domain = mono_domain_get ();
 
-       switch (sig->ret->type) {
-       case MONO_TYPE_VOID:
-               break;
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_OBJECT:
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_ARRAY:
-       case MONO_TYPE_SZARRAY:
-               isobject = 1;
-               break;
-       case MONO_TYPE_VALUETYPE:
-               retval = mono_object_new_checked (context->domain, klass, error);
-               ret = mono_object_unbox (retval);
-               if (!sig->ret->data.klass->enumtype)
-                       result.data.vt = ret;
-               else
-                       result.data.vt = alloca (mono_class_instance_size (klass));
-               break;
-       case MONO_TYPE_GENERICINST:
-               if (!MONO_TYPE_IS_REFERENCE (sig->ret)) {
-                       retval = mono_object_new_checked (context->domain, klass, error);
-                       ret = mono_object_unbox (retval);
-                       if (!sig->ret->data.klass->enumtype)
-                               result.data.vt = ret;
-                       else
-                               result.data.vt = alloca (mono_class_instance_size (klass));
-               } else {
-                       isobject = 1;
+       MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
+
+       //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
+
+       result.data.vt = alloca (mono_class_instance_size (klass));
+       args = alloca (sizeof (stackval) * 4);
+
+       if (sig->hasthis)
+               args [0].data.p = obj;
+       else
+               args [0].data.p = NULL;
+       args [1].data.p = params;
+       args [2].data.p = exc;
+       args [3].data.p = method;
+
+       INIT_FRAME (&frame, context->current_frame, args, &result, domain, invoke_wrapper, error);
+
+       if (exc)
+               frame.invoke_trap = 1;
+       context->managed_code = 1;
+       ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
+       context->managed_code = 0;
+       if (context == &context_struct)
+               set_context (NULL);
+       else
+               context->current_frame = old_frame;
+       if (frame.ex != NULL) {
+               if (exc != NULL) {
+                       *exc = (MonoObject*) frame.ex;
+                       return NULL;
                }
-               break;
+               if (context->current_env != NULL) {
+                       context->env_frame->ex = frame.ex;
+                       longjmp(*context->current_env, 1);
+               }
+               else
+                       printf("dropped exception...\n");
+       }
+       return result.data.p;
+}
 
-       case MONO_TYPE_PTR:
-               retval = mono_object_new_checked (context->domain, mono_defaults.int_class, error);
-               ret = mono_object_unbox (retval);
-               break;
-       default:
-               retval = mono_object_new_checked (context->domain, klass, error);
-               ret = mono_object_unbox (retval);
-               break;
+typedef struct {
+       InterpMethod *rmethod;
+       gpointer this_arg;
+       gpointer res;
+       gpointer args [16];
+       gpointer *many_args;
+} InterpEntryData;
+
+/* Main function for entering the interpreter from compiled code */
+static void
+interp_entry (InterpEntryData *data)
+{
+       InterpFrame frame;
+       InterpMethod *rmethod = data->rmethod;
+       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+       ThreadContext context_struct;
+       InterpFrame *old_frame;
+       stackval result;
+       stackval *args;
+       MonoMethod *method;
+       MonoMethodSignature *sig;
+       MonoType *type;
+       int i;
+
+       method = rmethod->method;
+       sig = mono_method_signature (method);
+
+       // FIXME: Optimize this
+
+       //printf ("%s\n", mono_method_full_name (method, 1));
+
+       frame.ex = NULL;
+       if (context == NULL) {
+               context = &context_struct;
+               memset (context, 0, sizeof (ThreadContext));
+               context_struct.base_frame = &frame;
+               context_struct.env_frame = &frame;
+               set_context (context);
+       } else {
+               old_frame = context->current_frame;
        }
 
+       args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
        if (sig->hasthis)
-               args [0].data.p = obj;
+               args [0].data.p = data->this_arg;
 
+       gpointer *params;
+       if (data->many_args)
+               params = data->many_args;
+       else
+               params = data->args;
        for (i = 0; i < sig->param_count; ++i) {
-               int a_index = i + !!sig->hasthis;
+               int a_index = i + (sig->hasthis ? 1 : 0);
                if (sig->params [i]->byref) {
                        args [a_index].data.p = params [i];
                        continue;
                }
-               type = sig->params [i]->type;
-handle_enum:
-               switch (type) {
+               type = rmethod->param_types [i];
+               switch (type->type) {
                case MONO_TYPE_U1:
                case MONO_TYPE_I1:
-               case MONO_TYPE_BOOLEAN:
                        args [a_index].data.i = *(MonoBoolean*)params [i];
                        break;
                case MONO_TYPE_U2:
                case MONO_TYPE_I2:
-               case MONO_TYPE_CHAR:
                        args [a_index].data.i = *(gint16*)params [i];
                        break;
+               case MONO_TYPE_U:
 #if SIZEOF_VOID_P == 4
-               case MONO_TYPE_U: /* use VAL_POINTER? */
+                       args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
+#else
+                       args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
+#endif
+                       break;
                case MONO_TYPE_I:
+#if SIZEOF_VOID_P == 4
+                       args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
+#else
+                       args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
 #endif
+                       break;
                case MONO_TYPE_U4:
+                       args [a_index].data.i = *(guint32*)params [i];
+                       break;
                case MONO_TYPE_I4:
                        args [a_index].data.i = *(gint32*)params [i];
                        break;
-#if SIZEOF_VOID_P == 8
-               case MONO_TYPE_U:
-               case MONO_TYPE_I:
-#endif
                case MONO_TYPE_U8:
+                       args [a_index].data.l = *(guint64*)params [i];
+                       break;
                case MONO_TYPE_I8:
                        args [a_index].data.l = *(gint64*)params [i];
                        break;
-               case MONO_TYPE_VALUETYPE:
-                       if (sig->params [i]->data.klass->enumtype) {
-                               type = mono_class_enum_basetype (sig->params [i]->data.klass)->type;
-                               goto handle_enum;
-                       } else {
-                               args [a_index].data.p = params [i];
-                       }
-                       break;
-               case MONO_TYPE_STRING:
                case MONO_TYPE_PTR:
-               case MONO_TYPE_CLASS:
-               case MONO_TYPE_ARRAY:
-               case MONO_TYPE_SZARRAY:
                case MONO_TYPE_OBJECT:
-               case MONO_TYPE_GENERICINST:
+                       args [a_index].data.p = *(MonoObject**)params [i];
+                       break;
+               case MONO_TYPE_VALUETYPE:
                        args [a_index].data.p = params [i];
                        break;
+               case MONO_TYPE_GENERICINST:
+                       if (MONO_TYPE_IS_REFERENCE (type))
+                               args [a_index].data.p = params [i];
+                       else
+                               args [a_index].data.vt = params [i];
+                       break;
                default:
-                       g_error ("type 0x%x not handled in  runtime invoke", sig->params [i]->type);
+                       printf ("%s\n", mono_type_full_name (sig->params [i]));
+                       NOT_IMPLEMENTED;
+                       break;
                }
        }
 
-       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
-               method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
-       INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
-       if (exc)
-               frame.invoke_trap = 1;
+       init_frame (&frame, NULL, data->rmethod, args, &result);
        context->managed_code = 1;
-       ves_exec_method_with_context (&frame, context);
+
+       type = rmethod->rtype;
+       switch (type->type) {
+       case MONO_TYPE_GENERICINST:
+               if (!MONO_TYPE_IS_REFERENCE (type))
+                       frame.retval->data.vt = data->res;
+               break;
+       case MONO_TYPE_VALUETYPE:
+               frame.retval->data.vt = data->res;
+               break;
+       default:
+               break;
+       }
+
+       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);
+               set_context (NULL);
        else
                context->current_frame = old_frame;
-       if (frame.ex != NULL) {
-               if (exc != NULL) {
-                       *exc = (MonoObject*) frame.ex;
-                       return NULL;
-               }
-               if (context->current_env != NULL) {
-                       context->env_frame->ex = frame.ex;
-                       longjmp(*context->current_env, 1);
+
+       // FIXME:
+       g_assert (frame.ex == NULL);
+
+       type = rmethod->rtype;
+       switch (type->type) {
+       case MONO_TYPE_VOID:
+               break;
+       case MONO_TYPE_I1:
+               *(gint8*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U1:
+               *(guint8*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I2:
+               *(gint16*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U2:
+               *(guint16*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I4:
+               *(gint32*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U4:
+               *(guint64*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I8:
+               *(gint64*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_U8:
+               *(guint64*)data->res = frame.retval->data.i;
+               break;
+       case MONO_TYPE_I:
+#if SIZEOF_VOID_P == 8
+               *(gint64*)data->res = (gint64)frame.retval->data.p;
+#else
+               *(gint32*)data->res = (gint32)frame.retval->data.p;
+#endif
+               break;
+       case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 8
+               *(guint64*)data->res = (guint64)frame.retval->data.p;
+#else
+               *(guint32*)data->res = (guint32)frame.retval->data.p;
+#endif
+               break;
+       case MONO_TYPE_OBJECT:
+               /* No need for a write barrier */
+               *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
+               break;
+       case MONO_TYPE_GENERICINST:
+               if (MONO_TYPE_IS_REFERENCE (type)) {
+                       *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
+               } else {
+                       /* Already set before the call */
                }
-               else
-                       printf("dropped exception...\n");
+               break;
+       case MONO_TYPE_VALUETYPE:
+               /* Already set before the call */
+               break;
+       default:
+               printf ("%s\n", mono_type_full_name (sig->ret));
+               NOT_IMPLEMENTED;
+               break;
        }
-       if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
-               return NULL;
-       if (isobject || method->string_ctor)
-               return result.data.p;
-       stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
-       return retval;
 }
 
 static stackval * 
 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
 {
-       MonoInvocation *old_frame = context->current_frame;
-       MonoInvocation *old_env_frame = context->env_frame;
+       InterpFrame *old_frame = context->current_frame;
+       InterpFrame *old_env_frame = context->env_frame;
        jmp_buf *old_env = context->current_env;
        jmp_buf env;
 
@@ -1431,12 +1666,12 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
 
        switch (op) {
        case MINT_ICALL_V_V: {
-               void (*func)() = ptr;
+               void (*func)(void) = ptr;
                func ();
                break;
        }
        case MINT_ICALL_V_P: {
-               gpointer (*func)() = ptr;
+               gpointer (*func)(void) = ptr;
                sp++;
                sp [-1].data.p = func ();
                break;
@@ -1498,84 +1733,455 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
        return sp;
 }
 
-static mono_mutex_t create_method_pointer_mutex;
+static stackval *
+do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod)
+{
+       MonoMethodSignature *sig;
+       MonoFtnDesc ftndesc;
+       guint8 res_buf [256];
+       MonoType *type;
+       MonoLMFExt ext;
+
+       //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
+
+       /*
+        * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
+        * by ref and return a return value using an explicit return value argument.
+        */
+       if (!rmethod->jit_wrapper) {
+               MonoMethod *method = rmethod->method;
+               MonoError error;
+
+               sig = mono_method_signature (method);
+               g_assert (sig);
 
-static GHashTable *method_pointer_hash = NULL;
+               MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+               //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
 
-#define TRAMPS_USED 8
+               gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
+               mono_error_assert_ok (&error);
 
-static MonoMethod *method_pointers [TRAMPS_USED] = {0};
+               gpointer addr = mono_jit_compile_method_jit_only (method, &error);
+               g_assert (addr);
+               mono_error_assert_ok (&error);
 
-#define GEN_METHOD_PTR_TRAMP(num) \
-               static MonoObject * mp_tramp_ ## num (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) { \
-                       MonoError error; \
-                       void *params_real[] = {this_obj, &params, &exc, &compiled_method}; \
-                       MonoObject *ret = mono_interp_runtime_invoke (method_pointers [num], NULL, params_real, NULL, &error); \
-                       mono_error_cleanup (&error); \
-                       return ret; \
+               rmethod->jit_addr = addr;
+               rmethod->jit_sig = sig;
+               mono_memory_barrier ();
+               rmethod->jit_wrapper = jit_wrapper;
+
+       } else {
+               sig = rmethod->jit_sig;
+       }
+
+       sp -= sig->param_count;
+       if (sig->hasthis)
+               --sp;
+
+       ftndesc.addr = rmethod->jit_addr;
+       ftndesc.arg = NULL;
+
+       // FIXME: Optimize this
+
+       gpointer args [32];
+       int pindex = 0;
+       int stack_index = 0;
+       if (rmethod->hasthis) {
+               args [pindex ++] = sp [0].data.p;
+               stack_index ++;
+       }
+       type = rmethod->rtype;
+       if (type->type != MONO_TYPE_VOID) {
+               if (MONO_TYPE_ISSTRUCT (type))
+                       args [pindex ++] = vt_sp;
+               else
+                       args [pindex ++] = res_buf;
+       }
+       for (int i = 0; i < rmethod->param_count; ++i) {
+               MonoType *t = rmethod->param_types [i];
+               stackval *sval = &sp [stack_index + i];
+               if (sig->params [i]->byref) {
+                       args [pindex ++] = sval->data.p;
+               } else if (MONO_TYPE_ISSTRUCT (t)) {
+                       args [pindex ++] = sval->data.p;
+               } else if (MONO_TYPE_IS_REFERENCE (t)) {
+                       args [pindex ++] = &sval->data.p;
+               } else {
+                       switch (t->type) {
+                       case MONO_TYPE_I1:
+                       case MONO_TYPE_U1:
+                       case MONO_TYPE_I2:
+                       case MONO_TYPE_U2:
+                       case MONO_TYPE_I4:
+                       case MONO_TYPE_U4:
+                       case MONO_TYPE_VALUETYPE:
+                               args [pindex ++] = &sval->data.i;
+                               break;
+                       case MONO_TYPE_PTR:
+                       case MONO_TYPE_FNPTR:
+                       case MONO_TYPE_I:
+                       case MONO_TYPE_U:
+                       case MONO_TYPE_OBJECT:
+                               args [pindex ++] = &sval->data.p;
+                               break;
+                       case MONO_TYPE_I8:
+                       case MONO_TYPE_U8:
+                               args [pindex ++] = &sval->data.l;
+                               break;
+                       default:
+                               printf ("%s\n", mono_type_full_name (t));
+                               g_assert_not_reached ();
+                       }
+               }
+       }
+
+       interp_push_lmf (&ext, frame);
+
+       switch (pindex) {
+       case 0: {
+               void (*func)(gpointer) = rmethod->jit_wrapper;
+
+               func (&ftndesc);
+               break;
+       }
+       case 1: {
+               void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], &ftndesc);
+               break;
+       }
+       case 2: {
+               void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], args [1], &ftndesc);
+               break;
+       }
+       case 3: {
+               void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], args [1], args [2], &ftndesc);
+               break;
+       }
+       case 4: {
+               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], args [1], args [2], args [3], &ftndesc);
+               break;
+       }
+       case 5: {
+               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
+               break;
+       }
+       case 6: {
+               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
+               break;
+       }
+       case 7: {
+               void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+               func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
+               break;
+       }
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+
+       interp_pop_lmf (&ext);
+
+       MonoType *rtype = rmethod->rtype;
+       switch (rtype->type) {
+       case MONO_TYPE_VOID:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+               sp->data.p = *(gpointer*)res_buf;
+               break;
+       case MONO_TYPE_I1:
+               sp->data.i = *(gint8*)res_buf;
+               break;
+       case MONO_TYPE_U1:
+               sp->data.i = *(guint8*)res_buf;
+               break;
+       case MONO_TYPE_I2:
+               sp->data.i = *(gint16*)res_buf;
+               break;
+       case MONO_TYPE_U2:
+               sp->data.i = *(guint16*)res_buf;
+               break;
+       case MONO_TYPE_I4:
+               sp->data.i = *(gint32*)res_buf;
+               break;
+       case MONO_TYPE_U4:
+               sp->data.i = *(guint32*)res_buf;
+               break;
+       case MONO_TYPE_VALUETYPE:
+               /* The result was written to vt_sp */
+               sp->data.p = vt_sp;
+               break;
+       case MONO_TYPE_GENERICINST:
+               if (MONO_TYPE_IS_REFERENCE (rtype)) {
+                       sp->data.p = *(gpointer*)res_buf;
+               } else {
+                       /* The result was written to vt_sp */
+                       sp->data.p = vt_sp;
                }
+               break;
+       default:
+               printf ("%s\n", mono_type_full_name (rtype));
+               g_assert_not_reached ();
+               break;
+       }
+
+       return sp;
+}
+
+static void
+do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
+{
+       MonoLMFExt ext;
+       interp_push_lmf (&ext, frame);
+       tramp ();
+       interp_pop_lmf (&ext);
+}
+
+static void
+do_transform_method (InterpFrame *frame, ThreadContext *context)
+{
+       MonoLMFExt ext;
+
+       /* Use the parent frame as the current frame is not complete yet */
+       interp_push_lmf (&ext, frame->parent);
 
+       frame->ex = mono_interp_transform_method (frame->imethod, context);
+       context->managed_code = 1;
+
+       interp_pop_lmf (&ext);
+}
+
+/*
+ * These functions are the entry points into the interpreter from compiled code.
+ * They are called by the interp_in wrappers. They have the following signature:
+ * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
+ * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
+ * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
+ * more wrappers then these functions.
+ * this/static * ret/void * 16 arguments -> 64 functions.
+ */
 
-GEN_METHOD_PTR_TRAMP (0);
-GEN_METHOD_PTR_TRAMP (1);
-GEN_METHOD_PTR_TRAMP (2);
-GEN_METHOD_PTR_TRAMP (3);
-GEN_METHOD_PTR_TRAMP (4);
-GEN_METHOD_PTR_TRAMP (5);
-GEN_METHOD_PTR_TRAMP (6);
-GEN_METHOD_PTR_TRAMP (7);
+#define MAX_INTERP_ENTRY_ARGS 8
 
-#undef GEN_METHOD_PTR_TRAMP
+#define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
+       InterpEntryData data; \
+       (data).rmethod = (_method); \
+       (data).res = (_res); \
+       (data).this_arg = (_this_arg); \
+       (data).many_args = NULL;
 
-gpointer *mp_tramps[TRAMPS_USED] = {
-       (gpointer) mp_tramp_0, (gpointer) mp_tramp_1, (gpointer) mp_tramp_2, (gpointer) mp_tramp_3,
-       (gpointer) mp_tramp_4, (gpointer) mp_tramp_5, (gpointer) mp_tramp_6, (gpointer) mp_tramp_7
-};
+#define INTERP_ENTRY0(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY1(_this_arg, _res, _method) {        \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY2(_this_arg, _res, _method) {  \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY3(_this_arg, _res, _method) { \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY4(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY5(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY6(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       (data).args [5] = arg6; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY7(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       (data).args [5] = arg6; \
+       (data).args [6] = arg7; \
+       interp_entry (&data); \
+       }
+#define INTERP_ENTRY8(_this_arg, _res, _method) {      \
+       INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+       (data).args [0] = arg1; \
+       (data).args [1] = arg2; \
+       (data).args [2] = arg3; \
+       (data).args [3] = arg4; \
+       (data).args [4] = arg5; \
+       (data).args [5] = arg6; \
+       (data).args [6] = arg7; \
+       (data).args [7] = arg8; \
+       interp_entry (&data); \
+       }
 
-static int tramps_used = 0;
+#define ARGLIST0 InterpMethod *rmethod
+#define ARGLIST1 gpointer arg1, InterpMethod *rmethod
+#define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
+#define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
+#define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
+#define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
+#define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
+#define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
+#define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
+
+static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
+static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
+static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
+static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
+static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
+static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
+static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
+static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
+static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
+static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
+static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
+static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
+static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
+static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
+static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
+static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
+static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
+static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
+static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
+static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
+static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
+static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
+static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
+static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
+static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
+static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
+static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
+static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod)
+
+#define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
+
+gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
+gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
+gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
+gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
+
+/* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
+static void
+interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
+{
+       INTERP_ENTRY_BASE (rmethod, this_arg, res);
+       data.many_args = args;
+       interp_entry (&data);
+}
 
+/*
+ * mono_interp_create_method_pointer:
+ *
+ * Return a function pointer which can be used to call METHOD using the
+ * interpreter. Return NULL for methods which are not supported.
+ */
 gpointer
 mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
 {
        gpointer addr;
-       MonoJitInfo *ji;
-
-       mono_os_mutex_lock (&create_method_pointer_mutex);
-       if (!method_pointer_hash) {
-               // FIXME: is registering method table as GC root really necessary?
-               // MONO_GC_REGISTER_ROOT_FIXED (method_pointer_hash);
-               method_pointer_hash = g_hash_table_new (NULL, NULL);
-       }
-       addr = g_hash_table_lookup (method_pointer_hash, method);
-       if (addr) {
-               mono_os_mutex_unlock (&create_method_pointer_mutex);
-               return addr;
+       MonoMethodSignature *sig = mono_method_signature (method);
+       MonoMethod *wrapper;
+       InterpMethod *rmethod = mono_interp_get_imethod (mono_domain_get (), method, error);
+
+       /* HACK: method_ptr of delegate should point to a runtime method*/
+       if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+               return rmethod;
+
+       if (rmethod->jit_entry)
+               return rmethod->jit_entry;
+       wrapper = mini_get_interp_in_wrapper (sig);
+
+       gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
+       mono_error_assert_ok (error);
+
+       //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
+       gpointer entry_func;
+       if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
+               entry_func = interp_entry_general;
+       } else if (sig->hasthis) {
+               if (sig->ret->type == MONO_TYPE_VOID)
+                       entry_func = entry_funcs_instance [sig->param_count];
+               else
+                       entry_func = entry_funcs_instance_ret [sig->param_count];
+       } else {
+               if (sig->ret->type == MONO_TYPE_VOID)
+                       entry_func = entry_funcs_static [sig->param_count];
+               else
+                       entry_func = entry_funcs_static_ret [sig->param_count];
        }
+       g_assert (entry_func);
+
+       /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
+       MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
+       ftndesc->addr = entry_func;
+       ftndesc->arg = rmethod;
+       mono_error_assert_ok (error);
 
        /*
-        * If it is a static P/Invoke method, we can just return the pointer
-        * to the method implementation.
+        * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
+        * rgctx register using a trampoline.
         */
-       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) {
-               ji = g_new0 (MonoJitInfo, 1);
-               ji->d.method = method;
-               ji->code_size = 1;
-               ji->code_start = addr = ((MonoMethodPInvoke*) method)->addr;
-
-               mono_jit_info_table_add (mono_get_root_domain (), ji);
-       }               
-       else {
-               g_assert (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE);
-               g_assert (tramps_used < TRAMPS_USED);
-
-               /* FIXME: needs locking */
-               method_pointers [tramps_used] = method;
-               addr = mp_tramps [tramps_used];
-               tramps_used++;
-       }
 
-       g_hash_table_insert (method_pointer_hash, method, addr);
-       mono_os_mutex_unlock (&create_method_pointer_mutex);
+       if (mono_aot_only)
+               addr = mono_aot_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
+       else
+               addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
+
+       mono_memory_barrier ();
+       rmethod->jit_entry = addr;
 
        return addr;
 }
@@ -1599,7 +2205,7 @@ static int opcode_counts[512];
                } \
                sp->data.l = 0; \
                output_indent (); \
-               char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
+               char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
                g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \
                g_free (mn); \
                mono_interp_dis_mintop(rtm->code, ip); \
@@ -1629,18 +2235,23 @@ static int opcode_counts[512];
 #define MINT_IN_DEFAULT default:
 #endif
 
+/*
+ * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
+ */
 static void 
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
+ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally)
 {
-       MonoInvocation child_frame;
+       InterpFrame child_frame;
        GSList *finally_ips = NULL;
        const unsigned short *endfinally_ip = NULL;
        const unsigned short *ip = NULL;
        register stackval *sp;
-       RuntimeMethod *rtm;
+       InterpMethod *rtm;
 #if DEBUG_INTERP
        gint tracing = global_tracing;
        unsigned char *vtalloc;
+#else
+       gint tracing = 0;
 #endif
        int i32;
        unsigned char *vt_sp;
@@ -1661,19 +2272,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
        frame->ip = NULL;
        context->current_frame = frame;
 
-#if DEBUG_INTERP
        debug_enter (frame, &tracing);
-#endif
 
-       if (!frame->runtime_method->transformed) {
+       if (!frame->imethod->transformed) {
                context->managed_code = 0;
 #if DEBUG_INTERP
-               char *mn = mono_method_full_name (frame->runtime_method->method, TRUE);
+               char *mn = mono_method_full_name (frame->imethod->method, TRUE);
                g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
                g_free (mn);
 #endif
-               frame->ex = mono_interp_transform_method (frame->runtime_method, context);
-               context->managed_code = 1;
+
+               do_transform_method (frame, context);
                if (frame->ex) {
                        rtm = NULL;
                        ip = NULL;
@@ -1681,26 +2290,28 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                }
        }
 
-       rtm = frame->runtime_method;
-       frame->args = alloca (rtm->alloca_size);
-       memset (frame->args, 0, rtm->alloca_size);
-
-       sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size);
-       memset (sp, 0, rtm->stack_size);
+       rtm = frame->imethod;
+       if (!start_with_ip ) {
+               frame->args = alloca (rtm->alloca_size);
+               memset (frame->args, 0, rtm->alloca_size);
 
+               ip = rtm->code;
+       } else {
+               ip = start_with_ip;
+       }
+       sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
        vt_sp = (unsigned char *) sp + rtm->stack_size;
-       memset (vt_sp, 0, rtm->vt_stack_size);
 #if DEBUG_INTERP
        vtalloc = vt_sp;
 #endif
-
        locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
-       memset (vt_sp, 0, rtm->locals_size);
-
+       frame->locals = locals;
        child_frame.parent = frame;
 
-       /* ready to go */
-       ip = rtm->code;
+       if (filter_exception) {
+               sp->data.p = filter_exception;
+               sp++;
+       }
 
        /*
         * using while (ip < end) may result in a 15% performance drop, 
@@ -1721,7 +2332,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_BREAK)
                        ++ip;
-                       G_BREAKPOINT (); /* this is not portable... */
+                       do_debugger_tramp (mono_debugger_agent_user_break, frame);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDNULL) 
                        sp->data.p = NULL;
@@ -1824,7 +2435,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_JMP) {
-                       RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
+                       InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
                        if (!new_method->transformed) {
                                frame->ip = ip;
                                frame->ex = mono_interp_transform_method (new_method, context);
@@ -1834,12 +2445,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        ip += 2;
                        if (new_method->alloca_size > rtm->alloca_size)
                                g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size); 
-                       rtm = frame->runtime_method = new_method;
+                       rtm = frame->imethod = new_method;
                        vt_sp = (unsigned char *) sp + rtm->stack_size;
 #if DEBUG_INTERP
                        vtalloc = vt_sp;
 #endif
                        locals = vt_sp + rtm->vt_stack_size;
+                       frame->locals = locals;
                        ip = rtm->new_body_start; /* bypass storing input args from callers frame */
                        MINT_IN_BREAK;
                }
@@ -1853,7 +2465,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        ip += 2;
                        --sp;
                        --endsp;
-                       child_frame.runtime_method = sp->data.p;
+                       child_frame.imethod = sp->data.p;
 
                        sp->data.p = vt_sp;
                        child_frame.retval = sp;
@@ -1863,12 +2475,15 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                --sp;
                        child_frame.stack_args = sp;
 
+#ifndef DISABLE_REMOTING
                        /* `this' can be NULL for string:.ctor */
                        if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
-                               child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
+                               child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.imethod->method), &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
-                               child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
+                       } else
+#endif
+                       if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+                               child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
 
@@ -1881,10 +2496,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                }
                        }
 
-                       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..
@@ -1912,7 +2534,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        --sp;
                        --endsp;
                        code = sp->data.p;
-                       child_frame.runtime_method = NULL;
+                       child_frame.imethod = NULL;
 
                        sp->data.p = vt_sp;
                        child_frame.retval = sp;
@@ -1925,6 +2547,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
 
                        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..
@@ -1949,25 +2578,35 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
 
                        frame->ip = ip;
                        
-                       child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
+                       child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
                        ip += 2;
                        sp->data.p = vt_sp;
                        child_frame.retval = sp;
                        /* decrement by the actual number of args */
-                       sp -= child_frame.runtime_method->param_count;
-                       if (child_frame.runtime_method->hasthis)
+                       sp -= child_frame.imethod->param_count;
+                       if (child_frame.imethod->hasthis)
                                --sp;
                        child_frame.stack_args = sp;
 
+#ifndef DISABLE_REMOTING
                        /* `this' can be NULL for string:.ctor */
-                       if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
-                               child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
+                       if (child_frame.imethod->hasthis && !child_frame.imethod->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
+                               child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.imethod->method), &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
-                       ves_exec_method_with_context (&child_frame, context);
+#endif
+
+                       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..
@@ -1984,14 +2623,14 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                MINT_IN_CASE(MINT_VCALL) {
                        frame->ip = ip;
                        
-                       child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)];
+                       child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
                        ip += 2;
 
                        sp->data.p = vt_sp;
                        child_frame.retval = sp;
                        /* decrement by the actual number of args */
-                       sp -= child_frame.runtime_method->param_count;
-                       if (child_frame.runtime_method->hasthis) {
+                       sp -= child_frame.imethod->param_count;
+                       if (child_frame.imethod->hasthis) {
                                --sp;
                                MonoObject *this_arg = sp->data.p;
                                if (!this_arg)
@@ -1999,15 +2638,24 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        }
                        child_frame.stack_args = sp;
 
-                       if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
-                               child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
+#ifndef DISABLE_REMOTING
+                       if (child_frame.imethod->hasthis && !child_frame.imethod->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
+                               child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.imethod->method), &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
+#endif
 
-                       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..
@@ -2017,6 +2665,31 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        }
                        MINT_IN_BREAK;
                }
+
+               MINT_IN_CASE(MINT_JIT_CALL) {
+                       InterpMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
+                       frame->ip = ip;
+                       ip += 2;
+                       sp = do_jit_call (sp, vt_sp, context, frame, rmethod);
+
+                       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;
+                       }
+                       if (rmethod->rtype->type != MONO_TYPE_VOID)
+                               sp++;
+
+                       MINT_IN_BREAK;
+               }
+
                MINT_IN_CASE(MINT_CALLVIRT) {
                        stackval *endsp = sp;
                        MonoObject *this_arg;
@@ -2026,29 +2699,36 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        
                        token = * (unsigned short *)(ip + 1);
                        ip += 2;
-                       child_frame.runtime_method = rtm->data_items [token];
+                       child_frame.imethod = rtm->data_items [token];
                        sp->data.p = vt_sp;
                        child_frame.retval = sp;
 
                        /* decrement by the actual number of args */
-                       sp -= child_frame.runtime_method->param_count + 1;
+                       sp -= child_frame.imethod->param_count + 1;
                        child_frame.stack_args = sp;
                        this_arg = sp->data.p;
                        if (!this_arg)
                                THROW_EX (mono_get_exception_null_reference(), ip - 2);
-                       child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
+                       child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
 
                        MonoClass *this_class = this_arg->vtable->klass;
-                       if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
+                       if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
                                /* unbox */
                                gpointer *unboxed = mono_object_unbox (this_arg);
                                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..
@@ -2074,28 +2754,35 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        
                        token = * (unsigned short *)(ip + 1);
                        ip += 2;
-                       child_frame.runtime_method = rtm->data_items [token];
+                       child_frame.imethod = rtm->data_items [token];
                        sp->data.p = vt_sp;
                        child_frame.retval = sp;
 
                        /* decrement by the actual number of args */
-                       sp -= child_frame.runtime_method->param_count + 1;
+                       sp -= child_frame.imethod->param_count + 1;
                        child_frame.stack_args = sp;
                        this_arg = sp->data.p;
                        if (!this_arg)
                                THROW_EX (mono_get_exception_null_reference(), ip - 2);
-                       child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
+                       child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
 
                        MonoClass *this_class = this_arg->vtable->klass;
-                       if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
+                       if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
                                gpointer *unboxed = mono_object_unbox (this_arg);
                                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..
@@ -2110,7 +2797,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CALLRUN)
-                       ves_runtime_method (frame, context);
+                       ves_imethod (frame, context);
                        if (frame->ex) {
                                rtm = NULL;
                                goto handle_exception;
@@ -2124,7 +2811,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        goto exit_frame;
                MINT_IN_CASE(MINT_RET_VOID)
                        if (sp > frame->stack)
-                               g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
+                               g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
                        goto exit_frame;
                MINT_IN_CASE(MINT_RET_VT)
                        i32 = READ32(ip + 1);
@@ -2415,7 +3102,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                gint offset;
                                ip += 2 * (guint32)sp->data.i;
                                offset = READ32 (ip);
-                               ip = st + offset;
+                               ip = ip + offset;
                        } else {
                                ip = st;
                        }
@@ -2444,7 +3131,8 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDIND_I8)
                        ++ip;
-                       sp[-1].data.l = *(gint64*)sp[-1].data.p;
+                       /* memmove handles unaligned case */
+                       memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDIND_I) {
                        guint16 offset = * (guint16 *)(ip + 1);
@@ -2504,6 +3192,11 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        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; \
@@ -2733,7 +3426,11 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        ++ip;
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CONV_U4_R8)
-                       sp [-1].data.i = (guint32)sp [-1].data.f;
+                       /* needed on arm64 */
+                       if (isinf (sp [-1].data.f))
+                               sp [-1].data.i = 0;
+                       else
+                               sp [-1].data.i = (guint32)sp [-1].data.f;
                        ++ip;
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CONV_I8_I4)
@@ -2782,10 +3479,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CPOBJ) {
                        c = rtm->data_items[* (guint16 *)(ip + 1)];
-                       g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
+                       g_assert (c->valuetype);
                        /* if this assertion fails, we need to add a write barrier */
                        g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
-                       stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+                       if (c->byval_arg.type == MONO_TYPE_VALUETYPE)
+                               stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+                       else
+                               stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
                        ip += 2;
                        sp -= 2;
                        MINT_IN_BREAK;
@@ -2823,9 +3523,9 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        child_frame.ip = NULL;
                        child_frame.ex = NULL;
 
-                       child_frame.runtime_method = rtm->data_items [token];
-                       csig = mono_method_signature (child_frame.runtime_method->method);
-                       newobj_class = child_frame.runtime_method->method->klass;
+                       child_frame.imethod = rtm->data_items [token];
+                       csig = mono_method_signature (child_frame.imethod->method);
+                       newobj_class = child_frame.imethod->method->klass;
                        /*if (profiling_classes) {
                                guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
                                count++;
@@ -2835,7 +3535,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        if (newobj_class->parent == mono_defaults.array_class) {
                                sp -= csig->param_count;
                                child_frame.stack_args = sp;
-                               o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
+                               o = ves_array_create (&child_frame, rtm->domain, newobj_class, csig, sp);
                                if (child_frame.ex)
                                        THROW_EX (child_frame.ex, ip);
                                goto array_constructed;
@@ -2863,7 +3563,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        } else {
                                if (newobj_class != mono_defaults.string_class) {
                                        context->managed_code = 0;
-                                       o = mono_object_new_checked (context->domain, newobj_class, &error);
+                                       o = mono_object_new_checked (rtm->domain, newobj_class, &error);
                                        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                                        context->managed_code = 1;
                                        if (*mono_thread_interruption_request_flag ())
@@ -2877,10 +3577,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
 
                        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..
@@ -2950,6 +3657,7 @@ array_constructed:
                        frame->ex_handler = NULL;
                        if (!sp->data.p)
                                sp->data.p = mono_get_exception_null_reference ();
+
                        THROW_EX ((MonoException *)sp->data.p, ip);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
@@ -3010,14 +3718,15 @@ array_constructed:
                                THROW_EX (mono_get_exception_null_reference (), ip);
                        field = rtm->data_items[* (guint16 *)(ip + 1)];
                        ip += 2;
+#ifndef DISABLE_REMOTING
                        if (mono_object_is_transparent_proxy (o)) {
                                MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
 
                                addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       } else {
+                       } else
+#endif
                                addr = (char*)o + field->offset;
-                       }                               
 
                        stackval_from_data (field->type, &sp [-1], addr, FALSE);
                        MINT_IN_BREAK;
@@ -3034,13 +3743,14 @@ array_constructed:
                        field = rtm->data_items[* (guint16 *)(ip + 1)];
                        i32 = READ32(ip + 2);
                        ip += 4;
+#ifndef DISABLE_REMOTING
                        if (mono_object_is_transparent_proxy (o)) {
                                MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
                                addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       } else {
+                       } else
+#endif
                                addr = (char*)o + field->offset;
-                       }                               
 
                        sp [-1].data.p = vt_sp;
                        memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
@@ -3096,11 +3806,13 @@ array_constructed:
                        field = rtm->data_items[* (guint16 *)(ip + 1)];
                        ip += 2;
 
+#ifndef DISABLE_REMOTING
                        if (mono_object_is_transparent_proxy (o)) {
                                MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
                                mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        } else
+#endif
                                stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
 
                        sp -= 2;
@@ -3116,11 +3828,13 @@ array_constructed:
                        i32 = READ32(ip + 2);
                        ip += 4;
 
+#ifndef DISABLE_REMOTING
                        if (mono_object_is_transparent_proxy (o)) {
                                MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
                                mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        } else
+#endif
                                memcpy((char*)o + field->offset, sp [-1].data.p, i32);
 
                        sp -= 2;
@@ -3129,14 +3843,14 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_LDSFLDA) {
                        MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
-                       sp->data.p = mono_class_static_field_address (context->domain, field);
+                       sp->data.p = mono_class_static_field_address (rtm->domain, field);
                        ip += 2;
                        ++sp;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_LDSFLD) {
                        MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
-                       gpointer addr = mono_class_static_field_address (context->domain, field);
+                       gpointer addr = mono_class_static_field_address (rtm->domain, field);
                        stackval_from_data (field->type, sp, addr, FALSE);
                        ip += 2;
                        ++sp;
@@ -3144,7 +3858,7 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_LDSFLD_VT) {
                        MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
-                       gpointer addr = mono_class_static_field_address (context->domain, field);
+                       gpointer addr = mono_class_static_field_address (rtm->domain, field);
                        int size = READ32 (ip + 2);
                        ip += 4;
 
@@ -3156,7 +3870,7 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_STSFLD) {
                        MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
-                       gpointer addr = mono_class_static_field_address (context->domain, field);
+                       gpointer addr = mono_class_static_field_address (rtm->domain, field);
                        ip += 2;
                        --sp;
                        stackval_to_data (field->type, sp, addr, FALSE);
@@ -3164,7 +3878,7 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_STSFLD_VT) {
                        MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
-                       gpointer addr = mono_class_static_field_address (context->domain, field);
+                       gpointer addr = mono_class_static_field_address (rtm->domain, field);
                        int size = READ32 (ip + 2);
                        ip += 4;
 
@@ -3242,20 +3956,20 @@ array_constructed:
 
                        if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
                                int size = mono_class_value_size (c, NULL);
-                               sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error);
+                               sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                                size = (size + 7) & ~7;
                                vt_sp -= size;
                        } else {
                                stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
-                               sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error);
+                               sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_NEWARR)
-                       sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
+                       sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
                        if (!mono_error_ok (&error)) {
                                THROW_EX (mono_error_convert_to_exception (&error), ip);
                        }
@@ -3290,7 +4004,10 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_STRLEN)
                        ++ip;
-                       sp [-1].data.i = mono_string_length ((MonoString*)sp [-1].data.p);
+                       o = sp [-1].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       sp [-1].data.i = mono_string_length ((MonoString*) o);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ARRAY_RANK)
                        o = sp [-1].data.p;
@@ -3400,6 +4117,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 */
@@ -3431,6 +4149,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;
@@ -3580,17 +4301,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;
@@ -3659,13 +4413,20 @@ 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;
+                       }
                        if (finally_ips) {
                                ip = finally_ips->data;
                                finally_ips = g_slist_remove (finally_ips, ip);
                                goto main_loop;
                        }
                        if (frame->ex)
-                               goto handle_fault;
+                               goto handle_catch;
                        ves_abort();
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LEAVE) /* Fall through */
@@ -3697,6 +4458,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;
@@ -3707,7 +4475,7 @@ array_constructed:
                        ++sp;
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_MONO_NEWOBJ)
-                       sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
+                       sp->data.p = mono_object_new_checked (rtm->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
                        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        ip += 2;
                        sp++;
@@ -3721,11 +4489,102 @@ array_constructed:
                MINT_IN_CASE(MINT_MONO_RETOBJ)
                        ++ip;
                        sp--;
-                       stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p,
-                            mono_method_signature (frame->runtime_method->method)->pinvoke);
+                       stackval_from_data (mono_method_signature (frame->imethod->method)->ret, frame->retval, sp->data.p,
+                            mono_method_signature (frame->imethod->method)->pinvoke);
                        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_MEMORY_BARRIER) {
+                       ++ip;
+                       mono_memory_barrier ();
+                       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 != rtm->domain || !tls_jit)
+                               context->original_domain = mono_jit_thread_attach (rtm->domain);
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_MONO_JIT_DETACH)
+                       ++ip;
+                       mono_jit_set_domain (context->original_domain);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MONO_LDDOMAIN)
+                       sp->data.p = mono_domain_get ();
+                       ++sp;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SDB_INTR_LOC)
+                       if (G_UNLIKELY (ss_enabled)) {
+                               static void (*ss_tramp) (void);
+
+                               if (!ss_tramp) {
+                                       void *tramp = mini_get_single_step_trampoline ();
+                                       mono_memory_barrier ();
+                                       ss_tramp = tramp;
+                               }
+
+                               /*
+                                * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
+                                * the address of that instruction is stored as the seq point address.
+                                */
+                               frame->ip = ip + 1;
+
+                               /*
+                                * Use the same trampoline as the JIT. This ensures that
+                                * the debugger has the context for the last interpreter
+                                * native frame.
+                                */
+                               do_debugger_tramp (ss_tramp, frame);
+
+                               if (context->has_resume_state) {
+                                       if (frame == context->handler_frame)
+                                               SET_RESUME_STATE (context);
+                                       else
+                                               goto exit_frame;
+                               }
+                       }
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SDB_SEQ_POINT)
+                       /* Just a placeholder for a breakpoint */
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
+                       static void (*bp_tramp) (void);
+                       if (!bp_tramp) {
+                               void *tramp = mini_get_breakpoint_trampoline ();
+                               mono_memory_barrier ();
+                               bp_tramp = tramp;
+                       }
+
+                       frame->ip = ip;
+
+                       /* Use the same trampoline as the JIT */
+                       do_debugger_tramp (bp_tramp, frame);
+
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
+                       ++ip;
+                       MINT_IN_BREAK;
+               }
 
 #define RELOP(datamem, op) \
        --sp; \
@@ -3818,13 +4677,13 @@ array_constructed:
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_LDVIRTFTN) {
-                       RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
+                       InterpMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
                        ip += 2;
                        --sp;
                        if (!sp->data.p)
                                THROW_EX (mono_get_exception_null_reference (), ip - 2);
                                
-                       sp->data.p = get_virtual_method (context->domain, m, sp->data.p);
+                       sp->data.p = get_virtual_method (m, sp->data.p);
                        ++sp;
                        MINT_IN_BREAK;
                }
@@ -3904,6 +4763,26 @@ array_constructed:
                        MINT_IN_BREAK;
                }
 
+               MINT_IN_CASE(MINT_PROF_ENTER) {
+                       ip += 1;
+
+                       if (MONO_PROFILER_ENABLED (method_enter)) {
+                               MonoProfilerCallContext *prof_ctx = NULL;
+
+                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT) {
+                                       prof_ctx = g_new0 (MonoProfilerCallContext, 1);
+                                       prof_ctx->interp_frame = frame;
+                                       prof_ctx->method = frame->imethod->method;
+                               }
+
+                               MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
+
+                               g_free (prof_ctx);
+                       }
+
+                       MINT_IN_BREAK;
+               }
+
                MINT_IN_CASE(MINT_LDARGA)
                        sp->data.p = frame->args + * (guint16 *)(ip + 1);
                        ip += 2;
@@ -3978,16 +4857,17 @@ array_constructed:
 
                        int len = sp [-1].data.i;
                        sp [-1].data.p = alloca (len);
-                       MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
+                       MonoMethodHeader *header = mono_method_get_header_checked (frame->imethod->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;
                }
-#if 0
-               MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK;
-#endif
+               MINT_IN_CASE(MINT_ENDFILTER)
+                       /* top of stack is result of filter */
+                       frame->retval = &sp [-1];
+                       goto exit_frame;
                MINT_IN_CASE(MINT_INITOBJ)
                        --sp;
                        memset (sp->data.vt, 0, READ32(ip + 1));
@@ -4025,7 +4905,7 @@ array_constructed:
                        ip += 2;
                        MINT_IN_BREAK;
 #endif
-               MINT_IN_CASE(MINT_RETHROW)
+          MINT_IN_CASE(MINT_RETHROW) {
                        /* 
                         * need to clarify what this should actually do:
                         * start the search from the last found handler in
@@ -4036,9 +4916,11 @@ array_constructed:
                         * We need to NULL frame->ex_handler for the later code to
                         * actually run the new found handler.
                         */
+                       int exvar_offset = *(guint16*)(ip + 1);
                        frame->ex_handler = NULL;
-                       THROW_EX (frame->ex, ip - 1);
+                       THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip - 1, TRUE);
                        MINT_IN_BREAK;
+          }
                MINT_IN_DEFAULT
                        g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
                        THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
@@ -4055,7 +4937,7 @@ array_constructed:
        {
                int i;
                guint32 ip_offset;
-               MonoInvocation *inv;
+               InterpFrame *inv;
                MonoExceptionClause *clause;
                /*char *message;*/
                MonoObject *ex_obj;
@@ -4071,37 +4953,59 @@ array_constructed:
 
                for (inv = frame; inv; inv = inv->parent) {
                        MonoMethod *method;
-                       if (inv->runtime_method == NULL)
+                       if (inv->imethod == NULL)
                                continue;
-                       method = inv->runtime_method->method;
+                       method = inv->imethod->method;
                        if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
                                continue;
                        if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
                                continue;
                        if (inv->ip == NULL)
                                continue;
-                       ip_offset = inv->ip - inv->runtime_method->code;
+                       ip_offset = inv->ip - inv->imethod->code;
                        inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one  - this one wins */
-                       for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
-                               clause = &inv->runtime_method->clauses [i];
-                               if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
-                                       if (!clause->flags) {
-                                               MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
-                                               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                                               if (isinst_obj) {
-                                                       /* 
-                                                        * OK, we found an handler, now we need to execute the finally
-                                                        * and fault blocks before branching to the handler code.
-                                                        */
-                                                       inv->ex_handler = clause;
+                       for (i = 0; i < inv->imethod->num_clauses; ++i) {
+                               clause = &inv->imethod->clauses [i];
+#if DEBUG_INTERP
+                               g_print ("* clause [%d]: %p\n", i, clause);
+#endif
+                               if (!MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
+                                       continue;
+                               }
+                               if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+#if DEBUG_INTERP
+                                       if (tracing)
+                                               g_print ("* Filter found at '%s'\n", method->name);
+#endif
+                                       InterpFrame dup_frame;
+                                       stackval retval;
+                                       memcpy (&dup_frame, inv, sizeof (InterpFrame));
+                                       dup_frame.retval = &retval;
+                                       ves_exec_method_with_context (&dup_frame, context, inv->imethod->code + clause->data.filter_offset, frame->ex, -1);
+                                       if (dup_frame.retval->data.i) {
 #if DEBUG_INTERP
-                                                       if (tracing)
-                                                               g_print ("* Found handler at '%s'\n", method->name);
+                                               if (tracing)
+                                                       g_print ("* Matched Filter at '%s'\n", method->name);
 #endif
-                                                       goto handle_finally;
-                                               }
-                                       } else {
-                                               g_error ("FIXME: handle filter clause");
+                                               inv->ex_handler = clause;
+                                               *(MonoException**)(inv->locals + inv->imethod->exvar_offsets [i]) = frame->ex;
+                                               goto handle_finally;
+                                       }
+                               } else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
+                                       MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
+                                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+                                       if (isinst_obj) {
+                                               /* 
+                                                * OK, we found an handler, now we need to execute the finally
+                                                * and fault blocks before branching to the handler code.
+                                                */
+#if DEBUG_INTERP
+                                               if (tracing)
+                                                       g_print ("* Found handler at '%s'\n", method->name);
+#endif
+                                               inv->ex_handler = clause;
+                                               *(MonoException**)(inv->locals + inv->imethod->exvar_offsets [i]) = frame->ex;
+                                               goto handle_finally;
                                        }
                                }
                        }
@@ -4114,7 +5018,8 @@ array_constructed:
                                goto handle_finally;
                }
 die_on_ex:
-               ex_obj = (MonoObject*)frame->ex;
+               ex_obj = (MonoObject *) frame->ex;
+               mono_unhandled_exception (ex_obj);
                MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls ();
                jit_tls->abort_func (ex_obj);
                g_assert_not_reached ();
@@ -4125,7 +5030,7 @@ die_on_ex:
                guint32 ip_offset;
                MonoExceptionClause *clause;
                GSList *old_list = finally_ips;
-               MonoMethod *method = frame->runtime_method->method;
+               MonoMethod *method = frame->imethod->method;
                MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                
@@ -4181,7 +5086,8 @@ die_on_ex:
                int i;
                guint32 ip_offset;
                MonoExceptionClause *clause;
-               MonoMethod *method = frame->runtime_method->method;
+               GSList *old_list = finally_ips;
+               MonoMethod *method = frame->imethod->method;
                MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                
@@ -4194,13 +5100,23 @@ die_on_ex:
                        clause = &rtm->clauses [i];
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
                                ip = rtm->code + clause->handler_offset;
+                               finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
 #if DEBUG_INTERP
                                if (tracing)
                                        g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
 #endif
-                               goto main_loop;
                        }
                }
+
+               if (old_list != finally_ips && finally_ips) {
+                       ip = finally_ips->data;
+                       finally_ips = g_slist_remove (finally_ips, ip);
+                       sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
+                       goto main_loop;
+               }
+       }
+       handle_catch:
+       {
                /*
                 * If the handler for the exception was found in this method, we jump
                 * to it right away, otherwise we return and let the caller run
@@ -4223,14 +5139,46 @@ die_on_ex:
                goto exit_frame;
        }
 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;
+                               }
+                       }
+
+                       MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+
+                       g_free (prof_ctx);
+               }
+       } else
+               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, (MonoObject *) frame->ex));
+
        DEBUG_LEAVE ();
 }
 
 void
-ves_exec_method (MonoInvocation *frame)
+ves_exec_method (InterpFrame *frame)
 {
        ThreadContext *context = mono_native_tls_get_value (thread_context_id);
        ThreadContext context_struct;
+       MonoDomain *domain = frame->imethod->domain;
        MonoError error;
        jmp_buf env;
 
@@ -4242,21 +5190,20 @@ ves_exec_method (MonoInvocation *frame)
        }
        if (context == NULL) {
                context = &context_struct;
-               context_struct.domain = mono_domain_get ();
                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);
+               set_context (context);
        }
        frame->ip = NULL;
        frame->parent = context->current_frame;
-       frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
+       frame->imethod = mono_interp_get_imethod (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) {
@@ -4267,160 +5214,30 @@ ves_exec_method (MonoInvocation *frame)
                        mono_unhandled_exception ((MonoObject*)frame->ex);
        }
        if (context->base_frame == frame)
-               mono_native_tls_set_value (thread_context_id, NULL);
+               set_context (NULL);
        else
                context->current_frame = frame->parent;
 }
 
-static int 
-ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
-{
-       MonoImage *image = mono_assembly_get_image (assembly);
-       MonoMethod *method;
-       MonoError error;
-       int rval;
-
-       method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
-       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-
-       if (!method)
-               g_error ("No entry point method found in %s", mono_image_get_filename (image));
-
-       rval = mono_runtime_run_main_checked (method, argc, argv, &error);
-       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-       return rval;
-}
-
-static void
-usage (void)
-{
-       fprintf (stderr,
-                "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
-                "Usage is: mint [options] executable args...\n\n", VERSION);
-       fprintf (stderr,
-                "Runtime Debugging:\n"
-#ifdef DEBUG_INTERP
-                "   --debug\n"
-#endif
-                "   --dieonex\n"
-                "   --noptr\t\t\tdon't print pointer addresses in trace output\n"
-                "   --opcode-count\n"
-                "   --print-vtable\n"
-                "   --traceclassinit\n"
-                "\n"
-                "Development:\n"
-                "   --debug method_name\n"
-                "   --profile\n"
-                "   --trace\n"
-                "   --traceops\n"
-                "   --regression\n"
-                "\n"
-                "Runtime:\n"
-                "   --config filename  load the specified config file instead of the default\n"
-                "   --workers n        maximum number of worker threads\n"
-               );
-       exit (1);
-}
-
-static MonoBoolean
-interp_ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
-                         MonoReflectionMethod **method, 
-                         gint32 *iloffset, gint32 *native_offset,
-                         MonoString **file, gint32 *line, gint32 *column)
-{
-       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
-       MonoInvocation *inv = context->current_frame;
-       MonoError error;
-       int i;
-
-       for (i = 0; inv && i < skip; inv = inv->parent)
-               if (inv->runtime_method != NULL)
-                       ++i;
-
-       if (iloffset)
-               *iloffset = 0;
-       if (native_offset)
-               *native_offset = 0;
-       if (method) {
-               if (inv == NULL) {
-                       *method = NULL;
-               } else {
-                       *method = mono_method_get_object_checked (context->domain, inv->runtime_method->method, NULL, &error);
-                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-               }
-       }
-       if (line)
-               *line = 0;
-       if (need_file_info) {
-               if (column)
-                       *column = 0;
-               if (file)
-                       *file = mono_string_new (mono_domain_get (), "unknown");
-       }
-
-       return TRUE;
-}
-
-static MonoArray *
-interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
+void
+mono_interp_parse_options (const char *options)
 {
-       MonoDomain *domain = mono_domain_get ();
-       MonoArray *res;
-       MonoArray *ta = exc->trace_ips;
-       MonoError error;
-       int i, len;
-
-       if (ta == NULL) {
-               /* Exception is not thrown yet */
-               MonoArray *array = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, &error);
-               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-               return array;
-       }
-       
-       len = mono_array_length (ta);
-
-       res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error);
-       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+       char **args, **ptr;
 
-       for (i = skip; i < len / 2; i++) {
-               MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
-               mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-               gushort *ip = mono_array_get (ta, gpointer, 2 * i + 1);
-               RuntimeMethod *rtm = mono_array_get (ta, gpointer, 2 * i);
-
-               if (rtm != NULL) {
-                       sf->method = mono_method_get_object_checked (domain, rtm->method, NULL, &error);
-                       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-                       sf->native_offset = ip - rtm->code;
-               }
-
-#if 0
-               sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
-
-               if (need_file_info) {
-                       gchar *filename;
-                       
-                       filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
+       args = g_strsplit (options, ",", -1);
+       for (ptr = args; ptr && *ptr; ptr ++) {
+               char *arg = *ptr;
 
-                       sf->filename = filename? mono_string_new (domain, filename): NULL;
-                       sf->column = 0;
-
-                       g_free (filename);
-               }
-#endif
-
-               mono_array_set (res, gpointer, i, sf);
+               if (strncmp (arg, "jit=", 4) == 0)
+                       jit_classes = g_slist_prepend (jit_classes, arg + 4);
        }
-
-       return res;
 }
 
 void
 mono_interp_init ()
 {
        mono_native_tls_alloc (&thread_context_id, NULL);
-    mono_native_tls_set_value (thread_context_id, NULL);
-       mono_os_mutex_init_recursive (&create_method_pointer_mutex);
+       set_context (NULL);
 
        mono_interp_transform_init ();
 }
@@ -4537,6 +5354,7 @@ interp_regression_step (MonoImage *image, int verbose, int *total_run, int *tota
        *total += failed + cfailed;
        *total_run += run;
 }
+
 static int
 interp_regression (MonoImage *image, int verbose, int *total_run)
 {
@@ -4589,3 +5407,176 @@ 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 (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
+{
+       ThreadContext *context;
+
+       g_assert (jit_tls);
+       context = jit_tls->interp_context;
+       g_assert (context);
+
+       context->has_resume_state = TRUE;
+       context->handler_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)
+{
+       InterpFrame *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 {
+       InterpFrame *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 = (InterpFrame*)interp_exit_data;
+}
+
+gboolean
+mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
+{
+       StackIter *stack_iter = (StackIter*)iter;
+       InterpFrame *iframe = stack_iter->current;
+
+       memset (frame, 0, sizeof (StackFrameInfo));
+       /* pinvoke frames doesn't have imethod set */
+       while (iframe && !(iframe->imethod && iframe->imethod->code))
+               iframe = iframe->parent;
+       if (!iframe)
+               return FALSE;
+
+       frame->type = FRAME_TYPE_INTERP;
+       // FIXME:
+       frame->domain = mono_domain_get ();
+       frame->interp_frame = iframe;
+       frame->method = iframe->imethod->method;
+       frame->actual_method = frame->method;
+       /* This is the offset in the interpreter IR */
+       frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
+       frame->ji = iframe->imethod->jinfo;
+
+       stack_iter->current = iframe->parent;
+
+       return TRUE;
+}
+
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
+{
+       InterpMethod* rtm;
+
+       rtm = lookup_imethod (domain, method);
+       if (rtm)
+               return rtm->jinfo;
+       else
+               return NULL;
+}
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+       guint16 *code = (guint16*)ip;
+       g_assert (*code == MINT_SDB_SEQ_POINT);
+       *code = MINT_SDB_BREAKPOINT;
+}
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+       guint16 *code = (guint16*)ip;
+       g_assert (*code == MINT_SDB_BREAKPOINT);
+       *code = MINT_SDB_SEQ_POINT;
+}
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
+{
+       InterpFrame *iframe = (InterpFrame*)frame;
+
+       g_assert (iframe->imethod);
+       return iframe->imethod->jinfo;
+}
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
+{
+       InterpFrame *iframe = (InterpFrame*)frame;
+
+       g_assert (iframe->imethod);
+       return (gpointer)iframe->ip;
+}
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
+{
+       InterpFrame *iframe = (InterpFrame*)frame;
+
+       g_assert (iframe->imethod);
+
+       int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)];
+
+       return iframe->args + arg_offset;
+}
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
+{
+       InterpFrame *iframe = (InterpFrame*)frame;
+
+       g_assert (iframe->imethod);
+
+       return iframe->locals + iframe->imethod->local_offsets [pos];
+}
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame)
+{
+       InterpFrame *iframe = (InterpFrame*)frame;
+
+       g_assert (iframe->imethod);
+       g_assert (iframe->imethod->hasthis);
+
+       int arg_offset = iframe->imethod->arg_offsets [0];
+
+       return iframe->args + arg_offset;
+}
+
+void
+mono_interp_start_single_stepping (void)
+{
+       ss_enabled = TRUE;
+}
+
+void
+mono_interp_stop_single_stepping (void)
+{
+       ss_enabled = FALSE;
+}