Tue Oct 4 20:23:25 CEST 2005 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index 08cb35c5d2e52738dc1b1b85139f921d3e1bc3ff..1e0dfc46dedcc1314e1e522d3baff3251ea016d8 100644 (file)
@@ -48,6 +48,8 @@
 #include <mono/metadata/mono-debug-debugger.h>
 #include <mono/metadata/monitor.h>
 #include <mono/metadata/security-manager.h>
+#include <mono/metadata/threads-types.h>
+#include <mono/metadata/rawbuffer.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/os/gc_wrapper.h>
@@ -86,48 +88,8 @@ static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlo
 
 extern guint8 mono_burg_arity [];
 /* helper methods signature */
-static MonoMethodSignature *helper_sig_int_int_int = NULL;
-static MonoMethodSignature *helper_sig_long_long_long = NULL;
-static MonoMethodSignature *helper_sig_long_long_int = NULL;
-static MonoMethodSignature *helper_sig_newarr = NULL;
-static MonoMethodSignature *helper_sig_newarr_specific = NULL;
-static MonoMethodSignature *helper_sig_ldstr = NULL;
-static MonoMethodSignature *helper_sig_domain_get = NULL;
-static MonoMethodSignature *helper_sig_object_new = NULL;
-static MonoMethodSignature *helper_sig_object_new_specific = NULL;
-static MonoMethodSignature *helper_sig_compile = NULL;
-static MonoMethodSignature *helper_sig_compile_virt = NULL;
-static MonoMethodSignature *helper_sig_obj_ptr = NULL;
-static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
-static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
-static MonoMethodSignature *helper_sig_obj_obj_obj_ptr = NULL;
-static MonoMethodSignature *helper_sig_void_obj_obj_ptr = NULL;
-static MonoMethodSignature *helper_sig_obj_void = NULL;
-static MonoMethodSignature *helper_sig_ptr_void = NULL;
-static MonoMethodSignature *helper_sig_void_void = NULL;
-static MonoMethodSignature *helper_sig_void_ptr = NULL;
-static MonoMethodSignature *helper_sig_void_obj = NULL;
-static MonoMethodSignature *helper_sig_void_obj_ptr_int = NULL;
-static MonoMethodSignature *helper_sig_void_obj_ptr_ptr_obj = NULL;
-static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
-static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
-static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
-static MonoMethodSignature *helper_sig_ptr_ptr_ptr_ptr = NULL;
-static MonoMethodSignature *helper_sig_ptr_obj = NULL;
-static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
-static MonoMethodSignature *helper_sig_ptr_int = NULL;
-static MonoMethodSignature *helper_sig_ulong_double = NULL;
-static MonoMethodSignature *helper_sig_long_double = NULL;
-static MonoMethodSignature *helper_sig_double_long = NULL;
-static MonoMethodSignature *helper_sig_double_int = NULL;
-static MonoMethodSignature *helper_sig_float_long = NULL;
-static MonoMethodSignature *helper_sig_double_double_double = NULL;
-static MonoMethodSignature *helper_sig_uint_double = NULL;
-static MonoMethodSignature *helper_sig_int_double = NULL;
-static MonoMethodSignature *helper_sig_stelem_ref = NULL;
-static MonoMethodSignature *helper_sig_stelem_ref_check = NULL;
 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
-static MonoMethodSignature *helper_sig_compile_generic_method = NULL;
+static MonoMethodSignature *helper_sig_domain_get = NULL;
 
 static guint32 default_opt = 0;
 
@@ -141,6 +103,8 @@ gboolean mono_use_security_manager = FALSE;
 
 static int mini_verbose = 0;
 
+#define mono_jit_lock() EnterCriticalSection (&jit_mutex)
+#define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
 static CRITICAL_SECTION jit_mutex;
 
 static GHashTable *class_init_hash_addr = NULL;
@@ -170,6 +134,31 @@ mono_running_on_valgrind (void)
 #endif
 }
 
+/*
+ * mono_create_ftnptr:
+ *
+ *   Given a function address, create a function descriptor for it.
+ * This is only needed on IA64.
+ */
+gpointer
+mono_create_ftnptr (MonoDomain *domain, gpointer addr)
+{
+#ifdef __ia64__
+       gpointer *desc;
+
+       mono_domain_lock (domain);
+       desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
+       mono_domain_unlock (domain);
+
+       desc [0] = addr;
+       desc [1] = NULL;
+
+       return desc;
+#else
+       return addr;
+#endif
+}
+
 /* debug function */
 G_GNUC_UNUSED static char*
 get_method_from_ip (void *ip)
@@ -269,9 +258,9 @@ void *mono_global_codeman_reserve (int size)
                return mono_code_manager_reserve (global_codeman, size);
        }
        else {
-               EnterCriticalSection (&jit_mutex);
+               mono_jit_lock ();
                ptr = mono_code_manager_reserve (global_codeman, size);
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
                return ptr;
        }
 }
@@ -863,7 +852,7 @@ df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
        int i;
 
        array [*dfn] = start;
