[interp] resolve right class for valuetype
[mono.git] / mono / mini / interp / interp.c
index 4d70808a41e5d641b24d0ab93610f97a661ab91c..c9f5c59d45c2cec441c449dce72a636c309dd681 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/**
+ * \file
  * PLEASE NOTE: This is a research prototype.
  *
  *
@@ -36,7 +37,7 @@
 
 /* trim excessive headers */
 #include <mono/metadata/image.h>
-#include <mono/metadata/assembly.h>
+#include <mono/metadata/assembly-internals.h>
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/tabledefs.h>
 #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 (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *rmethod, stackval *method_args, stackval *method_retval)
+{
+       frame->parent = parent_frame;
+       frame->stack_args = method_args;
+       frame->retval = method_retval;
+       frame->runtime_method = 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 { \
+       RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error));    \
+       init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
        } while (0)
 
+/*
+ * List of classes whose methods will be executed by transitioning to JITted code.
+ * Used for testing.
+ */
+GSList *jit_classes;
+
 void ves_exec_method (MonoInvocation *frame);
 
 static char* dump_stack (stackval *stack, stackval *sp);
@@ -253,26 +266,38 @@ ves_real_abort (int line, MonoMethod *mh,
                THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
        } while (0);
 
-static mono_mutex_t runtime_method_lookup_section;
-
 RuntimeMethod*
 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
 {
        RuntimeMethod *rtm;
+       MonoJitDomainInfo *info;
+       MonoMethodSignature *sig;
+       int i;
+
        error_init (error);
 
-       mono_os_mutex_lock (&runtime_method_lookup_section);
-       if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) {
-               mono_os_mutex_unlock (&runtime_method_lookup_section);
+       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);
+       if (rtm)
                return rtm;
-       }
-       rtm = mono_mempool_alloc (domain->mp, sizeof (RuntimeMethod));
-       memset (rtm, 0, sizeof (*rtm));
+
+       sig = mono_method_signature (method);
+
+       rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
        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);
-       mono_os_mutex_unlock (&runtime_method_lookup_section);
+       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);
 
        return rtm;
 }
@@ -328,6 +353,11 @@ get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObjec
                virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        }
+
+       if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+               virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
+       }
+
        RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        return virtual_runtime_method;
@@ -482,9 +512,13 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
        case MONO_TYPE_SZARRAY:
        case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
-       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_ARRAY: {
+               gpointer *p = (gpointer *) data;
+               mono_gc_wbarrier_generic_store (p, val->data.p);
+               return;
+       }
        case MONO_TYPE_PTR: {
-               gpointer *p = (gpointer*)data;
+               gpointer *p = (gpointer *) data;
                *p = val->data.p;
                return;
        }
@@ -495,9 +529,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 ();
@@ -694,8 +735,6 @@ interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUn
                        return;
                frame = frame->parent;
        }
-
-       g_assert (0);
 }
 
 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
@@ -758,7 +797,7 @@ 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 > 12)
                g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
 
        if (margs->flen > 3)
@@ -796,13 +835,19 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
                case MONO_TYPE_GENERICINST:
                        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);
+                       g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
 #endif
                        int_i++;
                        break;
                case MONO_TYPE_R4:
                case MONO_TYPE_R8:
-                       margs->fargs [int_f] = frame->stack_args [i].data.f;
+                       if (ptype == MONO_TYPE_R4)
+                               * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
+                       else
+                               margs->fargs [int_f] = frame->stack_args [i].data.f;
+#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
                        int_f++;
                        break;
                default:
@@ -912,8 +957,10 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
 void
 mono_interp_init_delegate (MonoDelegate *del)
 {
-       if (!del->method)
-               del->method = ((RuntimeMethod *) del->method_ptr)->method;
+       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;
 }
 
 /*
@@ -932,6 +979,15 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
 
        mono_class_init (method->klass);
 
+       if (method->klass == mono_defaults.array_class) {
+               if (!strcmp (method->name, "UnsafeMov")) {
+                       /* TODO: layout checks */
+                       MonoType *mt = mono_method_signature (method)->ret;
+                       stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
+                       return;
+               }
+       }
+
        isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        if (obj && isinst_obj) {
@@ -1222,6 +1278,8 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
        jmp_buf env;
 
        error_init (error);
+       if (exc)
+               *exc = NULL;
 
        frame.ex = NULL;
 
@@ -1264,13 +1322,32 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
                break;
        case MONO_TYPE_VALUETYPE:
                retval = mono_object_new_checked (context->domain, klass, error);
-               ret = ((char*)retval) + sizeof (MonoObject);
+               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;
+               }
+               break;
+
+       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 = ((char*)retval) + sizeof (MonoObject);
+               ret = mono_object_unbox (retval);
                break;
        }
 
