2008-07-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 49204c627be81a82cccc5e8603c4f117af31f2a2..d18a3f2f14169f9b4f8b8e47366a5a3dd68093c1 100644 (file)
@@ -64,6 +64,7 @@
 #include <mono/utils/mono-counters.h>
 #include <mono/utils/mono-logger.h>
 #include <mono/utils/mono-mmap.h>
+#include <mono/utils/dtrace.h>
 
 #include "mini.h"
 #include <string.h>
        } while (0)
 #define GENERIC_SHARING_FAILURE(opcode) do {           \
                if (cfg->generic_sharing_context) {     \
-                       /*g_print ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__)*/; \
+            if (cfg->verbose_level > 1) \
+                           printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
                        cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
                        goto exception_exit;    \
                }                       \
                if (method->klass->valuetype)   \
                        GENERIC_SHARING_FAILURE ((opcode)); \
        } while (0)
+#define GET_RGCTX(rgctx, context_used) do {                                            \
+               MonoInst *this = NULL;                                  \
+               g_assert (context_used);                                \
+               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
+               if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&       \
+                               !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
+                       NEW_ARGLOAD (cfg, this, 0);                     \
+               (rgctx) = get_runtime_generic_context (cfg, method, (context_used), this, ip); \
+       } while (0)
+
 
 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
@@ -130,6 +142,10 @@ static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *de
 
 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
 
+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);
+
 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
                   int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
                   guint inline_offset, gboolean is_virtual_call);
@@ -140,10 +156,11 @@ handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, Mon
 #endif
 
 /* helper methods signature */
-static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
-static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
-static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
-static MonoMethodSignature *helper_sig_domain_get = NULL;
+/* FIXME: Make these static again */
+MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
+MonoMethodSignature *helper_sig_domain_get = NULL;
+MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
 
 static guint32 default_opt = 0;
 static gboolean default_opt_set = FALSE;
@@ -159,6 +176,14 @@ gboolean mono_break_on_exc = FALSE;
 #ifndef DISABLE_AOT
 gboolean mono_compile_aot = FALSE;
 #endif
+/* If this is set, no code is generated dynamically, everything is taken from AOT files */
+gboolean mono_aot_only = FALSE;
+/* Whenever to use IMT */
+#ifdef MONO_ARCH_HAVE_IMT
+gboolean mono_use_imt = TRUE;
+#else
+gboolean mono_use_imt = FALSE;
+#endif
 MonoMethodDesc *mono_inject_async_exc_method = NULL;
 int mono_inject_async_exc_pos;
 MonoMethodDesc *mono_break_at_bb_method = NULL;
@@ -174,7 +199,8 @@ static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
 
 static MonoCodeManager *global_codeman = NULL;
 
-static GHashTable *jit_icall_name_hash = NULL;
+/* FIXME: Make this static again */
+GHashTable *jit_icall_name_hash = NULL;
 
 static MonoDebugOptions debug_options;
 
@@ -193,6 +219,9 @@ mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
 /* Whenever to check for pending exceptions in managed-to-native wrappers */
 gboolean check_for_pending_exc = TRUE;
 
+/* Whenever to disable passing/returning small valuetypes in registers for managed methods */
+gboolean disable_vtypes_in_regs = FALSE;
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -364,6 +393,9 @@ void *mono_global_codeman_reserve (int size)
 {
        void *ptr;
 
+       if (mono_aot_only)
+               g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
+
        if (!global_codeman) {
                /* This can happen during startup */
                global_codeman = mono_code_manager_new ();
@@ -401,11 +433,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
  * dfn: Depth First Number
  * block_num: unique ID assigned at bblock creation
  */
-#define NEW_BBLOCK(cfg,new_bb) do {    \
-               new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); \
-               MONO_INST_LIST_INIT (&new_bb->ins_list); \
-       } while (0)
-
+#define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
 #define ADD_BBLOCK(cfg,b) do { \
                cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
                (b)->block_num = cfg->num_bblocks++;    \
@@ -416,19 +444,17 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
                if (!(tblock)) {        \
                        if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
-                       NEW_BBLOCK (cfg, (tblock));     \
+                       (tblock) = NEW_BBLOCK (cfg);    \
                        (tblock)->cil_code = (ip);      \
                        ADD_BBLOCK (cfg, (tblock));     \
                } \
        } while (0)
 
 #define CHECK_BBLOCK(target,ip,tblock) do {    \
-               if ((target) < (ip) && \
-                               MONO_INST_LIST_EMPTY (&(tblock)->ins_list)) { \
-                       bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
-                       if (cfg->verbose_level > 2) \
-                               g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code)); \
-               } \
+               if ((target) < (ip) && !(tblock)->code) {       \
+                       bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
+                       if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code));     \
+               }       \
        } while (0)
 
 #define NEW_ICONST(cfg,dest,val) do {  \
@@ -439,8 +465,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_PCONST(cfg,dest,val) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_PCONST;     \
+               MONO_INST_NEW ((cfg), (dest), OP_PCONST);       \
                (dest)->inst_p0 = (val);        \
                (dest)->type = STACK_PTR;       \
        } while (0)
@@ -449,14 +474,13 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #ifdef MONO_ARCH_NEED_GOT_VAR
 
 #define NEW_PATCH_INFO(cfg,dest,el1,el2) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_PATCH_INFO; \
+               MONO_INST_NEW ((cfg), (dest), OP_PATCH_INFO);   \
                (dest)->inst_left = (gpointer)(el1);    \
                (dest)->inst_right = (gpointer)(el2);   \
        } while (0)
 
 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {                    \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP); \
                (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
                if (cfg->compile_aot) {                                 \
                        MonoInst *group, *got_var, *got_loc;            \
@@ -474,8 +498,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
                MonoInst *group, *got_var, *got_loc;                    \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
-               (dest)->opcode = OP_GOT_ENTRY;                          \
+               MONO_INST_NEW ((cfg), (dest), OP_GOT_ENTRY); \
                got_loc = mono_get_got_var (cfg);                       \
                NEW_TEMPLOAD ((cfg), got_var, got_loc->inst_c0);        \
                NEW_PATCH_INFO ((cfg), group, NULL, patch_type);        \
@@ -489,7 +512,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #else
 
 #define NEW_AOTCONST(cfg,dest,patch_type,cons) do {    \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST;    \
                (dest)->inst_p0 = (cons);       \
                (dest)->inst_i1 = (gpointer)(patch_type); \
@@ -497,8 +520,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
     } while (0)
 
 #define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_AOTCONST;   \
+               MONO_INST_NEW ((cfg), (dest), OP_AOTCONST);     \
                (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
                (dest)->inst_p1 = (gpointer)(patch_type); \
                (dest)->type = (stack_type);    \
@@ -547,7 +569,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_ARGLOAD(cfg,dest,num) do { \
                 if (arg_array [(num)]->opcode == OP_ICONST) (dest) = arg_array [(num)]; else { \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->ssa_op = MONO_SSA_LOAD; \
                (dest)->inst_i0 = arg_array [(num)];    \
                (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
@@ -556,7 +578,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        }} while (0)
 
 #define NEW_LOCLOAD(cfg,dest,num) do { \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->ssa_op = MONO_SSA_LOAD; \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
                (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
@@ -565,11 +587,10 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_LOCLOADA(cfg,dest,num) do {        \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
                (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
-               (dest)->opcode = OP_LDADDR;     \
                (dest)->type = STACK_MP;        \
                (dest)->klass = (dest)->inst_i0->klass; \
         if (!MONO_TYPE_ISSTRUCT (header->locals [(num)])) \
@@ -578,14 +599,14 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_RETLOADA(cfg,dest) do {    \
         if (cfg->vret_addr) { \
-                   (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));   \
+                   MONO_INST_NEW ((cfg), (dest), OP_NOP);      \
                    (dest)->ssa_op = MONO_SSA_LOAD;     \
                    (dest)->inst_i0 = cfg->vret_addr; \
                    (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
             (dest)->type = STACK_MP; \
                    (dest)->klass = (dest)->inst_i0->klass;     \
         } else { \
-                       (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+                       MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                    (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;    \
                    (dest)->inst_i0 = (cfg)->ret;       \
                    (dest)->inst_i0->flags |= MONO_INST_INDIRECT;       \
@@ -598,18 +619,17 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_ARGLOADA(cfg,dest,num) do {        \
                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
                (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = arg_array [(num)];    \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
-               (dest)->opcode = OP_LDADDR;     \
                (dest)->type = STACK_MP;        \
                (dest)->klass = (dest)->inst_i0->klass; \
                 (cfg)->disable_ssa = TRUE; \
        } while (0)
 
 #define NEW_TEMPLOAD(cfg,dest,num) do {        \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->ssa_op = MONO_SSA_LOAD; \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
                (dest)->opcode = mini_type_to_ldind ((cfg), (dest)->inst_i0->inst_vtype); \
@@ -618,20 +638,18 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_TEMPLOADA(cfg,dest,num) do {       \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_LDADDR);       \
                (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
-               (dest)->opcode = OP_LDADDR;     \
                (dest)->type = STACK_MP;        \
                (dest)->klass = (dest)->inst_i0->klass; \
         if (!MONO_TYPE_ISSTRUCT (cfg->varinfo [(num)]->inst_vtype)) \
            (cfg)->disable_ssa = TRUE; \
        } while (0)
 
-
 #define NEW_INDLOAD(cfg,dest,addr,vtype) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->inst_left = addr;       \
                (dest)->opcode = mini_type_to_ldind ((cfg), vtype);     \
                type_to_eval_stack_type ((cfg), vtype, (dest)); \
@@ -639,7 +657,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_INDSTORE(cfg,dest,addr,value,vtype) do {   \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->inst_i0 = addr; \
                (dest)->opcode = mini_type_to_stind ((cfg), vtype);     \
                (dest)->inst_i1 = (value);      \
@@ -647,7 +665,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_TEMPSTORE(cfg,dest,num,inst) do {  \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->ssa_op = MONO_SSA_STORE;        \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
                (dest)->opcode = mini_type_to_stind ((cfg), (dest)->inst_i0->inst_vtype); \
@@ -656,7 +674,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_LOCSTORE(cfg,dest,num,inst) do {   \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->opcode = mini_type_to_stind ((cfg), header->locals [(num)]); \
                (dest)->ssa_op = MONO_SSA_STORE;        \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
@@ -666,7 +684,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_ARGSTORE(cfg,dest,num,inst) do {   \
                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_NOP);  \
                (dest)->opcode = mini_type_to_stind ((cfg), param_types [(num)]); \
                (dest)->ssa_op = MONO_SSA_STORE;        \
                (dest)->inst_i0 = arg_array [(num)];    \
@@ -678,7 +696,6 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                MONO_INST_NEW (cfg, dest, OP_MEMCPY); \
         (dest)->inst_left = (dst); \
                (dest)->inst_right = (src); \
-               (dest)->cil_code = ip; \
         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
                (dest)->backend.memcpy_args->size = (memcpy_size); \
                (dest)->backend.memcpy_args->align = (memcpy_align); \
@@ -688,39 +705,42 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                MONO_INST_NEW (cfg, dest, OP_MEMSET); \
         (dest)->inst_left = (dst); \
                (dest)->inst_imm = (imm); \
-               (dest)->cil_code = ip; \
         (dest)->backend.memcpy_args = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoMemcpyArgs)); \
                (dest)->backend.memcpy_args->size = (memcpy_size); \
                (dest)->backend.memcpy_args->align = (memcpy_align); \
     } while (0)
 
 #define NEW_DUMMY_USE(cfg,dest,load) do { \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_DUMMY_USE; \
+               MONO_INST_NEW ((cfg), (dest), OP_DUMMY_USE);    \
                (dest)->inst_left = (load); \
     } while (0)
 
 #define NEW_DUMMY_STORE(cfg,dest,num) do { \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               MONO_INST_NEW ((cfg), (dest), OP_DUMMY_STORE);  \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
-               (dest)->opcode = OP_DUMMY_STORE; \
                (dest)->klass = (dest)->inst_i0->klass; \
        } while (0)
 
 #define ADD_BINOP(op) do {     \
                MONO_INST_NEW (cfg, ins, (op)); \
-               ins->cil_code = ip;     \
                sp -= 2;        \
                ins->inst_i0 = sp [0];  \
                ins->inst_i1 = sp [1];  \
                *sp++ = ins;    \
                type_from_op (ins);     \
                CHECK_TYPE (ins);       \
+               /* Have to insert a widening op */               \
+               /* FIXME: Need to add many more cases */ \
+               if (ins->inst_i0->type == STACK_PTR && ins->inst_i1->type == STACK_I4) { \
+                       MonoInst *widen;  \
+                       MONO_INST_NEW (cfg, widen, CEE_CONV_I); \
+            widen->inst_i0 = ins->inst_i1; \
+                       ins->inst_i1 = widen; \
+               } \
        } while (0)
 
 #define ADD_UNOP(op) do {      \
                MONO_INST_NEW (cfg, ins, (op)); \
-               ins->cil_code = ip;     \
                sp--;   \
                ins->inst_i0 = sp [0];  \
                *sp++ = ins;    \
@@ -793,8 +813,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_LDELEMA(cfg,dest,sp,k) do {        \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = CEE_LDELEMA;   \
+               MONO_INST_NEW ((cfg), (dest), CEE_LDELEMA);     \
                (dest)->inst_left = (sp) [0];   \
                (dest)->inst_right = (sp) [1];  \
                (dest)->type = STACK_MP;        \
@@ -803,8 +822,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
        } while (0)
 
 #define NEW_GROUP(cfg,dest,el1,el2) do {       \
-               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->opcode = OP_GROUP;      \
+               MONO_INST_NEW ((cfg), (dest), OP_GROUP);        \
                (dest)->inst_left = (el1);      \
                (dest)->inst_right = (el2);     \
        } while (0)
@@ -886,7 +904,7 @@ link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
  *
  *   Unlink two basic blocks.
  */
-static void
+void
 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
 {
        int i, pos;
@@ -927,6 +945,24 @@ mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
        }
 }
 
+/*
+ * mono_bblocks_linked:
+ *
+ *   Return whenever BB1 and BB2 are linked in the CFG.
+ */
+static gboolean
+mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
+{
+       int i;
+
+       for (i = 0; i < bb1->out_count; ++i) {
+               if (bb1->out_bb [i] == bb2)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 /**
  * mono_find_block_region:
  *
@@ -1052,7 +1088,7 @@ df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
        int i;
 
        array [*dfn] = start;
-       /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
+       /* g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num); */
        for (i = 0; i < start->out_count; ++i) {
                if (start->out_bb [i]->dfn)
                        continue;
@@ -1088,7 +1124,7 @@ split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
        MonoInst *inst;
        MonoBasicBlock *bb;
 
-       if (!MONO_INST_LIST_EMPTY (&second->ins_list))
+       if (second->code)
                return;
        
        /* 
@@ -1110,33 +1146,23 @@ split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
        first->out_bb = NULL;
        link_bblock (cfg, first, second);
 
+       second->last_ins = first->last_ins;
+
        /*g_print ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
        MONO_BB_FOR_EACH_INS (first, inst) {
-               MonoInst *inst_next;
-
                /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
                g_print ("found %p: %s", inst->next->cil_code, code);
                g_free (code);*/
-               if (inst->cil_code >= second->cil_code)
-                       continue;
-
-               inst_next = mono_inst_list_next (&inst->node, &first->ins_list);
-               if (!inst_next)
-                       break;
-
-               if (inst_next->cil_code < second->cil_code)
-                       continue;
-                       
-               second->ins_list.next = inst->node.next;
-               second->ins_list.prev = first->ins_list.prev;
-               inst->node.next = &first->ins_list;
-               first->ins_list.prev = &inst->node;
-
-               second->next_bb = first->next_bb;
-               first->next_bb = second;
-               return;
+               if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
+                       second->code = inst->next;
+                       inst->next = NULL;
+                       first->last_ins = inst;
+                       second->next_bb = first->next_bb;
+                       first->next_bb = second;
+                       return;
+               }
        }
-       if (MONO_INST_LIST_EMPTY (&second->ins_list)) {
+       if (!second->code) {
                g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
                //G_BREAKPOINT ();
        }
@@ -1176,6 +1202,130 @@ reverse_branch_op (guint32 opcode)
        return opcode;
 }
 
+guint
+mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
+{
+       if (type->byref)
+               return OP_STORE_MEMBASE_REG;
+
+handle_enum:
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+               return OP_STOREI1_MEMBASE_REG;
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
+               return OP_STOREI2_MEMBASE_REG;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+               return OP_STOREI4_MEMBASE_REG;
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+               return OP_STORE_MEMBASE_REG;
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_ARRAY:    
+               return OP_STORE_MEMBASE_REG;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               return OP_STOREI8_MEMBASE_REG;
+       case MONO_TYPE_R4:
+               return OP_STORER4_MEMBASE_REG;
+       case MONO_TYPE_R8:
+               return OP_STORER8_MEMBASE_REG;
+       case MONO_TYPE_VALUETYPE:
+               if (type->data.klass->enumtype) {
+                       type = type->data.klass->enum_basetype;
+                       goto handle_enum;
+               }
+               return OP_STOREV_MEMBASE;
+       case MONO_TYPE_TYPEDBYREF:
+               return OP_STOREV_MEMBASE;
+       case MONO_TYPE_GENERICINST:
+               type = &type->data.generic_class->container_class->byval_arg;
+               goto handle_enum;
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               /* FIXME: all the arguments must be references for now,
+                * later look inside cfg and see if the arg num is
+                * really a reference
+                */
+               g_assert (cfg->generic_sharing_context);
+               return OP_STORE_MEMBASE_REG;
+       default:
+               g_error ("unknown type 0x%02x in type_to_store_membase", type->type);
+       }
+       return -1;
+}
+
+guint
+mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
+{
+       if (type->byref)
+               return OP_LOAD_MEMBASE;
+
+       switch (mono_type_get_underlying_type (type)->type) {
+       case MONO_TYPE_I1:
+               return OP_LOADI1_MEMBASE;
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+               return OP_LOADU1_MEMBASE;
+       case MONO_TYPE_I2:
+               return OP_LOADI2_MEMBASE;
+       case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
+               return OP_LOADU2_MEMBASE;
+       case MONO_TYPE_I4:
+               return OP_LOADI4_MEMBASE;
+       case MONO_TYPE_U4:
+               return OP_LOADU4_MEMBASE;
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+               return OP_LOAD_MEMBASE;
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_ARRAY:    
+               return OP_LOAD_MEMBASE;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               return OP_LOADI8_MEMBASE;
+       case MONO_TYPE_R4:
+               return OP_LOADR4_MEMBASE;
+       case MONO_TYPE_R8:
+               return OP_LOADR8_MEMBASE;
+       case MONO_TYPE_VALUETYPE:
+       case MONO_TYPE_TYPEDBYREF:
+               return OP_LOADV_MEMBASE;
+       case MONO_TYPE_GENERICINST:
+               if (mono_type_generic_inst_is_valuetype (type))
+                       return OP_LOADV_MEMBASE;
+               else
+                       return OP_LOAD_MEMBASE;
+               break;
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               /* FIXME: all the arguments must be references for now,
+                * later look inside cfg and see if the arg num is
+                * really a reference
+                */
+               g_assert (cfg->generic_sharing_context);
+               return OP_LOAD_MEMBASE;
+       default:
+               g_error ("unknown type 0x%02x in type_to_load_membase", type->type);
+       }
+       return -1;
+}
+
 #ifdef MONO_ARCH_SOFT_FLOAT
 static int
 condbr_to_fp_br (int opcode)
@@ -1588,6 +1738,86 @@ stelem_to_stind [] = {
        CEE_STIND_REF
 };
 
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+static void
+handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
+{
+       MonoInst *iargs [2];
+       iargs [0] = val;
+       iargs [1] = ptr;
+
+       mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
+}
+
+static int
+handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
+{
+       MonoInst *iargs [1];
+       iargs [0] = ptr;
+
+       return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
+}
+
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
+                       int temp;       \
+                       NEW_LOCLOADA (cfg, (ins), (idx));       \
+                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
+                       NEW_TEMPLOAD (cfg, (ins), temp);        \
+               }       \
+       } while (0)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
+                       NEW_LOCLOADA (cfg, (ins), (idx));       \
+                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
+                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
+               }       \
+       } while (0)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+                       int temp;       \
+                       NEW_ARGLOADA (cfg, (ins), (idx));       \
+                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
+                       NEW_TEMPLOAD (cfg, (ins), temp);        \
+               }       \
+       } while (0)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+                       NEW_ARGLOADA (cfg, (ins), (idx));       \
+                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
+                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
+               }       \
+       } while (0)
+
+#define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip) do {            \
+       if ((ins)->opcode == CEE_LDIND_R4) {                                            \
+           int idx = (num);                                                                            \
+           int temp;                                                                                   \
+           NEW_TEMPLOADA (cfg, (ins), (idx));                                                  \
+               temp = handle_load_float (cfg, (bblock), (ins), ip);            \
+               NEW_TEMPLOAD (cfg, (ins), (temp));                                                      \
+       }                                                                                                                               \
+       } while (0)
+
+#define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip) do {               \
+       if ((ins)->opcode == CEE_STIND_R4) {                                                            \
+           int idx = (num);                                                                            \
+               NEW_TEMPLOADA (cfg, (ins), (idx)); \
+               handle_store_float ((cfg), (bblock), (ins), (val), (ip));       \
+       } \
+       } while (0)
+
+#else
+
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#define NEW_TEMPLOAD_SOFT_FLOAT(cfg,bblock,ins,num,ip)
+#define NEW_TEMPSTORE_SOFT_FLOAT(cfg,bblock,ins,num,val,ip)
+#endif
+
 #if 0
 
 static const char
@@ -1666,7 +1896,7 @@ mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
        return mono_type_to_ldind (type);
 }
 
-static guint
+guint
 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
 {
        if (cfg->generic_sharing_context && !type->byref) {
@@ -1685,7 +1915,11 @@ mono_op_imm_to_op (int opcode)
 {
        switch (opcode) {
        case OP_ADD_IMM:
-               return OP_PADD;
+#if SIZEOF_VOID_P == 4
+               return OP_IADD;
+#else
+               return OP_LADD;
+#endif
        case OP_IADD_IMM:
                return OP_IADD;
        case OP_LADD_IMM:
@@ -1760,9 +1994,12 @@ mono_op_imm_to_op (int opcode)
                return OP_COMPARE;
        case OP_ICOMPARE_IMM:
                return OP_ICOMPARE;
+       case OP_LOCALLOC_IMM:
+               return OP_LOCALLOC;
        default:
                printf ("%s\n", mono_inst_name (opcode));
                g_assert_not_reached ();
+               return -1;
        }
 }
 
@@ -1772,16 +2009,21 @@ mono_op_imm_to_op (int opcode)
  *   Replace the OP_.._IMM INS with its non IMM variant.
  */
 void
-mono_decompose_op_imm (MonoCompile *cfg, MonoInst *ins)
+mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
 {
        MonoInst *temp;
 
        MONO_INST_NEW (cfg, temp, OP_ICONST);
        temp->inst_c0 = ins->inst_imm;
        temp->dreg = mono_regstate_next_int (cfg->rs);
-       MONO_INST_LIST_ADD_TAIL (&(temp)->node, &(ins)->node);
+       mono_bblock_insert_before_ins (bb, ins, temp);
        ins->opcode = mono_op_imm_to_op (ins->opcode);
-       ins->sreg2 = temp->dreg;
+       if (ins->opcode == OP_LOCALLOC)
+               ins->sreg1 = temp->dreg;
+       else
+               ins->sreg2 = temp->dreg;
+
+       bb->max_vreg = MAX (bb->max_vreg, cfg->rs->next_vreg);
 }
 
 /*
@@ -1817,7 +2059,7 @@ mono_get_got_var (MonoCompile *cfg)
 }
 
 static MonoInst *
-mono_get_rgctx_var (MonoCompile *cfg)
+mono_get_vtable_var (MonoCompile *cfg)
 {
        g_assert (cfg->generic_sharing_context);
 
@@ -1830,40 +2072,133 @@ mono_get_rgctx_var (MonoCompile *cfg)
        return cfg->rgctx_var;
 }
 
+static void
+set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
+{
+       if (vreg >= cfg->vreg_to_inst_len) {
+               MonoInst **tmp = cfg->vreg_to_inst;
+               int size = cfg->vreg_to_inst_len;
+
+               while (vreg >= cfg->vreg_to_inst_len)
+                       cfg->vreg_to_inst_len = cfg->vreg_to_inst_len ? cfg->vreg_to_inst_len * 2 : 32;
+               cfg->vreg_to_inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->vreg_to_inst_len);
+               if (size)
+                       memcpy (cfg->vreg_to_inst, tmp, size * sizeof (MonoInst*));
+       }
+       cfg->vreg_to_inst [vreg] = inst;
+}
+
+#define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
+#define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
+
 MonoInst*
-mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
+mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
 {
        MonoInst *inst;
        int num = cfg->num_varinfo;
+       gboolean regpair;
 
        if ((num + 1) >= cfg->varinfo_count) {
                int orig_count = cfg->varinfo_count;
-               cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
+               cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
                cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
                cfg->vars = (MonoMethodVar *)g_realloc (cfg->vars, sizeof (MonoMethodVar) * cfg->varinfo_count);
                memset (&cfg->vars [orig_count], 0, (cfg->varinfo_count - orig_count) * sizeof (MonoMethodVar));
        }
 
-       /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
        mono_jit_stats.allocate_var++;
 
        MONO_INST_NEW (cfg, inst, opcode);
        inst->inst_c0 = num;
        inst->inst_vtype = type;
        inst->klass = mono_class_from_mono_type (type);
+       type_to_eval_stack_type (cfg, type, inst);
        /* if set to 1 the variable is native */
        inst->backend.is_pinvoke = 0;
+       inst->dreg = vreg;
 
        cfg->varinfo [num] = inst;
 
        MONO_INIT_VARINFO (&cfg->vars [num], num);
 
+       if (vreg != -1)
+               set_vreg_to_inst (cfg, vreg, inst);
+
+#if SIZEOF_VOID_P == 4
+#ifdef MONO_ARCH_SOFT_FLOAT
+       regpair = mono_type_is_long (type) || mono_type_is_float (type);
+#else
+       regpair = mono_type_is_long (type);
+#endif
+#else
+       regpair = FALSE;
+#endif
+
+       if (regpair) {
+               MonoInst *tree;
+
+               /* 
+                * These two cannot be allocated using create_var_for_vreg since that would
+                * put it into the cfg->varinfo array, confusing many parts of the JIT.
+                */
+
+               /* 
+                * Set flags to VOLATILE so SSA skips it.
+                */
+
+               if (cfg->verbose_level >= 4) {
+                       printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
+               }
+
+               /* Allocate a dummy MonoInst for the first vreg */
+               MONO_INST_NEW (cfg, tree, OP_LOCAL);
+               tree->dreg = inst->dreg + 1;
+               if (cfg->opt & MONO_OPT_SSA)
+                       tree->flags = MONO_INST_VOLATILE;
+               tree->inst_c0 = num;
+               tree->type = STACK_I4;
+               tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
+               tree->klass = mono_class_from_mono_type (tree->inst_vtype);
+
+               set_vreg_to_inst (cfg, inst->dreg + 1, tree);
+
+               /* Allocate a dummy MonoInst for the second vreg */
+               MONO_INST_NEW (cfg, tree, OP_LOCAL);
+               tree->dreg = inst->dreg + 2;
+               if (cfg->opt & MONO_OPT_SSA)
+                       tree->flags = MONO_INST_VOLATILE;
+               tree->inst_c0 = num;
+               tree->type = STACK_I4;
+               tree->inst_vtype = &mono_defaults.int32_class->byval_arg;
+               tree->klass = mono_class_from_mono_type (tree->inst_vtype);
+
+               set_vreg_to_inst (cfg, inst->dreg + 2, tree);
+       }
+
        cfg->num_varinfo++;
        if (cfg->verbose_level > 2)
-               g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
+               g_print ("created temp %d (R%d) of type %s\n", num, vreg, mono_type_get_name (type));
        return inst;
 }
 
+MonoInst*
+mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
+{
+       int dreg;
+
+       if (mono_type_is_long (type))
+               dreg = mono_alloc_dreg (cfg, STACK_I8);
+#ifdef MONO_ARCH_SOFT_FLOAT
+       else if (mono_type_is_float (type))
+               dreg = mono_alloc_dreg (cfg, STACK_R8);
+#endif
+       else
+               /* All the others are unified */
+               dreg = mono_alloc_preg (cfg);
+
+       return mono_compile_create_var_for_vreg (cfg, type, opcode, dreg);
+}
+
 /*
  * Transform a MonoInst into a load from the variable of index var_index.
  */
@@ -1978,18 +2313,181 @@ array_access_to_klass (int opcode, MonoInst *array_obj)
        return NULL;
 }
 
+/*
+ * mono_add_ins_to_end:
+ *
+ *   Same as MONO_ADD_INS, but add INST before any branches at the end of BB.
+ */
 void
 mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
 {
-       MonoInst *last = mono_inst_list_last (&bb->ins_list);
+       int opcode;
 
-       if (last && ((last->opcode >= CEE_BEQ &&
-                       last->opcode <= CEE_BLT_UN) ||
-                       last->opcode == OP_BR ||
-                       last->opcode == OP_SWITCH)) {
-               MONO_INST_LIST_ADD_TAIL (&inst->node, &last->node);
-       } else {
+       if (!bb->code) {
                MONO_ADD_INS (bb, inst);
+               return;
+       }
+
+       switch (bb->last_ins->opcode) {
+       case OP_BR:
+       case OP_BR_REG:
+       case CEE_BEQ:
+       case CEE_BGE:
+       case CEE_BGT:
+       case CEE_BLE:
+       case CEE_BLT:
+       case CEE_BNE_UN:
+       case CEE_BGE_UN:
+       case CEE_BGT_UN:
+       case CEE_BLE_UN:
+       case CEE_BLT_UN:
+       case OP_SWITCH:
+               mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
+               break;
+       default:
+               if (MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
+                       /* Need to insert the ins before the compare */
+                       if (bb->code == bb->last_ins) {
+                               mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
+                               return;
+                       }
+
+                       if (bb->code->next == bb->last_ins) {
+                               /* Only two instructions */
+                               opcode = bb->code->opcode;
+
+                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
+                                       /* NEW IR */
+                                       mono_bblock_insert_before_ins (bb, bb->code, inst);
+                               } else {
+                                       mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
+                               }
+                       } else {
+                               opcode = bb->last_ins->prev->opcode;
+
+                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
+                                       /* NEW IR */
+                                       mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
+                               } else {
+                                       mono_bblock_insert_before_ins (bb, bb->last_ins, inst);
+                               }                                       
+                       }
+               }
+               else
+                       MONO_ADD_INS (bb, inst);
+               break;
+       }
+}
+
+/**
+ * mono_replace_ins:
+ *
+ *   Replace INS with its decomposition which is stored in a series of bblocks starting
+ * at FIRST_BB and ending at LAST_BB. On enter, PREV points to the predecessor of INS. 
+ * On return, it will be set to the last ins of the decomposition.
+ */
+void
+mono_replace_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **prev, MonoBasicBlock *first_bb, MonoBasicBlock *last_bb)
+{
+       MonoInst *next = ins->next;
+
+       if (next && next->opcode == OP_NOP) {
+               /* Avoid NOPs following branches */
+               ins->next = next->next;
+               next = next->next;
+       }
+
+       if (first_bb == last_bb) {
+               /* 
+                * Only one replacement bb, merge the code into
+                * the current bb.
+                */
+
+               /* Delete links between the first_bb and its successors */
+               while (first_bb->out_count)
+                       mono_unlink_bblock (cfg, first_bb, first_bb->out_bb [0]);
+
+               /* Head */
+               if (*prev) {
+                       (*prev)->next = first_bb->code;
+                       first_bb->code->prev = (*prev);
+               } else {
+                       bb->code = first_bb->code;
+               }
+
+               /* Tail */
+               last_bb->last_ins->next = next;
+               if (next)
+                       next->prev = last_bb->last_ins;
+               else
+                       bb->last_ins = last_bb->last_ins;
+               *prev = last_bb->last_ins;
+       } else {
+               int i, count;
+               MonoBasicBlock **tmp_bblocks, *tmp;
+               MonoInst *last;
+
+               /* Multiple BBs */
+
+               /* Set region */
+               for (tmp = first_bb; tmp; tmp = tmp->next_bb)
+                       tmp->region = bb->region;
+
+               /* Split the original bb */
+               if (ins->next)
+                       ins->next->prev = NULL;
+               ins->next = NULL;
+               bb->last_ins = ins;
+
+               /* Merge the second part of the original bb into the last bb */
+               if (last_bb->last_ins) {
+                       last_bb->last_ins->next = next;
+                       if (next)
+                               next->prev = last_bb->last_ins;
+               } else {
+                       last_bb->code = next;
+               }
+
+               if (next) {
+                       for (last = next; last->next != NULL; last = last->next)
+                               ;
+                       last_bb->last_ins = last;
+               }
+
+               for (i = 0; i < bb->out_count; ++i)
+                       link_bblock (cfg, last_bb, bb->out_bb [i]);
+
+               /* Merge the first (dummy) bb to the original bb */
+               if (*prev) {
+                       (*prev)->next = first_bb->code;
+                       first_bb->code->prev = (*prev);
+               } else {
+                       bb->code = first_bb->code;
+               }
+               bb->last_ins = first_bb->last_ins;
+
+               /* Delete the links between the original bb and its successors */
+               tmp_bblocks = bb->out_bb;
+               count = bb->out_count;
+               for (i = 0; i < count; ++i)
+                       mono_unlink_bblock (cfg, bb, tmp_bblocks [i]);
+
+               /* Add links between the original bb and the first_bb's successors */
+               for (i = 0; i < first_bb->out_count; ++i) {
+                       MonoBasicBlock *out_bb = first_bb->out_bb [i];
+
+                       link_bblock (cfg, bb, out_bb);
+               }
+               /* Delete links between the first_bb and its successors */
+               for (i = 0; i < bb->out_count; ++i) {
+                       MonoBasicBlock *out_bb = bb->out_bb [i];
+
+                       mono_unlink_bblock (cfg, first_bb, out_bb);
+               }
+               last_bb->next_bb = bb->next_bb;
+               bb->next_bb = first_bb->next_bb;
+
+               *prev = NULL;
        }
 }
 
