New tests.
[mono.git] / mono / mini / method-to-ir.c
index 95aa915d245d03cfa63385aa0d827fe74af0f212..5ae9f41d06e578a9fe5d7e56044e2352bf8707d1 100644 (file)
@@ -27,9 +27,7 @@
 #include <alloca.h>
 #endif
 
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
+#include <mono/utils/memcheck.h>
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/security-core-clr.h>
 #include <mono/metadata/monitor.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/profiler.h>
 #include <mono/utils/mono-compiler.h>
+#include <mono/metadata/mono-basic-block.h>
 
 #include "mini.h"
 #include "trace.h"
@@ -57,6 +58,8 @@
 #include "ir-emit.h"
 
 #include "jit-icalls.h"
+#include "jit.h"
+#include "debugger-agent.h"
 
 #define BRANCH_COST 100
 #define INLINE_LENGTH_LIMIT 20
@@ -114,6 +117,7 @@ extern MonoMethodSignature *helper_sig_domain_get;
 extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
 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;
 
 /*
  * Instruction metadata
@@ -156,8 +160,6 @@ const gint8 ins_sreg_counts[] = {
 #undef MINI_OP
 #undef MINI_OP3
 
-extern GHashTable *jit_icall_name_hash;
-
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
        (vi)->reg = -1; \
@@ -462,8 +464,7 @@ mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
 static int
 mono_find_block_region (MonoCompile *cfg, int offset)
 {
-       MonoMethod *method = cfg->method;
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
        int i;
 
@@ -492,10 +493,8 @@ mono_find_block_region (MonoCompile *cfg, int offset)
 static GList*
 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
 {
-       MonoMethod *method = cfg->method;
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
-       MonoBasicBlock *handler;
        int i;
        GList *res = NULL;
 
@@ -503,11 +502,8 @@ mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *targe
                clause = &header->clauses [i];
                if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
                    (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
-                       if (clause->flags == type) {
-                               handler = cfg->cil_offset_to_bb [clause->handler_offset];
-                               g_assert (handler);
-                               res = g_list_append (res, handler);
-                       }
+                       if (clause->flags == type)
+                               res = g_list_append (res, clause);
                }
        }
        return res;
@@ -529,7 +525,7 @@ mono_create_spvar_for_region (MonoCompile *cfg, int region)
        g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
 }
 
-static MonoInst *
+MonoInst *
 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
 {
        return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
@@ -1096,7 +1092,8 @@ type_from_stack_type (MonoInst *ins) {
 static G_GNUC_UNUSED int
 type_to_stack_type (MonoType *t)
 {
-       switch (mono_type_get_underlying_type (t)->type) {
+       t = mono_type_get_underlying_type (t);
+       switch (t->type) {
        case MONO_TYPE_I1:
        case MONO_TYPE_U1:
        case MONO_TYPE_BOOLEAN:
@@ -1189,7 +1186,7 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
        int pos, vnum;
 
        /* inlining can result in deeper stacks */ 
-       if (slot >= mono_method_get_header (cfg->method)->max_stack)
+       if (slot >= cfg->header->max_stack)
                return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
 
        pos = ins->type - 1 + slot * STACK_MAX;
@@ -1373,17 +1370,26 @@ mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg,
        }
 }
 
-/* 
- * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
- * stored in "klass_reg" implements the interface "klass".
- */
 static void
-mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
 {
        int ibitmap_reg = alloc_preg (cfg);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       MonoInst *args [2];
+       MonoInst *res, *ins;
+       NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
+       MONO_ADD_INS (cfg->cbb, ins);
+       args [0] = ins;
+       if (cfg->compile_aot)
+               EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
+       else
+               EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
+       res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
+       MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
+#else
        int ibitmap_byte_reg = alloc_preg (cfg);
 
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap));
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
 
        if (cfg->compile_aot) {
                int iid_reg = alloc_preg (cfg);
@@ -1404,6 +1410,17 @@ mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass
                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
        }
+#endif
+}
+
+/* 
+ * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
+ * stored in "klass_reg" implements the interface "klass".
+ */
+static void
+mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
+{
+       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
 }
 
 /* 
@@ -1413,30 +1430,7 @@ mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass
 static void
 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
 {
-       int ibitmap_reg = alloc_preg (cfg);
-       int ibitmap_byte_reg = alloc_preg (cfg);
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap));
-
-       if (cfg->compile_aot) {
-               int iid_reg = alloc_preg (cfg);
-               int shifted_iid_reg = alloc_preg (cfg);
-               int ibitmap_byte_address_reg = alloc_preg (cfg);
-               int masked_iid_reg = alloc_preg (cfg);
-               int iid_one_bit_reg = alloc_preg (cfg);
-               int iid_bit_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, shifted_iid_reg, iid_reg, 3);
-               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, masked_iid_reg, iid_reg, 7);
-               MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
-               MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
-               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
-       } else {
-               MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
-       }
+       mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
 }
 
 /* 
@@ -1482,8 +1476,8 @@ mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass
        mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
 }
 
-static void 
-mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+static void
+mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
 {
        int idepth_reg = alloc_preg (cfg);
        int stypes_reg = alloc_preg (cfg);
@@ -1496,7 +1490,9 @@ mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoB
        }
        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-       if (cfg->compile_aot) {
+       if (klass_ins) {
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
+       } else if (cfg->compile_aot) {
                int const_reg = alloc_preg (cfg);
                MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
@@ -1506,7 +1502,13 @@ mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoB
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
 }
 
-static void 
+static void
+mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
+{
+       mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
+}
+
+static void
 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
 {
        int intf_reg = alloc_preg (cfg);
@@ -1523,7 +1525,7 @@ mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBa
 /*
  * Variant of the above that takes a register to the class, not the vtable.
  */
-static void 
+static void
 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
 {
        int intf_bit_reg = alloc_preg (cfg);
@@ -1538,9 +1540,11 @@ mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, M
 }
 
 static inline void
-mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
 {
-       if (cfg->compile_aot) {
+       if (klass_inst) {
+               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
+       } else if (cfg->compile_aot) {
                int const_reg = alloc_preg (cfg);
                MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
                MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
@@ -1550,6 +1554,12 @@ mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
 }
 
+static inline void
+mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
+{
+       return mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
+}
+
 static inline void
 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
 {
@@ -1562,14 +1572,18 @@ mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass,
        }
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
 }
+
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
        
-static void 
-mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+static void
+mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
 {
        if (klass->rank) {
                int rank_reg = alloc_preg (cfg);
                int eclass_reg = alloc_preg (cfg);
 
+               g_assert (!klass_inst);
                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
                MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
@@ -1611,10 +1625,16 @@ mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *kl
                }
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
-               mini_emit_class_check (cfg, stype, klass);
+               mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
        }
 }
 
+static void
+mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
+{
+       return mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
+}
+
 static void 
 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
 {
@@ -1693,8 +1713,6 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val,
        }
 }
 
-#endif /* DISABLE_JIT */
-
 void 
 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
 {
@@ -1703,6 +1721,9 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so
        if (align == 0)
                align = 4;
 
+       /*FIXME arbitrary hack to avoid unbound code expansion.*/
+       g_assert (size < 10000);
+
        if (align < 4) {
                /* This could be optimized further if neccesary */
                while (size >= 1) {
@@ -1754,8 +1775,6 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so
        }
 }
 
-#ifndef DISABLE_JIT
-
 static int
 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
 {
@@ -2098,9 +2117,6 @@ mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpoint
        return ji;
 }
 
-inline static MonoInst*
-mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
-
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
                                         MonoInst **args, int calli, int virtual, int tail)
@@ -2153,30 +2169,32 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
                call->inst.dreg = alloc_dreg (cfg, call->inst.type);
 
 #ifdef MONO_ARCH_SOFT_FLOAT
-       /* 
-        * If the call has a float argument, we would need to do an r8->r4 conversion using 
-        * an icall, but that cannot be done during the call sequence since it would clobber
-        * the call registers + the stack. So we do it before emitting the call.
-        */
-       for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
-               MonoType *t;
-               MonoInst *in = call->args [i];
+       if (COMPILE_SOFT_FLOAT (cfg)) {
+               /* 
+                * If the call has a float argument, we would need to do an r8->r4 conversion using 
+                * an icall, but that cannot be done during the call sequence since it would clobber
+                * the call registers + the stack. So we do it before emitting the call.
+                */
+               for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
+                       MonoType *t;
+                       MonoInst *in = call->args [i];
 
-               if (i >= sig->hasthis)
-                       t = sig->params [i - sig->hasthis];
-               else
-                       t = &mono_defaults.int_class->byval_arg;
-               t = mono_type_get_underlying_type (t);
+                       if (i >= sig->hasthis)
+                               t = sig->params [i - sig->hasthis];
+                       else
+                               t = &mono_defaults.int_class->byval_arg;
+                       t = mono_type_get_underlying_type (t);
 
-               if (!t->byref && t->type == MONO_TYPE_R4) {
-                       MonoInst *iargs [1];
-                       MonoInst *conv;
+                       if (!t->byref && t->type == MONO_TYPE_R4) {
+                               MonoInst *iargs [1];
+                               MonoInst *conv;
 
-                       iargs [0] = in;
-                       conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
+                               iargs [0] = in;
+                               conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
 
-                       /* The result will be in an int vreg */
-                       call->args [i] = conv;
+                               /* The result will be in an int vreg */
+                               call->args [i] = conv;
+                       }
                }
        }
 #endif
@@ -2287,6 +2305,8 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
                if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
+                       MONO_EMIT_NULL_CHECK (cfg, this_reg);
+
                        /* Make a call to delegate->invoke_impl */
                        call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
                        call->inst.inst_basereg = this_reg;
@@ -2300,20 +2320,22 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                if ((!cfg->compile_aot || enable_for_aot) && 
                        (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
                         (MONO_METHOD_IS_FINAL (method) &&
-                         method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) {
+                         method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
+                       !(method->klass->marshalbyref && context_used)) {
                        /* 
                         * the method is not virtual, we just need to ensure this is not null
                         * and then we can call the method directly.
                         */
                        if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
+                               /* 
+                                * The check above ensures method is not gshared, this is needed since
+                                * gshared methods can't have wrappers.
+                                */
                                method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
                        }
 
-                       if (!method->string_ctor) {
-                               cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
-                               MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, this_reg);
-                               MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, this_reg);
-                       }
+                       if (!method->string_ctor)
+                               MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
 
                        call->inst.opcode = callvirt_to_call (call->inst.opcode);
 
