Remove one more compile-time dependency on sgen.
[mono.git] / mono / mini / method-to-ir.c
index 34c941e608acdc9ae4ae64f336e259698f533411..ae7cd780e3c7d4f819d36c29ed29d0f36dc6f4cb 100644 (file)
@@ -30,6 +30,7 @@
 #include <mono/utils/memcheck.h>
 
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/attrdefs.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
@@ -74,7 +75,7 @@
 #define METHOD_ACCESS_FAILURE do {     \
                char *method_fname = mono_method_full_name (method, TRUE);      \
                char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
-               cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);             \
                cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
                g_free (method_fname);  \
                g_free (cil_method_fname);      \
@@ -83,7 +84,7 @@
 #define FIELD_ACCESS_FAILURE do {      \
                char *method_fname = mono_method_full_name (method, TRUE);      \
                char *field_fname = mono_field_full_name (field);       \
-               cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);              \
                cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
                g_free (method_fname);  \
                g_free (field_fname);   \
                if (cfg->generic_sharing_context) {     \
             if (cfg->verbose_level > 2) \
                            printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
-                       cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
+                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
                        goto exception_exit;    \
                }                       \
        } while (0)
-
+#define OUT_OF_MEMORY_FAILURE do {     \
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
+               goto exception_exit;    \
+       } while (0)
 /* Determine whenever 'ins' represents a load of the 'this' argument */
 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
 
@@ -111,14 +115,14 @@ MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMetho
 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
 
-/* helper methods signature */
-extern MonoMethodSignature *helper_sig_class_init_trampoline;
-extern MonoMethodSignature *helper_sig_domain_get;
-extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
-extern MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
-extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
-extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
-extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
+/* helper methods signatures */
+static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
+static MonoMethodSignature *helper_sig_domain_get = NULL;
+static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
+static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
+static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
+static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
 
 /*
  * Instruction metadata
@@ -288,6 +292,8 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
 
 #define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
 
+#define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
+
 #define GET_BBLOCK(cfg,tblock,ip) do { \
                (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
                if (!(tblock)) {        \
@@ -2593,19 +2599,26 @@ create_write_barrier_bitmap (MonoClass *klass, unsigned *wb_bitmap, int offset)
 static void
 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_reg)
 {
-#ifdef HAVE_SGEN_GC
        int card_table_shift_bits;
        gpointer card_table_mask;
-       guint8 *card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
+       guint8 *card_table;
        MonoInst *dummy_use;
-
-#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER__
        int nursery_shift_bits;
        size_t nursery_size;
+       gboolean has_card_table_wb = FALSE;
+
+       if (!cfg->gen_write_barriers)
+               return;
+
+       card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
 
        mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
 
-       if (card_table && nursery_shift_bits > 0) {
+#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
+       has_card_table_wb = TRUE;
+#endif
+
+       if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0) {
                MonoInst *wbarrier;
 
                MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
@@ -2615,9 +2628,7 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_
                else
                        wbarrier->sreg2 = value_reg;
                MONO_ADD_INS (cfg->cbb, wbarrier);
-       }
-#else
-       if (card_table) {
+       } else if (card_table) {
                int offset_reg = alloc_preg (cfg);
                int card_reg  = alloc_preg (cfg);
                MonoInst *ins;
@@ -2629,16 +2640,18 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_
                /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
                 * IMM's larger than 32bits.
                 */
-               MONO_INST_NEW (cfg, ins, OP_PCONST);
-               ins->inst_p0 = card_table;
-               ins->dreg = card_reg;
-               MONO_ADD_INS (cfg->cbb, ins);
+               if (cfg->compile_aot) {
+                       MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
+               } else {
+                       MONO_INST_NEW (cfg, ins, OP_PCONST);
+                       ins->inst_p0 = card_table;
+                       ins->dreg = card_reg;
+                       MONO_ADD_INS (cfg->cbb, ins);
+               }
 
                MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
                MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
-       }
-#endif
-       else {
+       } else {
                MonoMethod *write_barrier = mono_gc_get_write_barrier ();
                mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
        }