@@ -2023,15 +2521,16 @@ mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest
  * bb->in_stack, if the basic block is before or after the joint point).
  * If the stack merge fails at a join point, cfg->unverifiable is set.
  */
-static int
-handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
+static void
+handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count)
+{
        int i, bindex;
        MonoBasicBlock *outb;
        MonoInst *inst, **locals;
        gboolean found;
 
        if (!count)
-               return 0;
+               return;
        if (cfg->verbose_level > 3)
                g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
 
@@ -2086,8 +2585,10 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                if (outb->flags & BB_EXCEPTION_HANDLER)
                        continue;
                if (outb->in_scount) {
-                       if (outb->in_scount != bb->out_scount)
-                               G_BREAKPOINT ();
+                       if (outb->in_scount != bb->out_scount) {
+                               cfg->unverifiable = TRUE;
+                               return;
+                       }
                        continue; /* check they are the same locals */
                }
                outb->in_scount = count;
@@ -2142,8 +2643,6 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                        bindex ++;
                }
        }
-       
-       return 0;
 }
 
 static int
@@ -2561,7 +3060,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
                     MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
 {
        MonoCallInst *call;
-       MonoInst *arg, *n;
+       MonoInst *arg;
 
        MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
 
@@ -2589,13 +3088,16 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
        type_to_eval_stack_type (cfg, sig->ret, &call->inst);
 
-       MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (arg, n, &call->out_args, node) {
+       for (arg = call->out_args; arg;) {
+               MonoInst *narg = arg->next;
+               arg->next = NULL;
                if (!arg->cil_code)
                        arg->cil_code = ip;
                if (to_end)
                        mono_add_ins_to_end (bblock, arg);
                else
                        MONO_ADD_INS (bblock, arg);
+               arg = narg;
        }
        return call;
 }
@@ -2745,10 +3247,12 @@ mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer fun
 
 static MonoCallInst*
 mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
-               MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip, MonoInst *this)
+               MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg, const guint8 *ip, MonoInst *this)
 {
        MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
 
+       g_assert (!(rgctx_arg && imt_arg));
+
        if (rgctx_arg) {
                switch (call->inst.opcode) {
                case OP_CALL: call->inst.opcode = OP_CALL_RGCTX; break;
@@ -2766,6 +3270,30 @@ mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMetho
                        g_assert (!call->inst.inst_right);
                        call->inst.inst_right = rgctx_arg;
                }
+       } else if (imt_arg) {
+               switch (call->inst.opcode) {
+               case OP_CALLVIRT: call->inst.opcode = OP_CALLVIRT_IMT; break;
+               case OP_VOIDCALLVIRT: call->inst.opcode = OP_VOIDCALLVIRT_IMT; break;
+               case OP_FCALLVIRT: call->inst.opcode = OP_FCALLVIRT_IMT; break;
+               case OP_LCALLVIRT: call->inst.opcode = OP_LCALLVIRT_IMT; break;
+               case OP_VCALLVIRT: {
+                       MonoInst *group;
+
+                       NEW_GROUP (cfg, group, call->inst.inst_left, NULL);
+                       call->inst.inst_left = group;
+                       call->inst.opcode = OP_VCALLVIRT_IMT;
+                       break;
+               }
+               default: g_assert_not_reached ();
+               }
+
+               if (call->inst.opcode != OP_VCALLVIRT_IMT) {
+                       g_assert (!call->inst.inst_right);
+                       call->inst.inst_right = imt_arg;
+               } else {
+                       g_assert (!call->inst.inst_left->inst_right);
+                       call->inst.inst_left->inst_right = imt_arg;
+               }
        }
 
        return call;
@@ -2773,10 +3301,10 @@ mono_emit_rgctx_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMetho
 
 inline static int
 mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
-               MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, const guint8 *ip,
-               MonoInst *this)
+               MonoMethodSignature *signature, MonoInst **args, MonoInst *rgctx_arg, MonoInst *imt_arg,
+               const guint8 *ip, MonoInst *this)
 {
-       MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, ip, this);
+       MonoCallInst *call = mono_emit_rgctx_method_call (cfg, bblock, method, signature, args, rgctx_arg, imt_arg, ip, this);
 
        return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
 }
@@ -2784,8 +3312,8 @@ mono_emit_rgctx_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, M
 static void
 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
 {
-       MonoInst *ins, *temp = NULL, *store, *load;
-       MonoInstList *head, *list;
+       MonoInst *ins, *temp = NULL, *store, *load, *begin;
+       MonoInst *last_arg = NULL;
        int nargs;
        MonoCallInst *call;
 
@@ -2793,7 +3321,6 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
        //mono_print_tree_nl (tree);
        MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (info->sig->ret, FALSE, FALSE, cfg->generic_sharing_context));
        ins = (MonoInst*)call;
-       MONO_INST_LIST_INIT (&ins->node);
        
        call->inst.cil_code = tree->cil_code;
        call->args = iargs;
@@ -2805,7 +3332,6 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
                temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
                temp->flags |= MONO_INST_IS_TEMP;
                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
-               MONO_INST_LIST_INIT (&store->node);
                /* FIXME: handle CEE_STIND_R4 */
                store->cil_code = tree->cil_code;
        } else {
@@ -2814,13 +3340,15 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
 
        nargs = info->sig->param_count + info->sig->hasthis;
 
-       if (nargs) {
-               MONO_INST_LIST_ADD_TAIL (&store->node,
-                                       &call->out_args);
-               list = &call->out_args;
-       } else {
-               list = &store->node;
-       }
+       for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
+
+       if (nargs)
+               last_arg->next = store;
+
+       if (nargs)
+               begin = call->out_args;
+       else
+               begin = store;
 
        if (cfg->prev_ins) {
                /* 
@@ -2828,13 +3356,13 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
                 * node before it is called for its children. dec_foreach needs to
                 * take this into account.
                 */
-               head = &cfg->prev_ins->node;
+               store->next = cfg->prev_ins->next;
+               cfg->prev_ins->next = begin;
        } else {
-               head = &cfg->cbb->ins_list;
+               store->next = cfg->cbb->code;
+               cfg->cbb->code = begin;
        }
 
-       MONO_INST_LIST_SPLICE_INIT (list, head);
-
        call->fptr = mono_icall_get_wrapper (info);
 
        if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
@@ -2901,7 +3429,7 @@ mono_get_array_new_va_signature (int arity)
        for (i = 0; i < arity; i++)
                res->params [i + 1] = &mono_defaults.int_class->byval_arg;
 
-       res->ret = &mono_defaults.int_class->byval_arg;
+       res->ret = &mono_defaults.object_class->byval_arg;
 
        g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
        mono_jit_unlock ();
@@ -2909,64 +3437,30 @@ mono_get_array_new_va_signature (int arity)
        return res;
 }
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-static void
-handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
+MonoJitICallInfo *
+mono_get_array_new_va_icall (int rank)
 {
-       MonoInst *iargs [2];
-       iargs [0] = val;
-       iargs [1] = ptr;
+       MonoMethodSignature *esig;
+       char icall_name [256];
+       char *name;
+       MonoJitICallInfo *info;
 
-       mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
-}
+       /* Need to register the icall so it gets an icall wrapper */
+       sprintf (icall_name, "ves_array_new_va_%d", rank);
 
-static int
-handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
-{
-       MonoInst *iargs [1];
-       iargs [0] = ptr;
+       mono_jit_lock ();
+       info = mono_find_jit_icall_by_name (icall_name);
+       if (info == NULL) {
+               esig = mono_get_array_new_va_signature (rank);
+               name = g_strdup (icall_name);
+               info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
 
-       return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
-}
+               g_hash_table_insert (jit_icall_name_hash, name, name);
+       }
+       mono_jit_unlock ();
 
-#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
-                       int temp;       \
-                       NEW_LOCLOADA (cfg, (ins), (idx));       \
-                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
-                       NEW_TEMPLOAD (cfg, (ins), temp);        \
-               }       \
-       } while (0)
-#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
-                       int temp;       \
-                       NEW_LOCLOADA (cfg, (ins), (idx));       \
-                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
-                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
-               }       \
-       } while (0)
-#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
-                       int temp;       \
-                       NEW_ARGLOADA (cfg, (ins), (idx));       \
-                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
-                       NEW_TEMPLOAD (cfg, (ins), temp);        \
-               }       \
-       } while (0)
-#define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
-               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
-                       int temp;       \
-                       NEW_ARGLOADA (cfg, (ins), (idx));       \
-                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
-                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
-               }       \
-       } while (0)
-#else
-#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
-#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
-#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
-#define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
-#endif
+       return info;
+}
 
 static MonoMethod*
 get_memcpy_method (void)
@@ -3121,11 +3615,12 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboole
 }
 
 static int
-handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *vtable_inst,
+handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, MonoInst *data_inst,
                gboolean for_box, const guchar *ip)
 {
        MonoInst *iargs [2];
        MonoMethod *managed_alloc = NULL;
+       void *alloc_ftn;
        /*
          FIXME: we cannot get managed_alloc here because we can't get
          the class's vtable (because it's not a closed class)
@@ -3134,32 +3629,26 @@ handle_alloc_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *kla
        MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
        */
 
-       g_assert (!(cfg->opt & MONO_OPT_SHARED));
-       g_assert (!cfg->compile_aot);
-
-       if (managed_alloc) {
-               iargs [0] = vtable_inst;
-               return mono_emit_method_call_spilled (cfg, bblock, managed_alloc, mono_method_signature (managed_alloc), iargs, ip, NULL);
-       }
+       if (cfg->opt & MONO_OPT_SHARED) {
+               NEW_DOMAINCONST (cfg, iargs [0]);
+               iargs [1] = data_inst;
+               alloc_ftn = mono_object_new;
+       } else {
+               g_assert (!cfg->compile_aot);
 
-       iargs [0] = vtable_inst;
+               if (managed_alloc) {
+                       iargs [0] = data_inst;
+                       return mono_emit_method_call_spilled (cfg, bblock, managed_alloc,
+                               mono_method_signature (managed_alloc), iargs, ip, NULL);
+               }
 
-       return mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
-}
+               iargs [0] = data_inst;
+               alloc_ftn = mono_object_new_specific;
+       }
 
-/**
- * Handles unbox of a Nullable<T>, returning a temp variable
- * where the result is stored
- */
-static int
-handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
-{
-       MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
-       return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
-       
+       return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
 }
 
-
 static MonoInst*
 handle_box_copy (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass, int temp)
 {
@@ -3212,13 +3701,13 @@ handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const gucha
 
 static MonoInst *
 handle_box_from_inst (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip,
-               MonoClass *klass, MonoInst *vtable_inst)
+               MonoClass *klass, MonoInst *data_inst)
 {
        int temp;
 
        g_assert (!mono_class_is_nullable (klass));
 
-       temp = handle_alloc_from_inst (cfg, bblock, klass, vtable_inst, TRUE, ip);
+       temp = handle_alloc_from_inst (cfg, bblock, klass, data_inst, TRUE, ip);
 
        return handle_box_copy (cfg, bblock, val, ip, klass, temp);
 }
@@ -3240,12 +3729,10 @@ handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass
                NEW_TEMPLOAD (cfg, obj, temp);
                NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, target));
                MONO_INST_NEW (cfg, ins, OP_PADD);
-               ins->cil_code = ip;
                ins->inst_left = obj;
                ins->inst_right = offset_ins;
 
                MONO_INST_NEW (cfg, store, CEE_STIND_REF);
-               store->cil_code = ip;
                store->inst_left = ins;
                store->inst_right = target;
                mono_bblock_add_inst (bblock, store);
@@ -3255,14 +3742,12 @@ handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass
        NEW_TEMPLOAD (cfg, obj, temp);
        NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, method));
        MONO_INST_NEW (cfg, ins, OP_PADD);
-       ins->cil_code = ip;
        ins->inst_left = obj;
        ins->inst_right = offset_ins;
 
        NEW_METHODCONST (cfg, method_ins, method);
 
        MONO_INST_NEW (cfg, store, CEE_STIND_I);
-       store->cil_code = ip;
        store->inst_left = ins;
        store->inst_right = method_ins;
        mono_bblock_add_inst (bblock, store);
@@ -3271,7 +3756,6 @@ handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass
        NEW_TEMPLOAD (cfg, obj, temp);
        NEW_ICONST (cfg, offset_ins, G_STRUCT_OFFSET (MonoDelegate, invoke_impl));
        MONO_INST_NEW (cfg, ins, OP_PADD);
-       ins->cil_code = ip;
        ins->inst_left = obj;
        ins->inst_right = offset_ins;
 
@@ -3279,7 +3763,6 @@ handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass
        NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
 
        MONO_INST_NEW (cfg, store, CEE_STIND_I);
-       store->cil_code = ip;
        store->inst_left = ins;
        store->inst_right = tramp_ins;
        mono_bblock_add_inst (bblock, store);
@@ -3294,24 +3777,9 @@ handle_delegate_ctor (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass
 static int
 handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst **sp, unsigned char *ip)
 {
-       MonoMethodSignature *esig;
-       char icall_name [256];
-       char *name;
        MonoJitICallInfo *info;
 
-       /* Need to register the icall so it gets an icall wrapper */
-       sprintf (icall_name, "ves_array_new_va_%d", rank);
-
-       mono_jit_lock ();
-       info = mono_find_jit_icall_by_name (icall_name);
-       if (info == NULL) {
-               esig = mono_get_array_new_va_signature (rank);
-               name = g_strdup (icall_name);
-               info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
-
-               g_hash_table_insert (jit_icall_name_hash, name, name);
-       }
-       mono_jit_unlock ();
+       info = mono_get_array_new_va_icall (rank);
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
 
@@ -3332,7 +3800,12 @@ mono_emit_load_got_addr (MonoCompile *cfg)
        NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
 
        /* Add it to the start of the first bblock */
-       MONO_INST_LIST_ADD (&store->node, &cfg->bb_entry->ins_list);
+       if (cfg->bb_entry->code) {
+               store->next = cfg->bb_entry->code;
+               cfg->bb_entry->code = store;
+       }
+       else
+               MONO_ADD_INS (cfg->bb_entry, store);
 
        cfg->got_var_allocated = TRUE;
 
@@ -3349,7 +3822,7 @@ mono_emit_load_got_addr (MonoCompile *cfg)
 
 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
 
-static gboolean
+gboolean
 mini_class_is_system_array (MonoClass *klass)
 {
        if (klass->parent == mono_defaults.array_class)
@@ -3407,6 +3880,15 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 #endif
        }
 
+       /* 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)
+               return FALSE;
+
        /*
         * if we can initialize the class of the method right away, we do,
         * otherwise we don't allow inlining if the class needs initialization,
@@ -3414,9 +3896,14 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
         * inside the inlined code
         */
        if (!(cfg->opt & MONO_OPT_SHARED)) {
-               vtable = mono_class_vtable (cfg->domain, method->klass);
                if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
                        if (cfg->run_cctors && method->klass->has_cctor) {
+                               if (!method->klass->runtime_info)
+                                       /* No vtable created yet */
+                                       return FALSE;
+                               vtable = mono_class_vtable (cfg->domain, method->klass);
+                               if (!vtable)
+                                       return FALSE;
                                /* This makes so that inline cannot trigger */
                                /* .cctors: too many apps depend on them */
                                /* running with a specific order... */
@@ -3424,9 +3911,16 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                                        return FALSE;
                                mono_runtime_class_init (vtable);
                        }
+               } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
+                       if (!method->klass->runtime_info)
+                               /* No vtable created yet */
+                               return FALSE;
+                       vtable = mono_class_vtable (cfg->domain, method->klass);
+                       if (!vtable)
+                               return FALSE;
+                       if (!vtable->initialized)
+                               return FALSE;
                }
-               else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
-                       return FALSE;
        } else {
                /* 
                 * If we're compiling for shared code
@@ -3445,15 +3939,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (mono_method_has_declsec (method))
                return FALSE;
 
-       /* also consider num_locals? */
-       if (getenv ("MONO_INLINELIMIT")) {
-               if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
-                       return TRUE;
-               }
-       } else if (header->code_size < INLINE_LENGTH_LIMIT)
-               return TRUE;
-
-       return FALSE;
+       return TRUE;
 }
 
 static gboolean
@@ -3489,7 +3975,6 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
                addr->inst_left = sp [0];
                addr->inst_right = sp [1];
-               addr->cil_code = ip;
                addr->type = STACK_MP;
                addr->klass = cmethod->klass->element_class;
                return addr;
@@ -3504,7 +3989,6 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
                addr->inst_left = sp [0];
                addr->inst_right = indexes;
-               addr->cil_code = ip;
                addr->type = STACK_MP;
                addr->klass = cmethod->klass->element_class;
                return addr;
@@ -3531,22 +4015,6 @@ mono_find_jit_opcode_emulation (int opcode)
                return NULL;
 }
 
-static int
-is_unsigned_regsize_type (MonoType *type)
-{
-       switch (type->type) {
-       case MONO_TYPE_U1:
-       case MONO_TYPE_U2:
-       case MONO_TYPE_U4:
-#if SIZEOF_VOID_P == 8
-       /*case MONO_TYPE_U8: this requires different opcodes in inssel.brg */
-#endif
-               return TRUE;
-       default:
-               return FALSE;
-       }
-}
-
 static MonoInst*
 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -3643,21 +4111,11 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                store->inst_right = load;
                return store;
        } else if (cmethod->klass == mono_defaults.math_class) {
-               if (strcmp (cmethod->name, "Min") == 0) {
-                       if (is_unsigned_regsize_type (fsig->params [0])) {
-                               MONO_INST_NEW (cfg, ins, OP_MIN);
-                               ins->inst_i0 = args [0];
-                               ins->inst_i1 = args [1];
-                               return ins;
-                       }
-               } else if (strcmp (cmethod->name, "Max") == 0) {
-                       if (is_unsigned_regsize_type (fsig->params [0])) {
-                               MONO_INST_NEW (cfg, ins, OP_MAX);
-                               ins->inst_i0 = args [0];
-                               ins->inst_i1 = args [1];
-                               return ins;
-                       }
-               }
+               /* 
+                * There is general branches code for Min/Max, but it does not work for 
+                * all inputs:
+                * http://everything2.com/?node_id=1051618
+                */
        } else if (cmethod->klass->image == mono_defaults.corlib &&
                           (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
                           (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
@@ -3769,6 +4227,23 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                }
 #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.
+                */
+               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);
+                               ins->inst_i0 = args [0];
+                               ins->inst_i1 = args [1];
+                               ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
+                       }
+                       /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
+               }
+#endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
+
                if (ins)
                        return ins;
        } else if (cmethod->klass->image == mono_defaults.corlib) {
@@ -3937,11 +4412,11 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
 
        /* allocate starte and end blocks */
-       NEW_BBLOCK (cfg, sbblock);
+       sbblock = NEW_BBLOCK (cfg);
        sbblock->block_num = cfg->num_bblocks++;
        sbblock->real_offset = real_offset;
 
-       NEW_BBLOCK (cfg, ebblock);
+       ebblock = NEW_BBLOCK (cfg);
        ebblock->block_num = cfg->num_bblocks++;
        ebblock->real_offset = real_offset;
 
@@ -3974,14 +4449,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 
                if (rvar) {
                        NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
-#ifdef MONO_ARCH_SOFT_FLOAT
-                       if (ins->opcode == CEE_LDIND_R4) {
-                               int temp;
-                               NEW_TEMPLOADA (cfg, ins, rvar->inst_c0);
-                               temp = handle_load_float (cfg, bblock, ins, ip);
-                               NEW_TEMPLOAD (cfg, ins, temp);
-                       }
-#endif
+                       NEW_TEMPLOAD_SOFT_FLOAT (cfg, ebblock, ins, rvar->inst_c0, ip);
                        *sp++ = ins;
                }
                *last_b = ebblock;
@@ -4154,7 +4622,7 @@ emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8
 }
 
 static inline MonoMethod *
-mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
+mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
 {
        MonoMethod *method;
 
@@ -4166,6 +4634,17 @@ mini_get_method (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericCont
        return method;
 }
 
+static inline MonoMethod *
+mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
+{
+       MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
+
+       if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
+               return NULL;
+
+       return method;
+}
+
 static inline MonoClass*
 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
 {
@@ -4325,7 +4804,7 @@ initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, Mono
 
                if (newarr->inst_newa_len->opcode != OP_ICONST)
                        return NULL;
-               cmethod = mini_get_method (method, token, NULL, NULL);
+               cmethod = mini_get_method (NULL, method, token, NULL, NULL);
                if (!cmethod)
                        return NULL;
                if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
@@ -4377,62 +4856,80 @@ static void
 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
 {
        char *method_fname = mono_method_full_name (method, TRUE);
-       char *method_code = mono_disasm_code_one (NULL, method, ip, NULL);
+       char *method_code;
+
+       if (mono_method_get_header (method)->code_size == 0)
+               method_code = g_strdup ("method body is empty.");
+       else
+               method_code = mono_disasm_code_one (NULL, method, ip, NULL);
        cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
        cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
        g_free (method_fname);
        g_free (method_code);
 }
 
-/*
- * Generates this->vtable->runtime_generic_context
- */
+static void
+set_exception_object (MonoCompile *cfg, MonoException *exception)
+{
+       cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
+       MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
+       cfg->exception_ptr = exception;
+}
+
 static MonoInst*
-get_runtime_generic_context_from_this (MonoCompile *cfg, MonoInst *this, unsigned char *ip)
+get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
 {
-       MonoInst *vtable, *rgc_ptr_addr, *rgc_ptr_offset, *rgc_ptr;
+       g_assert (!method->klass->valuetype);
 
-       MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
-       vtable->cil_code = ip;
-       vtable->inst_left = this;
-       vtable->type = STACK_PTR;
+       if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
+               MonoInst *mrgctx_loc, *mrgctx_var;
 
-       NEW_ICONST (cfg, rgc_ptr_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
+               g_assert (!this);
+               g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
 
-       MONO_INST_NEW (cfg, rgc_ptr_addr, OP_PADD);
-       rgc_ptr_addr->cil_code = ip;
-       rgc_ptr_addr->inst_left = vtable;
-       rgc_ptr_addr->inst_right = rgc_ptr_offset;
-       rgc_ptr_addr->type = STACK_PTR;
+               mrgctx_loc = mono_get_vtable_var (cfg);
+               NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
 
-       MONO_INST_NEW (cfg, rgc_ptr, CEE_LDIND_I);
-       rgc_ptr->cil_code = ip;
-       rgc_ptr->inst_left = rgc_ptr_addr;
-       rgc_ptr->type = STACK_PTR;
+               return mrgctx_var;
+       } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
+               MonoInst *vtable_loc, *vtable_var;
 
-       return rgc_ptr;
-}
+               g_assert (!this);
 
-static MonoInst*
-get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, MonoInst *this, unsigned char *ip)
-{
-       g_assert (!method->klass->valuetype);
+               vtable_loc = mono_get_vtable_var (cfg);
+               NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
+
+               if (method->is_inflated && mono_method_get_context (method)->method_inst) {
+                       MonoInst *mrgctx_var = vtable_var;
 
-       if (method->flags & METHOD_ATTRIBUTE_STATIC) {
-               MonoInst *rgctx_loc, *rgctx_var;
+                       g_assert (G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable) == 0);
 
-               rgctx_loc = mono_get_rgctx_var (cfg);
-               NEW_TEMPLOAD (cfg, rgctx_var, rgctx_loc->inst_c0);
+                       MONO_INST_NEW (cfg, vtable_var, CEE_LDIND_I);
+                       vtable_var->cil_code = ip;
+                       vtable_var->inst_left = mrgctx_var;
+                       vtable_var->type = STACK_PTR;
+               }
 
-               return rgctx_var;
+               return vtable_var;
        } else {
-               return get_runtime_generic_context_from_this (cfg, this, ip);
+               MonoInst *vtable;
+
+               g_assert (this);
+
+               MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
+               vtable->inst_left = this;
+               vtable->type = STACK_PTR;
+
+               return vtable;
        }
 }
 
-static gpointer
-create_rgctx_lazy_fetch_trampoline (guint32 offset)
+gpointer
+mini_create_rgctx_lazy_fetch_trampoline (guint32 offset)
 {
+       static gboolean inited = FALSE;
+       static int num_trampolines = 0;
+
        gpointer tramp, ptr;
 
        mono_jit_lock ();
@@ -4453,18 +4950,26 @@ create_rgctx_lazy_fetch_trampoline (guint32 offset)
        g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
        mono_jit_unlock ();
 
+       if (!inited) {
+               mono_counters_register ("RGCTX num lazy fetch trampolines",
+                               MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
+               inited = TRUE;
+       }
+       num_trampolines++;
+
        return ptr;
-}      
+}
 
 static MonoInst*
-lazy_fetch_rgctx_direct_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
+get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
+       MonoInst *rgc_ptr, guint32 slot, const unsigned char *ip)
 {
        MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
-       guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_DIRECT_OFFSET (offset));
+       guint8 *tramp = mini_create_rgctx_lazy_fetch_trampoline (slot);
        int temp;
        MonoInst *field;
 
-       temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE); 
+       temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
 
        NEW_TEMPLOAD (cfg, field, temp);
 
@@ -4472,182 +4977,270 @@ lazy_fetch_rgctx_direct_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoIns
 }
 
 static MonoInst*
-lazy_fetch_rgctx_indirect_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
+get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
+       MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
 {
-       MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
-       guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_INDIRECT_OFFSET (offset));
-       int temp;
-       MonoInst *field;
+       guint32 slot = mono_method_lookup_or_register_other_info (method,
+               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, generic_context);
 
-       temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE); 
+       return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
+}
 
-       NEW_TEMPLOAD (cfg, field, temp);
+static MonoInst*
+get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
+       MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
+{
+       guint32 slot = mono_method_lookup_or_register_other_info (method,
+               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, generic_context);
 
-       return field;
+       return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
 }
 
-/*
- * Generates ((MonoRuntimeGenericSuperInfo*)rgc)[-depth].XXX where XXX
- * is specified by rgctx_type.
- */
 static MonoInst*
-get_runtime_generic_context_super_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
-       MonoInst *rgc_ptr, int depth, int rgctx_type, unsigned char *ip)
+get_runtime_generic_context_field (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
+       MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
+       const unsigned char *ip)
 {
-       int field_offset_const, offset;
+       guint32 slot = mono_method_lookup_or_register_other_info (method,
+               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, generic_context);
 
-       g_assert (depth >= 1);
+       return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
+}
 
-       switch (rgctx_type) {
-       case MONO_RGCTX_INFO_STATIC_DATA :
-               field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, static_data);
-               break;
-       case MONO_RGCTX_INFO_KLASS :
-               field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, klass);
-               break;
-       case MONO_RGCTX_INFO_VTABLE:
-               field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, vtable);
-               break;
-       default :
-               g_assert_not_reached ();
-       }
+static MonoInst*
+get_runtime_generic_context_method_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoBasicBlock *bblock,
+       MonoMethod *rgctx_method, MonoGenericContext *generic_context, MonoInst *rgctx, const unsigned char *ip)
+{
+       guint32 slot = mono_method_lookup_or_register_other_info (method,
+               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
+               MONO_RGCTX_INFO_METHOD_RGCTX, generic_context);
+
+       return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
+}
 
-       offset = -depth * sizeof (MonoRuntimeGenericSuperInfo) + field_offset_const;
+static gboolean
+generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
+{
+       MonoType *type;
 
-       return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
+       if (cfg->generic_sharing_context)
+               type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
+       else
+               type = &klass->byval_arg;
+       return MONO_TYPE_IS_REFERENCE (type);
 }
 
+/**
+ * Handles unbox of a Nullable<T>, returning a temp variable where the
+ * result is stored.  If a rgctx is passed, then shared generic code
+ * is generated.
+ */
 static int
-get_rgctx_arg_info_field_offset (int rgctx_type)
-{
-       switch (rgctx_type) {
-       case MONO_RGCTX_INFO_STATIC_DATA :
-               return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, static_data);
-       case MONO_RGCTX_INFO_KLASS:
-               return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, klass);
-       case MONO_RGCTX_INFO_VTABLE :
-               return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, vtable);
-       default:
-               g_assert_not_reached ();
+handle_unbox_nullable (MonoCompile* cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock* bblock,
+       MonoInst* val, const guchar *ip, MonoClass* klass, MonoGenericContext *generic_context, MonoInst *rgctx)
+{
+       MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
+       MonoMethodSignature *signature = mono_method_signature (method);
+
+       if (rgctx) {
+               MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
+                       generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
+
+               return mono_emit_rgctx_calli_spilled (cfg, bblock, signature, &val, addr, NULL, ip);
+       } else {
+               return mono_emit_method_call_spilled (cfg, bblock, method, signature, &val, ip, NULL);
        }
 }
 
-/*
- * Generates rgc->arg_infos [arg_num].XXX where XXX is specified by
- * rgctx_type;
- */
 static MonoInst*
-get_runtime_generic_context_arg_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
-       MonoInst *rgc_ptr, int arg_num, int rgctx_type, unsigned char *ip)
+handle_box_nullable_from_inst (MonoCompile *cfg, MonoMethod *caller_method, int context_used, MonoBasicBlock *bblock,
+       MonoInst *val, const guchar *ip, MonoClass *klass, MonoGenericContext *generic_context, MonoInst *rgctx)
+{
+       MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+       MonoInst *dest, *method_addr;
+       int temp;
+
+       g_assert (mono_class_is_nullable (klass));
+
+       method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
+                       generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
+       temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
+                       method_addr, NULL, ip);
+       NEW_TEMPLOAD (cfg, dest, temp);
+       return dest;
+}
+
+static int
+emit_castclass (MonoClass *klass, guint32 token, int context_used, gboolean inst_is_castclass, MonoCompile *cfg,
+               MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
+               unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
+               MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
 {
-       int arg_info_offset, arg_info_field_offset, offset;
+       MonoBasicBlock *bblock = *_bblock;
+       unsigned char *ip = *_ip;
+       MonoInst **sp = *_sp;
+       int inline_costs = *_inline_costs;
+       guint real_offset = *_real_offset;
+       int return_value = 0;
 
-       g_assert (arg_num >= 0);
-       //g_assert (!lazy);
+       if (context_used) {
+               MonoInst *rgctx, *args [2];
+               int temp;
 
-       arg_info_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, arg_infos) +
-               arg_num * sizeof (MonoRuntimeGenericArgInfo);
+               g_assert (!method->klass->valuetype);
 
-       arg_info_field_offset = get_rgctx_arg_info_field_offset (rgctx_type);
+               /* obj */
+               args [0] = *sp;
 
-       offset = arg_info_offset + arg_info_field_offset;
+               /* klass */
+               GET_RGCTX (rgctx, context_used);
+               args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                               generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
 
-       return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
-}
+               temp = mono_emit_jit_icall (cfg, bblock, mono_object_castclass, args, ip);
+               NEW_TEMPLOAD (cfg, *sp, temp);
 
-/*
- * Generates rgc->other_infos [index].XXX if index is non-negative, or
- * rgc->extra_other_infos [-index + 1] if index is negative.  XXX is
- * specified by rgctx_type;
- */
-static MonoInst*
-get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
-       MonoInst *rgc_ptr, int index, unsigned char *ip)
-{
-       if (index < MONO_RGCTX_MAX_OTHER_INFOS) {
-               int other_type_offset;
+               sp++;
+               ip += 5;
+               inline_costs += 2;
+       } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 
-               other_type_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, other_infos) +
-                       index * sizeof (gpointer);
+               MonoMethod *mono_castclass;
+               MonoInst *iargs [1];
+               MonoBasicBlock *ebblock;
+               int costs;
+               int temp;
 