-       /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
+       /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
        for (i = 0; i < start->out_count; ++i) {
                if (start->out_bb [i]->dfn)
                        continue;
@@ -1813,6 +1802,9 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                found = FALSE;
                for (i = 0; i < bb->out_count; ++i) {
                        outb = bb->out_bb [i];
+                       /* exception handlers are linked, but they should not be considered for stack args */
+                       if (outb->flags & BB_EXCEPTION_HANDLER)
+                               continue;
                        //g_print (" %d", outb->block_num);
                        if (outb->in_stack) {
                                found = TRUE;
@@ -1846,8 +1838,14 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
 
        for (i = 0; i < bb->out_count; ++i) {
                outb = bb->out_bb [i];
-               if (outb->in_scount)
+               /* exception handlers are linked, but they should not be considered for stack args */
+               if (outb->flags & BB_EXCEPTION_HANDLER)
+                       continue;
+               if (outb->in_scount) {
+                       if (outb->in_scount != bb->out_scount)
+                               G_BREAKPOINT ();
                        continue; /* check they are the same locals */
+               }
                outb->in_scount = count;
                outb->in_stack = bb->out_stack;
        }
@@ -1880,6 +1878,11 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                found = FALSE;
                while (bindex < bb->out_count) {
                        outb = bb->out_bb [bindex];
+                       /* exception handlers are linked, but they should not be considered for stack args */
+                       if (outb->flags & BB_EXCEPTION_HANDLER) {
+                               bindex++;
+                               continue;
+                       }
                        if (outb->in_stack != locals) {
                                /* 
                                 * Instead of storing sp [i] to locals [i], we need to store
@@ -2352,7 +2355,7 @@ mono_get_element_address_signature (int arity)
        MonoMethodSignature *res;
        int i;
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
        }
@@ -2376,7 +2379,7 @@ mono_get_element_address_signature (int arity)
        res->ret = &mono_defaults.int_class->byval_arg;
 
        g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
 
        return res;
 }
@@ -2388,12 +2391,12 @@ mono_get_array_new_va_signature (int arity)
        MonoMethodSignature *res;
        int i;
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
        }
        else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
                return res;
        }
 
@@ -2412,7 +2415,7 @@ mono_get_array_new_va_signature (int arity)
        res->ret = &mono_defaults.int_class->byval_arg;
 
        g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
 
        return res;
 }
@@ -2604,9 +2607,9 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
 
-               EnterCriticalSection (&jit_mutex);
+               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
        }
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
@@ -2768,6 +2771,9 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
        if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
+#ifdef MONO_ARCH_EMULATE_MUL_DIV
+               /* OP_LDELEMA2D depends on OP_LMUL */
+#else
                MonoInst *indexes;
                NEW_GROUP (cfg, indexes, sp [1], sp [2]);
                MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
@@ -2777,6 +2783,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                addr->type = STACK_MP;
                addr->klass = cmethod->klass;
                return addr;
+#endif
        }
 
        /* Need to register the icall so it gets an icall wrapper */
@@ -2788,9 +2795,9 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
 
-               EnterCriticalSection (&jit_mutex);
+               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
        }
 
        temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
@@ -2811,6 +2818,38 @@ mono_find_jit_opcode_emulation (int opcode)
                return NULL;
 }
 
+static MonoException*
+mini_loader_error_to_exception (MonoLoaderError *error)
+{
+       MonoException *ex = NULL;
+
+       switch (error->kind) {
+       case MONO_LOADER_ERROR_TYPE: {
+               MonoString *class_name = mono_string_new (mono_domain_get (), error->class_name);
+               
+               ex = mono_get_exception_type_load (class_name, error->assembly_name);
+               break;
+       }
+       case MONO_LOADER_ERROR_METHOD:
+       case MONO_LOADER_ERROR_FIELD: {
+               char *class_name;
+               
+               class_name = g_strdup_printf ("%s%s%s", error->klass->name_space, *error->klass->name_space ? "." : "", error->klass->name);
+
+               if (error->kind == MONO_LOADER_ERROR_METHOD)
+                       ex = mono_get_exception_missing_method (class_name, error->member_name);
+               else
+                       ex = mono_get_exception_missing_field (class_name, error->member_name);
+               g_free (class_name);
+               break;
+       }
+       default:
+               g_assert_not_reached ();
+       }
+
+       return ex;
+}
+
 static MonoInst*
 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -2842,9 +2881,16 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        ins->inst_i0 = args [0];
                        return ins;
                } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
+#ifdef MONO_ARCH_EMULATE_MUL_DIV
+               /* The OP_GETHASHCODE rule depends on OP_MUL */
+#else
                        MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
                        ins->inst_i0 = args [0];
                        return ins;
+#endif
+               } else if (strcmp (cmethod->name, ".ctor") == 0) {
+                       MONO_INST_NEW (cfg, ins, CEE_NOP);
+                       return ins;
                } else
                        return NULL;
        } else if (mini_class_is_system_array (cmethod->klass)) {
@@ -2870,7 +2916,6 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
        } else if (cmethod->klass == mono_defaults.thread_class) {
                if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
                        return ins;
-               return NULL;
        }
 
        return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
@@ -3076,11 +3121,15 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        target = start + cli_addr + 2 + (signed char)ip [1];
                        GET_BBLOCK (cfg, bbhash, bblock, target);
                        ip += 2;
+                       if (ip < end)
+                               GET_BBLOCK (cfg, bbhash, bblock, ip);
                        break;
                case MonoInlineBrTarget:
                        target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
                        GET_BBLOCK (cfg, bbhash, bblock, target);
                        ip += 5;
+                       if (ip < end)
+                               GET_BBLOCK (cfg, bbhash, bblock, ip);
                        break;
                case MonoInlineSwitch: {
                        guint32 n = read32 (ip + 1);
@@ -3104,6 +3153,19 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                default:
                        g_assert_not_reached ();
                }
+
+               if (i == CEE_THROW) {
+                       unsigned char *bb_start = ip - 1;
+                       
+                       /* Find the start of the bblock containing the throw */
+                       bblock = NULL;
+                       while ((bb_start > start) && !bblock) {
+                               bblock = g_hash_table_lookup (bbhash, (bb_start));
+                               bb_start --;
+                       }
+                       if (bblock)
+                               bblock->out_of_line = 1;
+               }
        }
        return 0;
 unverified:
@@ -3117,8 +3179,7 @@ emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8
        MonoInst *store, *temp, *load;
        
        if (ip_in_bb (cfg, bblock, ip_next) &&
-               (CODE_IS_STLOC (ip_next) || *ip_next == CEE_BRTRUE || *ip_next == CEE_BRFALSE ||
-               *ip_next == CEE_BRTRUE_S || *ip_next == CEE_BRFALSE_S || *ip_next == CEE_RET))
+               (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
                        return ins;
        
        temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
@@ -3132,16 +3193,35 @@ emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8
 }
 
 static inline MonoMethod *
-mini_get_method (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context)
+mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
 {
-       MonoMethod *method = mono_get_method_full (image, token, klass, context);
+       MonoMethod *method;
 
-       if (method->is_inflated)
+       if (m->wrapper_type != MONO_WRAPPER_NONE)
+               return mono_method_get_wrapper_data (m, token);
+
+       method = mono_get_method_full (m->klass->image, token, klass, context);
+
+       if (method && method->is_inflated)
                method = mono_get_inflated_method (method);
 
        return method;
 }
 