@@ -2650,7 +2663,6 @@ emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_
                dummy_use->sreg1 = value_reg;
                MONO_ADD_INS (cfg->cbb, dummy_use);
        }
-#endif
 }
 
 static gboolean
@@ -3000,6 +3012,43 @@ emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
 #endif
 }
 
+static void
+save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
+{
+       if (mini_get_debug_options ()->better_cast_details) {
+               int to_klass_reg = alloc_preg (cfg);
+               int vtable_reg = alloc_preg (cfg);
+               int klass_reg = alloc_preg (cfg);
+               MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
+
+               if (!tls_get) {
+                       fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
+                       exit (1);
+               }
+
+               MONO_ADD_INS (cfg->cbb, tls_get);
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
+
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
+               MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
+       }
+}
+
+static void
+reset_cast_details (MonoCompile *cfg)
+{
+       /* Reset the variables holding the cast details */
+       if (mini_get_debug_options ()->better_cast_details) {
+               MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
+
+               MONO_ADD_INS (cfg->cbb, tls_get);
+               /* It is enough to reset the from field */
+               MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
+       }
+}
+
 /*
  * On return the caller must check @array_class for load errors
  */
@@ -3012,8 +3061,10 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
        if (cfg->generic_sharing_context)
                context_used = mono_class_check_context_used (array_class);
 
+       save_cast_details (cfg, array_class, obj->dreg);
+
        MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
-                                      
+
        if (cfg->opt & MONO_OPT_SHARED) {
                int class_reg = alloc_preg (cfg);
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
@@ -3048,43 +3099,8 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl
        }
        
        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
-}
 