-               return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, other_type_offset, ip);
-       } else {
-               int slot_offset;
+               mono_castclass = mono_marshal_get_castclass (klass);
+               iargs [0] = sp [0];
 
-               slot_offset = (index - MONO_RGCTX_MAX_OTHER_INFOS) * sizeof (gpointer);
+               costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock,
+                               iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
 
-               return lazy_fetch_rgctx_indirect_field (cfg, bblock, rgc_ptr, slot_offset, ip);
-       }
-}
+               g_assert (costs > 0);
 
-static MonoInst*
-get_runtime_generic_context_other_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
-       MonoInst *rgc_ptr, guint32 token, int token_source, int rgctx_type, unsigned char *ip, int index)
-{
-       MonoInst *args [6];
-       int temp;
-       MonoInst *result;
+               ip += 5;
+               real_offset += 5;
 
-       g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+               GET_BBLOCK (cfg, bblock, ip);
+               ebblock->next_bb = bblock;
+               link_bblock (cfg, ebblock, bblock);
 
-       NEW_CLASSCONST (cfg, args [0], method->klass);
-       args [1] = rgc_ptr;
-       NEW_ICONST (cfg, args [2], token);
-       NEW_ICONST (cfg, args [3], token_source);
-       NEW_ICONST (cfg, args [4], rgctx_type);
-       NEW_ICONST (cfg, args [5], index);
+               temp = iargs [0]->inst_i0->inst_c0;
+               NEW_TEMPLOAD (cfg, *sp, temp);
+
+               sp++;
+               bblock = ebblock;
+               inline_costs += costs;
+       } else {
+               MonoInst *ins;
 
-       temp = mono_emit_jit_icall (cfg, bblock, mono_helper_get_rgctx_other_ptr, args, ip);
-       NEW_TEMPLOAD (cfg, result, temp);
+               /* Needed by the code generated in inssel.brg */
+               mono_get_got_var (cfg);
 
-       return result;
+               MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
+               ins->type = STACK_OBJ;
+               ins->inst_left = *sp;
+               ins->klass = klass;
+               ins->inst_newa_class = klass;
+               if (inst_is_castclass)
+                       ins->backend.record_cast_details = debug_options.better_cast_details;
+               if (inst_is_castclass)
+                       *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
+               else
+                       *sp++ = ins;
+               ip += 5;
+       }
+
+do_return:
+       *_bblock = bblock;
+       *_ip = ip;
+       *_sp = sp;
+       *_inline_costs = inline_costs;
+       *_real_offset = real_offset;
+       return return_value;
+exception_exit:
+       return_value = -2;
+       goto do_return;
+unverified:
+       return_value = -1;
+       goto do_return;
 }
 
-static MonoInst*
-get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
-       MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
-       int rgctx_type, unsigned char *ip)
-{
-       int arg_num = -1;
-       int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
-
-       switch (relation) {
-       case MINI_GENERIC_CLASS_RELATION_SELF: {
-               int depth = klass->idepth;
-               return get_runtime_generic_context_super_ptr (cfg, bblock, rgctx, depth, rgctx_type, ip);
-       }
-       case MINI_GENERIC_CLASS_RELATION_ARGUMENT:
-               return get_runtime_generic_context_arg_ptr (cfg, bblock, rgctx, arg_num, rgctx_type, ip);
-       case MINI_GENERIC_CLASS_RELATION_OTHER_TABLE:
-               return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
-       case MINI_GENERIC_CLASS_RELATION_OTHER:
-               return get_runtime_generic_context_other_ptr (cfg, method, bblock, rgctx,
-                       type_token, token_source, rgctx_type, ip, arg_num);
-       default:
-               g_assert_not_reached ();
-               return NULL;
+static int
+emit_unbox (MonoClass *klass, guint32 token, int context_used,
+               MonoCompile *cfg, MonoMethod *method, MonoInst **arg_array, MonoType **param_types, GList *dont_inline,
+               unsigned char *end, MonoMethodHeader *header, MonoGenericContext *generic_context,
+               MonoBasicBlock **_bblock, unsigned char **_ip, MonoInst ***_sp, int *_inline_costs, guint *_real_offset)
+{
+       MonoBasicBlock *bblock = *_bblock;
+       unsigned char *ip = *_ip;
+       MonoInst **sp = *_sp;
+       int inline_costs = *_inline_costs;
+       guint real_offset = *_real_offset;
+       int return_value = 0;
+
+       MonoInst *add, *vtoffset, *ins;
+
+       /* Needed by the code generated in inssel.brg */
+       mono_get_got_var (cfg);
+
+       if (context_used) {
+               MonoInst *rgctx, *element_class;
+
+               /* This assertion is from the unboxcast insn */
+               g_assert (klass->rank == 0);
+
+               GET_RGCTX (rgctx, context_used);
+               element_class = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
+                               klass->element_class, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
+
+               MONO_INST_NEW (cfg, ins, OP_UNBOXCAST_REG);
+               ins->type = STACK_OBJ;
+               ins->inst_left = *sp;
+               ins->inst_right = element_class;
+               ins->klass = klass;
+               ins->cil_code = ip;
+       } else {
+               MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
+               ins->type = STACK_OBJ;
+               ins->inst_left = *sp;
+               ins->klass = klass;
+               ins->inst_newa_class = klass;
+               ins->cil_code = ip;
        }
-}
 
-static MonoInst*
-get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
-       MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
-{
-       int arg_num = mono_class_lookup_or_register_other_info (method->klass, cmethod, rgctx_type, generic_context);
+       MONO_INST_NEW (cfg, add, OP_PADD);
+       NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
+       add->inst_left = ins;
+       add->inst_right = vtoffset;
+       add->type = STACK_MP;
+       add->klass = klass;
+       *sp = add;
 
-       return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
+do_return:
+       *_bblock = bblock;
+       *_ip = ip;
+       *_sp = sp;
+       *_inline_costs = inline_costs;
+       *_real_offset = real_offset;
+       return return_value;
+exception_exit:
+       return_value = -2;
+       goto do_return;
 }
 
-static gboolean
-generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
+gboolean
+mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
 {
-       MonoType *type;
-
-       if (cfg->generic_sharing_context)
-               type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
-       else
-               type = &klass->byval_arg;
-       return MONO_TYPE_IS_REFERENCE (type);
+       MonoAssembly *assembly = method->klass->image->assembly;
+       if (method->wrapper_type != MONO_WRAPPER_NONE)
+               return FALSE;
+       if (assembly->in_gac || assembly->image == mono_defaults.corlib)
+               return FALSE;
+       if (mono_security_get_mode () != MONO_SECURITY_MODE_NONE)
+               return FALSE;
+       return mono_assembly_has_skip_verification (assembly);
 }
 
 /*
@@ -4657,13 +5250,18 @@ generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
  * 
  * Returns true if the method is invalid. 
  */
-static gboolean
+gboolean
 mini_method_verify (MonoCompile *cfg, MonoMethod *method)
 {
        GSList *tmp, *res;
-       gboolean is_fulltrust = mono_verifier_is_method_full_trust (method);
+       gboolean is_fulltrust;
        MonoLoaderError *error;
 
+       if (method->verification_success)
+               return FALSE;
+
+       is_fulltrust = mono_verifier_is_method_full_trust (method);
+
        if (!mono_verifier_is_enabled_for_method (method))
                return FALSE;
 
@@ -4694,6 +5292,7 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method)
                }
                mono_free_verify_list (res);
        }
+       method->verification_success = 1;
        return FALSE;
 }
 
@@ -4708,7 +5307,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
        MonoInst *ins, **sp, **stack_start;
        MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
-       MonoMethod *cmethod;
+       MonoMethod *cmethod, *method_definition;
        MonoInst **arg_array;
        MonoMethodHeader *header;
        MonoImage *image;
@@ -4732,6 +5331,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoDeclSecurityActions actions;
        GSList *class_inits = NULL;
        gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
+       int context_used;
 
        /* serialization and xdomain stuff may need access to private fields and methods */
        dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
@@ -4751,7 +5351,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        image = method->klass->image;
        header = mono_method_get_header (method);
-       generic_container = method->generic_container;
+       generic_container = mono_method_get_generic_container (method);
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
        ip = (unsigned char*)header->code;
@@ -4759,7 +5359,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
 
-       if (!dont_verify && mini_method_verify (cfg, method))
+       method_definition = method;
+       while (method_definition->is_inflated) {
+               MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
+               method_definition = imethod->declaring;
+       }
+
+       /* SkipVerification is not allowed if core-clr is enabled */
+       if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
+               dont_verify = TRUE;
+               dont_verify_stloc = TRUE;
+       }
+
+       if (!dont_verify && mini_method_verify (cfg, method_definition))
                goto exception_exit;
 
        if (sig->is_inflated)
@@ -4770,6 +5382,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        if (!cfg->generic_sharing_context)
                g_assert (!sig->has_type_parameters);
 
+       if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
+               g_assert (method->is_inflated);
+               g_assert (mono_method_get_context (method)->method_inst);
+       }
+       if (method->is_inflated && mono_method_get_context (method)->method_inst)
+               g_assert (sig->generic_param_count);
+
        if (cfg->method == method)
                real_offset = 0;
        else
@@ -4788,15 +5407,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
 
                /* ENTRY BLOCK */
-               NEW_BBLOCK (cfg, start_bblock);
-               cfg->bb_entry = start_bblock;
+               cfg->bb_entry = start_bblock = NEW_BBLOCK (cfg);
                start_bblock->cil_code = NULL;
                start_bblock->cil_length = 0;
                start_bblock->block_num = cfg->num_bblocks++;
 
                /* EXIT BLOCK */
-               NEW_BBLOCK (cfg, end_bblock);
-               cfg->bb_exit = end_bblock;
+               cfg->bb_exit = end_bblock = NEW_BBLOCK (cfg);
                end_bblock->cil_code = NULL;
                end_bblock->cil_length = 0;
                end_bblock->block_num = cfg->num_bblocks++;
@@ -4815,14 +5432,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoBasicBlock *try_bb;
                        MonoExceptionClause *clause = &header->clauses [i];
 
-                       if ((method->flags & METHOD_ATTRIBUTE_STATIC) &&
-                                       clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
-                                       clause->data.catch_class &&
-                                       cfg->generic_sharing_context &&
-                                       mono_class_check_context_used (clause->data.catch_class)) {
-                               mono_get_rgctx_var (cfg);
-                       }
-
                        GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
                        try_bb->real_offset = clause->try_offset;
                        GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
@@ -4880,6 +5489,52 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_ADD_INS (tblock, ins);
                                }
                        }
+
+                       if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
+                                       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
+                                * the exception handling code has to
+                                * be able to get to the rgctx.
+                                * Therefore we have to make sure that
+                                * the vtable/mrgctx argument (for
+                                * static or generic methods) or the
+                                * "this" argument (for non-static
+                                * methods) are live.
+                                */
+                               if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
+                                               mini_method_get_context (method)->method_inst) {
+                                       mono_get_vtable_var (cfg);
+                               } else {
+                                       MonoInst *this, *dummy_use;
+                                       MonoType *this_type;
+
+                                       if (method->klass->valuetype)
+                                               this_type = &method->klass->this_arg;
+                                       else
+                                               this_type = &method->klass->byval_arg;
+
+                                       if (arg_array [0]->opcode == OP_ICONST) {
+                                               this = arg_array [0];
+                                       } else {
+                                               this = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));
+                                               this->ssa_op = MONO_SSA_LOAD;
+                                               this->inst_i0 = arg_array [0];
+                                               this->opcode = mini_type_to_ldind ((cfg), this->inst_i0->inst_vtype);
+                                               type_to_eval_stack_type ((cfg), this_type, this);
+                                               this->klass = this->inst_i0->klass;
+                                       }
+
+                                       NEW_DUMMY_USE (cfg, dummy_use, this);
+                                       MONO_ADD_INS (tblock, dummy_use);
+                               }
+                       }
                }
        } else {
                arg_array = alloca (sizeof (MonoInst *) * num_args);
@@ -4887,7 +5542,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
 
        /* FIRST CODE BLOCK */
-       NEW_BBLOCK (cfg, bblock);
+       bblock = NEW_BBLOCK (cfg);
        bblock->cil_code = ip;
 
        ADD_BBLOCK (cfg, bblock);
@@ -4942,8 +5597,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        
        if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
                /* we use a separate basic block for the initialization code */
-               NEW_BBLOCK (cfg, init_localsbb);
-               cfg->bb_init = init_localsbb;
+               cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
                init_localsbb->real_offset = real_offset;
                start_bblock->next_bb = init_localsbb;
                init_localsbb->next_bb = bblock;
@@ -5057,6 +5711,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        real_offset = ip - header->code;
                else
                        real_offset = inline_offset;
+               cfg->ip = ip;
+
+               context_used = 0;
 
                if (start_new_bblock) {
                        bblock->cil_length = ip - bblock->cil_code;
@@ -5112,7 +5769,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
 
                        MONO_INST_NEW (cfg, store, CEE_STIND_I);
-                       store->cil_code = ip;
                        store->inst_left = ins;
                        store->inst_right = one;
 
@@ -5125,12 +5781,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                switch (*ip) {
                case CEE_NOP:
                        MONO_INST_NEW (cfg, ins, OP_NOP);
-                       ins->cil_code = ip++;
+                       ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
                case CEE_BREAK:
                        MONO_INST_NEW (cfg, ins, OP_BREAK);
-                       ins->cil_code = ip++;
+                       ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
                case CEE_LDARG_0:
@@ -5142,7 +5798,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_ARG (n);
                        NEW_ARGLOAD (cfg, ins, n);
                        LDARG_SOFT_FLOAT (cfg, ins, n, ip);
-                       ins->cil_code = ip++;
+                       ip++;
                        *sp++ = ins;
                        break;
                case CEE_LDLOC_0:
@@ -5154,7 +5810,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_LOCAL (n);
                        NEW_LOCLOAD (cfg, ins, n);
                        LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
-                       ins->cil_code = ip++;
+                       ip++;
                        *sp++ = ins;
                        break;
                case CEE_STLOC_0:
@@ -5167,7 +5823,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        NEW_LOCSTORE (cfg, ins, n, *sp);
-                       ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
                                UNVERIFIED;
                        STLOC_SOFT_FLOAT (cfg, ins, n, ip);
@@ -5185,7 +5840,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_ARG (ip [1]);
                        NEW_ARGLOAD (cfg, ins, ip [1]);
                        LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
-                       ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
                        break;
@@ -5194,7 +5848,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        CHECK_ARG (ip [1]);
                        NEW_ARGLOADA (cfg, ins, ip [1]);
-                       ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
                        break;
@@ -5205,7 +5858,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_ARG (ip [1]);
                        NEW_ARGSTORE (cfg, ins, ip [1], *sp);
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
-                       ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
                                UNVERIFIED;
                        STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
@@ -5222,7 +5874,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_LOCAL (ip [1]);
                        NEW_LOCLOAD (cfg, ins, ip [1]);
                        LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
-                       ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
                        break;
@@ -5231,7 +5882,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        CHECK_LOCAL (ip [1]);
                        NEW_LOCLOADA (cfg, ins, ip [1]);
-                       ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
                        break;
@@ -5242,7 +5892,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        CHECK_LOCAL (ip [1]);
                        NEW_LOCSTORE (cfg, ins, ip [1], *sp);
-                       ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
                                UNVERIFIED;
                        STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
@@ -5257,7 +5906,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDNULL:
                        CHECK_STACK_OVF (1);
                        NEW_PCONST (cfg, ins, NULL);
-                       ins->cil_code = ip;
                        ins->type = STACK_OBJ;
                        ++ip;
                        *sp++ = ins;
@@ -5265,7 +5913,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDC_I4_M1:
                        CHECK_STACK_OVF (1);
                        NEW_ICONST (cfg, ins, -1);
-                       ins->cil_code = ip;
                        ++ip;
                        *sp++ = ins;
                        break;
@@ -5280,7 +5927,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDC_I4_8:
                        CHECK_STACK_OVF (1);
                        NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
-                       ins->cil_code = ip;
                        ++ip;
                        *sp++ = ins;
                        break;
@@ -5289,7 +5935,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        ++ip;
                        NEW_ICONST (cfg, ins, *((signed char*)ip));
-                       ins->cil_code = ip;
                        ++ip;
                        *sp++ = ins;
                        break;
@@ -5297,7 +5942,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        CHECK_STACK_OVF (1);
                        NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
-                       ins->cil_code = ip;
                        ip += 5;
                        *sp++ = ins;
                        break;
@@ -5305,7 +5949,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (9);
                        CHECK_STACK_OVF (1);
                        MONO_INST_NEW (cfg, ins, OP_I8CONST);
-                       ins->cil_code = ip;
                        ins->type = STACK_I8;
                        ++ip;
                        ins->inst_l = (gint64)read64 (ip);
@@ -5363,14 +6006,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp++;
                                MONO_INST_NEW (cfg, temp, 0);
                                *temp = *ins;
-                               temp->cil_code = ip;
                                *sp++ = temp;
                        } else {
                                temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
                                temp->flags |= MONO_INST_IS_TEMP;
-                               temp->cil_code = ip;
                                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
-                               store->cil_code = ip;
                                /* FIXME: handle CEE_STIND_R4 */
                                if (store->opcode == CEE_STOBJ) {
                                        NEW_TEMPLOADA (cfg, store, temp->inst_c0);
@@ -5380,10 +6020,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                                NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
                                *sp++ = ins;
-                               ins->cil_code = ip;
                                NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
                                *sp++ = ins;
-                               ins->cil_code = ip;
                        }
                        ++ip;
                        inline_costs += 2;
@@ -5393,7 +6031,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, CEE_POP);
                        MONO_ADD_INS (bblock, ins);
-                       ins->cil_code = ip++;
+                       ip++;
                        --sp;
                        ins->inst_i0 = *sp;
                        break;
@@ -5404,7 +6042,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_INST_NEW (cfg, ins, OP_JMP);
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
-                       cmethod = mini_get_method (method, token, NULL, generic_context);
+                       cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
 
                        if (!cmethod)
                                goto load_error;
@@ -5430,10 +6068,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoMethodSignature *fsig = NULL;
                        int temp, array_rank = 0;
                        int virtual = *ip == CEE_CALLVIRT;
-                       MonoInst *rgctx_arg = NULL;
                        gboolean no_spill;
-                       int context_used = 0;
-                       gboolean pass_rgctx = FALSE;
+                       gboolean pass_imt_from_rgctx = FALSE;
+                       MonoInst *imt_arg = NULL;
+                       gboolean pass_vtable = FALSE;
+                       gboolean pass_mrgctx = FALSE;
+                       MonoInst *vtable_arg = NULL;
+                       gboolean check_this = FALSE;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
@@ -5459,14 +6100,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
                                        cil_method = cmethod;
                                } else {
-                                       cmethod = mini_get_method (method, token, NULL, generic_context);
+                                       cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
                                        cil_method = cmethod;
                                }
 
                                if (!cmethod)
                                        goto load_error;
-                               if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cil_method))
-                                       METHOD_ACCESS_FAILURE;
+                               if (!dont_verify && !cfg->skip_visibility) {
+                                       MonoMethod *target_method = cil_method;
+                                       if (method->is_inflated) {
+                                               target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
+                                       }
+                                       if (!mono_method_can_access_method (method_definition, target_method) &&
+                                               !mono_method_can_access_method (method, cil_method))
+                                               METHOD_ACCESS_FAILURE;
+                               }
 
                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
                                        ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
@@ -5512,6 +6160,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
                                UNVERIFIED;
 
+                       if (!cfg->generic_sharing_context && cmethod)
+                               g_assert (!mono_method_check_context_used (cmethod));
+
                        CHECK_STACK (n);
 
                        //g_assert (!virtual || fsig->hasthis);
@@ -5533,7 +6184,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         */
                                        MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, &constrained_call->byval_arg));
                                        type_to_eval_stack_type (cfg, &constrained_call->byval_arg, load);
-                                       load->cil_code = ip;
                                        load->inst_left = sp [0];
                                        sp [0] = handle_box (cfg, bblock, load, ip, constrained_call);
                                } else if (!constrained_call->valuetype) {
@@ -5546,7 +6196,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         */
 
                                        MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
-                                       ins->cil_code = ip;
                                        ins->inst_i0 = sp [0];
                                        ins->type = STACK_OBJ;
                                        ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
@@ -5566,7 +6215,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
 
                                /*
-                                * Pass rgctx iff target method might
+                                * Pass vtable iff target method might
                                 * be shared, which means that sharing
                                 * is enabled for its class and its
                                 * context is sharable (and it's not a
@@ -5574,7 +6223,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 */
                                if (sharing_enabled && context_sharable &&
                                                !mini_method_get_context (cmethod)->method_inst)
-                                       pass_rgctx = TRUE;
+                                       pass_vtable = TRUE;
+                       }
+
+                       if (cmethod && mini_method_get_context (cmethod) &&
+                                       mini_method_get_context (cmethod)->method_inst) {
+                               gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
+                               MonoGenericContext *context = mini_method_get_context (cmethod);
+                               gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+
+                               g_assert (!pass_vtable);
+
+                               if (sharing_enabled && context_sharable)
+                                       pass_mrgctx = TRUE;
                        }
 
                        if (cfg->generic_sharing_context && cmethod) {
@@ -5582,48 +6243,92 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                context_used = mono_method_check_context_used (cmethod);
 
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
-                                       GENERIC_SHARING_FAILURE (*ip);
-
-                               if (context_used &&
-                                               ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) ||
-                                               (cmethod_context && cmethod_context->method_inst && cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
-                                       GENERIC_SHARING_FAILURE (*ip);
+                               if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                                       /* Generic method interface
+                                          calls are resolved via a
+                                          helper function and don't
+                                          need an imt. */
+                                       if (!cmethod_context || !cmethod_context->method_inst)
+                                               pass_imt_from_rgctx = TRUE;
                                }
+
+                               /*
+                                * If a shared method calls another
+                                * shared method then the caller must
+                                * have a generic sharing context
+                                * because the magic trampoline
+                                * requires it.  FIXME: We shouldn't
+                                * have to force the vtable/mrgctx
+                                * variable here.  Instead there
+                                * should be a flag in the cfg to
+                                * request a generic sharing context.
+                                */
+                               if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
+                                       mono_get_vtable_var (cfg);
                        }
 
-                       if (pass_rgctx) {
+                       if (pass_vtable) {
                                if (context_used) {
-                                       MonoInst *this = NULL, *rgctx, *vtable, *field_offset, *field_addr;
+                                       MonoInst *rgctx;
 
-                                       GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
-                                       if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                               NEW_ARGLOAD (cfg, this, 0);
-                                       rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                                       vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
-                                               token, MINI_TOKEN_SOURCE_METHOD, generic_context,
-                                               rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+                                       GET_RGCTX (rgctx, context_used);
+                                       vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
+                                               bblock, cmethod->klass, generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+                               } else {
+                                       MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+                                       
+                                       CHECK_TYPELOAD (cmethod->klass);
+                                       NEW_VTABLECONST (cfg, vtable_arg, vtable);
+                               }
+                       }
 
-                                       NEW_ICONST (cfg, field_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
+                       if (pass_mrgctx) {
+                               g_assert (!vtable_arg);
 
-                                       MONO_INST_NEW (cfg, field_addr, OP_PADD);
-                                       field_addr->cil_code = ip;
-                                       field_addr->inst_left = vtable;
-                                       field_addr->inst_right = field_offset;
-                                       field_addr->type = STACK_PTR;
+                               if (context_used) {
+                                       MonoInst *rgctx;
 
-                                       MONO_INST_NEW (cfg, rgctx_arg, CEE_LDIND_I);
-                                       rgctx_arg->cil_code = ip;
-                                       rgctx_arg->inst_left = field_addr;
-                                       rgctx_arg->type = STACK_PTR;
+                                       GET_RGCTX (rgctx, context_used);
+                                       vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
+                                               context_used, bblock, cmethod, generic_context, rgctx, ip);
                                } else {
-                                       MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+                                       MonoMethodRuntimeGenericContext *mrgctx;
 
-                                       NEW_PCONST (cfg, rgctx_arg, vtable->runtime_generic_context);
+                                       mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
+                                               mini_method_get_context (cmethod)->method_inst);
+
+                                       NEW_PCONST (cfg, vtable_arg, mrgctx);
+                               }
+
+                               if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+                                               (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
+                                       if (virtual)
+                                               check_this = TRUE;
+                                       virtual = 0;
                                }
                        }
 
+                       if (pass_imt_from_rgctx) {
+                               MonoInst *rgctx;
+
+                               g_assert (!pass_vtable);
+                               g_assert (cmethod);
+
+                               GET_RGCTX (rgctx, context_used);
+                               imt_arg = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
+                                               generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+                       }
+
+                       if (check_this) {
+                               MonoInst *check;
+
+                               MONO_INST_NEW (cfg, check, OP_CHECK_THIS_PASSTHROUGH);
+                               check->cil_code = ip;
+                               check->inst_left = sp [0];
+                               check->type = sp [0]->type;
+                               sp [0] = check;
+                       }
+
                        if (cmethod && virtual && 
                            (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
                            !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
@@ -5637,23 +6342,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                INLINE_FAILURE;
 
                                this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
-                               this_temp->cil_code = ip;
                                NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
-
-                               store->cil_code = ip;
                                MONO_ADD_INS (bblock, store);
 
                                /* FIXME: This should be a managed pointer */
                                this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
-                               this_arg_temp->cil_code = ip;
 
                                /* Because of the PCONST below */
                                cfg->disable_aot = TRUE;
                                NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
-                               NEW_METHODCONST (cfg, iargs [1], cmethod);
-                               NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
-                               NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
+                               if (context_used) {
+                                       MonoInst *rgctx;
+
+                                       GET_RGCTX (rgctx, context_used);
+                                       iargs [1] = get_runtime_generic_context_method (cfg, method, context_used,
+                                                       bblock, cmethod,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+                                       NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
+                                       temp = mono_emit_jit_icall (cfg, bblock,
+                                               mono_helper_compile_generic_method_wo_context, iargs, ip);
+                               } else {
+                                       NEW_METHODCONST (cfg, iargs [1], cmethod);
+                                       NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
+                                       NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method,
+                                               iargs, ip);
+                               }
 
                                NEW_TEMPLOAD (cfg, addr, temp);
                                NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
@@ -5669,12 +6383,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        /* FIXME: runtime generic context pointer for jumps? */
-                       if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
+                       /* 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)))) {
                                int i;
 
-                               GENERIC_SHARING_FAILURE (*ip);
-
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
                                INLINE_FAILURE;
                                /* FIXME: This assumes the two methods has the same number and type of arguments */
@@ -5698,7 +6411,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                continue;
 
                                        NEW_ARGSTORE (cfg, ins, i, sp [i]);
-                                       ins->cil_code = ip;
                                        /* FIXME: handle CEE_STIND_R4 */
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_ARGLOADA (cfg, ins, i);
@@ -5708,7 +6420,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                MONO_ADD_INS (bblock, ins);
                                }
                                MONO_INST_NEW (cfg, ins, OP_JMP);
-                               ins->cil_code = ip;
                                ins->inst_p0 = cmethod;
                                ins->inst_p1 = arg_array [0];
                                MONO_ADD_INS (bblock, ins);
@@ -5720,8 +6431,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
                        if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
-                               ins->cil_code = ip;
-
                                if (MONO_TYPE_IS_VOID (fsig->ret)) {
                                        MONO_ADD_INS (bblock, ins);
                                } else {
@@ -5737,7 +6446,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                       if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
+                       if ((cfg->opt & MONO_OPT_INLINE) && cmethod && //!check_this &&
                            (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
                            mono_method_check_inlining (cfg, cmethod) &&
                                 !g_list_find (dont_inline, cmethod)) {
@@ -5778,7 +6487,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        /* tail recursion elimination */
                        if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
-                                       !rgctx_arg) {
+                                       !vtable_arg) {
                                gboolean has_vtargs = FALSE;
                                int i;
                                
@@ -5794,11 +6503,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        for (i = 0; i < n; ++i) {
                                                /* FIXME: handle CEE_STIND_R4 */
                                                NEW_ARGSTORE (cfg, ins, i, sp [i]);
-                                               ins->cil_code = ip;
                                                MONO_ADD_INS (bblock, ins);
                                        }
                                        MONO_INST_NEW (cfg, ins, OP_BR);
-                                       ins->cil_code = ip;
                                        MONO_ADD_INS (bblock, ins);
                                        tblock = start_bblock->out_bb [0];
                                        link_bblock (cfg, bblock, tblock);
@@ -5824,52 +6531,58 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                no_spill = FALSE;
 
+                       /* FIXME: only do this for generic methods if
+                          they are not shared! */
                        if (context_used &&
                                        (cmethod->klass->valuetype ||
-                                       (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) ||
+                                       (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
                                        ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
-                                               mono_class_generic_sharing_enabled (cmethod->klass)))) {
-                               MonoInst *this = NULL, *rgctx;
+                                               mono_class_generic_sharing_enabled (cmethod->klass)) ||
+                                       (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
+                                               (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+                                               !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
+                               MonoInst *rgctx;
 
                                INLINE_FAILURE;
 
                                g_assert (cfg->generic_sharing_context && cmethod);
-                               g_assert (addr == NULL);
+                               g_assert (!addr);
 
                                /*
-                                * We are compiling a call to a
-                                * generic method from shared code,
-                                * which means that we have to look up
-                                * the method in the rgctx and do an
-                                * indirect call.
+                                * We are compiling a call to
+                                * non-shared generic code from shared
+                                * code, which means that we have to
+                                * look up the method in the rgctx and
+                                * do an indirect call.
                                 */
-
-                               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
-                               if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                       NEW_ARGLOAD (cfg, this, 0);
-                               rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                               addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
+                               GET_RGCTX (rgctx, context_used);
+                               addr = get_runtime_generic_context_method (cfg, method, context_used, bblock, cmethod,
                                                generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
+
                        }
 
                        if (addr) {
-                               if (*ip == CEE_CALL)
+                               g_assert (!imt_arg);
+
+                               if (*ip == CEE_CALL) {
                                        g_assert (context_used);
-                               else if (*ip == CEE_CALLI)
-                                       g_assert (!rgctx_arg);
-                               else
-                                       g_assert_not_reached ();
+                               } else if (*ip == CEE_CALLI) {
+                                       g_assert (!vtable_arg);
+                               } else {
+                                       g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+                                                       !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
+                               }
 
                                /* Prevent inlining of methods with indirect calls */
                                INLINE_FAILURE;
                                if (no_spill) {
-                                       ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
+                                       ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
                                        *sp++ = ins;                                    
                                } else {
-                                       temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
+                                       temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
                                        if (temp != -1) {
                                                NEW_TEMPLOAD (cfg, *sp, temp);
+                                               NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
                                                sp++;
                                        }
                                }                       
@@ -5885,14 +6598,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                
                                                array = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
                                                NEW_TEMPSTORE (cfg, store, array->inst_c0, sp [0]);
-                                               store->cil_code = ip;
                                                MONO_ADD_INS (bblock, store);
                                                NEW_TEMPLOAD (cfg, iargs [0], array->inst_c0);
 
                                                to_store = mono_compile_create_var (cfg, type_from_stack_type (sp [fsig->param_count]), OP_LOCAL);
                                                NEW_TEMPSTORE (cfg, store, to_store->inst_c0, sp [fsig->param_count]);
                                                /* FIXME: handle CEE_STIND_R4 */
-                                               store->cil_code = ip;
                                                MONO_ADD_INS (bblock, store);
                                                NEW_TEMPLOAD (cfg, iargs [1], to_store->inst_c0);
 
@@ -5910,7 +6621,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                        addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
                                        NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
-                                       ins->cil_code = ip;
                                        /* FIXME: handle CEE_STIND_R4 */
                                        if (ins->opcode == CEE_STOBJ) {
                                                handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
@@ -5921,7 +6631,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
                                        addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
                                        NEW_INDLOAD (cfg, ins, addr, fsig->ret);
-                                       ins->cil_code = ip;
 
                                        *sp++ = ins;
                                } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
@@ -5931,7 +6640,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                mono_get_got_var (cfg);
 
                                                MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
-                                               check->cil_code = ip;
                                                check->klass = cmethod->klass;
                                                check->inst_left = sp [0];
                                                check->type = STACK_OBJ;
@@ -5954,10 +6662,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                sp++;
                                        }
                                } else if (no_spill) {
-                                       ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL);
+                                       ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
+                                                       vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL);
                                        *sp++ = ins;
                                } else {
-                                       if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL)) != -1) {
+                                       if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
+                                                       vtable_arg, imt_arg, ip, virtual ? sp [0] : NULL)) != -1) {
                                                MonoInst *load;
                                                NEW_TEMPLOAD (cfg, load, temp);
 
@@ -5987,7 +6697,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        //g_assert (returnvar != -1);
                                        NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
                                        store->cil_code = sp [0]->cil_code;
-                                       /* FIXME: handle CEE_STIND_R4 */
                                        if (store->opcode == CEE_STOBJ) {
                                                g_assert_not_reached ();
                                                NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
@@ -6014,7 +6723,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                handle_stobj (cfg, bblock, ins, *sp, ip, cfg->ret->klass, FALSE, FALSE, FALSE);
                                        } else {
                                                ins->opcode = OP_SETRET;
-                                               ins->cil_code = ip;
                                                ins->inst_i0 = *sp;;
                                                ins->inst_i1 = NULL;
                                                MONO_ADD_INS (bblock, ins);
@@ -6024,7 +6732,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start)
                                UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, OP_BR);
