2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / interpreter / interp.c
index 485196062025b608ccd0414859bf7f8b4f79b2a0..214b1b14f61ad08d12ca0229a858820066865c2e 100644 (file)
@@ -21,6 +21,8 @@
 #include <glib.h>
 #include <setjmp.h>
 #include <signal.h>
+#include <math.h>
+#include <locale.h>
 
 #include <mono/os/gc_wrapper.h>
 
@@ -38,7 +40,6 @@
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/tabledefs.h>
-#include <mono/metadata/blob.h>
 #include <mono/metadata/tokentype.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/threads.h>
 #include <mono/metadata/verify.h>
 #include <mono/metadata/opcodes.h>
 #include <mono/metadata/debug-helpers.h>
-#include <mono/io-layer/io-layer.h>
-#include <mono/metadata/socket-io.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/os/util.h>
 
-/*#include <mono/cli/types.h>*/
 #include "interp.h"
+#include "mintops.h"
+#include "embed.h"
 #include "hacks.h"
 
+#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
+       a = i,
+
+enum {
+#include "mono/cil/opcode.def"
+       CEE_LASTOP
+};
+#undef OPDEF
+
 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
 #ifdef _WIN32
 #define isnan _isnan
 #define finite _finite
 #endif
+#ifndef HAVE_FINITE
+#ifdef HAVE_ISFINITE
+#define finite isfinite
+#endif
+#endif
+
+static gint *abort_requested;
 
 /* If true, then we output the opcodes as we interpret them */
 static int global_tracing = 0;
 static int global_no_pointers = 0;
 
-static int debug_indent_level = 0;
-
-/*
- * Pull the list of opcodes
- */
-#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
-       a = i,
-
-enum {
-#include "mono/cil/opcode.def"
-       LAST = 0xff
-};
-#undef OPDEF
+int mono_interp_traceopt = 0;
 
-#define GET_NATI(sp) ((sp).data.nati)
-#define CSIZE(x) (sizeof (x) / 4)
+static int debug_indent_level = 0;
 
 #define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,mono_method)  \
        do {    \
@@ -95,26 +98,30 @@ enum {
                (frame)->obj = (obj_this);      \
                (frame)->stack_args = (method_args);    \
                (frame)->retval = (method_retval);      \
-               (frame)->method = (mono_method);        \
-               (frame)->ex_handler = NULL;     \
+               (frame)->runtime_method = mono_interp_get_runtime_method (mono_method); \
                (frame)->ex = NULL;     \
-               (frame)->child = NULL;  \
+               (frame)->ip = NULL;     \
                (frame)->invoke_trap = 0;       \
        } while (0)
 
 void ves_exec_method (MonoInvocation *frame);
 
+static char* dump_stack (stackval *stack, stackval *sp);
+static char* dump_frame (MonoInvocation *inv);
+static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
+static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context);
+
 typedef void (*ICallMethod) (MonoInvocation *frame);
 
 static guint32 die_on_exception = 0;
-static guint32 frame_thread_id = 0;
+static guint32 thread_context_id = 0;
 
 #define DEBUG_INTERP 1
+#define COUNT_OPS 0
 #if DEBUG_INTERP
 
-static unsigned long opcode_count = 0;
-static unsigned long fcall_count = 0;
 static int break_on_method = 0;
+static int nested_trace = 0;
 static GList *db_methods = NULL;
 
 static void
@@ -137,46 +144,40 @@ db_match_method (gpointer data, gpointer user_data)
 }
 
 #define DEBUG_ENTER()  \
-       fcall_count++;  \
-       g_list_foreach (db_methods, db_match_method, (gpointer)frame->method);  \
-       if (break_on_method) tracing=2; \
-       break_on_method = 0;    \
+       if (db_methods) { \
+               g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);  \
+               if (break_on_method) tracing=nested_trace ? (global_tracing = 2, 3) : 2;        \
+               break_on_method = 0;    \
+       } \
        if (tracing) {  \
-               char *mn, *args = dump_stack (frame->stack_args, frame->stack_args+signature->param_count);     \
+               MonoMethod *method = frame->runtime_method->method ;\
+               char *mn, *args = dump_args (frame);    \
                debug_indent_level++;   \
                output_indent ();       \
-               mn = mono_method_full_name (frame->method, FALSE); \
-               g_print ("(%d) Entering %s (", GetCurrentThreadId(), mn);       \
+               mn = mono_method_full_name (method, FALSE); \
+               g_print ("(%u) Entering %s (", GetCurrentThreadId(), mn);       \
                g_free (mn); \
-               if (signature->hasthis) { \
-                       if (global_no_pointers) { \
-                               g_print ("this%s ", frame->obj ? "" : "=null"); \
-                       } else { \
-                               g_print ("%p ", frame->obj); } \
-               } \
                g_print ("%s)\n", args);        \
                g_free (args);  \
        }       \
        if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)    \
-               mono_profiler_method_enter (frame->method);
+               mono_profiler_method_enter (frame->runtime_method->method);
 
 #define DEBUG_LEAVE()  \
        if (tracing) {  \
                char *mn, *args;        \
-               if (signature->ret->type != MONO_TYPE_VOID)     \
-                       args = dump_stack (frame->retval, frame->retval + 1);   \
-               else    \
-                       args = g_strdup ("");   \
+               args = dump_retval (frame);     \
                output_indent ();       \
-               mn = mono_method_full_name (frame->method, FALSE); \
-               g_print ("(%d) Leaving %s", GetCurrentThreadId(),  mn); \
+               mn = mono_method_full_name (frame->runtime_method->method, FALSE); \
+               g_print ("(%u) Leaving %s", GetCurrentThreadId(),  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->method);
+               mono_profiler_method_leave (frame->runtime_method->method);
 
 #else
 
@@ -187,62 +188,124 @@ db_match_method (gpointer data, gpointer user_data)
 
 static void
 interp_ex_handler (MonoException *ex) {
-       MonoInvocation *frame = TlsGetValue (frame_thread_id);
-       frame->ex = ex;
-       longjmp (*(jmp_buf*)frame->locals, 1);
+       ThreadContext *context = TlsGetValue (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 (ex->stack_trace);
+               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 (ex->message);
+                       fprintf(stderr, ": %s", m);
+                       g_free(m);
+               }
+               fprintf(stderr, "\n");
+               fprintf(stderr, "%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 (ex->message);
+                               fprintf(stderr, ": %s", m);
+                               g_free(m);
+                       }
+                       strace = mono_string_to_utf8 (ex->stack_trace);
+                       fprintf(stderr, "\n");
+                       fprintf(stderr, "%s\n", strace);
+                       g_free (strace);
+               }
+               /* wait for other threads to also collapse */
+               Sleep(1000);
+               exit(1);
+       }
+       context->env_frame->ex = ex;
+       context->search_for_handler = 1;
+       longjmp (*context->current_env, 1);
 }
 
 static void
 ves_real_abort (int line, MonoMethod *mh,
-               const unsigned char *ip, stackval *stack, stackval *sp)
+               const unsigned short *ip, stackval *stack, stackval *sp)
 {
-       MonoMethodNormal *mm = (MonoMethodNormal *)mh;
        fprintf (stderr, "Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
        fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
-                ip-mm->header->code);
+                ip-(const unsigned short *)mono_method_get_header (mh)->code);
        g_print ("0x%04x %02x\n",
-                ip-mm->header->code, *ip);
+                ip-(const unsigned short *)mono_method_get_header (mh)->code, *ip);
        if (sp > stack)
-               printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
+               printf ("\t[%d] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
 }
-#define ves_abort() do {ves_real_abort(__LINE__, frame->method, ip, frame->stack, sp); THROW_EX (mono_get_exception_execution_engine (NULL), ip);} while (0);
+
+#define ves_abort() \
+       do {\
+               ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \
+               THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
+       } while (0);
 
 static gpointer
-interp_create_remoting_trampoline (MonoMethod *method)
+interp_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
+{
+       return mono_interp_get_runtime_method (mono_marshal_get_remoting_invoke_for_target (method, target));
+}
+
+static CRITICAL_SECTION runtime_method_lookup_section;
+
+RuntimeMethod*
+mono_interp_get_runtime_method (MonoMethod *method)
 {
-       return mono_marshal_get_remoting_invoke (method);
+       MonoDomain *domain = mono_domain_get ();
+       RuntimeMethod *rtm;
+
+       EnterCriticalSection (&runtime_method_lookup_section);
+       if ((rtm = g_hash_table_lookup (domain->jit_code_hash, method))) {
+               LeaveCriticalSection (&runtime_method_lookup_section);
+               return rtm;
+       }
+       rtm = mono_mempool_alloc (domain->mp, sizeof (RuntimeMethod));
+       memset (rtm, 0, sizeof (*rtm));
+       rtm->method = method;
+       rtm->param_count = mono_method_signature (method)->param_count;
+       rtm->hasthis = mono_method_signature (method)->hasthis;
+       rtm->valuetype = method->klass->valuetype;
+       g_hash_table_insert (domain->jit_code_hash, method, rtm);
+       LeaveCriticalSection (&runtime_method_lookup_section);
+
+       return rtm;
 }
 
-static MonoMethod*
-get_virtual_method (MonoDomain *domain, MonoMethod *m, stackval *objs)
+static gpointer
+interp_create_trampoline (MonoMethod *method)
 {
-       MonoObject *obj;
-       MonoClass *klass;
-       MonoMethod **vtable;
-       gboolean is_proxy = FALSE;
-       MonoMethod *res;
+       if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+               method = mono_marshal_get_synchronized_wrapper (method);
+       return mono_interp_get_runtime_method (method);
+}
 
-       if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL))
-                       return m;
+static inline RuntimeMethod*
+get_virtual_method (RuntimeMethod *runtime_method, MonoObject *obj)
+{
+       MonoMethod *m = runtime_method->method;
 
-       obj = objs->data.p;
-       if ((klass = obj->vtable->klass) == mono_defaults.transparent_proxy_class) {
-               klass = ((MonoTransparentProxy *)obj)->klass;
-               is_proxy = TRUE;
+       if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+               if (obj->vtable->klass == mono_defaults.transparent_proxy_class) 
+                       return mono_interp_get_runtime_method (mono_marshal_get_remoting_invoke (m));
+               else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+                       return mono_interp_get_runtime_method (mono_marshal_get_synchronized_wrapper (m));
+               else
+                       return runtime_method;
        }
-       vtable = (MonoMethod **)klass->vtable;
 
        if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               res = *(MonoMethod**)((char*)obj->vtable->interface_offsets [m->klass->interface_id] + (m->slot<<2));
+               return ((RuntimeMethod **)obj->vtable->interface_offsets [m->klass->interface_id]) [m->slot];
        } else {
-               res = vtable [m->slot];
+               return ((RuntimeMethod **)obj->vtable->vtable) [m->slot];
        }
-       g_assert (res);
-
-       if (is_proxy)
-               return mono_marshal_get_remoting_invoke (res);
-       
-       return res;
 }
 
 void inline
@@ -255,62 +318,51 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo
                case MONO_TYPE_STRING:
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
-                       result->type = VAL_OBJ;
                        break;
                default:
-                       result->type = VAL_VALUETA;
                        break;
                }
                result->data.p = *(gpointer*)data;
-               result->data.vt.klass = mono_class_from_mono_type (type);
                return;
        }
        switch (type->type) {
        case MONO_TYPE_VOID:
                return;
        case MONO_TYPE_I1:
-               result->type = VAL_I32;
                result->data.i = *(gint8*)data;
                return;
        case MONO_TYPE_U1:
        case MONO_TYPE_BOOLEAN:
-               result->type = VAL_I32;
                result->data.i = *(guint8*)data;
                return;
        case MONO_TYPE_I2:
-               result->type = VAL_I32;
                result->data.i = *(gint16*)data;
                return;
        case MONO_TYPE_U2:
        case MONO_TYPE_CHAR:
-               result->type = VAL_I32;
                result->data.i = *(guint16*)data;
                return;
        case MONO_TYPE_I4:
-               result->type = VAL_I32;
                result->data.i = *(gint32*)data;
                return;
        case MONO_TYPE_U:
        case MONO_TYPE_I:
+               result->data.nati = *(mono_i*)data;
+               return;
        case MONO_TYPE_PTR:
-               result->type = VAL_TP;
                result->data.p = *(gpointer*)data;
                return;
        case MONO_TYPE_U4:
-               result->type = VAL_I32;
                result->data.i = *(guint32*)data;
                return;
        case MONO_TYPE_R4:
-               result->type = VAL_DOUBLE;
                result->data.f = *(float*)data;
                return;
        case MONO_TYPE_I8:
        case MONO_TYPE_U8:
-               result->type = VAL_I64;
                result->data.l = *(gint64*)data;
                return;
        case MONO_TYPE_R8:
-               result->type = VAL_DOUBLE;
                result->data.f = *(double*)data;
                return;
        case MONO_TYPE_STRING:
@@ -318,23 +370,20 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo
        case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
        case MONO_TYPE_ARRAY:
-               result->type = VAL_OBJ;
                result->data.p = *(gpointer*)data;
-               result->data.vt.klass = mono_class_from_mono_type (type);
                return;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       return stackval_from_data (type->data.klass->enum_basetype, result, data, pinvoke);
+                       stackval_from_data (type->data.klass->enum_basetype, result, data, pinvoke);
+                       return;
                } else {
                        int size;
-                       result->type = VAL_VALUET;
-                       result->data.vt.klass = type->data.klass;
                        
                        if (pinvoke)
                                size = mono_class_native_size (type->data.klass, NULL);
                        else
                                size = mono_class_value_size (type->data.klass, NULL);
-                       memcpy (result->data.vt.vt, data, size);
+                       memcpy (result->data.vt, data, size);
                }
                return;
        default:
@@ -351,7 +400,7 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
                *p = val->data.p;
                return;
        }
-       //printf ("TODAT0 %p\n", data);
+       /* printf ("TODAT0 %p\n", data); */
        switch (type->type) {
        case MONO_TYPE_I1:
        case MONO_TYPE_U1: {
@@ -371,20 +420,27 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
                *p = val->data.i;
                return;
        }
-#if SIZEOF_VOID_P == 4
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-#endif
+       case MONO_TYPE_I: {
+               mono_i *p = (mono_i*)data;
+               /* In theory the value used by stloc should match the local var type
+                  but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
+                  a native int - both by csc and mcs). Not sure what to do about sign extension
+                  as it is outside the spec... doing the obvious */
+               *p = (mono_i)val->data.nati;
+               return;
+       }
+       case MONO_TYPE_U: {
+               mono_u *p = (mono_u*)data;
+               /* see above. */
+               *p = (mono_u)val->data.nati;
+               return;
+       }
        case MONO_TYPE_I4:
        case MONO_TYPE_U4: {
                gint32 *p = (gint32*)data;
                *p = val->data.i;
                return;
        }
-#if SIZEOF_VOID_P == 8
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-#endif
        case MONO_TYPE_I8:
        case MONO_TYPE_U8: {
                gint64 *p = (gint64*)data;
@@ -413,7 +469,8 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
        }
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       return stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
+                       stackval_to_data (type->data.klass->enum_basetype, val, data, pinvoke);
+                       return;
                } else {
                        int size;
 
@@ -422,7 +479,7 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
                        else
                                size = mono_class_value_size (type->data.klass, NULL);
 
-                       memcpy (data, val->data.vt.vt, size);
+                       memcpy (data, val->data.p, size);
                }
                return;
        default:
@@ -431,6 +488,26 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
        }
 }
 
+static void
+fill_in_trace (MonoException *exception, MonoInvocation *frame)
+{
+       char *stack_trace = dump_frame (frame);
+       MonoDomain *domain = mono_domain_get();
+       (exception)->stack_trace = mono_string_new (domain, stack_trace);
+       (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)      \
+       do {\
+               frame->ip = (ex_ip);            \
+               frame->ex = (MonoException*)(exception);        \
+               FILL_IN_TRACE(frame->ex, frame); \
+               goto handle_exception;  \
+       } while (0)
+
 static MonoObject*
 ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
 {
@@ -477,18 +554,31 @@ ves_array_set (MonoInvocation *frame)
                for (i = 1; i < ac->rank; i++) {
                        if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
                            ao->bounds [i].length) {
-                               g_warning ("wrong array index");
-                               g_assert_not_reached ();
+                               frame->ex = mono_get_exception_index_out_of_range ();
+                               FILL_IN_TRACE(frame->ex, frame);
+                               return;
                        }
                        pos = pos*ao->bounds [i].length + sp [i].data.i - 
                                ao->bounds [i].lower_bound;
                }
+       } else if (pos >= ao->max_length) {
+               frame->ex = mono_get_exception_index_out_of_range ();
+               FILL_IN_TRACE(frame->ex, frame);
+               return;
+       }
+
+#if 0 /* FIX */
+       if (sp [ac->rank].data.p && !mono_object_isinst (sp [ac->rank].data.p, mono_object_class (o)->element_class)) {
+               frame->ex = mono_get_exception_array_type_mismatch ();
+               FILL_IN_TRACE (frame->ex, frame);
+               return;
        }
+#endif
 
        esize = mono_array_element_size (ac);
        ea = mono_array_addr_with_size (ao, esize, pos);
 
-       mt = frame->method->signature->params [ac->rank];
+       mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
        stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
 }
 
@@ -499,7 +589,7 @@ ves_array_get (MonoInvocation *frame)
        MonoObject *o;
        MonoArray *ao;
        MonoClass *ac;
-       gint32 i, pos, esize;
+       gint32 i, t, pos, esize;
        gpointer ea;
        MonoType *mt;
 
@@ -512,15 +602,27 @@ ves_array_get (MonoInvocation *frame)
        pos = sp [0].data.i;
        if (ao->bounds != NULL) {
                pos -= ao->bounds [0].lower_bound;
-               for (i = 1; i < ac->rank; i++)
+               for (i = 1; i < ac->rank; i++) {
+                       if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
+                           ao->bounds [i].length) {
+                               frame->ex = mono_get_exception_index_out_of_range ();
+                               FILL_IN_TRACE(frame->ex, frame);
+                               return;
+                       }
+
                        pos = pos*ao->bounds [i].length + sp [i].data.i - 
                                ao->bounds [i].lower_bound;
+               }
+       } else if (pos >= ao->max_length) {
+               frame->ex = mono_get_exception_index_out_of_range ();
+               FILL_IN_TRACE(frame->ex, frame);
+               return;
        }
 
        esize = mono_array_element_size (ac);
        ea = mono_array_addr_with_size (ao, esize, pos);
 
-       mt = frame->method->signature->ret;
+       mt = mono_method_signature (frame->runtime_method->method)->ret;
        stackval_from_data (mt, frame->retval, ea, FALSE);
 }
 
@@ -531,7 +633,7 @@ ves_array_element_address (MonoInvocation *frame)
        MonoObject *o;
        MonoArray *ao;
        MonoClass *ac;
-       gint32 i, pos, esize;
+       gint32 i, t, pos, esize;
        gpointer ea;
 
        o = frame->obj;
@@ -543,82 +645,141 @@ ves_array_element_address (MonoInvocation *frame)
        pos = sp [0].data.i;
        if (ao->bounds != NULL) {
                pos -= ao->bounds [0].lower_bound;
-               for (i = 1; i < ac->rank; i++)
+               for (i = 1; i < ac->rank; i++) {
+                       if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
+                           ao->bounds [i].length) {
+                               frame->ex = mono_get_exception_index_out_of_range ();
+                               FILL_IN_TRACE(frame->ex, frame);
+                               return;
+                       }
                        pos = pos*ao->bounds [i].length + sp [i].data.i - 
                                ao->bounds [i].lower_bound;
+               }
+       } else if (pos >= ao->max_length) {
+               frame->ex = mono_get_exception_index_out_of_range ();
+               FILL_IN_TRACE(frame->ex, frame);
+               return;
        }
 
        esize = mono_array_element_size (ac);
        ea = mono_array_addr_with_size (ao, esize, pos);
 
-       frame->retval->type = VAL_TP;
        frame->retval->data.p = ea;
 }
 
 static void
-interp_walk_stack (MonoStackWalk func, gpointer user_data)
+interp_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data)
 {
-       MonoInvocation *frame = TlsGetValue (frame_thread_id);
+       ThreadContext *context = TlsGetValue (thread_context_id);
+       MonoInvocation *frame;
        int il_offset;
        MonoMethodHeader *hd;
 
+       if (!context) return;
+               
+       frame = context->current_frame;
+
        while (frame) {
                gboolean managed = FALSE;
-               if (!frame->method || (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || 
-                               (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
+               MonoMethod *method = frame->runtime_method->method;
+               if (!method || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || 
+                               (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
                        il_offset = -1;
                else {
-                       hd = ((MonoMethodNormal*)frame->method)->header;
-                       il_offset = frame->ip - hd->code;
-                       if (!frame->method->wrapper_type)
+                       hd = mono_method_get_header (method);
+                       il_offset = frame->ip - (const unsigned short *)hd->code;
+                       if (!method->wrapper_type)
                                managed = TRUE;
                }
-               if (func (frame->method, -1, il_offset, managed, user_data))
+               if (func (method, -1, il_offset, managed, user_data))
                        return;
                frame = frame->parent;
        }
 }
 
 static void 
-ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor)
+ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc addr, gboolean string_ctor, ThreadContext *context)
 {
        jmp_buf env;
        MonoPIFunc func;
+       MonoInvocation *old_frame = context->current_frame;
+       MonoInvocation *old_env_frame = context->env_frame;
+       jmp_buf *old_env = context->current_env;
 
        if (setjmp (env)) {
-               TlsSetValue (frame_thread_id, frame->args);
+               context->current_frame = old_frame;
+               context->env_frame = old_env_frame;
+               context->current_env = old_env;
+               context->managed_code = 1;
                return;
        }
 
-       if (frame->method) {
-               if (!frame->method->info) {
-                       func = frame->method->info = mono_create_trampoline (sig, string_ctor);
-               } else { 
-                       func = (MonoPIFunc)frame->method->info;
-               }
+       frame->ex = NULL;
+       context->env_frame = frame;
+       context->current_env = &env;
+
+       if (frame->runtime_method) {
+               func = frame->runtime_method->func;
        } else {
-               func = mono_create_trampoline (sig, string_ctor);
+               func = mono_arch_create_trampoline (sig, string_ctor);
        }
 
-       /* 
-        * frame->locals and args are unused for P/Invoke methods, so we reuse them. 
-        * locals will point to the jmp_buf, while args will point to the previous
-        * MonoInvocation frame: this is needed to make exception searching work across
-        * managed/unmanaged boundaries.
-        */
-       frame->locals = (char*)&env;
-       frame->args = (char*)TlsGetValue (frame_thread_id);
-       TlsSetValue (frame_thread_id, frame);
+       context->current_frame = frame;
+       context->managed_code = 0;
 
        func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
 
+       context->managed_code = 1;
+       /* domain can only be changed by native code */
+       context->domain = mono_domain_get ();
+
+       if (*abort_requested)
+               mono_thread_interruption_checkpoint ();
+       
        if (string_ctor) {
                stackval_from_data (&mono_defaults.string_class->byval_arg, 
                                    frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
        } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
                stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
 
-       TlsSetValue (frame_thread_id, frame->args);
+       context->current_frame = old_frame;
+       context->env_frame = old_env_frame;
+       context->current_env = old_env;
+}
+
+static void
+interp_delegate_ctor (MonoDomain *domain, MonoObject *this, MonoObject *target, RuntimeMethod *runtime_method)
+{
+       MonoDelegate *delegate = (MonoDelegate *)this;
+
+       delegate->method_info = mono_method_get_object (domain, runtime_method->method, NULL);
+       delegate->target = target;
+
+       if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
+               MonoMethod *method = mono_marshal_get_remoting_invoke (runtime_method->method);
+               delegate->method_ptr = mono_interp_get_runtime_method (method);
+       } else {
+               delegate->method_ptr = runtime_method;
+       }
+}
+
+MonoDelegate*
+mono_interp_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
+{
+       MonoDelegate *d;
+       MonoJitInfo *ji;
+       MonoDomain *domain = mono_domain_get ();
+
+       d = (MonoDelegate*)mono_object_new (domain, klass);
+
+       ji = mono_jit_info_table_find (domain, ftn);
+       if (ji == NULL)
+               mono_raise_exception (mono_get_exception_argument ("", "Function pointer was not created by a Delegate."));
+
+       /* FIXME: discard the wrapper and call the original method */
+       interp_delegate_ctor (domain, (MonoObject*)d, NULL, mono_interp_get_runtime_method (ji->method));
+
+       return d;
 }
 
 /*
@@ -627,57 +788,17 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFunc ad
  * provided by the runtime and is primarily used for the methods of delegates.
  */
 static void
-ves_runtime_method (MonoInvocation *frame)
+ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
 {
-       const char *name = frame->method->name;
+       MonoMethod *method = frame->runtime_method->method;
+       const char *name = method->name;
        MonoObject *obj = (MonoObject*)frame->obj;
-       MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)frame->obj;
-       MonoInvocation call;
-       MonoMethod *nm;
 
-
-       mono_class_init (frame->method->klass);
+       mono_class_init (method->klass);
        
        if (obj && mono_object_isinst (obj, mono_defaults.multicastdelegate_class)) {
                if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
-                       mono_delegate_ctor (obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
-                       return;
-               }
-               if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
-                       guchar *code;
-                       MonoJitInfo *ji;
-                       MonoMethod *method;
-               
-                       while (delegate) {
-
-                               code = (guchar*)delegate->delegate.method_ptr;
-                               if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
-                                       method = ji->method;
-                                       INIT_FRAME(&call,frame,delegate->delegate.target,frame->stack_args,frame->retval,method);
-                                       ves_exec_method (&call);
-                                       frame->ex = call.ex;
-                                       if (frame->ex)
-                                               return;
-                               } else {
-                                       g_assert_not_reached ();
-                               }
-
-                               delegate = delegate->prev;
-                       }
-                       return;
-               }
-               if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
-                       nm = mono_marshal_get_delegate_begin_invoke (frame->method);
-                       INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
-                       ves_exec_method (&call);
-                       frame->ex = call.ex;
-                       return;
-               }
-               if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
-                       nm = mono_marshal_get_delegate_end_invoke (frame->method);
-                       INIT_FRAME(&call,frame,obj,frame->stack_args,frame->retval,nm);
-                       ves_exec_method (&call);
-                       frame->ex = call.ex;
+                       interp_delegate_ctor (context->domain, obj, frame->stack_args[0].data.p, frame->stack_args[1].data.p);
                        return;
                }
        }