@@ -2328,9 +2350,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                         * it's class or the method itself are sealed.
                         * But first we need to ensure it's not a null reference.
                         */
-                       cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
-                       MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, this_reg);
-                       MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, this_reg);
+                       MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
 
                        call->inst.opcode = callvirt_to_call (call->inst.opcode);
                        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -2341,7 +2361,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
 
                vtable_reg = alloc_preg (cfg);
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+               MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
                if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                        slot_reg = -1;
 #ifdef MONO_ARCH_HAVE_IMT
@@ -2360,7 +2380,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                } else {
                        slot_reg = vtable_reg;
                        call->inst.inst_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
-                               (mono_method_get_vtable_index (method) * SIZEOF_VOID_P);
+                               ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
 #ifdef MONO_ARCH_HAVE_IMT
                        if (imt_arg) {
                                g_assert (mono_method_signature (method)->generic_param_count);
@@ -2382,7 +2402,9 @@ static MonoInst*
 mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
                MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg)
 {
+#ifdef MONO_ARCH_RGCTX_REG
        int rgctx_reg = 0;
+#endif
        MonoInst *ins;
        MonoCallInst *call;
 
@@ -2410,7 +2432,7 @@ mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMeth
        return ins;
 }
 
-static inline MonoInst*
+MonoInst*
 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
 {
        return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL);
@@ -2432,7 +2454,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
        return (MonoInst*)call;
 }
 
-inline static MonoInst*
+MonoInst*
 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
 {
        MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
@@ -2559,10 +2581,17 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                        if (context_used) {
                                iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
                        } else {
-                               EMIT_NEW_PCONST (cfg, iargs [2], klass);
-                               mono_class_compute_gc_descriptor (klass);
+                               if (cfg->compile_aot) {
+                                       EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
+                               } else {
+                                       EMIT_NEW_PCONST (cfg, iargs [2], klass);
+                                       mono_class_compute_gc_descriptor (klass);
+                               }
                        }
 
+                       /* FIXME: this does the memcpy as well (or
+                          should), so we don't need the memcpy
+                          afterwards */
                        mono_emit_jit_icall (cfg, mono_value_copy, iargs);
                }
        }
@@ -2699,14 +2728,35 @@ emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
        return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
+/*
+ * emit_get_rgctx_method:
+ *
+ *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
+ * normal constants, else emit a load from the rgctx.
+ */
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
                                           MonoMethod *cmethod, int rgctx_type)
 {
-       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
-       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+       if (!context_used) {
+               MonoInst *ins;
 
-       return emit_rgctx_fetch (cfg, rgctx, entry);
+               switch (rgctx_type) {
+               case MONO_RGCTX_INFO_METHOD:
+                       EMIT_NEW_METHODCONST (cfg, ins, cmethod);
+                       return ins;
+               case MONO_RGCTX_INFO_METHOD_RGCTX:
+                       EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
+                       return ins;
+               default:
+                       g_assert_not_reached ();
+               }
+       } else {
+               MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
+               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+
+               return emit_rgctx_fetch (cfg, rgctx, entry);
+       }
 }
 
 static MonoInst*
@@ -2876,7 +2926,7 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
        int rank_reg = alloc_dreg (cfg ,STACK_I4);
 
        obj_reg = sp [0]->dreg;
-       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+       MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
        MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
 
        /* FIXME: generics */
@@ -2918,11 +2968,42 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
  * Returns NULL and set the cfg exception on error.
  */
 static MonoInst*
-handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
+handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
 {
        MonoInst *iargs [2];
        void *alloc_ftn;
 
+       if (context_used) {
+               MonoInst *data;
+               int rgctx_info;
+               MonoInst *iargs [2];
+
+               /*
+                 FIXME: we cannot get managed_alloc here because we can't get
+                 the class's vtable (because it's not a closed class)
+
+                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
+               */
+
+               if (cfg->opt & MONO_OPT_SHARED)
+                       rgctx_info = MONO_RGCTX_INFO_KLASS;
+               else
+                       rgctx_info = MONO_RGCTX_INFO_VTABLE;
+               data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
+
+               if (cfg->opt & MONO_OPT_SHARED) {
+                       EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
+                       iargs [1] = data;
+                       alloc_ftn = mono_object_new;
+               } else {
+                       iargs [0] = data;
+                       alloc_ftn = mono_object_new_specific;
+               }
+
+               return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
+       }
+
        if (cfg->opt & MONO_OPT_SHARED) {
                EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
                EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
@@ -2966,54 +3047,32 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
 
        return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
 }
-
-static MonoInst*
-handle_alloc_from_inst (MonoCompile *cfg, MonoClass *klass, MonoInst *data_inst,
-                                               gboolean for_box)
-{
-       MonoInst *iargs [2];
-       MonoMethod *managed_alloc = NULL;
-       void *alloc_ftn;
-
-       /*
-         FIXME: we cannot get managed_alloc here because we can't get
-         the class's vtable (because it's not a closed class)
-
-       MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
-       MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
-       */
-
-       if (cfg->opt & MONO_OPT_SHARED) {
-               EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
-               iargs [1] = data_inst;
-               alloc_ftn = mono_object_new;
-       } else {
-               if (managed_alloc) {
-                       iargs [0] = data_inst;
-                       return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
-               }
-
-               iargs [0] = data_inst;
-               alloc_ftn = mono_object_new_specific;
-       }
-
-       return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
-}
        
 /*
  * Returns NULL and set the cfg exception on error.
  */    
 static MonoInst*
-handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
+handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
 {
        MonoInst *alloc, *ins;
 
        if (mono_class_is_nullable (klass)) {
                MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
-               return mono_emit_method_call (cfg, method, &val, NULL);
+
+               if (context_used) {
+                       /* FIXME: What if the class is shared?  We might not
+                          have to get the method address from the RGCTX. */
+                       MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
+                                                                                                       MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+                       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+
+                       return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+               } else {
+                       return mono_emit_method_call (cfg, method, &val, NULL);
+               }
        }
 
-       alloc = handle_alloc (cfg, klass, TRUE);
+       alloc = handle_alloc (cfg, klass, TRUE, context_used);
        if (!alloc)
                return NULL;
 
@@ -3022,38 +3081,40 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
        return alloc;
 }
 
-static MonoInst *
-handle_box_from_inst (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoInst *data_inst)
-{
-       MonoInst *alloc, *ins;
-
-       if (mono_class_is_nullable (klass)) {
-               MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
-               /* FIXME: What if the class is shared?  We might not
-                  have to get the method address from the RGCTX. */
-               MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
-                       MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
-
-               return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
-       } else {
-               alloc = handle_alloc_from_inst (cfg, klass, data_inst, TRUE);
-
-               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
-
-               return alloc;
-       }
-}
+// 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)
 
 /*
  * Returns NULL and set the cfg exception on error.
  */
 static MonoInst*
-handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
 {
        MonoBasicBlock *is_null_bb;
        int obj_reg = src->dreg;
        int vtable_reg = alloc_preg (cfg);
+       MonoInst *klass_inst = NULL;
+
+       if (context_used) {
+               MonoInst *args [2];
+
+               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 */
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass */
+                       args [1] = klass_inst;
+
+                       return mono_emit_jit_icall (cfg, mono_object_castclass, args);
+               } else {
+                       /* Simple case, handled by the code below */
+               }
+       }
 
        NEW_BBLOCK (cfg, is_null_bb);
 
@@ -3087,7 +3148,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                        MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
                } else {
                        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
-                       mini_emit_castclass (cfg, obj_reg, klass_reg, klass, is_null_bb);
+                       mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
                }
        }
 
@@ -3102,13 +3163,34 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
  * Returns NULL and set the cfg exception on error.
  */
 static MonoInst*
-handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
+handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
 {
        MonoInst *ins;
        MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
        int obj_reg = src->dreg;
        int vtable_reg = alloc_preg (cfg);
        int res_reg = alloc_preg (cfg);
+       MonoInst *klass_inst = NULL;
+
+       if (context_used) {
+               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 */
+                       args [0] = src;
+
+                       /* klass */
+                       args [1] = klass_inst;
+
+                       return mono_emit_jit_icall (cfg, mono_object_isinst, args);
+               } else {
+                       /* Simple case, the code below can handle it */
+               }
+       }
 
        NEW_BBLOCK (cfg, is_null_bb);
        NEW_BBLOCK (cfg, false_bb);
@@ -3122,19 +3204,20 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
 
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+               g_assert (!context_used);
                /* the is_null_bb target simply copies the input register to the output */
                mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
        } else {
                int klass_reg = alloc_preg (cfg);
 
-               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
-
                if (klass->rank) {
                        int rank_reg = alloc_preg (cfg);
                        int eclass_reg = alloc_preg (cfg);
 
+                       g_assert (!context_used);
                        MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
                        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
@@ -3168,11 +3251,13 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                                mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
                        }
                } else if (mono_class_is_nullable (klass)) {
+                       g_assert (!context_used);
                        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
                        /* the is_null_bb target simply copies the input register to the output */
                        mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
                } else {
                        if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
+                               g_assert (!context_used);
                                /* the remoting code is broken, access the class for now */
                                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);
@@ -3191,7 +3276,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
                        } else {
                                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
                                /* the is_null_bb target simply copies the input register to the output */
-                               mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, is_null_bb);
+                               mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
                        }
                }
        }
@@ -3315,6 +3400,8 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
 
+       save_cast_details (cfg, klass, obj_reg);
+
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                NEW_BBLOCK (cfg, interface_fail_bb);
        
@@ -3381,14 +3468,14 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
  * Returns NULL and set the cfg exception on error.
  */
 static G_GNUC_UNUSED MonoInst*
-handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method)
+handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
 {
        gpointer *trampoline;
        MonoInst *obj, *method_ins, *tramp_ins;
        MonoDomain *domain;
        guint8 **code_slot;
 
-       obj = handle_alloc (cfg, klass, FALSE);
+       obj = handle_alloc (cfg, klass, FALSE, 0);
        if (!obj)
                return NULL;
 
@@ -3400,7 +3487,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
 
        /* Set method field */
-       EMIT_NEW_METHODCONST (cfg, method_ins, method);
+       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);
 
        /* 
@@ -3411,18 +3498,22 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        if (!cfg->compile_aot && !method->dynamic) {
                MonoInst *code_slot_ins;
 
-               domain = mono_domain_get ();
-               mono_domain_lock (domain);
-               if (!domain_jit_info (domain)->method_code_hash)
-                       domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
-               code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
-               if (!code_slot) {
-                       code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
-                       g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
+               if (context_used) {
+                       code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
+               } else {
+                       domain = mono_domain_get ();
+                       mono_domain_lock (domain);
+                       if (!domain_jit_info (domain)->method_code_hash)
+                               domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
+                       code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
+                       if (!code_slot) {
+                               code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
+                               g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
+                       }
+                       mono_domain_unlock (domain);
+
+                       EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
                }
-               mono_domain_unlock (domain);
-
-               EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
        }
 
@@ -3497,7 +3588,7 @@ static gboolean inline_limit_inited;
 static gboolean
 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 {
-       MonoMethodHeader *header;
+       MonoMethodHeaderSummary header;
        MonoVTable *vtable;
 #ifdef MONO_ARCH_SOFT_FLOAT
        MonoMethodSignature *sig = mono_method_signature (method);
@@ -3507,6 +3598,9 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (cfg->generic_sharing_context)
                return FALSE;
 
+       if (cfg->inline_depth > 10)
+               return FALSE;
+
 #ifdef MONO_ARCH_HAVE_LMF_OPS
        if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
@@ -3514,19 +3608,15 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                return TRUE;
 #endif
 
-       if (method->is_inflated)
-               /* Avoid inflating the header */
-               header = mono_method_get_header (((MonoMethodInflated*)method)->declaring);
-       else
-               header = mono_method_get_header (method);
 
-       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
-           (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
-           (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
+       if (!mono_method_get_header_summary (method, &header))
+               return FALSE;
+
+       /*runtime, icall and pinvoke are checked by summary call*/
+       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
-           (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
            (method->klass->marshalbyref) ||
-           !header || header->num_clauses)
+           header.has_clauses)
                return FALSE;
 
        /* also consider num_locals? */
@@ -3538,7 +3628,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                        inline_limit = INLINE_LENGTH_LIMIT;
                inline_limit_inited = TRUE;
        }
-       if (header->code_size >= inline_limit)
+       if (header.code_size >= inline_limit)
                return FALSE;
 
        /*
@@ -3623,7 +3713,7 @@ mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTa
 }
 
 static MonoInst*
-mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index)
+mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
 {
        MonoInst *ins;
        guint32 size;
@@ -3638,8 +3728,13 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
 
 #if SIZEOF_REGISTER == 8
        /* The array reg is 64 bits but the index reg is only 32 */
-       index2_reg = alloc_preg (cfg);
-       MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+       if (COMPILE_LLVM (cfg)) {
+               /* Not needed */
+               index2_reg = index_reg;
+       } else {
+               index2_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+       }
 #else
        if (index->type == STACK_I8) {
                index2_reg = alloc_preg (cfg);
@@ -3649,7 +3744,8 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
        }
 #endif
 
-       MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
+       if (bcheck)
+               MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
 
 #if defined(TARGET_X86) || defined(TARGET_AMD64)
        if (size == 1 || size == 2 || size == 4 || size == 8) {
@@ -3743,7 +3839,7 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
        if (rank == 1)
-               return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1]);
+               return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
 
 #ifndef MONO_ARCH_EMULATE_MUL_DIV
        /* emit_ldelema_2 depends on OP_LMUL */
@@ -3759,6 +3855,72 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        return addr;
 }
 
+static MonoBreakPolicy
+always_insert_breakpoint (MonoMethod *method)
+{
+       return MONO_BREAK_POLICY_ALWAYS;
+}
+
+static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
+
+/**
+ * mono_set_break_policy:
+ * policy_callback: the new callback function
+ *
+ * Allow embedders to decide wherther to actually obey breakpoint instructions
+ * (both break IL instructions and Debugger.Break () method calls), for example
+ * to not allow an app to be aborted by a perfectly valid IL opcode when executing
+ * untrusted or semi-trusted code.
+ *
+ * @policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls Debugger.Break()
+ * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
+ * if it wants the breakpoint to not be effective in the given method.
+ * #MONO_BREAK_POLICY_ALWAYS is the default.
+ */
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+       if (policy_callback)
+               break_policy_func = policy_callback;
+       else
+               break_policy_func = always_insert_breakpoint;
+}
+
+static gboolean
+should_insert_brekpoint (MonoMethod *method) {
+       switch (break_policy_func (method)) {
+       case MONO_BREAK_POLICY_ALWAYS:
+               return TRUE;
+       case MONO_BREAK_POLICY_NEVER:
+               return FALSE;
+       case MONO_BREAK_POLICY_ON_DBG:
+               return mono_debug_using_mono_debugger ();
+       default:
+               g_warning ("Incorrect value returned from break policy callback");
+               return FALSE;
+       }
+}
+
+/* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
+static MonoInst*
+emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
+{
+       MonoInst *addr, *store, *load;
+       MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
+
+       /* the bounds check is already done by the callers */
+       addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
+       if (is_set) {
+               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
+               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
+       } else {
+               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
+               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
+       }
+       return store;
+}
+
 static MonoInst*
 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -3816,6 +3978,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
                        MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
+                       return cfg->cbb->last_ins;
                } else 
                        return NULL;
        } else if (cmethod->klass == mono_defaults.object_class) {
@@ -3823,7 +3986,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (strcmp (cmethod->name, "GetType") == 0) {
                        int dreg = alloc_preg (cfg);
                        int vt_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+                       MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
                        type_from_op (ins, NULL, NULL);
 
@@ -3846,14 +4009,16 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                } else
                        return NULL;
        } else if (cmethod->klass == mono_defaults.array_class) {
+               if (strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
+                       return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
                if (cmethod->name [0] != 'g')
                        return NULL;
 
                if (strcmp (cmethod->name, "get_Rank") == 0) {
                        int dreg = alloc_ireg (cfg);
                        int vtable_reg = alloc_preg (cfg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, vtable_reg, 
-                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
+                                                                                                args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
                                                                   vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
                        type_from_op (ins, NULL, NULL);
@@ -3862,8 +4027,8 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                } else if (strcmp (cmethod->name, "get_Length") == 0) {
                        int dreg = alloc_ireg (cfg);
 
-                       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
-                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
+                       EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
+                                                                                args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
                        type_from_op (ins, NULL, NULL);
 
                        return ins;
@@ -3891,19 +4056,31 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                if (strcmp (cmethod->name, "Enter") == 0) {
                        MonoCallInst *call;
 
-                       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
-                                       NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
-                       mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
-                                       MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       if (COMPILE_LLVM (cfg)) {
+                               /* 
+                                * Pass the argument normally, the LLVM backend will handle the
+                                * calling convention problems.
+                                */
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
+                       } else {
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
+                                           NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
+                               mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
+                                                                                          MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       }
 
                        return (MonoInst*)call;
                } else if (strcmp (cmethod->name, "Exit") == 0) {
                        MonoCallInst *call;
 
-                       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
-                                       NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
-                       mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
-                                       MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       if (COMPILE_LLVM (cfg)) {
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
+                       } else {
+                               call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
+                                           NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
+                               mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
+                                                                                          MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
+                       }
 
                        return (MonoInst*)call;
                }
@@ -3924,15 +4101,6 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
                return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
 #endif
-       } else if (mini_class_is_system_array (cmethod->klass) &&
-                       strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
-               MonoInst *addr, *store, *load;
-               MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
-
-               addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1]);
-               EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
-               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
-               return store;
        } else if (cmethod->klass->image == mono_defaults.corlib &&
                           (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
                           (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
@@ -4062,8 +4230,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
 #if HAVE_WRITE_BARRIERS
                        if (is_ref) {
+                               MonoInst *dummy_use;
                                MonoMethod *write_barrier = mono_gc_get_write_barrier ();
                                mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
                        }
 #endif
                }
@@ -4077,7 +4247,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                size = 4;
                        else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
                                size = sizeof (gpointer);
-                       else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I4)
+                       else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
                                size = 8;
                        if (size == 4) {
                                MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
@@ -4100,8 +4270,10 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        }
 #if HAVE_WRITE_BARRIERS
                        if (is_ref) {
+                               MonoInst *dummy_use;
                                MonoMethod *write_barrier = mono_gc_get_write_barrier ();
                                mono_emit_method_call (cfg, write_barrier, &args [0], NULL);
+                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [1]);
                        }
 #endif
                }