-static void
-save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
-{
-       if (mini_get_debug_options ()->better_cast_details) {
-               int to_klass_reg = alloc_preg (cfg);
-               int vtable_reg = alloc_preg (cfg);
-               int klass_reg = alloc_preg (cfg);
-               MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
-
-               if (!tls_get) {
-                       fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
-                       exit (1);
-               }
-
-               MONO_ADD_INS (cfg->cbb, tls_get);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
-
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
-               MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
-       }
-}
-
-static void
-reset_cast_details (MonoCompile *cfg)
-{
-       /* Reset the variables holding the cast details */
-       if (mini_get_debug_options ()->better_cast_details) {
-               MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
-
-               MONO_ADD_INS (cfg->cbb, tls_get);
-               /* It is enough to reset the from field */
-               MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
-       }
+       reset_cast_details (cfg);
 }
 
 /**
@@ -3218,7 +3234,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_
                gboolean pass_lw;
 
                if (!vtable) {
-                       cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
                        cfg->exception_ptr = klass;
                        return NULL;
                }
@@ -3279,8 +3295,40 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
        return alloc;
 }
 
+
+static gboolean
+mini_class_has_reference_variant_generic_argument (MonoClass *klass, int context_used)
+{
+       int i;
+       MonoGenericContainer *container;
+       MonoGenericInst *ginst;
+
+       if (klass->generic_class) {
+               container = klass->generic_class->container_class->generic_container;
+               ginst = klass->generic_class->context.class_inst;
+       } else if (klass->generic_container && context_used) {
+               container = klass->generic_container;
+               ginst = container->context.class_inst;
+       } else {
+               return FALSE;
+       }
+
+       for (i = 0; i < container->type_argc; ++i) {
+               MonoType *type;
+               if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
+                       continue;
+               type = ginst->type_argv [i];
+               if (MONO_TYPE_IS_REFERENCE (type))
+                       return TRUE;
+
+               if (context_used && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 // FIXME: This doesn't work yet (class libs tests fail?)
-#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mono_class_has_variant_generic_params (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
 
 /*
  * Returns NULL and set the cfg exception on error.
@@ -3294,10 +3342,27 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context
        MonoInst *klass_inst = NULL;
 
        if (context_used) {
-               MonoInst *args [2];
+               MonoInst *args [3];
+
+               if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                       MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+                       MonoInst *cache_ins;
 
-               klass_inst = emit_get_rgctx_klass (cfg, context_used,
-                                                                                  klass, MONO_RGCTX_INFO_KLASS);
+                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass - it's the second element of the cache entry*/
+                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+                       /* cache */
+                       args [2] = cache_ins;
+
+                       return mono_emit_method_call (cfg, mono_castclass, args, NULL);
+               }
+
+               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
 
                if (is_complex_isinst (klass)) {
                        /* Complex case, handle by an icall */
@@ -3334,7 +3399,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context
                        if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
                                MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
                                if (!vt) {
-                                       cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+                                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
                                        cfg->exception_ptr = klass;
                                        return NULL;
                                }
@@ -3371,11 +3436,29 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us
        MonoInst *klass_inst = NULL;
 
        if (context_used) {
+               MonoInst *args [3];
+
+               if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                       MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+                       MonoInst *cache_ins;
+
+                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass - it's the second element of the cache entry*/
+                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+                       /* cache */
+                       args [2] = cache_ins;
+
+                       return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+               }
+
                klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
 
                if (is_complex_isinst (klass)) {
-                       MonoInst *args [2];
-
                        /* Complex case, handle by an icall */
 
                        /* obj */
@@ -3460,7 +3543,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us
                                if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
                                        MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
                                        if (!vt) {
-                                               cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+                                               mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
                                                cfg->exception_ptr = klass;
                                                return NULL;
                                        }
@@ -3668,6 +3751,8 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
 static G_GNUC_UNUSED MonoInst*
 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
 {
+       MonoInst *ptr;
+       int dreg;
        gpointer *trampoline;
        MonoInst *obj, *method_ins, *tramp_ins;
        MonoDomain *domain;
@@ -3681,13 +3766,23 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
 
        /* Set target field */
        /* Optimize away setting of NULL target */
-       if (!(target->opcode == OP_PCONST && target->inst_p0 == 0))
+       if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
+               if (cfg->gen_write_barriers) {
+                       dreg = alloc_preg (cfg);
+                       EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
+                       emit_write_barrier (cfg, ptr, target, 0);
+               }
+       }
 
        /* Set method field */
        method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
-
+       if (cfg->gen_write_barriers) {
+               dreg = alloc_preg (cfg);
+               EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
+               emit_write_barrier (cfg, ptr, method_ins, 0);
+       }
        /* 
         * To avoid looking up the compiled code belonging to the target method
         * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
@@ -4310,10 +4405,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                }
        } else if (cmethod->klass == mono_defaults.monitor_class) {
 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
-               /* The trampolines don't work under SGEN */
-               gboolean is_moving_gc = mono_gc_is_moving ();
-
-               if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1 && !is_moving_gc) {
+               if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
                        MonoCallInst *call;
 
                        if (COMPILE_LLVM (cfg)) {
@@ -4330,7 +4422,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        }
 
                        return (MonoInst*)call;
-               } else if (strcmp (cmethod->name, "Exit") == 0 && !is_moving_gc) {
+               } else if (strcmp (cmethod->name, "Exit") == 0) {
                        MonoCallInst *call;
 
                        if (COMPILE_LLVM (cfg)) {
@@ -4687,7 +4779,7 @@ check_inline_caller_method_name_limit (MonoMethod *caller_method)
 
 static int
 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
-               guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_allways)
+               guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
 {
        MonoInst *ins, *rvar = NULL;
        MonoMethodHeader *cheader;
@@ -4709,11 +4801,11 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
 
 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
-       if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
+       if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
                return 0;
 #endif
 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
-       if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
+       if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
                return 0;
 #endif
 
@@ -4729,12 +4821,23 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cheader = mono_method_get_header (cmethod);
 
        if (cheader == NULL || mono_loader_get_last_error ()) {
+               MonoLoaderError *error = mono_loader_get_last_error ();
+
                if (cheader)
                        mono_metadata_free_mh (cheader);
+               if (inline_always && error)
+                       mono_cfg_set_exception (cfg, error->exception_type);
+
                mono_loader_clear_error ();
                return 0;
        }
 
+       /*Must verify before creating locals as it can cause the JIT to assert.*/
+       if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
+               mono_metadata_free_mh (cheader);
+               return 0;
+       }
+
        /* allocate space to store the return value */
        if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
@@ -4789,7 +4892,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cfg->ret_var_set = prev_ret_var_set;
        cfg->inline_depth --;
 
-       if ((costs >= 0 && costs < 60) || inline_allways) {
+       if ((costs >= 0 && costs < 60) || inline_always) {
                if (cfg->verbose_level > 2)
                        printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
                
@@ -4906,7 +5009,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
-#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
 
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
@@ -5077,7 +5180,7 @@ gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *cal
                mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
        } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
                 /* don't hide previous results */
-               cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
                cfg->exception_data = result;
                return TRUE;
        }
@@ -5241,7 +5344,7 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign
                method_code = g_strdup ("method body is empty.");
        else
                method_code = mono_disasm_code_one (NULL, method, ip, NULL);
-       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+       mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
        cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
        g_free (method_fname);
        g_free (method_code);
@@ -5251,8 +5354,8 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign
 static void
 set_exception_object (MonoCompile *cfg, MonoException *exception)
 {
-       cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
-       MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
+       mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
+       MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
        cfg->exception_ptr = exception;
 }
 
@@ -5339,6 +5442,60 @@ is_exception_class (MonoClass *class)
        return FALSE;
 }
 
+/*
+ * is_jit_optimizer_disabled:
+ *
+ *   Determine whenever M's assembly has a DebuggableAttribute with the
+ * IsJITOptimizerDisabled flag set.
+ */
+static gboolean
+is_jit_optimizer_disabled (MonoMethod *m)
+{
+       MonoAssembly *ass = m->klass->image->assembly;
+       MonoCustomAttrInfo* attrs;
+       static MonoClass *klass;
+       int i;
+       gboolean val = FALSE;
+
+       g_assert (ass);
+       if (ass->jit_optimizer_disabled_inited)
+               return ass->jit_optimizer_disabled;
+
+       klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
+
+       attrs = mono_custom_attrs_from_assembly (ass);
+       if (attrs) {
+               for (i = 0; i < attrs->num_attrs; ++i) {
+                       MonoCustomAttrEntry *attr = &attrs->attrs [i];
+                       const gchar *p;
+                       int len;
+                       MonoMethodSignature *sig;
+
+                       if (!attr->ctor || attr->ctor->klass != klass)
+                               continue;
+                       /* Decode the attribute. See reflection.c */
+                       len = attr->data_size;
+                       p = (const char*)attr->data;
+                       g_assert (read16 (p) == 0x0001);
+                       p += 2;
+
+                       // FIXME: Support named parameters
+                       sig = mono_method_signature (attr->ctor);
+                       if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
+                               continue;
+                       /* Two boolean arguments */
+                       p ++;
+                       val = *p;
+               }
+       }
+
+       ass->jit_optimizer_disabled = val;
+       mono_memory_barrier ();
+       ass->jit_optimizer_disabled_inited = TRUE;
+
+       return val;
+}
+
 /*
  * mono_method_to_ir:
  *
@@ -5377,6 +5534,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
        int context_used;
        gboolean init_locals, seq_points, skip_dead_blocks;
+       gboolean disable_inline;
+
+       disable_inline = is_jit_optimizer_disabled (method);
 
        /* serialization and xdomain stuff may need access to private fields and methods */
        dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
@@ -5399,9 +5559,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                MonoLoaderError *error;
 
                if ((error = mono_loader_get_last_error ())) {
-                       cfg->exception_type = error->exception_type;
+                       mono_cfg_set_exception (cfg, error->exception_type);
                } else {
-                       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+                       mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
                        cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
                }
                goto exception_exit;
@@ -5435,9 +5595,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                dont_verify_stloc = TRUE;
        }
 