@@ -698,8 +819,8 @@ ves_runtime_method (MonoInvocation *frame)
        }
        
        g_error ("Don't know how to exec runtime method %s.%s::%s", 
-                       frame->method->klass->name_space, frame->method->klass->name,
-                       frame->method->name);
+                       method->klass->name_space, method->klass->name,
+                       method->name);
 }
 
 static char*
@@ -712,367 +833,158 @@ dump_stack (stackval *stack, stackval *sp)
                return g_string_free (str, FALSE);
        
        while (s < sp) {
-               switch (s->type) {
-               case VAL_I32: g_string_sprintfa (str, "[%d] ", s->data.i); break;
-               case VAL_I64: g_string_sprintfa (str, "[%lld] ", s->data.l); break;
-               case VAL_DOUBLE: g_string_sprintfa (str, "[%0.5f] ", s->data.f); break;
-               case VAL_VALUET:
-                       if (!global_no_pointers)
-                               g_string_sprintfa (str, "[vt: %p] ", s->data.vt.vt);
-                       else
-                               g_string_sprintfa (str, "[vt%s] ", s->data.vt.vt ? "" : "=null");
-                       break;
-               case VAL_OBJ: {
-                       MonoObject *obj =  s->data.p;
-                       if (global_no_pointers && obj && obj->vtable) {
-                               MonoClass *klass = mono_object_class (obj);
-                               if (klass == mono_defaults.string_class) {
-                                       char *utf8 = mono_string_to_utf8 ((MonoString*) obj);
-                                       g_string_sprintfa (str, "[str:%s] ", utf8);
-                                       g_free (utf8);
-                                       break;
-                               } else if (klass == mono_defaults.sbyte_class) {
-                                       g_string_sprintfa (str, "[b:%d] ",
-                                                          *(gint8 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.int16_class) {
-                                       g_string_sprintfa (str, "[b:%d] ",
-                                                          *(gint16 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.int32_class) {
-                                       g_string_sprintfa (str, "[b:%d] ",
-                                                          *(gint32 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.byte_class) {
-                                       g_string_sprintfa (str, "[b:%u] ",
-                                                          *(guint8 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.char_class
-                                          || klass == mono_defaults.uint16_class) {
-                                       g_string_sprintfa (str, "[b:%u] ",
-                                                          *(guint16 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.uint32_class) {
-                                       g_string_sprintfa (str, "[b:%u] ",
-                                                          *(guint32 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.int64_class) {
-                                       g_string_sprintfa (str, "[b:%lld] ",
-                                                          *(gint64 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.uint64_class) {
-                                       g_string_sprintfa (str, "[b:%llu] ",
-                                                          *(guint64 *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.double_class) {
-                                       g_string_sprintfa (str, "[b:%0.5f] ",
-                                                          *(gdouble *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.single_class) {
-                                       g_string_sprintfa (str, "[b:%0.5f] ",
-                                                          *(gfloat *)((guint8 *) obj + sizeof (MonoObject)));
-                                       break;
-                               } else if (klass == mono_defaults.boolean_class) {
-                                       g_string_sprintfa (str, "[b:%s] ",
-                                                          *(gboolean *)((guint8 *) obj + sizeof (MonoObject))
-                                                          ? "true" : "false");
-                                       break;
-                               }
-                       }
-                       /* fall thru */
-               }
-               default:
-                       if (!global_no_pointers)
-                               g_string_sprintfa (str, "[%p] ", s->data.p);
-                       else
-                               g_string_sprintfa (str, s->data.p ? "[ptr] " : "[null] ");
-                       break;
-               }
+               g_string_sprintfa (str, "[%lld/0x%0llx] ", s->data.l, s->data.l);
                ++s;
        }
        return g_string_free (str, FALSE);
 }
 
+static void
+dump_stackval (GString *str, stackval *s, MonoType *type)
+{
+       switch (type->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_CHAR:
+       case MONO_TYPE_BOOLEAN:
+               g_string_sprintfa (str, "[%d] ", s->data.i);
+               break;
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+               g_string_sprintfa (str, "[%p] ", s->data.p);
+               break;
+       case MONO_TYPE_VALUETYPE:
+               if (type->data.klass->enumtype)
+                       g_string_sprintfa (str, "[%d] ", s->data.i);
+               else
+                       g_string_sprintfa (str, "[vt:%p] ", s->data.p);
+               break;
+       case MONO_TYPE_R4:
+       case MONO_TYPE_R8:
+               g_string_sprintfa (str, "[%g] ", s->data.f);
+               break;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       default:
+               g_string_sprintfa (str, "[%lld/0x%0llx] ", s->data.l, s->data.l);
+               break;
+       }
+}
+
 static char*
-dump_frame (MonoInvocation *inv)
+dump_args (MonoInvocation *inv)
 {
        GString *str = g_string_new ("");
        int i;
-       char *args;
-       for (i = 0; inv; inv = inv->parent, ++i) {
-               MonoClass *k = inv->method->klass;
-               int codep;
-               const char * opname;
-               gchar *source = NULL;
-               if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL ||
-                               inv->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
-                       codep = 0;
-                       opname = "";
-               } else {
-                       MonoMethodHeader *hd = ((MonoMethodNormal *)inv->method)->header;
+       MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method);
+       
+       if (signature->param_count == 0)
+               return g_string_free (str, FALSE);
 
-                       if (inv->ip)
-                               codep = *(inv->ip) == 0xfe? inv->ip [1] + 256: *(inv->ip);
-                       else
-                               codep = 0;
-                       opname = mono_opcode_names [codep];
-                       codep = inv->ip - hd->code;
+       if (signature->hasthis)
+               g_string_sprintfa (str, "%p ", inv->obj);
+
+       for (i = 0; i < signature->param_count; ++i)
+               dump_stackval (str, inv->stack_args + i, signature->params [i]);
 
-                       source = mono_debug_source_location_from_il_offset (inv->method, codep, NULL);
-               }
-               args = dump_stack (inv->stack_args, inv->stack_args + inv->method->signature->param_count);
-               if (source)
-                       g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s) at %s\n", i, codep, opname,
-                                          k->name_space, k->name, inv->method->name, args, source);
-               else
-                       g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s.%s::%s (%s)\n", i, codep, opname,
-                                          k->name_space, k->name, inv->method->name, args);
-               g_free (args);
-               g_free (source);
-       }
        return g_string_free (str, FALSE);
 }
 
-static CRITICAL_SECTION metadata_lock;
+static char*
+dump_retval (MonoInvocation *inv)
+{
+       GString *str = g_string_new ("");
+       MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
 
-typedef enum {
-       INLINE_STRING_LENGTH = 1,
-       INLINE_ARRAY_LENGTH,
-       INLINE_ARRAY_RANK,
-       INLINE_TYPE_ELEMENT_TYPE
-} InlineMethod;
+       if (ret->type != MONO_TYPE_VOID)
+               dump_stackval (str, inv->retval, ret);
 
-static void
-calc_offsets (MonoImage *image, MonoMethod *method)
+       return g_string_free (str, FALSE);
+}
+static char*
+dump_frame (MonoInvocation *inv)
 {
-       int i, align, size, offset = 0;
-       MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
-       MonoMethodSignature *signature = method->signature;
-       int hasthis = signature->hasthis;
-       register const unsigned char *ip, *end;
-       const MonoOpcode *opcode;
-       guint32 token;
-       MonoMethod *m;
-       MonoClass *class;
-       MonoDomain *domain = mono_domain_get ();
-       guint32 *offsets;
-
-       mono_profiler_method_jit (method); /* sort of... */
-       offsets = g_new0 (guint32, 2 + header->num_locals + signature->param_count + signature->hasthis);
-       for (i = 0; i < header->num_locals; ++i) {
-               size = mono_type_size (header->locals [i], &align);
-               offset += align - 1;
-               offset &= ~(align - 1);
-               offsets [2 + i] = offset;
-               offset += size;
-       }
-       offsets [0] = offset;
-       offset = 0;
-       if (hasthis) {
-               offset += sizeof (gpointer) - 1;
-               offset &= ~(sizeof (gpointer) - 1);
-               offsets [2 + header->num_locals] = offset;
-               offset += sizeof (gpointer);
-       }
-       for (i = 0; i < signature->param_count; ++i) {
-               if (signature->pinvoke)
-                       size = mono_type_native_stack_size (signature->params [i], &align);
-               else
-                       size = mono_type_stack_size (signature->params [i], &align);
-               offset += align - 1;
-               offset &= ~(align - 1);
-               offsets [2 + hasthis + header->num_locals + i] = offset;
-               offset += size;
-       }
-       offsets [1] = offset;
-
-       /* FIXME: This might cause a deadlock with domain->lock */
-       EnterCriticalSection (&metadata_lock);
-       /* intern the strings in the method. */
-       ip = header->code;
-       end = ip + header->code_size;
-       while (ip < end) {
-               i = *ip;
-               if (*ip == 0xfe) {
-                       ip++;
-                       i = *ip + 256;
-               }
-               opcode = &mono_opcodes [i];
-               switch (opcode->argument) {
-               case MonoInlineNone:
-                       ++ip;
-                       break;
-               case MonoInlineString:
-                       mono_ldstr (domain, image, mono_metadata_token_index (read32 (ip + 1)));
-                       ip += 5;
-                       break;
-               case MonoInlineType:
-                       if (method->wrapper_type == MONO_WRAPPER_NONE) {
-                               class = mono_class_get (image, read32 (ip + 1));
-                               mono_class_init (class);
-                               if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE))
-                                       mono_class_vtable (domain, class);
-                       }
-                       ip += 5;
-                       break;
-               case MonoInlineField:
-                       token = read32 (ip + 1);
-                       if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
-                               mono_field_from_memberref (image, token, &class);
-                       } else {
-                               class = mono_class_get (image, 
-                                       MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
-                       }
-                       mono_class_init (class);
-                       mono_class_vtable (domain, class);
-                       ip += 5;
-                       break;
-               case MonoInlineMethod:
-                       if (method->wrapper_type == MONO_WRAPPER_NONE) {
-                               m = mono_get_method (image, read32 (ip + 1), NULL);
-                               mono_class_init (m->klass);
-                               if (!(m->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
-                                       mono_class_vtable (domain, m->klass);
+       GString *str = g_string_new ("");
+       int i;
+       char *args;
+       for (i = 0; inv; inv = inv->parent) {
+               if (inv->runtime_method != NULL) {
+                       MonoMethod *method = inv->runtime_method->method;
+                       MonoClass *k;
+
+                       int codep = 0;
+                       const char * opname = "";
+                       char *name;
+                       gchar *source = NULL;
+
+                       k = method->klass;
+
+                       if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
+                               (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
+                               MonoMethodHeader *hd = mono_method_get_header (method);
+
+                               if (hd != NULL) {
+                                       if (inv->ip) {
+                                               opname = mono_interp_opname [*inv->ip];
+                                               codep = inv->ip - inv->runtime_method->code;
+                                       } else 
+                                               opname = "";
+       
+                                       source = mono_debug_source_location_from_il_offset (method, codep, NULL);
+                               }
                        }
-                       ip += 5;
-                       break;
-               case MonoInlineTok:
-               case MonoInlineSig:
-               case MonoShortInlineR:
-               case MonoInlineI:
-               case MonoInlineBrTarget:
-                       ip += 5;
-                       break;
-               case MonoInlineVar:
-                       ip += 3;
-                       break;
-               case MonoShortInlineVar:
-               case MonoShortInlineI:
-               case MonoShortInlineBrTarget:
-                       ip += 2;
-                       break;
-               case MonoInlineSwitch: {
-                       guint32 n;
-                       ++ip;
-                       n = read32 (ip);
-                       ip += 4;
-                       ip += 4 * n;
-                       break;
-               }
-               case MonoInlineR:
-               case MonoInlineI8:
-                       ip += 9;
-                       break;
-               default:
-                       g_assert_not_reached ();
+                       args = dump_args (inv);
+                       name = mono_method_full_name (method, TRUE);
+                       if (source)
+                               g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname,
+                                                  name, args, source);
+                       else
+                               g_string_sprintfa (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname,
+                                                  name, args);
+                       g_free (name);
+                       g_free (args);
+                       g_free (source);
+                       ++i;
                }
-
-       }
-       method->info = offsets;
-
-       /*
-        * We store the inline info in addr, since it's unused for IL methods.
-        */
-       if (method->klass == mono_defaults.string_class) {
-               if (strcmp (method->name, "get_Length") == 0)
-                       method->addr = GUINT_TO_POINTER (INLINE_STRING_LENGTH);
-       } else if (method->klass == mono_defaults.array_class) {
-               if (strcmp (method->name, "get_Length") == 0)
-                       method->addr = GUINT_TO_POINTER (INLINE_ARRAY_LENGTH);
-               else if (strcmp (method->name, "get_Rank") == 0 || strcmp (method->name, "GetRank") == 0)
-                       method->addr = GUINT_TO_POINTER (INLINE_ARRAY_RANK);
-       } else if (method->klass == mono_defaults.monotype_class) {
-               if (strcmp (method->name, "GetElementType") == 0)
-                       method->addr = GUINT_TO_POINTER (INLINE_TYPE_ELEMENT_TYPE);
        }
-       LeaveCriticalSection (&metadata_lock);
-       mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
+       return g_string_free (str, FALSE);
 }
 
-#define LOCAL_POS(n)            (frame->locals + offsets [2 + (n)])
-#define LOCAL_TYPE(header, n)   ((header)->locals [(n)])
-
-#define ARG_POS(n)              (args_pointers [(n)])
-#define ARG_TYPE(sig, n)        ((n) ? (sig)->params [(n) - (sig)->hasthis] : \
-                               (sig)->hasthis ? &frame->method->klass->this_arg: (sig)->params [(0)])
+static MonoArray *
+get_trace_ips (MonoDomain *domain, MonoInvocation *top)
+{
+       int i;
+       MonoArray *res;
+       MonoInvocation *inv;
 
-#define THROW_EX(exception,ex_ip)      \
-               do {\
-                       char *stack_trace;      \
-                       frame->ip = (ex_ip);            \
-                       stack_trace = dump_frame (frame);       \
-                       frame->ex = (MonoException*)(exception);        \
-                       frame->ex->stack_trace = mono_string_new (domain, stack_trace); \
-                       g_free (stack_trace);   \
-                       goto handle_exception;  \
-               } while (0)
-
-typedef struct _vtallocation vtallocation;
-
-struct _vtallocation {
-       vtallocation *next;
-       guint32 size;
-       char data [MONO_ZERO_LEN_ARRAY];
-};
+       for (i = 0, inv = top; inv; inv = inv->parent)
+               if (inv->runtime_method != NULL)
+                       ++i;
 
-#define vt_alloc(vtype,sp,native)      \
-       if ((vtype)->type == MONO_TYPE_VALUETYPE && !(vtype)->data.klass->enumtype) {   \
-               if (!(vtype)->byref) {  \
-                       guint32 align;  \
-                       guint32 size; \
-            vtallocation *tmp, *prev; \
-                        if (native) size = mono_class_native_size ((vtype)->data.klass, &align);       \
-                        else size = mono_class_value_size ((vtype)->data.klass, &align);       \
-            prev = NULL; \
-                       tmp = vtalloc; \
-                       while (tmp && (tmp->size < size)) { \
-                               prev = tmp; \
-                           tmp = tmp->next; \
-                       } \
-            if (!tmp) { \
-                               tmp = alloca (sizeof (vtallocation) + size);    \
-                               tmp->size = size;       \
-                               g_assert (size < 10000);        \
-                       } \
-                       else \
-                           if (prev) \
-                                   prev->next = tmp->next; \
-                else \
-                    vtalloc = tmp->next; \
-                       (sp)->data.vt.vt = tmp->data;   \
-               } else {        \
-                       (sp)->data.vt.klass = (vtype)->data.klass;      \
-               }       \
-       }
+       res = mono_array_new (domain, mono_defaults.int_class, 2 * i);
 
-#define vt_free(sp)    \
-       do {    \
-               if ((sp)->type == VAL_VALUET) { \
-                       vtallocation *tmp = (vtallocation*)(((char*)(sp)->data.vt.vt) - G_STRUCT_OFFSET (vtallocation, data));  \
-            tmp->next = vtalloc; \
-            vtalloc = tmp; \
-               }       \
-       } while (0)
+       for (i = 0, inv = top; inv; inv = inv->parent)
+               if (inv->runtime_method != NULL) {
+                       mono_array_set (res, gpointer, i, inv->runtime_method);
+                       ++i;
+                       mono_array_set (res, gpointer, i, (gpointer)inv->ip);
+                       ++i;
+               }
 
-/*
-static void
-verify_method (MonoMethod *m)
-{
-       GSList *errors, *tmp;
-       MonoVerifyInfo *info;
-
-       errors = mono_method_verify (m, MONO_VERIFY_ALL);
-       if (errors)
-               g_print ("Method %s.%s::%s has invalid IL.\n", m->klass->name_space, m->klass->name, m->name);
-       for (tmp = errors; tmp; tmp = tmp->next) {
-               info = tmp->data;
-               g_print ("%s\n", info->message);
-       }
-       if (errors)
-               G_BREAKPOINT ();
-       mono_free_verify_list (errors);
+       return res;
 }
-*/
+
 
 #define MYGUINT64_MAX 18446744073709551615ULL
 #define MYGINT64_MAX 9223372036854775807LL
@@ -1086,50 +998,117 @@ verify_method (MonoMethod *m)
        (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0  \
        : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
 
+#define CHECK_SUB_OVERFLOW(a,b) \
+       (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0   \
+       : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
+
 #define CHECK_ADD_OVERFLOW_UN(a,b) \
        (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
 
+#define CHECK_SUB_OVERFLOW_UN(a,b) \
+       (guint32)(a) < (guint32)(b) ? -1 : 0
+
 #define CHECK_ADD_OVERFLOW64(a,b) \
        (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0  \
        : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
 
+#define CHECK_SUB_OVERFLOW64(a,b) \
+       (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0   \
+       : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
+
 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
        (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
 
-/* Resolves to TRUE if the operands would overflow */
+#define CHECK_SUB_OVERFLOW64_UN(a,b) \
+       (guint64)(a) < (guint64)(b) ? -1 : 0
+
+#if SIZEOF_VOID_P == 4
+#define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
+#define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
+#else
+#define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
+#define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
+#endif
+
+/* Resolves to TRUE if the operands would overflow */
 #define CHECK_MUL_OVERFLOW(a,b) \
        ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
-       (((gint32)(a) > 0) && ((gint32)(b) > 0)) || (((gint32)(a) < 0) && ((gint32)(b) < 0)) ? \
-               (gint32)(b) > ((MYGINT32_MAX) / (gint32)(a)) : \
-               (gint32)(b) < ((MYGINT32_MIN) / (gint32)(a))
+       (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
+       (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
+       (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
+       (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
+       (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
+       (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
 
 #define CHECK_MUL_OVERFLOW_UN(a,b) \
        ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
        (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
+
 #define CHECK_MUL_OVERFLOW64(a,b) \
        ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
-       (((gint64)(a) > 0) && ((gint64)(b) > 0)) || (((gint64)(a) < 0) && ((gint64)(b) < 0)) ? \
-               (gint64)(b) > ((MYGINT64_MAX) / (gint64)(a)) : \
-               (gint64)(b) < ((MYGINT64_MIN) / (gint64)(a))
+       (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
+       (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
+       (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
+       (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
+       (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
+       (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
 
 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
        ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
        (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
 
+#if SIZEOF_VOID_P == 4
+#define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
+#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
+#else
+#define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
+#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
+#endif
+
 static MonoObject*
 interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
-       MonoInvocation frame, *parent;
+       MonoInvocation frame;
+       ThreadContext * volatile context = TlsGetValue (thread_context_id);
        MonoObject *retval = NULL;
-       MonoMethodSignature *sig = method->signature;
+       MonoMethodSignature *sig = mono_method_signature (method);
        MonoClass *klass = mono_class_from_mono_type (sig->ret);
        int i, type, isobject = 0;
-       void *ret;
+       void *ret = NULL;
        stackval result;
        stackval *args = alloca (sizeof (stackval) * sig->param_count);
+       ThreadContext context_struct;
+       MonoInvocation *old_frame = NULL;
+       jmp_buf env;
+
+       frame.ex = NULL;
+
+       if (setjmp(env)) {
+               if (context != &context_struct) {
+                       context->domain = mono_domain_get ();
+                       context->current_frame = old_frame;
+                       context->managed_code = 0;
+               } else 
+                       TlsSetValue (thread_context_id, NULL);
+               if (exc != NULL)
+                       *exc = (MonoObject *)frame.ex;
+               return retval;
+       }
+
+       if (context == NULL) {
+               context = &context_struct;
+               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;
+               TlsSetValue (thread_context_id, context);
+       }
+       else
+               old_frame = context->current_frame;
 
-       /* FIXME: Set frame for execption handling.  */
+       context->domain = mono_domain_get ();
 
        switch (sig->ret->type) {
        case MONO_TYPE_VOID:
@@ -1142,20 +1121,19 @@ interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
                isobject = 1;
                break;
        case MONO_TYPE_VALUETYPE:
-               retval = mono_object_new (mono_domain_get (), klass);
+               retval = mono_object_new (context->domain, klass);
                ret = ((char*)retval) + sizeof (MonoObject);
                if (!sig->ret->data.klass->enumtype)
-                       result.data.vt.vt = ret;
+                       result.data.vt = ret;
                break;
        default:
-               retval = mono_object_new (mono_domain_get (), klass);
+               retval = mono_object_new (context->domain, klass);
                ret = ((char*)retval) + sizeof (MonoObject);
                break;
        }
 
        for (i = 0; i < sig->param_count; ++i) {
                if (sig->params [i]->byref) {
-                       args [i].type = VAL_POINTER;
                        args [i].data.p = params [i];
                        continue;
                }
@@ -1165,16 +1143,12 @@ handle_enum:
                case MONO_TYPE_U1:
                case MONO_TYPE_I1:
                case MONO_TYPE_BOOLEAN:
-                       args [i].type = VAL_I32;
                        args [i].data.i = *(MonoBoolean*)params [i];
-                       args [i].data.vt.klass = NULL;
                        break;
                case MONO_TYPE_U2:
                case MONO_TYPE_I2:
                case MONO_TYPE_CHAR:
-                       args [i].type = VAL_I32;
                        args [i].data.i = *(gint16*)params [i];
-                       args [i].data.vt.klass = NULL;
                        break;
 #if SIZEOF_VOID_P == 4
                case MONO_TYPE_U: /* use VAL_POINTER? */
@@ -1182,9 +1156,7 @@ handle_enum:
 #endif
                case MONO_TYPE_U4:
                case MONO_TYPE_I4:
-                       args [i].type = VAL_I32;
                        args [i].data.i = *(gint32*)params [i];
-                       args [i].data.vt.klass = NULL;
                        break;
 #if SIZEOF_VOID_P == 8
                case MONO_TYPE_U:
@@ -1192,18 +1164,14 @@ handle_enum:
 #endif
                case MONO_TYPE_U8:
                case MONO_TYPE_I8:
-                       args [i].type = VAL_I64;
                        args [i].data.l = *(gint64*)params [i];
-                       args [i].data.vt.klass = NULL;
                        break;
                case MONO_TYPE_VALUETYPE:
                        if (sig->params [i]->data.klass->enumtype) {
                                type = sig->params [i]->data.klass->enum_basetype->type;
                                goto handle_enum;
                        } else {
-                               args [i].type = VAL_POINTER;
                                args [i].data.p = params [i];
-                               args [i].data.vt.klass = NULL;
                        }
                        break;
                case MONO_TYPE_STRING:
@@ -1211,24 +1179,36 @@ handle_enum:
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
                case MONO_TYPE_OBJECT:
-                       args [i].type = VAL_OBJ;
                        args [i].data.p = params [i];
-                       args [i].data.vt.klass = NULL;
                        break;
                default:
                        g_error ("type 0x%x not handled in  runtime invoke", sig->params [i]->type);
                }
        }
 
-       /* chain with managed parent if any */
-       parent = TlsGetValue (frame_thread_id);
-       INIT_FRAME(&frame,parent,obj,args,&result,method);
+       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) 
+               method = mono_marshal_get_native_wrapper (method);
+       INIT_FRAME(&frame,context->current_frame,obj,args,&result,method);
        if (exc)
                frame.invoke_trap = 1;
-       ves_exec_method (&frame);
-       if (exc && frame.ex) {
-               *exc = (MonoObject*) frame.ex;
-               return NULL;
+       context->managed_code = 1;
+       ves_exec_method_with_context (&frame, context);
+       context->managed_code = 0;
+       if (context == &context_struct)
+               TlsSetValue (thread_context_id, 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);
+               }
+               else
+                       printf("dropped exception...\n");
        }
        if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
                return NULL;
@@ -1238,134 +1218,249 @@ handle_enum:
        return retval;
 }
 
-/*
- * Need to optimize ALU ops when natural int == int32 
- *
- * IDEA: if we maintain a stack of ip, sp to be checked
- * in the return opcode, we could inline simple methods that don't
- * use the stack or local variables....
- * 
- * The {,.S} versions of many opcodes can/should be merged to reduce code
- * duplication.
- * 
- */
-void 
-ves_exec_method (MonoInvocation *frame)
+static stackval * 
+do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
 {
-       MonoDomain *domain = mono_domain_get ();        
-       MonoInvocation child_frame;
-       MonoMethodHeader *header;
-       MonoMethodSignature *signature;
-       MonoImage *image;
-       GSList *finally_ips = NULL;
-       const unsigned char *endfinally_ip;
-       register const unsigned char *ip;
-       register stackval *sp = NULL;
-       void **args_pointers;
-       guint32 *offsets;
-       gint il_ins_count = -1;
-       gint tracing = global_tracing;
-       unsigned char tail_recursion = 0;
-       unsigned char unaligned_address = 0;
-       unsigned char volatile_address = 0;
-       vtallocation *vtalloc = NULL;
-       MonoVTable *method_class_vt;
-       GOTO_LABEL_VARS;
+       MonoInvocation *old_frame = context->current_frame;
+       MonoInvocation *old_env_frame = context->env_frame;
+       jmp_buf *old_env = context->current_env;
+       jmp_buf env;
 
-       if (frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
-               frame->method = mono_marshal_get_native_wrapper (frame->method);
+       if (setjmp (env)) {
+               context->current_frame = old_frame;
+               context->env_frame = old_env_frame;
+               context->current_env = old_env;
+               context->managed_code = 1;
+               return sp;
+       }
 
-       method_class_vt = mono_class_vtable (domain, frame->method->klass);
-       if (!method_class_vt->initialized)
-               mono_runtime_class_init (method_class_vt);
-       signature = frame->method->signature;
+       context->env_frame = context->current_frame;
+       context->current_env = &env;
+       context->managed_code = 0;
 
-       DEBUG_ENTER ();
+       switch (op) {
+       case MINT_ICALL_V_V: {
+               void (*func)() = ptr;
+               func ();
+               break;
+       }
+       case MINT_ICALL_P_V: {
+               void (*func)(gpointer) = ptr;
+               func (sp [-1].data.p);
+               sp --;
+               break;
+       }
+       case MINT_ICALL_P_P: {
+               gpointer (*func)(gpointer) = ptr;
+               sp [-1].data.p = func (sp [-1].data.p);
+               break;
+       }
+       case MINT_ICALL_PP_V: {
+               void (*func)(gpointer,gpointer) = ptr;
+               sp -= 2;
+               func (sp [0].data.p, sp [1].data.p);
+               break;
+       }
+       case MINT_ICALL_PI_V: {
+               void (*func)(gpointer,int) = ptr;
+               sp -= 2;
+               func (sp [0].data.p, sp [1].data.i);
+               break;
+       }
+       case MINT_ICALL_PP_P: {
+               gpointer (*func)(gpointer,gpointer) = ptr;
+               --sp;
+               sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
+               break;
+       }
+       case MINT_ICALL_PI_P: {
+               gpointer (*func)(gpointer,int) = ptr;
+               --sp;
+               sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
+               break;
+       }
+       case MINT_ICALL_PPP_V: {
+               void (*func)(gpointer,gpointer,gpointer) = ptr;
+               sp -= 3;
+               func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
+               break;
+       }
+       case MINT_ICALL_PPI_V: {
+               void (*func)(gpointer,gpointer,int) = ptr;
+               sp -= 3;
+               func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
+               break;
+       }
+       default:
+               g_assert_not_reached ();
+       }
 
-       if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-               if (!frame->method->addr) {
-                       /* ugly, but needed by the iflags setting in loader.c */
-                       if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
-                               ves_runtime_method (frame);
-                               if (frame->ex)
-                                       goto handle_exception;
-                               DEBUG_LEAVE ();
-                               return;
-                       }
-                       if (frame->method->addr) {
-                               frame->ex = (MonoException*)mono_get_exception_missing_method ();
-                               goto handle_exception;
-                       }
-               }
-               ves_pinvoke_method (frame, frame->method->signature, frame->method->addr, 
-                           frame->method->string_ctor);
-               if (frame->ex)
-                       goto handle_exception;
-               DEBUG_LEAVE ();
-               return;
-       } 
+       context->env_frame = old_env_frame;
+       context->current_env = old_env;
 
-       if (frame->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
-               ves_runtime_method (frame);
-               if (frame->ex)
-                       goto handle_exception;
-               DEBUG_LEAVE ();
-               return;
-       } 
+       return sp;
+}
 
-       /*verify_method (frame->method);*/
+static CRITICAL_SECTION create_method_pointer_mutex;
 
-       header = ((MonoMethodNormal *)frame->method)->header;
-       image = frame->method->klass->image;
+static MonoGHashTable *method_pointer_hash = NULL;
 
-       if (!frame->method->info)
-               calc_offsets (image, frame->method);
-       offsets = frame->method->info;
+static void *
+mono_create_method_pointer (MonoMethod *method)
+{
+       gpointer addr;
+       MonoJitInfo *ji;
 
-       /*
-        * with alloca we get the expected huge performance gain
-        * stackval *stack = g_new0(stackval, header->max_stack);
-        */
-       g_assert (header->max_stack < 10000);
-       sp = frame->stack = alloca (sizeof (stackval) * header->max_stack);
-
-       if (header->num_locals) {
-               g_assert (offsets [0] < 10000);
-               frame->locals = alloca (offsets [0]);
-               /* 
-                * yes, we do it unconditionally, because it needs to be done for
-                * some cases anyway and checking for that would be even slower.
-                */
-               memset (frame->locals, 0, offsets [0]);
+       EnterCriticalSection (&create_method_pointer_mutex);
+       if (!method_pointer_hash) {
+               MONO_GC_REGISTER_ROOT (method_pointer_hash);
+               method_pointer_hash = mono_g_hash_table_new (NULL, NULL);
+       }
+       addr = mono_g_hash_table_lookup (method_pointer_hash, method);
+       if (addr) {
+               LeaveCriticalSection (&create_method_pointer_mutex);
+               return addr;
        }
+
        /*
-        * Copy args from stack_args to args.
+        * If it is a static P/Invoke method, we can just return the pointer
+        * to the method implementation.
         */
-       if (signature->param_count || signature->hasthis) {
-               int i;
-               int has_this = signature->hasthis;
-
-               g_assert (offsets [1] < 10000);
-               frame->args = alloca (offsets [1]);
-               g_assert ((signature->param_count + has_this) < 1000);
-               args_pointers = alloca (sizeof(void*) * (signature->param_count + has_this));
-               if (has_this) {
-                       gpointer *this_arg;
-                       this_arg = args_pointers [0] = frame->args;
-                       *this_arg = frame->obj;
-               }
-               for (i = 0; i < signature->param_count; ++i) {
-                       args_pointers [i + has_this] = frame->args + offsets [2 + header->num_locals + has_this + i];
-                       stackval_to_data (signature->params [i], frame->stack_args + i, args_pointers [i + has_this], signature->pinvoke);
+       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) {
+               ji = g_new0 (MonoJitInfo, 1);
+               ji->method = method;
+               ji->code_size = 1;
+               ji->code_start = addr = ((MonoMethodPInvoke*) method)->addr;
+
+               mono_jit_info_table_add (mono_get_root_domain (), ji);
+       }               
+       else
+               addr = mono_arch_create_method_pointer (method);
+
+       mono_g_hash_table_insert (method_pointer_hash, method, addr);
+       LeaveCriticalSection (&create_method_pointer_mutex);
+
+       return addr;
+}
+
+#if COUNT_OPS
+static int opcode_counts[512];
+
+#define COUNT_OP(op) opcode_counts[op]++
+#else
+#define COUNT_OP(op) 
+#endif
+
+#if DEBUG_INTERP
+#define DUMP_INSTR() \
+       if (tracing > 1) { \
+               char *ins; \
+               if (sp > frame->stack) { \
+                       ins = dump_stack (frame->stack, sp); \
+               } else { \
+                       ins = g_strdup (""); \
+               } \
+               sp->data.l = 0; \
+               output_indent (); \
+               g_print ("(%u) ", GetCurrentThreadId()); \
+               mono_interp_dis_mintop(rtm->code, ip); \
+               g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \
+               g_free (ins); \
+       }
+#else
+#define DUMP_INSTR()
+#endif
+
+#ifdef __GNUC__
+#define USE_COMPUTED_GOTO 1
+#endif
+#if USE_COMPUTED_GOTO
+#define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
+#define MINT_IN_CASE(x) LAB_ ## x:
+#if DEBUG_INTERP
+#define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
+#else
+#define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
+#endif
+#define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
+#else
+#define MINT_IN_SWITCH(op) switch (op)
+#define MINT_IN_CASE(x) case x:
+#define MINT_IN_BREAK break
+#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)
+{
+       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
+       register stackval *sp;
+       RuntimeMethod *rtm;
+#if DEBUG_INTERP
+       gint tracing = global_tracing;
+       unsigned char *vtalloc;
+#endif
+       int i32;
+       unsigned char *vt_sp;
+       char *locals;
+       MonoObject *o = NULL;
+       MonoClass *c;
+#if USE_COMPUTED_GOTO
+       static void *in_labels[] = {
+#define OPDEF(a,b,c,d) \
+       &&LAB_ ## a,
+#include "mintops.def"
+       0 };
+#endif
+
+       frame->ex = NULL;
+       frame->ex_handler = NULL;
+       frame->ip = NULL;
+       context->current_frame = frame;
+
+       DEBUG_ENTER ();
+
+       if (!frame->runtime_method->transformed) {
+               context->managed_code = 0;
+               frame->ex = mono_interp_transform_method (frame->runtime_method, context);
+               context->managed_code = 1;
+               if (frame->ex) {
+                       rtm = NULL;
+                       ip = NULL;
+                       goto exit_frame;
                }
        }
 
+       rtm = frame->runtime_method;
+       frame->args = alloca (rtm->alloca_size);
+       sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size);
+#if DEBUG_INTERP
+       if (tracing > 1)
+               memset(sp, 0, rtm->stack_size);
+#endif
+       vt_sp = (char *)sp + rtm->stack_size;
+#if DEBUG_INTERP
+       vtalloc = vt_sp;
+#endif
+       locals = vt_sp + rtm->vt_stack_size;
+
        child_frame.parent = frame;
-       frame->child = &child_frame;
-       frame->ex = NULL;
 
        /* ready to go */
-       ip = header->code;
+       ip = rtm->code;
 
        /*
         * using while (ip < end) may result in a 15% performance drop, 
@@ -1373,358 +1468,170 @@ ves_exec_method (MonoInvocation *frame)
         */
        while (1) {
        main_loop:
-               /*g_assert (sp >= stack);*/
-#if DEBUG_INTERP
-               opcode_count++;
-               if (tracing > 1) {
-                       char *ins, *discode;
-                       if (sp > frame->stack) {
-                               ins = dump_stack (frame->stack, sp);
-                       } else {
-                               ins = g_strdup ("");
-                       }
-                       output_indent ();
-                       discode = mono_disasm_code_one (NULL, frame->method, ip, NULL);
-                       discode [strlen (discode) - 1] = 0; /* no \n */
-                       g_print ("(%d) %-29s %s\n", GetCurrentThreadId(), discode, ins);
-                       g_free (ins);
-                       g_free (discode);
-               }
-               if (il_ins_count > 0)
-                       if (!(--il_ins_count))
-                               G_BREAKPOINT ();
-#endif
-               
-               SWITCH (*ip) {
-               CASE (CEE_NOP) 
+               /* g_assert (sp >= frame->stack); */
+               /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
+               DUMP_INSTR();
+               MINT_IN_SWITCH (*ip) {
+               MINT_IN_CASE(MINT_INITLOCALS)
+                       memset (locals, 0, rtm->locals_size);
                        ++ip;
-                       BREAK;
-               CASE (CEE_BREAK)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NOP)
                        ++ip;
-                       G_BREAKPOINT (); /* this is not portable... */
-                       BREAK;
-               CASE (CEE_LDARG_0)
-               CASE (CEE_LDARG_1)
-               CASE (CEE_LDARG_2)
-               CASE (CEE_LDARG_3) {
-                       int n = (*ip)-CEE_LDARG_0;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BREAK)
                        ++ip;
-                       vt_alloc (ARG_TYPE (signature, n), sp, signature->pinvoke);
-                       stackval_from_data (ARG_TYPE (signature, n), sp, ARG_POS (n), signature->pinvoke);
-                       ++sp;
-                       BREAK;
-               }
-               CASE (CEE_LDLOC_0)
-               CASE (CEE_LDLOC_1)
-               CASE (CEE_LDLOC_2)
-               CASE (CEE_LDLOC_3) {
-                       int n = (*ip)-CEE_LDLOC_0;
+                       G_BREAKPOINT (); /* this is not portable... */
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDNULL) 
+                       sp->data.p = NULL;
                        ++ip;
-                       if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
-                               sp->type = VAL_I32;
-                               sp->data.i = *(gint32*) LOCAL_POS (n);
-                               ++sp;
-                               BREAK;
-                       } else {
-                               vt_alloc (LOCAL_TYPE (header, n), sp, FALSE);
-                               stackval_from_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
-                       }
                        ++sp;
-                       BREAK;
-               }
-               CASE (CEE_STLOC_0)
-               CASE (CEE_STLOC_1)
-               CASE (CEE_STLOC_2)
-               CASE (CEE_STLOC_3) {
-                       int n = (*ip)-CEE_STLOC_0;
-                       ++ip;
-                       --sp;
-                       if ((LOCAL_TYPE (header, n))->type == MONO_TYPE_I4) {
-                               gint32 *p = (gint32*)LOCAL_POS (n);
-                               *p = sp->data.i;
-                               BREAK;
-                       } else {
-                               stackval_to_data (LOCAL_TYPE (header, n), sp, LOCAL_POS (n), FALSE);
-                               vt_free (sp);
-                               BREAK;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_VTRESULT) {
+                       int ret_size = * (guint16 *)(ip + 1);
+                       char *ret_vt_sp = vt_sp;
+                       vt_sp -= READ32(ip + 2);
+                       if (ret_size > 0) {
+                               memmove (vt_sp, ret_vt_sp, ret_size);
+                               vt_sp += (ret_size + 7) & ~7;
                        }
+                       ip += 4;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDARG_S)
-                       ++ip;
-                       vt_alloc (ARG_TYPE (signature, *ip), sp, signature->pinvoke);
-                       stackval_from_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
-                       ++sp;
-                       ++ip;
-                       BREAK;
-               CASE (CEE_LDARGA_S) {
-                       MonoType *t;
-                       MonoClass *c;
-
-                       ++ip;
-                       t = ARG_TYPE (signature, *ip);
-                       c = mono_class_from_mono_type (t);
-                       sp->data.vt.klass = c;
-                       sp->data.vt.vt = ARG_POS (*ip);
-
-                       if (c->valuetype)
-                               sp->type = VAL_VALUETA;
-                       else
-                               sp->type = VAL_TP;
-
-                       ++sp;
-                       ++ip;
-                       BREAK;
-               }
-               CASE (CEE_STARG_S)
-                       ++ip;
-                       --sp;
-                       stackval_to_data (ARG_TYPE (signature, *ip), sp, ARG_POS (*ip), signature->pinvoke);
-                       vt_free (sp);
-                       ++ip;
-                       BREAK;
-               CASE (CEE_LDLOC_S)
-                       ++ip;
-                       vt_alloc (LOCAL_TYPE (header, *ip), sp, FALSE);
-                       stackval_from_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
-                       ++ip;
-                       ++sp;
-                       BREAK;
-               CASE (CEE_LDLOCA_S) {
-                       MonoType *t;
-                       MonoClass *c;
-
-                       ++ip;
-                       t = LOCAL_TYPE (header, *ip);
-                       c =  mono_class_from_mono_type (t);
-                       sp->data.vt.klass = c;
-                       sp->data.p = LOCAL_POS (*ip);
-
-                       if (c->valuetype)
-                               sp->type = VAL_VALUETA;
-                       else 
-                               sp->type = VAL_TP;
-
-                       ++sp;
-                       ++ip;
-                       BREAK;
-               }
-               CASE (CEE_STLOC_S)
-                       ++ip;
-                       --sp;
-                       stackval_to_data (LOCAL_TYPE (header, *ip), sp, LOCAL_POS (*ip), FALSE);
-                       vt_free (sp);
-                       ++ip;
-                       BREAK;
-               CASE (CEE_LDNULL) 
-                       ++ip;
-                       sp->type = VAL_OBJ;
-                       sp->data.p = NULL;
-                       sp->data.vt.klass = NULL;
-                       ++sp;
-                       BREAK;
-               CASE (CEE_LDC_I4_M1)
-                       ++ip;
-                       sp->type = VAL_I32;
-                       sp->data.i = -1;
-                       ++sp;
-                       BREAK;
-               CASE (CEE_LDC_I4_0)
-               CASE (CEE_LDC_I4_1)
-               CASE (CEE_LDC_I4_2)
-               CASE (CEE_LDC_I4_3)
-               CASE (CEE_LDC_I4_4)
-               CASE (CEE_LDC_I4_5)
-               CASE (CEE_LDC_I4_6)
-               CASE (CEE_LDC_I4_7)
-               CASE (CEE_LDC_I4_8)
-                       sp->type = VAL_I32;
-                       sp->data.i = (*ip) - CEE_LDC_I4_0;
+#define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
+               MINT_IN_CASE(MINT_LDC_I4_M1)
+                       LDC(-1);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_0)
+                       LDC(0);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_1)
+                       LDC(1);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_2)
+                       LDC(2);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_3)
+                       LDC(3);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_4)
+                       LDC(4);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_5)
+                       LDC(5);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_6)
+                       LDC(6);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_7)
+                       LDC(7);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_8)
+                       LDC(8);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4_S) 
+                       sp->data.i = *(const short *)(ip + 1);
+                       ip += 2;
                        ++sp;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I4)
                        ++ip;
-                       BREAK;
-               CASE (CEE_LDC_I4_S) 
-                       ++ip;
-                       sp->type = VAL_I32;
-                       sp->data.i = *(const gint8 *)ip;
-                       ++ip;
+                       sp->data.i = READ32 (ip);
+                       ip += 2;
                        ++sp;
-                       BREAK;
-               CASE (CEE_LDC_I4)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_I8)
                        ++ip;
-                       sp->type = VAL_I32;
-                       sp->data.i = read32 (ip);
+                       sp->data.l = READ64 (ip);
                        ip += 4;
                        ++sp;
-                       BREAK;
-               CASE (CEE_LDC_I8)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDC_R4) {
+                       guint32 val;
                        ++ip;
-                       sp->type = VAL_I64;
-                       sp->data.l = read64 (ip);
-                       ip += 8;
-                       ++sp;
-                       BREAK;
-               CASE (CEE_LDC_R4) {
-                       float val;
-                       ++ip;
-                       sp->type = VAL_DOUBLE;
-                       readr4 (ip, &val);
-                       sp->data.f = val;
-                       ip += 4;
+                       val = READ32(ip);
+                       sp->data.f = * (float *)&val;
+                       ip += 2;
                        ++sp;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDC_R8) 
-                       ++ip;
-                       sp->type = VAL_DOUBLE;
-                       readr8(ip, &sp->data.f);
-                       ip += 8;
+               MINT_IN_CASE(MINT_LDC_R8) 
+                       sp->data.l = READ64 (ip + 1); /* note union usage */
+                       ip += 5;
+                       ++sp;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_DUP) 
+                       sp [0] = sp[-1];
                        ++sp;
-                       BREAK;
-               CASE (CEE_UNUSED99) ves_abort (); BREAK;
-               CASE (CEE_DUP) 
-                       if (sp [-1].type == VAL_VALUET) {
-                               MonoClass *c = sp [-1].data.vt.klass;
-                               vt_alloc (&c->byval_arg, sp, FALSE);
-                               stackval_from_data (&c->byval_arg, sp, sp [-1].data.vt.vt, FALSE);
-                       } else {
-                               *sp = sp [-1]; 
-                       }
-                       ++sp; 
                        ++ip; 
-                       BREAK;
-               CASE (CEE_POP)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_DUP_VT)
+                       i32 = READ32 (ip + 1);
+                       sp->data.p = vt_sp;
+                       memcpy(sp->data.p, sp [-1].data.p, i32);
+                       vt_sp += (i32 + 7) & ~7;
+                       ++sp;
+                       ip += 3;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_POP)
                        ++ip;
                        --sp;
-                       vt_free (sp);
-                       BREAK;
-               CASE (CEE_JMP) ves_abort(); BREAK;
-               CASE (CEE_CALLVIRT) /* Fall through */
-               CASE (CEE_CALLI)    /* Fall through */
-               CASE (CEE_CALL) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_JMP) {
+                       RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
+                       if (!new_method->transformed) {
+                               frame->ip = ip;
+                               frame->ex = mono_interp_transform_method (new_method, context);
+                               if (frame->ex)
+                                       goto exit_frame;
+                       }
+                       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;
+                       vt_sp = (char *)sp + rtm->stack_size;
+#if DEBUG_INTERP
+                       vtalloc = vt_sp;
+#endif
+                       locals = vt_sp + rtm->vt_stack_size;
+                       ip = rtm->new_body_start; /* bypass storing input args from callers frame */
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_CALLI) {
                        MonoMethodSignature *csignature;
-                       stackval retval;
                        stackval *endsp = sp;
-                       guint32 token;
-                       int virtual = *ip == CEE_CALLVIRT;
-                       int calli = *ip == CEE_CALLI;
-                       unsigned char *code = NULL;
-
-                       /*
-                        * We ignore tail recursion for now.
-                        */
-                       tail_recursion = 0;
 
                        frame->ip = ip;
                        
-                       ++ip;
-                       token = read32 (ip);
-                       ip += 4;
-                       if (calli) {
-                               MonoJitInfo *ji;
-                               --sp;
-                               code = sp->data.p;
-                               if (frame->method->wrapper_type != MONO_WRAPPER_NONE) {
-                                       csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (frame->method, token);
-                                       child_frame.method = NULL;
-                               } else if ((ji = mono_jit_info_table_find (mono_root_domain, code))) {
-                                       child_frame.method = ji->method;
-                               } else {
-                                       g_assert_not_reached ();
-                               }
-                               g_assert (code);
-                       } else {
-                               child_frame.method = mono_get_method (image, token, NULL);
-                               if (!child_frame.method)
-                                       THROW_EX (mono_get_exception_missing_method (), ip -5);
-                               csignature = child_frame.method->signature;
-                               if (virtual) {
-                                       stackval *this_arg = &sp [-csignature->param_count-1];
-                                       if (!this_arg->data.p)
-                                               THROW_EX (mono_get_exception_null_reference(), ip - 5);
-                                       child_frame.method = get_virtual_method (domain, child_frame.method, this_arg);
-                                       if (!child_frame.method)
-                                               THROW_EX (mono_get_exception_missing_method (), ip -5);
-                               }
-                       }
+                       csignature = rtm->data_items [* (guint16 *)(ip + 1)];
+                       ip += 2;
+                       --sp;
+                       --endsp;
+                       child_frame.runtime_method = sp->data.p;
 
-                       g_assert (csignature->call_convention == MONO_CALL_DEFAULT);
+                       sp->data.p = vt_sp;
+                       child_frame.retval = sp;
                        /* decrement by the actual number of args */
-                       if (csignature->param_count) {
-                               sp -= csignature->param_count;
-                               child_frame.stack_args = sp;
-                       } else {
-                               child_frame.stack_args = NULL;
-                       }
+                       sp -= csignature->param_count;
+                       child_frame.stack_args = sp;
                        if (csignature->hasthis) {
-                               g_assert (sp >= frame->stack);
                                --sp;
-                               /*
-                                * It may also be a TP from LD(S)FLDA
-                                * g_assert (sp->type == VAL_OBJ || sp->type == VAL_VALUETA);
-                                */
-                               if (sp->type == VAL_OBJ && child_frame.method &&
-                                   child_frame.method->klass->valuetype) /* unbox it */
-                                       child_frame.obj = (char*)sp->data.p + sizeof (MonoObject);
-                               else
-                                       child_frame.obj = sp->data.p;
+                               child_frame.obj = sp->data.p;
                        } else {
                                child_frame.obj = NULL;
                        }
-                       if (csignature->ret->type != MONO_TYPE_VOID) {
-                               vt_alloc (csignature->ret, &retval, csignature->pinvoke);
-                               child_frame.retval = &retval;
-                       } else {
-                               child_frame.retval = NULL;
-                       }
+                       if (csignature->hasthis &&
+                                       ((MonoObject *)child_frame.obj)->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               child_frame.runtime_method = mono_interp_get_runtime_method (
+                                                               mono_marshal_get_remoting_invoke (child_frame.runtime_method->method));
+                       } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) 
+                               child_frame.runtime_method = mono_interp_get_runtime_method (
+                                                               mono_marshal_get_native_wrapper (child_frame.runtime_method->method));
 
-                       child_frame.ex = NULL;
-                       child_frame.ex_handler = NULL;
-
-                       if (!child_frame.method) {
-                               g_assert (code);
-                               ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE);
-                       } else if (csignature->hasthis && sp->type == VAL_OBJ &&
-                                       ((MonoObject *)sp->data.p)->vtable->klass == mono_defaults.transparent_proxy_class) {
-                               g_assert (child_frame.method);
-                               child_frame.method = mono_marshal_get_remoting_invoke (child_frame.method);
-                               ves_exec_method (&child_frame);
-                       } else {
-                               switch (GPOINTER_TO_UINT (child_frame.method->addr)) {
-                               case INLINE_STRING_LENGTH:
-                                       retval.type = VAL_I32;
-                                       retval.data.i = ((MonoString*)sp->data.p)->length;
-                                       /*g_print ("length of '%s' is %d\n", mono_string_to_utf8 (sp->data.p), retval.data.i);*/
-                                       break;
-                               case INLINE_ARRAY_LENGTH:
-                                       retval.type = VAL_I32;
-                                       retval.data.i = mono_array_length ((MonoArray*)sp->data.p);
-                                       break;
-                               case INLINE_ARRAY_RANK:
-                                       retval.type = VAL_I32;
-                                       retval.data.i = mono_object_class (sp->data.p)->rank;
-                                       break;
-                               case INLINE_TYPE_ELEMENT_TYPE:
-                                       retval.type = VAL_OBJ;
-                                       {
-                                               MonoClass *c = mono_class_from_mono_type (((MonoReflectionType*)sp->data.p)->type);
-                                               retval.data.vt.klass = NULL;
-                                               if (c->enumtype && c->enum_basetype) /* types that are modifierd typebuilkders may not have enum_basetype set */
-                                                       retval.data.p = mono_type_get_object (domain, c->enum_basetype);
-                                               else if (c->element_class)
-                                                       retval.data.p = mono_type_get_object (domain, &c->element_class->byval_arg);
-                                               else
-                                                       retval.data.p = NULL;
-                                       }
-                                       break;
-                               default:
-                                       ves_exec_method (&child_frame);
-                               }
-                       }
+                       ves_exec_method_with_context (&child_frame, context);
 
-                       while (endsp > sp) {
-                               --endsp;
-                               vt_free (endsp);
-                       }
+                       context->current_frame = frame;
 
                        if (child_frame.ex) {
                                /*
@@ -1736,893 +1643,942 @@ ves_exec_method (MonoInvocation *frame)
 
                        /* need to handle typedbyref ... */
                        if (csignature->ret->type != MONO_TYPE_VOID) {
-                               *sp = retval;
+                               *sp = *endsp;
                                sp++;
                        }
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_RET)
-                       if (signature->ret->type != MONO_TYPE_VOID) {
-                               --sp;
-                               if (sp->type == VAL_VALUET) {
-                                       /* the caller has already allocated the memory */
-                                       stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt, signature->pinvoke);
-                                       vt_free (sp);
-                               } else {
-                                       *frame->retval = *sp;
-                               }
-                       }
-                       if (sp > frame->stack)
-                               g_warning ("more values on stack: %d", sp-frame->stack);
+               MINT_IN_CASE(MINT_CALLI_NAT) {
+                       MonoMethodSignature *csignature;
+                       stackval *endsp = sp;
+                       unsigned char *code = NULL;
 
-                       DEBUG_LEAVE ();
-                       return;
-               CASE (CEE_BR_S) /* Fall through */
-               CASE (CEE_BR)
-                       if (*ip == CEE_BR) {
-                               ++ip;
-                               ip += (gint32) read32(ip);
-                               ip += 4;
+                       frame->ip = ip;
+                       
+                       csignature = rtm->data_items [* (guint16 *)(ip + 1)];
+                       ip += 2;
+                       --sp;
+                       --endsp;
+                       code = sp->data.p;
+                       child_frame.runtime_method = NULL;
+
+                       sp->data.p = vt_sp;
+                       child_frame.retval = sp;
+                       /* decrement by the actual number of args */
+                       sp -= csignature->param_count;
+                       child_frame.stack_args = sp;
+                       if (csignature->hasthis) {
+                               --sp;
+                               child_frame.obj = sp->data.p;
                        } else {
-                               ++ip;
-                               ip += (signed char) *ip;
-                               ++ip;
+                               child_frame.obj = NULL;
                        }
-                       BREAK;
-               CASE (CEE_BRFALSE) /* Fall through */
-               CASE (CEE_BRFALSE_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BRFALSE_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+                       ves_pinvoke_method (&child_frame, csignature, (MonoFunc) code, FALSE, context);
+
+                       context->current_frame = frame;
+
+                       if (child_frame.ex) {
+                               /*
+                                * An exception occurred, need to run finally, fault and catch handlers..
+                                */
+                               frame->ex = child_frame.ex;
+                               if (context->search_for_handler) {
+                                       context->search_for_handler = 0;
+                                       goto handle_exception;
+                               }
+                               goto handle_finally;
                        }
-                       --sp;
-                       switch (sp->type) {
-                       case VAL_I32: result = sp->data.i == 0; break;
-                       case VAL_I64: result = sp->data.l == 0; break;
-                       case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
-                       default: result = sp->data.p == NULL; break;
+
+                       /* need to handle typedbyref ... */
+                       if (csignature->ret->type != MONO_TYPE_VOID) {
+                               *sp = *endsp;
+                               sp++;
                        }
-                       if (result)
-                               ip += broffset;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_BRTRUE) /* Fall through */
-               CASE (CEE_BRTRUE_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BRTRUE_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
+               MINT_IN_CASE(MINT_CALL) {
+                       stackval *endsp = sp;
+
+                       frame->ip = ip;
+                       
+                       child_frame.runtime_method = 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;
+                       child_frame.stack_args = sp;
+                       if (child_frame.runtime_method->hasthis) {
+                               --sp;
+                               child_frame.obj = sp->data.p;
                        } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+                               child_frame.obj = NULL;
                        }
-                       --sp;
-                       switch (sp->type) {
-                       case VAL_I32: result = sp->data.i != 0; break;
-                       case VAL_I64: result = sp->data.l != 0; break;
-                       case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
-                       default: result = sp->data.p != NULL; break;
+                       if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->valuetype &&
+                                       ((MonoObject *)child_frame.obj)->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               child_frame.runtime_method = mono_interp_get_runtime_method (
+                                                               mono_marshal_get_remoting_invoke (child_frame.runtime_method->method));
                        }
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_BEQ) /* Fall through */
-               CASE (CEE_BEQ_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BEQ_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+                       ves_exec_method_with_context (&child_frame, context);
+
+                       context->current_frame = frame;
+
+                       if (child_frame.ex) {
+                               /*
+                                * An exception occurred, need to run finally, fault and catch handlers..
+                                */
+                               frame->ex = child_frame.ex;
+                               goto handle_finally;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = sp [0].data.i == (gint)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = sp [0].data.l == sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = sp [0].data.f == sp [1].data.f;
-                       else
-                               result = (gint)GET_NATI (sp [0]) == (gint)GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
+
+                       /* need to handle typedbyref ... */
+                       *sp = *endsp;
+                       sp++;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_BGE) /* Fall through */
-               CASE (CEE_BGE_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BGE_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
+               MINT_IN_CASE(MINT_VCALL) {
+                       frame->ip = ip;
+                       
+                       child_frame.runtime_method = 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;
+                       child_frame.stack_args = sp;
+                       if (child_frame.runtime_method->hasthis) {
+                               --sp;
+                               child_frame.obj = sp->data.p;
                        } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+                               child_frame.obj = NULL;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = sp [0].data.i >= (gint)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = sp [0].data.l >= sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = sp [0].data.f >= sp [1].data.f;
-                       else
-                               result = (gint)GET_NATI (sp [0]) >= (gint)GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_BGT) /* Fall through */
-               CASE (CEE_BGT_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BGT_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+
+                       if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->valuetype &&
+                                       ((MonoObject *)child_frame.obj)->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               child_frame.runtime_method = mono_interp_get_runtime_method (
+                                                               mono_marshal_get_remoting_invoke (child_frame.runtime_method->method));
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = sp [0].data.i > (gint)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = sp [0].data.l > sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = sp [0].data.f > sp [1].data.f;
-                       else
-                               result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_BLT) /* Fall through */
-               CASE (CEE_BLT_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BLT_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+
+                       ves_exec_method_with_context (&child_frame, context);
+
+                       context->current_frame = frame;
+
+                       if (child_frame.ex) {
+                               /*
+                                * An exception occurred, need to run finally, fault and catch handlers..
+                                */
+                               frame->ex = child_frame.ex;
+                               goto handle_finally;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = sp[0].data.i < (gint)GET_NATI(sp[1]);
-                       else if (sp->type == VAL_I64)
-                               result = sp[0].data.l < sp[1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = sp[0].data.f < sp[1].data.f;
-                       else
-                               result = (gint)GET_NATI(sp[0]) < (gint)GET_NATI(sp[1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_BLE) /* fall through */
-               CASE (CEE_BLE_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BLE_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+               MINT_IN_CASE(MINT_CALLVIRT) {
+                       stackval *endsp = sp;
+                       MonoObject *this_arg;
+                       guint32 token;
+
+                       frame->ip = ip;
+                       
+                       token = * (unsigned short *)(ip + 1);
+                       ip += 2;
+                       child_frame.runtime_method = 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;
+                       child_frame.stack_args = sp;
+                       --sp;
+                       child_frame.obj = this_arg = sp->data.p;
+                       if (!this_arg)
+                               THROW_EX (mono_get_exception_null_reference(), ip - 2);
+                       child_frame.runtime_method = get_virtual_method (child_frame.runtime_method, this_arg);
+
+                       if (this_arg->vtable->klass->valuetype && child_frame.runtime_method->valuetype) {
+                               child_frame.obj = (char *)this_arg + sizeof(MonoObject);
                        }
-                       sp -= 2;
 
-                       if (sp->type == VAL_I32)
-                               result = sp [0].data.i <= (gint)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = sp [0].data.l <= sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = sp [0].data.f <= sp [1].data.f;
-                       else {
+                       ves_exec_method_with_context (&child_frame, context);
+
+                       context->current_frame = frame;
+
+                       if (child_frame.ex) {
                                /*
-                                * FIXME: here and in other places GET_NATI on the left side 
-                                * _will_ be wrong when we change the macro to work on 64 bits 
-                                * systems.
+                                * An exception occurred, need to run finally, fault and catch handlers..
                                 */
-                               result = (gint)GET_NATI (sp [0]) <= (gint)GET_NATI (sp [1]);
-                       }
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_BNE_UN) /* Fall through */
-               CASE (CEE_BNE_UN_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BNE_UN_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+                               frame->ex = child_frame.ex;
+                               if (context->search_for_handler) {
+                                       context->search_for_handler = 0;
+                                       goto handle_exception;
+                               }
+                               goto handle_finally;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = (guint32)sp [0].data.i != (guint32)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = (guint64)sp [0].data.l != (guint64)sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = isunordered (sp [0].data.f, sp [1].data.f) ||
-                                       (sp [0].data.f != sp [1].data.f);
-                       else
-                               result = GET_NATI (sp [0]) != GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
+
+                       /* need to handle typedbyref ... */
+                       *sp = *endsp;
+                       sp++;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_BGE_UN) /* Fall through */
-               CASE (CEE_BGE_UN_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BGE_UN_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+               MINT_IN_CASE(MINT_VCALLVIRT) {
+                       MonoObject *this_arg;
+                       guint32 token;
+
+                       frame->ip = ip;
+                       
+                       token = * (unsigned short *)(ip + 1);
+                       ip += 2;
+                       child_frame.runtime_method = 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;
+                       child_frame.stack_args = sp;
+                       --sp;
+                       child_frame.obj = this_arg = sp->data.p;
+                       if (!this_arg)
+                               THROW_EX (mono_get_exception_null_reference(), ip - 2);
+                       child_frame.runtime_method = get_virtual_method (child_frame.runtime_method, this_arg);
+
+                       if (this_arg->vtable->klass->valuetype && child_frame.runtime_method->valuetype) {
+                               child_frame.obj = (char *)this_arg + sizeof(MonoObject);
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = (guint32)sp [0].data.i >= (guint32)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = (guint64)sp [0].data.l >= (guint64)sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = !isless (sp [0].data.f,sp [1].data.f);
-                       else
-                               result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_BGT_UN) /* Fall through */
-               CASE (CEE_BGT_UN_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BGT_UN_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+
+                       ves_exec_method_with_context (&child_frame, context);
+
+                       context->current_frame = frame;
+
+                       if (child_frame.ex) {
+                               /*
+                                * An exception occurred, need to run finally, fault and catch handlers..
+                                */
+                               frame->ex = child_frame.ex;
+                               if (context->search_for_handler) {
+                                       context->search_for_handler = 0;
+                                       goto handle_exception;
+                               }
+                               goto handle_finally;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = (guint32)sp [0].data.i > (guint32)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = isgreater (sp [0].data.f, sp [1].data.f);
-                       else
-                               result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_BLE_UN) /* Fall through */
-               CASE (CEE_BLE_UN_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BLE_UN_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+               MINT_IN_CASE(MINT_CALLINT)
+                       ves_pinvoke_method (frame, mono_method_signature (frame->runtime_method->method), ((MonoMethodPInvoke*) frame->runtime_method->method)->addr, 
+                                   frame->runtime_method->method->string_ctor, context);
+                       if (frame->ex) {
+                               rtm = NULL;
+                               goto handle_exception;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = (guint32)sp [0].data.i <= (guint32)GET_NATI (sp [1]);
-                       else if (sp->type == VAL_I64)
-                               result = (guint64)sp [0].data.l <= (guint64)sp [1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = islessequal (sp [0].data.f, sp [1].data.f);
-                       else
-                               result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_BLT_UN) /* Fall through */
-               CASE (CEE_BLT_UN_S) {
-                       int result;
-                       int broffset;
-                       if (*ip == CEE_BLT_UN_S) {
-                               broffset = (signed char)ip [1];
-                               ip += 2;
-                       } else {
-                               broffset = (gint32) read32 (ip + 1);
-                               ip += 5;
+                       goto exit_frame;
+               MINT_IN_CASE(MINT_CALLRUN)
+                       ves_runtime_method (frame, context);
+                       if (frame->ex) {
+                               rtm = NULL;
+                               goto handle_exception;
                        }
-                       sp -= 2;
-                       if (sp->type == VAL_I32)
-                               result = (guint32)sp[0].data.i < (guint32)GET_NATI(sp[1]);
-                       else if (sp->type == VAL_I64)
-                               result = (guint64)sp[0].data.l < (guint64)sp[1].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               result = isunordered (sp [0].data.f, sp [1].data.f) ||
-                                       (sp [0].data.f < sp [1].data.f);
-                       else
-                               result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
-                       if (result)
-                               ip += broffset;
-                       BREAK;
-               }
-               CASE (CEE_SWITCH) {
+                       goto exit_frame;
+               MINT_IN_CASE(MINT_RET)
+                       --sp;
+                       *frame->retval = *sp;
+                       if (sp > frame->stack)
+                               g_warning ("ret: more values on stack: %d", sp-frame->stack);
+                       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);
+                       goto exit_frame;
+               MINT_IN_CASE(MINT_RET_VT)
+                       i32 = READ32(ip + 1);
+                       --sp;
+                       memcpy(frame->retval->data.p, sp->data.p, i32);
+                       if (sp > frame->stack)
+                               g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
+                       goto exit_frame;
+               MINT_IN_CASE(MINT_BR_S)
+                       ip += (short) *(ip + 1);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BR)
+                       ip += (gint32) READ32(ip + 1);
+                       MINT_IN_BREAK;
+#define ZEROP_S(datamem, op) \
+       --sp; \
+       if (sp->data.datamem op 0) \
+               ip += * (gint16 *)(ip + 1); \
+       else \
+               ip += 2;
+
+#define ZEROP(datamem, op) \
+       --sp; \
+       if (sp->data.datamem op 0) \
+               ip += READ32(ip + 1); \
+       else \
+               ip += 3;
+
+               MINT_IN_CASE(MINT_BRFALSE_I4_S)
+                       ZEROP_S(i, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRFALSE_I8_S)
+                       ZEROP_S(l, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRFALSE_R8_S)
+                       ZEROP_S(f, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRFALSE_I4)
+                       ZEROP(i, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRFALSE_I8)
+                       ZEROP(l, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRFALSE_R8)
+                       ZEROP_S(f, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRTRUE_I4_S)
+                       ZEROP_S(i, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRTRUE_I8_S)
+                       ZEROP_S(l, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRTRUE_R8_S)
+                       ZEROP_S(f, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRTRUE_I4)
+                       ZEROP(i, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRTRUE_I8)
+                       ZEROP(l, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BRTRUE_R8)
+                       ZEROP(f, !=);
+                       MINT_IN_BREAK;
+#define CONDBR_S(cond) \
+       sp -= 2; \
+       if (cond) \
+               ip += * (gint16 *)(ip + 1); \
+       else \
+               ip += 2;
+#define BRELOP_S(datamem, op) \
+       CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
+
+#define CONDBR(cond) \
+       sp -= 2; \
+       if (cond) \
+               ip += READ32(ip + 1); \
+       else \
+               ip += 3;
+
+#define BRELOP(datamem, op) \
+       CONDBR(sp[0].data.datamem op sp[1].data.datamem)
+
+               MINT_IN_CASE(MINT_BEQ_I4_S)
+                       BRELOP_S(i, ==)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BEQ_I8_S)
+                       BRELOP_S(l, ==)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BEQ_R8_S)
+                       CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BEQ_I4)
+                       BRELOP(i, ==)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BEQ_I8)
+                       BRELOP(l, ==)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BEQ_R8)
+                       CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_I4_S)
+                       BRELOP_S(i, >=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_I8_S)
+                       BRELOP_S(l, >=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_R8_S)
+                       CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_I4)
+                       BRELOP(i, >=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_I8)
+                       BRELOP(l, >=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_R8)
+                       CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_I4_S)
+                       BRELOP_S(i, >)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_I8_S)
+                       BRELOP_S(l, >)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_R8_S)
+                       CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_I4)
+                       BRELOP(i, >)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_I8)
+                       BRELOP(l, >)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_R8)
+                       CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_I4_S)
+                       BRELOP_S(i, <)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_I8_S)
+                       BRELOP_S(l, <)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_R8_S)
+                       CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_I4)
+                       BRELOP(i, <)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_I8)
+                       BRELOP(l, <)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_R8)
+                       CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_I4_S)
+                       BRELOP_S(i, <=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_I8_S)
+                       BRELOP_S(l, <=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_R8_S)
+                       CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_I4)
+                       BRELOP(i, <=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_I8)
+                       BRELOP(l, <=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_R8)
+                       CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BNE_UN_I4_S)
+                       BRELOP_S(i, !=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BNE_UN_I8_S)
+                       BRELOP_S(l, !=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BNE_UN_R8_S)
+                       CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BNE_UN_I4)
+                       BRELOP(i, !=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BNE_UN_I8)
+                       BRELOP(l, !=)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BNE_UN_R8)
+                       CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
+                       MINT_IN_BREAK;
+
+#define BRELOP_S_CAST(datamem, op, type) \
+       sp -= 2; \
+       if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
+               ip += * (gint16 *)(ip + 1); \
+       else \
+               ip += 2;
+
+#define BRELOP_CAST(datamem, op, type) \
+       sp -= 2; \
+       if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
+               ip += READ32(ip + 1); \
+       else \
+               ip += 3;
+
+               MINT_IN_CASE(MINT_BGE_UN_I4_S)
+                       BRELOP_S_CAST(i, >=, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_UN_I8_S)
+                       BRELOP_S_CAST(l, >=, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_UN_R8_S)
+                       CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_UN_I4)
+                       BRELOP_CAST(i, >=, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_UN_I8)
+                       BRELOP_CAST(l, >=, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGE_UN_R8)
+                       CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_UN_I4_S)
+                       BRELOP_S_CAST(i, >, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_UN_I8_S)
+                       BRELOP_S_CAST(l, >, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_UN_R8_S)
+                       CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_UN_I4)
+                       BRELOP_CAST(i, >, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_UN_I8)
+                       BRELOP_CAST(l, >, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BGT_UN_R8)
+                       CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_UN_I4_S)
+                       BRELOP_S_CAST(i, <=, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_UN_I8_S)
+                       BRELOP_S_CAST(l, <=, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_UN_R8_S)
+                       CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_UN_I4)
+                       BRELOP_CAST(i, <=, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_UN_I8)
+                       BRELOP_CAST(l, <=, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLE_UN_R8)
+                       CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_UN_I4_S)
+                       BRELOP_S_CAST(i, <, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_UN_I8_S)
+                       BRELOP_S_CAST(l, <, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_UN_R8_S)
+                       CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_UN_I4)
+                       BRELOP_CAST(i, <, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_UN_I8)
+                       BRELOP_CAST(l, <, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BLT_UN_R8)
+                       CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SWITCH) {
                        guint32 n;
-                       const unsigned char *st;
+                       const unsigned short *st;
                        ++ip;
-                       n = read32 (ip);
-                       ip += 4;
-                       st = ip + sizeof (gint32) * n;
+                       n = READ32 (ip);
+                       ip += 2;
+                       st = ip + 2 * n;
                        --sp;
                        if ((guint32)sp->data.i < n) {
                                gint offset;
-                               ip += sizeof (gint32) * (guint32)sp->data.i;
-                               offset = read32 (ip);
+                               ip += 2 * (guint32)sp->data.i;
+                               offset = READ32 (ip);
                                ip = st + offset;
                        } else {
                                ip = st;
                        }
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDIND_I1)
+               MINT_IN_CASE(MINT_LDIND_I1)
                        ++ip;
