2009-03-28 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / method-to-ir.c
index bc447d574272feb231c7366a8ce5a40127d6bc50..3c0c2c953e867b2e05ce1eec381f690e635b054a 100644 (file)
 #include <sys/time.h>
 #endif
 
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
@@ -44,9 +48,9 @@
 #include <mono/metadata/security-manager.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/monitor.h>
 #include <mono/utils/mono-compiler.h>
 
-#define NEW_IR
 #include "mini.h"
 #include "trace.h"
 
@@ -54,8 +58,6 @@
 
 #include "jit-icalls.h"
 
-#include "aliasing.h"
-
 #define BRANCH_COST 100
 #define INLINE_LENGTH_LIMIT 20
 #define INLINE_FAILURE do {\
@@ -106,15 +108,12 @@ MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMetho
 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
 
-int mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
-                  MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
-                  guint inline_offset, gboolean is_virtual_call);
-
 /* helper methods signature */
 extern MonoMethodSignature *helper_sig_class_init_trampoline;
 extern MonoMethodSignature *helper_sig_domain_get;
 extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
 extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
+extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
 
 /*
  * Instruction metadata
@@ -122,13 +121,17 @@ extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
 #ifdef MINI_OP
 #undef MINI_OP
 #endif
-#define MINI_OP(a,b,dest,src1,src2) dest, src1, src2,
+#ifdef MINI_OP3
+#undef MINI_OP3
+#endif
+#define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
+#define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
 #define NONE ' '
 #define IREG 'i'
 #define FREG 'f'
 #define VREG 'v'
 #define XREG 'x'
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
 #define LREG IREG
 #else
 #define LREG 'l'
@@ -139,6 +142,15 @@ ins_info[] = {
 #include "mini-ops.h"
 };
 #undef MINI_OP
+#undef MINI_OP3
+
+#define MINI_OP(a,b,dest,src1,src2) (((src1) != NONE) + ((src2) != NONE)),
+#define MINI_OP3(a,b,dest,src1,src2,src3) (((src1) != NONE) + ((src2) != NONE) + ((src3) != NONE)),
+const gint8 ins_sreg_counts[] = {
+#include "mini-ops.h"
+};
+#undef MINI_OP
+#undef MINI_OP3
 
 extern GHashTable *jit_icall_name_hash;
 
@@ -148,6 +160,14 @@ extern GHashTable *jit_icall_name_hash;
        (vi)->idx = (id); \
 } while (0)
 
+void
+mono_inst_set_src_registers (MonoInst *ins, int *regs)
+{
+       ins->sreg1 = regs [0];
+       ins->sreg2 = regs [1];
+       ins->sreg3 = regs [2];
+}
+
 guint32
 mono_alloc_ireg (MonoCompile *cfg)
 {
@@ -204,7 +224,7 @@ handle_enum:
                return OP_MOVE;
        case MONO_TYPE_I8:
        case MONO_TYPE_U8:
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                return OP_MOVE;
 #else
                return OP_LMOVE;
@@ -215,7 +235,7 @@ handle_enum:
                return OP_FMOVE;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
+                       type = mono_class_enum_basetype (type->data.klass);
                        goto handle_enum;
                }
                if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
@@ -271,30 +291,6 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                } \
        } while (0)
 
-#ifndef MONO_ARCH_EMIT_BOUNDS_CHECK
-#define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
-                       int _length_reg = alloc_ireg (cfg); \
-                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, _length_reg, array_reg, offset); \
-                       MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, _length_reg, index_reg); \
-                       MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
-       } while (0)
-#endif
-
-#define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
-            if (!(cfg->opt & MONO_OPT_ABCREM)) { \
-                MONO_ARCH_EMIT_BOUNDS_CHECK ((cfg), (array_reg), G_STRUCT_OFFSET (array_type, array_length_field), (index_reg)); \
-            } else { \
-                MonoInst *ins; \
-                MONO_INST_NEW ((cfg), ins, OP_BOUNDS_CHECK); \
-                ins->sreg1 = array_reg; \
-                ins->sreg2 = index_reg; \
-                ins->inst_imm = G_STRUCT_OFFSET (array_type, array_length_field); \
-                MONO_ADD_INS ((cfg)->cbb, ins); \
-                           (cfg)->flags |= MONO_CFG_HAS_ARRAY_ACCESS; \
-                (cfg)->cbb->has_array_access = TRUE; \
-            } \
-    } while (0)
-
 #if defined(__i386__) || defined(__x86_64__)
 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
                MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
@@ -307,10 +303,10 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
        } while (0)
 #endif
 
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
                /* FIXME: Need to add many more cases */ \
-               if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) { \
+               if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
                        MonoInst *widen; \
                        int dr = alloc_preg (cfg); \
                        EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
@@ -469,7 +465,6 @@ mono_find_block_region (MonoCompile *cfg, int offset)
        MonoExceptionClause *clause;
        int i;
 
-       /* first search for handlers and filters */
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
                if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
@@ -484,11 +479,7 @@ mono_find_block_region (MonoCompile *cfg, int offset)
                        else
                                return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
                }
-       }
 
-       /* search the try blocks */
-       for (i = 0; i < header->num_clauses; ++i) {
-               clause = &header->clauses [i];
                if (MONO_OFFSET_IN_CLAUSE (clause, offset))
                        return ((i + 1) << 8) | clause->flags;
        }
@@ -613,7 +604,7 @@ handle_enum:
                return;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