-       if (!dont_verify && mini_method_verify (cfg, method_definition))
-               goto exception_exit;
-
        if (mono_debug_using_mono_debugger ())
                cfg->keep_cil_nops = TRUE;
 
@@ -5510,6 +5667,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoExceptionClause *clause = &header->clauses [i];
                        GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
                        try_bb->real_offset = clause->try_offset;
+                       try_bb->try_start = TRUE;
+                       try_bb->region = ((i + 1) << 8) | clause->flags;
                        GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
                        tblock->flags |= BB_EXCEPTION_HANDLER;
@@ -5522,6 +5681,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
                            clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
                            clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
+                               if (seq_points) {
+                                       NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
+                                       MONO_ADD_INS (tblock, ins);
+                               }
                                MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                MONO_ADD_INS (tblock, ins);
 
@@ -6181,7 +6344,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
 
                        if (!cmethod || mono_loader_get_last_error ())
-                               goto load_error;
+                               LOAD_ERROR;
  
                        if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
                                GENERIC_SHARING_FAILURE (CEE_JMP);
@@ -6295,7 +6458,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                if (!cmethod || mono_loader_get_last_error ())
-                                       goto load_error;
+                                       LOAD_ERROR;
                                if (!dont_verify && !cfg->skip_visibility) {
                                        MonoMethod *target_method = cil_method;
                                        if (method->is_inflated) {
@@ -6328,7 +6491,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if (!cmethod->klass->inited)
                                        if (!mono_class_init (cmethod->klass))
-                                               goto load_error;
+                                               LOAD_ERROR;
 
                                if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
                                    mini_class_is_system_array (cmethod->klass)) {
@@ -6338,7 +6501,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        fsig = mono_method_signature (cmethod);
 
                                        if (!fsig)
-                                               goto load_error;
+                                               LOAD_ERROR;
 
                                        if (fsig->pinvoke) {
                                                MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
@@ -6629,6 +6792,33 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
+                       /*
+                        * Implement a workaround for the inherent races involved in locking:
+                        * Monitor.Enter ()
+                        * try {
+                        * } finally {
+                        *    Monitor.Exit ()
+                        * }
+                        * If a thread abort happens between the call to Monitor.Enter () and the start of the
+                        * try block, the Exit () won't be executed, see:
+                        * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
+                        * To work around this, we extend such try blocks to include the last x bytes
+                        * of the Monitor.Enter () call.
+                        */
+                       if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
+                               MonoBasicBlock *tbb;
+
+                               GET_BBLOCK (cfg, tbb, ip + 5);
+                               /* 
+                                * Only extend try blocks with a finally, to avoid catching exceptions thrown
+                                * from Monitor.Enter like ArgumentNullException.
+                                */
+                               if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
+                                       /* Mark this bblock as needing to be extended */
+                                       tbb->extend_try_block = TRUE;
+                               }
+                       }
+
                        /* Conversion to a JIT intrinsic */
                        if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
                                bblock = cfg->cbb;
@@ -6648,20 +6838,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* Inlining */
                        if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
                                (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
-                           mono_method_check_inlining (cfg, cmethod) &&
+                           !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
                                 !g_list_find (dont_inline, cmethod)) {
                                int costs;
-                               gboolean allways = FALSE;
+                               gboolean always = FALSE;
 
                                if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                                        (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
                                        /* Prevent inlining of methods that call wrappers */
                                        INLINE_FAILURE;
                                        cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
-                                       allways = TRUE;
+                                       always = TRUE;
                                }
 
-                               if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, allways))) {
+                               if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always))) {
                                        ip += 5;
                                        cfg->real_offset += 5;
                                        bblock = cfg->cbb;
@@ -7565,6 +7755,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                NEW_PCONST (cfg, ins, NULL);
                                                ins->type = STACK_OBJ;
                                                ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+                                               if (!ins->inst_p0)
+                                                       OUT_OF_MEMORY_FAILURE;
+
                                                *sp = ins;
                                                MONO_ADD_INS (bblock, ins);
                                        }