+static inline MonoClass*
+mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
+{
+       MonoClass *klass;
+
+       if (method->wrapper_type != MONO_WRAPPER_NONE)
+               klass = mono_method_get_wrapper_data (method, token);
+       else
+               klass = mono_class_get_full (method->klass->image, token, context);
+       if (klass)
+               mono_class_init (klass);
+       return klass;
+}
+
 static
 void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
 {
@@ -3264,19 +3344,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
                /* handle exception clauses */
                for (i = 0; i < header->num_clauses; ++i) {
-                       //unsigned char *p = ip;
+                       MonoBasicBlock *try_bb;
                        MonoExceptionClause *clause = &header->clauses [i];
-                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
-                       tblock->real_offset = clause->try_offset;
+                       GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+                       try_bb->real_offset = clause->try_offset;
                        GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
+                       tblock->flags |= BB_EXCEPTION_HANDLER;
+
+                       link_bblock (cfg, try_bb, tblock);
+
+                       if (*(ip + clause->handler_offset) == CEE_POP)
+                               tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
 
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
                            clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                MONO_ADD_INS (tblock, ins);
+
+                               /* todo: is a fault block unsafe to optimize? */
+                               if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                                       tblock->flags |= BB_EXCEPTION_UNSAFE;
                        }
 
+
                        /*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
                          while (p < end) {
                          g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
@@ -3305,7 +3396,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        tblock->real_offset = clause->data.filter_offset;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
-                                       tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->data.filter_offset);
+                                       /* The filter block shares the exvar with the handler block */
+                                       tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
                                        MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                        MONO_ADD_INS (tblock, ins);
                                }
@@ -3527,10 +3619,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                switch (*ip) {
                case CEE_NOP:
-                       ++ip;
-                       break;
                case CEE_BREAK:
-                       MONO_INST_NEW (cfg, ins, CEE_BREAK);
+                       MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
@@ -3791,7 +3881,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_INST_NEW (cfg, ins, CEE_JMP);
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
-                       cmethod = mini_get_method (image, token, NULL, generic_context);
+                       cmethod = mini_get_method (method, token, NULL, generic_context);
+
+                       if (!cmethod)
+                               goto load_error;
 
                        if (mono_use_security_manager) {
                                check_linkdemand (cfg, method, cmethod, bblock, ip);
@@ -3831,13 +3924,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
                                        cmethod = mono_get_inflated_method (cmethod);
                                } else {
-                                       cmethod = mini_get_method (image, token, NULL, generic_context);
+                                       cmethod = mini_get_method (method, token, NULL, generic_context);
                                }
 
-                               g_assert (cmethod);
+                               if (!cmethod)
+                                       goto load_error;
 
                                if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
-                                       goto unverified;
+                                       /* MS.NET seems to silently convert this to a callvirt */
+                                       virtual = 1;
 
                                if (!cmethod->klass->inited)
                                        mono_class_init (cmethod->klass);
@@ -3878,7 +3973,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        if (cmethod && cmethod->klass->generic_container) {
-                               G_BREAKPOINT ();
+                               // G_BREAKPOINT ();
                                goto unverified;
                        }
 
@@ -3926,7 +4021,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
-                               G_BREAKPOINT ();
+                               // G_BREAKPOINT ();
                                goto unverified;
                        }
 
@@ -4075,16 +4170,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->inst_target_bb = tblock;
                                        start_new_bblock = 1;
 
-                                       if (!MONO_TYPE_IS_VOID (fsig->ret)) {
-                                               /* just create a dummy - the value is never used */
-                                               ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
-                                               NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
-                                               sp++;
-                                               MONO_INST_NEW (cfg, ins, CEE_POP);
-                                               MONO_ADD_INS (bblock, ins);
-                                               --sp;
-                                               ins->inst_i0 = *sp;
-                                       }
                                        /* skip the CEE_RET, too */
                                        if (ip_in_bb (cfg, bblock, ip + 5))
                                                ip += 6;
@@ -4162,8 +4247,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (ip_in_bb (cfg, bblock, ip + 5) 
                                    && (!MONO_TYPE_ISSTRUCT (fsig->ret))
                                    && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
-                                   && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_BRTRUE || ip [5] == CEE_BRFALSE ||
-                                       ip [5] == CEE_BRTRUE_S || ip [5] == CEE_BRFALSE_S || ip [5] == CEE_RET)) {
+                                   && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
                                        /* no need to spill */
                                        ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
                                        *sp++ = ins;
@@ -4410,9 +4494,37 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins_flag = 0;
                        inline_costs += 1;
                        break;
+               case CEE_MUL:
+                       CHECK_STACK (2);
+                       ADD_BINOP (*ip);
+
+#ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
+                       /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
+                       if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
+                               switch (ins->opcode) {
+                               case CEE_MUL:
+                                       ins->opcode = OP_IMUL_IMM;
+                                       ins->inst_imm = ins->inst_right->inst_c0;
+                                       break;
+                               case OP_LMUL:
+                                       ins->opcode = OP_LMUL_IMM;
+                                       ins->inst_imm = ins->inst_right->inst_c0;
+                                       break;
+                               default:
+                                       g_assert_not_reached ();
+                               }
+                       }
+#endif
+
+                       if (mono_find_jit_opcode_emulation (ins->opcode)) {
+                               --sp;
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
+                               mono_get_got_var (cfg);
+                       }
+                       ip++;
+                       break;
                case CEE_ADD:
                case CEE_SUB:
-               case CEE_MUL:
                case CEE_DIV:
                case CEE_DIV_UN:
                case CEE_REM:
@@ -4513,12 +4625,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        CHECK_STACK (2);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
                        sp -= 2;
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MonoInst *store, *load;
@@ -4566,12 +4675,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        --sp;
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
                                ins->cil_code = ip;
@@ -4649,7 +4755,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = read32 (ip + 1);
 
                        if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
-                               NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));                                                                
+                               NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
                                ins->cil_code = ip;
                                ins->type = STACK_OBJ;
                                *sp = ins;
@@ -4681,15 +4787,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                        mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
                                } else {
-                                       if (cfg->compile_aot)
+                                       if (bblock->out_of_line) {
+                                               MonoInst *iargs [2];
+                                               int temp;
+
+                                               /* Avoid creating the string object */
+                                               NEW_IMAGECONST (cfg, iargs [0], image);
+                                               NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
+                                               temp = mono_emit_jit_icall (cfg, bblock, helper_ldstr, iargs, ip);
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
+                                       } 
+                                       else
+                                       if (cfg->compile_aot) {
                                                NEW_LDSTRCONST (cfg, ins, image, n);
+                                               *sp = ins;
+                                       } 
                                        else {
                                                NEW_PCONST (cfg, ins, NULL);
                                                ins->cil_code = ip;
                                                ins->type = STACK_OBJ;
                                                ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+                                               *sp = ins;
                                        }
-                                       *sp = ins;
                                }
                        }
 