-                       ins->cil_code = ip++;
+                       ip++;
                        ins->inst_target_bb = end_bblock;
                        MONO_ADD_INS (bblock, ins);
                        link_bblock (cfg, bblock, end_bblock);
@@ -6033,7 +6741,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_BR_S:
                        CHECK_OPSIZE (2);
                        MONO_INST_NEW (cfg, ins, OP_BR);
-                       ins->cil_code = ip++;
+                       ip++;
                        MONO_ADD_INS (bblock, ins);
                        target = ip + 1 + (signed char)(*ip);
                        ++ip;
@@ -6056,7 +6764,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
                                UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
-                       ins->cil_code = ip++;
+                       ip++;
                        target = ip + 1 + *(signed char*)ip;
                        ip++;
                        ADD_UNCOND (ins->opcode == CEE_BRTRUE);
@@ -6080,7 +6788,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (2);
                        CHECK_STACK (2);
                        MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
-                       ins->cil_code = ip++;
+                       ip++;
                        target = ip + 1 + *(signed char*)ip;
                        ip++;
 #ifdef MONO_ARCH_SOFT_FLOAT
@@ -6109,7 +6817,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_BR:
                        CHECK_OPSIZE (5);
                        MONO_INST_NEW (cfg, ins, OP_BR);
-                       ins->cil_code = ip++;
+                       ip++;
                        MONO_ADD_INS (bblock, ins);
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
@@ -6132,7 +6840,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
                                UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, *ip);
-                       ins->cil_code = ip++;
+                       ip++;
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
                        ADD_UNCOND(ins->opcode == CEE_BRTRUE);
@@ -6156,7 +6864,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        CHECK_STACK (2);
                        MONO_INST_NEW (cfg, ins, *ip);
-                       ins->cil_code = ip++;
+                       ip++;
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
 #ifdef MONO_ARCH_SOFT_FLOAT
@@ -6191,7 +6899,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_left = *sp;
                        if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
                                UNVERIFIED;
-                       ins->cil_code = ip;
                        ip += 5;
                        CHECK_OPSIZE (n * sizeof (guint32));
                        target = ip + n * sizeof (guint32);
@@ -6230,7 +6937,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDIND_REF:
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, *ip);
-                       ins->cil_code = ip;
                        --sp;
                        ins->inst_i0 = *sp;
                        *sp++ = ins;
@@ -6277,7 +6983,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 #endif
                        MONO_INST_NEW (cfg, ins, *ip);
-                       ins->cil_code = ip++;
+                       ip++;
                        sp -= 2;
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        MONO_ADD_INS (bblock, ins);
@@ -6335,7 +7041,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        if ((ins->opcode == OP_LSHR_UN) && (ins->type == STACK_I8) 
                                        && (ins->inst_right->opcode == OP_ICONST) && (ins->inst_right->inst_c0 == 32)) {
-                               ins->opcode = OP_LONG_SHRUN_32;
+                               ins->opcode = OP_LSHR_UN_32;
                                /*g_print ("applied long shr speedup to %s\n", cfg->method->name);*/
                                ip++;
                                break;
@@ -6361,6 +7067,31 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_CONV_R_UN:
                        CHECK_STACK (1);
                        ADD_UNOP (*ip);
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       /*
+                        * Its rather hard to emit the soft float code during the decompose
+                        * pass, so avoid it in some specific cases.
+                        */
+                       if (ins->opcode == OP_LCONV_TO_R4) {
+                               MonoInst *conv;
+
+                               ins->opcode = OP_LCONV_TO_R8;
+                               ins->type = STACK_R8;
+
+                               --sp;
+                               *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
+
+                               MONO_INST_NEW (cfg, conv, CEE_CONV_R4);
+                               conv->inst_left = sp [-1];
+                               conv->type = STACK_R8;
+                               sp [-1] = ins;
+
+                               ip++;
+                               break;
+                       }
+#endif
+
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
@@ -6421,13 +7152,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (generic_class_is_reference_type (cfg, klass)) {
                                MonoInst *store, *load;
                                MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
-                               load->cil_code = ip;
                                load->inst_i0 = sp [1];
                                load->type = STACK_OBJ;
                                load->klass = klass;
                                load->flags |= ins_flag;
                                MONO_INST_NEW (cfg, store, CEE_STIND_REF);
-                               store->cil_code = ip;
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
                                MONO_ADD_INS (bblock, store);
                                store->inst_i0 = sp [0];
@@ -6447,7 +7176,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        iargs [0] = sp [0];
                                        iargs [1] = sp [1];
                                        NEW_ICONST (cfg, iargs [2], n);
-                                       iargs [2]->cil_code = ip;
 
                                        mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                                }
@@ -6469,7 +7197,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_TYPELOAD (klass);
                        if (generic_class_is_reference_type (cfg, klass)) {
                                MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
-                               ins->cil_code = ip;
                                ins->inst_i0 = sp [0];
                                ins->type = STACK_OBJ;
                                ins->klass = klass;
@@ -6504,7 +7231,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: handle CEE_STIND_R4 */
                                if (ins->opcode == CEE_STOBJ) {
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
-                                       ins->cil_code = ip;
                                        g_assert (ins->opcode == CEE_STOBJ);
                                        NEW_LOCLOADA (cfg, ins, loc_index);
                                        handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -6525,7 +7251,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoMethod *memcpy_method = get_memcpy_method ();
                                iargs [1] = *sp;
                                NEW_ICONST (cfg, iargs [2], n);
-                               iargs [2]->cil_code = ip;
 
                                mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                        }
@@ -6544,7 +7269,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
                                /* FIXME: moving GC */
                                NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
-                               ins->cil_code = ip;
                                ins->type = STACK_OBJ;
                                ins->klass = mono_defaults.string_class;
                                *sp = ins;
@@ -6603,7 +7327,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } 
                                        else {
                                                NEW_PCONST (cfg, ins, NULL);
-                                               ins->cil_code = ip;
                                                ins->type = STACK_OBJ;
                                                ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
                                                ins->klass = mono_defaults.string_class;
@@ -6618,12 +7341,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_NEWOBJ: {
                        MonoInst *iargs [2];
                        MonoMethodSignature *fsig;
+                       MonoInst this_ins;
                        int temp;
-                       gboolean generic_shared = FALSE;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       cmethod = mini_get_method (method, token, NULL, generic_context);
+                       cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
                        if (!cmethod)
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
@@ -6633,15 +7356,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!mono_class_init (cmethod->klass))
                                goto load_error;
 
-                       if (cfg->generic_sharing_context) {
-                               int context_used = mono_method_check_context_used (cmethod);
-
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
-                                       GENERIC_SHARING_FAILURE (CEE_NEWOBJ);
-
-                               if (context_used)
-                                       generic_shared = TRUE;
-                       }
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_method_check_context_used (cmethod);
 
                        if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                if (check_linkdemand (cfg, method, cmethod, bblock, ip))
@@ -6697,15 +7413,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp [1] = sp [0];
                        }
 
+                       /* check_call_signature () requires sp[0] to be set */
+                       this_ins.type = STACK_OBJ;
+                       sp [0] = &this_ins;
+                       if (check_call_signature (cfg, fsig, sp))
+                               UNVERIFIED;
+
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
 
                        if (mini_class_is_system_array (cmethod->klass)) {
-                               g_assert (!generic_shared);
+                               g_assert (!context_used);
 
                                NEW_METHODCONST (cfg, *sp, cmethod);
-                               temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
+
+                               if (fsig->param_count == 2)
+                                       /* Avoid varargs in the common case */
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_array_new_2, sp, ip);
+                               else
+                                       temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
                        } else if (cmethod->string_ctor) {
-                               g_assert (!generic_shared);
+                               g_assert (!context_used);
 
                                /* we simply pass a null pointer */
                                NEW_PCONST (cfg, *sp, NULL); 
@@ -6729,22 +7456,24 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                         * iargs [0] to be a boxed instance, but luckily the vcall
                                         * will be transformed into a normal call there.
                                         */
-                               } else if (generic_shared) {
-                                       MonoInst *this = NULL, *rgctx, *vtable;
+                               } else if (context_used) {
+                                       MonoInst *rgctx, *data;
+                                       int rgctx_info;
 
-                                       GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
-                                       if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                               NEW_ARGLOAD (cfg, this, 0);
-                                       rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                                       vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
-                                               token, MINI_TOKEN_SOURCE_METHOD, generic_context,
-                                               rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+                                       GET_RGCTX (rgctx, context_used);
+                                       if (cfg->opt & MONO_OPT_SHARED)
+                                               rgctx_info = MONO_RGCTX_INFO_KLASS;
+                                       else
+                                               rgctx_info = MONO_RGCTX_INFO_VTABLE;
+                                       data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock,
+                                               cmethod->klass, generic_context, rgctx, rgctx_info, ip);
 