-                       sp[-1].type = VAL_I32;
                        sp[-1].data.i = *(gint8*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_U1)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_U1)
                        ++ip;
-                       sp[-1].type = VAL_I32;
                        sp[-1].data.i = *(guint8*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_I2)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_I2)
                        ++ip;
-                       sp[-1].type = VAL_I32;
                        sp[-1].data.i = *(gint16*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_U2)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_U2)
                        ++ip;
-                       sp[-1].type = VAL_I32;
                        sp[-1].data.i = *(guint16*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_I4) /* Fall through */
-               CASE (CEE_LDIND_U4)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
+               MINT_IN_CASE(MINT_LDIND_U4)
                        ++ip;
-                       sp[-1].type = VAL_I32;
                        sp[-1].data.i = *(gint32*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_I8)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_I8)
                        ++ip;
-                       sp[-1].type = VAL_I64;
                        sp[-1].data.l = *(gint64*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_I)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_I)
                        ++ip;
-                       sp[-1].type = VAL_NATI;
                        sp[-1].data.p = *(gpointer*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_R4)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_R4)
                        ++ip;
-                       sp[-1].type = VAL_DOUBLE;
                        sp[-1].data.f = *(gfloat*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_R8)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_R8)
                        ++ip;
-                       sp[-1].type = VAL_DOUBLE;
                        sp[-1].data.f = *(gdouble*)sp[-1].data.p;