@@ -1312,6 +1389,12 @@ handle_enum:
                case MONO_TYPE_I8:
                        args [a_index].data.l = *(gint64*)params [i];
                        break;
+               case MONO_TYPE_R4:
+                       args [a_index].data.f = *(gfloat *) params [i];
+                       break;
+               case MONO_TYPE_R8:
+                       args [a_index].data.f = *(gdouble *) 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;
@@ -1321,10 +1404,12 @@ handle_enum:
                        }
                        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 = params [i];
                        break;
                default:
@@ -1364,6 +1449,209 @@ handle_enum:
        return retval;
 }
 
+typedef struct {
+       RuntimeMethod *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)
+{
+       MonoInvocation frame;
+       RuntimeMethod *rmethod = data->rmethod;
+       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+       ThreadContext context_struct;
+       MonoInvocation *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;
+               mono_native_tls_set_value (thread_context_id, context);
+       }
+       else
+               old_frame = context->current_frame;
+       context->domain = mono_domain_get ();
+
+       args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
+       if (sig->hasthis)
+               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 ? 1 : 0);
+               if (sig->params [i]->byref) {
+                       args [a_index].data.p = params [i];
+                       continue;
+               }
+               type = rmethod->param_types [i];
+               switch (type->type) {
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I1:
+                       args [a_index].data.i = *(MonoBoolean*)params [i];
+                       break;
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I2:
+                       args [a_index].data.i = *(gint16*)params [i];
+                       break;
+               case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+                       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;
+               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_PTR:
+               case MONO_TYPE_OBJECT:
+                       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:
+                       printf ("%s\n", mono_type_full_name (sig->params [i]));
+                       NOT_IMPLEMENTED;
+                       break;
+               }
+       }
+
+       init_frame (&frame, context->current_frame, data->rmethod, args, &result);
+       context->managed_code = 1;
+
+       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);
+       context->managed_code = 0;
+       if (context == &context_struct)
+               mono_native_tls_set_value (thread_context_id, NULL);
+       else
+               context->current_frame = old_frame;
+
+       // 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 */
+               }
+               break;
+       case MONO_TYPE_VALUETYPE:
+               /* Already set before the call */
+               break;
+       default:
+               printf ("%s\n", mono_type_full_name (sig->ret));
+               NOT_IMPLEMENTED;
+               break;
+       }
+}
+
 static stackval * 
 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
 {
@@ -1453,76 +1741,224 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
        return sp;
 }
 
-static mono_mutex_t create_method_pointer_mutex;
+/*
+ * 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.
+ */
 
-static GHashTable *method_pointer_hash = NULL;
+#define MAX_INTERP_ENTRY_ARGS 8
 
-static MonoMethod *method_pointers [2] = {0};
+#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;
 
-static MonoObject *
-mp_tramp_0 (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 [0], NULL, params_real, NULL, &error);
-       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-       return ret;
-}
+#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 MonoObject *
-mp_tramp_1 (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 [1], NULL, params_real, NULL, &error);
-       mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-       return ret;
+#define ARGLIST0 RuntimeMethod *rmethod
+#define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
+#define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
+#define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
+#define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
+#define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
+#define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
+#define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
+#define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *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);
 }
 