-                                       temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, vtable, FALSE, ip);
+                                       temp = handle_alloc_from_inst (cfg, bblock, cmethod->klass, data, FALSE, ip);
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                } else {
                                        MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+
+                                       CHECK_TYPELOAD (cmethod->klass);
                                        if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
                                                guint8 *tramp = mono_create_class_init_trampoline (vtable);
                                                mono_emit_native_call (cfg, bblock, tramp, 
@@ -6762,7 +7491,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (cmethod->klass->marshalbyref)
                                        callvirt_this_arg = sp [0];
                                
-                               if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !generic_shared &&
+                               if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
                                    mono_method_check_inlining (cfg, cmethod) &&
                                    !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
                                    !g_list_find (dont_inline, cmethod)) {
@@ -6792,17 +7521,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                INLINE_FAILURE;
                                                mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                        }
-                               } else if (generic_shared && cmethod->klass->valuetype) {
-                                       MonoInst *this = NULL, *rgctx, *cmethod_addr;
+                               } else if (context_used &&
+                                               (cmethod->klass->valuetype ||
+                                               !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
+                                       MonoInst *rgctx, *cmethod_addr;
 
                                        g_assert (!callvirt_this_arg);
 
-                                       GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
-                                       if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                               NEW_ARGLOAD (cfg, this, 0);
-                                       rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                                       cmethod_addr = get_runtime_generic_context_method (cfg, method, bblock, cmethod,
+                                       GET_RGCTX (rgctx, context_used);
+                                       cmethod_addr = get_runtime_generic_context_method (cfg, method, context_used,
+                                                       bblock, cmethod,
                                                        generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
 
                                        mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
@@ -6821,9 +7549,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        inline_costs += 5;
                        break;
                }
-               case CEE_ISINST: {
-                       gboolean shared_access = FALSE;
-
+               case CEE_ISINST:
                        CHECK_STACK (1);
                        --sp;
                        CHECK_OPSIZE (5);
@@ -6833,36 +7559,24 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
-                       if (cfg->generic_sharing_context) {
-                               int context_used = mono_class_check_context_used (klass);
-
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
-                                       GENERIC_SHARING_FAILURE (CEE_ISINST);
-
-                               if (context_used)
-                                       shared_access = TRUE;
-                       }
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
                        /* Needed by the code generated in inssel.brg */
-                       if (!shared_access)
+                       if (!context_used)
                                mono_get_got_var (cfg);
 
-                       if (shared_access) {
-                               MonoInst *this = NULL, *rgctx;
-                               MonoInst *args [2];
+                       if (context_used) {
+                               MonoInst *rgctx, *args [2];
                                int temp;
 
-                               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
                                /* obj */
                                args [0] = *sp;
 
                                /* klass */
-                               if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                       NEW_ARGLOAD (cfg, this, 0);
-                               rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                               args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
-                                       token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
+                               GET_RGCTX (rgctx, context_used);
+                               args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                       generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
 
                                temp = mono_emit_jit_icall (cfg, bblock, mono_object_isinst, args, ip);
                                NEW_TEMPLOAD (cfg, *sp, temp);
@@ -6905,14 +7619,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->inst_left = *sp;
                                ins->inst_newa_class = klass;
                                ins->klass = klass;
-                               ins->cil_code = ip;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
                                ip += 5;
                        }
                        break;
-               }
                case CEE_UNBOX_ANY: {
-                       MonoInst *add, *vtoffset;
                        MonoInst *iargs [3];
                        guint32 align;
 
@@ -6923,80 +7634,44 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
-                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
-                               GENERIC_SHARING_FAILURE (CEE_UNBOX_ANY);
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
                        if (generic_class_is_reference_type (cfg, klass)) {
-                               /* CASTCLASS */
-                               if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-                                       MonoMethod *mono_castclass;
-                                       MonoInst *iargs [1];
-                                       MonoBasicBlock *ebblock;
-                                       int costs;
-                                       int temp;
-                                       
-                                       mono_castclass = mono_marshal_get_castclass (klass); 
-                                       iargs [0] = sp [0];
-                                       
-                                       costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
-                                                       iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
-                               
-                                       g_assert (costs > 0);
-                                       
-                                       ip += 5;
-                                       real_offset += 5;
-                               
-                                       GET_BBLOCK (cfg, bblock, ip);
-                                       ebblock->next_bb = bblock;
-                                       link_bblock (cfg, ebblock, bblock);
-       
-                                       temp = iargs [0]->inst_i0->inst_c0;
-                                       NEW_TEMPLOAD (cfg, *sp, temp);
-                                       
-                                       sp++;
-                                       bblock = ebblock;
-                                       inline_costs += costs;                          
-                               } else {
-                                       /* Needed by the code generated in inssel.brg */
-                                       mono_get_got_var (cfg);
-               
-                                       MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
-                                       ins->type = STACK_OBJ;
-                                       ins->inst_left = *sp;
-                                       ins->klass = klass;
-                                       ins->inst_newa_class = klass;
-                                       ins->cil_code = ip;
-                                       *sp++ = ins;
-                                       ip += 5;
+                               switch (emit_castclass (klass, token, context_used, FALSE,
+                                               cfg, method, arg_array, param_types, dont_inline, end, header,
+                                               generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
+                               case 0: break;
+                               case -1: goto unverified;
+                               case -2: goto exception_exit;
+                               default: g_assert_not_reached ();
                                }
                                break;
                        }
 
                        if (mono_class_is_nullable (klass)) {
-                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               int v;
+                               MonoInst *rgctx = NULL;
+
+                               if (context_used)
+                                       GET_RGCTX (rgctx, context_used);
+
+                               v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
+                                       generic_context, rgctx);
                                NEW_TEMPLOAD (cfg, *sp, v);
                                sp ++;
                                ip += 5;
                                break;
                        }
 
-                       /* Needed by the code generated in inssel.brg */
-                       mono_get_got_var (cfg);
-
-                       MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
-                       ins->type = STACK_OBJ;
-                       ins->inst_left = *sp;
-                       ins->klass = klass;
-                       ins->inst_newa_class = klass;
-                       ins->cil_code = ip;
-
-                       MONO_INST_NEW (cfg, add, OP_PADD);
-                       NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
-                       add->inst_left = ins;
-                       add->inst_right = vtoffset;
-                       add->type = STACK_MP;
-                       add->klass = mono_defaults.object_class;
-                       *sp = add;
+                       switch (emit_unbox (klass, token, context_used,
+                                       cfg, method, arg_array, param_types, dont_inline, end, header,
+                                       generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
+                       case 0: break;
+                       case -1: goto unverified;
+                       case -2: goto exception_exit;
+                       default: g_assert_not_reached ();
+                       }
                        ip += 5;
                        /* LDOBJ impl */
                        n = mono_class_value_size (klass, &align);
@@ -7010,7 +7685,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoMethod *memcpy_method = get_memcpy_method ();
                                iargs [1] = *sp;
                                NEW_ICONST (cfg, iargs [2], n);
-                               iargs [2]->cil_code = ip;
 
                                mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
                        }
@@ -7019,9 +7693,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        inline_costs += 2;
                        break;
                }
-               case CEE_UNBOX: {
-                       MonoInst *add, *vtoffset;
-
+               case CEE_UNBOX:
                        CHECK_STACK (1);
                        --sp;
                        CHECK_OPSIZE (5);
@@ -7029,38 +7701,36 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
-                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
-                               GENERIC_SHARING_FAILURE (CEE_UNBOX);
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
                        if (mono_class_is_nullable (klass)) {
-                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               int v;
+                               MonoInst *rgctx = NULL;
+
+                               if (context_used)
+                                       GET_RGCTX (rgctx, context_used);
+                               v = handle_unbox_nullable (cfg, method, context_used, bblock, *sp, ip, klass,
+                                       generic_context, rgctx);
                                NEW_TEMPLOAD (cfg, *sp, v);
                                sp ++;
                                ip += 5;
                                break;
                        }
 
-                       /* Needed by the code generated in inssel.brg */
-                       mono_get_got_var (cfg);
-
-                       MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
-                       ins->type = STACK_OBJ;
-                       ins->inst_left = *sp;
-                       ins->klass = klass;
-                       ins->inst_newa_class = klass;
-                       ins->cil_code = ip;
+                       switch (emit_unbox (klass, token, context_used,
+                                       cfg, method, arg_array, param_types, dont_inline, end, header,
+                                       generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
+                       case 0: break;
+                       case -1: goto unverified;
+                       case -2: goto exception_exit;
+                       default: g_assert_not_reached ();
+                       }
 
-                       MONO_INST_NEW (cfg, add, OP_PADD);
-                       NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
-                       add->inst_left = ins;
-                       add->inst_right = vtoffset;
-                       add->type = STACK_MP;
-                       add->klass = klass;
-                       *sp++ = add;
+                       sp++;
                        ip += 5;
                        inline_costs += 2;
                        break;
-               }
                case CEE_CASTCLASS:
                        CHECK_STACK (1);
                        --sp;
@@ -7071,51 +7741,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
-                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
-                               GENERIC_SHARING_FAILURE (CEE_CASTCLASS);
-
-                       /* Needed by the code generated in inssel.brg */
-                       mono_get_got_var (cfg);
-               
-                       if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-                               
-                               MonoMethod *mono_castclass;
-                               MonoInst *iargs [1];
-                               MonoBasicBlock *ebblock;
-                               int costs;
-                               int temp;
-                               
-                               mono_castclass = mono_marshal_get_castclass (klass); 
-                               iargs [0] = sp [0];
-                               
-                               costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), bblock, 
-                                               iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
-                       
-                               g_assert (costs > 0);
-                               
-                               ip += 5;
-                               real_offset += 5;
-                       
-                               GET_BBLOCK (cfg, bblock, ip);
-                               ebblock->next_bb = bblock;
-                               link_bblock (cfg, ebblock, bblock);
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
-                               temp = iargs [0]->inst_i0->inst_c0;
-                               NEW_TEMPLOAD (cfg, *sp, temp);
-                               
-                               sp++;
-                               bblock = ebblock;
-                               inline_costs += costs;
-                       } else {
-                               MONO_INST_NEW (cfg, ins, *ip);
-                               ins->type = STACK_OBJ;
-                               ins->inst_left = *sp;
-                               ins->klass = klass;
-                               ins->inst_newa_class = klass;
-                               ins->backend.record_cast_details = debug_options.better_cast_details;
-                               ins->cil_code = ip;
-                               *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
-                               ip += 5;
+                       switch (emit_castclass (klass, token, context_used, TRUE,
+                                       cfg, method, arg_array, param_types, dont_inline, end, header,
+                                       generic_context, &bblock, &ip, &sp, &inline_costs, &real_offset)) {
+                       case 0: break;
+                       case -1: goto unverified;
+                       case -2: goto exception_exit;
+                       default: g_assert_not_reached ();
                        }
                        break;
                case CEE_THROW:
@@ -7123,7 +7758,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_INST_NEW (cfg, ins, OP_THROW);
                        --sp;
                        ins->inst_left = *sp;
-                       ins->cil_code = ip++;
+                       ip++;
                        bblock->out_of_line = TRUE;
                        MONO_ADD_INS (bblock, ins);
                        MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
@@ -7206,13 +7841,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
                                        }
 #if HAVE_WRITE_BARRIERS
-                               } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF) {
+                               } else 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_marshal_get_write_barrier ();
                                        MonoInst *iargs [2];
                                        NEW_ICONST (cfg, offset_ins, foffset);
                                        MONO_INST_NEW (cfg, ins, OP_PADD);
-                                       ins->cil_code = ip;
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
@@ -7225,7 +7859,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else if (mini_type_to_stind (cfg, field->type) == CEE_STIND_R4) {
                                        NEW_ICONST (cfg, offset_ins, foffset);
                                        MONO_INST_NEW (cfg, ins, OP_PADD);
-                                       ins->cil_code = ip;
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
@@ -7236,13 +7869,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoInst *store;
                                        NEW_ICONST (cfg, offset_ins, foffset);
                                        MONO_INST_NEW (cfg, ins, OP_PADD);
-                                       ins->cil_code = ip;
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
 
                                        MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
-                                       store->cil_code = ip;
                                        store->inst_left = ins;
                                        store->inst_right = sp [1];
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -7290,12 +7921,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } else {
                                                temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
                                                NEW_TEMPLOAD (cfg, *sp, temp);
+                                               NEW_TEMPLOAD_SOFT_FLOAT (cfg, bblock, *sp, temp, ip);
                                                sp++;
                                        }
                                } else {
                                        NEW_ICONST (cfg, offset_ins, foffset);
                                        MONO_INST_NEW (cfg, ins, OP_PADD);
-                                       ins->cil_code = ip;
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
@@ -7307,7 +7938,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                MonoInst *load;
                                                MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
                                                type_to_eval_stack_type (cfg, field->type, load);
-                                               load->cil_code = ip;
                                                load->inst_left = ins;
                                                load->flags |= ins_flag;
                                                ins_flag = 0;
@@ -7330,9 +7960,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDSFLDA:
                case CEE_STSFLD: {
                        MonoClassField *field;
+                       gboolean is_special_static;
                        gpointer addr = NULL;
-                       gboolean shared_access = FALSE;
-                       int relation = 0;
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
@@ -7358,39 +7987,45 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        GENERIC_SHARING_FAILURE (*ip);
 #endif
 
-                       if (cfg->generic_sharing_context) {
-                               int context_used = mono_class_check_context_used (klass);
-
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD ||
-                                               klass->valuetype)
-                                       GENERIC_SHARING_FAILURE (*ip);
-
-                               if (context_used) {
-                                       relation = mono_class_generic_class_relation (klass, MONO_RGCTX_INFO_VTABLE,
-                                               method->klass, generic_context, NULL);
-                                       shared_access = TRUE;
-                               }
-                       }
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
                        g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
 
                        if ((*ip) == CEE_STSFLD)
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                       /* The special_static_fields field is init'd in mono_class_vtable, so it needs
-                        * to be called here.
-                        */
-                       if (!(cfg->opt & MONO_OPT_SHARED))
-                               mono_class_vtable (cfg->domain, klass);
-                       mono_domain_lock (cfg->domain);
-                       if (cfg->domain->special_static_fields)
-                               addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
-                       mono_domain_unlock (cfg->domain);
+                       is_special_static = mono_class_field_is_special_static (field);
 
-                       if (shared_access) {
-                               MonoInst *this, *rgctx, *static_data;
+                       if ((cfg->opt & MONO_OPT_SHARED) ||
+                                       (cfg->compile_aot && is_special_static) ||
+                                       (context_used && is_special_static)) {
+                               int temp;
+                               MonoInst *iargs [2];
 
-                               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
+                               g_assert (field->parent);
+                               if ((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) {
+                                       MonoInst *domain_var;
+                                       /* avoid depending on undefined C behavior in sequence points */
+                                       domain_var = mono_get_domainvar (cfg);
+                                       NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
+                               } else {
+                                       NEW_DOMAINCONST (cfg, iargs [0]);
+                               }
+                               if (context_used) {
+                                       MonoInst *rgctx;
+
+                                       GET_RGCTX (rgctx, context_used);
+                                       iargs [1] = get_runtime_generic_context_field (cfg, method, context_used,
+                                                       bblock, field,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
+                               } else {
+                                       NEW_FIELDCONST (cfg, iargs [1], field);
+                               }
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
+                               NEW_TEMPLOAD (cfg, ins, temp);
+                       } else if (context_used) {
+                               MonoInst *rgctx, *static_data;
 
                                /*
                                g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
@@ -7401,26 +8036,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (mono_class_needs_cctor_run (klass, method)) {
                                        MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
                                        MonoCallInst *call;
-                                       MonoInst *vtable;
+                                       MonoInst *vtable, *rgctx;
 
-                                       if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                               NEW_ARGLOAD (cfg, this, 0);
-                                       else
-                                               this = NULL;
-
-                                       if (relation == MINI_GENERIC_CLASS_RELATION_SELF && this) {
-                                               MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
-                                               vtable->cil_code = ip;
-                                               vtable->inst_left = this;
-                                               vtable->type = STACK_PTR;
-                                               vtable->klass = klass;
-                                       } else {
-                                               MonoInst *rgctx = get_runtime_generic_context (cfg, method, this, ip);
-
-                                               vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
-                                                       token, MINI_TOKEN_SOURCE_FIELD, generic_context,
-                                                       rgctx, MONO_RGCTX_INFO_VTABLE, ip);
-                                       }
+                                       GET_RGCTX (rgctx, context_used);
+                                       vtable = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_VTABLE, ip);
 
                                        call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
                                        call->inst.opcode = OP_TRAMPCALL_VTABLE;
@@ -7436,15 +8056,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                 *
                                 *   super_info.static_data + field->offset
                                 */
-
-                               if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                       NEW_ARGLOAD (cfg, this, 0);
-                               else
-                                       this = NULL;
-                               rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                               static_data = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
-                                       token, MINI_TOKEN_SOURCE_FIELD, generic_context,
-                                       rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
+                               GET_RGCTX (rgctx, context_used);
+                               static_data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                       generic_context, rgctx, MONO_RGCTX_INFO_STATIC_DATA, ip);
 
                                if (field->offset == 0) {
                                        ins = static_data;
@@ -7454,28 +8068,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_ICONST (cfg, field_offset, field->offset);
 
                                        MONO_INST_NEW (cfg, ins, OP_PADD);
-                                       ins->cil_code = ip;
                                        ins->inst_left = static_data;
                                        ins->inst_right = field_offset;
                                        ins->type = STACK_PTR;
                                        ins->klass = klass;
                                }
-                       } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
-                               int temp;
-                               MonoInst *iargs [2];
-                               MonoInst *domain_var;
-                               
-                               g_assert (field->parent);
-                               /* avoid depending on undefined C behavior in sequence points */
-                               domain_var = mono_get_domainvar (cfg);
-                               NEW_TEMPLOAD (cfg, iargs [0], domain_var->inst_c0);
-                               NEW_FIELDCONST (cfg, iargs [1], field);
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
-                               NEW_TEMPLOAD (cfg, ins, temp);
                        } else {
                                MonoVTable *vtable;
+
                                vtable = mono_class_vtable (cfg->domain, klass);
-                               if (!addr) {
+                               CHECK_TYPELOAD (klass);
+                               if (!is_special_static) {
                                        if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
                                                guint8 *tramp = mono_create_class_init_trampoline (vtable);
                                                mono_emit_native_call (cfg, bblock, tramp, 
@@ -7486,12 +8089,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                class_inits = g_slist_prepend (class_inits, vtable);
                                        } else {
                                                if (cfg->run_cctors) {
+                                                       MonoException *ex;
                                                        /* This makes so that inline cannot trigger */
                                                        /* .cctors: too many apps depend on them */
                                                        /* running with a specific order... */
                                                        if (! vtable->initialized)
                                                                INLINE_FAILURE;
-                                                       mono_runtime_class_init (vtable);
+                                                       ex = mono_runtime_class_init_full (vtable, FALSE);
+                                                       if (ex) {
+                                                               set_exception_object (cfg, ex);
+                                                               goto exception_exit;
+                                                       }                                       
                                                }
                                        }
                                        addr = (char*)vtable->data + field->offset;
@@ -7500,15 +8108,29 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                NEW_SFLDACONST (cfg, ins, field);
                                        else
                                                NEW_PCONST (cfg, ins, addr);
-                                       ins->cil_code = ip;
                                } else {
+                                       int temp;
+                                       MonoInst *iargs [1];
+
+                                       /* The special_static_fields
+                                        * field is init'd in
+                                        * mono_class_vtable, so it
+                                        * needs to be called here.
+                                        */
+                                       if (!(cfg->opt & MONO_OPT_SHARED)) {
+                                               mono_class_vtable (cfg->domain, klass);
+                                               CHECK_TYPELOAD (klass);
+                                       }
+                                       mono_domain_lock (cfg->domain);
+                                       if (cfg->domain->special_static_fields)
+                                               addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
+                                       mono_domain_unlock (cfg->domain);
+
                                        /* 
                                         * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
                                         * This could be later optimized to do just a couple of
                                         * memory dereferences with constant offsets.
                                         */
-                                       int temp;
-                                       MonoInst *iargs [1];
                                        NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
                                        temp = mono_emit_jit_icall (cfg, bblock, mono_get_special_static_data, iargs, ip);
                                        NEW_TEMPLOAD (cfg, ins, temp);
@@ -7524,7 +8146,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                sp--;
                                MONO_INST_NEW (cfg, store, mini_type_to_stind (cfg, field->type));
-                               store->cil_code = ip;
                                store->inst_left = ins;
                                store->inst_right = sp [0];
                                store->flags |= ins_flag;
@@ -7541,8 +8162,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_ADD_INS (bblock, store);
                        } else {
                                gboolean is_const = FALSE;
-                               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
-                               if (!shared_access && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
+                               MonoVTable *vtable = NULL;
+
+                               if (!context_used)
+                                       vtable = mono_class_vtable (cfg->domain, klass);
+
+                               CHECK_TYPELOAD (klass);
+                               if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
                                    vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
                                        gpointer addr = (char*)vtable->data + field->offset;
                                        int ro_type = field->type->type;
@@ -7615,7 +8241,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        CHECK_STACK_OVF (1);
                                        MONO_INST_NEW (cfg, load, mini_type_to_ldind (cfg, field->type));
                                        type_to_eval_stack_type (cfg, field->type, load);
-                                       load->cil_code = ip;
                                        load->inst_left = ins;
                                        load->flags |= ins_flag;
 #ifdef MONO_ARCH_SOFT_FLOAT
@@ -7647,7 +8272,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXME: should check item at sp [1] is compatible with the type of the store. */
                                MonoInst *store;
                                MONO_INST_NEW (cfg, store, n);
-                               store->cil_code = ip;
                                store->inst_left = sp [0];
                                store->inst_right = sp [1];
                                store->flags |= ins_flag;
@@ -7659,7 +8283,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_BOX: {
                        MonoInst *val;
-                       gboolean generic_shared = FALSE;
 
                        CHECK_STACK (1);
                        --sp;
@@ -7669,12 +8292,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
-                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass)) {
-                               if (mono_class_is_nullable (klass))
-                                       GENERIC_SHARING_FAILURE (CEE_BOX);
-                               else
-                                       generic_shared = TRUE;
-                       }
+                       if (cfg->generic_sharing_context)
+                               context_used =  mono_class_check_context_used (klass);
 
                        if (generic_class_is_reference_type (cfg, klass)) {
                                *sp++ = val;
@@ -7691,11 +8310,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
                                MONO_INST_NEW (cfg, ins, CEE_POP);
                                MONO_ADD_INS (bblock, ins);
-                               ins->cil_code = ip;
                                ins->inst_i0 = *sp;
                                ip += 5;
+                               cfg->ip = ip;
                                MONO_INST_NEW (cfg, ins, OP_BR);
-                               ins->cil_code = ip;
                                MONO_ADD_INS (bblock, ins);
                                if (*ip == CEE_BRTRUE_S) {
                                        CHECK_OPSIZE (2);
@@ -7722,19 +8340,27 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                start_new_bblock = 1;
                                break;
                        }
-                       if (generic_shared) {
-                               MonoInst *this = NULL, *rgctx, *vtable;
+                       if (context_used) {
+                               MonoInst *rgctx;
 
-                               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
+                               if (mono_class_is_nullable (klass)) {
+                                       GET_RGCTX (rgctx, context_used);
+                                       *sp++ = handle_box_nullable_from_inst (cfg, method, context_used, bblock, val,
+                                                       ip, klass, generic_context, rgctx);
+                               } else {
+                                       MonoInst *data;
+                                       int rgctx_info;
 
-                               if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                       NEW_ARGLOAD (cfg, this, 0);
-                               rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                               vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
-                                       token, MINI_TOKEN_SOURCE_CLASS, generic_context,
-                                       rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+                                       GET_RGCTX (rgctx, context_used);
+                                       if (cfg->opt & MONO_OPT_SHARED)
+                                               rgctx_info = MONO_RGCTX_INFO_KLASS;
+                                       else
+                                               rgctx_info = MONO_RGCTX_INFO_VTABLE;
+                                       data = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                                       generic_context, rgctx, rgctx_info, ip);
 
-                               *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, vtable);
+                                       *sp++ = handle_box_from_inst (cfg, bblock, val, ip, klass, data);
+                               }
                        } else {
                                *sp++ = handle_box (cfg, bblock, val, ip, klass);
                        }
@@ -7742,9 +8368,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        inline_costs += 1;
                        break;
                }
-               case CEE_NEWARR: {
-                       gboolean shared_access = FALSE;
-
+               case CEE_NEWARR:
                        CHECK_STACK (1);
                        --sp;
 
@@ -7764,32 +8388,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
-                       if (cfg->generic_sharing_context) {
-                               int context_used = mono_class_check_context_used (klass);
-
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD || klass->valuetype)
-                                       GENERIC_SHARING_FAILURE (CEE_NEWARR);
-
-                               if (context_used)
-                                       shared_access = TRUE;
-                       }
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
-                       if (shared_access) {
-                               MonoInst *this = NULL, *rgctx;
-                               MonoInst *args [3];
+                       if (context_used) {
+                               MonoInst *rgctx, *args [3];
                                int temp;
 
-                               GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
-
                                /* domain */
+                               /* FIXME: what about domain-neutral code? */
                                NEW_DOMAINCONST (cfg, args [0]);
 
                                /* klass */
-                               if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                       NEW_ARGLOAD (cfg, this, 0);
-                               rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                               args [1] = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
-                                       token, MINI_TOKEN_SOURCE_CLASS, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
+                               GET_RGCTX (rgctx, context_used);
+                               args [1] = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                       generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
 
                                /* array len */
                                args [2] = *sp;
@@ -7798,7 +8411,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_TEMPLOAD (cfg, ins, temp);
                        } else {
                                MONO_INST_NEW (cfg, ins, *ip);
-                               ins->cil_code = ip;
                                ins->inst_newa_class = klass;
                                ins->inst_newa_len = *sp;
                                ins->type = STACK_OBJ;
@@ -7837,7 +8449,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_INST_NEW (cfg, add, OP_PADD);
                                        add->inst_left = load;
                                        add->inst_right = data_offset;
-                                       add->cil_code = ip;
                                        iargs [0] = add;
                                        if (cfg->compile_aot) {
                                                NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
@@ -7853,14 +8464,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        inline_costs += 1;
                        break;
-               }
                case CEE_LDLEN:
                        CHECK_STACK (1);
                        --sp;
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, *ip);
-                       ins->cil_code = ip++;
+                       ip++;
                        ins->inst_left = *sp;
                        ins->type = STACK_PTR;
                        *sp++ = ins;
@@ -7885,7 +8495,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                mono_get_got_var (cfg);
 
                                MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
-                               check->cil_code = ip;
                                check->klass = mono_array_class_get (klass, 1);
                                check->inst_left = sp [0];
                                check->type = STACK_OBJ;
@@ -7895,7 +8504,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        readonly = FALSE;
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, ins, sp, klass);
-                       ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 5;
                        break;
@@ -7911,9 +8519,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, load, sp, klass);
-                       load->cil_code = ip;
                        MONO_INST_NEW (cfg, ins, mini_type_to_ldind (cfg, &klass->byval_arg));
-                       ins->cil_code = ip;
                        ins->inst_left = load;
                        *sp++ = ins;
                        type_to_eval_stack_type (cfg, &klass->byval_arg, ins);
@@ -7943,7 +8549,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                UNVERIFIED;
                        klass = array_access_to_klass (*ip, sp [0]);
                        NEW_LDELEMA (cfg, load, sp, klass);
-                       load->cil_code = ip;
 #ifdef MONO_ARCH_SOFT_FLOAT
                        if (*ip == CEE_LDELEM_R4) {
                                int temp;
@@ -7955,7 +8560,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 #endif
                        MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
-                       ins->cil_code = ip;
                        ins->inst_left = load;
                        *sp++ = ins;
                        ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
@@ -7982,7 +8586,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                UNVERIFIED;
                        klass = array_access_to_klass (*ip, sp [0]);
                        NEW_LDELEMA (cfg, load, sp, klass);
-                       load->cil_code = ip;
 #ifdef MONO_ARCH_SOFT_FLOAT
                        if (*ip == CEE_STELEM_R4) {
                                handle_store_float (cfg, bblock, load, sp [2], ip);
@@ -7991,7 +8594,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 #endif
                        MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
-                       ins->cil_code = ip;
                        ins->inst_left = load;
                        ins->inst_right = sp [2];
                        ++ip;
@@ -8021,9 +8623,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
                                        MonoInst *load;
                                        NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
-                                       load->cil_code = ip;
                                        MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
-                                       ins->cil_code = ip;
                                        ins->inst_left = load;
                                        ins->inst_right = sp [2];
                                        MONO_ADD_INS (bblock, ins);
@@ -8040,7 +8640,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        } else {
                                NEW_LDELEMA (cfg, load, sp, klass);
-                               load->cil_code = ip;
 
                                n = mini_type_to_stind (cfg, &klass->byval_arg);
                                /* FIXME: CEE_STIND_R4 */
@@ -8048,7 +8647,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
                                else {
                                        MONO_INST_NEW (cfg, ins, n);
-                                       ins->cil_code = ip;
                                        ins->inst_left = load;
                                        ins->inst_right = sp [2];
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -8076,9 +8674,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
                                MonoInst *load;
                                NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
-                               load->cil_code = ip;
                                MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
-                               ins->cil_code = ip;
                                ins->inst_left = load;
                                ins->inst_right = sp [2];
                                MONO_ADD_INS (bblock, ins);
@@ -8105,12 +8701,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        
                        MONO_INST_NEW (cfg, ins, OP_CKFINITE);
-                       ins->cil_code = ip;
                        ins->inst_left = sp [-1];
                        temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
 
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
-                       store->cil_code = ip;
                        MONO_ADD_INS (bblock, store);
 
                        NEW_TEMPLOAD (cfg, sp [-1], temp->inst_c0);
@@ -8120,41 +8714,86 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
                case CEE_REFANYVAL:
                        CHECK_STACK (1);
-                       MONO_INST_NEW (cfg, ins, *ip);
                        --sp;
                        CHECK_OPSIZE (5);
-                       klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+                       token = read32 (ip + 1);
+                       klass = mono_class_get_full (image, token, generic_context);
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
-                       ins->type = STACK_MP;
-                       ins->inst_left = *sp;
-                       ins->klass = klass;
-                       ins->inst_newa_class = klass;
-                       ins->cil_code = ip;
+
+                       /* Needed by the code generated in inssel.brg */
+                       mono_get_got_var (cfg);
+
+                       if (cfg->generic_sharing_context) {
+                               context_used = mono_class_check_context_used (klass);
+                               if (context_used && cfg->compile_aot)
+                                       GENERIC_SHARING_FAILURE (*ip);
+                       }
+
+                       if (context_used) {
+                               MonoInst *rgctx;
+
+                               MONO_INST_NEW (cfg, ins, OP_REFANYVAL_REG);
+                               ins->type = STACK_MP;
+                               ins->inst_left = *sp;
+                               ins->klass = klass;
+
+                               GET_RGCTX (rgctx, context_used);
+                               ins->inst_right = get_runtime_generic_context_ptr (cfg, method, context_used,
+                                               bblock, klass, generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
+                       } else {
+                               MONO_INST_NEW (cfg, ins, *ip);
+                               ins->type = STACK_MP;
+                               ins->inst_left = *sp;
+                               ins->klass = klass;
+                               ins->inst_newa_class = klass;
+                       }
                        ip += 5;
                        *sp++ = ins;
                        break;
                case CEE_MKREFANY: {
-                       MonoInst *loc, *klassconst;
+                       MonoInst *loc;
 
                        CHECK_STACK (1);
-                       MONO_INST_NEW (cfg, ins, *ip);
                        --sp;
                        CHECK_OPSIZE (5);
-                       klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+                       token = read32 (ip + 1);
+                       klass = mono_class_get_full (image, token, generic_context);
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
-                       ins->cil_code = ip;
 
-                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
-                               GENERIC_SHARING_FAILURE (CEE_MKREFANY);
+                       if (cfg->generic_sharing_context) {
+                               context_used = mono_class_check_context_used (klass);
+                               if (context_used && cfg->compile_aot)
+                                       GENERIC_SHARING_FAILURE (CEE_MKREFANY);
+                       }
 
                        loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
-                       NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
+                       if (context_used) {
+                               MonoInst *rgctx, *klass_type, *klass_klass, *loc_load;
+
+                               GET_RGCTX (rgctx, context_used);
+                               klass_klass = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                               generic_context, rgctx, MONO_RGCTX_INFO_KLASS, ip);
+                               GET_RGCTX (rgctx, context_used);
+                               klass_type = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, klass,
+                                               generic_context, rgctx, MONO_RGCTX_INFO_TYPE, ip);
+
+                               NEW_TEMPLOADA (cfg, loc_load, loc->inst_c0);
+
+                               MONO_INST_NEW (cfg, ins, OP_MKREFANY_REGS);
+                               NEW_GROUP (cfg, ins->inst_left, klass_type, klass_klass);
+                               NEW_GROUP (cfg, ins->inst_right, *sp, loc_load);
+                       } else {
+                               MonoInst *klassconst;
+
+                               NEW_PCONST (cfg, klassconst, klass);
+
+                               MONO_INST_NEW (cfg, ins, *ip);
+                               NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
+                               NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
+                       }
 
-                       NEW_PCONST (cfg, klassconst, klass);
-                       NEW_GROUP (cfg, ins->inst_left, *sp, klassconst);
-                       
                        MONO_ADD_INS (bblock, ins);
 
                        NEW_TEMPLOAD (cfg, *sp, loc->inst_c0);
@@ -8165,7 +8804,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDTOKEN: {
                        gpointer handle;
                        MonoClass *handle_class;
-                       int context_used = 0;
 
                        CHECK_STACK_OVF (1);
 
@@ -8201,23 +8839,35 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        context_used = mono_method_check_context_used (handle);
                                else
                                        g_assert_not_reached ();
-
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
-                                       GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
                        }
 
                        if (cfg->opt & MONO_OPT_SHARED) {
                                int temp;
                                MonoInst *res, *store, *addr, *vtvar, *iargs [3];
+                               int method_context_used;
 
-                               GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
+                               if (cfg->generic_sharing_context)
+                                       method_context_used = mono_method_check_context_used (method);
+                               else
+                                       method_context_used = 0;
 
                                vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
 
                                NEW_IMAGECONST (cfg, iargs [0], image);
                                NEW_ICONST (cfg, iargs [1], n);
-                               NEW_PCONST (cfg, iargs [2], generic_context);
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
+                               if (method_context_used) {
+                                       MonoInst *rgctx;
+
+                                       GET_RGCTX (rgctx, method_context_used);
+                                       iargs [2] = get_runtime_generic_context_method (cfg, method, method_context_used,
+                                                       bblock, method,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper_generic_shared,
+                                                       iargs, ip);
+                               } else {
+                                       NEW_PCONST (cfg, iargs [2], generic_context);
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
+                               }
                                NEW_TEMPLOAD (cfg, res, temp);
                                NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
                                NEW_INDSTORE (cfg, store, addr, res, &mono_defaults.int_class->byval_arg);
@@ -8227,22 +8877,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if ((ip + 10 < end) && ip_in_bb (cfg, bblock, ip + 5) &&
                                        handle_class == mono_defaults.typehandle_class &&
                                        ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
-                                       (cmethod = mini_get_method (method, read32 (ip + 6), NULL, generic_context)) &&
+                                       (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
                                        (cmethod->klass == mono_defaults.monotype_class->parent) &&
                                        (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
                                        MonoClass *tclass = mono_class_from_mono_type (handle);
                                        mono_class_init (tclass);
                                        if (context_used) {
-                                               MonoInst *this, *rgctx;
+                                               MonoInst *rgctx;
 
                                                g_assert (!cfg->compile_aot);
-                                               if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
-                                                       NEW_ARGLOAD (cfg, this, 0);
-                                               rgctx = get_runtime_generic_context (cfg, method, this, ip);
-                                               ins = get_runtime_generic_context_ptr (cfg, method, bblock, tclass,
-                                                       token, MINI_TOKEN_SOURCE_CLASS, generic_context,
-                                                       rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
+
+                                               GET_RGCTX (rgctx, context_used);
+                                               ins = get_runtime_generic_context_ptr (cfg, method, context_used, bblock, tclass,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_REFLECTION_TYPE, ip);
                                        } else if (cfg->compile_aot) {
+                                               /*
+                                                * FIXME: We would have to include the context into the
+                                                * aot constant too (tests/generic-array-type.2.exe).
+                                                */
+                                               if (generic_context)
+                                                       cfg->disable_aot = TRUE;
                                                NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
                                        } else {
                                                NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
@@ -8253,12 +8907,34 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else {
                                        MonoInst *store, *addr, *vtvar;
 
-                                       GENERIC_SHARING_FAILURE (CEE_LDTOKEN);
+                                       if (context_used) {
+                                                       MonoInst *rgctx;
+
+                                               g_assert (!cfg->compile_aot);
 
-                                       if (cfg->compile_aot)
+                                               GET_RGCTX (rgctx, context_used);
+                                               if (handle_class == mono_defaults.typehandle_class) {
+                                                       ins = get_runtime_generic_context_ptr (cfg, method,
+                                                                       context_used, bblock,
+                                                                       mono_class_from_mono_type (handle), generic_context,
+                                                                       rgctx, MONO_RGCTX_INFO_TYPE, ip);
+                                               } else if (handle_class == mono_defaults.methodhandle_class) {
+                                                       ins = get_runtime_generic_context_method (cfg, method,
+                                                                       context_used, bblock, handle, generic_context,
+                                                                       rgctx, MONO_RGCTX_INFO_METHOD, ip);
+                                               } else if (handle_class == mono_defaults.fieldhandle_class) {
+                                                       ins = get_runtime_generic_context_field (cfg, method,
+                                                                       context_used, bblock, handle, generic_context,
+                                                                       rgctx, MONO_RGCTX_INFO_CLASS_FIELD, ip);
+                                               } else {
+                                                       g_assert_not_reached ();
+                                               }
+                                       }
+                                       else if (cfg->compile_aot) {
                                                NEW_LDTOKENCONST (cfg, ins, image, n);
-                                       else
+                                       } else {
                                                NEW_PCONST (cfg, ins, handle);
+                                       }
                                        vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
                                        NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
                                        NEW_INDSTORE (cfg, store, addr, ins, &mono_defaults.int_class->byval_arg);
@@ -8295,7 +8971,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_ENDFINALLY:
                        MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
                        MONO_ADD_INS (bblock, ins);
-                       ins->cil_code = ip++;
+                       ip++;
                        start_new_bblock = 1;
 
                        /*
@@ -8304,7 +8980,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        while (sp != stack_start) {
                                MONO_INST_NEW (cfg, ins, CEE_POP);
-                               ins->cil_code = ip;
                                sp--;
                                ins->inst_i0 = *sp;
                                MONO_ADD_INS (bblock, ins);
@@ -8325,7 +9000,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        /* empty the stack */
                        while (sp != stack_start) {
                                MONO_INST_NEW (cfg, ins, CEE_POP);
-                               ins->cil_code = ip;
                                sp--;
                                ins->inst_i0 = *sp;
                                MONO_ADD_INS (bblock, ins);
@@ -8349,7 +9023,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoInst *load;
 
                                        NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
-                                       load->cil_code = ip;
 
                                        temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_undeniable_exception, NULL, ip);
                                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -8357,7 +9030,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
                                        ins->inst_left = *sp;
                                        ins->inst_right = load;
-                                       ins->cil_code = ip;
                                        MONO_ADD_INS (bblock, ins);
                                }
                        }
@@ -8368,7 +9040,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        tblock = tmp->data;
                                        link_bblock (cfg, bblock, tblock);
                                        MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
-                                       ins->cil_code = ip;
                                        ins->inst_target_bb = tblock;
                                        MONO_ADD_INS (bblock, ins);
                                }
@@ -8376,7 +9047,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        } 
 
                        MONO_INST_NEW (cfg, ins, OP_BR);
-                       ins->cil_code = ip;
                        MONO_ADD_INS (bblock, ins);
                        GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
@@ -8397,7 +9067,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        MONO_ADD_INS (bblock, ins);
-                       ins->cil_code = ip++;
+                       ip++;
                        ins->inst_i0 = sp [0];
                        ins->inst_i1 = sp [1];
                        inline_costs += 1;
@@ -8451,19 +9121,42 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
 
                                ptr = mono_method_get_wrapper_data (method, token);
-                               if (cfg->compile_aot && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+                               if (cfg->compile_aot && (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
                                        MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
 
                                        if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
                                                NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
-                                               ins->cil_code = ip;
                                                *sp++ = ins;
                                                ip += 6;
                                                break;
                                        }
+
+                                       if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
+                                               MonoJitICallInfo *callinfo;
+                                               const char *icall_name;
+
+                                               icall_name = method->name + strlen ("__icall_wrapper_");
+                                               g_assert (icall_name);
+                                               callinfo = mono_find_jit_icall_by_name (icall_name);
+                                               g_assert (callinfo);
+
+                                               if (ptr == callinfo->func) {
+                                                       /* Will be transformed into an AOTCONST later */
+                                                       NEW_PCONST (cfg, ins, ptr);
+                                                       *sp++ = ins;
+                                                       ip += 6;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               /* FIXME: Generalize this */
+                               if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
+                                       NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
+                                       *sp++ = ins;
+                                       ip += 6;
+                                       break;
                                }
                                NEW_PCONST (cfg, ins, ptr);
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 6;
                                inline_costs += 10 * num_calls++;
@@ -8475,7 +9168,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                --sp;
                                MONO_INST_NEW (cfg, ins, OP_VTADDR);
-                               ins->cil_code = ip;
                                ins->type = STACK_MP;
                                ins->inst_left = *sp;
                                *sp++ = ins;
@@ -8502,7 +9194,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                --sp;
                                MONO_INST_NEW (cfg, ins, OP_OBJADDR);
-                               ins->cil_code = ip;
                                ins->type = STACK_MP;
                                ins->inst_left = *sp;
                                *sp++ = ins;
@@ -8536,7 +9227,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        UNVERIFIED;
                                
                                MONO_INST_NEW (cfg, ins, OP_BR);
-                               ins->cil_code = ip;
                                ins->inst_target_bb = end_bblock;
                                MONO_ADD_INS (bblock, ins);
                                link_bblock (cfg, bblock, end_bblock);
@@ -8552,13 +9242,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
                                /* Needed by the code generated in inssel.brg */
                                mono_get_got_var (cfg);
+
+#ifdef __i386__
+                               /* 
+                                * The code generated for CCASTCLASS has too much register pressure
+                                * (obj+vtable+ibitmap_byte_reg+iid_reg), leading to the usual
+                                * branches-inside-bblocks problem.
+                                */
+                               cfg->disable_aot = TRUE;
+#endif
                
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
                                MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_CISINST) ? OP_CISINST : OP_CCASTCLASS);
                                ins->type = STACK_I4;
                                ins->inst_left = *sp;
                                ins->inst_newa_class = klass;
-                               ins->cil_code = ip;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
                                ip += 6;
                                break;
@@ -8577,7 +9275,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
                                NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 6;
                                inline_costs += 10 * num_calls++;
@@ -8591,7 +9288,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                MONO_INST_NEW (cfg, ins, OP_TLS_GET);
                                ins->inst_offset = (gint32)read32 (ip + 2);
-                               ins->cil_code = ip;
                                ins->type = STACK_PTR;
                                *sp++ = ins;
                                ip += 6;
@@ -8612,13 +9308,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
 
                                NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
-                               addr->cil_code = ip;
                                MONO_INST_NEW (cfg, ins, OP_ARGLIST);
-                               ins->cil_code = ip;
                                ins->inst_left = addr;
                                MONO_ADD_INS (bblock, ins);
                                NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 2;
                                break;
@@ -8644,10 +9337,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp -= 2;
                                cmp->inst_i0 = sp [0];
                                cmp->inst_i1 = sp [1];
-                               cmp->cil_code = ip;
                                type_from_op (cmp);
                                CHECK_TYPE (cmp);
-                               ins->cil_code = ip;
                                ins->type = STACK_I4;
                                ins->inst_i0 = cmp;
 #if MONO_ARCH_SOFT_FLOAT
@@ -8677,22 +9368,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *argconst;
                                MonoMethod *cil_method, *ctor_method;
                                int temp;
-                               gboolean is_shared;
+                               gboolean is_shared = FALSE;
 
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
-                               cmethod = mini_get_method (method, n, NULL, generic_context);
+                               cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
                                if (!cmethod)
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
-                               if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
-                                       GENERIC_SHARING_FAILURE (CEE_LDFTN);
+                               if (cfg->generic_sharing_context)
+                                       context_used = mono_method_check_context_used (cmethod);
 
-                               is_shared = (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
-                                       (cmethod->klass->generic_class || cmethod->klass->generic_container) &&
-                                       mono_class_generic_sharing_enabled (cmethod->klass);
+                               if (mono_class_generic_sharing_enabled (cmethod->klass)) {
+                                       if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
+                                                       (cmethod->klass->generic_class ||
+                                                       cmethod->klass->generic_container)) {
+                                               is_shared = TRUE;
+                                       }
+                                       if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
+                                               is_shared = TRUE;
+                               }
 
                                cil_method = cmethod;
                                if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
@@ -8711,7 +9408,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
                                /* FIXME: SGEN support */
                                /* FIXME: handle shared static generic methods */
-                               if (!is_shared && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+                               /* FIXME: handle this in shared code */
+                               if (!is_shared && !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;
 
                                        ip += 6;
@@ -8728,10 +9426,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                               if (is_shared)
+                               if (context_used) {
+                                       MonoInst *rgctx;
+
+                                       if (is_shared)
+                                               cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
+
+                                       GET_RGCTX (rgctx, context_used);
+                                       argconst = get_runtime_generic_context_method (cfg, method, context_used,
+                                                       bblock, cmethod,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+                               } else if (is_shared) {
                                        NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
-                               else
+                               } else {
                                        NEW_METHODCONST (cfg, argconst, cmethod);
+                               }
                                if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
                                        temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
                                else
@@ -8750,13 +9459,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
-                               cmethod = mini_get_method (method, n, NULL, generic_context);
+                               cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
                                if (!cmethod)
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
-                               if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
-                                       GENERIC_SHARING_FAILURE (CEE_LDVIRTFTN);
+                               if (cfg->generic_sharing_context)
+                                       context_used = mono_method_check_context_used (cmethod);
 
                                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                                        if (check_linkdemand (cfg, method, cmethod, bblock, ip))
@@ -8770,8 +9479,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                --sp;
                                args [0] = *sp;
-                               NEW_METHODCONST (cfg, args [1], cmethod);
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
+                               if (context_used) {
+                                       MonoInst *rgctx;
+
+                                       GET_RGCTX (rgctx, context_used);
+                                       args [1] = get_runtime_generic_context_method (cfg, method, context_used,
+                                                       bblock, cmethod,
+                                                       generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn_gshared, args, ip);
+                               } else {
+                                       NEW_METHODCONST (cfg, args [1], cmethod);
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldvirtfn, args, ip);
+                               }
                                NEW_TEMPLOAD (cfg, *sp, temp);
                                sp ++;
 
@@ -8786,7 +9505,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_ARG (n);
                                NEW_ARGLOAD (cfg, ins, n);
                                LDARG_SOFT_FLOAT (cfg, ins, n, ip);
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
                                break;
@@ -8796,7 +9514,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_ARG (n);
                                NEW_ARGLOADA (cfg, ins, n);
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
                                break;
@@ -8808,7 +9525,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_ARG (n);
                                NEW_ARGSTORE (cfg, ins, n, *sp);
-                               ins->cil_code = ip;
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
                                        UNVERIFIED;
                                STARG_SOFT_FLOAT (cfg, ins, n, ip);
@@ -8826,7 +9542,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_LOCAL (n);
                                NEW_LOCLOAD (cfg, ins, n);
                                LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
                                break;
@@ -8836,7 +9551,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_LOCAL (n);
                                NEW_LOCLOADA (cfg, ins, n);
-                               ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
                                break;
@@ -8850,7 +9564,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_LOCSTORE (cfg, ins, n, *sp);
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
                                        UNVERIFIED;
-                               ins->cil_code = ip;
                                STLOC_SOFT_FLOAT (cfg, ins, n, ip);
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_LOCLOADA (cfg, ins, n);
@@ -8874,7 +9587,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        goto inline_failure;
                                MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
                                ins->inst_left = *sp;
-                               ins->cil_code = ip;
                                ins->type = STACK_PTR;
 
                                cfg->flags |= MONO_CFG_HAS_ALLOCA;
@@ -8895,7 +9607,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        UNVERIFIED;
                                MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
                                ins->inst_left = *sp;
-                               ins->cil_code = ip;
                                MONO_ADD_INS (bblock, ins);
                                start_new_bblock = 1;
                                ip += 2;
@@ -8945,17 +9656,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (generic_class_is_reference_type (cfg, klass)) {
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
-                                       load->cil_code = ip;
                                        load->type = STACK_OBJ;
                                        load->klass = klass;
                                        MONO_INST_NEW (cfg, store, CEE_STIND_REF);
-                                       store->cil_code = ip;
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                                        MONO_ADD_INS (bblock, store);
                                        store->inst_i0 = sp [0];
                                        store->inst_i1 = load;
                                } else {
-                                       GENERIC_SHARING_FAILURE (CEE_INITOBJ);
                                        handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
                                }
                                ip += 6;
@@ -9022,10 +9730,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                g_assert (handler_offset != -1);
 
                                NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
-                               load->cil_code = ip;
                                MONO_INST_NEW (cfg, ins, OP_RETHROW);
                                ins->inst_left = load;
-                               ins->cil_code = ip;
                                MONO_ADD_INS (bblock, ins);
                                sp = stack_start;
                                link_bblock (cfg, bblock, end_bblock);
@@ -9034,8 +9740,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
                        case CEE_SIZEOF:
-                               GENERIC_SHARING_FAILURE (CEE_SIZEOF);
-
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
@@ -9050,7 +9754,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        token = mono_class_value_size (klass, &align);
                                }
                                NEW_ICONST (cfg, ins, token);
-                               ins->cil_code = ip;
                                *sp++= ins;
                                ip += 6;
                                break;
@@ -9062,7 +9765,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->inst_left = *sp;
                                ins->type = STACK_VTYPE;
                                ins->klass = mono_defaults.typehandle_class;
-                               ins->cil_code = ip;
                                ip += 2;
                                *sp++ = ins;
                                break;
@@ -9108,6 +9810,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        if (header->init_locals) {
                MonoInst *store;
+               cfg->ip = header->code;
                for (i = 0; i < header->num_locals; ++i) {
                        MonoType *ptype = header->locals [i];
                        int t = ptype->type;
@@ -9149,6 +9852,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
 
+       cfg->ip = NULL;
+
        /* resolve backward branches in the middle of an existing basic block */
        for (tmp = bb_recheck; tmp; tmp = tmp->next) {
                bblock = tmp->data;
@@ -9393,7 +10098,7 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
        g_free (name);
 
-       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
+       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper, TRUE));
        mono_register_jit_icall_wrapper (callinfo, trampoline);
 
        callinfo->trampoline = trampoline;
@@ -9423,23 +10128,312 @@ mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
        return res;
 }
 
-typedef struct {
-       MonoClass *vtype;
-       GList *active;
-       GSList *slots;
-} StackSlotInfo;
+typedef struct {
+       MonoClass *vtype;
+       GList *active, *inactive;
+       GSList *slots;
+} StackSlotInfo;
+
+static inline GSList*
+g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
+                                                gpointer  data)
+{
+  GSList *new_list;
+
+  new_list = mono_mempool_alloc (mp, sizeof (GSList));
+  new_list->data = data;
+  new_list->next = list;
+
+  return new_list;
+}
+
+static gint 
+compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
+{
+       MonoMethodVar *v1 = (MonoMethodVar*)a;
+       MonoMethodVar *v2 = (MonoMethodVar*)b;
+
+       if (v1 == v2)
+               return 0;
+       else if (v1->interval->range && v2->interval->range)
+               return v1->interval->range->from - v2->interval->range->from;
+       else if (v1->interval->range)
+               return -1;
+       else
+               return 1;
+}
+
+#if 0
+#define LSCAN_DEBUG(a) do { a; } while (0)
+#else
+#define LSCAN_DEBUG(a)
+#endif
+
+static gint32*
+mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
+{
+       int i, slot, offset, size;
+       guint32 align;
+       MonoMethodVar *vmv;
+       MonoInst *inst;
+       gint32 *offsets;
+       GList *vars = NULL, *l, *unhandled;
+       StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
+       MonoType *t;
+       int nvtypes;
+
+       LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
+
+       scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
+       vtype_stack_slots = NULL;
+       nvtypes = 0;
+
+       offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
+       for (i = 0; i < cfg->num_varinfo; ++i)
+               offsets [i] = -1;
+
+       for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+               inst = cfg->varinfo [i];
+               vmv = MONO_VARINFO (cfg, i);
+
+               if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
+                       continue;
+
+               vars = g_list_prepend (vars, vmv);
+       }
+
+       vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
+
+       /* Sanity check */
+       /*
+       i = 0;
+       for (unhandled = vars; unhandled; unhandled = unhandled->next) {
+               MonoMethodVar *current = unhandled->data;
+
+               if (current->interval->range) {
+                       g_assert (current->interval->range->from >= i);
+                       i = current->interval->range->from;
+               }
+       }
+       */
+
+       offset = 0;
+       *stack_align = 0;
+       for (unhandled = vars; unhandled; unhandled = unhandled->next) {
+               MonoMethodVar *current = unhandled->data;
+
+               vmv = current;
+               inst = cfg->varinfo [vmv->idx];
+
+               /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
+               * pinvoke wrappers when they call functions returning structures */
+               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
+                       size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
+               else {
+                       int ialign;
+
+                       size = mono_type_size (inst->inst_vtype, &ialign);
+                       align = ialign;
+               }
+
+               t = mono_type_get_underlying_type (inst->inst_vtype);
+               switch (t->type) {
+               case MONO_TYPE_GENERICINST:
+                       if (!mono_type_generic_inst_is_valuetype (t)) {
+                               slot_info = &scalar_stack_slots [t->type];
+                               break;
+                       }
+                       /* Fall through */
+               case MONO_TYPE_VALUETYPE:
+                       if (!vtype_stack_slots)
+                               vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
+                       for (i = 0; i < nvtypes; ++i)
+                               if (t->data.klass == vtype_stack_slots [i].vtype)
+                                       break;
+                       if (i < nvtypes)
+                               slot_info = &vtype_stack_slots [i];
+                       else {
+                               g_assert (nvtypes < 256);
+                               vtype_stack_slots [nvtypes].vtype = t->data.klass;
+                               slot_info = &vtype_stack_slots [nvtypes];
+                               nvtypes ++;
+                       }
+                       break;
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_ARRAY:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_STRING:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+               case MONO_TYPE_I4:
+#else
+               case MONO_TYPE_I8:
+                       /* Share non-float stack slots of the same size */
+                       slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
+                       break;
+#endif
+               default:
+                       slot_info = &scalar_stack_slots [t->type];
+               }
+
+               slot = 0xffffff;
+               if (cfg->comp_done & MONO_COMP_LIVENESS) {
+                       int pos;
+                       gboolean changed;
+
+                       //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
+
+                       if (!current->interval->range) {
+                               if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
+                                       pos = ~0;
+                               else {
+                                       /* Dead */
+                                       inst->flags |= MONO_INST_IS_DEAD;
+                                       continue;
+                               }
+                       }
+                       else
+                               pos = current->interval->range->from;
+
+                       LSCAN_DEBUG (printf ("process R%d ", inst->dreg));
+                       if (current->interval->range)
+                               LSCAN_DEBUG (mono_linterval_print (current->interval));
+                       LSCAN_DEBUG (printf ("\n"));
+
+                       /* Check for intervals in active which expired or inactive */
+                       changed = TRUE;
+                       /* FIXME: Optimize this */
+                       while (changed) {
+                               changed = FALSE;
+                               for (l = slot_info->active; l != NULL; l = l->next) {
+                                       MonoMethodVar *v = (MonoMethodVar*)l->data;
+
+                                       if (v->interval->last_range->to < pos) {
+                                               slot_info->active = g_list_delete_link (slot_info->active, l);
+                                               slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
+                                               LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
+                                               changed = TRUE;
+                                               break;
+                                       }
+                                       else if (!mono_linterval_covers (v->interval, pos)) {
+                                               slot_info->inactive = g_list_append (slot_info->inactive, v);
+                                               slot_info->active = g_list_delete_link (slot_info->active, l);
+                                               LSCAN_DEBUG (printf ("Interval R%d became inactive\n", cfg->varinfo [v->idx]->dreg));
+                                               changed = TRUE;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       /* Check for intervals in inactive which expired or active */
+                       changed = TRUE;
+                       /* FIXME: Optimize this */
+                       while (changed) {
+                               changed = FALSE;
+                               for (l = slot_info->inactive; l != NULL; l = l->next) {
+                                       MonoMethodVar *v = (MonoMethodVar*)l->data;
+
+                                       if (v->interval->last_range->to < pos) {
+                                               slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
+                                               // FIXME: Enabling this seems to cause impossible to debug crashes
+                                               //slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [v->idx]));
+                                               LSCAN_DEBUG (printf ("Interval R%d has expired, adding 0x%x to slots\n", cfg->varinfo [v->idx]->dreg, offsets [v->idx]));
+                                               changed = TRUE;
+                                               break;
+                                       }
+                                       else if (mono_linterval_covers (v->interval, pos)) {
+                                               slot_info->active = g_list_append (slot_info->active, v);
+                                               slot_info->inactive = g_list_delete_link (slot_info->inactive, l);
+                                               LSCAN_DEBUG (printf ("\tInterval R%d became active\n", cfg->varinfo [v->idx]->dreg));
+                                               changed = TRUE;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       /* 
+                        * This also handles the case when the variable is used in an
+                        * exception region, as liveness info is not computed there.
+                        */
+                       /* 
+                        * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
+                        * opcodes.
+                        */
+                       if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
+                               if (slot_info->slots) {
+                                       slot = GPOINTER_TO_INT (slot_info->slots->data);
+
+                                       slot_info->slots = slot_info->slots->next;
+                               }
+
+                               /* FIXME: We might want to consider the inactive intervals as well if slot_info->slots is empty */
+
+                               slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
+                       }
+               }
+
+#if 0
+               {
+                       static int count = 0;
+                       count ++;
+
+                       if (count == atoi (getenv ("COUNT3")))
+                               printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
+                       if (count > atoi (getenv ("COUNT3")))
+                               slot = 0xffffff;
+                       else {
+                               mono_print_tree_nl (inst);
+                               }
+               }
+#endif
+
+               LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot));
+
+               if (slot == 0xffffff) {
+                       /*
+                        * Allways allocate valuetypes to sizeof (gpointer) to allow more
+                        * efficient copying (and to work around the fact that OP_MEMCPY
+                        * and OP_MEMSET ignores alignment).
+                        */
+                       if (MONO_TYPE_ISSTRUCT (t))
+                               align = sizeof (gpointer);
+
+                       if (backward) {
+                               offset += size;
+                               offset += align - 1;
+                               offset &= ~(align - 1);
+                               slot = offset;
+                       }
+                       else {
+                               offset += align - 1;
+                               offset &= ~(align - 1);
+                               slot = offset;
+                               offset += size;
+                       }
+
+                       if (*stack_align == 0)
+                               *stack_align = align;
+               }
 
-static inline GSList*
-g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
-                                                gpointer  data)
-{
-  GSList *new_list;
+               offsets [vmv->idx] = slot;
+       }
+       g_list_free (vars);
+       for (i = 0; i < MONO_TYPE_PINNED; ++i) {
+               if (scalar_stack_slots [i].active)
+                       g_list_free (scalar_stack_slots [i].active);
+       }
+       for (i = 0; i < nvtypes; ++i) {
+               if (vtype_stack_slots [i].active)
+                       g_list_free (vtype_stack_slots [i].active);
+       }
 
-  new_list = mono_mempool_alloc (mp, sizeof (GSList));
-  new_list->data = data;
-  new_list->next = list;
+       mono_jit_stats.locals_stack_size += offset;
 
-  return new_list;
+       *stack_size = offset;
+       return offsets;
 }
 
 /*
@@ -9452,7 +10446,7 @@ g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
  * STACK_ALIGN is set to the alignment needed by the locals area.
  */
 gint32*
-mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
+mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
 {
        int i, slot, offset, size;
        guint32 align;
@@ -9464,17 +10458,20 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
        MonoType *t;
        int nvtypes;
 
-       scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
+       if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval)
+               return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align);
+
+       scalar_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
        vtype_stack_slots = NULL;
        nvtypes = 0;
 
-       offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
-       for (i = 0; i < m->num_varinfo; ++i)
+       offsets = mono_mempool_alloc (cfg->mempool, sizeof (gint32) * cfg->num_varinfo);
+       for (i = 0; i < cfg->num_varinfo; ++i)
                offsets [i] = -1;
 
-       for (i = m->locals_start; i < m->num_varinfo; i++) {
-               inst = m->varinfo [i];
-               vmv = MONO_VARINFO (m, i);
+       for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+               inst = cfg->varinfo [i];
+               vmv = MONO_VARINFO (cfg, i);
 
                if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
                        continue;
@@ -9482,12 +10479,12 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                vars = g_list_prepend (vars, vmv);
        }
 
-       vars = mono_varlist_sort (m, vars, 0);
+       vars = mono_varlist_sort (cfg, vars, 0);
        offset = 0;
        *stack_align = 0;
        for (l = vars; l; l = l->next) {
                vmv = l->data;
-               inst = m->varinfo [vmv->idx];
+               inst = cfg->varinfo [vmv->idx];
 
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
@@ -9513,7 +10510,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                /* Fall through */
                        case MONO_TYPE_VALUETYPE:
                                if (!vtype_stack_slots)
-                                       vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
+                                       vtype_stack_slots = mono_mempool_alloc0 (cfg->mempool, sizeof (StackSlotInfo) * 256);
                                for (i = 0; i < nvtypes; ++i)
                                        if (t->data.klass == vtype_stack_slots [i].vtype)
                                                break;
@@ -9548,7 +10545,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                }
 
                slot = 0xffffff;
-               if (m->comp_done & MONO_COMP_LIVENESS) {
+               if (cfg->comp_done & MONO_COMP_LIVENESS) {
                        //printf ("START  %2d %08x %08x\n",  vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
                        
                        /* expire old intervals in active */
@@ -9561,7 +10558,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                //printf ("EXPIR  %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
 
                                slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
-                               slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+                               slot_info->slots = g_slist_prepend_mempool (cfg->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
                        }
 
                        /* 
@@ -9579,7 +10576,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                        slot_info->slots = slot_info->slots->next;
                                }
 
-                               slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
+                               slot_info->active = mono_varlist_insert_sorted (cfg, slot_info->active, vmv, TRUE);
                        }
                }
 
@@ -9589,7 +10586,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
 
                        /*
                        if (count == atoi (getenv ("COUNT")))
-                               printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
+                               printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
                        if (count > atoi (getenv ("COUNT")))
                                slot = 0xffffff;
                        else {
@@ -9597,6 +10594,10 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                }
                        */
                }
+
+               if (cfg->disable_reuse_stack_slots)
+                       slot = 0xffffff;
+
                if (slot == 0xffffff) {
                        /*
                         * Allways allocate valuetypes to sizeof (gpointer) to allow more
@@ -9707,6 +10708,7 @@ decompose_foreach (MonoInst *tree, gpointer data)
                else {
                        MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
 
+                       g_assert (vtable);
                        NEW_VTABLECONST (cfg, iargs [0], vtable);
                        iargs [1] = tree->inst_newa_len;
 
@@ -9813,12 +10815,11 @@ print_dfn (MonoCompile *cfg) {
        int i, j;
        char *code;
        MonoBasicBlock *bb;
+       MonoInst *c;
 
        g_print ("IR code for method %s\n", mono_method_full_name (cfg->method, TRUE));
 
        for (i = 0; i < cfg->num_bblocks; ++i) {
-               MonoInst *c;
-
                bb = cfg->bblocks [i];
                /*if (bb->cil_code) {
                        char* code1, *code2;
@@ -9834,10 +10835,14 @@ print_dfn (MonoCompile *cfg) {
                        g_free (code2);
                } else*/
                        code = g_strdup ("\n");
-               g_print ("\nBB%d DFN%d (len: %d): %s", bb->block_num, i, bb->cil_length, code);
+               g_print ("\nBB%d (%d) (len: %d): %s", bb->block_num, i, bb->cil_length, code);
                MONO_BB_FOR_EACH_INS (bb, c) {
-                       mono_print_tree (c);
-                       g_print ("\n");
+                       if (cfg->new_ir) {
+                               mono_print_ins_index (-1, c);
+                       } else {
+                               mono_print_tree (c);
+                               g_print ("\n");
+                       }
                }
 
                g_print ("\tprev:");
@@ -9866,7 +10871,89 @@ print_dfn (MonoCompile *cfg) {
 void
 mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
 {
-       MONO_INST_LIST_ADD_TAIL (&inst->node, &bb->ins_list);
+       MONO_ADD_INS (bb, inst);
+}
+
+void
+mono_bblock_insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
+{
+       if (ins == NULL) {
+               ins = bb->code;
+               bb->code = ins_to_insert;
+               ins_to_insert->next = ins;
+               if (bb->last_ins == NULL)
+                       bb->last_ins = ins_to_insert;
+       } else {
+               /* Link with next */
+               ins_to_insert->next = ins->next;
+               if (ins->next)
+                       ins->next->prev = ins_to_insert;
+
+               /* Link with previous */
+               ins->next = ins_to_insert;
+               ins_to_insert->prev = ins;
+
+               if (bb->last_ins == ins)
+                       bb->last_ins = ins_to_insert;
+       }
+}
+
+void
+mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert)
+{
+       if (ins == NULL) {
+               NOT_IMPLEMENTED;
+               ins = bb->code;
+               bb->code = ins_to_insert;
+               ins_to_insert->next = ins;
+               if (bb->last_ins == NULL)
+                       bb->last_ins = ins_to_insert;
+       } else {
+               /* Link with previous */
+               if (ins->prev)
+                       ins->prev->next = ins_to_insert;
+               ins_to_insert->prev = ins->prev;
+
+               /* Link with next */
+               ins->prev = ins_to_insert;
+               ins_to_insert->next = ins;
+
+               if (bb->code == ins)
+                       bb->code = ins_to_insert;
+       }
+}
+
+/*
+ * mono_verify_bblock:
+ *
+ *   Verify that the next and prev pointers are consistent inside the instructions in BB.
+ */
+void
+mono_verify_bblock (MonoBasicBlock *bb)
+{
+       MonoInst *ins, *prev;
+
+       prev = NULL;
+       for (ins = bb->code; ins; ins = ins->next) {
+               g_assert (ins->prev == prev);
+               prev = ins;
+       }
+       if (bb->last_ins)
+               g_assert (!bb->last_ins->next);
+}
+
+/*
+ * mono_verify_cfg:
+ *
+ *   Perform consistency checks on the JIT data structures and the IR
+ */
+void
+mono_verify_cfg (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb;
+
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
+               mono_verify_bblock (bb);
 }
 
 void
@@ -9884,6 +10971,8 @@ mono_destroy_compile (MonoCompile *cfg)
        g_list_free (cfg->ldstr_list);
        g_hash_table_destroy (cfg->token_info_hash);
 
+       g_free (cfg->reverse_inst_list);
+
        g_free (cfg->varinfo);
        g_free (cfg->vars);
        g_free (cfg->exception_message);
@@ -10146,6 +11235,19 @@ mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpoin
        cfg->patch_info = ji;
 }
 
+MonoJumpInfo *
+mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJumpInfoType type, gconstpointer target)
+{
+       MonoJumpInfo *ji = g_new0 (MonoJumpInfo, 1);
+
+       ji->ip.i = ip;
+       ji->type = type;
+       ji->data.target = target;
+       ji->next = list;
+
+       return ji;
+}
+
 void
 mono_remove_patch_info (MonoCompile *cfg, int ip)
 {
@@ -10264,6 +11366,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
        switch (patch_info->type) {
        case MONO_PATCH_INFO_BB:
+               g_assert (patch_info->data.bb->native_offset);
                target = patch_info->data.bb->native_offset + code;
                break;
        case MONO_PATCH_INFO_ABS:
@@ -10304,10 +11407,12 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        target = code;
                } else {
                        /* get the trampoline to the method from the domain */
-                       if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE)
-                               target = mono_ldftn_nosync (patch_info->data.method);
-                       else
+                       if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
+                               target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
+                                       patch_info->data.method, FALSE);
+                       } else {
                                target = mono_create_jit_trampoline (patch_info->data.method);
+                       }
                }
                break;
        case MONO_PATCH_INFO_SWITCH: {
@@ -10318,13 +11423,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                } else {
                        mono_domain_lock (domain);
-                       jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
+                       if (mono_aot_only)
+                               jump_table = mono_mempool_alloc (domain->mp, sizeof (gpointer) * patch_info->data.table->table_size);
+                       else
+                               jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                        mono_domain_unlock (domain);
                }
 
-               for (i = 0; i < patch_info->data.table->table_size; i++) {
+               for (i = 0; i < patch_info->data.table->table_size; i++)
                        jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-               }
                target = jump_table;
                break;
        }
@@ -10344,15 +11451,22 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        case MONO_PATCH_INFO_VTABLE:
                target = mono_class_vtable (domain, patch_info->data.klass);
+               g_assert (target);
                break;
-       case MONO_PATCH_INFO_CLASS_INIT:
-               target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
+       case MONO_PATCH_INFO_CLASS_INIT: {
+               MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.klass);
+
+               g_assert (vtable);
+               target = mono_create_class_init_trampoline (vtable);
                break;
+       }
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
                target = mono_create_delegate_trampoline (patch_info->data.klass);
                break;
        case MONO_PATCH_INFO_SFLDA: {
                MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
+
+               g_assert (vtable);
                if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
                        /* Done by the generated code */
                        ;
@@ -10408,6 +11522,18 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_ICALL_ADDR:
                target = mono_lookup_internal_call (patch_info->data.method);
                break;
+       case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
+               MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
+               if (!mi) {
+                       g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
+                       g_assert_not_reached ();
+               }
+               target = mi->func;
+               break;
+       }
+       case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
+               target = mono_thread_interruption_request_flag ();
+               break;
        case MONO_PATCH_INFO_BB_OVF:
        case MONO_PATCH_INFO_EXC_OVF:
        case MONO_PATCH_INFO_GOT_OFFSET:
@@ -10502,7 +11628,7 @@ nullify_basic_block (MonoBasicBlock *bb)
        bb->in_bb = NULL;
        bb->out_bb = NULL;
        bb->next_bb = NULL;
-       MONO_INST_LIST_INIT (&bb->ins_list);
+       bb->code = bb->last_ins = NULL;
        bb->cil_code = NULL;
 }
 
@@ -10548,67 +11674,45 @@ replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl
 
 static void
 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
-       MonoInst *inst;
+       MonoInst *ins;
        
-       MONO_BB_FOR_EACH_INS (bb, inst) {
-               if (inst->opcode == OP_CALL_HANDLER) {
-                       if (inst->inst_target_bb == orig)
-                               inst->inst_target_bb = repl;
-               }
-       }
-
-       inst = mono_inst_list_last (&bb->ins_list);
-       if (!inst)
-               return;
-
-       switch (inst->opcode) {
-       case OP_BR:
-               if (inst->inst_target_bb == orig)
-                       inst->inst_target_bb = repl;
-               break;
-       case OP_SWITCH: {
-               int i;
-               int n = GPOINTER_TO_INT (inst->klass);
-               for (i = 0; i < n; i++ ) {
-                       if (inst->inst_many_bb [i] == orig)
-                               inst->inst_many_bb [i] = repl;
+       for (ins = bb->code; ins != NULL; ins = ins->next) {
+               switch (ins->opcode) {
+               case OP_BR:
+                       if (ins->inst_target_bb == orig)
+                               ins->inst_target_bb = repl;
+                       break;
+               case OP_CALL_HANDLER:
+                       if (ins->inst_target_bb == orig)
+                               ins->inst_target_bb = repl;
+                       break;
+               case OP_SWITCH: {
+                       int i;
+                       int n = GPOINTER_TO_INT (ins->klass);
+                       for (i = 0; i < n; i++ ) {
+                               if (ins->inst_many_bb [i] == orig)
+                                       ins->inst_many_bb [i] = repl;
+                       }
+                       break;
                }
-               break;
-       }
-       case CEE_BNE_UN:
-       case CEE_BEQ:
-       case CEE_BLT:
-       case CEE_BLT_UN:
-       case CEE_BGT:
-       case CEE_BGT_UN:
-       case CEE_BGE:
-       case CEE_BGE_UN:
-       case CEE_BLE:
-       case CEE_BLE_UN:
-               if (inst->inst_true_bb == orig)
-                       inst->inst_true_bb = repl;
-               if (inst->inst_false_bb == orig)
-                       inst->inst_false_bb = repl;
-               break;
-       default:
-               break;
-       }
-}
-
-static void 
-replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
-{
-       int i, j;
-
-       for (i = 0; i < bb->out_count; i++) {
-               MonoBasicBlock *ob = bb->out_bb [i];
-               for (j = 0; j < ob->in_count; j++) {
-                       if (ob->in_bb [j] == orig) {
-                               ob->in_bb [j] = repl;
+               default:
+                       if (MONO_IS_COND_BRANCH_OP (ins)) {
+                               if (ins->inst_true_bb == orig)
+                                       ins->inst_true_bb = repl;
+                               if (ins->inst_false_bb == orig)
+                                       ins->inst_false_bb = repl;
+                       } else if (MONO_IS_JUMP_TABLE (ins)) {
+                               int i;
+                               MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins);
+                               for (i = 0; i < table->table_size; i++ ) {
+                                       if (table->table [i] == orig)
+                                               table->table [i] = repl;
+                               }
                        }
+
+                       break;
                }
        }
-
 }
 
 /**
@@ -10621,7 +11725,7 @@ static gboolean
 remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
        MonoBasicBlock *target_bb = NULL;
        MonoInst *inst;
-       
+
        /* Do not touch handlers */
        if (bb->region != -1) {
                bb->not_useless = TRUE;
@@ -10651,9 +11755,9 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        }
        
        /* Do not touch BBs following a switch (they are the "default" branch) */
-       inst = mono_inst_list_last (&previous_bb->ins_list);
-       if (inst && inst->opcode == OP_SWITCH)
+       if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == OP_SWITCH)) {
                return FALSE;
+       }
        
        /* Do not touch BBs following the entry BB and jumping to something that is not */
        /* thiry "next" bb (the entry BB cannot contain the branch) */
@@ -10670,11 +11774,10 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        
        /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
        if ((target_bb != NULL) && (target_bb != bb)) {
-               MonoInst *last_ins;
                int i;
 
                if (cfg->verbose_level > 1) {
-                       printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+                       printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
                }
                
                /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
@@ -10687,14 +11790,12 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
                
                mono_unlink_bblock (cfg, bb, target_bb);
                
-               last_ins = mono_inst_list_last (&previous_bb->ins_list);
-
                if ((previous_bb != cfg->bb_entry) &&
                                (previous_bb->region == bb->region) &&
-                               ((last_ins == NULL) ||
-                               ((last_ins->opcode != OP_BR) &&
-                               (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
-                               (last_ins->opcode != OP_SWITCH)))) {
+                               ((previous_bb->last_ins == NULL) ||
+                               ((previous_bb->last_ins->opcode != OP_BR) &&
+                               (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+                               (previous_bb->last_ins->opcode != OP_SWITCH)))) {
                        for (i = 0; i < previous_bb->out_count; i++) {
                                if (previous_bb->out_bb [i] == target_bb) {
                                        MonoInst *jump;
@@ -10716,25 +11817,67 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        }
 }
 
-static void
-merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
+void
+mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn) 
 {
-       MonoInst *last_ins;
-
-       bb->out_count = bbn->out_count;
-       bb->out_bb = bbn->out_bb;
-
-       replace_basic_block (bb, bbn, bb);
+       MonoInst *inst;
+       MonoBasicBlock *prev_bb;
+       int i;
 
-       last_ins = mono_inst_list_last (&bb->ins_list);
+       bb->has_array_access |= bbn->has_array_access;
+       bb->extended |= bbn->extended;
 
-       /* Nullify branch at the end of bb */
-       if (last_ins && MONO_IS_BRANCH_OP (last_ins))
-               last_ins->opcode = OP_NOP;
+       mono_unlink_bblock (cfg, bb, bbn);
+       for (i = 0; i < bbn->out_count; ++i)
+               mono_link_bblock (cfg, bb, bbn->out_bb [i]);
+       while (bbn->out_count)
+               mono_unlink_bblock (cfg, bbn, bbn->out_bb [0]);
 
-       MONO_INST_LIST_SPLICE_TAIL_INIT (&bbn->ins_list, &bb->ins_list);
+       /* Handle the branch at the end of the bb */
+       for (inst = bb->code; inst != NULL; inst = inst->next) {
+               if (inst->opcode == OP_CALL_HANDLER) {
+                       g_assert (inst->inst_target_bb == bbn);
+                       NULLIFY_INS (inst);
+               }
+               if (MONO_IS_JUMP_TABLE (inst)) {
+                       int i;
+                       MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
+                       for (i = 0; i < table->table_size; i++ ) {
+                               /* Might be already NULL from a previous merge */
+                               if (table->table [i])
+                                       g_assert (table->table [i] == bbn);
+                               table->table [i] = NULL;
+                       }
+                       /* Can't nullify this as later instructions depend on it */
+               }
+       }
+       if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
+               g_assert (bb->last_ins->inst_false_bb == bbn);
+               bb->last_ins->inst_false_bb = NULL;
+               bb->extended = TRUE;
+       } else if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
+               NULLIFY_INS (bb->last_ins);
+       }
 
-       bb->next_bb = bbn->next_bb;
+       if (bb->last_ins) {
+               if (bbn->code) {
+                       bb->last_ins->next = bbn->code;
+                       bbn->code->prev = bb->last_ins;
+                       bb->last_ins = bbn->last_ins;
+               }
+       } else {
+               bb->code = bbn->code;
+               bb->last_ins = bbn->last_ins;
+       }
+       for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
+               ;
+       if (prev_bb) {
+               prev_bb->next_bb = bbn->next_bb;
+       } else {
+               /* bbn might not be in the bb list yet */
+               if (bb->next_bb == bbn)
+                       bb->next_bb = bbn->next_bb;
+       }
        nullify_basic_block (bbn);
 }
 
@@ -10742,7 +11885,6 @@ static void
 move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
 {
        MonoBasicBlock *bbn, *next;
-       MonoInst *last_ins;
 
        next = bb->next_bb;
 
@@ -10759,10 +11901,8 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
        bbn->next_bb = bb;
        bb->next_bb = NULL;
 
-       last_ins = mono_inst_list_last (&bb->ins_list);
-
        /* Add a branch */
-       if (next && (!last_ins || (last_ins->opcode != OP_NOT_REACHED))) {
+       if (next && (!bb->last_ins || ((bb->last_ins->opcode != OP_NOT_REACHED) && (bb->last_ins->opcode != OP_BR) && (bb->last_ins->opcode != OP_BR_REG) && (!MONO_IS_COND_BRANCH_OP (bb->last_ins))))) {
                MonoInst *ins;
 
                MONO_INST_NEW (cfg, ins, OP_BR);
@@ -10772,6 +11912,23 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
        }               
 }
 
+/*
+ * mono_remove_block:
+ *
+ *   Remove BB from the control flow graph
+ */
+void
+mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb) 
+{
+       MonoBasicBlock *tmp_bb;
+
+       for (tmp_bb = cfg->bb_entry; tmp_bb && tmp_bb->next_bb != bb; tmp_bb = tmp_bb->next_bb)
+               ;
+
+       g_assert (tmp_bb);
+       tmp_bb->next_bb = bb->next_bb;
+}
+
 /* checks that a and b represent the same instructions, conservatively,
  * it can return FALSE also for two trees that are equal.
  * FIXME: also make sure there are no side effects.
@@ -10844,20 +12001,20 @@ tree_is_unsigned (MonoInst* ins) {
  * Note that this can't be applied if the second arg is not positive...
  */
 static int
-try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *bb_last)
+try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
 {
        MonoBasicBlock *truet, *falset;
-       MonoInst *cmp_inst = bb_last->inst_left;
+       MonoInst *cmp_inst = bb->last_ins->inst_left;
        MonoInst *condb;
        if (!cmp_inst->inst_right->inst_c0 == 0)
                return FALSE;
-       truet = bb_last->inst_true_bb;
-       falset = bb_last->inst_false_bb;
+       truet = bb->last_ins->inst_true_bb;
+       falset = bb->last_ins->inst_false_bb;
        if (falset->in_count != 1)
                return FALSE;
-       condb = mono_inst_list_last (&falset->ins_list);
+       condb = falset->last_ins;
        /* target bb must have one instruction */
-       if (!condb || (condb->node.next != &falset->ins_list))
+       if (!condb || (condb != falset->code))
                return FALSE;
        if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
                        || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
@@ -10866,8 +12023,8 @@ try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *bb_last)
                        return FALSE;
                condb->opcode = get_unsigned_condbranch (condb->opcode);
                /* change the original condbranch to just point to the new unsigned check */
-               bb_last->opcode = OP_BR;
-               bb_last->inst_target_bb = falset;
+               bb->last_ins->opcode = OP_BR;
+               bb->last_ins->inst_target_bb = falset;
                replace_out_block (bb, truet, NULL);
                replace_in_block (truet, bb, NULL);
                return TRUE;
@@ -10879,8 +12036,8 @@ try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *bb_last)
  * Optimizes the branches on the Control Flow Graph
  *
  */
-static void
-optimize_branches (MonoCompile *cfg)
+void
+mono_optimize_branches (MonoCompile *cfg)
 {
        int i, changed = FALSE;
        MonoBasicBlock *bb, *bbn;
@@ -10895,7 +12052,7 @@ optimize_branches (MonoCompile *cfg)
                niterations = cfg->num_bblocks * 2;
        else
                niterations = 1000;
-
+       
        do {
                MonoBasicBlock *previous_bb;
                changed = FALSE;
@@ -10903,8 +12060,6 @@ optimize_branches (MonoCompile *cfg)
 
                /* we skip the entry block (exit is handled specially instead ) */
                for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
-                       MonoInst *last_ins;
-
                        /* dont touch code inside exception clauses */
                        if (bb->region != -1)
                                continue;
@@ -10927,21 +12082,22 @@ optimize_branches (MonoCompile *cfg)
                                changed = TRUE;
                        }
 
-                       last_ins = mono_inst_list_last (&bb->ins_list);
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
                                /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
-                               if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins)) {
-                                       MonoInst *pop;
-                                       MONO_INST_NEW (cfg, pop, CEE_POP);
-                                       pop->inst_left = last_ins->inst_left->inst_left;
-                                       mono_add_ins_to_end (bb, pop);
-                                       MONO_INST_NEW (cfg, pop, CEE_POP);
-                                       pop->inst_left = last_ins->inst_left->inst_right;
-                                       mono_add_ins_to_end (bb, pop);
-                                       last_ins->opcode = OP_BR;
-                                       last_ins->inst_target_bb = last_ins->inst_true_bb;
+                               if (bb->last_ins && (bb->last_ins->opcode != OP_BR) && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
+                                       if (!cfg->new_ir) {
+                                               MonoInst *pop;
+                                               MONO_INST_NEW (cfg, pop, CEE_POP);
+                                               pop->inst_left = bb->last_ins->inst_left->inst_left;
+                                               mono_add_ins_to_end (bb, pop);
+                                               MONO_INST_NEW (cfg, pop, CEE_POP);
+                                               pop->inst_left = bb->last_ins->inst_left->inst_right;
+                                               mono_add_ins_to_end (bb, pop);
+                                       }
+                                       bb->last_ins->opcode = OP_BR;
+                                       bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
                                        changed = TRUE;
                                        if (cfg->verbose_level > 2)
                                                g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
@@ -10951,19 +12107,18 @@ optimize_branches (MonoCompile *cfg)
                                        /* the block are in sequence anyway ... */
 
                                        /* branches to the following block can be removed */
-                                       if (last_ins && last_ins->opcode == OP_BR) {
-                                               last_ins->opcode = OP_NOP;
+                                       if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
+                                               bb->last_ins->opcode = OP_NOP;
                                                changed = TRUE;
                                                if (cfg->verbose_level > 2)
                                                        g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
                                        }
 
-                                       if (bbn->in_count == 1) {
-
+                                       if (bbn->in_count == 1 && !bb->extended) {
                                                if (bbn != cfg->bb_exit) {
                                                        if (cfg->verbose_level > 2)
                                                                g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
-                                                       merge_basic_blocks (bb, bbn);
+                                                       mono_merge_basic_blocks (cfg, bb, bbn);
                                                        changed = TRUE;
                                                        continue;
                                                }
@@ -10972,6 +12127,7 @@ optimize_branches (MonoCompile *cfg)
                                        }
                                }
                        }
+
                        if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
                                if (cfg->verbose_level > 2) {
                                        g_print ("nullify block triggered %d\n", bbn->block_num);
@@ -10989,115 +12145,137 @@ optimize_branches (MonoCompile *cfg)
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
-                               if (last_ins && last_ins->opcode == OP_BR) {
-                                       MonoInst *bbn_code;
-
-                                       bbn = last_ins->inst_target_bb;
-                                       bbn_code = mono_inst_list_first (&bbn->ins_list);
-                                       if (bb->region == bbn->region && bbn_code &&
-                                                       bbn_code->opcode == OP_BR &&
-                                                       bbn_code->inst_target_bb->region == bb->region) {
+                               if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
+                                       bbn = bb->last_ins->inst_target_bb;
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
+                                           bbn->code->inst_target_bb->region == bb->region) {
+                                               
                                                if (cfg->verbose_level > 2)
-                                                       g_print ("in %s branch to branch triggered %d -> %d -> %d\n", cfg->method->name, 
-                                                                bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num);
+                                                       g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
 
                                                replace_in_block (bbn, bb, NULL);
-                                               replace_out_block (bb, bbn, bbn_code->inst_target_bb);
-                                               link_bblock (cfg, bb, bbn_code->inst_target_bb);
-                                               last_ins->inst_target_bb = bbn_code->inst_target_bb;
+                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+                                               bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
                                                changed = TRUE;
                                                continue;
                                        }
                                }
                        } else if (bb->out_count == 2) {
-                               if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
-                                       int branch_result = mono_eval_cond_branch (last_ins);
+                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
+                                       int branch_result;
                                        MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
-                                       MonoInst *bbn_code;
+
+                                       if (cfg->new_ir) {
+                                               if (bb->last_ins->flags & MONO_INST_CFOLD_TAKEN)
+                                                       branch_result = BRANCH_TAKEN;
+                                               else if (bb->last_ins->flags & MONO_INST_CFOLD_NOT_TAKEN)
+                                                       branch_result = BRANCH_NOT_TAKEN;
+                                               else
+                                                       branch_result = BRANCH_UNDEF;
+                                       }
+                                       else
+                                               branch_result = mono_eval_cond_branch (bb->last_ins);
 
                                        if (branch_result == BRANCH_TAKEN) {
-                                               taken_branch_target = last_ins->inst_true_bb;
-                                               untaken_branch_target = last_ins->inst_false_bb;
+                                               taken_branch_target = bb->last_ins->inst_true_bb;
+                                               untaken_branch_target = bb->last_ins->inst_false_bb;
                                        } else if (branch_result == BRANCH_NOT_TAKEN) {
-                                               taken_branch_target = last_ins->inst_false_bb;
-                                               untaken_branch_target = last_ins->inst_true_bb;
+                                               taken_branch_target = bb->last_ins->inst_false_bb;
+                                               untaken_branch_target = bb->last_ins->inst_true_bb;
                                        }
                                        if (taken_branch_target) {
                                                /* if mono_eval_cond_branch () is ever taken to handle 
                                                 * non-constant values to compare, issue a pop here.
                                                 */
-                                               last_ins->opcode = OP_BR;
-                                               last_ins->inst_target_bb = taken_branch_target;
-                                               mono_unlink_bblock (cfg, bb, untaken_branch_target);
+                                               bb->last_ins->opcode = OP_BR;
+                                               bb->last_ins->inst_target_bb = taken_branch_target;
+                                               if (!bb->extended)
+                                                       mono_unlink_bblock (cfg, bb, untaken_branch_target);
                                                changed = TRUE;
                                                continue;
                                        }
-                                       bbn = last_ins->inst_true_bb;
-                                       bbn_code = mono_inst_list_first (&bbn->ins_list);
-                                       if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
-                                                       bbn_code->inst_target_bb->region == bb->region) {
+                                       bbn = bb->last_ins->inst_true_bb;
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
+                                           bbn->code->inst_target_bb->region == bb->region) {
                                                if (cfg->verbose_level > 2)             
                                                        g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
-                                                                bbn_code->opcode);
+                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
+                                                                bbn->code->opcode);
 
                                                /* 
                                                 * Unlink, then relink bblocks to avoid various
                                                 * tricky situations when the two targets of the branch
                                                 * are equal, or will become equal after the change.
                                                 */
-                                               mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
-                                               mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               last_ins->inst_true_bb = bbn_code->inst_target_bb;
+                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
 
-                                               link_bblock (cfg, bb, last_ins->inst_true_bb);
-                                               link_bblock (cfg, bb, last_ins->inst_false_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
                                                changed = TRUE;
                                                continue;
                                        }
 
-                                       bbn = last_ins->inst_false_bb;
-                                       bbn_code = mono_inst_list_first (&bbn->ins_list);
-                                       if (bb->region == bbn->region && bbn_code && bbn_code->opcode == OP_BR &&
-                                                       bbn_code->inst_target_bb->region == bb->region) {
+                                       bbn = bb->last_ins->inst_false_bb;
+                                       if (bbn && bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
+                                           bbn->code->inst_target_bb->region == bb->region) {
                                                if (cfg->verbose_level > 2)
                                                        g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn_code->inst_target_bb->block_num, 
-                                                                bbn_code->opcode);
+                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
+                                                                bbn->code->opcode);
 
-                                               mono_unlink_bblock (cfg, bb, last_ins->inst_true_bb);
-                                               mono_unlink_bblock (cfg, bb, last_ins->inst_false_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               last_ins->inst_false_bb = bbn_code->inst_target_bb;
+                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
 
-                                               link_bblock (cfg, bb, last_ins->inst_true_bb);
-                                               link_bblock (cfg, bb, last_ins->inst_false_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
+
+                                               changed = TRUE;
+                                               continue;
+                                       }
 
+                                       bbn = bb->last_ins->inst_false_bb;
+                                       /*
+                                        * If bb is an extended bb, it could contain an inside branch to bbn.
+                                        * FIXME: Enable the optimization if that is not true.
+                                        * If bblocks_linked () is true, then merging bb and bbn
+                                        * would require addition of an extra branch at the end of bbn 
+                                        * slowing down loops.
+                                        */
+                                       if (cfg->new_ir && bbn && bb->region == bbn->region && bbn->in_count == 1 && cfg->enable_extended_bblocks && bbn != cfg->bb_exit && !bb->extended && !bbn->out_of_line && !mono_bblocks_linked (bbn, bb)) {
+                                               g_assert (bbn->in_bb [0] == bb);
+                                               if (cfg->verbose_level > 2)
+                                                       g_print ("merge false branch target triggered BB%d -> BB%d\n", bb->block_num, bbn->block_num);
+                                               mono_merge_basic_blocks (cfg, bb, bbn);
                                                changed = TRUE;
                                                continue;
                                        }
                                }
 
                                /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
-                               if (last_ins && last_ins->opcode == CEE_BLT && last_ins->inst_left->inst_right->opcode == OP_ICONST) {
-                                       if (try_unsigned_compare (cfg, bb, last_ins)) {
-                                               /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
+                               if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && !cfg->new_ir && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
+                                       if (try_unsigned_compare (cfg, bb)) {
+                                               /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
                                                changed = TRUE;
                                                continue;
                                        }
                                }
 
-                               if (last_ins && MONO_IS_COND_BRANCH_NOFP (last_ins)) {
-                                       if (last_ins->inst_false_bb->out_of_line && (bb->region == last_ins->inst_false_bb->region)) {
+                               if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
+                                       if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
                                                /* Reverse the branch */
-                                               last_ins->opcode = reverse_branch_op (last_ins->opcode);
-                                               bbn = last_ins->inst_false_bb;
-                                               last_ins->inst_false_bb = last_ins->inst_true_bb;
-                                               last_ins->inst_true_bb = bbn;
+                                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                                               bbn = bb->last_ins->inst_false_bb;
+                                               bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
+                                               bb->last_ins->inst_true_bb = bbn;
 
-                                               move_basic_block_to_end (cfg, last_ins->inst_true_bb);
+                                               move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
                                                if (cfg->verbose_level > 2)
                                                        g_print ("cbranch to throw block triggered %d.\n", 
                                                                         bb->block_num);
@@ -11106,7 +12284,6 @@ optimize_branches (MonoCompile *cfg)
                        }
                }
        } while (changed && (niterations > 0));
-
 }
 
 static void
@@ -11121,10 +12298,16 @@ mono_compile_create_vars (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
        
        if (!MONO_TYPE_IS_VOID (sig->ret)) {
-               cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
-               cfg->ret->opcode = OP_RETARG;
-               cfg->ret->inst_vtype = sig->ret;
-               cfg->ret->klass = mono_class_from_mono_type (sig->ret);
+               if (cfg->new_ir) {
+                       cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
+                       /* Inhibit optimizations */
+                       cfg->ret->flags |= MONO_INST_VOLATILE;
+               } else {
+                       cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+                       cfg->ret->opcode = OP_RETARG;
+                       cfg->ret->inst_vtype = sig->ret;
+                       cfg->ret->klass = mono_class_from_mono_type (sig->ret);
+               }
        }
        if (cfg->verbose_level > 2)
                g_print ("creating vars\n");
@@ -11137,17 +12320,36 @@ mono_compile_create_vars (MonoCompile *cfg)
        for (i = 0; i < sig->param_count; ++i) {
                cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
                if (sig->params [i]->byref) {
-                       cfg->disable_ssa = TRUE;
+                       if (!cfg->new_ir) cfg->disable_ssa = TRUE;
+               }
+       }
+
+       if (cfg->new_ir && cfg->verbose_level > 2) {
+               if (cfg->ret) {
+                       printf ("\treturn : ");
+                       mono_print_ins (cfg->ret);
+               }
+
+               if (sig->hasthis) {
+                       printf ("\tthis: ");
+                       mono_print_ins (cfg->args [0]);
+               }
+
+               for (i = 0; i < sig->param_count; ++i) {
+                       printf ("\targ [%d]: ", i);
+                       mono_print_ins (cfg->args [i + sig->hasthis]);
                }
        }
 
        cfg->locals_start = cfg->num_varinfo;
+       cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
 
        if (cfg->verbose_level > 2)
                g_print ("creating locals\n");
 
        for (i = 0; i < header->num_locals; ++i)
-               mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
+               cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
+
        if (cfg->verbose_level > 2)
                g_print ("locals done\n");
 
@@ -11155,20 +12357,25 @@ mono_compile_create_vars (MonoCompile *cfg)
 }
 
 void
-mono_print_code (MonoCompile *cfg)
+mono_print_code (MonoCompile *cfg, const char* msg)
 {
        MonoBasicBlock *bb;
        
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *tree;
+               MonoInst *tree = bb->code;      
 
-               if (!MONO_INST_LIST_EMPTY (&bb->ins_list))
-                       g_print ("CODE BLOCK %d (nesting %d):\n",
-                                bb->block_num, bb->nesting);
+               if (cfg->new_ir) {
+                       mono_print_bb (bb, msg);
+               } else {
+                       if (!tree)
+                               continue;
+                       
+                       g_print ("%s CODE BLOCK %d (nesting %d):\n", msg, bb->block_num, bb->nesting);
 
-               MONO_BB_FOR_EACH_INS (bb, tree) {
-                       mono_print_tree (tree);
-                       g_print ("\n");
+                       MONO_BB_FOR_EACH_INS (bb, tree) {
+                               mono_print_tree (tree);
+                               g_print ("\n");
+                       }
                }
        }
 }
@@ -11230,8 +12437,11 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
                if (nts [1]) {
                        emit_state (cfg, kids [1], nts [1]);
                        if (nts [2]) {
-                               g_assert (!nts [3]);
                                emit_state (cfg, kids [2], nts [2]);
+                               if (nts [3]) {
+                                       g_assert (!nts [4]);
+                                       emit_state (cfg, kids [3], nts [3]);
+                               }
                        }
                }
        }
@@ -11251,52 +12461,49 @@ mini_select_instructions (MonoCompile *cfg)
        cfg->rs = mono_regstate_new ();
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *last_ins = mono_inst_list_last (&bb->ins_list);
-
-               if (last_ins && MONO_IS_COND_BRANCH_OP (last_ins) &&
-                               bb->next_bb != last_ins->inst_false_bb) {
+               if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
+                   bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
 
                        /* we are careful when inverting, since bugs like #59580
                         * could show up when dealing with NaNs.
                         */
-                       if (MONO_IS_COND_BRANCH_NOFP(last_ins) && bb->next_bb == last_ins->inst_true_bb) {
-                               MonoBasicBlock *tmp =  last_ins->inst_true_bb;
-                               last_ins->inst_true_bb = last_ins->inst_false_bb;
-                               last_ins->inst_false_bb = tmp;
+                       if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
+                               MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
+                               bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
+                               bb->last_ins->inst_false_bb = tmp;
 
-                               last_ins->opcode = reverse_branch_op (last_ins->opcode);
+                               bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
                        } else {                        
-                               MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
-                               inst->opcode = OP_BR;
-                               inst->inst_target_bb = last_ins->inst_false_bb;
-                               mono_bblock_add_inst (bb, inst);
+                               MonoInst *ins;
+
+                               MONO_INST_NEW (cfg, ins, OP_BR);
+                               ins->inst_target_bb = bb->last_ins->inst_false_bb;
+                               MONO_ADD_INS (bb, ins);
                        }
                }
        }
 
 #ifdef DEBUG_SELECTION
        if (cfg->verbose_level >= 4) {
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *tree; 
-               g_print ("DUMP BLOCK %d:\n", bb->block_num);
-
-               MONO_BB_FOR_EACH_INS (bb, tree) {
-                       mono_print_tree (tree);
-                       g_print ("\n");
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                       MonoInst *tree;
+                       g_print ("DUMP BLOCK %d:\n", bb->block_num);
+                       MONO_BB_FOR_EACH_INS (bb, tree) {
+                               mono_print_tree (tree);
+                               g_print ("\n");
+                       }
                }
        }