@@ -4703,10 +4822,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE) {
-                               cmethod = mono_method_get_wrapper_data (method, token);
-                       } else
-                               cmethod = mini_get_method (image, token, NULL, generic_context);
+                       cmethod = mini_get_method (method, token, NULL, generic_context);
+                       if (!cmethod)
+                               goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
 
                        mono_class_init (cmethod->klass);
@@ -4809,11 +4927,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -4867,11 +4983,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
-                       else 
-                               klass = mono_class_get_full (image, token, generic_context);
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                /* CASTCLASS */
@@ -4963,11 +5077,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
-                       else 
-                               klass = mono_class_get_full (image, token, generic_context);
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -4994,11 +5106,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -5056,6 +5166,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip - 1;
                        MONO_ADD_INS (bblock, ins);
                        sp = stack_start;
+                       
                        link_bblock (cfg, bblock, end_bblock);
                        start_new_bblock = 1;
                        mono_get_got_var (cfg);
@@ -5082,6 +5193,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        field = mono_field_from_token (image, token, &klass, generic_context);
+                       if (!field)
+                               goto load_error;
                        mono_class_init (klass);
 
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
@@ -5224,6 +5337,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
 
                        field = mono_field_from_token (image, token, &klass, generic_context);
+                       if (!field)
+                               goto load_error;
                        mono_class_init (klass);
 
                        g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