@@ -4112,13 +4284,16 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        } else if (cmethod->klass->image == mono_defaults.corlib) {
                if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
                                && strcmp (cmethod->klass->name, "Debugger") == 0) {
-                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       if (should_insert_brekpoint (cfg->method))
+                               MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       else
+                               MONO_INST_NEW (cfg, ins, OP_NOP);
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
                if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
                                && strcmp (cmethod->klass->name, "Environment") == 0) {
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
                        EMIT_NEW_ICONST (cfg, ins, 1);
 #else
                        EMIT_NEW_ICONST (cfg, ins, 0);
@@ -4154,7 +4329,7 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method,
 {
        if (method->klass == mono_defaults.string_class) {
                /* managed string allocation support */
-               if (strcmp (method->name, "InternalAllocateStr") == 0) {
+               if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                        MonoInst *iargs [2];
                        MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
                        MonoMethod *managed_alloc = NULL;
@@ -4301,13 +4476,23 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                mono_jit_stats.inlineable_methods++;
                cmethod->inline_info = 1;
        }
+
+       /* allocate local variables */
+       cheader = mono_method_get_header (cmethod);
+
+       if (cheader == NULL || mono_loader_get_last_error ()) {
+               if (cheader)
+                       mono_metadata_free_mh (cheader);
+               mono_loader_clear_error ();
+               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);
        }
 
-       /* allocate local variables */
-       cheader = mono_method_get_header (cmethod);
+
        prev_locals = cfg->locals;
        cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
        for (i = 0; i < cheader->num_locals; ++i)
@@ -4327,6 +4512,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_inlined_method = cfg->inlined_method;
        cfg->inlined_method = cmethod;
        cfg->ret_var_set = FALSE;
+       cfg->inline_depth ++;
        prev_real_offset = cfg->real_offset;
        prev_cbb_hash = cfg->cbb_hash;
        prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
@@ -4353,6 +4539,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cfg->current_method = prev_current_method;
        cfg->generic_context = prev_generic_context;
        cfg->ret_var_set = prev_ret_var_set;
+       cfg->inline_depth --;
 
        if ((costs >= 0 && costs < 60) || inline_allways) {
                if (cfg->verbose_level > 2)
@@ -4426,6 +4613,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                        EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
                        *sp++ = ins;
                }
+               mono_metadata_free_mh (cheader);
                return costs + 1;
        } else {
                if (cfg->verbose_level > 2)
@@ -4436,6 +4624,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                /* This gets rid of the newly added bblocks */
                cfg->cbb = prev_cbb;
        }
+       mono_metadata_free_mh (cheader);
        return 0;
 }
 
@@ -4693,36 +4882,20 @@ static void
 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
                                          MonoBasicBlock *bblock, unsigned char *ip)
 {
-       /* there's no restriction to access Transparent or SafeCritical fields, so we only check calls to Critical methods */
-       if (mono_security_core_clr_class_level (mono_field_get_parent (field)) != MONO_SECURITY_CORE_CLR_CRITICAL)
-               return;
-
        /* we can't get the coreclr security level on wrappers since they don't have the attributes */
-       caller = get_original_method (caller);
-       if (!caller)
-               return;
-
-       /* caller is Critical! only SafeCritical and Critical callers can access the field, so we throw if caller is Transparent */
-       if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
-               emit_throw_exception (cfg, mono_get_exception_field_access ());
+       MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
+       if (ex)
+               emit_throw_exception (cfg, ex);
 }
 
 static void
 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
                                         MonoBasicBlock *bblock, unsigned char *ip)
 {
-       /* there's no restriction to call Transparent or SafeCritical code, so we only check calls to Critical methods */
-       if (mono_security_core_clr_method_level (callee, TRUE) != MONO_SECURITY_CORE_CLR_CRITICAL)
-               return;
-
        /* we can't get the coreclr security level on wrappers since they don't have the attributes */
-       caller = get_original_method (caller);
-       if (!caller)
-               return;
-
-       /* caller is Critical! only SafeCritical and Critical callers can call it, so we throw if the caller is Transparent */
-       if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
-               emit_throw_exception (cfg, mono_get_exception_method_access ());
+       MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
+       if (ex)
+               emit_throw_exception (cfg, ex);
 }
 
 /*
@@ -4781,464 +4954,72 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
 #endif
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
-                       size = 8; break;
-#endif
-               default:
-                       return NULL;
-               }
-               size *= len;
-               if (size > mono_type_size (field->type, &dummy_align))
-                   return NULL;
-               *out_size = size;
-               /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
-               if (!method->klass->image->dynamic) {
-                       field_index = read32 (ip + 2) & 0xffffff;
-                       mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
-                       data_ptr = mono_image_rva_map (method->klass->image, rva);
-                       /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
-                       /* for aot code we do the lookup on load */
-                       if (aot && data_ptr)
-                               return GUINT_TO_POINTER (rva);
-               } else {
-                       /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
-                       g_assert (!aot);
-                       data_ptr = mono_field_get_data (field);
-               }
-               return data_ptr;
-       }
-       return NULL;
-}
-
-static void
-set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
-{
-       char *method_fname = mono_method_full_name (method, TRUE);
-       char *method_code;
-
-       if (mono_method_get_header (method)->code_size == 0)
-               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;
-       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);
-}
-
-static void
-set_exception_object (MonoCompile *cfg, MonoException *exception)
-{
-       cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
-       MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
-       cfg->exception_ptr = exception;
-}
-
-static gboolean
-generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
-{
-       MonoType *type;
-
-       if (cfg->generic_sharing_context)
-               type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
-       else
-               type = &klass->byval_arg;
-       return MONO_TYPE_IS_REFERENCE (type);
-}
-
-/**
- * mono_decompose_array_access_opts:
- *
- *  Decompose array access opcodes.
- * This should be in decompose.c, but it emits calls so it has to stay here until
- * the old JIT is gone.
- */
-void
-mono_decompose_array_access_opts (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb, *first_bb;
-
-       /*
-        * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it 
-        * can be executed anytime. It should be run before decompose_long
-        */
-
-       /**
-        * Create a dummy bblock and emit code into it so we can use the normal 
-        * code generation macros.
-        */
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-       first_bb = cfg->cbb;
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MonoInst *prev = NULL;
-               MonoInst *dest;
-               MonoInst *iargs [3];
-               gboolean restart;
-
-               if (!bb->has_array_access)
-                       continue;
-
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
-
-               cfg->cbb->code = cfg->cbb->last_ins = NULL;
-               restart = TRUE;
-
-               while (restart) {
-                       restart = FALSE;
-
-                       for (ins = bb->code; ins; ins = ins->next) {
-                               switch (ins->opcode) {
-                               case OP_LDLEN:
-                                       NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
-                                                                         G_STRUCT_OFFSET (MonoArray, max_length));
-                                       MONO_ADD_INS (cfg->cbb, dest);
-                                       break;
-                               case OP_BOUNDS_CHECK:
-                                       MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
-                                       break;
-                               case OP_NEWARR:
-                                       if (cfg->opt & MONO_OPT_SHARED) {
-                                               EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
-                                               EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
-                                               MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
-                                               iargs [2]->dreg = ins->sreg1;
-
-                                               dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
-                                               dest->dreg = ins->dreg;
-                                       } else {
-                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
-                                               MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
-
-                                               g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
-                                               NEW_VTABLECONST (cfg, iargs [0], vtable);
-                                               MONO_ADD_INS (cfg->cbb, iargs [0]);
-                                               MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
-                                               iargs [1]->dreg = ins->sreg1;
-
-                                               if (managed_alloc)
-                                                       dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
-                                               else
-                                                       dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
-                                               dest->dreg = ins->dreg;
-                                       }
-                                       break;
-                               case OP_STRLEN:
-                                       NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg,
-                                                                         ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
-                                       MONO_ADD_INS (cfg->cbb, dest);
-                                       break;
-                               default:
-                                       break;
-                               }
-
-                               g_assert (cfg->cbb == first_bb);
-
-                               if (cfg->cbb->code || (cfg->cbb != first_bb)) {
-                                       /* Replace the original instruction with the new code sequence */
-
-                                       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-                                       first_bb->code = first_bb->last_ins = NULL;
-                                       first_bb->in_count = first_bb->out_count = 0;
-                                       cfg->cbb = first_bb;
-                               }
-                               else
-                                       prev = ins;
-                       }
-               }
-
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
-       }
-}
-
-typedef union {
-       guint32 vali [2];
-       gint64 vall;
-       double vald;
-} DVal;
-
-#ifdef MONO_ARCH_SOFT_FLOAT
-
-/**
- * mono_decompose_soft_float:
- *
- *  Soft float support on ARM. We store each double value in a pair of integer vregs,
- * similar to long support on 32 bit platforms. 32 bit float values require special
- * handling when used as locals, arguments, and in calls.
- * One big problem with soft-float is that there are few r4 test cases in our test suite.
- */
-void
-mono_decompose_soft_float (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb, *first_bb;
-
-       /*
-        * This pass creates long opcodes, so it should be run before decompose_long_opts ().
-        */
-
-       /**
-        * Create a dummy bblock and emit code into it so we can use the normal 
-        * code generation macros.
-        */
-       cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-       first_bb = cfg->cbb;
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *ins;
-               MonoInst *prev = NULL;
-               gboolean restart;
-
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
-
-               cfg->cbb->code = cfg->cbb->last_ins = NULL;
-               restart = TRUE;
-
-               while (restart) {
-                       restart = FALSE;
-
-                       for (ins = bb->code; ins; ins = ins->next) {
-                               const char *spec = INS_INFO (ins->opcode);
-
-                               /* Most fp operations are handled automatically by opcode emulation */
-
-                               switch (ins->opcode) {
-                               case OP_R8CONST: {
-                                       DVal d;
-                                       d.vald = *(double*)ins->inst_p0;
-                                       MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
-                                       break;
-                               }
-                               case OP_R4CONST: {
-                                       DVal d;
-                                       /* We load the r8 value */
-                                       d.vald = *(float*)ins->inst_p0;
-                                       MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
-                                       break;
-                               }
-                               case OP_FMOVE:
-                                       ins->opcode = OP_LMOVE;
-                                       break;
-                               case OP_FGETLOW32:
-                                       ins->opcode = OP_MOVE;
-                                       ins->sreg1 = ins->sreg1 + 1;
-                                       break;
-                               case OP_FGETHIGH32:
-                                       ins->opcode = OP_MOVE;
-                                       ins->sreg1 = ins->sreg1 + 2;
-                                       break;
-                               case OP_SETFRET: {
-                                       int reg = ins->sreg1;
-
-                                       ins->opcode = OP_SETLRET;
-                                       ins->dreg = -1;
-                                       ins->sreg1 = reg + 1;
-                                       ins->sreg2 = reg + 2;
-                                       break;
-                               }
-                               case OP_LOADR8_MEMBASE:
-                                       ins->opcode = OP_LOADI8_MEMBASE;
-                                       break;
-                               case OP_STORER8_MEMBASE_REG:
-                                       ins->opcode = OP_STOREI8_MEMBASE_REG;
-                                       break;
-                               case OP_STORER4_MEMBASE_REG: {
-                                       MonoInst *iargs [2];
-                                       int addr_reg;
-
-                                       /* Arg 1 is the double value */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-
-                                       /* Arg 2 is the address to store to */
-                                       addr_reg = mono_alloc_preg (cfg);
-                                       EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
-                                       mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
-                                       restart = TRUE;
-                                       break;
-                               }
-                               case OP_LOADR4_MEMBASE: {
-                                       MonoInst *iargs [1];
-                                       MonoInst *conv;
-                                       int addr_reg;
-
-                                       addr_reg = mono_alloc_preg (cfg);
-                                       EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
-                                       conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
-                                       conv->dreg = ins->dreg;
-                                       break;
-                               }                                       
-                               case OP_FCALL:
-                               case OP_FCALL_REG:
-                               case OP_FCALL_MEMBASE: {
-                                       MonoCallInst *call = (MonoCallInst*)ins;
-                                       if (call->signature->ret->type == MONO_TYPE_R4) {
-                                               MonoCallInst *call2;
-                                               MonoInst *iargs [1];
-                                               MonoInst *conv;
-
-                                               /* Convert the call into a call returning an int */
-                                               MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
-                                               memcpy (call2, call, sizeof (MonoCallInst));
-                                               switch (ins->opcode) {
-                                               case OP_FCALL:
-                                                       call2->inst.opcode = OP_CALL;
-                                                       break;
-                                               case OP_FCALL_REG:
-                                                       call2->inst.opcode = OP_CALL_REG;
-                                                       break;
-                                               case OP_FCALL_MEMBASE:
-                                                       call2->inst.opcode = OP_CALL_MEMBASE;
-                                                       break;
-                                               default:
-                                                       g_assert_not_reached ();
-                                               }
-                                               call2->inst.dreg = mono_alloc_ireg (cfg);
-                                               MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
-
-                                               /* FIXME: Optimize this */
-
-                                               /* Emit an r4->r8 conversion */
-                                               EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
-                                               conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
-                                               conv->dreg = ins->dreg;
-                                       } else {
-                                               switch (ins->opcode) {
-                                               case OP_FCALL:
-                                                       ins->opcode = OP_LCALL;
-                                                       break;
-                                               case OP_FCALL_REG:
-                                                       ins->opcode = OP_LCALL_REG;
-                                                       break;
-                                               case OP_FCALL_MEMBASE:
-                                                       ins->opcode = OP_LCALL_MEMBASE;
-                                                       break;
-                                               default:
-                                                       g_assert_not_reached ();
-                                               }
-                                       }
-                                       break;
-                               }
-                               case OP_FCOMPARE: {
-                                       MonoJitICallInfo *info;
-                                       MonoInst *iargs [2];
-                                       MonoInst *call, *cmp, *br;
-
-                                       /* Convert fcompare+fbcc to icall+icompare+beq */
-
-                                       info = mono_find_jit_opcode_emulation (ins->next->opcode);
-                                       g_assert (info);
-
-                                       /* Create dummy MonoInst's for the arguments */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-                                       MONO_INST_NEW (cfg, iargs [1], OP_ARG);
-                                       iargs [1]->dreg = ins->sreg2;
-
-                                       call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
-
-                                       MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
-                                       cmp->sreg1 = call->dreg;
-                                       cmp->inst_imm = 0;
-                                       MONO_ADD_INS (cfg->cbb, cmp);
-                                       
-                                       MONO_INST_NEW (cfg, br, OP_IBNE_UN);
-                                       br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
-                                       br->inst_true_bb = ins->next->inst_true_bb;
-                                       br->inst_false_bb = ins->next->inst_false_bb;
-                                       MONO_ADD_INS (cfg->cbb, br);
-
-                                       /* The call sequence might include fp ins */
-                                       restart = TRUE;
-
-                                       /* Skip fbcc or fccc */
-                                       NULLIFY_INS (ins->next);
-                                       break;
-                               }
-                               case OP_FCEQ:
-                               case OP_FCGT:
-                               case OP_FCGT_UN:
-                               case OP_FCLT:
-                               case OP_FCLT_UN: {
-                                       MonoJitICallInfo *info;
-                                       MonoInst *iargs [2];
-                                       MonoInst *call;
-
-                                       /* Convert fccc to icall+icompare+iceq */
-
-                                       info = mono_find_jit_opcode_emulation (ins->opcode);
-                                       g_assert (info);
-
-                                       /* Create dummy MonoInst's for the arguments */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-                                       MONO_INST_NEW (cfg, iargs [1], OP_ARG);
-                                       iargs [1]->dreg = ins->sreg2;
-
-                                       call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
-
-                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
-
-                                       /* The call sequence might include fp ins */
-                                       restart = TRUE;
-                                       break;
-                               }
-                               case OP_CKFINITE: {
-                                       MonoInst *iargs [2];
-                                       MonoInst *call, *cmp;
-
-                                       /* Convert to icall+icompare+cond_exc+move */
-
-                                       /* Create dummy MonoInst's for the arguments */
-                                       MONO_INST_NEW (cfg, iargs [0], OP_ARG);
-                                       iargs [0]->dreg = ins->sreg1;
-
-                                       call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
-
-                                       MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
-                                       cmp->sreg1 = call->dreg;
-                                       cmp->inst_imm = 1;
-                                       MONO_ADD_INS (cfg->cbb, cmp);
-
-                                       MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
-
-                                       /* Do the assignment if the value is finite */
-                                       MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
-
-                                       restart = TRUE;
-                                       break;
-                               }
-                               default:
-                                       if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
-                                               mono_print_ins (ins);
-                                               g_assert_not_reached ();
-                                       }
-                                       break;
-                               }
+                       size = 8; break;
+#endif
+               default:
+                       return NULL;
+               }
+               size *= len;
+               if (size > mono_type_size (field->type, &dummy_align))
+                   return NULL;
+               *out_size = size;
+               /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
+               if (!method->klass->image->dynamic) {
+                       field_index = read32 (ip + 2) & 0xffffff;
+                       mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
+                       data_ptr = mono_image_rva_map (method->klass->image, rva);
+                       /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
+                       /* for aot code we do the lookup on load */
+                       if (aot && data_ptr)
+                               return GUINT_TO_POINTER (rva);
+               } else {
+                       /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
+                       g_assert (!aot);
+                       data_ptr = mono_field_get_data (field);
+               }
+               return data_ptr;
+       }
+       return NULL;
+}
 