@@ -7585,15 +7778,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
                        if (!cmethod || mono_loader_get_last_error ())
-                               goto load_error;
+                               LOAD_ERROR;
                        fsig = mono_method_get_signature (cmethod, image, token);
                        if (!fsig)
-                               goto load_error;
+                               LOAD_ERROR;
 
                        mono_save_token_info (cfg, image, token, cmethod);
 
                        if (!mono_class_init (cmethod->klass))
-                               goto load_error;
+                               LOAD_ERROR;
 
                        if (cfg->generic_sharing_context)
                                context_used = mono_method_check_context_used (cmethod);
@@ -7765,12 +7958,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
 
                                        CHECK_CFG_EXCEPTION;
-                               } else
-
-
-
-                               if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
-                                   mono_method_check_inlining (cfg, cmethod) &&
+                               } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
+                                   !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
                                    !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
                                    !g_list_find (dont_inline, cmethod)) {
                                        int costs;
@@ -7826,8 +8015,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
-                       if (!context_used && mono_class_has_variant_generic_params (klass)) {
-                               MonoInst *args [2];
+                       if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                               MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+                               MonoInst *args [3];
 
                                /* obj */
                                args [0] = *sp;
@@ -7835,8 +8025,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* klass */
                                EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 
-                               ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
-                               *sp ++ = ins;
+                               /* inline cache*/
+                               /*FIXME AOT support*/
+                               EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
+
+                               /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
+                               *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
                                ip += 5;
                                inline_costs += 2;
                        } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
@@ -7848,7 +8042,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                iargs [0] = sp [0];
                                
                                costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
-                                                          iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
+                                                          iargs, ip, cfg->real_offset, dont_inline, TRUE);
+                               CHECK_CFG_EXCEPTION;
                                g_assert (costs > 0);
                                
                                ip += 5;