-gpointer *mp_tramps[] = {(gpointer) mp_tramp_0, (gpointer) mp_tramp_1};
-
-static int tramps_used = 0;
-
+/*
+ * 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;
+       MonoMethodSignature *sig = mono_method_signature (method);
+       MonoMethod *wrapper;
+       RuntimeMethod *rmethod;
 
-       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;
+       if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
+               return NULL;
+
+       /* HACK: method_ptr of delegate should point to a runtime method*/
+       if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+               return mono_interp_get_runtime_method (mono_domain_get (), method, error);
+
+       rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
+       if (rmethod->jit_entry)
+               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 < 2);
-
-               /* 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);
+       // FIXME: AOT
+       g_assert (!mono_aot_only);
+       addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
+
+       mono_memory_barrier ();
+       rmethod->jit_entry = addr;
 
        return addr;
 }
@@ -1576,23 +2012,16 @@ static int opcode_counts[512];
 #define MINT_IN_DEFAULT default:
 #endif
 
-/* 
- * Defining this causes register allocation errors in some versions of gcc:
- * error: unable to find a register to spill in class `SIREG'
- */
-/* #define MINT_USE_DEDICATED_IP_REG */
+static void
+ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
 
 static void 
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
+ves_exec_method_with_context_with_ip (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception)
 {
        MonoInvocation child_frame;
        GSList *finally_ips = NULL;
        const unsigned short *endfinally_ip = NULL;
-#if defined(__GNUC__) && defined (i386) && defined (MINT_USE_DEDICATED_IP_REG)
-       register const unsigned short *ip asm ("%esi");
-#else
-       register const unsigned short *ip;
-#endif
+       const unsigned short *ip = NULL;
        register stackval *sp;
        RuntimeMethod *rtm;
 #if DEBUG_INTERP
@@ -1639,25 +2068,26 @@ 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);
+       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);
-
        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, 
@@ -1921,6 +2351,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        }
+
                        ves_exec_method_with_context (&child_frame, context);
 
                        context->current_frame = frame;
@@ -1974,6 +2405,215 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        }
                        MINT_IN_BREAK;
                }
+
+               MINT_IN_CASE(MINT_JIT_CALL) {
+                       MonoMethodSignature *sig;
+                       RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
+                       MonoFtnDesc ftndesc;
+                       guint8 res_buf [256];
+                       MonoType *type;
+
+                       //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);
+
+                               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));
+
+                               gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
+                               mono_error_assert_ok (&error);
+
+                               gpointer addr = mono_jit_compile_method_jit_only (method, &error);
+                               g_assert (addr);
+                               mono_error_assert_ok (&error);
+
+                               rmethod->jit_addr = addr;
+                               rmethod->jit_sig = sig;
+                               mono_memory_barrier ();
+                               rmethod->jit_wrapper = jit_wrapper;
+
+                       } else {
+                               sig = rmethod->jit_sig;
+                       }
+
+                       frame->ip = ip;
+                       ip += 2;
+                       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 ();
+                                       }
+                               }
+                       }
+
+                       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;
+                       }
+
+                       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;
+                       }
+                       if (rtype->type != MONO_TYPE_VOID)
+                               sp++;
+                       MINT_IN_BREAK;
+               }
+
                MINT_IN_CASE(MINT_CALLVIRT) {
                        stackval *endsp = sp;
                        MonoObject *this_arg;
@@ -2424,7 +3064,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                MINT_IN_CASE(MINT_STIND_REF) 
                        ++ip;
                        sp -= 2;
-                       * (gpointer *) sp->data.p = sp[1].data.p;
+                       mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_STIND_I1)
                        ++ip;
@@ -2740,6 +3380,8 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                MINT_IN_CASE(MINT_CPOBJ) {
                        c = rtm->data_items[* (guint16 *)(ip + 1)];
                        g_assert (c->byval_arg.type == MONO_TYPE_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);
                        ip += 2;
                        sp -= 2;
@@ -3020,8 +3662,15 @@ array_constructed:
                MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
-               MINT_IN_CASE(MINT_STFLD_O) STFLD(p, gpointer); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STFLD_O)
+                       o = sp [-2].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       sp -= 2;
+                       mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
+                       ip += 2;
+                       MINT_IN_BREAK;
 
                MINT_IN_CASE(MINT_STFLD_VT)
                        o = sp [-2].data.p;
@@ -3132,11 +3781,14 @@ array_constructed:
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_STOBJ) {
-                       int size;
                        c = rtm->data_items[* (guint16 *)(ip + 1)];
                        ip += 2;
-                       size = mono_class_value_size (c, NULL);
-                       memcpy(sp [-2].data.p, &sp [-1].data, size);
+
+                       g_assert (!c->byval_arg.byref);
+                       if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
+                               mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
+                       else
+                               stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
                        sp -= 2;
                        MINT_IN_BREAK;
                }
@@ -3235,7 +3887,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;
@@ -3345,6 +4000,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 */
@@ -3376,6 +4032,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;
@@ -3393,7 +4052,7 @@ array_constructed:
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                                if (sp [2].data.p && !isinst_obj)
                                        THROW_EX (mono_get_exception_array_type_mismatch (), ip);