-                               g_assert (cfg->cbb == first_bb);
+static void
+set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
+{
+       char *method_fname = mono_method_full_name (method, TRUE);
+       char *method_code;
+       MonoMethodHeader *header = mono_method_get_header (method);
 
-                               if (cfg->cbb->code || (cfg->cbb != first_bb)) {
-                                       /* Replace the original instruction with the new code sequence */
+       if (header->code_size == 0)
+               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;
+       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);
+       mono_metadata_free_mh (header);
+}
 
-                                       mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
-                                       first_bb->code = first_bb->last_ins = NULL;
-                                       first_bb->in_count = first_bb->out_count = 0;
-                                       cfg->cbb = first_bb;
-                               }
-                               else
-                                       prev = ins;
-                       }
-               }
+static void
+set_exception_object (MonoCompile *cfg, MonoException *exception)
+{
+       cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
+       MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
+       cfg->exception_ptr = exception;
+}
 
-               if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
-       }
+static gboolean
+generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
+{
+       MonoType *type;
 
-       mono_decompose_long_opts (cfg);
+       if (cfg->generic_sharing_context)
+               type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
+       else
+               type = &klass->byval_arg;
+       return MONO_TYPE_IS_REFERENCE (type);
 }
 
-#endif
-
 static void
 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
 {
@@ -5320,8 +5101,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                   MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
                   guint inline_offset, gboolean is_virtual_call)
 {
+       MonoError error;
        MonoInst *ins, **sp, **stack_start;
        MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
+       MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
        MonoMethod *cmethod, *method_definition;
        MonoInst **arg_array;
        MonoMethodHeader *header;
@@ -5345,7 +5128,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        GSList *class_inits = NULL;
        gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
        int context_used;
-       gboolean init_locals;
+       gboolean init_locals, seq_points, skip_dead_blocks;
 
        /* serialization and xdomain stuff may need access to private fields and methods */
        dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
@@ -5373,6 +5156,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        mono_jit_stats.cil_code_size += header->code_size;
        init_locals = header->init_locals;
 
+       seq_points = cfg->gen_seq_points && cfg->method == method;
+
        /* 
         * Methods without init_locals set could cause asserts in various passes
         * (#497220).
@@ -5720,9 +5505,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                NEW_ARGLOAD (cfg, arg_ins, 0);
                MONO_ADD_INS (cfg->cbb, arg_ins);
-               cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
-               MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, arg_ins->dreg);
-               MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, arg_ins->dreg);
+               MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
+       }
+
+       skip_dead_blocks = !dont_verify;
+       if (skip_dead_blocks) {
+               original_bb = bb = mono_basic_block_split (method, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_cleanup (&error);
+                       UNVERIFIED;
+               }
+               g_assert (bb);
        }
 
        /* we use a spare stack slot in SWITCH and NEWOBJ and others */
@@ -5732,7 +5525,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        start_new_bblock = 0;
        cfg->cbb = bblock;
        while (ip < end) {
-
                if (cfg->method == method)
                        cfg->real_offset = ip - header->code;
                else
@@ -5783,6 +5575,38 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                }
 
+               if (skip_dead_blocks) {
+                       int ip_offset = ip - header->code;
+
+                       if (ip_offset == bb->end)
+                               bb = bb->next;
+
+                       if (bb->dead) {
+                               int op_size = mono_opcode_size (ip, end);
+                               g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
+
+                               if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
+
+                               if (ip_offset + op_size == bb->end) {
+                                       MONO_INST_NEW (cfg, ins, OP_NOP);
+                                       MONO_ADD_INS (bblock, ins);
+                                       start_new_bblock = 1;
+                               }
+
+                               ip += op_size;
+                               continue;
+                       }
+               }
+               /*
+                * Sequence points are points where the debugger can place a breakpoint.
+                * Currently, we generate these automatically at points where the IL
+                * stack is empty.
+                */
+               if (seq_points && sp == stack_start) {
+                       NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
+                       MONO_ADD_INS (cfg->cbb, ins);
+               }
+
                bblock->real_offset = cfg->real_offset;
 
                if ((cfg->method == method) && cfg->coverage_info) {
@@ -5814,7 +5638,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_ADD_INS (bblock, ins);
                        break;
                case CEE_BREAK:
-                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       if (should_insert_brekpoint (cfg->method))
+                               MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       else
+                               MONO_INST_NEW (cfg, ins, OP_NOP);
                        ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
@@ -6167,6 +5994,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        fsig = mono_metadata_parse_signature (image, token);
 
                                n = fsig->param_count + fsig->hasthis;
+
+                               if (method->dynamic && fsig->pinvoke) {
+                                       MonoInst *args [3];
+
+                                       /*
+                                        * This is a call through a function pointer using a pinvoke
+                                        * signature. Have to create a wrapper and call that instead.
+                                        * FIXME: This is very slow, need to create a wrapper at JIT time
+                                        * instead based on the signature.
+                                        */
+                                       EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
+                                       EMIT_NEW_PCONST (cfg, args [1], fsig);
+                                       args [2] = addr;
+                                       addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
+                               }
                        } else {
                                MonoMethod *cil_method;
                                
@@ -6211,6 +6053,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        /* MS.NET seems to silently convert this to a callvirt */
                                        virtual = 1;
 
+                               {
+                                       /*
+                                        * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
+                                        * converts to a callvirt.
+                                        *
+                                        * tests/bug-515884.il is an example of this behavior
+                                        */
+                                       const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
+                                       const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
+                                       if (!virtual && cmethod->klass->marshalbyref && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
+                                               virtual = 1;
+                               }
+
                                if (!cmethod->klass->inited)
                                        if (!mono_class_init (cmethod->klass))
                                                goto load_error;
@@ -6220,7 +6075,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        array_rank = cmethod->klass->rank;
                                        fsig = mono_method_signature (cmethod);
                                } else {
-                                       if (mono_method_signature (cmethod)->pinvoke) {
+                                       fsig = mono_method_signature (cmethod);
+
+                                       if (!fsig)
+                                               goto load_error;
+
+                                       if (fsig->pinvoke) {
                                                MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
                                                        check_for_pending_exc, FALSE);
                                                fsig = mono_method_signature (wrapper);
@@ -6262,17 +6122,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * We have the `constrained.' prefix opcode.
                                 */
                                if (constrained_call->valuetype && !cmethod->klass->valuetype) {
-                                       int dreg;
-
                                        /*
                                         * The type parameter is instantiated as a valuetype,
                                         * but that type doesn't override the method we're
                                         * calling, so we need to box `this'.
                                         */
-                                       dreg = alloc_dreg (cfg, STACK_VTYPE);
-                                       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADV_MEMBASE, dreg, sp [0]->dreg, 0);
+                                       EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
                                        ins->klass = constrained_call;
-                                       sp [0] = handle_box (cfg, ins, constrained_call);
+                                       sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
                                        CHECK_CFG_EXCEPTION;
                                } else if (!constrained_call->valuetype) {
                                        int dreg = alloc_preg (cfg);
@@ -6376,12 +6233,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (pass_mrgctx) {
                                g_assert (!vtable_arg);
 
-                               if (context_used) {
-                                       vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
-                               } else {
-                                       EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
+                               if (!cfg->compile_aot) {
+                                       /* 
+                                        * emit_get_rgctx_method () calls mono_class_vtable () so check 
+                                        * for type load errors before.
+                                        */
+                                       mono_class_setup_vtable (cmethod->klass);
+                                       CHECK_TYPELOAD (cmethod->klass);
                                }
 
+                               vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
+
                                if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
                                                MONO_METHOD_IS_FINAL (cmethod)) {
                                        if (virtual)
@@ -6398,13 +6260,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod, MONO_RGCTX_INFO_METHOD);
                        }
 
-                       if (check_this) {
-                               MonoInst *check;
-
-                               MONO_INST_NEW (cfg, check, OP_CHECK_THIS);
-                               check->sreg1 = sp [0]->dreg;
-                               MONO_ADD_INS (cfg->cbb, check);
-                       }
+                       if (check_this)
+                               MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
 
                        /* Calling virtual generic methods */
                        if (cmethod && virtual && 
@@ -6420,17 +6277,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* Prevent inlining of methods that contain indirect calls */
                                INLINE_FAILURE;
 
-#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && !defined(ENABLE_LLVM)
-                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
+#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
+                               /* The llvm vcall trampolines doesn't support generic virtual calls yet */
+                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt && !mono_use_llvm) {
                                        g_assert (!imt_arg);
-                                       if (context_used) {
-                                               imt_arg = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD);
-
-                                       } else {
+                                       if (!context_used)
                                                g_assert (cmethod->is_inflated);
-                                               EMIT_NEW_METHODCONST (cfg, imt_arg, cmethod);
-                                       }
+                                       imt_arg = emit_get_rgctx_method (cfg, context_used,
+                                                                                                        cmethod, MONO_RGCTX_INFO_METHOD);
                                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg);
                                } else
 #endif
@@ -6443,17 +6297,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
                                        EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
-                                       if (context_used) {
-                                               iargs [1] = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD);
-                                               EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
-                                               addr = mono_emit_jit_icall (cfg,
-                                                               mono_helper_compile_generic_method, iargs);
-                                       } else {
-                                               EMIT_NEW_METHODCONST (cfg, iargs [1], cmethod);
-                                               EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
-                                               addr = mono_emit_jit_icall (cfg, mono_helper_compile_generic_method, iargs);
-                                       }
+                                       iargs [1] = emit_get_rgctx_method (cfg, context_used,
+                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
+                                       EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
+                                       addr = mono_emit_jit_icall (cfg,
+                                                                                               mono_helper_compile_generic_method, iargs);
 
                                        EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
 
@@ -6463,6 +6311,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (!MONO_TYPE_IS_VOID (fsig->ret))
                                        *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
+                               CHECK_CFG_EXCEPTION;
+
                                ip += 5;
                                ins_flag = 0;
                                break;
@@ -6509,6 +6359,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (bblock, ins);
                                link_bblock (cfg, bblock, end_bblock);                  
                                start_new_bblock = 1;
+
+                               CHECK_CFG_EXCEPTION;
+
                                /* skip CEE_RET as well */
                                ip += 6;
                                ins_flag = 0;
@@ -6523,6 +6376,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        sp++;
                                }
 