@@ -7880,8 +8075,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
-                       if (!context_used && mono_class_has_variant_generic_params (klass)) {
-                               MonoInst *args [2];
+                       if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                               MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+                               MonoInst *args [3];
 
                                /* obj */
                                args [0] = *sp;
@@ -7889,8 +8085,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* klass */
                                EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 
-                               *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
-                               sp++;
+                               /* inline cache*/
+                               /*FIXME AOT support*/
+                               EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
+
+                               *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
                                ip += 5;
                                inline_costs += 2;
                        } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
@@ -7902,7 +8101,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                iargs [0] = sp [0];
 
                                costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
-                                                          iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
+                                                          iargs, ip, cfg->real_offset, dont_inline, TRUE);
+                               CHECK_CFG_EXCEPTION;
                                g_assert (costs > 0);
                                
                                ip += 5;
@@ -7937,7 +8137,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (generic_class_is_reference_type (cfg, klass)) {
                                /* CASTCLASS FIXME kill this huge slice of duplicated code*/
-                               if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                               if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                                       MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+                                       MonoInst *args [3];
+
+                                       /* obj */
+                                       args [0] = *sp;
+
+                                       /* klass */
+                                       EMIT_NEW_CLASSCONST (cfg, args [1], klass);
+
+                                       /* inline cache*/
+                                       /*FIXME AOT support*/
+                                       EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
+
+                                       /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
+                                       *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
+                                       ip += 5;
+                                       inline_costs += 2;
+                               } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                        MonoMethod *mono_castclass;
                                        MonoInst *iargs [1];
                                        int costs;
@@ -7947,7 +8165,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
                                                                                   iargs, ip, cfg->real_offset, dont_inline, TRUE);
-                       
+                                       CHECK_CFG_EXCEPTION;
                                        g_assert (costs > 0);
                                
                                        ip += 5;
@@ -8149,7 +8367,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                field = mono_field_from_token (image, token, &klass, generic_context);
                        }
                        if (!field)
-                               goto load_error;
+                               LOAD_ERROR;
                        if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
                                FIELD_ACCESS_FAILURE;
                        mono_class_init (klass);
@@ -8178,6 +8396,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
                                                costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
                                                                       iargs, ip, cfg->real_offset, dont_inline, TRUE);
+                                               CHECK_CFG_EXCEPTION;
                                                g_assert (costs > 0);
                                                      
                                                cfg->real_offset += 5;
@@ -8224,6 +8443,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
                                        costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
                                                                                   iargs, ip, cfg->real_offset, dont_inline, TRUE);
+                                       CHECK_CFG_EXCEPTION;
                                        bblock = cfg->cbb;
                                        g_assert (costs > 0);
                                                      
@@ -8297,7 +8517,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                field = mono_field_from_token (image, token, &klass, generic_context);
                        if (!field)
-                               goto load_error;
+                               LOAD_ERROR;
                        mono_class_init (klass);
                        if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
                                FIELD_ACCESS_FAILURE;