+                       type = mono_class_enum_basetype (type->data.klass);
                        goto handle_enum;
                } else {
                        inst->klass = klass;
@@ -786,7 +777,7 @@ type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
        case OP_LCOMPARE:
        case OP_ICOMPARE:
                ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
-               if ((src1->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
+               if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
                        ins->opcode = OP_LCOMPARE;
                else if (src1->type == STACK_R8)
                        ins->opcode = OP_FCOMPARE;
@@ -795,7 +786,7 @@ type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
                break;
        case OP_ICOMPARE_IMM:
                ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
-               if ((src1->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
+               if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
                        ins->opcode = OP_LCOMPARE_IMM;          
                break;
        case CEE_BEQ:
@@ -879,11 +870,11 @@ type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
                ins->type = STACK_PTR;
                switch (src1->type) {
                case STACK_I4:
-                       ins->opcode = OP_MOVE;
+                       ins->opcode = OP_ICONV_TO_U;
                        break;
                case STACK_PTR:
                case STACK_MP:
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                        ins->opcode = OP_LCONV_TO_U;
 #else
                        ins->opcode = OP_MOVE;
@@ -1636,24 +1627,24 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val,
                switch (size) {
                case 1:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
-                       break;
+                       return;
                case 2:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
-                       break;
+                       return;
                case 4:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
-                       break;
-#if SIZEOF_VOID_P == 8
+                       return;
+#if SIZEOF_REGISTER == 8
                case 8:
                        MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
+                       return;
 #endif
                }
-               return;
        }
 
        val_reg = alloc_preg (cfg);
 
-       if (sizeof (gpointer) == 8)
+       if (SIZEOF_REGISTER == 8)
                MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
        else
                MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
@@ -1669,7 +1660,7 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val,
        }       
 
 #if !NO_UNALIGNED_ACCESS
-       if (sizeof (gpointer) == 8) {
+       if (SIZEOF_REGISTER == 8) {
                if (offset % 8) {
                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
                        offset += 4;
@@ -1703,7 +1694,7 @@ mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val,
 #endif /* DISABLE_JIT */
 
 void 
-mini_emit_memcpy2 (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
+mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
 {
        int cur_reg;
 
@@ -1723,7 +1714,7 @@ mini_emit_memcpy2 (MonoCompile *cfg, int destreg, int doffset, int srcreg, int s
        }
 
 #if !NO_UNALIGNED_ACCESS
-       if (sizeof (gpointer) == 8) {
+       if (SIZEOF_REGISTER == 8) {
                while (size >= 8) {
                        cur_reg = alloc_preg (cfg);
                        MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
@@ -1802,7 +1793,7 @@ handle_enum:
                return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
+                       type = mono_class_enum_basetype (type->data.klass);
                        goto handle_enum;
                } else
                        return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
@@ -2003,7 +1994,7 @@ handle_enum:
                        continue;
                case MONO_TYPE_VALUETYPE:
                        if (simple_type->data.klass->enumtype) {
-                               simple_type = simple_type->data.klass->enum_basetype;
+                               simple_type = mono_class_enum_basetype (simple_type->data.klass);
                                goto handle_enum;
                        }
                        if (args [i]->type != STACK_VTYPE)
@@ -2205,7 +2196,7 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
 {
 #ifdef MONO_ARCH_RGCTX_REG
        MonoCallInst *call;
-       int rgctx_reg;
+       int rgctx_reg = -1;
 
        if (rgctx_arg) {
                rgctx_reg = mono_alloc_preg (cfg);
@@ -2234,7 +2225,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
        if (method->string_ctor) {
                /* Create the real signature */
                /* FIXME: Cache these */
-               MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_full (cfg->mempool, sig);
+               MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
                ctor_sig->ret = &mono_defaults.string_class->byval_arg;
 
                sig = ctor_sig;
@@ -2257,9 +2248,21 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
                this_reg = this->dreg;
 
+#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+               if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
+                       /* Make a call to delegate->invoke_impl */
+                       call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
+                       call->inst.inst_basereg = this_reg;
+                       call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
+                       MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
+
+                       return (MonoInst*)call;
+               }
+#endif
+
                if ((!cfg->compile_aot || enable_for_aot) && 
                        (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
-                        ((method->flags & METHOD_ATTRIBUTE_FINAL) && 
+                        (MONO_METHOD_IS_FINAL (method) &&
                          method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) {
                        /* 
                         * the method is not virtual, we just need to ensure this is not null
@@ -2282,21 +2285,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                        return (MonoInst*)call;
                }
 
-#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
-               if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
-                       /* Make a call to delegate->invoke_impl */
-                       call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
-                       call->inst.inst_basereg = this_reg;
-                       call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
-                       MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
-
-                       return (MonoInst*)call;
-               }
-#endif
-
-               if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
-                       ((method->flags &  METHOD_ATTRIBUTE_FINAL) ||
-                        (method->klass && method->klass->flags & TYPE_ATTRIBUTE_SEALED))) {
+               if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
                        /*
                         * the method is virtual, but we can statically dispatch since either
                         * it's class or the method itself are sealed.
@@ -2335,10 +2324,12 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                        slot_reg = vtable_reg;
                        call->inst.inst_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
                                (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);
                                emit_imt_argument (cfg, call, imt_arg);
                        }
+#endif
                }
 
                call->inst.sreg1 = slot_reg;
@@ -2472,9 +2463,24 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
        else
                n = mono_class_value_size (klass, &align);
 
+#if HAVE_WRITE_BARRIERS
+       /* if native is true there should be no references in the struct */
+       if (klass->has_references && !native) {
+               /* Avoid barriers when storing to the stack */
+               if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
+                         (dest->opcode == OP_LDADDR))) {
+                       iargs [0] = dest;
+                       iargs [1] = src;
+                       EMIT_NEW_PCONST (cfg, iargs [2], klass);
+
+                       mono_emit_jit_icall (cfg, mono_value_copy, iargs);
+               }
+       }
+#endif
+
        if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
                /* FIXME: Optimize the case when src/dest is OP_LDADDR */
-               mini_emit_memcpy2 (cfg, dest->dreg, 0, src->dreg, 0, n, align);
+               mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
        } else {
                iargs [0] = dest;
                iargs [1] = src;
@@ -2785,7 +2791,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
                EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
 
                alloc_ftn = mono_object_new;
-       } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
+       } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
                /* This happens often in argument checking code, eg. throw new FooException... */
                /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
                EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
@@ -3024,7 +3030,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
 
        MONO_START_BB (cfg, false_bb);
 
-       MONO_EMIT_NEW_ICONST (cfg, res_reg, 0);
+       MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 
        MONO_START_BB (cfg, is_null_bb);
@@ -3248,8 +3254,12 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        }
 
        /* Set invoke_impl field */
-       trampoline = mono_create_delegate_trampoline (klass);
-       EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
+       if (cfg->compile_aot) {
+               EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
+       } else {
+               trampoline = mono_create_delegate_trampoline (klass);
+               EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
+       }
        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
 
        /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
@@ -3305,10 +3315,13 @@ mono_emit_load_got_addr (MonoCompile *cfg)
        MONO_ADD_INS (cfg->bb_exit, dummy_use);
 }
 
+static int inline_limit;
+static gboolean inline_limit_inited;
+
 static gboolean
 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 {
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header;
        MonoVTable *vtable;
 #ifdef MONO_ARCH_SOFT_FLOAT
        MonoMethodSignature *sig = mono_method_signature (method);
@@ -3325,6 +3338,12 @@ 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) ||
@@ -3336,11 +3355,14 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 
        /* also consider num_locals? */
        /* Do the size check early to avoid creating vtables */
-       if (getenv ("MONO_INLINELIMIT")) {
-               if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
-                       return FALSE;
-               }
-       } else if (header->code_size >= INLINE_LENGTH_LIMIT)
+       if (!inline_limit_inited) {
+               if (getenv ("MONO_INLINELIMIT"))
+                       inline_limit = atoi (getenv ("MONO_INLINELIMIT"));
+               else
+                       inline_limit = INLINE_LENGTH_LIMIT;
+               inline_limit_inited = TRUE;
+       }
+       if (header->code_size >= inline_limit)
                return FALSE;
 
        /*
@@ -3437,12 +3459,17 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
        array_reg = arr->dreg;
        index_reg = index->dreg;
 
-#if SIZEOF_VOID_P == 8
+#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);
 #else
-       index2_reg = index_reg;
+       if (index->type == STACK_I8) {
+               index2_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
+       } else {
+               index2_reg = index_reg;
+       }
 #endif
 
        MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
@@ -3572,7 +3599,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        int mult_reg = alloc_preg (cfg);
                        int add_reg = alloc_preg (cfg);
 
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                        /* The array reg is 64 bits but the index reg is only 32 */
                        MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
 #else
@@ -3687,6 +3714,44 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
+       } else if (cmethod->klass == mono_defaults.monitor_class) {
+#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
+               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);
+
+                       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);
+
+                       return (MonoInst*)call;
+               }
+#elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
+               MonoMethod *fast_method = NULL;
+
+               /* Avoid infinite recursion */
+               if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
+                               (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
+                                strcmp (cfg->method->name, "FastMonitorExit") == 0))
+                       return NULL;
+
+               if (strcmp (cmethod->name, "Enter") == 0 ||
+                               strcmp (cmethod->name, "Exit") == 0)
+                       fast_method = mono_monitor_get_fast_path (cmethod);
+               if (!fast_method)
+                       return NULL;
+
+               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;
@@ -3701,7 +3766,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                           (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
                ins = NULL;
 
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
                        /* 64 bit reads are already atomic */
                        MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
@@ -3719,7 +3784,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_ADD_NEW_I4;
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                        else if (fsig->params [0]->type == MONO_TYPE_I8)
                                opcode = OP_ATOMIC_ADD_NEW_I8;
 #endif
@@ -3743,7 +3808,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_ADD_NEW_I4;
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                        else if (fsig->params [0]->type == MONO_TYPE_I8)
                                opcode = OP_ATOMIC_ADD_NEW_I8;
 #endif
@@ -3766,7 +3831,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_ADD_NEW_I4;
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                        else if (fsig->params [0]->type == MONO_TYPE_I8)
                                opcode = OP_ATOMIC_ADD_NEW_I8;
 #endif
@@ -3777,7 +3842,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                                ins->inst_basereg = args [0]->dreg;
                                ins->inst_offset = 0;
                                ins->sreg2 = args [1]->dreg;
-                               ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
+                               ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
                                MONO_ADD_INS (cfg->cbb, ins);
                        }
                }
@@ -3789,7 +3854,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_EXCHANGE_I4;
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                        else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
                                         (fsig->params [0]->type == MONO_TYPE_I) ||
                                         (fsig->params [0]->type == MONO_TYPE_OBJECT))
@@ -3826,25 +3891,36 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                }
 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
  
-#ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
-               /* 
-                * Can't implement CompareExchange methods this way since they have
-                * three arguments. We can implement one of the common cases, where the new
-                * value is a constant.
-                */
+#ifdef MONO_ARCH_HAVE_ATOMIC_CAS
                if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
-                       if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
-                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
+                       int size = 0;
+                       if (fsig->params [1]->type == MONO_TYPE_I4)
+                               size = 4;
+                       else if (fsig->params [1]->type == MONO_TYPE_I || MONO_TYPE_IS_REFERENCE (fsig->params [1]))
+                               size = sizeof (gpointer);
+                       else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I4)
+                               size = 8;
+                       if (size == 4) {
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
                                ins->dreg = alloc_ireg (cfg);
                                ins->sreg1 = args [0]->dreg;
                                ins->sreg2 = args [1]->dreg;
-                               ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
+                               ins->sreg3 = args [2]->dreg;
                                ins->type = STACK_I4;
                                MONO_ADD_INS (cfg->cbb, ins);
+                       } else if (size == 8) {
+                               MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
+                               ins->dreg = alloc_ireg (cfg);
+                               ins->sreg1 = args [0]->dreg;
+                               ins->sreg2 = args [1]->dreg;
+                               ins->sreg3 = args [2]->dreg;
+                               ins->type = STACK_I8;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                       } else {
+                               /* g_assert_not_reached (); */
                        }
-                       /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
                }