-                       BREAK;
-               CASE (CEE_LDIND_REF)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDIND_REF)
                        ++ip;
-                       sp[-1].type = VAL_OBJ;
                        sp[-1].data.p = *(gpointer*)sp[-1].data.p;
-                       sp[-1].data.vt.klass = NULL;
-                       BREAK;
-               CASE (CEE_STIND_REF) {
-                       gpointer *p;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_REF) 
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = sp[1].data.p;
-                       BREAK;
-               }
-               CASE (CEE_STIND_I1) {
-                       gint8 *p;
+                       * (gpointer *) sp->data.p = sp[1].data.p;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_I1)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = (gint8)sp[1].data.i;
-                       BREAK;
-               }
-               CASE (CEE_STIND_I2) {
-                       gint16 *p;
+                       * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_I2)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = (gint16)sp[1].data.i;
-                       BREAK;
-               }
-               CASE (CEE_STIND_I4) {
-                       gint32 *p;
+                       * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_I4)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = sp[1].data.i;
-                       BREAK;
-               }
-               CASE (CEE_STIND_I) {
-                       mono_i *p;
+                       * (gint32 *) sp->data.p = sp[1].data.i;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_I)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = (mono_i)sp[1].data.p;
-                       BREAK;
-               }
-               CASE (CEE_STIND_I8) {
-                       gint64 *p;
+                       * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_I8)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = sp[1].data.l;
-                       BREAK;
-               }
-               CASE (CEE_STIND_R4) {
-                       float *p;
+                       * (gint64 *) sp->data.p = sp[1].data.l;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_R4)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = (gfloat)sp[1].data.f;
-                       BREAK;
-               }
-               CASE (CEE_STIND_R8) {
-                       double *p;
+                       * (float *) sp->data.p = (gfloat)sp[1].data.f;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STIND_R8)
                        ++ip;
                        sp -= 2;
-                       p = sp->data.p;
-                       *p = sp[1].data.f;
-                       BREAK;
-               }
-               CASE (CEE_ADD)
+                       * (double *) sp->data.p = sp[1].data.f;
+                       MINT_IN_BREAK;
+#define BINOP(datamem, op) \
+       --sp; \
+       sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
+       ++ip;
+               MINT_IN_CASE(MINT_ADD_I4)
+                       BINOP(i, +);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD_I8)
+                       BINOP(l, +);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD_R8)
+                       BINOP(f, +);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD1_I4)
+                       ++sp [-1].data.i;
                        ++ip;
-                       --sp;
-                       /* should probably consider the pointers as unsigned */
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i += GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l += sp [0].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f += sp [0].data.f;
-                       else {
-                               char *p = sp [-1].data.p;
-                               p += GET_NATI (sp [0]);
-                               sp [-1].data.p = p;
-                       }
-                       BREAK;
-               CASE (CEE_SUB)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_I4)
+                       BINOP(i, -);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_I8)
+                       BINOP(l, -);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_R8)
+                       BINOP(f, -);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB1_I4)
+                       --sp [-1].data.i;
                        ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_I4)
+                       BINOP(i, *);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_I8)
+                       BINOP(l, *);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_R8)
+                       BINOP(f, *);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_DIV_I4)
+                       if (sp [-1].data.i == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP(i, /);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_DIV_I8)
+                       if (sp [-1].data.l == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP(l, /);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_DIV_R8)
+                       BINOP(f, /);
+                       MINT_IN_BREAK;
+
+#define BINOP_CAST(datamem, op, type) \
+       --sp; \
+       sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
+       ++ip;
+               MINT_IN_CASE(MINT_DIV_UN_I4)
+                       if (sp [-1].data.i == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP_CAST(i, /, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_DIV_UN_I8)
+                       if (sp [-1].data.l == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP_CAST(l, /, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_REM_I4)
+                       if (sp [-1].data.i == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP(i, %);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_REM_I8)
+                       if (sp [-1].data.l == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP(l, %);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_REM_R8)
+                       /* FIXME: what do we actually do here? */
                        --sp;
-                       /* should probably consider the pointers as unsigned */
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i -= GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l -= sp [0].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f -= sp [0].data.f;
-                       else {
-                               char *p = sp [-1].data.p;
-                               p -= GET_NATI (sp [0]);
-                               sp [-1].data.p = p;
-                       }
-                       BREAK;
-               CASE (CEE_MUL)
+                       sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
                        ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_REM_UN_I4)
+                       if (sp [-1].data.i == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP_CAST(i, %, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_REM_UN_I8)
+                       if (sp [-1].data.l == 0)
+                               THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       BINOP_CAST(l, %, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_AND_I4)
+                       BINOP(i, &);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_AND_I8)
+                       BINOP(l, &);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_OR_I4)
+                       BINOP(i, |);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_OR_I8)
+                       BINOP(l, |);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_XOR_I4)
+                       BINOP(i, ^);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_XOR_I8)
+                       BINOP(l, ^);
+                       MINT_IN_BREAK;
+
+#define SHIFTOP(datamem, op) \
+       --sp; \
+       sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
+       ++ip;
+
+               MINT_IN_CASE(MINT_SHL_I4)
+                       SHIFTOP(i, <<);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SHL_I8)
+                       SHIFTOP(l, <<);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SHR_I4)
+                       SHIFTOP(i, >>);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SHR_I8)
+                       SHIFTOP(l, >>);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SHR_UN_I4)
                        --sp;
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i *= (gint)GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l *= sp [0].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f *= sp [0].data.f;
-                       BREAK;
-               CASE (CEE_DIV)
+                       sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
                        ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SHR_UN_I8)
                        --sp;