@@ -5399,11 +5514,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
                        n = mono_type_to_stind (&klass->byval_arg);
                        if (n == CEE_STOBJ) {
                                handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
@@ -5428,11 +5541,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        val = *sp;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                *sp++ = val;
@@ -5463,12 +5574,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* Ditto */
                        mono_get_got_var (cfg);
 
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
-                       else
-                               klass = mono_class_get_full (image, token, generic_context);
-
-                       mono_class_init (klass);
+                       klass = mini_get_class (method, token, generic_context);
+                       if (!klass)
+                               goto load_error;
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
@@ -5505,11 +5613,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        CHECK_OPSIZE (5);
 
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
-                       else
-                               klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
-                       
+                       klass = mini_get_class (method, read32 (ip + 1), generic_context);
+                       if (!klass)
+                               goto load_error;                        
                        /* we need to make sure that this array is exactly the type it needs
                         * to be for correctness. the wrappers are lax with their usage
                         * so we need to ignore them here
@@ -5537,6 +5643,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
+                       if (!klass)
+                               goto load_error;
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -5618,6 +5726,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
+                       if (!klass)
+                               goto load_error;
                        mono_class_init (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MonoMethod* helper = mono_marshal_get_stelemref ();
@@ -5708,6 +5818,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+                       if (!klass)
+                               goto load_error;
                        mono_class_init (klass);
                        ins->type = STACK_MP;
                        ins->inst_left = *sp;
@@ -5725,6 +5837,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+                       if (!klass)
+                               goto load_error;
                        mono_class_init (klass);
                        ins->cil_code = ip;
 
@@ -5750,7 +5864,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        n = read32 (ip + 1);
 
-                       handle = mono_ldtoken (image, n, &handle_class, generic_context);
+                       if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+                               handle = mono_method_get_wrapper_data (method, n);
+                               handle_class = mono_method_get_wrapper_data (method, n + 1);
+                       }
+                       else {
+                               handle = mono_ldtoken (image, n, &handle_class, generic_context);
+                       }
+                       if (!handle)
+                               goto load_error;
                        mono_class_init (handle_class);
 
                        if (cfg->opt & MONO_OPT_SHARED) {
@@ -5769,7 +5891,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (bblock, store);
                                NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
                        } else {
-                               if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (image, read32 (ip + 6), NULL, generic_context)) &&
+                               if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
                                                (cmethod->klass == mono_defaults.monotype_class->parent) &&
                                                (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
                                        MonoClass *tclass = mono_class_from_mono_type (handle);
@@ -6165,12 +6287,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
-                               if (method->wrapper_type != MONO_WRAPPER_NONE)
-                                       cmethod = mono_method_get_wrapper_data (method, n);
-                               else {
-                                       cmethod = mini_get_method (image, n, NULL, generic_context);
-                               }
-
+                               cmethod = mini_get_method (method, n, NULL, generic_context);
+                               if (!cmethod)
+                                       goto load_error;
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
@@ -6198,11 +6317,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
-                               if (method->wrapper_type != MONO_WRAPPER_NONE)
-                                       cmethod = mono_method_get_wrapper_data (method, n);
-                               else
-                                       cmethod = mini_get_method (image, n, NULL, generic_context);
-
+                               cmethod = mini_get_method (method, n, NULL, generic_context);
+                               if (!cmethod)
+                                       goto load_error;
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
@@ -6340,7 +6457,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                for (cc = 0; cc < header->num_clauses; ++cc) {
                                        clause = &header->clauses [cc];
                                        if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
-                                           (!nearest || (clause->data.filter_offset > nearest->data.filter_offset))) {
+                                               ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
+                                           (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
                                                nearest = clause;
                                                nearest_num = cc;
                                        }
@@ -6373,10 +6491,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                --sp;
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
-                               if (method->wrapper_type != MONO_WRAPPER_NONE)
-                                       klass = mono_method_get_wrapper_data (method, token);
-                               else
-                                       klass = mono_class_get_full (image, token, generic_context);
+                               klass = mini_get_class (method, token, generic_context);
+                               if (!klass)
+                                       goto load_error;
                                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
@@ -6399,6 +6516,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
                                constrained_call = mono_class_get_full (image, token, generic_context);
+                               if (!constrained_call)
+                                       goto load_error;
                                ip += 6;
                                break;
                        case CEE_CPBLK:
@@ -6453,6 +6572,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                handler_offset = clause->handler_offset;
                                }
 
+                               bblock->flags |= BB_EXCEPTION_UNSAFE;
+
                                g_assert (handler_offset != -1);
 
                                NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
@@ -6477,9 +6598,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoType *type = mono_type_create_from_typespec (image, token);
                                        token = mono_type_size (type, &align);
                                } else {
-                                       MonoClass *szclass = mono_class_get_full (image, token, generic_context);
-                                       mono_class_init (szclass);
-                                       token = mono_class_value_size (szclass, &align);
+                                       MonoClass *klass = mono_class_get_full (image, token, generic_context);
+                                       if (!klass)
+                                               goto load_error;
+                                       mono_class_init (klass);
+                                       token = mono_class_value_size (klass, &align);
                                }
                                NEW_ICONST (cfg, ins, token);
                                ins->cil_code = ip;
@@ -6568,7 +6691,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                   ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_class_is_valuetype (ptype->data.generic_class))) {
                                NEW_LOCLOADA (cfg, ins, i);
                                handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
-                               break;
                        } else {
                                NEW_PCONST (cfg, ins, NULL);
                                NEW_LOCSTORE (cfg, store, i, ins);
@@ -6617,6 +6739,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_inline = g_list_remove (dont_inline, method);
        return -1;
 
+ load_error:
+       if (cfg->method != method)
+               g_hash_table_destroy (bbhash);
+       g_slist_free (class_inits);
+       dont_inline = g_list_remove (dont_inline, method);
+       return -1;
+
  unverified:
        if (cfg->method != method) 
                g_hash_table_destroy (bbhash);
@@ -6764,128 +6893,11 @@ mono_print_tree_nl (MonoInst *tree)
        printf ("\n");
 }
 
-#define make_icall_sig mono_create_icall_signature
-
 static void
 create_helper_signature (void)
 {
-       /* MonoArray * mono_array_new (MonoDomain *domain, MonoClass *klass, gint32 len) */
-       helper_sig_newarr = make_icall_sig ("object ptr ptr int32");
-
-       /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
-       helper_sig_newarr_specific = make_icall_sig ("object ptr int32");
-
-       /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
-       helper_sig_object_new = make_icall_sig ("object ptr ptr");
-
-       /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
-       helper_sig_object_new_specific = make_icall_sig ("object ptr");
-
-       /* void* mono_method_compile (MonoMethod*) */
-       helper_sig_compile = make_icall_sig ("ptr ptr");
-
-       /* void* mono_ldvirtfn (MonoObject *, MonoMethod*) */
-       helper_sig_compile_virt = make_icall_sig ("ptr object ptr");
-
-       /* MonoString* mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 str_index) */
-       helper_sig_ldstr = make_icall_sig ("object ptr ptr int32");
-
-       /* MonoDomain *mono_domain_get (void) */
-       helper_sig_domain_get = make_icall_sig ("ptr");
-
-       /* void stelem_ref (MonoArray *, int index, MonoObject *) */
-       helper_sig_stelem_ref = make_icall_sig ("void ptr int32 object");
-
-       /* void stelem_ref_check (MonoArray *, MonoObject *) */
-       helper_sig_stelem_ref_check = make_icall_sig ("void object object");
-
-       /* void *helper_compile_generic_method (MonoObject *, MonoMethod *, MonoGenericContext *) */
-       helper_sig_compile_generic_method = make_icall_sig ("ptr object ptr ptr");
-
-       /* int amethod (int, int) */
-       helper_sig_int_int_int = make_icall_sig ("int32 int32 int32");
-
-       /* long amethod (long, long) */
-       helper_sig_long_long_long = make_icall_sig ("long long long");
-
-       /* object  amethod (intptr) */
-       helper_sig_obj_ptr = make_icall_sig ("object ptr");
-
-       helper_sig_obj_ptr_ptr = make_icall_sig ("object ptr ptr");
-
-       helper_sig_obj_obj_ptr_ptr = make_icall_sig ("object object ptr ptr");
-
-       helper_sig_void_void = make_icall_sig ("void");
-
-       /* void amethod (intptr) */
-       helper_sig_void_ptr = make_icall_sig ("void ptr");
-
-       /* void amethod (MonoObject *obj) */
-       helper_sig_void_obj = make_icall_sig ("void object");
-
-       /* void amethod (MonoObject *obj, void *ptr, int i) */
-       helper_sig_void_obj_ptr_int = make_icall_sig ("void object ptr int");
-
-       helper_sig_void_obj_ptr_ptr_obj = make_icall_sig ("void object ptr ptr object");
-
-       /* intptr amethod (void) */
-       helper_sig_ptr_void = make_icall_sig ("ptr");
-
-       /* object amethod (void) */
-       helper_sig_obj_void = make_icall_sig ("object");
-
-       /* void  amethod (intptr, intptr) */
-       helper_sig_void_ptr_ptr = make_icall_sig ("void ptr ptr");
-
-       /* void  amethod (intptr, intptr, intptr) */
-       helper_sig_void_ptr_ptr_ptr = make_icall_sig ("void ptr ptr ptr");
-
-       /* intptr  amethod (intptr, intptr) */
-       helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
-
-       helper_sig_ptr_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr ptr");
-
-       /* IntPtr  amethod (object) */
-       helper_sig_ptr_obj = make_icall_sig ("ptr object");
-
-       /* IntPtr  amethod (object, int) */
-       helper_sig_ptr_obj_int = make_icall_sig ("ptr object int");
-
-       /* IntPtr  amethod (int) */
-       helper_sig_ptr_int = make_icall_sig ("ptr int32");
-
-       /* long amethod (long, guint32) */
-       helper_sig_long_long_int = make_icall_sig ("long long int32");
-
-       /* ulong amethod (double) */
-       helper_sig_ulong_double = make_icall_sig ("ulong double");
-
-       /* long amethod (double) */
-       helper_sig_long_double = make_icall_sig ("long double");
-
-       /* double amethod (long) */
-       helper_sig_double_long = make_icall_sig ("double long");
-
-       /* double amethod (int) */
-       helper_sig_double_int = make_icall_sig ("double int32");
-
-       /* float amethod (long) */
-       helper_sig_float_long = make_icall_sig ("float long");
-
-       /* double amethod (double, double) */
-       helper_sig_double_double_double = make_icall_sig ("double double double");
-
-       /* uint amethod (double) */
-       helper_sig_uint_double = make_icall_sig ("uint32 double");
-
-       /* int amethod (double) */
-       helper_sig_int_double = make_icall_sig ("int32 double");
-
-       helper_sig_class_init_trampoline = make_icall_sig ("void");
-
-       helper_sig_obj_obj_obj_ptr = make_icall_sig ("object object object ptr");
-
-       helper_sig_void_obj_obj_ptr = make_icall_sig ("void object object ptr");
+       helper_sig_domain_get = mono_create_icall_signature ("ptr");
+       helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
 }
 
 gconstpointer