-       }
 #endif
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoInst *tree, *n;     
-               MonoInstList head;
+               MonoInst *tree = bb->code, *next;       
                MBState *mbstate;
 
-               MONO_INST_LIST_INIT (&head);
-               if (MONO_INST_LIST_EMPTY (&bb->ins_list))
+               if (!tree)
                        continue;
-               MONO_INST_LIST_SPLICE_INIT (&bb->ins_list, &head);
+               bb->code = NULL;
+               bb->last_ins = NULL;
                
                cfg->cbb = bb;
                mono_regstate_reset (cfg->rs);
@@ -11305,7 +12512,8 @@ mini_select_instructions (MonoCompile *cfg)
                if (cfg->verbose_level >= 3)
                        g_print ("LABEL BLOCK %d:\n", bb->block_num);
 #endif
-               MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (tree, n, &head, node) {
+               for (; tree; tree = next) {
+                       next = tree->next;
 #ifdef DEBUG_SELECTION
                        if (cfg->verbose_level >= 3) {
                                mono_print_tree (tree);
@@ -11313,6 +12521,7 @@ mini_select_instructions (MonoCompile *cfg)
                        }
 #endif
 
+                       cfg->ip = tree->cil_code;
                        if (!(mbstate = mono_burg_label (tree, cfg))) {
                                g_warning ("unable to label tree %p", tree);
                                mono_print_tree (tree);
@@ -11323,9 +12532,14 @@ mini_select_instructions (MonoCompile *cfg)
                }
                bb->max_vreg = cfg->rs->next_vreg;
 
+               if (bb->last_ins)
+                       bb->last_ins->next = NULL;
+
                mono_mempool_empty (cfg->state_pool); 
        }
        mono_mempool_destroy (cfg->state_pool); 
+
+       cfg->ip = NULL;
 }
 
 /*
@@ -11422,7 +12636,8 @@ mono_codegen (MonoCompile *cfg)
                /* we reuse dfn here */
                /* bb->dfn = bb_count++; */
 #ifdef MONO_ARCH_ENABLE_NORMALIZE_OPCODES