-                       if (sp->type == VAL_I32) {
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               sp [-1].data.i /= (gint)GET_NATI (sp [0]);
-                       } else if (sp->type == VAL_I64) {
-                               if (sp [0].data.l == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               sp [-1].data.l /= sp [0].data.l;
-                       } else if (sp->type == VAL_DOUBLE) {
-                               /* set NaN is divisor is 0.0 */
-                               sp [-1].data.f /= sp [0].data.f;
-                       }
-                       BREAK;
-               CASE (CEE_DIV_UN)
+                       sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32) {
-                               guint32 val;
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               val = sp [-1].data.i;
-                               val /= (guint32)GET_NATI (sp [0]);
-                               sp [-1].data.i = val;
-                       } else if (sp->type == VAL_I64) {
-                               guint64 val;
-                               if (sp [0].data.l == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               val = sp [-1].data.l;
-                               val /= (guint64)sp [0].data.l;
-                               sp [-1].data.l = val;
-                       } else if (sp->type == VAL_NATI) {
-                               mono_u val;
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               val = (mono_u)sp [-1].data.p;
-                               val /= (mono_u)sp [0].data.p;
-                               sp [-1].data.p = (gpointer)val;
-                       }
-                       BREAK;
-               CASE (CEE_REM)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NEG_I4)
+                       sp [-1].data.i = - sp [-1].data.i;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32) {
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               sp [-1].data.i %= (gint)GET_NATI (sp [0]);
-                       } else if (sp->type == VAL_I64) {
-                               if (sp [0].data.l == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               sp [-1].data.l %= sp [0].data.l;
-                       } else if (sp->type == VAL_DOUBLE) {
-                               /* FIXME: what do we actually do here? */
-                               sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
-                       } else {
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               (gint)GET_NATI (sp [-1]) %= (gint)GET_NATI (sp [0]);
-                       }
-                       BREAK;
-               CASE (CEE_REM_UN)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NEG_I8)
+                       sp [-1].data.l = - sp [-1].data.l;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32) {
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               (guint)sp [-1].data.i %= (guint)GET_NATI (sp [0]);
-                       } else if (sp->type == VAL_I64) {
-                               if (sp [0].data.l == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               (guint64)sp [-1].data.l %= (guint64)sp [0].data.l;
-                       } else if (sp->type == VAL_DOUBLE) {
-                               /* unspecified behaviour according to the spec */
-                       } else {
-                               if (GET_NATI (sp [0]) == 0)
-                                       THROW_EX (mono_get_exception_divide_by_zero (), ip - 1);
-                               (guint64)GET_NATI (sp [-1]) %= (guint64)GET_NATI (sp [0]);
-                       }
-                       BREAK;
-               CASE (CEE_AND)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NEG_R8)
+                       sp [-1].data.f = - sp [-1].data.f;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i &= GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l &= sp [0].data.l;
-                       else
-                               GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
-                       BREAK;
-               CASE (CEE_OR)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NOT_I4)
+                       sp [-1].data.i = ~ sp [-1].data.i;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i |= GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l |= sp [0].data.l;
-                       else
-                               GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
-                       BREAK;
-               CASE (CEE_XOR)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NOT_I8)
+                       sp [-1].data.l = ~ sp [-1].data.l;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i ^= GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l ^= sp [0].data.l;
-                       else
-                               GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
-                       BREAK;
-               CASE (CEE_SHL)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I1_I4)
+                       sp [-1].data.i = (gint8)sp [-1].data.i;
                        ++ip;
-                       --sp;
-                       if (sp [-1].type == VAL_I32)
-                               sp [-1].data.i <<= GET_NATI (sp [0]);
-                       else if (sp [-1].type == VAL_I64)
-                               sp [-1].data.l <<= GET_NATI (sp [0]);
-                       else
-                               GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
-                       BREAK;
-               CASE (CEE_SHR)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I1_I8)
+                       sp [-1].data.i = (gint8)sp [-1].data.l;
                        ++ip;
-                       --sp;
-                       if (sp [-1].type == VAL_I32)
-                               sp [-1].data.i >>= GET_NATI (sp [0]);
-                       else if (sp [-1].type == VAL_I64)
-                               sp [-1].data.l >>= GET_NATI (sp [0]);
-                       else
-                               (gint)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
-                       BREAK;
-               CASE (CEE_SHR_UN)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I1_R8)
+                       sp [-1].data.i = (gint8)sp [-1].data.f;
                        ++ip;
-                       --sp;
-                       if (sp [-1].type == VAL_I32)
-                               (guint)sp [-1].data.i >>= GET_NATI (sp [0]);
-                       else if (sp [-1].type == VAL_I64)
-                               (guint64)sp [-1].data.l >>= GET_NATI (sp [0]);
-                       else
-                               (guint64)GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
-                       BREAK;
-               CASE (CEE_NEG)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U1_I4)
+                       sp [-1].data.i = (guint8)sp [-1].data.i;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32) 
-                               sp->data.i = - sp->data.i;
-                       else if (sp->type == VAL_I64)
-                               sp->data.l = - sp->data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               sp->data.f = - sp->data.f;
-                       else if (sp->type == VAL_NATI)
-                               sp->data.p = (gpointer)(- (mono_i)sp->data.p);
-                       ++sp;
-                       BREAK;
-               CASE (CEE_NOT)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U1_I8)
+                       sp [-1].data.i = (guint8)sp [-1].data.l;
                        ++ip;
-                       --sp;
-                       if (sp->type == VAL_I32)
-                               sp->data.i = ~ sp->data.i;
-                       else if (sp->type == VAL_I64)
-                               sp->data.l = ~ sp->data.l;
-                       else if (sp->type == VAL_NATI)
-                               sp->data.p = (gpointer)(~ (mono_i)sp->data.p);
-                       ++sp;
-                       BREAK;
-               CASE (CEE_CONV_U1) /* fall through */
-               CASE (CEE_CONV_I1) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U1_R8)
+                       sp [-1].data.i = (guint8)sp [-1].data.f;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               sp [-1].data.i = (gint8)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               sp [-1].data.i = (gint8)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.i = (gint8)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.i = (gint8)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_I32;
-                       BREAK;
-               }
-               CASE (CEE_CONV_U2) /* fall through */
-               CASE (CEE_CONV_I2) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I2_I4)
+                       sp [-1].data.i = (gint16)sp [-1].data.i;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               sp [-1].data.i = (gint16)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               sp [-1].data.i = (gint16)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.i = (gint16)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.i = (gint16)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_I32;
-                       BREAK;
-               }
-               CASE (CEE_CONV_U4) /* Fall through */
-#if SIZEOF_VOID_P == 4
-               CASE (CEE_CONV_I) /* Fall through */
-               CASE (CEE_CONV_U) /* Fall through */
-#endif
-               CASE (CEE_CONV_I4) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I2_I8)
+                       sp [-1].data.i = (gint16)sp [-1].data.l;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               sp [-1].data.i = (gint32)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               sp [-1].data.i = (gint32)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               break;
-                       default:
-                               sp [-1].data.i = (gint32)sp [-1].data.p;
-                               break;
-                       }
-                       sp [-1].type = VAL_I32;
-                       BREAK;
-               }
-#if SIZEOF_VOID_P == 8
-               CASE (CEE_CONV_I) /* Fall through */
-#endif
-               CASE (CEE_CONV_I8)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I2_R8)
+                       sp [-1].data.i = (gint16)sp [-1].data.f;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               sp [-1].data.l = (gint64)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.l = (gint64)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.l = (gint64)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_I64;
-                       BREAK;
-               CASE (CEE_CONV_R4) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U2_I4)
+                       sp [-1].data.i = (guint16)sp [-1].data.i;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               sp [-1].data.f = (float)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               sp [-1].data.f = (float)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.f = (float)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.f = (float)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_DOUBLE;
-                       BREAK;
-               }
-               CASE (CEE_CONV_R8) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U2_I8)
+                       sp [-1].data.i = (guint16)sp [-1].data.l;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               sp [-1].data.f = (double)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               sp [-1].data.f = (double)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.f = (double)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.f = (double)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_DOUBLE;
-                       BREAK;
-               }
-#if SIZEOF_VOID_P == 8
-               CASE (CEE_CONV_U) /* Fall through */
-#endif
-               CASE (CEE_CONV_U8)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U2_R8)
+                       sp [-1].data.i = (guint16)sp [-1].data.f;
                        ++ip;
-
-                       switch (sp [-1].type){
-                       case VAL_DOUBLE:
-                               sp [-1].data.l = (guint64)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.l = sp [-1].data.i & 0xffffffff;
-                               break;
-                       default:
-                               sp [-1].data.l = (guint64) sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_I64;
-                       BREAK;
-               CASE (CEE_CPOBJ) {
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I4_R8)
+                       sp [-1].data.i = (gint32)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U4_I8)
+               MINT_IN_CASE(MINT_CONV_I4_I8)
+                       sp [-1].data.i = (gint32)sp [-1].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I4_I8_SP)
+                       sp [-2].data.i = (gint32)sp [-2].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U4_R8)
+                       sp [-1].data.i = (guint32)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I8_I4)
+                       sp [-1].data.l = sp [-1].data.i;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I8_I4_SP)
+                       sp [-2].data.l = sp [-2].data.i;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I8_U4)
+                       sp [-1].data.l = (guint32)sp [-1].data.i;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_I8_R8)
+                       sp [-1].data.l = (gint64)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R4_I4)
+                       sp [-1].data.f = (float)sp [-1].data.i;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R4_I8)
+                       sp [-1].data.f = (float)sp [-1].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R4_R8)
+                       sp [-1].data.f = (float)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R8_I4)
+                       sp [-1].data.f = (double)sp [-1].data.i;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R8_I8)
+                       sp [-1].data.f = (double)sp [-1].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U8_I4)
+                       sp [-1].data.l = sp [-1].data.i & 0xffffffff;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_U8_R8)
+                       sp [-1].data.l = (guint64)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+#if 0
+               MINT_IN_CASE(MINT_CPOBJ) {
                        MonoClass *vtklass;
                        ++ip;
-                       vtklass = mono_class_get (image, read32 (ip));
-                       ip += 4;
+                       vtklass = rtm->data_items[READ32 (ip)];
+                       ip += 2;
                        sp -= 2;
                        memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDOBJ) {
-                       guint32 token;
-                       MonoClass *c;
-                       char *addr;
-
-                       ++ip;
-                       token = read32 (ip);
-                       ip += 4;
-
-                       if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
-                               c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
-                       else
-                               c = mono_class_get (image, token);
-
-                       addr = sp [-1].data.vt.vt;
-                       vt_alloc (&c->byval_arg, &sp [-1], FALSE);
-                       stackval_from_data (&c->byval_arg, &sp [-1], addr, FALSE);
-                       BREAK;
+#endif
+               MINT_IN_CASE(MINT_LDOBJ) {
+                       int size;
+                       void *p;
+                       c = rtm->data_items[* (guint16 *)(ip + 1)];
+                       ip += 2;
+                       if (c->byval_arg.type != MONO_TYPE_VALUETYPE || c->byval_arg.data.klass->enumtype) {
+                               p = sp [-1].data.p;
+                               stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
+                       } else {
+                               size = mono_class_value_size (c, NULL);
+                               p = sp [-1].data.p;
+                               sp [-1].data.p = vt_sp;
+                               memcpy(vt_sp, p, size);
+                               vt_sp += (size + 7) & ~7;
+                       }
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDSTR) {
-                       MonoObject *o;
-                       guint32 str_index;
-
-                       ip++;
-                       str_index = mono_metadata_token_index (read32 (ip));
-                       ip += 4;
-
-                       o = (MonoObject*)mono_ldstr (domain, image, str_index);
-                       sp->type = VAL_OBJ;
-                       sp->data.p = o;
-                       sp->data.vt.klass = NULL;
-
+               MINT_IN_CASE(MINT_LDSTR)
+                       sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
                        ++sp;
-                       BREAK;
-               }
-               CASE (CEE_NEWOBJ) {
-                       MonoObject *o;
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NEWOBJ) {
                        MonoClass *newobj_class;
                        MonoMethodSignature *csig;
                        stackval valuetype_this;
-                       stackval *endsp = sp;
                        guint32 token;
                        stackval retval;
 
                        frame->ip = ip;
 
-                       ip++;
-                       token = read32 (ip);
-                       ip += 4;
-
-                       if (!(child_frame.method = mono_get_method (image, token, NULL)))
-                               THROW_EX (mono_get_exception_missing_method (), ip -5);
+                       token = * (guint16 *)(ip + 1);
+                       ip += 2;
 
-                       csig = child_frame.method->signature;
-                       newobj_class = child_frame.method->klass;
+                       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;
                        /*if (profiling_classes) {
                                guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
                                count++;
@@ -2632,7 +2588,7 @@ ves_exec_method (MonoInvocation *frame)
 
                        if (newobj_class->parent == mono_defaults.array_class) {
                                sp -= csig->param_count;
-                               o = ves_array_create (domain, newobj_class, csig, sp);
+                               o = ves_array_create (context->domain, newobj_class, csig, sp);
                                goto array_constructed;
                        }
 
@@ -2640,20 +2596,20 @@ ves_exec_method (MonoInvocation *frame)
                         * First arg is the object.
                         */
                        if (newobj_class->valuetype) {
-                               void *zero;
-                               vt_alloc (&newobj_class->byval_arg, &valuetype_this, csig->pinvoke);
                                if (!newobj_class->enumtype && (newobj_class->byval_arg.type == MONO_TYPE_VALUETYPE)) {
-                                       zero = valuetype_this.data.vt.vt;
-                                       child_frame.obj = valuetype_this.data.vt.vt;
+                                       child_frame.obj = vt_sp;
+                                       valuetype_this.data.p = vt_sp;
                                } else {
                                        memset (&valuetype_this, 0, sizeof (stackval));
-                                       zero = &valuetype_this;
                                        child_frame.obj = &valuetype_this;
                                }
-                               stackval_from_data (&newobj_class->byval_arg, &valuetype_this, zero, csig->pinvoke);
                        } else {
                                if (newobj_class != mono_defaults.string_class) {
-                                       o = mono_object_new (domain, newobj_class);
+                                       context->managed_code = 0;
+                                       o = mono_object_new (context->domain, newobj_class);
+                                       context->managed_code = 1;
+                                       if (*abort_requested)
+                                               mono_thread_interruption_checkpoint ();
                                        child_frame.obj = o;
                                } else {
                                        child_frame.retval = &retval;
@@ -2669,15 +2625,12 @@ ves_exec_method (MonoInvocation *frame)
 
                        g_assert (csig->call_convention == MONO_CALL_DEFAULT);
 
+                       child_frame.ip = NULL;
                        child_frame.ex = NULL;
-                       child_frame.ex_handler = NULL;
 
-                       ves_exec_method (&child_frame);
+                       ves_exec_method_with_context (&child_frame, context);
 
-                       while (endsp > sp) {
-                               --endsp;
-                               vt_free (endsp);
-                       }
+                       context->current_frame = frame;
 
                        if (child_frame.ex) {
                                /*
@@ -2695,574 +2648,576 @@ array_constructed:
                        } else if (newobj_class == mono_defaults.string_class) {
                                *sp = retval;
                        } else {
-                               sp->type = VAL_OBJ;
                                sp->data.p = o;
-                               sp->data.vt.klass = newobj_class;
                        }
                        ++sp;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_CASTCLASS) /* Fall through */
-               CASE (CEE_ISINST) {
-                       MonoObject *o;
-                       MonoVTable *vt;
-                       MonoClass *c , *oclass;
-                       guint32 token;
-                       int do_isinst = *ip == CEE_ISINST;
-
-                       ++ip;
-                       token = read32 (ip);
-                       c = mono_class_get (image, token);
-
-                       g_assert (sp [-1].type == VAL_OBJ);
-
+               MINT_IN_CASE(MINT_CASTCLASS)
+                       c = rtm->data_items [*(guint16 *)(ip + 1)];
                        if ((o = sp [-1].data.p)) {
-                               vt = o->vtable;
-                               oclass = vt->klass;
-
-                               if (mono_object_isinst (o, c)) {
-                                       sp [-1].data.vt.klass = c;
+                               if (c->marshalbyref) {
+                                       if (!mono_object_isinst_mbyref (o, c))
+                                               THROW_EX (mono_get_exception_invalid_cast (), ip);
+                               } else {
+                                       MonoVTable *vt = o->vtable;
+                                       MonoClass *oklass = vt->klass;
+                                       if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                                               if (c->interface_id > vt->max_interface_id ||
+                                                   vt->interface_offsets [c->interface_id] == 0) {
+                                                       THROW_EX (mono_get_exception_invalid_cast (), ip);
+                                               }
+                                       } else if (c->rank) {
+                                               if (!mono_object_isinst (o, c))
+                                                       THROW_EX (mono_get_exception_invalid_cast (), ip);
+                                       } else if (!mono_class_has_parent (oklass, c)) {
+                                               THROW_EX (mono_get_exception_invalid_cast (), ip);
+                                       }
                                }
-                               else {
-                                       if (do_isinst) {
+                       }
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ISINST)
+                       c = rtm->data_items [*(guint16 *)(ip + 1)];
+                       if ((o = sp [-1].data.p)) {
+                               if (c->marshalbyref) {
+                                       if (!mono_object_isinst_mbyref (o, c))
                                                sp [-1].data.p = NULL;
-                                               sp [-1].data.vt.klass = NULL;
-                                       } else
-                                               THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
+                               } else {
+                                       MonoVTable *vt = o->vtable;
+                                       MonoClass *oklass = vt->klass;
+                                       if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                                               if (c->interface_id > vt->max_interface_id ||
+                                                   vt->interface_offsets [c->interface_id] == 0) {
+                                                       sp [-1].data.p = NULL;
+                                               }
+                                       } else if (c->rank) {
+                                               if (!mono_object_isinst (o, c))
+                                                       sp [-1].data.p = NULL;
+                                       } else if (!mono_class_has_parent (oklass, c)) {
+                                               sp [-1].data.p = NULL;
+                                       }
                                }
                        }
-                       ip += 4;
-                       BREAK;
-               }
-               CASE (CEE_CONV_R_UN)
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R_UN_I4)
+                       sp [-1].data.f = (double)(guint32)sp [-1].data.i;
                        ++ip;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               break;
-                       case VAL_I64:
-                               sp [-1].data.f = (double)(guint64)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               sp [-1].data.f = (double)(guint32)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.f = (double)(guint64)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_DOUBLE;
-                       BREAK;
-               CASE (CEE_UNUSED58)
-               CASE (CEE_UNUSED1) ves_abort(); BREAK;
-               CASE (CEE_UNBOX) {
-                       MonoObject *o;
-                       MonoClass *c;
-                       guint32 token;
-
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_R_UN_I8)
+                       sp [-1].data.f = (double)(guint64)sp [-1].data.l;
                        ++ip;
-                       token = read32 (ip);
-                       
-                       if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
-                               c = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
-                       else 
-                               c = mono_class_get (image, token);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_UNBOX)
+                       c = rtm->data_items[*(guint16 *)(ip + 1)];
                        
                        o = sp [-1].data.p;
                        if (!o)
-                               THROW_EX (mono_get_exception_null_reference(), ip - 1);
+                               THROW_EX (mono_get_exception_null_reference(), ip);
 
-                       if (o->vtable->klass->element_class->type_token != c->element_class->type_token)
-                               THROW_EX (mono_get_exception_invalid_cast (), ip - 1);
+                       if (!(mono_object_isinst (o, c) || 
+                                 ((o->vtable->klass->rank == 0) && 
+                                  (o->vtable->klass->element_class == c->element_class))))
+                               THROW_EX (mono_get_exception_invalid_cast (), ip);
 
-                       sp [-1].type = VAL_MP;
                        sp [-1].data.p = (char *)o + sizeof (MonoObject);
-
-                       ip += 4;
-                       BREAK;
-               }
-               CASE (CEE_THROW)
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_THROW)
                        --sp;
                        frame->ex_handler = NULL;
                        if (!sp->data.p)
                                sp->data.p = mono_get_exception_null_reference ();
-                       THROW_EX (sp->data.p, ip);
-                       BREAK;
-               CASE (CEE_LDFLDA) /* Fall through */
-               CASE (CEE_LDFLD) {
-                       MonoObject *obj;
-                       MonoClassField *field;
-                       guint32 token;
-                       int load_addr = *ip == CEE_LDFLDA;
-                       char *addr;
-
-                       if (!sp [-1].data.p)
+                       THROW_EX ((MonoException *)sp->data.p, ip);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLDA)
+                       o = sp [-1].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CKNULL)
+                       o = sp [-1].data.p;
+                       if (!o)
                                THROW_EX (mono_get_exception_null_reference (), ip);
-                       
                        ++ip;
-                       token = read32 (ip);
+                       MINT_IN_BREAK;
+
+#define LDFLD(datamem, fieldtype) \
+       o = sp [-1].data.p; \
+       if (!o) \
+               THROW_EX (mono_get_exception_null_reference (), ip); \
+       sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
+       ip += 2;
+
+               MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_LDFLD_VT)
+                       o = sp [-1].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       i32 = READ32(ip + 2);
+                       sp [-1].data.p = vt_sp;
+                       memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
+                       vt_sp += (i32 + 7) & ~7;
                        ip += 4;
+                       MINT_IN_BREAK;
 
-                       if (sp [-1].type == VAL_OBJ) {
-                               obj = sp [-1].data.p;
+               MINT_IN_CASE(MINT_LDRMFLD) {
+                       MonoClassField *field;
+                       char *addr;
 
-                               if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
-                                       MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
-                                       field = mono_class_get_field (klass, token);
-                                       addr = mono_load_remote_field (obj, klass, field, NULL);
-                               } else {
-                                       if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
-                                               field = mono_field_from_memberref (image, token, NULL);
-                                       else
-                                               field = mono_class_get_field (obj->vtable->klass, token);
-                                       addr = (char*)obj + field->offset;
-                               }                               
+                       o = sp [-1].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       field = rtm->data_items[* (guint16 *)(ip + 1)];
+                       ip += 2;
+                       if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
+                               addr = mono_load_remote_field (o, klass, field, NULL);
                        } else {
-                               obj = sp [-1].data.vt.vt;
-                               field = mono_class_get_field (sp [-1].data.vt.klass, token);
-                               addr = (char*)obj + field->offset - sizeof (MonoObject);
-                       }
+                               addr = (char*)o + field->offset;
+                       }                               
 
-                       if (load_addr) {
-                               sp [-1].type = VAL_TP;
-                               sp [-1].data.p = addr;
-                               sp [-1].data.vt.klass = mono_class_from_mono_type (field->type);
-                       } else {
-                               vt_alloc (field->type, &sp [-1], FALSE);
-                               stackval_from_data (field->type, &sp [-1], addr, FALSE);
-                               
-                       }
-                       BREAK;
+                       stackval_from_data (field->type, &sp [-1], addr, FALSE);
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_STFLD) {
-                       MonoObject *obj;
+
+               MINT_IN_CASE(MINT_LDRMFLD_VT) {
                        MonoClassField *field;
-                       guint32 token, offset;
+                       char *addr;
 
-                       sp -= 2;
-                       
-                       if (!sp [0].data.p)
+                       o = sp [-1].data.p;
+                       if (!o)
                                THROW_EX (mono_get_exception_null_reference (), ip);
-                       
-                       ++ip;
-                       token = read32 (ip);
+                       field = rtm->data_items[* (guint16 *)(ip + 1)];
+                       i32 = READ32(ip + 2);
                        ip += 4;
-                       
-                       if (sp [0].type == VAL_OBJ) {
-                               obj = sp [0].data.p;
+                       if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
+                               addr = mono_load_remote_field (o, klass, field, NULL);
+                       } else {
+                               addr = (char*)o + field->offset;
+                       }                               
+
+                       sp [-1].data.p = vt_sp;
+                       memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
+                       vt_sp += (i32 + 7) & ~7;
+                       memcpy(sp [-1].data.p, addr, i32);
+                       MINT_IN_BREAK;
+               }
 
-                               if (obj->vtable->klass == mono_defaults.transparent_proxy_class) {
-                                       MonoClass *klass = ((MonoTransparentProxy*)obj)->klass;
-                                       field = mono_class_get_field (klass, token);
+#define STFLD(datamem, fieldtype) \
+       o = sp [-2].data.p; \
+       if (!o) \
+               THROW_EX (mono_get_exception_null_reference (), ip); \
+       sp -= 2; \
+       * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
+       ip += 2;
+
+               MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
+               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_VT)
+                       o = sp [-2].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       i32 = READ32(ip + 2);
+                       sp -= 2;
+                       memcpy((char *)o + * (guint16 *)(ip + 1), sp [1].data.p, i32);
+                       vt_sp -= (i32 + 7) & ~7;
+                       ip += 4;
+                       MINT_IN_BREAK;
 
-                                       mono_store_remote_field (obj, klass, field, &sp [1].data);
-                                       offset = field->offset;
-                               } else {
-                                       if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
-                                               field = mono_field_from_memberref (image, token, NULL);
-                                       else
-                                               field = mono_class_get_field (obj->vtable->klass, token);
-                                       offset = field->offset;
-                                       stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
-                                       vt_free (&sp [1]);
-                               }
-                       } else {
-                               obj = sp [0].data.vt.vt;
-                               field = mono_class_get_field (sp [0].data.vt.klass, token);
-                               offset = field->offset - sizeof (MonoObject);
-                               stackval_to_data (field->type, &sp [1], (char*)obj + offset, FALSE);
-                               vt_free (&sp [1]);
-                       }
+               MINT_IN_CASE(MINT_STRMFLD) {
+                       MonoClassField *field;
+
+                       o = sp [-2].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       
+                       field = rtm->data_items[* (guint16 *)(ip + 1)];
+                       ip += 2;
 
-                       BREAK;
+                       if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
+                               mono_store_remote_field (o, klass, field, &sp [-1].data);
+                       } else
+                               stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
+
+                       sp -= 2;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDSFLD) /* Fall through */
-               CASE (CEE_LDSFLDA) {
-                       MonoVTable *vt;
-                       MonoClass *klass;
+               MINT_IN_CASE(MINT_STRMFLD_VT) {
                        MonoClassField *field;
-                       guint32 token;
-                       int load_addr = *ip == CEE_LDSFLDA;
-                       gpointer addr;
 
-                       ++ip;
-                       token = read32 (ip);
+                       o = sp [-2].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       field = rtm->data_items[* (guint16 *)(ip + 1)];
+                       i32 = READ32(ip + 2);
                        ip += 4;
-                       
-                       /* need to handle fieldrefs */
-                       if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
-                               field = mono_field_from_memberref (image, token, &klass);
-                       } else {
-                               klass = mono_class_get (image, 
-                                       MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
-                               field = mono_class_get_field (klass, token);
-                       }
-                       g_assert (field);
-                       
-                       vt = mono_class_vtable (domain, klass);
-                       if (!vt->initialized)
-                               mono_runtime_class_init (vt);
-                       if (!domain->thread_static_fields || !(addr = g_hash_table_lookup (domain->thread_static_fields, field)))
-                               addr = (char*)(vt->data) + field->offset;
-                       else
-                               addr = mono_threads_get_static_data (GPOINTER_TO_UINT (addr));
 
-                       if (load_addr) {
-                               sp->type = VAL_TP;
-                               sp->data.p = addr;
-                               sp->data.vt.klass = mono_class_from_mono_type (field->type);
-                       } else {
-                               vt_alloc (field->type, sp, FALSE);
-                               stackval_from_data (field->type, sp, addr, FALSE);
+                       if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+                               MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
+                               mono_store_remote_field (o, klass, field, &sp [-1].data);
+                       } else
+                               memcpy((char*)o + field->offset, sp [-1].data.p, i32);
+
+                       sp -= 2;
+                       vt_sp -= (i32 + 7) & ~7;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_LDSFLDA) {
+                       MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
+                       MonoVTable *vt = mono_class_vtable (context->domain, field->parent);
+                       gpointer addr;
+
+                       if (!vt->initialized) {
+                               frame->ip = ip;
+                               mono_runtime_class_init (vt);
                        }
+                       ip += 2;
+
+                       if (context->domain->special_static_fields && (addr = g_hash_table_lookup (context->domain->special_static_fields, field)))
+                               sp->data.p = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+                       else
+                               sp->data.p = (char*)(vt->data) + field->offset;
                        ++sp;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_STSFLD) {
+               MINT_IN_CASE(MINT_LDSFLD) {
                        MonoVTable *vt;
-                       MonoClass *klass;
                        MonoClassField *field;
-                       guint32 token;
                        gpointer addr;
 
-                       ++ip;
-                       token = read32 (ip);
-                       ip += 4;
-                       --sp;
-
-                       /* need to handle fieldrefs */
-                       if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
-                               field = mono_field_from_memberref (image, token, &klass);
-                       } else {
-                               klass = mono_class_get (image, 
-                                       MONO_TOKEN_TYPE_DEF | mono_metadata_typedef_from_field (image, token & 0xffffff));
-                               field = mono_class_get_field (klass, token);
-                       }
-                       g_assert (field);
-
-                       vt = mono_class_vtable (domain, klass);
-                       if (!vt->initialized)
+                       field = rtm->data_items[*(guint16 *)(ip + 1)];
+                       vt = rtm->data_items [*(guint16 *)(ip + 2)];
+                       if (!vt->initialized) {
+                               frame->ip = ip;
                                mono_runtime_class_init (vt);
-                       if (!domain->thread_static_fields || !(addr = g_hash_table_lookup (domain->thread_static_fields, field)))
-                               addr = (char*)(vt->data) + field->offset;
+                       }
+                       ip += 3;
+                       if (context->domain->special_static_fields && (addr = g_hash_table_lookup (context->domain->special_static_fields, field)))
+                               addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
                        else
-                               addr = mono_threads_get_static_data (GPOINTER_TO_UINT (addr));
+                               addr = (char*)(vt->data) + field->offset;
 
-                       stackval_to_data (field->type, sp, addr, FALSE);
-                       vt_free (sp);
-                       BREAK;
-               }
-               CASE (CEE_STOBJ) {
-                       MonoClass *vtklass;
-                       ++ip;
-                       vtklass = mono_class_get (image, read32 (ip));
-                       ip += 4;
-                       sp -= 2;
-                       memcpy (sp [0].data.p, sp [1].data.vt.vt, mono_class_value_size (vtklass, NULL));
-                       BREAK;
-               }
-#if SIZEOF_VOID_P == 8
-               CASE (CEE_CONV_OVF_I_UN)
-#endif
-               CASE (CEE_CONV_OVF_I8_UN) {
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.l = (guint64)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               /* Can't overflow */
-                               sp [-1].data.l = (guint64)sp [-1].data.i;
-                               break;
-                       default:
-                               sp [-1].data.l = (guint64)sp [-1].data.nati;
-                               break;
-                       }
-                       sp [-1].type = VAL_I64;
-                       ++ip;
-                       BREAK;
+                       stackval_from_data (field->type, sp, addr, FALSE);
+                       ++sp;
+                       MINT_IN_BREAK;
                }