-#endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
+#endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
 
                if (ins)
                        return ins;
@@ -4015,6 +4091,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        guint32 prev_cil_offset_to_bb_len;
        MonoMethod *prev_current_method;
        MonoGenericContext *prev_generic_context;
+       gboolean ret_var_set, prev_ret_var_set;
 
        g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
 
@@ -4068,8 +4145,11 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        prev_cbb = cfg->cbb;
        prev_current_method = cfg->current_method;
        prev_generic_context = cfg->generic_context;
+       prev_ret_var_set = cfg->ret_var_set;
 
-       costs = mono_method_to_ir2 (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+       costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+
+       ret_var_set = cfg->ret_var_set;
 
        cfg->inlined_method = prev_inlined_method;
        cfg->real_offset = prev_real_offset;
@@ -4082,6 +4162,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cfg->arg_types = prev_arg_types;
        cfg->current_method = prev_current_method;
        cfg->generic_context = prev_generic_context;
+       cfg->ret_var_set = prev_ret_var_set;
 
        if ((costs >= 0 && costs < 60) || inline_allways) {
                if (cfg->verbose_level > 2)
@@ -4109,6 +4190,10 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                        MonoBasicBlock *prev = ebblock->in_bb [0];
                        mono_merge_basic_blocks (cfg, prev, ebblock);
                        cfg->cbb = prev;
+                       if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
+                               mono_merge_basic_blocks (cfg, prev_cbb, prev);
+                               cfg->cbb = prev_cbb;
+                       }
                } else {
                        cfg->cbb = ebblock;
                }
@@ -4118,7 +4203,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                         * If the inlined method contains only a throw, then the ret var is not 
                         * set, so set it to a dummy value.
                         */
-                       if (!cfg->ret_var_set) {
+                       if (!ret_var_set) {
                                static double r8_0 = 0.0;
 
                                switch (rvar->type) {
@@ -4400,53 +4485,83 @@ emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMe
 }
 
 static MonoMethod*
-verification_exception (void)
+field_access_exception (void)
 {
        static MonoMethod *method = NULL;
 
        if (!method) {
                MonoSecurityManager *secman = mono_security_manager_get_methods ();
                method = mono_class_get_method_from_name (secman->securitymanager,
-                                                         "VerificationException", 0);
+                                                         "FieldAccessException", 2);
        }
        g_assert (method);
        return method;
 }
 
 static void
-emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
+emit_throw_field_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
+                                   MonoBasicBlock *bblock, unsigned char *ip)
+{
+       MonoMethod *thrower = field_access_exception ();
+       MonoInst *args [2];
+
+       EMIT_NEW_METHODCONST (cfg, args [0], caller);
+       EMIT_NEW_METHODCONST (cfg, args [1], field);
+       mono_emit_method_call (cfg, thrower, args, NULL);
+}
+
+/*
+ * Return the original method is a wrapper is specified. We can only access 
+ * the custom attributes from the original method.
+ */
+static MonoMethod*
+get_original_method (MonoMethod *method)
 {
-       MonoMethod *thrower = verification_exception ();
+       if (method->wrapper_type == MONO_WRAPPER_NONE)
+               return method;
+
+       /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
+       if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
+               return NULL;
 
-       mono_emit_method_call (cfg, thrower, NULL, NULL);
+       /* in other cases we need to find the original method */
+       return mono_marshal_method_from_wrapper (method);
 }
 
 static void
-ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
-                                        MonoBasicBlock *bblock, unsigned char *ip)
+ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
+                                         MonoBasicBlock *bblock, unsigned char *ip)
 {
-       MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
-       MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
-       gboolean is_safe = TRUE;
+       /* 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;
 
-       if (!(caller_level >= callee_level ||
-                       caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
-                       callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
-               is_safe = FALSE;
-       }
+       /* 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;
 
-       if (!is_safe)
-               emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
+       /* 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_field_access_exception (cfg, caller, field, bblock, ip);
 }
 
-static gboolean
-method_is_safe (MonoMethod *method)
+static void
+ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
+                                        MonoBasicBlock *bblock, unsigned char *ip)
 {
-       /*
-       if (strcmp (method->name, "unsafeMethod") == 0)
-               return FALSE;
-       */
-       return TRUE;
+       /* 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_method_access_exception (cfg, caller, callee, bblock, ip);
 }
 
 /*
@@ -4454,7 +4569,7 @@ method_is_safe (MonoMethod *method)
  * sequence and return the pointer to the data and the size.
  */
 static const char*
-initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size)
+initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
 {
        /*
         * newarr[System.Int32]
@@ -4477,6 +4592,8 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
                if (!field)
                        return NULL;
 
+               *out_field_token = field_token;
+
                cmethod = mini_get_method (NULL, method, token, NULL, NULL);
                if (!cmethod)
                        return NULL;
@@ -4901,6 +5018,31 @@ mono_decompose_soft_float (MonoCompile *cfg)
                                        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);
@@ -4937,7 +5079,8 @@ emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
 {
        MonoInst *ins;
        guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
-       if ((opcode == OP_MOVE) && ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
+       if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
+                       ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
                /* Optimize reg-reg moves away */
                /* 
                 * Can't optimize other opcodes, since sp[0] might point to
@@ -4991,11 +5134,24 @@ load_error:
        return NULL;
 }
 
+static gboolean
+is_exception_class (MonoClass *class)
+{
+       while (class) {
+               if (class == mono_defaults.exception_class)
+                       return TRUE;
+               class = class->parent;
+       }
+       return FALSE;
+}
+
 /*
- * mono_method_to_ir: translates IL into basic blocks containing trees
+ * mono_method_to_ir:
+ *
+ *   Translate the .net IL into linear IR.
  */
 int
-mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
+mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
                   MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
                   guint inline_offset, gboolean is_virtual_call)
 {
@@ -5181,6 +5337,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                
                                if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                        GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
+                                       tblock->flags |= BB_EXCEPTION_HANDLER;
                                        tblock->real_offset = clause->data.filter_offset;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
@@ -5195,9 +5352,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        clause->data.catch_class &&
                                        cfg->generic_sharing_context &&
                                        mono_class_check_context_used (clause->data.catch_class)) {
-                               if (mono_method_get_context (method)->method_inst)
-                                       GENERIC_SHARING_FAILURE (CEE_NOP);
-
                                /*
                                 * In shared generic code with catch
                                 * clauses containing type variables
@@ -5221,7 +5375,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        }
                }
        } else {
-               arg_array = alloca (sizeof (MonoInst *) * num_args);
+               arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
                cfg->cbb = start_bblock;
                cfg->args = arg_array;
                mono_save_args (cfg, sig, inline_args);
@@ -5344,8 +5498,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                }
                        }
                }
-               if (!method_is_safe (method))
-                       emit_throw_verification_exception (cfg, bblock, ip);
        }
 
        if (header->code_size == 0)
@@ -5365,6 +5517,22 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
        }
        class_inits = NULL;
 
+       /* We force the vtable variable here for all shared methods
+          for the possibility that they might show up in a stack
+          trace where their exact instantiation is needed. */
+       if (cfg->generic_sharing_context && method == cfg->method) {
+               if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
+                               mini_method_get_context (method)->method_inst ||
+                               method->klass->valuetype) {
+                       mono_get_vtable_var (cfg);
+               } else {
+                       /* FIXME: Is there a better way to do this?
+                          We need the variable live for the duration
+                          of the whole method. */
+                       cfg->args [0]->flags |= MONO_INST_INDIRECT;
+               }
+       }
+
        /* add a check for this != NULL to inlined methods */
        if (is_virtual_call) {
                MonoInst *arg_ins;
@@ -5630,9 +5798,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                case CEE_LDC_R4: {
                        float *f;
                        /* FIXME: we should really allocate this only late in the compilation process */
-                       mono_domain_lock (cfg->domain);
                        f = mono_domain_alloc (cfg->domain, sizeof (float));
-                       mono_domain_unlock (cfg->domain);
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_R4CONST);
@@ -5650,9 +5816,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                case CEE_LDC_R8: {
                        double *d;
                        /* FIXME: we should really allocate this only late in the compilation process */
-                       mono_domain_lock (cfg->domain);
                        d = mono_domain_alloc (cfg->domain, sizeof (double));
-                       mono_domain_unlock (cfg->domain);
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_R8CONST);
@@ -5701,6 +5865,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                case CEE_JMP: {
                        MonoCallInst *call;
 
+                       INLINE_FAILURE;
+
                        CHECK_OPSIZE (5);
                        if (stack_start != sp)
                                UNVERIFIED;
@@ -5714,19 +5880,14 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
                                GENERIC_SHARING_FAILURE (CEE_JMP);
 
-                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
-                               if (check_linkdemand (cfg, method, cmethod))
-                                       INLINE_FAILURE;
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
                                CHECK_CFG_EXCEPTION;
-                       }
 
 #ifdef __x86_64__
                        {
                                MonoMethodSignature *fsig = mono_method_signature (cmethod);
                                int i, n;
 
-                               /* FIXME: Remove OP_JMP from mini-amd64.c when the old JIT is removed */
-
                                /* Handle tail calls similarly to calls */
                                n = fsig->param_count + fsig->hasthis;
 
@@ -5793,7 +5954,19 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
                                        cil_method = cmethod;
                                } else if (constrained_call) {
-                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+                                       if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
+                                               /* 
+                                                * This is needed since get_method_constrained can't find 
+                                                * the method in klass representing a type var.
+                                                * The type var is guaranteed to be a reference type in this
+                                                * case.
+                                                */
+                                               cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
+                                               cil_method = cmethod;
+                                               g_assert (!cmethod->klass->valuetype);
+                                       } else {
+                                               cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+                                       }
                                } else {
                                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
                                        cil_method = cmethod;
@@ -5848,7 +6021,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        CHECK_CFG_EXCEPTION;
                                }
 
-                               if (cmethod->string_ctor)
+                               if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
                                        g_assert_not_reached ();
                        }
 
@@ -5981,7 +6154,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                }
 
                                if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