+                               CHECK_CFG_EXCEPTION;
+
                                ip += 5;
                                ins_flag = 0;
                                break;
@@ -6667,6 +6522,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (!MONO_TYPE_IS_VOID (fsig->ret))
                                        *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
+                               CHECK_CFG_EXCEPTION;
+
                                ip += 5;
                                ins_flag = 0;
                                break;
@@ -6706,6 +6563,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        g_assert_not_reached ();
                                }
 
+                               CHECK_CFG_EXCEPTION;
+
                                ip += 5;
                                ins_flag = 0;
                                break;
@@ -6716,6 +6575,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (!MONO_TYPE_IS_VOID (fsig->ret))
                                        *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
+                               CHECK_CFG_EXCEPTION;
+
                                ip += 5;
                                ins_flag = 0;
                                break;
@@ -6735,6 +6596,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!MONO_TYPE_IS_VOID (fsig->ret))
                                *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 
+                       CHECK_CFG_EXCEPTION;
+
                        ip += 5;
                        ins_flag = 0;
                        break;
@@ -6760,6 +6623,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (cfg->ret) {
                                        MonoType *ret_type = mono_method_signature (method)->ret;
 
+                                       if (seq_points) {
+                                               /* 
+                                                * Place a seq point here too even through the IL stack is not
+                                                * empty, so a step over on
+                                                * call <FOO>
+                                                * ret
+                                                * will work correctly.
+                                                */
+                                               NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
+                                               MONO_ADD_INS (cfg->cbb, ins);
+                                       }
+
                                        g_assert (!return_var);
                                        CHECK_STACK (1);
                                        --sp;
@@ -6778,7 +6653,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                }
                                        } else {
 #ifdef MONO_ARCH_SOFT_FLOAT
-                                               if (!ret_type->byref && ret_type->type == MONO_TYPE_R4) {
+                                               if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
                                                        MonoInst *iargs [1];
                                                        MonoInst *conv;
 
@@ -7107,9 +6982,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
 #if HAVE_WRITE_BARRIERS
                        if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
+                               MonoInst *dummy_use;
                                /* insert call to write barrier */
                                MonoMethod *write_barrier = mono_gc_get_write_barrier ();
                                mono_emit_method_call (cfg, write_barrier, sp, NULL);
+                               EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
                        }
 #endif
 
@@ -7186,7 +7063,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 #endif
                                        }
                                        else
-                                               ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
+                                               ins->inst_imm = (gssize)(sp [1]->inst_c0);
                                        ins->sreg2 = -1;
 
                                        /* Might be followed by an instruction added by ADD_WIDEN_OP */
@@ -7282,6 +7159,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_CONV_U:
                        CHECK_STACK (1);
                        ADD_UNOP (*ip);
+                       CHECK_CFG_EXCEPTION;
                        ip++;
                        break;
                case CEE_ADD_OVF:
@@ -7455,6 +7333,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!cmethod)
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
+                       if (!fsig)
+                               goto load_error;
 
                        mono_save_token_info (cfg, image, token, cmethod);
 
@@ -7475,12 +7355,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
                                        mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
                                if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