-               mono_normalize_opcodes (cfg, bb);
+               if (!cfg->new_ir)
+                       mono_normalize_opcodes (cfg, bb);
 #endif
 
                mono_arch_lowering_pass (cfg, bb);
@@ -11430,7 +12645,8 @@ mono_codegen (MonoCompile *cfg)
                if (cfg->opt & MONO_OPT_PEEPHOLE)
                        mono_arch_peephole_pass_1 (cfg, bb);
 
-               mono_local_regalloc (cfg, bb);
+               if (!cfg->globalra)
+                       mono_local_regalloc (cfg, bb);
 
                if (cfg->opt & MONO_OPT_PEEPHOLE)
                        mono_arch_peephole_pass_2 (cfg, bb);
@@ -11452,7 +12668,8 @@ mono_codegen (MonoCompile *cfg)
        /* emit code all basic blocks */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                bb->native_offset = cfg->code_len;
-               mono_arch_output_basic_block (cfg, bb);
+               //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
+                       mono_arch_output_basic_block (cfg, bb);
 
                if (bb == cfg->bb_exit) {
                        cfg->epilog_begin = cfg->code_len;
@@ -11479,6 +12696,10 @@ mono_codegen (MonoCompile *cfg)
        /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
 
        if (cfg->method->dynamic) {
+               guint unwindlen = 0;
+#ifdef WIN64
+               unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
+#endif
                /* Allocate the code into a separate memory pool so it can be freed */
                cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
                cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
@@ -11486,10 +12707,14 @@ mono_codegen (MonoCompile *cfg)
                mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
                mono_domain_unlock (cfg->domain);
 
-               code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size);
+               code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
        } else {
+               guint unwindlen = 0;
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+               unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
+#endif
                mono_domain_lock (cfg->domain);
-               code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size);
+               code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size + unwindlen);
                mono_domain_unlock (cfg->domain);
        }
 