@@ -6922,6 +6934,20 @@ mono_init_trampolines (void)
 #ifdef MONO_ARCH_HAVE_PIC_AOT
        mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
 #endif
+#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+       mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
+#endif
+}
+
+static void
+mono_init_exceptions (void)
+{
+#ifndef CUSTOM_EXCEPTION_HANDLING
+       mono_arch_get_restore_context ();
+       mono_arch_get_call_filter ();
+       mono_arch_get_throw_exception ();
+       mono_arch_get_rethrow_exception ();
+#endif
 }
 
 guint8 *
@@ -6933,16 +6959,16 @@ mono_get_trampoline_code (MonoTrampolineType tramp_type)
 gpointer
 mono_create_class_init_trampoline (MonoVTable *vtable)
 {
-       gpointer code;
+       gpointer code, ptr;
 
        /* previously created trampoline code */
        mono_domain_lock (vtable->domain);
-       code = 
+       ptr = 
                g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
                                                                  vtable);
        mono_domain_unlock (vtable->domain);
-       if (code)
-               return code;
+       if (ptr)
+               return ptr;
 
 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
        code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
@@ -6950,19 +6976,21 @@ mono_create_class_init_trampoline (MonoVTable *vtable)
        code = mono_arch_create_class_init_trampoline (vtable);
 #endif
 
+       ptr = mono_create_ftnptr (vtable->domain, code);
+
        /* store trampoline address */
        mono_domain_lock (vtable->domain);
        g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
-                                                         vtable, code);
+                                                         vtable, ptr);
        mono_domain_unlock (vtable->domain);
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (!class_init_hash_addr)
                class_init_hash_addr = g_hash_table_new (NULL, NULL);
-       g_hash_table_insert (class_init_hash_addr, code, vtable);
-       LeaveCriticalSection (&jit_mutex);
+       g_hash_table_insert (class_init_hash_addr, ptr, vtable);
+       mono_jit_unlock ();
 
-       return code;
+       return ptr;
 }
 
 gpointer
@@ -7004,7 +7032,7 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
         * trampoline address, so we save it here.
         */
 
-       mono_jit_info_table_add (mono_get_root_domain (), ji);
+       mono_jit_info_table_add (domain, ji);
 
        mono_domain_lock (domain);
        g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
@@ -7049,7 +7077,6 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 {
        gpointer tramp;
 
-#ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
        MonoDomain *domain = mono_domain_get ();
        guint8 *buf, *start;
 
@@ -7057,14 +7084,11 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
        buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
        mono_domain_unlock (domain);
 
-       *(gpointer*)buf = image;
+       *(gpointer*)(gpointer)buf = image;
        buf += sizeof (gpointer);
-       *(guint32*)buf = token;
+       *(guint32*)(gpointer)buf = token;
 
        tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
-#else
-       tramp = mono_arch_create_jit_trampoline_from_token (image, token);
-#endif
 
        mono_jit_stats.method_trampolines++;
 
@@ -7072,17 +7096,58 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 }      
 #endif
 
+gpointer
+mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
+{
+#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+       gpointer code, ptr;
+       guint32 code_size;
+       MonoDomain *domain = mono_domain_get ();
+
+#ifndef __ia64__
+       code = mono_jit_find_compiled_method (domain, method);
+       if (code)
+               return code;
+#else
+       /* 
+        * FIXME: We should return a function descriptor here but it is not stored
+        * anywhere so it would be leaked.
+        */
+#endif
+
+       mono_domain_lock (domain);
+       ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
+       mono_domain_unlock (domain);
+       if (ptr)
+               return ptr;
+
+       code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
+
+       ptr = mono_create_ftnptr (domain, code);
+
+       /* store trampoline address */
+       mono_domain_lock (domain);
+       g_hash_table_insert (domain->delegate_trampoline_hash,
+                                                         method, ptr);
+       mono_domain_unlock (domain);
+
+       return ptr;
+#else
+       return addr;
+#endif
+}
+
 MonoVTable*
 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
 {
        MonoVTable *res;
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (class_init_hash_addr)
                res = g_hash_table_lookup (class_init_hash_addr, addr);
        else
                res = NULL;
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
        return res;
 }
 
@@ -7113,7 +7178,7 @@ typedef struct {
 } StackSlotInfo;
 
 /*
- * mono_allocate_stack_slots:
+ * mono_allocate_stack_slots_full:
  *
  *  Allocate stack slots for all non register allocated variables using a
  * linear scan algorithm.
@@ -7122,7 +7187,7 @@ typedef struct {
  * STACK_ALIGN is set to the alignment needed by the locals area.
  */
 gint32*
-mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
+mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
 {
        int i, slot, offset, size, align;
        MonoMethodVar *vmv;
@@ -7243,10 +7308,18 @@ mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_a
                        if (t->type == MONO_TYPE_VALUETYPE)
                                align = sizeof (gpointer);
 
-                       offset += size;
-                       offset += align - 1;
-                       offset &= ~(align - 1);
-                       slot = offset;
+                       if (backward) {
+                               offset += size;
+                               offset += align - 1;
+                               offset &= ~(align - 1);
+                               slot = offset;
+                       }
+                       else {
+                               offset += align - 1;
+                               offset &= ~(align - 1);
+                               slot = offset;
+                               offset += size;
+                       }
 
                        if (*stack_align == 0)
                                *stack_align = align;
@@ -7270,10 +7343,17 @@ mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_a
        return offsets;
 }
 
+gint32*
+mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
+{
+       return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
+}
+
 void
-mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
+mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
 {
        MonoJitICallInfo *info;
+       MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
 
        if (!emul_opcode_map)
                emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
@@ -7286,6 +7366,19 @@ mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignatur
        emul_opcode_map [opcode] = info;
 }
 
+static void
+register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+{
+       MonoMethodSignature *sig;
+
+       if (sigstr)
+               sig = mono_create_icall_signature (sigstr);
+       else
+               sig = NULL;
+
+       mono_register_jit_icall (func, name, sig, save);
+}
+
 static void
 decompose_foreach (MonoInst *tree, gpointer data) 
 {
@@ -7551,11 +7644,15 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 
        mono_arch_setup_jit_tls_data (jit_tls);
 
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+       mono_setup_altstack (jit_tls);
+#endif
+
        return jit_tls;
 }
 
 static void
-mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
+mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
 {
        MonoThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
@@ -7576,7 +7673,7 @@ mono_thread_abort_dummy (MonoObject *obj)
 }
 
 static void
-mono_thread_attach_cb (guint32 tid, gpointer stack_start)
+mono_thread_attach_cb (gsize tid, gpointer stack_start)
 {
        MonoThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
@@ -7594,6 +7691,10 @@ mini_thread_cleanup (MonoThread *thread)
 
        if (jit_tls) {
                mono_arch_free_jit_tls_data (jit_tls);
+
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+               mono_free_altstack (jit_tls);
+#endif
                g_free (jit_tls->first_lmf);
                g_free (jit_tls);
                thread->jit_data = NULL;
@@ -8159,7 +8260,10 @@ optimize_branches (MonoCompile *cfg)
         * loop, see bug #53003 for an example. To prevent this, we put an upper
         * bound on the number of iterations.
         */
-       niterations = 1000;
+       if (cfg->num_bblocks > 1000)
+               niterations = cfg->num_bblocks * 2;
+       else
+               niterations = 1000;
        do {
                MonoBasicBlock *previous_bb;
                changed = FALSE;
@@ -9063,11 +9167,16 @@ MonoCompile*
 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
 {
        MonoMethodHeader *header = mono_method_get_header (method);
-       guint8 *ip = (guint8 *)header->code;
+       guint8 *ip;
        MonoCompile *cfg;
        MonoJitInfo *jinfo;
        int dfn = 0, i, code_size_ratio;
 
+       if (!header)
+               return NULL;
+
+       ip = (guint8 *)header->code;
+
        mono_jit_stats.methods_compiled++;
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_jit (method);
@@ -9268,7 +9377,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_codegen (cfg);
        if (cfg->verbose_level >= 2) {
                char *id =  mono_method_full_name (cfg->method, FALSE);
-               mono_disassemble_code (cfg->native_code, cfg->code_len, id + 3);
+               mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
                g_free (id);
        }
        
@@ -9327,6 +9436,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        cfg->jit_info = jinfo;
+#if defined(__arm__)
+       mono_arch_fixup_jinfo (cfg);
+#endif
 
        mono_domain_lock (cfg->domain);
        mono_jit_info_table_add (cfg->domain, jinfo);
@@ -9391,7 +9503,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
        method = mono_get_inflated_method (method);
 
 #ifdef MONO_USE_AOT_COMPILER
-       if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
+       if (!mono_compile_aot && (opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
                MonoJitInfo *info;
                MonoDomain *domain = mono_domain_get ();
 
@@ -9425,7 +9537,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
                                        mono_lookup_pinvoke_call (method, NULL, NULL);
                }
                        nm = mono_marshal_get_native_wrapper (method);
-                       return mono_compile_method (nm);
+                       return mono_get_addr_from_ftnptr (mono_compile_method (nm));
 
                        //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
                        //mono_debug_add_wrapper (method, nm);
@@ -9437,16 +9549,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
                        if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
                                MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
                                g_assert (mi);
-                               return (gpointer)mono_icall_get_wrapper (mi);
+                               return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
                        } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
                                nm = mono_marshal_get_delegate_invoke (method);
-                               return mono_jit_compile_method (nm);
+                                       return mono_get_addr_from_ftnptr (mono_compile_method (nm));
                        } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
                                nm = mono_marshal_get_delegate_begin_invoke (method);
-                               return mono_jit_compile_method (nm);
+                               return mono_get_addr_from_ftnptr (mono_compile_method (nm));
                        } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
                                nm = mono_marshal_get_delegate_end_invoke (method);
-                               return mono_jit_compile_method (nm);
+                               return mono_get_addr_from_ftnptr (mono_compile_method (nm));
                        }
                }
                return NULL;
@@ -9454,6 +9566,19 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
 
        cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
 
+       if (!cfg) {
+               /* Throw a type load exception if needed */
+               MonoLoaderError *error = mono_loader_get_last_error ();
+
+               if (error) {
+                       MonoException *ex = mini_loader_error_to_exception (error);
+                       mono_loader_clear_error ();
+                       mono_raise_exception (ex);
+               }
+               else
+                       g_assert_not_reached ();
+       }
+
        mono_domain_lock (target_domain);
 
        /* Check if some other thread already did the job. In this case, we can
@@ -9517,13 +9642,13 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
                        mono_domain_unlock (target_domain);
                        mono_jit_stats.methods_lookups++;
                        mono_runtime_class_init (mono_class_vtable (domain, method->klass));
-                       return info->code_start;
+                       return mono_create_ftnptr (domain, info->code_start);
                }
        }
 
        mono_domain_unlock (target_domain);
        p = mono_jit_compile_method_inner (method, target_domain);
-       return p;
+       return mono_create_ftnptr (domain, p);
 }
 
 static gpointer
@@ -9726,6 +9851,19 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 #endif
        GET_CONTEXT
 
+#ifdef MONO_ARCH_USE_SIGACTION
+       if (debug_options.collect_pagefault_stats) {
+               if (mono_raw_buffer_is_pagefault (info->si_addr)) {
+                       mono_raw_buffer_handle_pagefault (info->si_addr);
+                       return;
+               }
+               if (mono_aot_is_pagefault (info->si_addr)) {
+                       mono_aot_handle_pagefault (info->si_addr);
+                       return;
+               }
+       }
+#endif
+
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        /* Can't allocate memory using Boehm GC on altstack */
        if (jit_tls->stack_size && 
@@ -9862,6 +10000,7 @@ mono_runtime_install_handlers (void)
                add_signal_handler (SIGUSR2, sigusr2_signal_handler);
 
        add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
+       signal (SIGPIPE, SIG_IGN);
 
        /* catch SIGSEGV */
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
@@ -9980,7 +10119,7 @@ mono_jit_create_remoting_trampoline (MonoMethod *method, MonoRemotingTarget targ
        } else {
                addr = mono_compile_method (method);
        }
-       return addr;
+       return mono_get_addr_from_ftnptr (addr);
 }
 
 static void
@@ -10003,9 +10142,11 @@ mini_parse_debug_options (void)
                        debug_options.keep_delegates = TRUE;
                else if (!strcmp (arg, "abort-on-sigsegv"))
                        debug_options.abort_on_sigsegv = TRUE;
+               else if (!strcmp (arg, "collect-pagefault-stats"))
+                       debug_options.collect_pagefault_stats = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv', 'collect-pagefault-stats'\n");
                        exit (1);
                }
        }