-                                       if (context_used) {
-                                               vtable_arg = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
-                                       } else {
-                                               EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
-                                       }
+                                       mono_class_vtable (cfg->domain, cmethod->klass);
+                                       CHECK_TYPELOAD (cmethod->klass);
+
+                                       vtable_arg = emit_get_rgctx_method (cfg, context_used,
+                                                                                                               cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
                                } else {
                                        if (context_used) {
                                                vtable_arg = emit_get_rgctx_klass (cfg, context_used,
@@ -7551,18 +7430,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mini_class_is_system_array (cmethod->klass)) {
                                g_assert (!vtable_arg);
 
-                               if (context_used) {
-                                       *sp = emit_get_rgctx_method (cfg, context_used,
-                                               cmethod, MONO_RGCTX_INFO_METHOD);
-                               } else {
-                                       EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
-                               }
+                               *sp = emit_get_rgctx_method (cfg, context_used,
+                                                                                        cmethod, MONO_RGCTX_INFO_METHOD);
 
                                /* Avoid varargs in the common case */
                                if (fsig->param_count == 1)
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
                                else if (fsig->param_count == 2)
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
+                               else if (fsig->param_count == 3)
+                                       alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
                                else
                                        alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
                        } else if (cmethod->string_ctor) {
@@ -7588,16 +7465,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         * will be transformed into a normal call there.
                                         */
                                } else if (context_used) {
-                                       MonoInst *data;
-                                       int rgctx_info;
-
-                                       if (cfg->opt & MONO_OPT_SHARED)
-                                               rgctx_info = MONO_RGCTX_INFO_KLASS;
-                                       else
-                                               rgctx_info = MONO_RGCTX_INFO_VTABLE;
-                                       data = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, rgctx_info);
-
-                                       alloc = handle_alloc_from_inst (cfg, cmethod->klass, data, FALSE);
+                                       alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
                                        *sp = alloc;
                                } else {
                                        MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
@@ -7616,7 +7484,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                class_inits = g_slist_prepend (class_inits, vtable);
                                        }
 
-                                       alloc = handle_alloc (cfg, cmethod->klass, FALSE);
+                                       alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
                                        *sp = alloc;
                                }
                                CHECK_CFG_EXCEPTION; /*for handle_alloc*/
@@ -7686,21 +7554,20 @@ 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) {
+                       if (!context_used && mono_class_has_variant_generic_params (klass)) {
                                MonoInst *args [2];
 
                                /* obj */
                                args [0] = *sp;
 
                                /* klass */
-                               args [1] = emit_get_rgctx_klass (cfg, context_used,
-                                       klass, MONO_RGCTX_INFO_KLASS);
+                               EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 
                                ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
                                *sp ++ = ins;
                                ip += 5;
                                inline_costs += 2;
-                       } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                       } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                MonoMethod *mono_castclass;
                                MonoInst *iargs [1];
                                int costs;
@@ -7721,7 +7588,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                inline_costs += costs;
                        }
                        else {
-                               ins = handle_castclass (cfg, klass, *sp);
+                               ins = handle_castclass (cfg, klass, *sp, context_used);
                                CHECK_CFG_EXCEPTION;
                                bblock = cfg->cbb;
                                *sp ++ = ins;
@@ -7741,20 +7608,20 @@ 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) {
+                       if (!context_used && mono_class_has_variant_generic_params (klass)) {
                                MonoInst *args [2];
 
                                /* obj */
                                args [0] = *sp;
 
                                /* klass */
-                               args [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 
                                *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
                                sp++;
                                ip += 5;
                                inline_costs += 2;
-                       } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                    
+                       } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
                                MonoMethod *mono_isinst;
                                MonoInst *iargs [1];
                                int costs;
@@ -7775,7 +7642,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                inline_costs += costs;
                        }
                        else {
-                               ins = handle_isinst (cfg, klass, *sp);
+                               ins = handle_isinst (cfg, klass, *sp, context_used);
                                CHECK_CFG_EXCEPTION;
                                bblock = cfg->cbb;
                                *sp ++ = ins;
@@ -7829,7 +7696,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        *sp++ = iargs [0];
                                        inline_costs += costs;
                                } else {
-                                       ins = handle_castclass (cfg, klass, *sp);
+                                       ins = handle_castclass (cfg, klass, *sp, 0);
                                        CHECK_CFG_EXCEPTION;
                                        bblock = cfg->cbb;
                                        *sp ++ = ins;
@@ -7923,19 +7790,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
-                       if (context_used) {
-                               MonoInst *data;
-                               int rgctx_info;
-
-                               if (cfg->opt & MONO_OPT_SHARED)
-                                       rgctx_info = MONO_RGCTX_INFO_KLASS;
-                               else
-                                       rgctx_info = MONO_RGCTX_INFO_VTABLE;
-                               data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
-                               *sp++ = handle_box_from_inst (cfg, val, klass, context_used, data);
-                       } else {
-                               *sp++ = handle_box (cfg, val, klass);
-                       }
+                       *sp++ = handle_box (cfg, val, klass, context_used);
 
                        CHECK_CFG_EXCEPTION;
                        ip += 5;
@@ -8024,7 +7879,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                    field->offset);
                                        iargs [4] = sp [1];
 
-                                       if (cfg->opt & MONO_OPT_INLINE) {
+                                       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);
                                                g_assert (costs > 0);
@@ -8039,19 +7894,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        MonoInst *store;
 
+                                       MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
 
 #if HAVE_WRITE_BARRIERS
                                if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
                                        /* insert call to write barrier */
                                        MonoMethod *write_barrier = mono_gc_get_write_barrier ();
-                                       MonoInst *iargs [2];
+                                       MonoInst *iargs [2], *dummy_use;
                                        int dreg;
 
                                        dreg = alloc_preg (cfg);
                                        EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
                                        iargs [1] = sp [1];
                                        mono_emit_method_call (cfg, write_barrier, iargs, NULL);
+
+                                       EMIT_NEW_DUMMY_USE (cfg, dummy_use, sp [1]);
                                }
 #endif
 
@@ -8101,6 +7960,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        sp [0] = ins;
                                }
 
+                               MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
+
                                if (*ip == CEE_LDFLDA) {
                                        dreg = alloc_preg (cfg);
 
@@ -8113,6 +7974,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
                                        load->flags |= ins_flag;
+                                       load->flags |= MONO_INST_FAULT;
                                        *sp++ = load;
                                }
                        }
@@ -8176,8 +8038,53 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        is_special_static = mono_class_field_is_special_static (field);
 
                        /* Generate IR to compute the field address */
+                       if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
+                               /*
+                                * Fast access to TLS data
+                                * Inline version of get_thread_static_data () in
+                                * threads.c.
+                                */
+                               guint32 offset;
+                               int idx, static_data_reg, array_reg, dreg;
+                               MonoInst *thread_ins;
+
+                               // offset &= 0x7fffffff;
+                               // idx = (offset >> 24) - 1;
+                               //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
 
-                       if ((cfg->opt & MONO_OPT_SHARED) ||
+                               thread_ins = mono_get_thread_intrinsic (cfg);
+                               MONO_ADD_INS (cfg->cbb, thread_ins);
+                               static_data_reg = alloc_ireg (cfg);
+                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
+
+                               if (cfg->compile_aot) {
+                                       int offset_reg, offset2_reg, idx_reg;
+
+                                       /* For TLS variables, this will return the TLS offset */
+                                       EMIT_NEW_SFLDACONST (cfg, ins, field);
+                                       offset_reg = ins->dreg;
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
+                                       idx_reg = alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
+                                       MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
+                                       array_reg = alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
+                                       offset2_reg = alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
+                                       dreg = alloc_ireg (cfg);
+                                       EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
+                               } else {
+                                       offset = (gsize)addr & 0x7fffffff;
+                                       idx = (offset >> 24) - 1;
+
+                                       array_reg = alloc_ireg (cfg);
+                                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
+                                       dreg = alloc_ireg (cfg);
+                                       EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
+                               }
+                       } else if ((cfg->opt & MONO_OPT_SHARED) ||
                                        (cfg->compile_aot && is_special_static) ||
                                        (context_used && is_special_static)) {
                                MonoInst *iargs [2];
@@ -8276,11 +8183,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        else
                                                EMIT_NEW_PCONST (cfg, ins, addr);
                                } else {
-                                       /* 
-                                        * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
-                                        * This could be later optimized to do just a couple of
-                                        * memory dereferences with constant offsets.
-                                        */
                                        MonoInst *iargs [1];
                                        EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
                                        ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
@@ -8345,21 +8247,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
                                                sp++;
                                                break;
-#ifndef HAVE_MOVING_COLLECTOR
                                        case MONO_TYPE_I:
                                        case MONO_TYPE_U:
+                                       case MONO_TYPE_PTR:
+                                       case MONO_TYPE_FNPTR:
+#ifndef HAVE_MOVING_COLLECTOR
                                        case MONO_TYPE_STRING:
                                        case MONO_TYPE_OBJECT:
                                        case MONO_TYPE_CLASS:
                                        case MONO_TYPE_SZARRAY:
-                                       case MONO_TYPE_PTR:
-                                       case MONO_TYPE_FNPTR:
                                        case MONO_TYPE_ARRAY:
+#endif
                                                EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
                                                type_to_eval_stack_type ((cfg), field->type, *sp);
                                                sp++;
                                                break;
-#endif
                                        case MONO_TYPE_I8:
                                        case MONO_TYPE_U8:
                                                EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
@@ -8436,8 +8338,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (context_used) {
                                MonoInst *args [3];
                                MonoClass *array_class = mono_array_class_get (klass, 1);
+                               /* FIXME: we cannot get a managed
+                                  allocator because we can't get the
+                                  open generic class's vtable.  We
+                                  have the same problem in
+                                  handle_alloc().  This
+                                  needs to be solved so that we can
+                                  have managed allocs of shared
+                                  generic classes. */
+                               /*
                                MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
                                MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
+                               */
+                               MonoMethod *managed_alloc = NULL;
 
                                /* FIXME: Decompose later to help abcrem */
 
@@ -8550,7 +8463,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        readonly = FALSE;
-                       ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
+                       ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
                        *sp++ = ins;
                        ip += 5;
                        break;
@@ -8594,7 +8507,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
                                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
                        } else {
-                               addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
+                               addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
                                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
                        }
                        *sp++ = ins;
@@ -8658,7 +8571,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
                                } else {
-                                       addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
+                                       addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
                                }
                        }
@@ -8961,6 +8874,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* 
                         * If this leave statement is in a catch block, check for a
                         * pending exception, and rethrow it if necessary.
+                        * We avoid doing this in runtime invoke wrappers, since those are called
+                        * by native code which excepts the wrapper to catch all exceptions.
                         */
                        for (i = 0; i < header->num_clauses; ++i) {
                                MonoExceptionClause *clause = &header->clauses [i];
@@ -8971,7 +8886,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 * The ordering of the exception clauses guarantees that we find the
                                 * innermost clause.
                                 */
-                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
+                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len) && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
                                        MonoInst *exc_ins;
                                        MonoBasicBlock *dont_throw;
 