-                                               (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
+                                               MONO_METHOD_IS_FINAL (cmethod)) {
                                        if (virtual)
                                                check_this = TRUE;
                                        virtual = 0;
@@ -6007,7 +6180,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        /* Calling virtual generic methods */
                        if (cmethod && virtual && 
                            (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
-                           !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
+                           !(MONO_METHOD_IS_FINAL (cmethod) && 
                              cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
                            mono_method_signature (cmethod)->generic_param_count) {
                                MonoInst *this_temp, *this_arg_temp, *store;
@@ -6019,19 +6192,15 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                INLINE_FAILURE;
 
 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
-                               if (!(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) &&
-                                               cmethod->wrapper_type == MONO_WRAPPER_NONE) {
+                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE) {
                                        g_assert (!imt_arg);
                                        if (context_used) {
                                                imt_arg = emit_get_rgctx_method (cfg, context_used,
-                                                       cmethod, MONO_RGCTX_INFO_METHOD_CONTEXT);
+                                                       cmethod, MONO_RGCTX_INFO_METHOD);
 
                                        } else {
-                                               // FIXME:
-                                               cfg->disable_aot = TRUE;
                                                g_assert (cmethod->is_inflated);
-                                               EMIT_NEW_PCONST (cfg, imt_arg,
-                                                       ((MonoMethodInflated*)cmethod)->context.method_inst);
+                                               EMIT_NEW_METHODCONST (cfg, imt_arg, cmethod);
                                        }
                                        ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg);
                                } else
@@ -6074,7 +6243,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        /* FIXME: runtime generic context pointer for jumps? */
                        /* FIXME: handle this for generic sharing eventually */
                        if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
-                                (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
+                               (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod))) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret)) {
                                MonoCallInst *call;
 
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
@@ -6129,7 +6298,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                        /* Inlining */
                        if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
-                           (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
+                               (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
                            mono_method_check_inlining (cfg, cmethod) &&
                                 !g_list_find (dont_inline, cmethod)) {
                                int costs;
@@ -6201,7 +6370,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        if (context_used && !imt_arg && !array_rank &&
                                        (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
                                                !mono_class_generic_sharing_enabled (cmethod->klass)) &&
-                                       (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+                                       (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
                                                !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
                                INLINE_FAILURE;
 
@@ -6227,6 +6396,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                else if (*ip == CEE_CALLI)
                                        g_assert (!vtable_arg);
                                else
+                                       /* FIXME: what the hell is this??? */
                                        g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
                                                        !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
 
@@ -6247,7 +6417,16 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        NOT_IMPLEMENTED;
 #endif
                                } else {
-                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
+                                       if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
+                                               /* 
+                                                * Instead of emitting an indirect call, emit a direct call
+                                                * with the contents of the aotconst as the patch info.
+                                                */
+                                               ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
+                                               NULLIFY_INS (addr);
+                                       } else {
+                                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
+                                       }
                                }
                                if (!MONO_TYPE_IS_VOID (fsig->ret)) {
                                        if (fsig->pinvoke && !fsig->ret->byref) {
@@ -6517,7 +6696,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        type_from_op (cmp, sp [0], NULL);
                        CHECK_TYPE (cmp);
 
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                        if (cmp->opcode == OP_LCOMPARE_IMM) {
                                /* Convert it to OP_LCOMPARE */
                                MONO_INST_NEW (cfg, ins, OP_I8CONST);
@@ -6572,12 +6751,11 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        MonoBasicBlock **targets;
                        MonoBasicBlock *default_bblock;
                        MonoJumpInfoBBTable *table;
-#ifndef __arm__
                        int offset_reg = alloc_preg (cfg);
                        int target_reg = alloc_preg (cfg);
                        int table_reg = alloc_preg (cfg);
                        int sum_reg = alloc_preg (cfg);
-#endif
+                       gboolean use_op_switch;
 
                        CHECK_OPSIZE (5);
                        CHECK_STACK (1);
@@ -6625,42 +6803,47 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        table->table = targets;
                        table->table_size = n;
 
+                       use_op_switch = FALSE;
 #ifdef __arm__
                        /* ARM implements SWITCH statements differently */
                        /* FIXME: Make it use the generic implementation */
-                       /* the backend code will deal with aot vs normal case */
-                       MONO_INST_NEW (cfg, ins, OP_SWITCH);
-                       ins->sreg1 = src1->dreg;
-                       ins->inst_p0 = table;
-                       ins->inst_many_bb = targets;
-                       ins->klass = GUINT_TO_POINTER (n);
-                       MONO_ADD_INS (cfg->cbb, ins);
-#else
-                       if (sizeof (gpointer) == 8)
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
-                       else
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
-
-#if SIZEOF_VOID_P == 8
-                       /* The upper word might not be zero, and we add it to a 64 bit address later */
-                       MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
+                       if (!cfg->compile_aot)
+                               use_op_switch = TRUE;
 #endif
-
-                       if (cfg->compile_aot) {
-                               MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
-                       } else {
-                               MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
-                               ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
+                       
+                       if (use_op_switch) {
+                               MONO_INST_NEW (cfg, ins, OP_SWITCH);
+                               ins->sreg1 = src1->dreg;
                                ins->inst_p0 = table;
-                               ins->dreg = table_reg;
+                               ins->inst_many_bb = targets;
+                               ins->klass = GUINT_TO_POINTER (n);
                                MONO_ADD_INS (cfg->cbb, ins);
-                       }
+                       } else {
+                               if (sizeof (gpointer) == 8)
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
+                               else
+                                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
 
-                       /* FIXME: Use load_memindex */
-                       MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
-                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
-                       MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
+#if SIZEOF_REGISTER == 8
+                               /* The upper word might not be zero, and we add it to a 64 bit address later */
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
 #endif
+
+                               if (cfg->compile_aot) {
+                                       MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
+                               } else {
+                                       MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
+                                       ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
+                                       ins->inst_p0 = table;
+                                       ins->dreg = table_reg;
+                                       MONO_ADD_INS (cfg->cbb, ins);
+                               }
+
+                               /* FIXME: Use load_memindex */
+                               MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
+                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
+                       }
                        start_new_bblock = 1;
                        inline_costs += (BRANCH_COST * 2);
                        break;
@@ -6710,6 +6893,17 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        CHECK_STACK (2);
                        sp -= 2;
 
+#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))) {
+                               /* insert call to write barrier */
+                               MonoMethod *write_barrier = mono_gc_get_write_barrier ();
+                               mono_emit_method_call (cfg, write_barrier, sp, NULL);
+                               ins_flag = 0;
+                               ip++;
+                               break;
+                       }
+#endif
+
                        NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
                        ins->flags |= ins_flag;
                        ins_flag = 0;
@@ -6780,7 +6974,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                if (imm_opcode != -1) {
                                        ins->opcode = imm_opcode;
                                        if (sp [1]->opcode == OP_I8CONST) {
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                                                ins->inst_imm = sp [1]->inst_l;
 #else
                                                ins->inst_ls_word = sp [1]->inst_ls_word;
@@ -6791,7 +6985,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
                                        ins->sreg2 = -1;
 
-                                       sp [1]->opcode = OP_NOP;
+                                       /* Might be followed by an instruction added by ADD_WIDEN_OP */
+                                       if (sp [1]->next == NULL)
+                                               sp [1]->opcode = OP_NOP;
                                }
                        }
                        MONO_ADD_INS ((cfg)->cbb, (ins));
@@ -6820,7 +7016,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                int data = sp [-1]->inst_c0;
                                sp [-1]->opcode = OP_I8CONST;
                                sp [-1]->type = STACK_I8;
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                                if ((*ip) == CEE_CONV_U8)
                                        sp [-1]->inst_c0 = (guint32)data;
                                else
@@ -7010,7 +7206,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        if (bblock->out_of_line) {
                                                MonoInst *iargs [2];
 
-                                               if (cfg->method->klass->image == mono_defaults.corlib) {
+                                               if (image == mono_defaults.corlib) {
                                                        /* 
                                                         * Avoid relocations in AOT and save some space by using a 
                                                         * version of helper_ldstr specialized to mscorlib.
@@ -7102,7 +7298,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                         * Generate smaller code for the common newobj <exception> instruction in
                         * argument checking code.
                         */
-                       if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
+                       if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
+                               is_exception_class (cmethod->klass) && n <= 2 &&
                                ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
                                ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
                                MonoInst *iargs [3];
@@ -7149,11 +7346,14 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        iargs [0] = NULL;
 
                        if (mini_class_is_system_array (cmethod->klass)) {
-                               if (context_used)
-                                       GENERIC_SHARING_FAILURE (*ip);
-                               g_assert (!context_used);
                                g_assert (!vtable_arg);
-                               EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
+
+                               if (context_used) {
+                                       *sp = emit_get_rgctx_method (cfg, context_used,
+                                               cmethod, MONO_RGCTX_INFO_METHOD);
+                               } else {
+                                       EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
+                               }
 
                                /* Avoid varargs in the common case */
                                if (fsig->param_count == 1)
@@ -7245,16 +7445,16 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                        !mono_class_generic_sharing_enabled (cmethod->klass))) {
                                        MonoInst *cmethod_addr;
 
-                                       g_assert (!callvirt_this_arg);
-
                                        cmethod_addr = emit_get_rgctx_method (cfg, context_used,
                                                cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 
                                        mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
                                } else {
                                        INLINE_FAILURE;
-                                       mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
-                                                       callvirt_this_arg, NULL, vtable_arg);
+                                       ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
+                                                                                                                       callvirt_this_arg, NULL, vtable_arg);
+                                       if (mono_method_is_generic_sharable_impl (cmethod, TRUE) && ((MonoCallInst*)ins)->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+                                               GENERIC_SHARING_FAILURE (*ip);
                                }
                        }
 
@@ -7501,9 +7701,11 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                ins->inst_target_bb = tblock;
                                GET_BBLOCK (cfg, tblock, ip);
                                /* 
-                                * This leads to some inconsistency, since the two bblocks are not
-                                * really connected, but it is needed for handling stack arguments
-                                * correct (See test_0_box_brtrue_opt_regress_81102).
+                                * This leads to some inconsistency, since the two bblocks are 
+                                * not really connected, but it is needed for handling stack 
+                                * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
+                                * FIXME: This should only be needed if sp != stack_start, but that
+                                * doesn't work for some reason (test failure in mcs/tests on x86).
                                 */
                                link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
@@ -7595,6 +7797,12 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                FIELD_ACCESS_FAILURE;
                        mono_class_init (klass);
 
+                       /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
+                          any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
+                       */
+
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
                        if (*ip == CEE_STFLD) {
                                if (target_type_is_incompatible (cfg, field->type, sp [1]))
@@ -7625,6 +7833,20 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                } else {
                                        MonoInst *store;
 
+#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];
+                                       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);
+                               }
+#endif
+
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
                                                
                                        store->flags |= ins_flag;
@@ -7714,6 +7936,10 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
                                FIELD_ACCESS_FAILURE;
 
+                       /* if the class is Critical then transparent code cannot access it's fields */
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
+
                        /*
                         * We can only support shared generic static
                         * field access on architectures where the
@@ -7859,6 +8085,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                        if (*ip == CEE_LDSFLDA) {
                                ins->klass = mono_class_from_mono_type (field->type);
+                               ins->type = STACK_PTR;
                                *sp++ = ins;
                        } else if (*ip == CEE_STSFLD) {
                                MonoInst *store;
@@ -7880,7 +8107,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        gpointer addr = (char*)vtable->data + field->offset;
                                        int ro_type = field->type->type;
                                        if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
-                                               ro_type = field->type->data.klass->enum_basetype->type;
+                                               ro_type = mono_class_enum_basetype (field->type->data.klass)->type;
                                        }
                                        /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
                                        is_const = TRUE;
@@ -7912,6 +8139,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
                                                sp++;
                                                break;
+#ifndef HAVE_MOVING_COLLECTOR
                                        case MONO_TYPE_I:
                                        case MONO_TYPE_U:
                                        case MONO_TYPE_STRING:
@@ -7925,6 +8153,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                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));
@@ -7975,6 +8204,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        MonoInst *len_ins;
                        const char *data_ptr;
                        int data_size = 0;
+                       guint32 field_token;
 
                        CHECK_STACK (1);
                        --sp;
@@ -8039,14 +8269,14 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                         * for small sizes open code the memcpy
                         * ensure the rva field is big enough
                         */
-                       if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size))) {
+                       if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
                                MonoMethod *memcpy_method = get_memcpy_method ();
                                MonoInst *iargs [3];
                                int add_reg = alloc_preg (cfg);
 
                                EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
                                if (cfg->compile_aot) {
-                                       EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
+                                       EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
                                } else {
                                        EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
                                }
@@ -8326,7 +8556,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        CHECK_OPSIZE (5);
                        n = read32 (ip + 1);
 
-                       if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+                       if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
+                                       method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
                                handle = mono_method_get_wrapper_data (method, n);
                                handle_class = mono_method_get_wrapper_data (method, n + 1);
                                if (handle_class == mono_defaults.typehandle_class)
@@ -8339,7 +8570,13 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                goto load_error;
                        mono_class_init (handle_class);
                        if (cfg->generic_sharing_context) {
-                               if (handle_class == mono_defaults.typehandle_class) {
+                               if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
+                                               mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
+                                       /* This case handles ldtoken
+                                          of an open type, like for
+                                          typeof(Gen<>). */
+                                       context_used = 0;
+                               } else if (handle_class == mono_defaults.typehandle_class) {
                                        /* If we get a MONO_TYPE_CLASS
                                           then we need to provide the
                                           open type, not an
@@ -8356,7 +8593,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        g_assert_not_reached ();
                        }
 
-                       if (cfg->opt & MONO_OPT_SHARED) {
+                       if ((cfg->opt & MONO_OPT_SHARED) &&
+                                       method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
+                                       method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
                                MonoInst *addr, *vtvar, *iargs [3];
                                int method_context_used;
 
@@ -8846,7 +9085,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                cmp->sreg2 = sp [1]->dreg;
                                type_from_op (cmp, sp [0], sp [1]);
                                CHECK_TYPE (cmp);
-                               if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
+                               if ((sp [0]->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
                                        cmp->opcode = OP_LCOMPARE;
                                else if (sp [0]->type == STACK_R8)
                                        cmp->opcode = OP_FCOMPARE;
@@ -8873,7 +9112,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        }
                        case CEE_LDFTN: {
                                MonoInst *argconst;
-                               MonoMethod *cil_method, *ctor_method;
+                               MonoMethod *cil_method;
                                gboolean needs_static_rgctx_invoke;
 
                                CHECK_STACK_OVF (1);
@@ -8910,18 +9149,26 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                /* 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) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
-                                       MonoInst *target_ins;
+                               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)) {
+                                       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;
 
-                                       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);
-                                       ip += 5;                                        
-                                       sp ++;
-                                       break;
+                                               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);
+                                               ip += 5;                        
+                                               sp ++;
+                                               break;
+                                       }
                                }
 #endif
 
@@ -9151,7 +9398,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                sp -= 3;
 
                                if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
-                                       mini_emit_memcpy2 (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
+                                       mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
                                } else if ((ip [1] == CEE_INITBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
                                        /* emit_memset only works when val == 0 */
                                        mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
@@ -9288,14 +9535,14 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                MonoInst *store;
 
                cfg->cbb = init_localsbb;
-               cfg->ip = header->code;
+               cfg->ip = NULL;
                for (i = 0; i < header->num_locals; ++i) {
                        MonoType *ptype = header->locals [i];
                        int t = ptype->type;
                        dreg = cfg->locals [i]->dreg;
 
                        if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
-                               t = ptype->data.klass->enum_basetype->type;
+                               t = mono_class_enum_basetype (ptype->data.klass)->type;
                        if (ptype->byref) {
                                MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
                        } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
@@ -9310,7 +9557,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                MONO_ADD_INS (init_localsbb, ins);
                                EMIT_NEW_LOCSTORE (cfg, store, i, ins);
                        } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
-+                                 ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
+                                  ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
                                MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
                        } else {
                                MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
@@ -9561,7 +9808,7 @@ mono_load_membase_to_load_mem (int opcode)
                return OP_LOADI4_MEM;
        case OP_LOADU4_MEMBASE:
                return OP_LOADU4_MEM;
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
        case OP_LOADI8_MEMBASE:
                return OP_LOADI8_MEM;
 #endif
@@ -9821,7 +10068,7 @@ int
 mono_op_to_op_imm_noemul (int opcode)
 {
        switch (opcode) {
-#if SIZEOF_VOID_P == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
+#if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
        case OP_LSHR:
        case OP_LSHL:
        case OP_LSHR_UN:
@@ -9879,7 +10126,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
 
                        g_assert (ins->opcode >= MONO_CEE_LAST);
 
-                       for (regindex = 0; regindex < 3; regindex ++) {
+                       for (regindex = 0; regindex < 4; regindex ++) {
                                int vreg;
 
                                if (regindex == 0) {
@@ -9892,14 +10139,19 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                        if (regtype == ' ')
                                                continue;
                                        vreg = ins->sreg1;
-                               } else {
+                               } else if (regindex == 2) {
                                        regtype = spec [MONO_INST_SRC2];
                                        if (regtype == ' ')
                                                continue;
                                        vreg = ins->sreg2;
+                               } else if (regindex == 3) {
+                                       regtype = spec [MONO_INST_SRC3];
+                                       if (regtype == ' ')
+                                               continue;
+                                       vreg = ins->sreg3;
                                }
 
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                                if (regtype == 'l') {
                                        /*
                                         * Since some instructions reference the original long vreg,
@@ -9969,7 +10221,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
                case STACK_PTR:
                case STACK_MP:
                case STACK_VTYPE:
-#if SIZEOF_VOID_P == 8
+#if SIZEOF_REGISTER == 8
                case STACK_I8:
 #endif
 #if !defined(__i386__) && !defined(MONO_ARCH_SOFT_FLOAT)
@@ -10043,7 +10295,7 @@ mono_handle_global_vregs (MonoCompile *cfg)
                                cfg->varinfo [pos]->inst_c0 = pos;
                                memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
                                cfg->vars [pos].idx = pos;
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                                if (cfg->varinfo [pos]->type == STACK_I8) {
                                        /* Modify the two component vars too */
                                        MonoInst *var1;
@@ -10081,6 +10333,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        guint32 i, lvregs_len;
        gboolean dest_has_lvreg = FALSE;
        guint32 stacktypes [128];
+       MonoInst **live_range_start, **live_range_end;
+       MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
 
        *need_local_opts = FALSE;
 
@@ -10094,7 +10348,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        stacktypes ['x'] = STACK_VTYPE;
 #endif
 
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
        /* Create MonoInsts for longs */
        for (i = 0; i < cfg->num_varinfo; i++) {
                MonoInst *ins = cfg->varinfo [i];
@@ -10140,6 +10394,20 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
        vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
        lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
        lvregs_len = 0;
+
+       /* 
+        * These arrays contain the first and last instructions accessing a given
+        * variable.
+        * Since we emit bblocks in the same order we process them here, and we
+        * 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.
+        */
+       /* FIXME: Only do this if debugging info is requested */
+       live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
+       live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
+       live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
+       live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
        
        /* Add spill loads/stores */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -10156,8 +10424,9 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                cfg->cbb = bb;
                MONO_BB_FOR_EACH_INS (bb, ins) {
                        const char *spec = INS_INFO (ins->opcode);
-                       int regtype, srcindex, sreg, tmp_reg, prev_dreg;
+                       int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
                        gboolean store, no_lvreg;
+                       int sregs [MONO_MAX_SRC_REGS];
 
                        if (G_UNLIKELY (cfg->verbose_level > 2))
                                mono_print_ins (ins);
@@ -10216,6 +10485,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                spec2 [MONO_INST_DEST] = ' ';
                                spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
                                spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
+                               spec2 [MONO_INST_SRC3] = ' ';
                                spec = spec2;
                        } else if (MONO_IS_STORE_MEMINDEX (ins))
                                g_assert_not_reached ();
@@ -10223,8 +10493,13 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                store = FALSE;
                        no_lvreg = FALSE;
 
-                       if (G_UNLIKELY (cfg->verbose_level > 2))
-                               printf ("\t %.3s %d %d %d\n", spec, ins->dreg, ins->sreg1, ins->sreg2);
+                       if (G_UNLIKELY (cfg->verbose_level > 2)) {
+                               printf ("\t %.3s %d", spec, ins->dreg);
+                               num_sregs = mono_inst_get_src_registers (ins, sregs);
+                               for (srcindex = 0; srcindex < 3; ++srcindex)
+                                       printf (" %d", sregs [srcindex]);
+                               printf ("\n");
+                       }
 
                        /***************/
                        /*    DREG     */
@@ -10237,6 +10512,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
                                MonoInst *store_ins;
                                int store_opcode;
+                               MonoInst *def_ins = ins;
+                               int dreg = ins->dreg; /* The original vreg */
 
                                store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
 
@@ -10249,6 +10526,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        g_assert (var->opcode == OP_REGOFFSET);
                                        if (ins->opcode == OP_MOVE) {
                                                NULLIFY_INS (ins);
+                                               def_ins = NULL;
                                        } else {
                                                ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
                                                ins->inst_basereg = var->inst_basereg;
@@ -10282,6 +10560,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
                                                NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
+                                               def_ins = store_ins;
                                        }
                                        else {
                                                g_assert (store_opcode != OP_STOREV_MEMBASE);
@@ -10293,6 +10572,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        ins->inst_imm = ins->inst_c0;
                                                        ins->inst_destbasereg = var->inst_basereg;
                                                        ins->inst_offset = var->inst_offset;
+                                                       spec = INS_INFO (ins->opcode);
                                                } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
                                                        ins->opcode = store_opcode;
                                                        ins->inst_destbasereg = var->inst_basereg;
@@ -10308,6 +10588,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        spec2 [MONO_INST_DEST] = ' ';
                                                        spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
                                                        spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
+                                                       spec2 [MONO_INST_SRC3] = ' ';
                                                        spec = spec2;
                                                } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
                                                        // FIXME: The backends expect the base reg to be in inst_basereg
@@ -10324,6 +10605,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                        /* Insert it after the instruction */
                                                        mono_bblock_insert_after_ins (bb, ins, store_ins);
 
+                                                       def_ins = store_ins;
+
                                                        /* 
                                                         * We can't assign ins->dreg to var->dreg here, since the
                                                         * sregs could use it. So set a flag, and do it after
@@ -10334,26 +10617,33 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                }
                                        }
                                }
+
+                               if (def_ins && !live_range_start [dreg]) {
+                                       live_range_start [dreg] = def_ins;
+                                       live_range_start_bb [dreg] = bb;
+                               }
                        }
 
                        /************/
                        /*  SREGS   */
                        /************/
-                       for (srcindex = 0; srcindex < 2; ++srcindex) {
-                               regtype = spec [(srcindex == 0) ? MONO_INST_SRC1 : MONO_INST_SRC2];
-                               sreg = srcindex == 0 ? ins->sreg1 : ins->sreg2;
+                       num_sregs = mono_inst_get_src_registers (ins, sregs);
+                       for (srcindex = 0; srcindex < 3; ++srcindex) {
+                               regtype = spec [MONO_INST_SRC1 + srcindex];
+                               sreg = sregs [srcindex];
 
                                g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
                                if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
                                        MonoInst *var = get_vreg_to_inst (cfg, sreg);
+                                       MonoInst *use_ins = ins;
                                        MonoInst *load_ins;
                                        guint32 load_opcode;
 
                                        if (var->opcode == OP_REGVAR) {
-                                               if (srcindex == 0)
-                                                       ins->sreg1 = var->dreg;
-                                               else
-                                                       ins->sreg2 = var->dreg;
+                                               sregs [srcindex] = var->dreg;
+                                               //mono_inst_set_src_registers (ins, sregs);
+                                               live_range_end [sreg] = use_ins;
+                                               live_range_end_bb [sreg] = bb;
                                                continue;
                                        }
 
@@ -10364,24 +10654,26 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        g_assert (load_opcode != OP_LOADV_MEMBASE);
 
                                        if (vreg_to_lvreg [sreg]) {
+                                               g_assert (vreg_to_lvreg [sreg] != -1);
+
                                                /* The variable is already loaded to an lvreg */
                                                if (G_UNLIKELY (cfg->verbose_level > 2))
                                                        printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
-                                               if (srcindex == 0)
-                                                       ins->sreg1 = vreg_to_lvreg [sreg];
-                                               else
-                                                       ins->sreg2 = vreg_to_lvreg [sreg];
+                                               sregs [srcindex] = vreg_to_lvreg [sreg];
+                                               //mono_inst_set_src_registers (ins, sregs);
                                                continue;
                                        }
 
                                        /* Try to fuse the load into the instruction */
                                        if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
                                                ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
-                                               ins->inst_basereg = var->inst_basereg;
+                                               sregs [0] = var->inst_basereg;
+                                               //mono_inst_set_src_registers (ins, sregs);
                                                ins->inst_offset = var->inst_offset;
                                        } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
                                                ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
-                                               ins->sreg2 = var->inst_basereg;
+                                               sregs [1] = var->inst_basereg;
+                                               //mono_inst_set_src_registers (ins, sregs);
                                                ins->inst_offset = var->inst_offset;
                                        } else {
                                                if (MONO_IS_REAL_MOVE (ins)) {
@@ -10401,35 +10693,43 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                                                         */
                                                                        sreg = ins->dreg;
                                                                }
+                                                               g_assert (sreg != -1);
                                                                vreg_to_lvreg [var->dreg] = sreg;
                                                                g_assert (lvregs_len < 1024);
                                                                lvregs [lvregs_len ++] = var->dreg;
                                                        }
                                                }
 
-                                               if (srcindex == 0)
-                                                       ins->sreg1 = sreg;
-                                               else
-                                                       ins->sreg2 = sreg;
+                                               sregs [srcindex] = sreg;
+                                               //mono_inst_set_src_registers (ins, sregs);
 
                                                if (regtype == 'l') {
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
+                                                       use_ins = load_ins;
                                                }
                                                else {
-#if SIZEOF_VOID_P == 4
+#if SIZEOF_REGISTER == 4
                                                        g_assert (load_opcode != OP_LOADI8_MEMBASE);
 #endif
                                                        NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
+                                                       use_ins = load_ins;
                                                }
                                        }
+
+                                       if (var->dreg < orig_next_vreg) {
+                                               live_range_end [var->dreg] = use_ins;
+                                               live_range_end_bb [var->dreg] = bb;
+                                       }
                                }
                        }
+                       mono_inst_set_src_registers (ins, sregs);
 
                        if (dest_has_lvreg) {
+                               g_assert (ins->dreg != -1);
                                vreg_to_lvreg [prev_dreg] = ins->dreg;
                                g_assert (lvregs_len < 1024);
                                lvregs [lvregs_len ++] = prev_dreg;
@@ -10447,12 +10747,44 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                for (i = 0; i < lvregs_len; i++)
                                        vreg_to_lvreg [lvregs [i]] = 0;
                                lvregs_len = 0;
+                       } else if (ins->opcode == OP_NOP) {
+                               ins->dreg = -1;
+                               MONO_INST_NULLIFY_SREGS (ins);
                        }
 
                        if (cfg->verbose_level > 2)
                                mono_print_ins_index (1, ins);
                }
        }
+       
+#ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
+       /*
+        * 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);
+               }
+       }
+#endif
+
+       g_free (live_range_start);
+       g_free (live_range_end);
+       g_free (live_range_start_bb);
+       g_free (live_range_end_bb);
 }
 
 /**
@@ -10530,13 +10862,8 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
  *   fcompare + branchCC.
  * - create a helper function for allocating a stack slot, taking into account 
  *   MONO_CFG_HAS_SPILLUP.
- * - merge new GC changes in mini.c.
  * - merge r68207.
  * - merge the ia64 switch changes.
- * - merge the mips conditional changes.
- * - remove unused opcodes from mini-ops.h, remove "op_" from the opcode names,
- *   remove the op_ opcodes from the cpu-..md files, clean up the cpu-..md files.
- * - make the cpu_ tables smaller when the usage of the cee_ opcodes is removed.
  * - optimize mono_regstate2_alloc_int/float.
  * - fix the pessimistic handling of variables accessed in exception handler blocks.
  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
@@ -10547,8 +10874,6 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
  * - LAST MERGE: 108395.
  * - when returning vtypes in registers, generate IR and append it to the end of the
  *   last bb instead of doing it in the epilog.
- * - when the new JIT is done, use the ins emission macros in ir-emit.h instead of the 
- *   ones in inssel.h.
  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
  */