-#if SIZEOF_VOID_P == 8
-               CASE (CEE_CONV_OVF_U_UN) 
-#endif
-               CASE (CEE_CONV_OVF_U8_UN) {
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT64_MAX)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.l = (guint64)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               /* nothing to do */
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               /* Can't overflow */
-                               sp [-1].data.l = (guint64)sp [-1].data.i;
-                               break;
-                       default:
-                               /* Can't overflow */
-                               sp [-1].data.l = (guint64)sp [-1].data.nati;
-                               break;
+               MINT_IN_CASE(MINT_LDSFLD_I4) {
+                       MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
+                       MonoVTable *vt = rtm->data_items [*(guint16 *)(ip + 2)];
+                       if (!vt->initialized) {
+                               frame->ip = ip;
+                               mono_runtime_class_init (vt);
                        }
-                       sp [-1].type = VAL_I64;
-                       ++ip;
-                       BREAK;
+                       ip += 3;
+                       sp->data.i = * (gint32 *)((char*)(vt->data) + field->offset);
+                       ++sp;
+                       MINT_IN_BREAK;
                }
-#if SIZEOF_VOID_P == 4
-               CASE (CEE_CONV_OVF_I_UN)
-               CASE (CEE_CONV_OVF_U_UN) 
-#endif
-               CASE (CEE_CONV_OVF_I1_UN)
-               CASE (CEE_CONV_OVF_I2_UN)
-               CASE (CEE_CONV_OVF_I4_UN)
-               CASE (CEE_CONV_OVF_U1_UN)
-               CASE (CEE_CONV_OVF_U2_UN)
-               CASE (CEE_CONV_OVF_U4_UN) {
-                       guint64 value;
-                       switch (sp [-1].type) {
-                       case VAL_DOUBLE:
-                               value = (guint64)sp [-1].data.f;
-                               break;
-                       case VAL_I64:
-                               value = (guint64)sp [-1].data.l;
-                               break;
-                       case VAL_VALUET:
-                               ves_abort();
-                       case VAL_I32:
-                               value = (guint64)sp [-1].data.i;
-                               break;
-                       default:
-                               value = (guint64)sp [-1].data.nati;
-                               break;
-                       }
-                       switch (*ip) {
-                       case CEE_CONV_OVF_I1_UN:
-                               if (value > 127)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = value;
-                               sp [-1].type = VAL_I32;
-                               break;
-                       case CEE_CONV_OVF_I2_UN:
-                               if (value > 32767)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = value;
-                               sp [-1].type = VAL_I32;
-                               break;
-#if SIZEOF_VOID_P == 4
-                       case CEE_CONV_OVF_I_UN: /* Fall through */
-#endif
-                       case CEE_CONV_OVF_I4_UN:
-                               if (value > 2147483647)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = value;
-                               sp [-1].type = VAL_I32;
-                               break;
-                       case CEE_CONV_OVF_U1_UN:
-                               if (value > 255)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = value;
-                               sp [-1].type = VAL_I32;
-                               break;
-                       case CEE_CONV_OVF_U2_UN:
-                               if (value > 65535)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = value;
-                               sp [-1].type = VAL_I32;
-                               break;
-#if SIZEOF_VOID_P == 4
-                       case CEE_CONV_OVF_U_UN: /* Fall through */
-#endif
-                       case CEE_CONV_OVF_U4_UN:
-                               if (value > 4294967295U)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = value;
-                               sp [-1].type = VAL_I32;
-                               break;
-                       default:
-                               g_assert_not_reached ();
+               MINT_IN_CASE(MINT_LDSFLD_O) {
+                       MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
+                       MonoVTable *vt = rtm->data_items [*(guint16 *)(ip + 2)];
+                       if (!vt->initialized) {
+                               frame->ip = ip;
+                               mono_runtime_class_init (vt);
                        }
-                       ++ip;
-                       BREAK;
+                       ip += 3;
+                       sp->data.p = * (gpointer *)((char*)(vt->data) + field->offset);
+                       ++sp;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_BOX) {
+               MINT_IN_CASE(MINT_LDSFLD_VT) {
+                       MonoVTable *vt;
+                       MonoClassField *field;
                        guint32 token;
-                       MonoClass *class;
-
-                       ip++;
-                       token = read32 (ip);
-
-                       if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
-                               class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
-                       else
-                               class = mono_class_get (image, token);
-                       g_assert (class != NULL);
-
-                       sp [-1].type = VAL_OBJ;
-                       if (class->byval_arg.type == MONO_TYPE_VALUETYPE && !class->enumtype) 
-                               sp [-1].data.p = mono_value_box (domain, class, sp [-1].data.p);
-                       else {
-                               stackval_to_data (&class->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
-                               sp [-1].data.p = mono_value_box (domain, class, &sp [-1]);
-                       }
-                       /* need to vt_free (sp); */
+                       gpointer addr;
+                       int size;
 
+                       token = * (guint16 *)(ip + 1);
+                       size = READ32(ip + 2);
+                       field = rtm->data_items[token];
                        ip += 4;
+                                               
+                       vt = mono_class_vtable (context->domain, field->parent);
+                       if (!vt->initialized) {
+                               frame->ip = ip - 2;
+                               mono_runtime_class_init (vt);
+                       }
+                       
+                       if (context->domain->special_static_fields && (addr = g_hash_table_lookup (context->domain->special_static_fields, field)))
+                               addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+                       else
+                               addr = (char*)(vt->data) + field->offset;
 
-                       BREAK;
+                       sp->data.p = vt_sp;
+                       vt_sp += (size + 7) & ~7;
+                       stackval_from_data (field->type, sp, addr, FALSE);
+                       ++sp;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_NEWARR) {
-                       MonoClass *class;
-                       MonoObject *o;
+               MINT_IN_CASE(MINT_STSFLD) {
+                       MonoVTable *vt;
+                       MonoClassField *field;
                        guint32 token;
+                       gpointer addr;
 
-                       ip++;
-                       token = read32 (ip);
+                       token = * (guint16 *)(ip + 1);
+                       field = rtm->data_items[token];
+                       ip += 2;
+                       --sp;
 
-                       if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
-                               class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
+                       vt = mono_class_vtable (context->domain, field->parent);
+                       if (!vt->initialized) {
+                               frame->ip = ip - 2;
+                               mono_runtime_class_init (vt);
+                       }
+                       
+                       if (context->domain->special_static_fields && (addr = g_hash_table_lookup (context->domain->special_static_fields, field)))
+                               addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
                        else
-                               class = mono_class_get (image, token);
+                               addr = (char*)(vt->data) + field->offset;
 
-                       o = (MonoObject*) mono_array_new (domain, class, sp [-1].data.i);
-                       ip += 4;
+                       stackval_to_data (field->type, sp, addr, FALSE);
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_STSFLD_VT) {
+                       MonoVTable *vt;
+                       MonoClassField *field;
+                       guint32 token;
+                       gpointer addr;
+                       int size;
 
-                       sp [-1].type = VAL_OBJ;
-                       sp [-1].data.p = o;
+                       token = * (guint16 *)(ip + 1);
+                       size = READ32(ip + 2);
+                       field = rtm->data_items[token];
+                       ip += 4;
+                                               
+                       vt = mono_class_vtable (context->domain, field->parent);
+                       if (!vt->initialized) {
+                               frame->ip = ip - 2;
+                               mono_runtime_class_init (vt);
+                       }
+                       
+                       if (context->domain->special_static_fields && (addr = g_hash_table_lookup (context->domain->special_static_fields, field)))
+                               addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+                       else
+                               addr = (char*)(vt->data) + field->offset;
+                       --sp;
+                       stackval_to_data (field->type, sp, addr, FALSE);
+                       vt_sp -= (size + 7) & ~7;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_STOBJ_VT) {
+                       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.p, size);
+                       vt_sp -= (size + 7) & ~7;
+                       sp -= 2;
+                       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);
+                       sp -= 2;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
+                       if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint32)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
+                       if (sp [-1].data.i < 0)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.l = sp [-1].data.i;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
+               MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
+                       if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.l = (guint64)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
+                       if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.l = (gint64)sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
+                       if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (mono_u)sp [-1].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_BOX)
+                       c = rtm->data_items [* (guint16 *)(ip + 1)];
+
+                       if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
+                               int size = mono_class_value_size (c, NULL);
+                               sp [-1].data.p = mono_value_box (context->domain, c, sp [-1].data.p);
+                               size = (size + 7) & ~7;
+                               vt_sp -= size;
+                       }                               
+                       else {
+                               stackval_to_data (&c->byval_arg, &sp [-1], (char*)&sp [-1], FALSE);
+                               sp [-1].data.p = mono_value_box (context->domain, c, &sp [-1]);
+                       }
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NEWARR)
+                       sp [-1].data.p = (MonoObject*) mono_array_new (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i);
+                       ip += 2;
                        /*if (profiling_classes) {
                                guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
                                count++;
                                g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
                        }*/
 
-                       BREAK;
-               }
-               CASE (CEE_LDLEN) {
-                       MonoArray *o;
-
-                       ip++;
-
-                       g_assert (sp [-1].type == VAL_OBJ);
-
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLEN)
                        o = sp [-1].data.p;
                        if (!o)
-                               THROW_EX (mono_get_exception_null_reference (), ip - 1);
-                       
-                       g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
-
-                       sp [-1].type = VAL_I32;
-                       sp [-1].data.i = mono_array_length (o);
-
-                       BREAK;
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       sp [-1].data.nati = mono_array_length ((MonoArray *)o);
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_GETCHR) {
+                       MonoString *s;
+                       s = sp [-2].data.p;
+                       if (!s)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       i32 = sp [-1].data.i;
+                       if (i32 < 0 || i32 >= mono_string_length (s))
+                               THROW_EX (mono_get_exception_index_out_of_range (), ip);
+                       --sp;
+                       sp [-1].data.i = mono_string_chars(s)[i32];
+                       ++ip;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDELEMA) {
-                       MonoArray *o;
-                       guint32 esize, token;
-                       
+               MINT_IN_CASE(MINT_STRLEN)
                        ++ip;
-                       token = read32 (ip);
-                       ip += 4;
+                       sp [-1].data.i = mono_string_length ((MonoString*)sp [-1].data.p);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ARRAY_RANK)
+                       o = sp [-1].data.p;
+                       if (!o)
+                               THROW_EX (mono_get_exception_null_reference (), ip);
+                       sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
+                       ip++;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDELEMA) {
+                       guint32 esize;
+                       mono_u aindex;
+                       
+                       /*token = READ32 (ip)*/;
+                       ip += 2;
                        sp -= 2;
 
-                       g_assert (sp [0].type == VAL_OBJ);
                        o = sp [0].data.p;
 
-                       g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
-                       
-                       if (sp [1].data.nati >= mono_array_length (o))
-                               THROW_EX (mono_get_exception_index_out_of_range (), ip - 5);
+                       aindex = sp [1].data.i;
+                       if (aindex >= mono_array_length ((MonoArray *) o))
+                               THROW_EX (mono_get_exception_index_out_of_range (), ip - 2);
 
                        /* check the array element corresponds to token */
-                       esize = mono_array_element_size (o->obj.vtable->klass);
+                       esize = mono_array_element_size (((MonoArray *) o)->obj.vtable->klass);
                        
-                       sp->type = VAL_MP;
-                       sp->data.p = mono_array_addr_with_size (o, esize, sp [1].data.i);
-                       sp->data.vt.klass = o->obj.vtable->klass->element_class;
-
+                       sp->data.p = mono_array_addr_with_size ((MonoArray *) o, esize, aindex);
                        ++sp;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDELEM_I1) /* fall through */
-               CASE (CEE_LDELEM_U1) /* fall through */
-               CASE (CEE_LDELEM_I2) /* fall through */
-               CASE (CEE_LDELEM_U2) /* fall through */
-               CASE (CEE_LDELEM_I4) /* fall through */
-               CASE (CEE_LDELEM_U4) /* fall through */
-               CASE (CEE_LDELEM_I8)  /* fall through */
-               CASE (CEE_LDELEM_I)  /* fall through */
-               CASE (CEE_LDELEM_R4) /* fall through */
-               CASE (CEE_LDELEM_R8) /* fall through */
-               CASE (CEE_LDELEM_REF) {
+               MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_I8)  /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_I)  /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
+               MINT_IN_CASE(MINT_LDELEM_REF) {
                        MonoArray *o;
                        mono_u aindex;
 
                        sp -= 2;
 
-                       g_assert (sp [0].type == VAL_OBJ);
                        o = sp [0].data.p;
                        if (!o)
                                THROW_EX (mono_get_exception_null_reference (), ip);
 
-                       g_assert (MONO_CLASS_IS_ARRAY (o->obj.vtable->klass));
-                       
-                       aindex = sp [1].data.nati;
+                       aindex = sp [1].data.i;
                        if (aindex >= mono_array_length (o))
                                THROW_EX (mono_get_exception_index_out_of_range (), ip);
-               
+
                        /*
                         * FIXME: throw mono_get_exception_array_type_mismatch () if needed 
                         */
                        switch (*ip) {
-                       case CEE_LDELEM_I1:
+                       case MINT_LDELEM_I1:
                                sp [0].data.i = mono_array_get (o, gint8, aindex);
-                               sp [0].type = VAL_I32;
                                break;
-                       case CEE_LDELEM_U1:
+                       case MINT_LDELEM_U1:
                                sp [0].data.i = mono_array_get (o, guint8, aindex);
-                               sp [0].type = VAL_I32;
                                break;
-                       case CEE_LDELEM_I2:
+                       case MINT_LDELEM_I2:
                                sp [0].data.i = mono_array_get (o, gint16, aindex);
-                               sp [0].type = VAL_I32;
                                break;
-                       case CEE_LDELEM_U2:
+                       case MINT_LDELEM_U2:
                                sp [0].data.i = mono_array_get (o, guint16, aindex);
-                               sp [0].type = VAL_I32;
                                break;
-                       case CEE_LDELEM_I:
+                       case MINT_LDELEM_I:
                                sp [0].data.nati = mono_array_get (o, mono_i, aindex);
-                               sp [0].type = VAL_NATI;
                                break;
-                       case CEE_LDELEM_I4:
+                       case MINT_LDELEM_I4:
                                sp [0].data.i = mono_array_get (o, gint32, aindex);
-                               sp [0].type = VAL_I32;
                                break;
-                       case CEE_LDELEM_U4:
+                       case MINT_LDELEM_U4:
                                sp [0].data.i = mono_array_get (o, guint32, aindex);
-                               sp [0].type = VAL_I32;
                                break;
-                       case CEE_LDELEM_I8:
+                       case MINT_LDELEM_I8:
                                sp [0].data.l = mono_array_get (o, guint64, aindex);
-                               sp [0].type = VAL_I64;
                                break;
-                       case CEE_LDELEM_R4:
+                       case MINT_LDELEM_R4:
                                sp [0].data.f = mono_array_get (o, float, aindex);
-                               sp [0].type = VAL_DOUBLE;
                                break;
-                       case CEE_LDELEM_R8:
+                       case MINT_LDELEM_R8:
                                sp [0].data.f = mono_array_get (o, double, aindex);
-                               sp [0].type = VAL_DOUBLE;
                                break;
-                       case CEE_LDELEM_REF:
+                       case MINT_LDELEM_REF:
                                sp [0].data.p = mono_array_get (o, gpointer, aindex);
-                               sp [0].data.vt.klass = NULL;
-                               sp [0].type = VAL_OBJ;
                                break;
                        default:
                                ves_abort();
@@ -3270,326 +3225,247 @@ array_constructed:
 
                        ++ip;
                        ++sp;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_STELEM_I)  /* fall through */
-               CASE (CEE_STELEM_I1) /* fall through */ 
-               CASE (CEE_STELEM_I2) /* fall through */
-               CASE (CEE_STELEM_I4) /* fall through */
-               CASE (CEE_STELEM_I8) /* fall through */
-               CASE (CEE_STELEM_R4) /* fall through */
-               CASE (CEE_STELEM_R8) /* fall through */
-               CASE (CEE_STELEM_REF) {
-                       MonoArray *o;
-                       MonoClass *ac;
+               MINT_IN_CASE(MINT_STELEM_I)  /* fall through */
+               MINT_IN_CASE(MINT_STELEM_I1) /* fall through */ 
+               MINT_IN_CASE(MINT_STELEM_I2) /* 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 */
+               MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
+               MINT_IN_CASE(MINT_STELEM_REF) {
                        mono_u aindex;
 
                        sp -= 3;
 
-                       g_assert (sp [0].type == VAL_OBJ);
                        o = sp [0].data.p;
                        if (!o)
                                THROW_EX (mono_get_exception_null_reference (), ip);
 
-                       ac = o->obj.vtable->klass;
-                       g_assert (MONO_CLASS_IS_ARRAY (ac));
-                   
-                       aindex = sp [1].data.nati;
-                       if (aindex >= mono_array_length (o))
+                       aindex = sp [1].data.i;
+                       if (aindex >= mono_array_length ((MonoArray *)o))
                                THROW_EX (mono_get_exception_index_out_of_range (), ip);
 
-                       /*
-                        * FIXME: throw mono_get_exception_array_type_mismatch () if needed 
-                        */
                        switch (*ip) {
-                       case CEE_STELEM_I:
-                               mono_array_set (o, mono_i, aindex, sp [2].data.nati);
+                       case MINT_STELEM_I:
+                               mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
                                break;
-                       case CEE_STELEM_I1:
-                               mono_array_set (o, gint8, aindex, sp [2].data.i);
+                       case MINT_STELEM_I1:
+                               mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
                                break;
-                       case CEE_STELEM_I2:
-                               mono_array_set (o, gint16, aindex, sp [2].data.i);
+                       case MINT_STELEM_I2:
+                               mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
                                break;
-                       case CEE_STELEM_I4:
-                               mono_array_set (o, gint32, aindex, sp [2].data.i);
+                       case MINT_STELEM_I4:
+                               mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
                                break;
-                       case CEE_STELEM_I8:
-                               mono_array_set (o, gint64, aindex, sp [2].data.l);
+                       case MINT_STELEM_I8:
+                               mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
                                break;
-                       case CEE_STELEM_R4:
-                               mono_array_set (o, float, aindex, sp [2].data.f);
+                       case MINT_STELEM_R4:
+                               mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
                                break;
-                       case CEE_STELEM_R8:
-                               mono_array_set (o, double, aindex, sp [2].data.f);
+                       case MINT_STELEM_R8:
+                               mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
                                break;
-                       case CEE_STELEM_REF:
-                               g_assert (sp [2].type == VAL_OBJ);
+                       case MINT_STELEM_REF:
                                if (sp [2].data.p && !mono_object_isinst (sp [2].data.p, mono_object_class (o)->element_class))
                                        THROW_EX (mono_get_exception_array_type_mismatch (), ip);
-                               mono_array_set (o, gpointer, aindex, sp [2].data.p);
+                               mono_array_set ((MonoArray *)o, gpointer, aindex, sp [2].data.p);
                                break;
                        default:
                                ves_abort();
                        }
 
                        ++ip;
-                       BREAK;
+                       MINT_IN_BREAK;
                }
-               CASE (CEE_LDELEM) 
-               CASE (CEE_STELEM) 
-               CASE (CEE_UNBOX_ANY) 
-               CASE (CEE_UNUSED5) 
-               CASE (CEE_UNUSED6) 
-               CASE (CEE_UNUSED7) 
-               CASE (CEE_UNUSED8) 
-               CASE (CEE_UNUSED9) 
-               CASE (CEE_UNUSED10) 
-               CASE (CEE_UNUSED11) 
-               CASE (CEE_UNUSED12) 
-               CASE (CEE_UNUSED13) 
-               CASE (CEE_UNUSED14) 
-               CASE (CEE_UNUSED15) 
-               CASE (CEE_UNUSED16) 
-               CASE (CEE_UNUSED17) ves_abort(); BREAK;
-               CASE (CEE_CONV_OVF_I1)
-                       if (sp [-1].type == VAL_I32) {
-                               if (sp [-1].data.i < 128 || sp [-1].data.i > 127)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = (gint8)sp [-1].data.i;
-                       } else if (sp [-1].type == VAL_I64) {
-                               if (sp [-1].data.l < 128 || sp [-1].data.l > 127)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = (gint8)sp [-1].data.l;
-                       } else {
-                               ves_abort();
-                       }
+               MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
+                       if (sp [-1].data.i < 0)
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        ++ip;
-                       BREAK;
-               CASE (CEE_CONV_OVF_U1)
-                       if (sp [-1].type == VAL_I32) {
-                               if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = (gint8)sp [-1].data.i;
-                       } else if (sp [-1].type == VAL_I64) {
-                               if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = (gint8)sp [-1].data.l;
-                       } else {
-                               ves_abort();
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
+                       if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint32) sp [-1].data.l;
                        ++ip;
-                       BREAK;
-               CASE (CEE_CONV_OVF_I2)
-               CASE (CEE_CONV_OVF_U2)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
+                       if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint32) sp [-1].data.f;
                        ++ip;
-                       /* FIXME: handle other cases */
-                       if (sp [-1].type == VAL_I32) {
-                               /* defined as NOP */
-                       } else {
-                               ves_abort();
-                       }
-                       BREAK;
-               CASE (CEE_CONV_OVF_I4)
-                       /* FIXME: handle other cases */
-                       if (sp [-1].type == VAL_I32) {
-                               /* defined as NOP */
-                       } else if(sp [-1].type == VAL_I64) {
-                               sp [-1].data.i = (gint32)sp [-1].data.l;
-                               sp [-1].type = VAL_I32;
-                       } else {
-                               ves_abort();
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
+                       if (sp [-1].data.i < 0)
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        ++ip;
-                       BREAK;
-               CASE (CEE_CONV_OVF_U4)
-                       /* FIXME: handle other cases */
-                       if (sp [-1].type == VAL_I32) {
-                               /* defined as NOP */
-                       } else if(sp [-1].type == VAL_I64) {
-                               sp [-1].data.i = (guint32)sp [-1].data.l;
-                               sp [-1].type = VAL_I32;
-                       } else {
-                               ves_abort();
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
+                       if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint32) sp [-1].data.l;
                        ++ip;
-                       BREAK;
-               CASE (CEE_CONV_OVF_I8)
-                       /* FIXME: handle other cases */
-                       if (sp [-1].type == VAL_I32) {
-                               sp [-1].data.l = (guint64)sp [-1].data.i;
-                               sp [-1].type = VAL_I64;
-                       } else if(sp [-1].type == VAL_I64) {
-                               /* defined as NOP */
-                       } else {
-                               ves_abort();
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
+                       if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint32) sp [-1].data.f;
                        ++ip;
-                       BREAK;
-               CASE (CEE_CONV_OVF_U8)
-                       /* FIXME: handle other cases */
-                       if (sp [-1].type == VAL_I32) {
-                               sp [-1].data.l = (guint64) sp [-1].data.i;
-                               sp [-1].type = VAL_I64;
-                       } else if(sp [-1].type == VAL_I64) {
-                               /* defined as NOP */
-                       } else {
-                               ves_abort();
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
+                       if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        ++ip;
-                       BREAK;
-               CASE (CEE_UNUSED50) 
-               CASE (CEE_UNUSED18) 
-               CASE (CEE_UNUSED19) 
-               CASE (CEE_UNUSED20) 
-               CASE (CEE_UNUSED21) 
-               CASE (CEE_UNUSED22) 
-               CASE (CEE_UNUSED23) ves_abort(); BREAK;
-               CASE (CEE_REFANYVAL) ves_abort(); BREAK;
-               CASE (CEE_CKFINITE)
-                       if (!finite(sp [-1].data.f))
-                               THROW_EX (mono_get_exception_arithmetic (), ip);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
+                       if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint16) sp [-1].data.l;
                        ++ip;
-                       BREAK;
-               CASE (CEE_UNUSED24) ves_abort(); BREAK;
-               CASE (CEE_UNUSED25) ves_abort(); BREAK;
-               CASE (CEE_MKREFANY) ves_abort(); BREAK;
-               CASE (CEE_UNUSED59) 
-               CASE (CEE_UNUSED60) 
-               CASE (CEE_UNUSED61) 
-               CASE (CEE_UNUSED62) 
-               CASE (CEE_UNUSED63) 
-               CASE (CEE_UNUSED64) 
-               CASE (CEE_UNUSED65) 
-               CASE (CEE_UNUSED66) 
-               CASE (CEE_UNUSED67) ves_abort(); BREAK;
-               CASE (CEE_LDTOKEN) {
-                       gpointer handle;
-                       MonoClass *handle_class;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
+                       if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint16) sp [-1].data.f;
                        ++ip;
-                       handle = mono_ldtoken (image, read32 (ip), &handle_class);
-                       ip += 4;
-                       vt_alloc (&handle_class->byval_arg, sp, FALSE);
-                       stackval_from_data (&handle_class->byval_arg, sp, (char*)&handle, FALSE);
-                       ++sp;
-                       BREAK;
-               }
-               CASE (CEE_CONV_OVF_I)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
+                       if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        ++ip;
-                       --sp;
-                       /* FIXME: check overflow. */
-                       switch (sp->type) {
-                       case VAL_I32:
-                               sp->data.p = (gpointer)(mono_i) sp->data.i;
-                               break;
-                       case VAL_I64:
-                               sp->data.p = (gpointer)(mono_i) sp->data.l;
-                               break;
-                       case VAL_NATI:
-                               break;
-                       case VAL_DOUBLE:
-                               sp->data.p = (gpointer)(mono_i) sp->data.f;
-                               break;
-                       default:
-                               ves_abort ();
-                       }
-                       sp->type = VAL_NATI;
-                       ++sp;
-                       BREAK;
-               CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
-               CASE (CEE_ADD_OVF)
-                       --sp;
-                       /* FIXME: check overflow */
-                       if (sp->type == VAL_I32) {
-                               if (CHECK_ADD_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = (gint32)sp [-1].data.i + (gint32)GET_NATI (sp [0]);
-                       } else if (sp->type == VAL_I64) {
-                               if (CHECK_ADD_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.l = (gint64)sp [-1].data.l + (gint64)sp [0].data.l;
-                       } else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f += sp [0].data.f;
-                       else {
-                               char *p = sp [-1].data.p;
-                               p += GET_NATI (sp [0]);
-                               sp [-1].data.p = p;
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
+                       if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint16) sp [-1].data.l;
                        ++ip;
-                       BREAK;
-               CASE (CEE_ADD_OVF_UN)
-                       --sp;
-                       /* FIXME: check overflow, make unsigned */
-                       if (sp->type == VAL_I32) {
-                               if (CHECK_ADD_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i = (guint32)sp [-1].data.i + (guint32)GET_NATI (sp [0]);
-                       } else if (sp->type == VAL_I64) {
-                               if (CHECK_ADD_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.l = (guint64)sp [-1].data.l + (guint64)sp [0].data.l;
-                       } else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f += sp [0].data.f;
-                       else {
-                               char *p = sp [-1].data.p;
-                               p += GET_NATI (sp [0]);
-                               sp [-1].data.p = p;
-                       }
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
+                       if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint16) sp [-1].data.f;
                        ++ip;
-                       BREAK;
-               CASE (CEE_MUL_OVF)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
+                       if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        ++ip;
-                       --sp;
-                       /* FIXME: check overflow */
-                       if (sp->type == VAL_I32) {
-                               if (CHECK_MUL_OVERFLOW (sp [-1].data.i, GET_NATI (sp [0])))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i *= (gint)GET_NATI (sp [0]);
-                       }
-                       else if (sp->type == VAL_I64) {
-                               if (CHECK_MUL_OVERFLOW64 (sp [-1].data.l, sp [0].data.l))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.l *= sp [0].data.l;
-                       }
-                       else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f *= sp [0].data.f;
-                       BREAK;
-               CASE (CEE_MUL_OVF_UN)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
+                       if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint8) sp [-1].data.l;
                        ++ip;
-                       --sp;
-                       /* FIXME: check overflow, make unsigned */
-                       if (sp->type == VAL_I32) {
-                               if (CHECK_MUL_OVERFLOW_UN (sp [-1].data.i, GET_NATI (sp [0])))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.i *= (gint)GET_NATI (sp [0]);
-                       }
-                       else if (sp->type == VAL_I64) {
-                               if (CHECK_MUL_OVERFLOW64_UN (sp [-1].data.l, sp [0].data.l))
-                                       THROW_EX (mono_get_exception_overflow (), ip);
-                               sp [-1].data.l *= sp [0].data.l;
-                       }
-                       else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f *= sp [0].data.f;
-                       BREAK;
-               CASE (CEE_SUB_OVF)
-               CASE (CEE_SUB_OVF_UN)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
+                       if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint8) sp [-1].data.f;
                        ++ip;
-                       --sp;
-                       /* FIXME: handle undeflow/unsigned */
-                       /* should probably consider the pointers as unsigned */
-                       if (sp->type == VAL_I32)
-                               sp [-1].data.i -= GET_NATI (sp [0]);
-                       else if (sp->type == VAL_I64)
-                               sp [-1].data.l -= sp [0].data.l;
-                       else if (sp->type == VAL_DOUBLE)
-                               sp [-1].data.f -= sp [0].data.f;
-                       else {
-                               char *p = sp [-1].data.p;
-                               p -= GET_NATI (sp [0]);
-                               sp [-1].data.p = p;
-                       }
-                       BREAK;
-               CASE (CEE_ENDFINALLY)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
+                       if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
+                       if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint8) sp [-1].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
+                       if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (guint8) sp [-1].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+#if 0
+               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 (!finite(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_LDTOKEN)
+                       sp->data.p = vt_sp;
+                       vt_sp += 8;
+                       * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
+                       ip += 2;
+                       ++sp;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD_OVF_I4)
+                       if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP(i, +);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD_OVF_I8)
+                       if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP(l, +);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
+                       if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP_CAST(i, +, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
+                       if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP_CAST(l, +, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_OVF_I4)
+                       if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP(i, *);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_OVF_I8)
+                       if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP(l, *);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
+                       if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP_CAST(i, *, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
+                       if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP_CAST(l, *, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_OVF_I4)
+                       if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP(i, -);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_OVF_I8)
+                       if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP(l, -);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
+                       if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP_CAST(i, -, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
+                       if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       BINOP_CAST(l, -, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ENDFINALLY)
                        if (finally_ips) {
                                ip = finally_ips->data;
                                finally_ips = g_slist_remove (finally_ips, ip);
@@ -3597,568 +3473,388 @@ array_constructed:
                        }
                        if (frame->ex)
                                goto handle_fault;
-                       /*
-                        * There was no exception, we continue normally at the target address.
-                        */
-                       ip = endfinally_ip;
-                       BREAK;
-               CASE (CEE_LEAVE) /* Fall through */
-               CASE (CEE_LEAVE_S)
-                       sp = frame->stack; /* empty the stack */
+                       ves_abort();
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LEAVE) /* Fall through */
+               MINT_IN_CASE(MINT_LEAVE_S)
+                       while (sp > frame->stack) {
+                               --sp;
+                       }
                        frame->ip = ip;