@@ -11505,14 +12730,18 @@ mono_codegen (MonoCompile *cfg)
                        MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
                        if (info) {
                                //printf ("TEST %s %p\n", info->name, patch_info->data.target);
+                               // FIXME: CLEAN UP THIS MESS.
                                if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && 
-                                       strstr (cfg->method->name, info->name))
+                                       strstr (cfg->method->name, info->name)) {
                                        /*
                                         * This is an icall wrapper, and this is a call to the
                                         * wrapped function.
                                         */
-                                       ;
-                               else {
+                                       if (cfg->compile_aot) {
+                                               patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR;
+                                               patch_info->data.name = info->name;
+                                       }
+                               } else {
                                        /* for these array methods we currently register the same function pointer
                                         * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
                                         * will return the incorrect one depending on the order they are registered.
@@ -11549,11 +12778,17 @@ mono_codegen (MonoCompile *cfg)
                                mono_domain_unlock (cfg->domain);
                        }
 
-                       if (!cfg->compile_aot)
+                       if (!cfg->compile_aot && !cfg->new_ir)
                                /* In the aot case, the patch already points to the correct location */
                                patch_info->ip.i = patch_info->ip.label->inst_c0;
                        for (i = 0; i < patch_info->data.table->table_size; i++) {
-                               table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
+                               /* Might be NULL if the switch is eliminated */
+                               if (patch_info->data.table->table [i]) {
+                                       g_assert (patch_info->data.table->table [i]->native_offset);
+                                       table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
+                               } else {
+                                       table [i] = NULL;
+                               }
                        }
                        patch_info->data.table->table = (MonoBasicBlock**)table;
                        break;
@@ -11580,6 +12815,18 @@ if (valgrind_register){
                g_free (nm);
        }
 
+       {
+               gboolean is_generic = FALSE;
+
+               if (cfg->method->is_inflated || mono_method_get_generic_container (cfg->method) ||
+                               cfg->method->klass->generic_container || cfg->method->klass->generic_class) {
+                       is_generic = TRUE;
+               }
+
+               if (cfg->generic_sharing_context)
+                       g_assert (is_generic);
+       }
+
 #ifdef MONO_ARCH_HAVE_SAVE_UNWIND_INFO
        mono_arch_save_unwind_info (cfg);
 #endif
@@ -11597,20 +12844,21 @@ if (valgrind_register){
        mono_arch_flush_icache (cfg->native_code, cfg->code_len);
 
        mono_debug_close_method (cfg);
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+       mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
+#endif
 }
 
-
-
-static void
-remove_critical_edges (MonoCompile *cfg) {
+void
+mono_remove_critical_edges (MonoCompile *cfg)
+{
        MonoBasicBlock *bb;
        MonoBasicBlock *previous_bb;
        
        if (cfg->verbose_level > 3) {
                for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       MonoInst *last_ins;
                        int i;
-                       printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+                       printf ("remove_critical_edges, BEFORE BB%d (in:", bb->block_num);
                        for (i = 0; i < bb->in_count; i++) {
                                printf (" %d", bb->in_bb [i]->block_num);
                        }
@@ -11619,10 +12867,9 @@ remove_critical_edges (MonoCompile *cfg) {
                                printf (" %d", bb->out_bb [i]->block_num);
                        }
                        printf (")");
-                       last_ins = mono_inst_list_last (&bb->ins_list);
-                       if (last_ins) {
+                       if (bb->last_ins != NULL) {
                                printf (" ");
-                               mono_print_tree (last_ins);
+                               mono_print_tree (bb->last_ins);
                        }
                        printf ("\n");
                }
@@ -11635,7 +12882,6 @@ remove_critical_edges (MonoCompile *cfg) {
                                MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
                                if (in_bb->out_count > 1) {
                                        MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-                                       MONO_INST_LIST_INIT (&new_bb->ins_list);
                                        new_bb->block_num = cfg->num_bblocks++;
 //                                     new_bb->real_offset = bb->real_offset;
                                        new_bb->region = bb->region;
@@ -11643,14 +12889,12 @@ remove_critical_edges (MonoCompile *cfg) {
                                        /* Do not alter the CFG while altering the BB list */
                                        if (previous_bb->region == bb->region) {
                                                if (previous_bb != cfg->bb_entry) {
-                                                       MonoInst *last_ins;
                                                        /* If previous_bb "followed through" to bb, */
                                                        /* keep it linked with a OP_BR */
-                                                       last_ins = mono_inst_list_last (&previous_bb->ins_list);
-                                                       if ((last_ins == NULL) ||
-                                                                       ((last_ins->opcode != OP_BR) &&
-                                                                       (!(MONO_IS_COND_BRANCH_OP (last_ins))) &&
-                                                                       (last_ins->opcode != OP_SWITCH))) {
+                                                       if ((previous_bb->last_ins == NULL) ||
+                                                                       ((previous_bb->last_ins->opcode != OP_BR) &&
+                                                                       (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+                                                                       (previous_bb->last_ins->opcode != OP_SWITCH))) {
                                                                int i;
                                                                /* Make sure previous_bb really falls through bb */
                                                                for (i = 0; i < previous_bb->out_count; i++) {
@@ -11669,7 +12913,6 @@ remove_critical_edges (MonoCompile *cfg) {
                                                        /* put a new BB in the middle to hold the OP_BR */
                                                        MonoInst *jump;
                                                        MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
-                                                       MONO_INST_LIST_INIT (&new_bb_after_entry->ins_list);
                                                        new_bb_after_entry->block_num = cfg->num_bblocks++;
 //                                                     new_bb_after_entry->real_offset = bb->real_offset;
                                                        new_bb_after_entry->region = bb->region;
@@ -11683,7 +12926,7 @@ remove_critical_edges (MonoCompile *cfg) {
                                                        previous_bb = new_bb_after_entry;
                                                        
                                                        if (cfg->verbose_level > 2) {
-                                                               printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
+                                                               printf ("remove_critical_edges, added helper BB%d jumping to BB%d\n", new_bb_after_entry->block_num, bb->block_num);
                                                        }
                                                }
                                        }
@@ -11707,7 +12950,7 @@ remove_critical_edges (MonoCompile *cfg) {
                                        replace_in_block (bb, in_bb, new_bb);
                                        
                                        if (cfg->verbose_level > 2) {
-                                               printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), in_bb->block_num, bb->block_num, new_bb->block_num);
+                                               printf ("remove_critical_edges, removed critical edge from BB%d to BB%d (added BB%d)\n", in_bb->block_num, bb->block_num, new_bb->block_num);
                                        }
                                }
                        }
@@ -11716,9 +12959,8 @@ remove_critical_edges (MonoCompile *cfg) {
        
        if (cfg->verbose_level > 3) {
                for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-                       MonoInst *last_ins;
                        int i;
-                       printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+                       printf ("remove_critical_edges, AFTER BB%d (in:", bb->block_num);
                        for (i = 0; i < bb->in_count; i++) {
                                printf (" %d", bb->in_bb [i]->block_num);
                        }
@@ -11727,16 +12969,29 @@ remove_critical_edges (MonoCompile *cfg) {
                                printf (" %d", bb->out_bb [i]->block_num);
                        }
                        printf (")");
-                       last_ins = mono_inst_list_last (&bb->ins_list);
-                       if (last_ins) {
+                       if (bb->last_ins != NULL) {
                                printf (" ");
-                               mono_print_tree (last_ins);
+                               mono_print_tree (bb->last_ins);
                        }
                        printf ("\n");
                }
        }
 }
 
+static MonoGenericInst*
+get_object_generic_inst (int type_argc)
+{
+       MonoType **type_argv;
+       int i;
+
+       type_argv = alloca (sizeof (MonoType*) * type_argc);
+
+       for (i = 0; i < type_argc; ++i)
+               type_argv [i] = &mono_defaults.object_class->byval_arg;
+
+       return mono_metadata_get_generic_inst (type_argc, type_argv);
+}
+
 /*
  * mini_method_compile:
  * @method: the method to compile
@@ -11756,23 +13011,25 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        guint8 *ip;
        MonoCompile *cfg;
        MonoJitInfo *jinfo;
-       int dfn = 0, i, code_size_ratio;
+       int dfn, i, code_size_ratio;
        gboolean deadce_has_run = FALSE;
        gboolean try_generic_shared;
-       MonoMethod *method_to_compile;
+       MonoMethod *method_to_compile, *method_to_register;
        int generic_info_size;
 
        mono_jit_stats.methods_compiled++;
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_jit (method);
+       if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
+               MONO_PROBE_METHOD_COMPILE_BEGIN (method);
  
        if (compile_aot)
                /* We are passed the original generic method definition */
                try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
-                       (opts & MONO_OPT_GSHARED) && (method->generic_container || method->klass->generic_container);
+                       (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
        else
                try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
-                       (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method);
+                       (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
 
        if (opts & MONO_OPT_GSHARED) {
                if (try_generic_shared)
@@ -11790,11 +13047,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        declaring_method = method;
                } else {
                        declaring_method = mono_method_get_declaring_generic_method (method);
-                       g_assert (method->klass->generic_class->container_class == declaring_method->klass);
+                       if (method->klass->generic_class)
+                               g_assert (method->klass->generic_class->container_class == declaring_method->klass);
+                       else
+                               g_assert (method->klass == declaring_method->klass);
                }
 
-               if (declaring_method->generic_container)
-                       shared_context = &declaring_method->generic_container->context;
+               if (declaring_method->is_generic)
+                       shared_context = &(mono_method_get_generic_container (declaring_method)->context);
                else
                        shared_context = &declaring_method->klass->generic_container->context;
 
@@ -11818,35 +13078,173 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
 
+       /* The debugger has no liveness information, so avoid sharing registers/stack slots */
+       if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
+               cfg->disable_reuse_registers = TRUE;
+               cfg->disable_reuse_stack_slots = TRUE;
+               /* 
+                * This decreases the change the debugger will read registers/stack slots which are
+                * not yet initialized.
+                */
+               cfg->disable_initlocals_opt = TRUE;
+
+               /* Temporarily disable this when running in the debugger until we have support
+                * for this in the debugger. */
+               cfg->disable_omit_fp = TRUE;
+
+               // cfg->opt |= MONO_OPT_SHARED;
+               cfg->opt &= ~MONO_OPT_INLINE;
+               cfg->opt &= ~MONO_OPT_COPYPROP;
+               cfg->opt &= ~MONO_OPT_CONSPROP;
+               cfg->opt &= ~MONO_OPT_GSHARED;
+       }
+
        header = mono_method_get_header (method_to_compile);
        if (!header) {
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                        mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
                return cfg;
        }
 
+       if (getenv ("MONO_VERBOSE_METHOD")) {
+               if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
+                       cfg->verbose_level = 4;
+       }
+
        ip = (guint8 *)header->code;
 
-       if (cfg->verbose_level > 2)
-               g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
+       cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
+
+       if (cfg->verbose_level > 2) {
+               if (cfg->generic_sharing_context)
+                       g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
+               else
+                       g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
+       }
+
+       if (cfg->opt & (MONO_OPT_ABCREM | MONO_OPT_SSAPRE))
+               cfg->opt |= MONO_OPT_SSA;
+
+       {
+               static int count = 0;
+
+               count ++;
+
+               if (getenv ("MONO_COUNT")) {
+                       if (count == atoi (getenv ("MONO_COUNT"))) {
+                               printf ("LAST: %s\n", mono_method_full_name (method, TRUE));
+                               //cfg->verbose_level = 5;
+                       }
+                       if (count <= atoi (getenv ("MONO_COUNT")))
+                               cfg->new_ir = TRUE;
+
+                       /*
+                        * Passing/returning vtypes in registers in managed methods is an ABI change 
+                        * from the old JIT.
+                        */
+                       disable_vtypes_in_regs = TRUE;
+               }
+               else
+                       cfg->new_ir = TRUE;
+       }
+
+       /* 
+       if ((cfg->method->klass->image != mono_defaults.corlib) || (strstr (cfg->method->klass->name, "StackOverflowException") && strstr (cfg->method->name, ".ctor")) || (strstr (cfg->method->klass->name, "OutOfMemoryException") && strstr (cfg->method->name, ".ctor")))
+               cfg->globalra = TRUE;
+       */
+
+       //cfg->globalra = TRUE;
+
+       //if (!strcmp (cfg->method->klass->name, "Tests") && !cfg->method->wrapper_type)
+       //      cfg->globalra = TRUE;
+
+       {
+               static int count = 0;
+               count ++;
+
+               if (getenv ("COUNT2")) {
+                       if (count == atoi (getenv ("COUNT2")))
+                               printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE));
+                       if (count > atoi (getenv ("COUNT2")))
+                               cfg->globalra = FALSE;
+               }
+       }
+
+       if (header->clauses)
+               cfg->globalra = FALSE;
+
+       if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
+               /* The code in the prolog clobbers caller saved registers */
+               cfg->globalra = FALSE;
+
+       // FIXME: Disable globalra in case of tracing/profiling
+
+       if (cfg->method->save_lmf)
+               /* The LMF saving code might clobber caller saved registers */
+               cfg->globalra = FALSE;
+
+       // FIXME:
+       if (!strcmp (cfg->method->name, "CompareInternal"))
+               cfg->globalra = FALSE;
+
+       /*
+       if (strstr (cfg->method->name, "LoadData"))
+               cfg->new_ir = FALSE;
+       */
+
+       if (cfg->new_ir) {
+               cfg->rs = mono_regstate_new ();
+               cfg->next_vreg = cfg->rs->next_vreg;
+       }
+
+       /* FIXME: Fix SSA to handle branches inside bblocks */
+       if (cfg->opt & MONO_OPT_SSA)
+               cfg->enable_extended_bblocks = FALSE;
+
+       /*
+        * FIXME: This confuses liveness analysis because variables which are assigned after
+        * a branch inside a bblock become part of the kill set, even though the assignment
+        * might not get executed. This causes the optimize_initlocals pass to delete some
+        * assignments which are needed.
+        * Also, the mono_if_conversion pass needs to be modified to recognize the code
+        * created by this.
+        */
+       //cfg->enable_extended_bblocks = TRUE;
 
        /*
         * create MonoInst* which represents arguments and local variables
         */
        mono_compile_create_vars (cfg);
 
-       if ((i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
+       if (cfg->new_ir) {
+               /* SSAPRE is not supported on linear IR */
+               cfg->opt &= ~MONO_OPT_SSAPRE;
+
+               i = mono_method_to_ir2 (cfg, method_to_compile, NULL, NULL, NULL, NULL, NULL, 0, FALSE);
+       }
+       else {
+               i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE);
+       }
+
+       if (i < 0) {
                if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
-                       if (compile_aot)
+                       if (compile_aot) {
+                               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                                       MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                                return cfg;
+                       }
                        mono_destroy_compile (cfg);
                        try_generic_shared = FALSE;
                        goto restart_compile;
                }
                g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED);
 
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
                if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                        mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
                /* cfg contains the details of the failure, so let the caller cleanup */
@@ -11856,60 +13254,82 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
        mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
 
-       if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
-               /* 
-                * we disable some optimizations if there are too many variables
-                * because JIT time may become too expensive. The actual number needs 
-                * to be tweaked and eventually the non-linear algorithms should be fixed.
-                */
-               cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
-               cfg->disable_ssa = TRUE;
-       }
-
        /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
 
+       if (cfg->new_ir) {
+               mono_decompose_long_opts (cfg);
+
+               /* Should be done before branch opts */
+               if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
+                       mono_local_cprop2 (cfg);
+       }
+
        if (cfg->opt & MONO_OPT_BRANCH)
-               optimize_branches (cfg);
+               mono_optimize_branches (cfg);
 
-       if (cfg->opt & MONO_OPT_SSAPRE) {
-               remove_critical_edges (cfg);
+       if (cfg->new_ir) {
+               /* This must be done _before_ global reg alloc and _after_ decompose */
+               mono_handle_global_vregs (cfg);
+               mono_local_deadce (cfg);
+               mono_if_conversion (cfg);
        }
 
+       if ((cfg->opt & MONO_OPT_SSAPRE) || cfg->globalra)
+               mono_remove_critical_edges (cfg);
+
        /* Depth-first ordering on basic blocks */
        cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
 
+       dfn = 0;
        df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
        if (cfg->num_bblocks != dfn + 1) {
                MonoBasicBlock *bb;
 
                cfg->num_bblocks = dfn + 1;
 
-               if (!header->clauses) {
-                       /* remove unreachable code, because the code in them may be 
-                        * inconsistent  (access to dead variables for example) */
-                       for (bb = cfg->bb_entry; bb;) {
-                               MonoBasicBlock *bbn = bb->next_bb;
-
-                               if (bbn && bbn->region == -1 && !bbn->dfn) {
-                                       if (cfg->verbose_level > 1)
-                                               g_print ("found unreachable code in BB%d\n", bbn->block_num);
-                                       bb->next_bb = bbn->next_bb;
-                                       nullify_basic_block (bbn);                      
-                               } else {
-                                       bb = bb->next_bb;
-                               }
+               /* remove unreachable code, because the code in them may be 
+                * inconsistent  (access to dead variables for example) */
+               for (bb = cfg->bb_entry; bb;) {
+                       MonoBasicBlock *bbn = bb->next_bb;
+
+                       /* 
+                        * FIXME: Can't use the second case in methods with clauses, since the 
+                        * bblocks inside the clauses are not processed during dfn computation.
+                        */
+                       if ((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
+                               (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) {
+                               if (cfg->verbose_level > 1)
+                                       g_print ("found unreachable code in BB%d\n", bbn->block_num);
+                               /* There may exist unreachable branches to this bb */
+                               bb->next_bb = bbn->next_bb;
+                               nullify_basic_block (bbn);                      
+                       } else {
+                               bb = bb->next_bb;
                        }
                }
        }
 
+       if (((cfg->num_varinfo > 2000) || (cfg->num_bblocks > 1000)) && !cfg->compile_aot) {
+               /* 
+                * we disable some optimizations if there are too many variables
+                * because JIT time may become too expensive. The actual number needs 
+                * to be tweaked and eventually the non-linear algorithms should be fixed.
+                */
+               cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
+               cfg->disable_ssa = TRUE;
+       }
+
        if (cfg->opt & MONO_OPT_LOOP) {
                mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM);
                mono_compute_natural_loops (cfg);
        }
 
        /* after method_to_ir */
-       if (parts == 1)
+       if (parts == 1) {
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
+       }
 
 //#define DEBUGSSA "logic_run"
 #define DEBUGSSA_CLASS "Tests"
@@ -11917,18 +13337,24 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if (!header->num_clauses && !cfg->disable_ssa) {
                mono_local_cprop (cfg);
+
 #ifndef DISABLE_SSA
-               mono_ssa_compute (cfg);
+               if (cfg->new_ir)
+                       mono_ssa_compute2 (cfg);
+               else
+                       mono_ssa_compute (cfg);
 #endif
        }
 #else 
-
-       /* fixme: add all optimizations which requires SSA */
-       if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
+       if (cfg->opt & MONO_OPT_SSA) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
-                       mono_local_cprop (cfg);
 #ifndef DISABLE_SSA
-                       mono_ssa_compute (cfg);
+                       if (!cfg->new_ir)
+                               mono_local_cprop (cfg);
+                       if (cfg->new_ir)
+                               mono_ssa_compute2 (cfg);
+                       else
+                               mono_ssa_compute (cfg);
 #endif
 
                        if (cfg->verbose_level >= 2) {
@@ -11939,56 +13365,105 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #endif
 
        /* after SSA translation */
-       if (parts == 2)
+       if (parts == 2) {
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
+       }
 
        if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
                if (cfg->comp_done & MONO_COMP_SSA) {
 #ifndef DISABLE_SSA
-                       mono_ssa_cprop (cfg);
+                       if (cfg->new_ir)
+                               mono_ssa_cprop2 (cfg);
+                       else
+                               mono_ssa_cprop (cfg);
 #endif
                } else {
-                       mono_local_cprop (cfg);
+                       if (!cfg->new_ir)
+                               mono_local_cprop (cfg);
                }
        }
 
 #ifndef DISABLE_SSA
        if (cfg->comp_done & MONO_COMP_SSA) {                   
-               //mono_ssa_deadce (cfg);
-
                //mono_ssa_strength_reduction (cfg);
 
                if (cfg->opt & MONO_OPT_SSAPRE) {
                        mono_perform_ssapre (cfg);
                        //mono_local_cprop (cfg);
                }
-               
+
                if (cfg->opt & MONO_OPT_DEADCE) {
-                       mono_ssa_deadce (cfg);
+                       if (cfg->new_ir)
+                               mono_ssa_deadce2 (cfg);
+                       else
+                               mono_ssa_deadce (cfg);
                        deadce_has_run = TRUE;
                }
-               
-               if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
-                       mono_perform_abc_removal (cfg);
-               
-               mono_ssa_remove (cfg);
 
-               if (cfg->opt & MONO_OPT_BRANCH)
-                       optimize_branches (cfg);
+               if (cfg->new_ir) {
+                       if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
+                               mono_perform_abc_removal2 (cfg);
+               } else {
+                       if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
+                               mono_perform_abc_removal (cfg);
+               }
+
+               if (cfg->new_ir) {
+                       mono_ssa_remove2 (cfg);
+                       mono_local_cprop2 (cfg);
+                       mono_handle_global_vregs (cfg);
+                       mono_local_deadce (cfg);
+               }
+               else
+                       mono_ssa_remove (cfg);
+
+               if (cfg->opt & MONO_OPT_BRANCH) {
+                       MonoBasicBlock *bb;
+
+                       mono_optimize_branches (cfg);
+
+                       /* Have to recompute cfg->bblocks and bb->dfn */
+                       if (cfg->globalra) {
+                               mono_remove_critical_edges (cfg);
+
+                               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
+                                       bb->dfn = 0;
+
+                               /* Depth-first ordering on basic blocks */
+                               cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
+
+                               dfn = 0;
+                               df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
+                               cfg->num_bblocks = dfn + 1;
+                       }
+               }
        }
 #endif
 
        /* after SSA removal */
-       if (parts == 3)
+       if (parts == 3) {
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
                return cfg;
+       }
+
+       if (cfg->new_ir) {
+#ifdef MONO_ARCH_SOFT_FLOAT
+               mono_handle_soft_float (cfg);
+#endif
+               mono_decompose_vtype_opts (cfg);
+               if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
+                       mono_decompose_array_access_opts (cfg);
+       }
+
+       if (!cfg->new_ir) {
+               if (cfg->verbose_level > 4)
+                       mono_print_code (cfg, "BEFORE DECOMPOSE");
 
-       if (cfg->verbose_level > 4) {
-               printf ("BEFORE DECOMPSE START\n");
-               mono_print_code (cfg);
-               printf ("BEFORE DECOMPSE END\n");
+               decompose_pass (cfg);
        }
-       
-       decompose_pass (cfg);
 
        if (cfg->got_var) {
                GList *regs;
@@ -12020,11 +13495,21 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
         */
        mono_liveness_handle_exception_clauses (cfg);
 
-       if (cfg->opt & MONO_OPT_LINEARS) {
+       if (cfg->globalra) {
+               MonoBasicBlock *bb;
+
+               /* Have to do this before regalloc since it can create vregs */
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
+                       mono_arch_lowering_pass (cfg, bb);
+
+               mono_global_regalloc (cfg);
+       }
+
+       if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
                GList *vars, *regs;
                
                /* For now, compute aliasing info only if needed for deadce... */
-               if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
+               if (!cfg->new_ir && (cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
                        cfg->aliasing_info = mono_build_aliasing_information (cfg);
                }
 
@@ -12056,12 +13541,67 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
     //print_dfn (cfg);
        
        /* variables are allocated after decompose, since decompose could create temps */
-       mono_arch_allocate_vars (cfg);
+       if (!cfg->globalra)
+               mono_arch_allocate_vars (cfg);
 
-       if (cfg->opt & MONO_OPT_CFOLD)
+       if (!cfg->new_ir && cfg->opt & MONO_OPT_CFOLD)
                mono_constant_fold (cfg);
 
-       mini_select_instructions (cfg);
+       if (cfg->new_ir) {
+               MonoBasicBlock *bb;
+               gboolean need_local_opts;
+
+               if (!cfg->globalra) {
+                       mono_spill_global_vars (cfg, &need_local_opts);
+
+                       if (need_local_opts || cfg->compile_aot) {
+                               /* To optimize code created by spill_global_vars */
+                               mono_local_cprop2 (cfg);
+                               mono_local_deadce (cfg);
+                       }
+               }
+
+               /* Add branches between non-consecutive bblocks */
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                       if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins) &&
+                               bb->last_ins->inst_false_bb && bb->next_bb != bb->last_ins->inst_false_bb) {
+                               /* we are careful when inverting, since bugs like #59580
+                                * could show up when dealing with NaNs.
+                                */
+                               if (MONO_IS_COND_BRANCH_NOFP(bb->last_ins) && bb->next_bb == bb->last_ins->inst_true_bb) {
+                                       MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
+                                       bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
+                                       bb->last_ins->inst_false_bb = tmp;
+
+                                       bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+                               } else {                        
+                                       MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+                                       inst->opcode = OP_BR;
+                                       inst->inst_target_bb = bb->last_ins->inst_false_bb;
+                                       mono_bblock_add_inst (bb, inst);
+                               }
+                       }
+               }
+
+               if (cfg->verbose_level >= 4 && !cfg->globalra) {
+                       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                               MonoInst *tree = bb->code;      
+                               g_print ("DUMP BLOCK %d:\n", bb->block_num);
+                               if (!tree)
+                                       continue;
+                               for (; tree; tree = tree->next) {
+                                       mono_print_ins_index (-1, tree);
+                               }
+                       }
+               }
+
+               /* FIXME: */
+               for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+                       bb->max_vreg = cfg->next_vreg;
+               }
+       }
+       else
+               mini_select_instructions (cfg);
 
        mono_codegen (cfg);
        if (cfg->verbose_level >= 2) {
@@ -12087,7 +13627,35 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                mono_domain_unlock (cfg->domain);
        }
 
-       jinfo->method = method;
+       if (cfg->generic_sharing_context) {
+               MonoGenericContext object_context;
+
+               g_assert (!method_to_compile->klass->generic_class);
+               if (method_to_compile->klass->generic_container) {
+                       int type_argc = method_to_compile->klass->generic_container->type_argc;
+
+                       object_context.class_inst = get_object_generic_inst (type_argc);
+               } else {
+                       object_context.class_inst = NULL;
+               }
+
+               if (mini_method_get_context (method_to_compile)->method_inst) {
+                       int type_argc = mini_method_get_context (method_to_compile)->method_inst->type_argc;
+
+                       object_context.method_inst = get_object_generic_inst (type_argc);
+               } else {
+                       object_context.method_inst = NULL;
+               }
+
+               g_assert (object_context.class_inst || object_context.method_inst);
+
+               method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
+       } else {
+               g_assert (method == method_to_compile);
+               method_to_register = method;
+       }
+
+       jinfo->method = method_to_register;
        jinfo->code_start = cfg->native_code;
        jinfo->code_size = cfg->code_len;
        jinfo->used_regs = cfg->used_int_regs;
@@ -12095,13 +13663,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
        jinfo->num_clauses = header->num_clauses;
 
-       /*
-        * Static methods only get a generic JIT info if they use the
-        * rgctx variable (which they are forced to if they have any
-        * open catch clauses).
-        */
-       if (cfg->generic_sharing_context &&
-                       (cfg->rgctx_var || !(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC))) {
+       if (cfg->generic_sharing_context) {
                MonoInst *inst;
                MonoGenericJitInfo *gi;
 
@@ -12112,32 +13674,46 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                gi->generic_sharing_context = cfg->generic_sharing_context;
 
-               if (method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) {
-                       inst = cfg->rgctx_var;
-                       g_assert (inst->opcode == OP_REGOFFSET);
-               } else {
-                       inst = cfg->varinfo [0];
-               }
+               /*
+                * Non-generic static methods only get a "this" info
+                * if they use the rgctx variable (which they are
+                * forced to if they have any open catch clauses).
+                */
+               if (cfg->rgctx_var ||
+                               (!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
+                               !mini_method_get_context (method_to_compile)->method_inst)) {
+                       gi->has_this = 1;
+
+                       if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
+                                       mini_method_get_context (method_to_compile)->method_inst) {
+                               inst = cfg->rgctx_var;
+                               g_assert (inst->opcode == OP_REGOFFSET);
+                       } else {
+                               inst = cfg->args [0];
+                       }
 
-               if (inst->opcode == OP_REGVAR) {
-                       gi->this_in_reg = 1;
-                       gi->this_reg = inst->dreg;
+                       if (inst->opcode == OP_REGVAR) {
+                               gi->this_in_reg = 1;
+                               gi->this_reg = inst->dreg;
 
-                       //g_print ("this in reg %d\n", inst->dreg);
-               } else {
-                       g_assert (inst->opcode == OP_REGOFFSET);
+                               //g_print ("this in reg %d\n", inst->dreg);
+                       } else {
+                               g_assert (inst->opcode == OP_REGOFFSET);
 #ifdef __i386__
-                       g_assert (inst->inst_basereg == X86_EBP);
+                               g_assert (inst->inst_basereg == X86_EBP);
 #elif defined(__x86_64__)
-                       g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
+                               g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
 #endif
-                       g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
+                               g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
 
-                       gi->this_in_reg = 0;
-                       gi->this_reg = inst->inst_basereg;
-                       gi->this_offset = inst->inst_offset;
+                               gi->this_in_reg = 0;
+                               gi->this_reg = inst->inst_basereg;
+                               gi->this_offset = inst->inst_offset;
 
-                       //g_print ("this at offset %d\n", inst->inst_offset);
+                               //g_print ("this at offset %d from reg %d\n", gi->this_offset, gi->this_reg);
+                       }
+               } else {
+                       gi->has_this = 0;
                }
        }
 
@@ -12182,27 +13758,33 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_arch_fixup_jinfo (cfg);
 #endif
 
-       mono_domain_lock (cfg->domain);
-       mono_jit_info_table_add (cfg->domain, jinfo);
+       if (!cfg->compile_aot) {
+               mono_domain_lock (cfg->domain);
+               mono_jit_info_table_add (cfg->domain, jinfo);
 
-       if (cfg->method->dynamic)
-               mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
-       mono_domain_unlock (cfg->domain);
+               if (cfg->method->dynamic)
+                       mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
+               mono_domain_unlock (cfg->domain);
+       }
 
        /* collect statistics */
        mono_jit_stats.allocated_code_size += cfg->code_len;
        code_size_ratio = cfg->code_len;
-       if (code_size_ratio > mono_jit_stats.biggest_method_size) {
-                       mono_jit_stats.biggest_method_size = code_size_ratio;
-                       mono_jit_stats.biggest_method = method;
+       if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) {
+               mono_jit_stats.biggest_method_size = code_size_ratio;
+               g_free (mono_jit_stats.biggest_method);
+               mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
        }
        code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
-       if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
+       if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) {
                mono_jit_stats.max_code_size_ratio = code_size_ratio;
-               mono_jit_stats.max_ratio_method = method;
+               g_free (mono_jit_stats.max_ratio_method);
+               mono_jit_stats.max_ratio_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
        }
        mono_jit_stats.native_code_size += cfg->code_len;
 
+       if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+               MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
        if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
 
@@ -12214,7 +13796,7 @@ lookup_generic_method (MonoDomain *domain, MonoMethod *method)
 {
        MonoMethod *open_method;
 
-       if (!mono_method_is_generic_sharable_impl (method))
+       if (!mono_method_is_generic_sharable_impl (method, FALSE))
                return NULL;
 
        open_method = mono_method_get_declaring_generic_method (method);
@@ -12222,23 +13804,39 @@ lookup_generic_method (MonoDomain *domain, MonoMethod *method)
        return mono_domain_lookup_shared_generic (domain, open_method);
 }
 
+/*
+ * LOCKING: Assumes domain->jit_code_hash_lock is held.
+ */
 static MonoJitInfo*
-lookup_method (MonoDomain *domain, MonoMethod *method)
+lookup_method_inner (MonoDomain *domain, MonoMethod *method)
 {
        MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
 
-       if (ji != NULL)
+       if (ji)
                return ji;
 
        return lookup_generic_method (domain, method);
 }
 
+static MonoJitInfo*
+lookup_method (MonoDomain *domain, MonoMethod *method)
+{
+       MonoJitInfo *info;
+
+       mono_domain_jit_code_hash_lock (domain);
+       info = lookup_method_inner (domain, method);
+       mono_domain_jit_code_hash_unlock (domain);
+
+       return info;
+}
+
 static gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
 {
        MonoCompile *cfg;
        gpointer code = NULL;
        MonoJitInfo *info;
+       MonoVTable *vtable;
 
 #ifdef MONO_USE_AOT_COMPILER
        if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
@@ -12249,7 +13847,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                mono_domain_lock (domain);
                if ((code = mono_aot_get_method (domain, method))) {
                        mono_domain_unlock (domain);
-                       mono_runtime_class_init (mono_class_vtable (domain, method->klass));
+                       vtable = mono_class_vtable (domain, method->klass);
+                       g_assert (vtable);
+                       mono_runtime_class_init (vtable);
                        return code;
                }
 
@@ -12262,15 +13862,17 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                MonoMethod *nm;
                MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
 
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
-                       g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
-
                if (!piinfo->addr) {
                        if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
                                piinfo->addr = mono_lookup_internal_call (method);
+                       else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+#ifdef PLATFORM_WIN32
+                               g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
+#else
+                               g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
+#endif
                        else
-                               if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
-                                       mono_lookup_pinvoke_call (method, NULL, NULL);
+                               mono_lookup_pinvoke_call (method, NULL, NULL);
                }
                        nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc);
                        return mono_get_addr_from_ftnptr (mono_compile_method (nm));
@@ -12304,6 +13906,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                return NULL;
        }
 
+       if (mono_aot_only)
+               g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method, TRUE));
+
        cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
 
        switch (cfg->exception_type) {
@@ -12377,6 +13982,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
                mono_raise_exception ((MonoException*)exc);
        }
+       case MONO_EXCEPTION_OBJECT_SUPPLIED: {
+               MonoException *exp = cfg->exception_ptr;
+               MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
+               mono_destroy_compile (cfg);
+               mono_raise_exception (exp);
+               break;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -12386,7 +13998,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        /* Check if some other thread already did the job. In this case, we can
        discard the code this thread generated. */
 
-       if ((info = lookup_method (target_domain, method))) {
+       mono_domain_jit_code_hash_lock (target_domain);
+
+       info = lookup_method_inner (target_domain, method);
+       if (info) {
                /* We can't use a domain specific method in another domain */
                if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
                        code = info->code_start;
@@ -12395,15 +14010,18 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        }
        
        if (code == NULL) {
-               mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
+               mono_internal_hash_table_insert (&target_domain->jit_code_hash, cfg->jit_info->method, cfg->jit_info);
+               mono_domain_jit_code_hash_unlock (target_domain);
                code = cfg->native_code;
 
-               if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method)) {
+               if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) {
                        /* g_print ("inserting method %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name); */
                        mono_domain_register_shared_generic (target_domain, 
                                mono_method_get_declaring_generic_method (method), cfg->jit_info);
                        mono_stats.generics_shared_methods++;
                }
+       } else {
+               mono_domain_jit_code_hash_unlock (target_domain);
        }
 
        mono_destroy_compile (cfg);
@@ -12426,7 +14044,14 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        mono_domain_unlock (target_domain);
 
-       mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
+       vtable = mono_class_vtable (target_domain, method->klass);
+       if (!vtable) {
+               MonoException *exc;
+               exc = mono_class_get_exception_for_failure (method->klass);
+               g_assert (exc);
+               mono_raise_exception (exc);
+       }
+       mono_runtime_class_init (vtable);
        return code;
 }
 
@@ -12459,19 +14084,19 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
        else 
                target_domain = domain;
 
-       mono_domain_lock (target_domain);
-
-       if ((info = lookup_method (target_domain, method))) {
+       info = lookup_method (target_domain, method);
+       if (info) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
-                       mono_domain_unlock (target_domain);
+                       MonoVTable *vtable;
+
                        mono_jit_stats.methods_lookups++;
-                       mono_runtime_class_init (mono_class_vtable (domain, method->klass));
+                       vtable = mono_class_vtable (domain, method->klass);
+                       mono_runtime_class_init (vtable);
                        return mono_create_ftnptr (target_domain, info->code_start);
                }
        }
 
-       mono_domain_unlock (target_domain);
        p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
 
        if (callinfo) {
@@ -12493,6 +14118,7 @@ mono_jit_compile_method (MonoMethod *method)
        return mono_jit_compile_method_with_opt (method, default_opt);
 }
 
+#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
 static void
 invalidated_delegate_trampoline (char *desc)
 {
@@ -12500,6 +14126,7 @@ invalidated_delegate_trampoline (char *desc)
                 "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
                 desc);
 }
+#endif
 
 /*
  * mono_jit_free_method:
@@ -12550,7 +14177,6 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
 
        if (destroy)
                mono_code_manager_destroy (ji->code_mp);
-       mono_thread_hazardous_free_or_queue (ji->ji, g_free);
        g_free (ji);
 }
 
@@ -12565,19 +14191,15 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
        else 
                target_domain = domain;
 
-       mono_domain_lock (target_domain);
-
-       if ((info = lookup_method (target_domain, method))) {
+       info = lookup_method (target_domain, method);
+       if (info) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
-                       mono_domain_unlock (target_domain);
                        mono_jit_stats.methods_lookups++;
                        return info->code_start;
                }
        }
 
-       mono_domain_unlock (target_domain);
-
        return NULL;
 }
 
@@ -12595,15 +14217,17 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        MonoMethod *invoke;
        MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
        void* compiled_method;
+       MonoVTable *vtable;
 
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
                return NULL;
        }
 
-       if ((method->flags & METHOD_ATTRIBUTE_STATIC) &&
+       if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
+                               (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
                        mono_class_generic_sharing_enabled (method->klass) &&
-                       mono_method_is_generic_sharable_impl (method)) {
+                       mono_method_is_generic_sharable_impl (method, FALSE)) {
                to_compile = mono_marshal_get_static_rgctx_invoke (method);
        } else {
                to_compile = method;
@@ -12615,7 +14239,9 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
         * the helper method in System.Object and not the target class
         */
-       mono_runtime_class_init (mono_class_vtable (mono_domain_get (), method->klass));
+       vtable = mono_class_vtable (mono_domain_get (), method->klass);
+       g_assert (vtable);
+       mono_runtime_class_init (vtable);
 
        if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
                (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
@@ -12818,14 +14444,97 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+#if defined(__i386__) || defined(__x86_64__)
+#define FULL_STAT_PROFILER_BACKTRACE 1
+#define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
+#define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
+#if MONO_ARCH_STACK_GROWS_UP
+#define IS_BEFORE_ON_STACK <
+#define IS_AFTER_ON_STACK >
+#else
+#define IS_BEFORE_ON_STACK >
+#define IS_AFTER_ON_STACK <
+#endif
+#else
+#define FULL_STAT_PROFILER_BACKTRACE 0
+#endif
+
+#if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
+
+static void
+SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+{
+       NOT_IMPLEMENTED;
+}
+
+#else
+
 static void
 SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
 {
+       int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
        GET_CONTEXT;
+       
+       if (call_chain_depth == 0) {
+               mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
+       } else {
+               MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+               int current_frame_index = 1;
+               MonoContext mono_context;
+#if FULL_STAT_PROFILER_BACKTRACE
+               guchar *current_frame;
+               guchar *stack_bottom;
+               guchar *stack_top;
+#else
+               MonoDomain *domain;
+#endif
+               guchar *ips [call_chain_depth + 1];
 
-       mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
+               mono_arch_sigctx_to_monoctx (ctx, &mono_context);
+               ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
+               
+               if (jit_tls != NULL) {
+#if FULL_STAT_PROFILER_BACKTRACE
+                       stack_bottom = jit_tls->end_of_stack;
+                       stack_top = MONO_CONTEXT_GET_SP (&mono_context);
+                       current_frame = MONO_CONTEXT_GET_BP (&mono_context);
+                       
+                       while ((current_frame_index <= call_chain_depth) &&
+                                       (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
+                                       ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
+                               ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
+                               current_frame_index ++;
+                               stack_top = current_frame;
+                               current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
+                       }
+#else
+                       domain = mono_domain_get ();
+                       if (domain != NULL) {
+                               MonoLMF *lmf = NULL;
+                               MonoJitInfo *ji;
+                               MonoJitInfo res;
+                               MonoContext new_mono_context;
+                               int native_offset;
+                               ji = mono_arch_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
+                                               &new_mono_context, NULL, &lmf, &native_offset, NULL);
+                               while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
+                                       ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
+                                       current_frame_index ++;
+                                       mono_context = new_mono_context;
+                                       ji = mono_arch_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
+                                                       &new_mono_context, NULL, &lmf, &native_offset, NULL);
+                               }
+                       }
+#endif
+               }
+               
+               
+               mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
+       }
 }
 
+#endif
+
 static void
 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
 {
@@ -13237,7 +14946,7 @@ mini_get_imt_trampoline (void)
 {
        static gpointer tramp = NULL;
        if (!tramp)
-               tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
+               tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
        return tramp;
 }
 #endif
@@ -13248,7 +14957,7 @@ mini_get_vtable_trampoline (void)
 {
        static gpointer tramp = NULL;
        if (!tramp)
-               tramp =  mono_arch_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_GENERIC, mono_get_root_domain (), NULL);
+               tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
        return tramp;
 }
 #endif
@@ -13275,12 +14984,18 @@ mini_parse_debug_options (void)
                        debug_options.collect_pagefault_stats = TRUE;
                else if (!strcmp (arg, "break-on-unverified"))
                        debug_options.break_on_unverified = TRUE;
+               else if (!strcmp (arg, "no-gdb-backtrace"))
+                       debug_options.no_gdb_backtrace = TRUE;
+               else if (!strcmp (arg, "dont-free-domains"))
+                       mono_dont_free_domains = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains'\n");
                        exit (1);
                }
        }
+
+       g_strfreev (args);
 }
 
 MonoDebugOptions *
@@ -13294,6 +15009,8 @@ mini_init (const char *filename, const char *runtime_version)
 {
        MonoDomain *domain;
 
+       MONO_PROBE_VES_INIT_BEGIN ();
+
 #ifdef __linux__
        if (access ("/proc/self/maps", F_OK) != 0) {
                g_print ("Mono requires /proc to be mounted.\n");
@@ -13317,8 +15034,6 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_trampolines_init ();
 
-       mono_exceptions_init ();
-
        if (!g_thread_supported ())
                g_thread_init (NULL);
 
@@ -13360,10 +15075,8 @@ mini_init (const char *filename, const char *runtime_version)
 #define JIT_INVOKE_WORKS
 #ifdef JIT_INVOKE_WORKS
        mono_install_runtime_invoke (mono_jit_runtime_invoke);
-       mono_install_handler (mono_arch_get_throw_exception ());
 #endif
        mono_install_stack_walk (mono_jit_walk_stack);
-       mono_install_init_vtable (mono_aot_init_vtable);
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
@@ -13377,13 +15090,28 @@ mini_init (const char *filename, const char *runtime_version)
                domain = mono_init_version (filename, runtime_version);
        else
                domain = mono_init_from_assembly (filename, filename);
+
+       if (mono_aot_only) {
+               /* The IMT tables are very dynamic thus they are hard to AOT */
+               mono_use_imt = FALSE;
+               /* This helps catch code allocation requests */
+               mono_code_manager_set_read_only (domain->code_mp);
+       }
+
 #ifdef MONO_ARCH_HAVE_IMT
-       mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-       mono_install_imt_trampoline (mini_get_imt_trampoline ());
+       if (mono_use_imt) {
+               mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
+               mono_install_imt_trampoline (mini_get_imt_trampoline ());
 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
-       mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
+               mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
 #endif
+       }
 #endif
+
+       /* This must come after mono_init () in the aot-only case */
+       mono_exceptions_init ();
+       mono_install_handler (mono_get_throw_exception ());
+
        mono_icall_init ();
 
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
@@ -13416,11 +15144,11 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "void", TRUE);
        register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
 
-       register_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
-       register_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
-       register_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
+       register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
+       register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
+       register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
-       register_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
+       register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
                                 "void ptr", TRUE);
 #endif
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
@@ -13455,12 +15183,19 @@ mini_init (const char *filename, const char *runtime_version)
        mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
        mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
        mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
+       mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE);
+       mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
+       mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE);
+       mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
 #endif
 
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
        mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
        mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
        mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
+       mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
+       mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
+       mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
 #endif
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
        mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
@@ -13476,6 +15211,7 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
        mono_register_opcode_emulation (CEE_CONV_R_UN, "__emul_conv_r_un", "double int32", mono_conv_to_r8_un, FALSE);
+       mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
        mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE);
@@ -13496,7 +15232,9 @@ mini_init (const char *filename, const char *runtime_version)
        mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
        mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
        mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
+       mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE);
        mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
+       mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
@@ -13535,6 +15273,8 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_class_static_field_address , "mono_class_static_field_address", 
                                 "ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
+       register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
+               "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
        register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
        register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
@@ -13546,16 +15286,20 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
+       register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
        register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
+       register_icall (mono_helper_compile_generic_method_wo_context, "compile_generic_method_wo_context",
+               "ptr object ptr ptr", FALSE);
        register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
        register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
        register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
        register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
-       register_icall (mono_helper_get_rgctx_other_ptr, "get_rgctx_other_ptr", "ptr ptr ptr int32 int32 int32 int32", FALSE);
+       register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
        register_icall (mono_break, "mono_break", NULL, TRUE);
        register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);
        register_icall (mono_create_corlib_exception_1, "mono_create_corlib_exception_1", "object int object", TRUE);
        register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
+       register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
 #endif
 
 #define JIT_RUNTIME_WORKS
@@ -13567,6 +15311,9 @@ mini_init (const char *filename, const char *runtime_version)
        mono_generic_sharing_init ();
 
        mono_thread_attach (domain);
+       
+       MONO_PROBE_VES_INIT_END ();
+       
        return domain;
 }
 
@@ -13587,14 +15334,15 @@ print_jit_stats (void)
                g_print ("Analyze stack repeat:   %ld\n", mono_jit_stats.analyze_stack_repeat);
                g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
                g_print ("Native code size:       %ld\n", mono_jit_stats.native_code_size);
-               g_print ("Max code size ratio:    %.2f (%s::%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
-                               mono_jit_stats.max_ratio_method->klass->name, mono_jit_stats.max_ratio_method->name);
-               g_print ("Biggest method:         %ld (%s::%s)\n", mono_jit_stats.biggest_method_size,
-                               mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
+               g_print ("Max code size ratio:    %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
+                                mono_jit_stats.max_ratio_method);
+               g_print ("Biggest method:         %ld (%s)\n", mono_jit_stats.biggest_method_size,
+                                mono_jit_stats.biggest_method);
                g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
                g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
                g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
                g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
+               g_print ("Regvars:                %ld\n", mono_jit_stats.regvars);
                g_print ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
 
                g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
@@ -13655,6 +15403,11 @@ print_jit_stats (void)
                        g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
                        g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
                }
+
+               g_free (mono_jit_stats.max_ratio_method);
+               mono_jit_stats.max_ratio_method = NULL;
+               g_free (mono_jit_stats.biggest_method);
+               mono_jit_stats.biggest_method = NULL;
        }
 }