-                               mono_array_set ((MonoArray *)o, gpointer, aindex, sp [2].data.p);
+                               mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
                                break;
                        }
                        case MINT_STELEM_VT: {
@@ -3604,6 +4263,9 @@ array_constructed:
                        BINOP_CAST(l, -, guint64);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_ENDFINALLY)
+                       while (sp > frame->stack) {
+                               --sp;
+                       }
                        if (finally_ips) {
                                ip = finally_ips->data;
                                finally_ips = g_slist_remove (finally_ips, ip);
@@ -3642,6 +4304,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;
@@ -3774,13 +4443,6 @@ array_constructed:
                        MINT_IN_BREAK;
                }
 
-               MINT_IN_CASE(MINT_LDTHISA)
-                       g_error ("should not happen");
-                       // sp->data.p = &frame->obj;
-                       ++ip;
-                       ++sp; 
-                       MINT_IN_BREAK;
-
 #define LDARG(datamem, argtype) \
        sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
        ip += 2; \
@@ -3937,9 +4599,10 @@ array_constructed:
                        ++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));
@@ -4036,24 +4699,44 @@ array_constructed:
                        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;
 #if DEBUG_INTERP
-                                                       if (tracing)
-                                                               g_print ("* Found handler at '%s'\n", method->name);
+                               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
+                                       MonoInvocation dup_frame;
+                                       stackval retval;
+                                       memcpy (&dup_frame, inv, sizeof (MonoInvocation));
+                                       dup_frame.retval = &retval;
+                                       ves_exec_method_with_context_with_ip (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex);
+                                       if (dup_frame.retval->data.i) {
+#if DEBUG_INTERP
+                                               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;
+                                               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;
+                                               goto handle_finally;
                                        }
                                }
                        }
@@ -4066,9 +4749,11 @@ array_constructed:
                                goto handle_finally;
                }
 die_on_ex:
-               ex_obj = (MonoObject*)frame->ex;
+               ex_obj = (MonoObject *) frame->ex;
                mono_unhandled_exception (ex_obj);
-               exit (1);
+               MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls ();
+               jit_tls->abort_func (ex_obj);
+               g_assert_not_reached ();
        }
        handle_finally:
        {
@@ -4177,6 +4862,12 @@ exit_frame:
        DEBUG_LEAVE ();
 }
 
+static void
+ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
+{
+       ves_exec_method_with_context_with_ip (frame, context, NULL, NULL);
+}
+
 void
 ves_exec_method (MonoInvocation *frame)
 {
@@ -4366,13 +5057,25 @@ interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_fi
        return res;
 }
 
+void
+mono_interp_parse_options (const char *options)
+{
+       char **args, **ptr;
+
+       args = g_strsplit (options, ",", -1);
+       for (ptr = args; ptr && *ptr; ptr ++) {
+               char *arg = *ptr;
+
+               if (strncmp (arg, "jit=", 4) == 0)
+                       jit_classes = g_slist_prepend (jit_classes, arg + 4);
+       }
+}
+
 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 (&runtime_method_lookup_section);
-       mono_os_mutex_init_recursive (&create_method_pointer_mutex);
+       mono_native_tls_set_value (thread_context_id, NULL);
 
        mono_interp_transform_init ();
 }
@@ -4393,16 +5096,6 @@ interp_regression_step (MonoImage *image, int verbose, int *total_run, int *tota
        cfailed = failed = run = 0;
        transform_time = elapsed = 0.0;
 
-#if 0
-       /* fixme: ugly hack - delete all previously compiled methods */
-       if (domain_jit_info (domain)) {
-               g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
-               domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-               mono_internal_hash_table_destroy (&(domain->jit_code_hash));
-               mono_jit_code_hash_init (&(domain->jit_code_hash));
-       }
-#endif
-
        g_timer_start (timer);
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
                MonoObject *exc = NULL;
@@ -4499,6 +5192,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)
 {
@@ -4534,7 +5228,7 @@ mono_interp_regression_list (int verbose, int count, char *images [])
        
        total_run = total = 0;
        for (i = 0; i < count; ++i) {
-               MonoAssembly *ass = mono_assembly_open (images [i], NULL);
+               MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL);
                if (!ass) {
                        g_warning ("failed to load assembly: %s", images [i]);
                        continue;