@@ -8840,9 +9060,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* storing a NULL doesn't need any of the complex checks in stelemref */
                        if (generic_class_is_reference_type (cfg, klass) &&
                                !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
-                               MonoMethod* helper = mono_marshal_get_stelemref ();
+                               MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
+                               MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
                                MonoInst *iargs [3];
 
+                               if (!helper->slot)
+                                       mono_class_setup_vtable (obj_array);
+                               g_assert (helper->slot);
+
                                if (sp [0]->type != STACK_OBJ)
                                        UNVERIFIED;
                                if (sp [2]->type != STACK_OBJ)
@@ -8851,8 +9076,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                iargs [2] = sp [2];
                                iargs [1] = sp [1];
                                iargs [0] = sp [0];
-                               
-                               mono_emit_method_call (cfg, helper, iargs, NULL);
+
+                               mono_emit_method_call (cfg, helper, iargs, sp [0]);
                        } else {
                                if (sp [1]->opcode == OP_ICONST) {
                                        int array_reg = sp [0]->dreg;
@@ -8997,7 +9222,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle = mono_ldtoken (image, n, &handle_class, generic_context);
                        }
                        if (!handle)
-                               goto load_error;
+                               LOAD_ERROR;
                        mono_class_init (handle_class);
                        if (cfg->generic_sharing_context) {
                                if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
@@ -9192,7 +9417,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_BBLOCK (cfg, dont_throw);
 
                                        /*
-                                        * Currently, we allways rethrow the abort exception, despite the 
+                                        * Currently, we always rethrow the abort exception, despite the 
                                         * fact that this is not correct. See thread6.cs for an example. 
                                         * But propagating the abort exception is more important than 
                                         * getting the sematics right.
@@ -9611,7 +9836,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
                                if (!cmethod || mono_loader_get_last_error ())
-                                       goto load_error;
+                                       LOAD_ERROR;
                                mono_class_init (cmethod->klass);
 
                                mono_save_token_info (cfg, image, n, cmethod);
@@ -9639,25 +9864,33 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
                                        MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
                                        if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+                                               MonoInst *target_ins;
                                                MonoMethod *invoke;
                                                int invoke_context_used = 0;
 
                                                invoke = mono_get_delegate_invoke (ctor_method->klass);
                                                if (!invoke || !mono_method_signature (invoke))
-                                                       goto load_error;
+                                                       LOAD_ERROR;
 
                                                if (cfg->generic_sharing_context)
                                                        invoke_context_used = mono_method_check_context_used (invoke);
 
+                                               target_ins = sp [-1];
+
+                                               if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
+                                                       /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
+                                                       if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
+                                                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
+                                                               MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
+                                                       }
+                                               }
+
 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
                                                /* FIXME: SGEN support */
-                                               if (!cfg->gen_write_barriers && invoke_context_used == 0) {
-                                                       MonoInst *target_ins;
-
+                                               if (invoke_context_used == 0) {
                                                        ip += 6;
                                                        if (cfg->verbose_level > 3)
                                                                g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
-                                                       target_ins = sp [-1];
                                                        sp --;
                                                        *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
                                                        CHECK_CFG_EXCEPTION;
@@ -9685,7 +9918,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
                                if (!cmethod || mono_loader_get_last_error ())
-                                       goto load_error;
+                                       LOAD_ERROR;
                                mono_class_init (cmethod->klass);
  
                                if (cfg->generic_sharing_context)
@@ -10119,7 +10352,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                /* Method is too large */
                mname = mono_method_full_name (method, TRUE);
-               cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+               mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
                cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
                g_free (mname);
                cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
@@ -10142,7 +10375,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        goto cleanup;
 
  load_error:
-       cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+       mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
        goto cleanup;
 
  unverified:
@@ -11350,6 +11583,18 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        g_free (live_range_end_bb);
 }
 
+void
+mono_create_helper_signatures (void)
+{
+       helper_sig_domain_get = mono_create_icall_signature ("ptr");
+       helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
+       helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
+       helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
+       helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
+       helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
+       helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
+}
+
 /**
  * FIXME:
  * - use 'iadd' instead of 'int_add'