-                       if (*ip == CEE_LEAVE_S) {
-                               ++ip;
-                               ip += (signed char) *ip;
-                               ++ip;
+                       if (*ip == MINT_LEAVE_S) {
+                               ip += (short) *(ip + 1);
                        } else {
-                               ++ip;
-                               ip += (gint32) read32 (ip);
-                               ip += 4;
+                               ip += (gint32) READ32 (ip + 1);
                        }
-#if 0
-                       /*
-                        * We may be either inside a try block or inside an handler.
-                        * In the first case there was no exception and we go on
-                        * executing the finally handlers and after that resume control
-                        * at endfinally_ip.
-                        * In the second case we need to clear the exception and
-                        * continue directly at the target ip.
-                        */
-                       if (!frame->ex) {
-                               endfinally_ip = ip;
-                               goto handle_finally;
-                       } else {
-                               frame->ex = NULL;
+                       endfinally_ip = ip;
+                       if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
                                frame->ex_handler = NULL;
+                               frame->ex = NULL;
                        }
-#else
-                       frame->ex = NULL;
-                       frame->ex_handler = NULL;
-                       endfinally_ip = ip;
                        goto handle_finally;
-                       BREAK;
-#endif
-               CASE (CEE_UNUSED41)
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_ICALL_V_V) 
+               MINT_IN_CASE(MINT_ICALL_P_V) 
+               MINT_IN_CASE(MINT_ICALL_P_P)
+               MINT_IN_CASE(MINT_ICALL_PP_V)
+               MINT_IN_CASE(MINT_ICALL_PI_V)
+               MINT_IN_CASE(MINT_ICALL_PP_P)
+               MINT_IN_CASE(MINT_ICALL_PI_P)
+               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 (frame->ex != NULL)
+                               goto handle_exception;
+                       ip += 2;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MONO_LDPTR) 
+                       sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
+                       ip += 2;
+                       ++sp;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MONO_NEWOBJ)
+                       sp->data.p = mono_object_new (context->domain, rtm->data_items [*(guint16 *)(ip + 1)]);
+                       ip += 2;
+                       sp++;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_MONO_FREE)
                        ++ip;
-                       switch (*ip) {
-                       case CEE_MONO_FUNC1: {
-                               MonoMarshalConv conv;
-                               ++ip;
-
-                               conv = *ip;
-
-                               ++ip;
-
-                               sp--;
-
-                               sp->type = VAL_I32;
-                               sp->data.vt.klass = NULL;
-
-                               switch (conv) {
-                               case MONO_MARSHAL_CONV_STR_LPWSTR:
-                                       sp->data.p = mono_string_to_utf16 (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_LPSTR_STR:
-                                       sp->data.p = mono_string_new_wrapper (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_LPTSTR:
-                               case MONO_MARSHAL_CONV_STR_LPSTR:
-                                       sp->data.p = mono_string_to_utf8 (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_BSTR:
-                                       sp->data.p = mono_string_to_bstr (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_TBSTR:
-                               case MONO_MARSHAL_CONV_STR_ANSIBSTR:
-                                       sp->data.p = mono_string_to_ansibstr (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_SB_LPSTR:
-                                       sp->data.p = mono_string_builder_to_utf8 (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
-                                       sp->data.p = mono_array_to_savearray (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
-                                       sp->data.p = mono_array_to_lparray (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_DEL_FTN:
-                                       sp->data.p = mono_delegate_to_ftnptr (sp->data.p);
-                                       break;
-                               case MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY:
-                                       sp->data.p = mono_marshal_string_array (sp->data.p);
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
-                               }
-                               sp++; 
-                               break;
-                       }
-                       case CEE_MONO_PROC2: {
-                               MonoMarshalConv conv;
-                               ++ip;
-                               conv = *ip;
-                               ++ip;
-
-                               sp -= 2;
-
-                               switch (conv) {
-                               case MONO_MARSHAL_CONV_LPSTR_SB:
-                                       mono_string_utf8_to_builder (sp [0].data.p, sp [1].data.p);
-                                       break;
-                               case MONO_MARSHAL_FREE_ARRAY:
-                                       mono_marshal_free_array (sp [0].data.p, sp [1].data.i);
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
-                               }                                
-                               break;
-                       }
-                       case CEE_MONO_PROC3: {
-                               MonoMarshalConv conv;
-                               ++ip;
-                               conv = *ip;
-                               ++ip;
-
-                               sp -= 3;
-
-                               switch (conv) {
-                               case MONO_MARSHAL_CONV_STR_BYVALSTR:
-                                       mono_string_to_byvalstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
-                                       break;
-                               case MONO_MARSHAL_CONV_STR_BYVALWSTR:
-                                       mono_string_to_byvalwstr (sp [0].data.p, sp [1].data.p, sp [2].data.i);
-                                       break;
-                               default:
-                                       g_assert_not_reached ();
-                               }
-                               break;
-                       }
-                       case CEE_MONO_VTADDR: {
-                               ++ip;
-
-                               sp->type = VAL_VALUETA;
-                               /* do nothing? */
-                               break;
-                       }
-                       case CEE_MONO_LDPTR: {
-                               guint32 token;
-                               ++ip;
-                               
-                               token = read32 (ip);
-                               ip += 4;
+                       --sp;
+                       g_free (sp->data.p);
+                       MINT_IN_BREAK;
+               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);
+                       if (sp > frame->stack)
+                               g_warning ("retobj: more values on stack: %d", sp-frame->stack);
+                       goto exit_frame;
+
+#define RELOP(datamem, op) \
+       --sp; \
+       sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
+       ++ip;
+               MINT_IN_CASE(MINT_CEQ_I4)
+                       RELOP(i, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CEQ0_I4)
+                       sp [-1].data.i = (sp [-1].data.i == 0);
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CEQ_I8)
+                       RELOP(l, ==);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CEQ_R8)
+                       --sp; 
+                       if (isunordered (sp [-1].data.f, sp [0].data.f))
+                               sp [-1].data.i = 0;
+                       else
+                               sp [-1].data.i = sp [-1].data.f == sp [0].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGT_I4)
+                       RELOP(i, >);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGT_I8)
+                       RELOP(l, >);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGT_R8)
+                       --sp; 
+                       if (isunordered (sp [-1].data.f, sp [0].data.f))
+                               sp [-1].data.i = 0;
+                       else
+                               sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+
+#define RELOP_CAST(datamem, op, type) \
+       --sp; \
+       sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
+       ++ip;
+
+               MINT_IN_CASE(MINT_CGT_UN_I4)
+                       RELOP_CAST(i, >, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGT_UN_I8)
+                       RELOP_CAST(l, >, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGT_UN_R8)
+                       --sp; 
+                       if (isunordered (sp [-1].data.f, sp [0].data.f))
+                               sp [-1].data.i = 1;
+                       else
+                               sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLT_I4)
+                       RELOP(i, <);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLT_I8)
+                       RELOP(l, <);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLT_R8)
+                       --sp; 
+                       if (isunordered (sp [-1].data.f, sp [0].data.f))
+                               sp [-1].data.i = 0;
+                       else
+                               sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLT_UN_I4)
+                       RELOP_CAST(i, <, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLT_UN_I8)
+                       RELOP_CAST(l, <, guint64);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLT_UN_R8)
+                       --sp; 
+                       if (isunordered (sp [-1].data.f, sp [0].data.f))
+                               sp [-1].data.i = 1;
+                       else
+                               sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFTN) {
+                       sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
+                       ++sp;
+                       ip += 2;
+                       MINT_IN_BREAK;
+               }
+               MINT_IN_CASE(MINT_LDVIRTFTN) {
+                       RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
+                       ip += 2;
+                       --sp;
+                       if (!sp->data.p)
+                               THROW_EX (mono_get_exception_null_reference (), ip - 2);
                                
-                               sp->type = VAL_I32;
-                               sp->data.p = mono_method_get_wrapper_data (frame->method, token);
-                               sp->data.vt.klass = NULL;
-                               ++sp;
-                               break;
-                       }
-                       case CEE_MONO_FREE: {
-                               ++ip;
-
-                               sp -= 1;
-                               g_free (sp->data.p);
-                               break;
-                       }
-                       case CEE_MONO_OBJADDR: {
-                               ++ip;
-
-                               sp->type = VAL_MP;
-                               /* do nothing? */
-                               break;
-                       }
-                       case CEE_MONO_NEWOBJ: {
-                               MonoClass *class;
-                               guint32 token;
-
-                               ++ip;
-                               token = read32 (ip);
-                               ip += 4;
-
-                               class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
-                               sp->data.p = mono_object_new (domain, class);
-                               sp++;
-                               break;
-                       }
-                       case CEE_MONO_RETOBJ: {
-                               MonoClass *class;
-                               guint32 token;
-
-                               ++ip;
-                               token = read32 (ip);
-                               ip += 4;
+                       sp->data.p = get_virtual_method (m, sp->data.p);
+                       ++sp;
+                       MINT_IN_BREAK;
+               }
 
-                               sp--;
+               MINT_IN_CASE(MINT_LDTHIS)
+                       sp->data.p = frame->obj;
+                       ++ip;
+                       ++sp; 
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STTHIS)
+                       --sp; 
+                       frame->obj = sp->data.p;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDTHISA)
+                       sp->data.p = &frame->obj;
+                       ++ip;
+                       ++sp; 
+                       MINT_IN_BREAK;
 
-                               class = (MonoClass *)mono_method_get_wrapper_data (frame->method, token);
-                               
-                               stackval_from_data (signature->ret, frame->retval, sp->data.vt.vt, signature->pinvoke);
+#define LDARG(datamem, argtype) \
+       sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
+       ip += 2; \
+       ++sp; 
+       
+               MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_LDARG_VT)
+                       sp->data.p = vt_sp;
+                       i32 = READ32(ip + 2);
+                       memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
+                       vt_sp += (i32 + 7) & ~7;
+                       ip += 4;
+                       ++sp;
+                       MINT_IN_BREAK;
 
-                               if (sp > frame->stack)
-                                       g_warning ("more values on stack: %d", sp-frame->stack);
-                               DEBUG_LEAVE ();
-                               return;
-                       }
-                       default:
-                               g_error ("Unimplemented opcode: 0xF0 %02x at 0x%x\n", *ip, ip-header->code);
-                       }
-                       BREAK;
-               CASE (CEE_UNUSED26) 
-               CASE (CEE_UNUSED27) 
-               CASE (CEE_UNUSED28) 
-               CASE (CEE_UNUSED29) 
-               CASE (CEE_UNUSED30) 
-               CASE (CEE_UNUSED31) 
-               CASE (CEE_UNUSED32) 
-               CASE (CEE_UNUSED33) 
-               CASE (CEE_UNUSED34) 
-               CASE (CEE_UNUSED35) 
-               CASE (CEE_UNUSED36) 
-               CASE (CEE_UNUSED37) 
-               CASE (CEE_UNUSED38) 
-               CASE (CEE_UNUSED39) 
-               CASE (CEE_UNUSED40) 
-               CASE (CEE_UNUSED42) 
-               CASE (CEE_UNUSED43) 
-               CASE (CEE_UNUSED44) 
-               CASE (CEE_UNUSED45) 
-               CASE (CEE_UNUSED46) 
-               CASE (CEE_UNUSED47) 
-               CASE (CEE_UNUSED48)
-               CASE (CEE_PREFIX7)
-               CASE (CEE_PREFIX6)
-               CASE (CEE_PREFIX5)
-               CASE (CEE_PREFIX4)
-               CASE (CEE_PREFIX3)
-               CASE (CEE_PREFIX2)
-               CASE (CEE_PREFIXREF) ves_abort(); BREAK;
-               /*
-                * Note: Exceptions thrown when executing a prefixed opcode need
-                * to take into account the number of prefix bytes (usually the
-                * throw point is just (ip - n_prefix_bytes).
-                */
-               SUB_SWITCH
-                       ++ip;
-                       switch (*ip) {
-                       case CEE_ARGLIST: ves_abort(); break;
-                       case CEE_CEQ: {
-                               gint32 result;
-                               ++ip;
-                               sp -= 2;
-
-                               if (sp->type == VAL_I32)
-                                       result = sp [0].data.i == (gint)GET_NATI (sp [1]);
-                               else if (sp->type == VAL_I64)
-                                       result = sp [0].data.l == sp [1].data.l;
-                               else if (sp->type == VAL_DOUBLE) {
-                                       if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
-                                               result = 0;
-                                       else
-                                               result = sp [0].data.f == sp [1].data.f;
-                               } else
-                                       result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
-                               sp->type = VAL_I32;
-                               sp->data.i = result;
+#define STARG(datamem, argtype) \
+       --sp; \
+       * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
+       ip += 2; \
+       
+               MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_STARG_VT) 
+                       i32 = READ32(ip + 2);
+                       --sp;
+                       memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
+                       vt_sp -= (i32 + 7) & ~7;
+                       ip += 4;
+                       MINT_IN_BREAK;
 
-                               sp++;
-                               break;
-                       }
-                       case CEE_CGT: {
-                               gint32 result;
-                               ++ip;
-                               sp -= 2;
-
-                               if (sp->type == VAL_I32)
-                                       result = sp [0].data.i > (gint)GET_NATI (sp [1]);
-                               else if (sp->type == VAL_I64)
-                                       result = sp [0].data.l > sp [1].data.l;
-                               else if (sp->type == VAL_DOUBLE) {
-                                       if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
-                                               result = 0;
-                                       else
-                                               result = sp [0].data.f > sp [1].data.f;
-                               } else
-                                       result = (gint)GET_NATI (sp [0]) > (gint)GET_NATI (sp [1]);
-                               sp->type = VAL_I32;
-                               sp->data.i = result;
+#define STINARG(datamem, argtype) \
+       do { \
+               int n = * (guint16 *)(ip + 1); \
+               * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
+               ip += 2; \
+       } while (0)
+       
+               MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_STINARG_VT) {
+                       int n = * (guint16 *)(ip + 1);
+                       i32 = READ32(ip + 2);
+                       memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
+                       ip += 4;
+                       MINT_IN_BREAK;
+               }
 
-                               sp++;
-                               break;
-                       }
-                       case CEE_CGT_UN: {
-                               gint32 result;
-                               ++ip;
-                               sp -= 2;
-
-                               if (sp->type == VAL_I32)
-                                       result = (guint32)sp [0].data.i > (mono_u)GET_NATI (sp [1]);
-                               else if (sp->type == VAL_I64)
-                                       result = (guint64)sp [0].data.l > (guint64)sp [1].data.l;
-                               else if (sp->type == VAL_DOUBLE)
-                                       result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
-                               else
-                                       result = (mono_u)GET_NATI (sp [0]) > (mono_u)GET_NATI (sp [1]);
-                               sp->type = VAL_I32;
-                               sp->data.i = result;
+               MINT_IN_CASE(MINT_LDARGA)
+                       sp->data.p = frame->args + * (guint16 *)(ip + 1);
+                       ip += 2;
+                       ++sp;
+                       MINT_IN_BREAK;
 
-                               sp++;
-                               break;
-                       }
-                       case CEE_CLT: {
-                               gint32 result;
-                               ++ip;
-                               sp -= 2;
-
-                               if (sp->type == VAL_I32)
-                                       result = sp [0].data.i < (gint)GET_NATI (sp [1]);
-                               else if (sp->type == VAL_I64)
-                                       result = sp [0].data.l < sp [1].data.l;
-                               else if (sp->type == VAL_DOUBLE) {
-                                       if (isnan (sp [0].data.f) || isnan (sp [1].data.f))
-                                               result = 0;
-                                       else
-                                               result = sp [0].data.f < sp [1].data.f;
-                               } else
-                                       result = (gint)GET_NATI (sp [0]) < (gint)GET_NATI (sp [1]);
-                               sp->type = VAL_I32;
-                               sp->data.i = result;
+#define LDLOC(datamem, argtype) \
+       sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
+       ip += 2; \
+       ++sp; 
+       
+               MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_LDLOC_VT)
+                       sp->data.p = vt_sp;
+                       i32 = READ32(ip + 2);
+                       memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
+                       vt_sp += (i32 + 7) & ~7;
+                       ip += 4;
+                       ++sp;
+                       MINT_IN_BREAK;
 