@@ -10029,12 +10170,20 @@ mini_init (const char *filename)
 
        mono_init_trampolines ();
 
+       mono_init_exceptions ();
+
        if (!g_thread_supported ())
                g_thread_init (NULL);
 
        if (getenv ("MONO_DEBUG") != NULL)
                mini_parse_debug_options ();
-       
+
+       if (mono_running_on_valgrind ()) {
+               gsize stack_bottom = (gsize)&domain;
+               stack_bottom += 4095;
+               stack_bottom &= ~4095;
+               GC_stackbottom = (char*)stack_bottom;
+       }
        MONO_GC_PRE_INIT ();
 
        mono_jit_tls_id = TlsAlloc ();
@@ -10054,6 +10203,7 @@ mini_init (const char *filename)
        mono_install_free_method (mono_jit_free_method);
        mono_install_trampoline (mono_create_jit_trampoline);
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
+       mono_install_delegate_trampoline (mono_create_delegate_trampoline);
 #endif
 #define JIT_INVOKE_WORKS
 #ifdef JIT_INVOKE_WORKS
@@ -10065,6 +10215,11 @@ mini_init (const char *filename)
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
+       if (debug_options.collect_pagefault_stats) {
+               mono_raw_buffer_set_make_unreadable (TRUE);
+               mono_aot_set_make_unreadable (TRUE);
+       }
+
        domain = mono_init_from_assembly (filename, filename);
        mono_icall_init ();
 
@@ -10090,27 +10245,26 @@ mini_init (const char *filename)
        mono_marshal_init ();
 
        mono_arch_register_lowlevel_calls ();
-       mono_register_jit_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
-       mono_register_jit_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
-       mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
-       mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
-       mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
-       mono_register_jit_icall (mono_jit_thread_attach, "mono_jit_thread_attach", helper_sig_void_void, TRUE);
-       mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
-
-       mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
-       mono_register_jit_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", helper_sig_void_obj, TRUE);
-       mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
-                                helper_sig_void_ptr, TRUE);
+       register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", NULL, TRUE);
+       register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", NULL, TRUE);
+       register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
+       register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
+       register_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
+       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
+       register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
+
+       register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
+       register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
+       register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
-       mono_register_jit_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
-                                helper_sig_void_ptr, TRUE);
+       register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
+                                "void ptr", TRUE);
 #endif
-       mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
-       mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", helper_sig_void_void, FALSE);
-       mono_register_jit_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", helper_sig_void_void, FALSE);
-       mono_register_jit_icall (mono_load_remote_field_new, "mono_load_remote_field_new", helper_sig_obj_obj_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_store_remote_field_new, "mono_store_remote_field_new", helper_sig_void_obj_ptr_ptr_obj, FALSE);
+       register_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", "object", FALSE);
+       register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
+       register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
+       register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
+       register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
 
        /* 
         * NOTE, NOTE, NOTE, NOTE:
@@ -10118,78 +10272,82 @@ mini_init (const char *filename)
         * rule to the burg files, because we need the arity information to be correct.
         */
 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
-       mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
-       mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
-       mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
-       mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
-       mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
-       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
-       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
+       mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE);
+       mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE);
+       mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE);
+       mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE);
+       mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE);
+       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE);
+       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE);
 #endif
 
 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
-       mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
-       mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
-       mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
+       mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE);
+       mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE);
+       mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE);
+#endif
+
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
+       mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, TRUE);
+       mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, TRUE);
+       mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, TRUE);
+       mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, TRUE);
 #endif
 
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
-       mono_register_opcode_emulation (CEE_MUL, "__emul_imul", helper_sig_int_int_int, mono_imul, TRUE);
-       mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", helper_sig_int_int_int, mono_idiv, TRUE);
-       mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", helper_sig_int_int_int, mono_idiv_un, TRUE);
-       mono_register_opcode_emulation (CEE_REM, "__emul_irem", helper_sig_int_int_int, mono_irem, TRUE);
-       mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", helper_sig_int_int_int, mono_irem_un, TRUE);
-       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", helper_sig_int_int_int, mono_imul_ovf, TRUE);
-       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", helper_sig_int_int_int, mono_imul_ovf_un, TRUE);
-       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", helper_sig_double_double_double, mono_fdiv, TRUE);
+       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, TRUE);
+       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, TRUE);
+       mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
+       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, TRUE);
 #endif
 
-       mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, FALSE);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE);
 
 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
-       mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", helper_sig_long_double, mono_fconv_i8, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
-       mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", helper_sig_double_int, mono_conv_to_r8_un, FALSE);
+       mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
-       mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", helper_sig_double_long, mono_lconv_to_r8, FALSE);
+       mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
-       mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", helper_sig_float_long, mono_lconv_to_r4, FALSE);
+       mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
-       mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", helper_sig_double_long, mono_lconv_to_r8_un, FALSE);
+       mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_FREM
-       mono_register_opcode_emulation (OP_FREM, "__emul_frem", helper_sig_double_double_double, fmod, FALSE);
+       mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
 #endif
 
 #if SIZEOF_VOID_P == 4
-       mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
 #endif
 
        /* other jit icalls */
-       mono_register_jit_icall (mono_delegate_ctor, "mono_delegate_ctor", helper_sig_void_obj_obj_ptr, FALSE);
-       mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
-                                helper_sig_ptr_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
-       mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
-       mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
-       mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
-       mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
-       mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
-       mono_register_jit_icall (mono_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
-       mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
-       mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
-       mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
-       mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
-       mono_register_jit_icall (mono_ldftn_nosync, "mono_ldftn_nosync", helper_sig_compile, FALSE);
-       mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
-       mono_register_jit_icall (helper_compile_generic_method, "compile_generic_method", helper_sig_compile_generic_method, FALSE);
+       register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
+       register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
+                                "ptr ptr ptr", FALSE);
+       register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
+       register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
+       register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
+       register_icall (helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
+       register_icall (helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
+       register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
+       register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
+       register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
+       register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
+       register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
+       register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
+       register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
+       register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
+       register_icall (helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
+       register_icall (helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
 #endif
 
 #define JIT_RUNTIME_WORKS
@@ -10249,6 +10407,10 @@ print_jit_stats (void)
                        g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
                        g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
                }
+               if (debug_options.collect_pagefault_stats) {
+                       g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
+                       g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
+               }
        }
 }