Tue Oct 4 20:23:25 CEST 2005 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index fd48bcb66bd2bd4a9040c992ae0c87e7fc5565d1..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>
@@ -101,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;
@@ -254,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;
        }
 }
@@ -848,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;
@@ -1798,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;
@@ -1831,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;
        }
@@ -1865,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
@@ -2337,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);
        }
@@ -2361,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;
 }
@@ -2373,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;
        }
 
@@ -2397,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;
 }
@@ -2589,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;
@@ -2777,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);
@@ -2800,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)
 {
@@ -2838,6 +2888,9 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        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)) {
@@ -2863,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);
@@ -3127,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);
@@ -3151,12 +3202,26 @@ mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericCont
 
        method = mono_get_method_full (m->klass->image, token, klass, context);
 
-       if (method->is_inflated)
+       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)
 {
@@ -3279,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));
@@ -3807,6 +3883,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* FIXME: check the signature matches */
                        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);
                        }
@@ -3848,7 +3927,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod = mini_get_method (method, token, NULL, generic_context);
                                }
 
-                               g_assert (cmethod);
+                               if (!cmethod)
+                                       goto load_error;
 
                                if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
                                        /* MS.NET seems to silently convert this to a callvirt */
@@ -3893,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;
                        }
 
@@ -3941,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;
                        }
 
@@ -4167,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;
@@ -4420,17 +4499,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ADD_BINOP (*ip);
 
 #ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
-                       if (ins->inst_right->opcode == OP_ICONST) {
+                       /* 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);
@@ -4540,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;
@@ -4593,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;
@@ -4744,6 +4823,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        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);
@@ -4846,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);
@@ -4904,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 */
@@ -5000,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);
@@ -5031,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);
@@ -5093,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);
@@ -5119,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;
@@ -5261,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));
@@ -5436,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);
@@ -5465,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;
@@ -5500,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;
@@ -5542,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
@@ -5574,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;
@@ -5655,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 ();
@@ -5745,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;
@@ -5762,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;
 
@@ -5794,6 +5871,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        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) {
@@ -6209,7 +6288,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (method, n, NULL, generic_context);
-
+                               if (!cmethod)
+                                       goto load_error;
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
@@ -6238,7 +6318,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (method, n, NULL, generic_context);
-
+                               if (!cmethod)
+                                       goto load_error;
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
@@ -6410,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);
@@ -6436,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:
@@ -6490,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);
@@ -6514,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;
@@ -6653,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);
@@ -6846,6 +6939,17 @@ mono_init_trampolines (void)
 #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 *
 mono_get_trampoline_code (MonoTrampolineType tramp_type)
 {
@@ -6880,11 +6984,11 @@ mono_create_class_init_trampoline (MonoVTable *vtable)
                                                          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, ptr, vtable);
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
 
        return ptr;
 }
@@ -7038,12 +7142,12 @@ 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;
 }
 
@@ -7074,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.
@@ -7083,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;
@@ -7204,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;
@@ -7231,6 +7343,12 @@ 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, const char *sigstr, gpointer func, gboolean no_throw)
 {
@@ -7526,6 +7644,10 @@ 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;
 }
 
@@ -7569,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;
@@ -9041,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);
@@ -9305,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);
@@ -9369,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 ();
 
@@ -9432,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
@@ -9704,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 && 
@@ -9840,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
@@ -9981,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);
                }
        }
@@ -10007,6 +10170,8 @@ mini_init (const char *filename)
 
        mono_init_trampolines ();
 
+       mono_init_exceptions ();
+
        if (!g_thread_supported ())
                g_thread_init (NULL);
 
@@ -10050,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 ();
 
@@ -10237,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 ());
+               }
        }
 }