-                               sp++;
-                               break;
-                       }
-                       case CEE_CLT_UN: {
-                               gint32 result;
-                               ++ip;
-                               sp -= 2;
-
-                               if (sp->type == VAL_I32)
-                                       result = (guint32)sp [0].data.i < (mono_u)GET_NATI (sp [1]);
-                               else if (sp->type == VAL_I64)
-                                       result = (guint64)sp [0].data.l < (guint64)sp [1].data.l;
-                               else if (sp->type == VAL_DOUBLE)
-                                       result = isnan (sp [0].data.f) || isnan (sp [1].data.f);
-                               else
-                                       result = (mono_u)GET_NATI (sp [0]) < (mono_u)GET_NATI (sp [1]);
-                               sp->type = VAL_I32;
-                               sp->data.i = result;
+               MINT_IN_CASE(MINT_LDLOCA_S)
+                       sp->data.p = locals + * (guint16 *)(ip + 1);
+                       ip += 2;
+                       ++sp;
+                       MINT_IN_BREAK;
 
-                               sp++;
-                               break;
-                       }
-                       case CEE_LDFTN:
-                       case CEE_LDVIRTFTN: {
-                               int virtual = *ip == CEE_LDVIRTFTN;
-                               MonoMethod *m;
-                               guint32 token;
-                               ++ip;
-                               token = read32 (ip);
-                               ip += 4;
-
-                               if (frame->method->wrapper_type != MONO_WRAPPER_NONE)
-                                       m = (MonoMethod *)mono_method_get_wrapper_data (frame->method, token);
-                               else 
-                                       m = mono_get_method (image, token, NULL);
-
-                               if (!m)
-                                       THROW_EX (mono_get_exception_missing_method (), ip - 5);
-                               if (virtual) {
-                                       --sp;
-                                       if (!sp->data.p)
-                                               THROW_EX (mono_get_exception_null_reference (), ip - 5);
-                                       
-                                       m = get_virtual_method (domain, m, sp);
-                               }
-                               sp->type = VAL_NATI;
-                               sp->data.p = mono_create_method_pointer (m);
-                               sp->data.vt.klass = NULL;
-                               ++sp;
-                               break;
-                       }
-                       case CEE_UNUSED56: ves_abort(); break;
-                       case CEE_LDARG: {
-                               guint32 arg_pos;
-                               ++ip;
-                               arg_pos = read16 (ip);
-                               ip += 2;
-                               vt_alloc (ARG_TYPE (signature, arg_pos), sp, signature->pinvoke);
-                               stackval_from_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
-                               ++sp;
-                               break;
-                       }
-                       case CEE_LDARGA: {
-                               MonoType *t;
-                               MonoClass *c;
-                               guint32 anum;
-
-                               ++ip;
-                               anum = read16 (ip);
-                               ip += 2;
-                               t = ARG_TYPE (signature, anum);
-                               c = mono_class_from_mono_type (t);
-                               sp->data.vt.klass = c;
-                               sp->data.vt.vt = ARG_POS (anum);
-
-                               if (c->valuetype)
-                                       sp->type = VAL_VALUETA;
-                               else
-                                       sp->type = VAL_TP;
-
-                               ++sp;
-                               break;
-                       }
-                       case CEE_STARG: {
-                               guint32 arg_pos;
-                               ++ip;
-                               arg_pos = read16 (ip);
-                               ip += 2;
-                               --sp;
-                               stackval_to_data (ARG_TYPE (signature, arg_pos), sp, ARG_POS (arg_pos), signature->pinvoke);
-                               vt_free (sp);
-                               break;
-                       }
-                       case CEE_LDLOC: {
-                               guint32 loc_pos;
-                               ++ip;
-                               loc_pos = read16 (ip);
-                               ip += 2;
-                               vt_alloc (LOCAL_TYPE (header, loc_pos), sp, FALSE);
-                               stackval_from_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
-                               ++sp;
-                               break;
-                       }
-                       case CEE_LDLOCA: {
-                               MonoType *t;
-                               MonoClass *c;
-                               guint32 loc_pos;
-
-                               ++ip;
-                               loc_pos = read16 (ip);
-                               ip += 2;
-                               t = LOCAL_TYPE (header, loc_pos);
-                               c =  mono_class_from_mono_type (t);
-                               sp->data.vt.vt = LOCAL_POS (loc_pos);
-                               sp->data.vt.klass = c;
-
-                               if (c->valuetype) 
-                                       sp->type = VAL_VALUETA;
-                               else
-                                       sp->type = VAL_TP;
-
-                               ++sp;
-                               break;
-                       }
-                       case CEE_STLOC: {
-                               guint32 loc_pos;
-                               ++ip;
-                               loc_pos = read16 (ip);
-                               ip += 2;
-                               --sp;
-                               stackval_to_data (LOCAL_TYPE (header, loc_pos), sp, LOCAL_POS (loc_pos), FALSE);
-                               vt_free (sp);
-                               break;
-                       }
-                       case CEE_LOCALLOC:
-                               --sp;
-                               if (sp != frame->stack)
-                                       THROW_EX (mono_get_exception_execution_engine (NULL), ip - 1);
-                               ++ip;
-                               sp->data.p = alloca (sp->data.i);
-                               sp->type = VAL_TP;
-                               sp++;
-                               break;
-                       case CEE_UNUSED57: ves_abort(); break;
-                       case CEE_ENDFILTER: ves_abort(); break;
-                       case CEE_UNALIGNED_:
-                               ++ip;
-                               unaligned_address = 1;
-                               break;
-                       case CEE_VOLATILE_:
-                               ++ip;
-                               volatile_address = 1;
-                               break;
-                       case CEE_TAIL_:
-                               ++ip;
-                               tail_recursion = 1;
-                               break;
-                       case CEE_INITOBJ: {
-                               guint32 token;
-                               ++ip;
-                               token = read32 (ip);
-                               ip += 4;
-                               /*
-                                * we ignore the value of token (I think we can as unspecified
-                                * behavior described in Partition II, 3.5).
-                                */
-                               --sp;
-                               g_assert (sp->type == VAL_VALUETA || sp->type == VAL_TP);
-                               memset (sp->data.vt.vt, 0, mono_class_value_size (sp->data.vt.klass, NULL));
-                               break;
-                       }
-                       case CEE_UNUSED68: ves_abort(); break;
-                       case CEE_CPBLK:
-                               sp -= 3;
-                               if (!sp [0].data.p || !sp [1].data.p)
-                                       THROW_EX (mono_get_exception_null_reference(), ip - 1);
-                               ++ip;
-                               /* FIXME: value and size may be int64... */
-                               memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
-                               break;
-                       case CEE_INITBLK:
-                               sp -= 3;
-                               if (!sp [0].data.p)
-                                       THROW_EX (mono_get_exception_null_reference(), ip - 1);
-                               ++ip;
-                               /* FIXME: value and size may be int64... */
-                               memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
-                               break;
-                       case CEE_UNUSED69: ves_abort(); break;
-                       case CEE_RETHROW:
-                               /* 
-                                * need to clarify what this should actually do:
-                                * start the search from the last found handler in
-                                * this method or continue in the caller or what.
-                                * Also, do we need to run finally/fault handlers after a retrow?
-                                * Well, this implementation will follow the usual search
-                                * for an handler, considering the current ip as throw spot.
-                                * We need to NULL frame->ex_handler for the later code to
-                                * actually run the new found handler.
-                                */
-                               frame->ex_handler = NULL;
-                               THROW_EX (frame->ex, ip - 1);
-                               break;
-                       case CEE_UNUSED: ves_abort(); break;
-                       case CEE_SIZEOF: {
-                               guint32 token;
-                               int align;
-                               ++ip;
-                               token = read32 (ip);
-                               ip += 4;
-                               if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
-                                       MonoType *type = mono_type_create_from_typespec (image, token);
-                                       sp->data.i = mono_type_size (type, &align);
-                                       mono_metadata_free_type (type);
-                               } else {
-                                       MonoClass *szclass = mono_class_get (image, token);
-                                       mono_class_init (szclass);
-                                       if (!szclass->valuetype)
-                                               THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
-                                       sp->data.i = mono_class_value_size (szclass, &align);
-                               }
-                               sp->type = VAL_I32;
-                               ++sp;
-                               break;
-                       }
-                       case CEE_REFANYTYPE: ves_abort(); break;
-                       case CEE_UNUSED52: 
-                       case CEE_UNUSED53: 
-                       case CEE_UNUSED54: 
-                       case CEE_UNUSED55: 
-                       case CEE_UNUSED70: 
-                       default:
-                               g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-header->code);
-                       }
-                       continue;
-               DEFAULT;
+#define STLOC(datamem, argtype) \
+       --sp; \
+       * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
+       ip += 2;
+       
+               MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
+
+#define STLOC_NP(datamem, argtype) \
+       * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
+       ip += 2;
+
+               MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_STLOC_VT)
+                       i32 = READ32(ip + 2);
+                       --sp;
+                       memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
+                       vt_sp -= (i32 + 7) & ~7;
+                       ip += 4;
+                       MINT_IN_BREAK;
+
+               MINT_IN_CASE(MINT_LOCALLOC)
+                       if (sp != frame->stack + 1) /*FIX?*/
+                               THROW_EX (mono_get_exception_execution_engine (NULL), ip);
+                       sp [-1].data.p = alloca (sp [-1].data.i);
+                       ++ip;
+                       MINT_IN_BREAK;
+#if 0
+               MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK;
+#endif
+               MINT_IN_CASE(MINT_INITOBJ)
+                       --sp;
+                       memset (sp->data.vt, 0, READ32(ip + 1));
+                       ip += 3;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CPBLK)
+                       sp -= 3;
+                       if (!sp [0].data.p || !sp [1].data.p)
+                               THROW_EX (mono_get_exception_null_reference(), ip - 1);
+                       ++ip;
+                       /* FIXME: value and size may be int64... */
+                       memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
+                       MINT_IN_BREAK;
+#if 0
+               MINT_IN_CASE(MINT_CONSTRAINED_) {
+                       guint32 token;
+                       /* FIXME: implement */
+                       ++ip;
+                       token = READ32 (ip);
+                       ip += 2;
+                       MINT_IN_BREAK;
+               }
+#endif
+               MINT_IN_CASE(MINT_INITBLK)
+                       sp -= 3;
+                       if (!sp [0].data.p)
+                               THROW_EX (mono_get_exception_null_reference(), ip - 1);
+                       ++ip;
+                       /* FIXME: value and size may be int64... */
+                       memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
+                       MINT_IN_BREAK;
+#if 0
+               MINT_IN_CASE(MINT_NO_)
+                       /* FIXME: implement */
+                       ip += 2;
+                       MINT_IN_BREAK;
+#endif
+               MINT_IN_CASE(MINT_RETHROW)
+                       /* 
+                        * need to clarify what this should actually do:
+                        * start the search from the last found handler in
+                        * this method or continue in the caller or what.
+                        * Also, do we need to run finally/fault handlers after a retrow?
+                        * Well, this implementation will follow the usual search
+                        * for an handler, considering the current ip as throw spot.
+                        * We need to NULL frame->ex_handler for the later code to
+                        * actually run the new found handler.
+                        */
+                       frame->ex_handler = NULL;
+                       THROW_EX (frame->ex, ip - 1);
+                       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);
                }
        }
 
@@ -4173,30 +3869,37 @@ array_constructed:
                int i;
                guint32 ip_offset;
                MonoInvocation *inv;
-               MonoMethodHeader *hd;
                MonoExceptionClause *clause;
                /*char *message;*/
                MonoObject *ex_obj;
 
 #if DEBUG_INTERP
                if (tracing)
-                       g_print ("* Handling exception '%s' at IL_%04x\n", mono_object_class (frame->ex)->name, frame->ip - header->code);
+                       g_print ("* Handling exception '%s' at IL_%04x\n", 
+                               frame->ex == NULL ? "** Unknown **" : mono_object_class (frame->ex)->name, 
+                               rtm == NULL ? 0 : frame->ip - rtm->code);
 #endif
                if (die_on_exception)
                        goto die_on_ex;
-               
+
                for (inv = frame; inv; inv = inv->parent) {
-                       if (inv->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+                       MonoMethod *method;
+                       if (inv->runtime_method == NULL)
+                               continue;
+                       method = inv->runtime_method->method;
+                       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+                               continue;
+                       if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
                                continue;
-                       if (inv->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))
+                       if (inv->ip == NULL)
                                continue;
-                       hd = ((MonoMethodNormal*)inv->method)->header;
-                       ip_offset = inv->ip - hd->code;
-                       for (i = 0; i < hd->num_clauses; ++i) {
-                               clause = &hd->clauses [i];
+                       ip_offset = inv->ip - inv->runtime_method->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) {
-                                               if (mono_object_isinst ((MonoObject*)frame->ex, mono_class_get (inv->method->klass->image, clause->token_or_filter))) {
+                                               if (mono_object_isinst ((MonoObject*)frame->ex, clause->data.catch_class)) {
                                                        /* 
                                                         * OK, we found an handler, now we need to execute the finally
                                                         * and fault blocks before branching to the handler code.
@@ -4204,16 +3907,9 @@ array_constructed:
                                                        inv->ex_handler = clause;
 #if DEBUG_INTERP
                                                        if (tracing)
-                                                               g_print ("* Found handler at '%s'\n", inv->method->name);
+                                                               g_print ("* Found handler at '%s'\n", method->name);
 #endif
-                                                       /*
-                                                        * It seems that if the catch handler is found in the same method,
-                                                        * it gets executed before the finally handler.
-                                                        */
-                                                       if (inv == frame)
-                                                               goto handle_fault;
-                                                       else
-                                                               goto handle_finally;
+                                                       goto handle_finally;
                                                }
                                        } else {
                                                /* FIXME: handle filter clauses */
@@ -4239,26 +3935,32 @@ die_on_ex:
                int i;
                guint32 ip_offset;
                MonoExceptionClause *clause;
+               GSList *old_list = finally_ips;
+               MonoMethod *method = frame->runtime_method->method;
+               MonoMethodHeader *header = mono_method_get_header (method);
                
 #if DEBUG_INTERP
                if (tracing)
-                       g_print ("* Handle finally\n");
+                       g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
 #endif
-               if ((frame->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) 
-                               || (frame->method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
-                       DEBUG_LEAVE ();
-                       return;
+               if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) 
+                               || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
+                       goto exit_frame;
                }
-               ip_offset = frame->ip - header->code;
+               ip_offset = frame->ip - rtm->code;
 
-               for (i = 0; i < header->num_clauses; ++i) {
-                       clause = &header->clauses [i];
-                       if (clause == frame->ex_handler)
+               if (endfinally_ip != NULL)
+                       finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
+               for (i = 0; i < header->num_clauses; ++i)
+                       if (frame->ex_handler == &rtm->clauses [i])
                                break;
-                       if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - header->code))) {
+               while (i > 0) {
+                       --i;
+                       clause = &rtm->clauses [i];
+                       if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
                                if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
-                                       ip = header->code + clause->handler_offset;
-                                       finally_ips = g_slist_append (finally_ips, (gpointer) ip);
+                                       ip = rtm->code + clause->handler_offset;
+                                       finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
 #if DEBUG_INTERP
                                        if (tracing)
                                                g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
@@ -4266,9 +3968,13 @@ die_on_ex:
                                }
                        }
                }
-               if (finally_ips) {
+
+               endfinally_ip = NULL;
+
+               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;
                }
 
@@ -4278,24 +3984,24 @@ die_on_ex:
                 */
                if (frame->ex)
                        goto handle_fault;
-               ip = endfinally_ip;
-               goto main_loop;
+               ves_abort();
        }
        handle_fault:
        {
                int i;
                guint32 ip_offset;
                MonoExceptionClause *clause;
+               MonoMethodHeader *header = mono_method_get_header (frame->runtime_method->method);
                
 #if DEBUG_INTERP
                if (tracing)
                        g_print ("* Handle fault\n");
 #endif
-               ip_offset = frame->ip - header->code;
+               ip_offset = frame->ip - rtm->code;
                for (i = 0; i < header->num_clauses; ++i) {
-                       clause = &header->clauses [i];
-                       if (clause->flags == 3 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
-                               ip = header->code + clause->handler_offset;
+                       clause = &rtm->clauses [i];
+                       if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
+                               ip = rtm->code + clause->handler_offset;
 #if DEBUG_INTERP
                                if (tracing)
                                        g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
@@ -4315,36 +4021,78 @@ die_on_ex:
                        if (tracing)
                                g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
 #endif
-                       ip = header->code + frame->ex_handler->handler_offset;
+                       ip = rtm->code + frame->ex_handler->handler_offset;
                        sp = frame->stack;
-                       sp->type = VAL_OBJ;
+                       vt_sp = (char *)sp + rtm->stack_size;
                        sp->data.p = frame->ex;
                        ++sp;
                        goto main_loop;
                }
-               if (!frame->parent)
-                       goto die_on_ex;
-               DEBUG_LEAVE ();
+               goto exit_frame;
+       }
+exit_frame:
+       DEBUG_LEAVE ();
+}
+
+void
+ves_exec_method (MonoInvocation *frame)
+{
+       ThreadContext *context = TlsGetValue (thread_context_id);
+       ThreadContext context_struct;
+       jmp_buf env;
+
+       frame->ex = NULL;
+
+       if (setjmp(env)) {
+               mono_unhandled_exception ((MonoObject*)frame->ex);
                return;
        }
-       
+       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;
+               TlsSetValue (thread_context_id, context);
+       }
+       frame->ip = NULL;
+       frame->parent = context->current_frame;
+       frame->runtime_method = mono_interp_get_runtime_method (frame->method);
+       context->managed_code = 1;
+       ves_exec_method_with_context(frame, context);
+       context->managed_code = 0;
+       if (frame->ex) {
+               if (context != &context_struct && context->current_env) {
+                       context->env_frame->ex = frame->ex;
+                       longjmp (*context->current_env, 1);
+               }
+               else
+                       mono_unhandled_exception ((MonoObject*)frame->ex);
+       }
+       if (context->base_frame == frame)
+               TlsSetValue (thread_context_id, NULL);
+       else
+               context->current_frame = frame->parent;
 }
 
 static int 
 ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
 {
-       MonoImage *image = assembly->image;
-       MonoCLIImageInfo *iinfo;
+       MonoImage *image = mono_assembly_get_image (assembly);
        MonoMethod *method;
        MonoObject *exc = NULL;
        int rval;
 
-       iinfo = image->image_info;
-       method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
+       method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
        if (!method)
-               g_error ("No entry point method found in %s", image->name);
+               g_error ("No entry point method found in %s", mono_image_get_filename (image));
 
        rval = mono_runtime_run_main (method, argc, argv, &exc);
+       if (exc != NULL)
+               mono_unhandled_exception (exc);
 
        return rval;
 }
@@ -4394,33 +4142,101 @@ test_load_class (MonoImage* image)
 }
 #endif
 
-static MonoException * segv_exception = NULL;
+static void
+add_signal_handler (int signo, void (*handler)(int))
+{
+#ifdef PLATFORM_WIN32
+       signal (signo, handler);
+#else
+       struct sigaction sa;
+
+       sa.sa_handler = handler;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = 0;
+
+       g_assert (sigaction (signo, &sa, NULL) != -1);
+#endif
+}
 
 static void
 segv_handler (int signum)
 {
-       signal (signum, segv_handler);
+       ThreadContext *context = TlsGetValue (thread_context_id);
+       MonoException *segv_exception;
+
+       if (context == NULL)
+               return;
+       segv_exception = mono_get_exception_null_reference ();
+       segv_exception->message = mono_string_new (mono_domain_get (), "Null Reference (SIGSEGV)");
        mono_raise_exception (segv_exception);
 }
 
+
+static void
+quit_handler (int signum)
+{
+       ThreadContext *context = TlsGetValue (thread_context_id);
+       MonoException *quit_exception;
+
+       if (context == NULL)
+               return;
+       quit_exception = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
+       mono_raise_exception (quit_exception);
+}
+
+static void
+abrt_handler (int signum)
+{
+       ThreadContext *context = TlsGetValue (thread_context_id);
+       MonoException *abrt_exception;
+
+       if (context == NULL)
+               return;
+       abrt_exception = mono_get_exception_execution_engine ("Abort (SIGABRT).");
+       mono_raise_exception (abrt_exception);
+}
+
+static void
+thread_abort_handler (int signum)
+{
+       ThreadContext *context = TlsGetValue (thread_context_id);
+       MonoException *exc;
+
+       if (context == NULL)
+               return;
+
+       exc = mono_thread_request_interruption (context->managed_code); 
+       if (exc) mono_raise_exception (exc);
+}
+
 static MonoBoolean
 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 = TlsGetValue (thread_context_id);
+       MonoInvocation *inv = context->current_frame;
+       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)
-               *method = NULL;
+               *method = inv == NULL ? NULL : mono_method_get_object (context->domain, inv->runtime_method->method, NULL);
        if (line)
                *line = 0;
-       if (column)
-               *column = 0;
-       if (file)
-               *file = mono_string_new (mono_domain_get (), "unknown");
+       if (need_file_info) {
+               if (column)
+                       *column = 0;
+               if (file)
+                       *file = mono_string_new (mono_domain_get (), "unknown");
+       }
 
        return TRUE;
 }
@@ -4428,9 +4244,68 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 static MonoArray *
 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
 {
-       return NULL;
+       MonoDomain *domain = mono_domain_get ();
+       MonoArray *res;
+       MonoArray *ta = exc->trace_ips;
+       int i, len;
+
+       if (ta == NULL) {
+               /* Exception is not thrown yet */
+               return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
+       }
+       
+       len = mono_array_length (ta);
+
+       res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
+
+       for (i = skip; i < len / 2; i++) {
+               MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
+               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 (domain, rtm->method, NULL);
+                       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);
+
+                       sf->filename = filename? mono_string_new (domain, filename): NULL;
+                       sf->column = 0;
+
+                       g_free (filename);
+               }
+#endif
+
+               mono_array_set (res, gpointer, i, sf);
+       }
+
+       return res;
+}
+
+static MonoObject *
+ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, MonoObject *target,
+                                                  MonoReflectionMethod *info)
+{
+       MonoClass *delegate_class = mono_class_from_mono_type (type->type);
+       MonoObject *delegate;
+
+       mono_assert (delegate_class->parent == mono_defaults.multicastdelegate_class);
+
+       delegate = mono_object_new (mono_object_domain (type), delegate_class);
+
+       interp_delegate_ctor (mono_object_domain (type), delegate, target, mono_interp_get_runtime_method (info->method));
+
+       return delegate;
 }
 
+
 typedef struct
 {
        MonoDomain *domain;
@@ -4444,10 +4319,11 @@ static void main_thread_handler (gpointer user_data)
 {
        MainThreadArgs *main_args=(MainThreadArgs *)user_data;
        MonoAssembly *assembly;
-       char *error;
 
-       if (main_args->enable_debugging)
+       if (main_args->enable_debugging) {
                mono_debug_init (MONO_DEBUG_FORMAT_MONO);
+               mono_debug_init_1 (main_args->domain);
+       }
 
        assembly = mono_domain_assembly_open (main_args->domain,
                                              main_args->file);
@@ -4463,14 +4339,6 @@ static void main_thread_handler (gpointer user_data)
 #ifdef RUN_TEST
        test_load_class (assembly->image);
 #else
-       error = mono_verify_corlib ();
-       if (error) {
-               fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
-               exit (1);
-       }
-       segv_exception = mono_get_exception_null_reference ();
-       segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
-       signal (SIGSEGV, segv_handler);
 
        ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
 #endif
@@ -4479,21 +4347,100 @@ static void main_thread_handler (gpointer user_data)
 static void
 mono_runtime_install_handlers (void)
 {
-       /* FIXME: anything to do here? */
+       add_signal_handler (SIGSEGV, segv_handler);
+       add_signal_handler (SIGINT, quit_handler);
+       add_signal_handler (SIGABRT, abrt_handler);
+       add_signal_handler (mono_thread_get_abort_signal (), thread_abort_handler);
+}
+
+static void
+quit_function (MonoDomain *domain, gpointer user_data)
+{
+       mono_profiler_shutdown ();
+       
+       mono_runtime_cleanup (domain);
+       mono_domain_free (domain, TRUE);
+
+}
+
+void
+mono_interp_cleanup(MonoDomain *domain)
+{
+       quit_function (domain, NULL);
+}
+
+int
+mono_interp_exec(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
+{
+       return ves_exec (domain, assembly, argc, argv);
+}
+
+MonoDomain *
+mono_interp_init(const char *file)
+{
+       MonoDomain *domain;
+
+       g_set_prgname (file);
+       mono_set_rootdir ();
+       
+       g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
+       g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
+
+       if (!g_thread_supported ())
+               g_thread_init (NULL);
+
+       thread_context_id = TlsAlloc ();
+       TlsSetValue (thread_context_id, NULL);
+       InitializeCriticalSection (&runtime_method_lookup_section);
+       InitializeCriticalSection (&create_method_pointer_mutex);
+
+       mono_runtime_install_handlers ();
+       mono_interp_transform_init ();
+       mono_install_compile_method (mono_create_method_pointer);
+       mono_install_runtime_invoke (interp_mono_runtime_invoke);
+       mono_install_remoting_trampoline (interp_create_remoting_trampoline);
+       mono_install_trampoline (interp_create_trampoline);
+
+       mono_install_handler (interp_ex_handler);
+       mono_install_stack_walk (interp_walk_stack);
+       mono_install_runtime_cleanup (quit_function);
+       abort_requested = mono_thread_interruption_request_flag ();
+
+       domain = mono_init_from_assembly (file, file);
+#ifdef __hpux /* generates very big stack frames */
+       mono_threads_set_default_stacksize(32*1024*1024);
+#endif
+       mono_icall_init ();
+       mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
+       mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
+       mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
+       mono_add_internal_call ("System.Delegate::CreateDelegate_internal", ves_icall_System_Delegate_CreateDelegate_internal);
+
+       mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", mono_create_icall_signature ("void"), FALSE);
+
+       mono_runtime_init (domain, NULL, NULL);
+
+
+       mono_thread_attach (domain);
+       return domain;
 }
 
 int 
-main (int argc, char *argv [])
+mono_main (int argc, char *argv [])
 {
        MonoDomain *domain;
-       int retval = 0, i, ocount = 0;
+       int retval = 0, i;
        char *file, *config_file = NULL;
        int enable_debugging = FALSE;
        MainThreadArgs main_args;
-       
+       const char *error;
+
+       setlocale (LC_ALL, "");
        if (argc < 2)
                usage ();
 
+       MONO_GC_PRE_INIT ();
+       
        for (i = 1; i < argc && argv [i][0] == '-'; i++){
                if (strcmp (argv [i], "--trace") == 0)
                        global_tracing = 1;
@@ -4501,6 +4448,8 @@ main (int argc, char *argv [])
                        global_no_pointers = 1;
                if (strcmp (argv [i], "--traceops") == 0)
                        global_tracing = 2;
+               if (strcmp (argv [i], "--traceopt") == 0)
+                       ++mono_interp_traceopt;
                if (strcmp (argv [i], "--dieonex") == 0) {
                        die_on_exception = 1;
                        enable_debugging = 1;
@@ -4509,8 +4458,6 @@ main (int argc, char *argv [])
                        mono_print_vtable = TRUE;
                if (strcmp (argv [i], "--profile") == 0)
                        mono_profiler_load (NULL);
-               if (strcmp (argv [i], "--opcode-count") == 0)
-                       ocount = 1;
                if (strcmp (argv [i], "--config") == 0)
                        config_file = argv [++i];
                if (strcmp (argv [i], "--workers") == 0) {
@@ -4527,6 +4474,8 @@ main (int argc, char *argv [])
                                g_error ("Invalid method name '%s'", argv [i]);
                        db_methods = g_list_append (db_methods, desc);
                }
+               if (strcmp (argv [i], "--nested") == 0)
+                       nested_trace = 1;
 #endif
        }
        
@@ -4535,31 +4484,15 @@ main (int argc, char *argv [])
        if (!file)
                usage ();
 
-       g_set_prgname (file);
-       mono_set_rootdir ();
+       domain = mono_interp_init(file);
        mono_config_parse (config_file);
-       
-       g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
-       g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
-
-       mono_init_icall ();
-       mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
-       mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
-       mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
-
-       frame_thread_id = TlsAlloc ();
-       TlsSetValue (frame_thread_id, NULL);
-
-       mono_install_compile_method (mono_create_method_pointer);
-       mono_install_runtime_invoke (interp_mono_runtime_invoke);
-       mono_install_remoting_trampoline (interp_create_remoting_trampoline);
-
-       mono_install_handler (interp_ex_handler);
-       mono_install_stack_walk (interp_walk_stack);
 
-       InitializeCriticalSection (&metadata_lock);
-       domain = mono_init (file);
-       mono_runtime_init (domain, NULL, NULL);
+       error = mono_check_corlib_version ();
+       if (error) {
+               fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
+               fprintf (stderr, "Download a newer corlib at http://www.go-mono.com/daily.\n");
+               exit (1);
+       }
 
        main_args.domain=domain;
        main_args.file=file;
@@ -4569,20 +4502,16 @@ main (int argc, char *argv [])
        
        mono_runtime_exec_managed_code (domain, main_thread_handler,
                                        &main_args);
-       
-       mono_profiler_shutdown ();
-       
-       mono_runtime_cleanup (domain);
-       mono_domain_unload (domain, TRUE);
+
+       quit_function (domain, NULL);
 
        /* Get the return value from System.Environment.ExitCode */
        retval=mono_environment_exitcode_get ();
 
-#if DEBUG_INTERP
-       if (ocount) {
-               fprintf (stderr, "opcode count: %ld\n", opcode_count);
-               fprintf (stderr, "fcall count: %ld\n", fcall_count);
-       }
+#if COUNT_OPS
+       for (i = 0; i < 512; i++)
+               if (opcode_counts[i] != 0)
+                       printf("%s %d\n", mono_interp_opname[i], opcode_counts[i]);
 #endif
        return retval;
 }