@@ -9002,13 +8917,29 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
                                GList *tmp;
+                               MonoExceptionClause *clause;
+
                                for (tmp = handlers; tmp; tmp = tmp->next) {
-                                       tblock = tmp->data;
+                                       clause = tmp->data;
+                                       tblock = cfg->cil_offset_to_bb [clause->handler_offset];
+                                       g_assert (tblock);
                                        link_bblock (cfg, bblock, tblock);
                                        MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
                                        ins->inst_target_bb = tblock;
+                                       ins->inst_eh_block = clause;
                                        MONO_ADD_INS (bblock, ins);
                                        bblock->has_call_handler = 1;
+                                       if (COMPILE_LLVM (cfg)) {
+                                               MonoBasicBlock *target_bb;
+
+                                               /* 
+                                                * Link the finally bblock with the target, since it will
+                                                * conceptually branch there.
+                                                * FIXME: Have to link the bblock containing the endfinally.
+                                                */
+                                               GET_BBLOCK (cfg, target_bb, target);
+                                               link_bblock (cfg, tblock, target_bb);
+                                       }
                                }
                                g_list_free (handlers);
                        } 
@@ -9414,39 +9345,40 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* 
                                 * Optimize the common case of ldftn+delegate creation
                                 */
-#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
-                               /* FIXME: SGEN support */
-                               /* FIXME: handle shared static generic methods */
-                               /* FIXME: handle this in shared code */
-                               if (!needs_static_rgctx_invoke && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
+                               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;
 
-                                               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);
-                                               CHECK_CFG_EXCEPTION;
-                                               ip += 5;                        
-                                               sp ++;
-                                               break;
+                                               if (cfg->generic_sharing_context)
+                                                       invoke_context_used = mono_method_check_context_used (invoke);
+
+#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
+                                               /* FIXME: SGEN support */
+                                               if (invoke_context_used == 0) {
+                                                       MonoInst *target_ins;
+
+                                                       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;
+                                                       ip += 5;                        
+                                                       sp ++;
+                                                       break;
+                                               }
+#endif
                                        }
                                }
-#endif
 
-                               if (context_used) {
-                                       argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
-                               } else {
-                                       EMIT_NEW_METHODCONST (cfg, argconst, cmethod);
-                               }
+                               argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
                                ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
                                *sp++ = ins;
                                
@@ -9479,14 +9411,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                --sp;
                                args [0] = *sp;
 
-                               if (context_used) {
-                                       args [1] = emit_get_rgctx_method (cfg, context_used,
-                                               cmethod, MONO_RGCTX_INFO_METHOD);
+                               args [1] = emit_get_rgctx_method (cfg, context_used,
+                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
+
+                               if (context_used)
                                        *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
-                               } else {
-                                       EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+                               else
                                        *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
-                               }
 
                                ip += 6;
                                inline_costs += 10 * num_calls++;
@@ -9730,7 +9661,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
-                               if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
+                               if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic) {
                                        MonoType *type = mono_type_create_from_typespec (image, token);
                                        token = mono_type_size (type, &ialign);
                                } else {
@@ -9764,13 +9695,27 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                readonly = TRUE;
                                ip += 2;
                                break;
+
+                       case CEE_UNUSED56:
+                       case CEE_UNUSED57:
+                       case CEE_UNUSED70:
+                       case CEE_UNUSED:
+                       case CEE_UNUSED99:
+                               UNVERIFIED;
+                               
                        default:
-                               g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
+                               g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
+                               UNVERIFIED;
                        }
                        break;
                }
+               case CEE_UNUSED58:
+               case CEE_UNUSED1:
+                       UNVERIFIED;
+
                default:
-                       g_error ("opcode 0x%02x not handled", *ip);
+                       g_warning ("opcode 0x%02x not handled", *ip);
+                       UNVERIFIED;
                }
        }
        if (start_new_bblock != 1)
@@ -9839,6 +9784,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
+       if (cfg->init_ref_vars && cfg->method == method) {
+               /* Emit initialization for ref vars */
+               // FIXME: Avoid duplication initialization for IL locals.
+               for (i = 0; i < cfg->num_varinfo; ++i) {
+                       MonoInst *ins = cfg->varinfo [i];
+
+                       if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
+                               MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
+               }
+       }
+
+       /* Add a sequence point for method entry/exit events */
+       if (seq_points) {
+               NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
+               MONO_ADD_INS (init_localsbb, ins);
+               NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
+               MONO_ADD_INS (cfg->bb_exit, ins);
+       }
+
        cfg->ip = NULL;
 
        if (cfg->method == method) {
@@ -9863,35 +9827,38 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
                g_free (mname);
+               mono_metadata_free_mh (header);
+               mono_basic_block_free (original_bb);
                return -1;
        }
 
        if ((cfg->verbose_level > 2) && (cfg->method == method)) 
                mono_print_code (cfg, "AFTER METHOD-TO-IR");
 
+       mono_metadata_free_mh (header);
+       mono_basic_block_free (original_bb);
        return inline_costs;
  
  exception_exit:
        g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
-       g_slist_free (class_inits);
-       dont_inline = g_list_remove (dont_inline, method);
-       return -1;
+       goto cleanup;
 
  inline_failure:
-       g_slist_free (class_inits);
-       dont_inline = g_list_remove (dont_inline, method);
-       return -1;
+       goto cleanup;
 
  load_error:
-       g_slist_free (class_inits);
-       dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
-       return -1;
+       goto cleanup;
 
  unverified:
+       set_exception_type_from_invalid_il (cfg, method, ip);
+       goto cleanup;
+
+ cleanup:
        g_slist_free (class_inits);
+       mono_basic_block_free (original_bb);
        dont_inline = g_list_remove (dont_inline, method);
-       set_exception_type_from_invalid_il (cfg, method, ip);
+       mono_metadata_free_mh (header);
        return -1;
 }
 
@@ -10346,14 +10313,15 @@ mono_op_to_op_imm_noemul (int opcode)
        case OP_LSHR:
        case OP_LSHL:
        case OP_LSHR_UN:
+               return -1;
 #endif
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
        case OP_IDIV:
        case OP_IDIV_UN:
        case OP_IREM:
        case OP_IREM_UN:
-#endif
                return -1;
+#endif
        default:
                return mono_op_to_op_imm (opcode);
        }
@@ -10467,6 +10435,9 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                                case 'i':
                                                        mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
                                                        break;
+                                               case 'l':
+                                                       mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
+                                                       break;
                                                case 'f':
                                                        mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
                                                        break;
@@ -10630,12 +10601,13 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
 
                if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
                        switch (ins->type) {
-#ifdef MONO_ARCH_SOFT_FLOAT
                        case STACK_R8:
-#endif
                        case STACK_I8: {
                                MonoInst *tree;
 
+                               if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
+                                       break;
+
                                g_assert (ins->opcode == OP_REGOFFSET);
 
                                tree = get_vreg_to_inst (cfg, ins->dreg + 1);
@@ -10677,6 +10649,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
         * don't split live ranges, these will precisely describe the live range of
         * the variable, i.e. the instruction range where a valid value can be found
         * in the variables location.
+        * The live range is computed using the liveness info computed by the liveness pass.
+        * We can't use vmv->range, since that is an abstract live range, and we need
+        * one which is instruction precise.
+        * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
         */
        /* FIXME: Only do this if debugging info is requested */
        live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
@@ -10821,12 +10797,10 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
 
                                        lvreg = 0;
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-                                       if (store_opcode == OP_STORER8_MEMBASE_REG) {
+                                       if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
                                                regtype = 'l';
                                                store_opcode = OP_STOREI8_MEMBASE_REG;
                                        }
-#endif
 
                                        ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
 
@@ -11030,6 +11004,29 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                        if (cfg->verbose_level > 2)
                                mono_print_ins_index (1, ins);
                }
+
+               /* Extend the live range based on the liveness info */
+               if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
+                       for (i = 0; i < cfg->num_varinfo; i ++) {
+                               MonoMethodVar *vi = MONO_VARINFO (cfg, i);
+
+                               if (vreg_is_volatile (cfg, vi->vreg))
+                                       /* The liveness info is incomplete */
+                                       continue;
+
+                               if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
+                                       /* Live from at least the first ins of this bb */
+                                       live_range_start [vi->vreg] = bb->code;
+                                       live_range_start_bb [vi->vreg] = bb;
+                               }
+
+                               if (mono_bitset_test_fast (bb->live_out_set, i)) {
+                                       /* Live at least until the last ins of this bb */
+                                       live_range_end [vi->vreg] = bb->last_ins;
+                                       live_range_end_bb [vi->vreg] = bb;
+                               }
+                       }
+               }
        }
        
 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
@@ -11037,21 +11034,26 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
         * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
         * by storing the current native offset into MonoMethodVar->live_range_start/end.
         */
-       for (i = 0; i < cfg->num_varinfo; ++i) {
-               int vreg = MONO_VARINFO (cfg, i)->vreg;
-               MonoInst *ins;
-
-               if (live_range_start [vreg]) {
-                       MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
-                       ins->inst_c0 = i;
-                       ins->inst_c1 = vreg;
-                       mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
-               }
-               if (live_range_end [vreg]) {
-                       MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
-                       ins->inst_c0 = i;
-                       ins->inst_c1 = vreg;
-                       mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+       if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
+               for (i = 0; i < cfg->num_varinfo; ++i) {
+                       int vreg = MONO_VARINFO (cfg, i)->vreg;
+                       MonoInst *ins;
+
+                       if (live_range_start [vreg]) {
+                               MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
+                               ins->inst_c0 = i;
+                               ins->inst_c1 = vreg;
+                               mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
+                       }
+                       if (live_range_end [vreg]) {
+                               MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
+                               ins->inst_c0 = i;
+                               ins->inst_c1 = vreg;
+                               if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
+                                       mono_add_ins_to_end (live_range_end_bb [vreg], ins);
+                               else
+                                       mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+                       }
                }
        }
 #endif