2008-08-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / method-to-ir.c
index 447fa04acffd9991d675648dde809c40a16f17a5..46ec4f916b91ab11b0ee8f21f5fcf2f67fe851b6 100644 (file)
@@ -99,7 +99,7 @@
        } while (0)
 #define GENERIC_SHARING_FAILURE(opcode) do {           \
                if (cfg->generic_sharing_context) {     \
-            if (cfg->verbose_level > -1) \
+            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;    \
@@ -128,10 +128,10 @@ int mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *st
                   guint inline_offset, gboolean is_virtual_call);
 
 /* helper methods signature */
-MonoMethodSignature *helper_sig_class_init_trampoline;
-MonoMethodSignature *helper_sig_domain_get;
-MonoMethodSignature *helper_sig_generic_class_init_trampoline;
-MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
+extern MonoMethodSignature *helper_sig_class_init_trampoline;
+extern MonoMethodSignature *helper_sig_domain_get;
+extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
+extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
 
 /*
  * Instruction metadata
@@ -333,7 +333,7 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                } \
        } while (0)
 #else
-#define ADD_WIDEN_OP(arg1, arg2)
+#define ADD_WIDEN_OP(ins, arg1, arg2)
 #endif
 
 #define ADD_BINOP(op) do {     \
@@ -2174,10 +2174,10 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
 #ifdef MONO_ARCH_IMT_REG
        int method_reg = alloc_preg (cfg);
 
-       if (cfg->compile_aot) {
-               MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
-       } else if (imt_arg) {
+       if (imt_arg) {
                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
+       } else if (cfg->compile_aot) {
+               MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
        } else {
                MonoInst *ins;
                MONO_INST_NEW (cfg, ins, OP_PCONST);
@@ -2193,6 +2193,18 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
 }
 #endif
 
+static MonoJumpInfo *
+mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
+{
+       MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+
+       ji->ip.i = ip;
+       ji->type = type;
+       ji->data.target = target;
+
+       return ji;
+}
+
 inline static MonoInst*
 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
 
@@ -2298,6 +2310,7 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
        call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr);
        mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
+       cfg->uses_rgctx_reg = TRUE;
        return (MonoInst*)call;
 #else
        g_assert_not_reached ();
@@ -2306,8 +2319,8 @@ mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **ar
 }
 
 static MonoInst*
-mono_emit_imt_method_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
-                                                  MonoInst **args, MonoInst *this, MonoInst *imt_arg)
+mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
+                                                       MonoInst **args, MonoInst *this, MonoInst *imt_arg)
 {
        gboolean virtual = this != NULL;
        gboolean enable_for_aot = TRUE;
@@ -2316,7 +2329,7 @@ mono_emit_imt_method_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSigna
        if (method->string_ctor) {
                /* Create the real signature */
                /* FIXME: Cache these */
-               MonoMethodSignature *ctor_sig = mono_metadata_signature_dup (sig);
+               MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_full (cfg->mempool, sig);
                ctor_sig->ret = &mono_defaults.string_class->byval_arg;
 
                sig = ctor_sig;
@@ -2431,10 +2444,9 @@ mono_emit_imt_method_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSigna
 }
 
 static inline MonoInst*
-mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
-                                          MonoInst **args, MonoInst *this)
+mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
 {
-       return mono_emit_imt_method_call (cfg, method, sig, args, this, NULL);
+       return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL);
 }
 
 MonoInst*
@@ -2463,6 +2475,30 @@ mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
        return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
 }
 
+/*
+ * mono_emit_abs_call:
+ *
+ *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
+ */
+inline static MonoInst*
+mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
+                                       MonoMethodSignature *sig, MonoInst **args)
+{
+       MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
+       MonoInst *ins;
+
+       /* 
+        * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
+        * handle it.
+        */
+       if (cfg->abs_patches == NULL)
+               cfg->abs_patches = g_hash_table_new (NULL, NULL);
+       g_hash_table_insert (cfg->abs_patches, ji, ji);
+       ins = mono_emit_native_call (cfg, ji, sig, args);
+       ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
+       return ins;
+}
+
 static MonoMethod*
 get_memcpy_method (void)
 {
@@ -2507,7 +2543,7 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                EMIT_NEW_ICONST (cfg, iargs [2], n);
                
                memcpy_method = get_memcpy_method ();
-               mono_emit_method_call (cfg, memcpy_method, memcpy_method->signature, iargs, NULL);
+               mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
        }
 }
 
@@ -2544,15 +2580,20 @@ mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass
                iargs [0] = dest;
                EMIT_NEW_ICONST (cfg, iargs [1], 0);
                EMIT_NEW_ICONST (cfg, iargs [2], n);
-               mono_emit_method_call (cfg, memset_method, memset_method->signature, iargs, NULL);
+               mono_emit_method_call (cfg, memset_method, iargs, NULL);
        }
 }
 
 static MonoInst*
-emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this)
+emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
 {
+       MonoInst *this = NULL;
+
        g_assert (!method->klass->valuetype);
 
+       if (!(method->flags & METHOD_ATTRIBUTE_STATIC) && !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD))
+               EMIT_NEW_ARGLOAD (cfg, this, 0);
+
        if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
                MonoInst *mrgctx_loc, *mrgctx_var;
 
@@ -2593,61 +2634,55 @@ emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst
 }
 
 #define EMIT_GET_RGCTX(rgctx, context_used) do {                               \
-               MonoInst *this = NULL;                                  \
                GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
-               if (!(method->flags & METHOD_ATTRIBUTE_STATIC) && !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
-                       EMIT_NEW_ARGLOAD (cfg, this, 0);                        \
-               (rgctx) = emit_get_rgctx (cfg, method, (context_used), this); \
+               (rgctx) = emit_get_rgctx (cfg, method, (context_used)); \
        } while (0)
 
-static MonoInst*
-emit_get_rgctx_other_table_ptr (MonoCompile *cfg, MonoInst *rgc_ptr, int slot)
+static MonoJumpInfoRgctxEntry *
+mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, int info_type)
 {
-       MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
-       guint8 *tramp = mini_create_rgctx_lazy_fetch_trampoline (slot);
+       MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
+       res->method = method;
+       res->in_mrgctx = in_mrgctx;
+       res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
+       res->data->type = patch_type;
+       res->data->data.target = patch_data;
+       res->info_type = info_type;
 
-       return mono_emit_native_call (cfg, tramp, sig, &rgc_ptr);
+       return res;
+}
+
+static inline MonoInst*
+emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
+{
+       return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
 }
 
 static MonoInst*
 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
                                          MonoInst *rgctx, MonoClass *klass, int rgctx_type)
 {
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, cfg->generic_context);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
 
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
                                           MonoInst *rgctx, MonoMethod *cmethod, int rgctx_type)
 {
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, cfg->generic_context);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
 
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 static MonoInst*
 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
                                          MonoInst *rgctx, MonoClassField *field, int rgctx_type)
 {
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, cfg->generic_context);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
 
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
-}
-
-static MonoInst*
-emit_get_rgctx_method_rgctx (MonoCompile *cfg, int context_used,
-                                                        MonoInst *rgctx, MonoMethod *rgctx_method)
-{
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
-               MONO_RGCTX_INFO_METHOD_RGCTX, cfg->generic_context);
-
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 /**
@@ -2658,16 +2693,14 @@ static MonoInst*
 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used, MonoInst *rgctx)
 {
        MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
-       // Can't encode method ref
-       cfg->disable_aot = TRUE;
 
-       if (rgctx) {
+       if (context_used) {
                MonoInst *addr = emit_get_rgctx_method (cfg, context_used, rgctx, method,
                                                                                                MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 
                return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
        } else {
-               return mono_emit_method_call (cfg, method, mono_method_signature (method), &val, NULL);
+               return mono_emit_method_call (cfg, method, &val, NULL);
        }
 }
 
@@ -2741,7 +2774,7 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
 
                if (managed_alloc) {
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
-                       return mono_emit_method_call (cfg, managed_alloc, mono_method_signature (managed_alloc), iargs, NULL);
+                       return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                }
                alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
                if (pass_lw) {
@@ -2779,12 +2812,9 @@ handle_alloc_from_inst (MonoCompile *cfg, MonoClass *klass, MonoInst *data_inst,
                iargs [1] = data_inst;
                alloc_ftn = mono_object_new;
        } else {
-               g_assert (!cfg->compile_aot);
-
                if (managed_alloc) {
                        iargs [0] = data_inst;
-                       return mono_emit_method_call (cfg, managed_alloc,
-                                                                                 mono_method_signature (managed_alloc), iargs, NULL);
+                       return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                }
 
                iargs [0] = data_inst;
@@ -2801,9 +2831,7 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
 
        if (mono_class_is_nullable (klass)) {
                MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
-               // Can't encode method ref
-               cfg->disable_aot = TRUE;
-               return mono_emit_method_call (cfg, method, mono_method_signature (method), &val, NULL);
+               return mono_emit_method_call (cfg, method, &val, NULL);
        }
 
        alloc = handle_alloc (cfg, klass, TRUE);
@@ -2814,17 +2842,23 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
 }
 
 static MonoInst *
-handle_box_from_inst (MonoCompile *cfg, MonoInst *val, MonoClass *klass, MonoInst *data_inst)
+handle_box_from_inst (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoInst *rgctx, MonoInst *data_inst)
 {
        MonoInst *alloc, *ins;
 
-       g_assert (!mono_class_is_nullable (klass));
+       if (mono_class_is_nullable (klass)) {
+               MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+               MonoInst *addr = emit_get_rgctx_method (cfg, context_used, rgctx, method,
+                                                                                               MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 
-       alloc = handle_alloc_from_inst (cfg, klass, data_inst, TRUE);
+               return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+       } else {
+               alloc = handle_alloc_from_inst (cfg, klass, data_inst, TRUE);
 
-       EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
+               EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
 
-       return alloc;
+               return alloc;
+       }
 }
 
 static MonoInst*
@@ -3171,6 +3205,8 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
 {
        gpointer *trampoline;
        MonoInst *obj, *method_ins, *tramp_ins;
+       MonoDomain *domain;
+       guint8 **code_slot;
 
        obj = handle_alloc (cfg, klass, FALSE);
 
@@ -3185,6 +3221,29 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        EMIT_NEW_METHODCONST (cfg, method_ins, method);
        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
 
+       /* 
+        * To avoid looking up the compiled code belonging to the target method
+        * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
+        * store it, and we fill it after the method has been compiled.
+        */
+       if (!cfg->compile_aot && !method->dynamic) {
+               MonoInst *code_slot_ins;
+
+               domain = mono_domain_get ();
+               mono_domain_lock (domain);
+               if (!domain->method_code_hash)
+                       domain->method_code_hash = g_hash_table_new (NULL, NULL);
+               code_slot = g_hash_table_lookup (domain->method_code_hash, method);
+               if (!code_slot) {
+                       code_slot = mono_mempool_alloc0 (domain->mp, sizeof (gpointer));
+                       g_hash_table_insert (domain->method_code_hash, method, code_slot);
+               }
+               mono_domain_unlock (domain);
+
+               EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
+       }
+
        /* Set invoke_impl field */
        trampoline = mono_create_delegate_trampoline (klass);
        EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
@@ -3243,8 +3302,6 @@ mono_emit_load_got_addr (MonoCompile *cfg)
        MONO_ADD_INS (cfg->bb_exit, dummy_use);
 }
 
-#define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
-
 static gboolean
 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 {
@@ -3490,7 +3547,7 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
 
        element_size = mono_class_array_element_size (cmethod->klass->element_class);
        addr_method = mono_marshal_get_array_address (rank, element_size);
-       addr = mono_emit_method_call (cfg, addr_method, addr_method->signature, sp, NULL);
+       addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
 
        return addr;
 }
@@ -3827,7 +3884,7 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method,
                                return NULL;
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
                        iargs [1] = args [0];
-                       return mono_emit_method_call (cfg, managed_alloc, mono_method_signature (managed_alloc), iargs, this);
+                       return mono_emit_method_call (cfg, managed_alloc, iargs, this);
                }
        }
        return NULL;
@@ -3862,50 +3919,62 @@ mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp, MonoI
 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
 
 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
-static char*
-mono_inline_called_method_name_limit = NULL;
-static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
-       char *called_method_name = mono_method_full_name (called_method, TRUE);
+static gboolean
+check_inline_called_method_name_limit (MonoMethod *called_method)
+{
        int strncmp_result;
+       static char *limit = NULL;
        
-       if (mono_inline_called_method_name_limit == NULL) {
+       if (limit == NULL) {
                char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
-               if (limit_string != NULL) {
-                       mono_inline_called_method_name_limit = limit_string;
-               } else {
-                       mono_inline_called_method_name_limit = (char *) "";
-               }
+
+               if (limit_string != NULL)
+                       limit = limit_string;
+               else
+                       limit = (char *) "";
        }
+
+       if (limit [0] != '\0') {
+               char *called_method_name = mono_method_full_name (called_method, TRUE);
+
+               strncmp_result = strncmp (called_method_name, limit, strlen (limit));
+               g_free (called_method_name);
        
-       strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
-       g_free (called_method_name);
-       
-       //return (strncmp_result <= 0);
-       return (strncmp_result == 0);
+               //return (strncmp_result <= 0);
+               return (strncmp_result == 0);
+       } else {
+               return FALSE;
+       }
 }
 #endif
 
 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
-static char*
-mono_inline_caller_method_name_limit = NULL;
-static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
-       char *caller_method_name = mono_method_full_name (caller_method, TRUE);
+static gboolean
+check_inline_caller_method_name_limit (MonoMethod *caller_method)
+{
        int strncmp_result;
+       static char *limit = NULL;
        
-       if (mono_inline_caller_method_name_limit == NULL) {
+       if (limit == NULL) {
                char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
                if (limit_string != NULL) {
-                       mono_inline_caller_method_name_limit = limit_string;
+                       limit = limit_string;
                } else {
-                       mono_inline_caller_method_name_limit = (char *) "";
+                       limit = (char *) "";
                }
        }
+
+       if (limit [0] != '\0') {
+               char *caller_method_name = mono_method_full_name (caller_method, TRUE);
+
+               strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
+               g_free (caller_method_name);
        
-       strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
-       g_free (caller_method_name);
-       
-       //return (strncmp_result <= 0);
-       return (strncmp_result == 0);
+               //return (strncmp_result <= 0);
+               return (strncmp_result == 0);
+       } else {
+               return FALSE;
+       }
 }
 #endif
 
@@ -3919,6 +3988,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        int i, costs;
        MonoMethod *prev_inlined_method;
        MonoInst **prev_locals, **prev_args;
+       MonoType **prev_arg_types;
        guint prev_real_offset;
        GHashTable *prev_cbb_hash;
        MonoBasicBlock **prev_cil_offset_to_bb;
@@ -3958,8 +4028,6 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        for (i = 0; i < cheader->num_locals; ++i)
                cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
 
-       prev_args = cfg->args;
-       
        /* allocate start and end blocks */
        /* This is needed so if the inline is aborted, we can clean up */
        NEW_BBLOCK (cfg, sbblock);
@@ -3969,6 +4037,8 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        ebblock->block_num = cfg->num_bblocks++;
        ebblock->real_offset = real_offset;
 
+       prev_args = cfg->args;
+       prev_arg_types = cfg->arg_types;
        prev_inlined_method = cfg->inlined_method;
        cfg->inlined_method = cmethod;
        cfg->ret_var_set = FALSE;
@@ -3991,6 +4061,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        cfg->cil_start = prev_cil_start;
        cfg->locals = prev_locals;
        cfg->args = prev_args;
+       cfg->arg_types = prev_arg_types;
        cfg->current_method = prev_current_method;
        cfg->generic_context = prev_generic_context;
 
@@ -4273,7 +4344,7 @@ gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *cal
 
                NEW_ICONST (cfg, args [0], 4);
                NEW_METHODCONST (cfg, args [1], caller);
-               mono_emit_method_call (cfg, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, NULL);
+               mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
        } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
                 /* don't hide previous results */
                cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
@@ -4307,7 +4378,7 @@ emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMe
 
        EMIT_NEW_METHODCONST (cfg, args [0], caller);
        EMIT_NEW_METHODCONST (cfg, args [1], callee);
-       mono_emit_method_call (cfg, thrower, mono_method_signature (thrower), args, NULL);
+       mono_emit_method_call (cfg, thrower, args, NULL);
 }
 
 static MonoMethod*
@@ -4329,7 +4400,7 @@ emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, uns
 {
        MonoMethod *thrower = verification_exception ();
 
-       mono_emit_method_call (cfg, thrower, mono_method_signature (thrower), NULL, NULL);
+       mono_emit_method_call (cfg, thrower, NULL, NULL);
 }
 
 static void
@@ -4954,9 +5025,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                end_bblock->cil_length = 0;
                g_assert (cfg->num_bblocks == 2);
 
-               arg_array = alloca (sizeof (MonoInst *) * num_args);
-               for (i = num_args - 1; i >= 0; i--)
-                       arg_array [i] = cfg->args [i];
+               arg_array = cfg->args;
 
                if (header->num_clauses) {
                        cfg->spvars = g_hash_table_new (NULL, NULL);
@@ -5055,6 +5124,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                arg_array = alloca (sizeof (MonoInst *) * num_args);
                cfg->cbb = start_bblock;
                mono_save_args (cfg, sig, inline_args, arg_array);
+               cfg->args = arg_array;
        }
 
        /* FIRST CODE BLOCK */
@@ -5140,7 +5210,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
                        EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
                        /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
-                       mono_emit_method_call (cfg, secman->demand, mono_method_signature (secman->demand), args, NULL);
+                       mono_emit_method_call (cfg, secman->demand, args, NULL);
                }
                if (actions.noncasdemand.blob) {
                        /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
@@ -5148,20 +5218,20 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
                        EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
                        /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
-                       mono_emit_method_call (cfg, secman->demand, mono_method_signature (secman->demand), args, NULL);
+                       mono_emit_method_call (cfg, secman->demand, args, NULL);
                }
                if (actions.demandchoice.blob) {
                        /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
                        EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
                        EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
                        /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
-                       mono_emit_method_call (cfg, secman->demandchoice, mono_method_signature (secman->demandchoice), args, NULL);
+                       mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
                }
        }
 
        /* we must Demand SecurityPermission.Unmanaged before p/invoking */
        if (pinvoke) {
-               mono_emit_method_call (cfg, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, NULL);
+               mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
        }
 
        if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
@@ -5194,6 +5264,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
        for (n = 0; n < sig->param_count; ++n)
                param_types [n + sig->hasthis] = sig->params [n];
+       cfg->arg_types = param_types;
        for (n = 0; n < header->num_locals; ++n) {
                if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
                        UNVERIFIED;
@@ -5402,10 +5473,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                token = read32 (ip + 4);
                                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_INITOBJ);
-
-                               if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               if (generic_class_is_reference_type (cfg, klass)) {
+                                       MONO_EMIT_NEW_PCONST (cfg, cfg->locals [ip [1]]->dreg, NULL);
+                               } else if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                        MONO_EMIT_NEW_PCONST (cfg, cfg->locals [ip [1]]->dreg, NULL);
                                } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
                                        MONO_EMIT_NEW_VZERO (cfg, cfg->locals [ip [1]]->dreg, klass);
@@ -5566,8 +5636,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        CHECK_OPSIZE (5);
                        if (stack_start != sp)
                                UNVERIFIED;
-                       MONO_INST_NEW_CALL (cfg, call, OP_JMP);
-                       ins = (MonoInst*)call;
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
@@ -5584,13 +5652,41 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                CHECK_CFG_EXCEPTION;
                        }
 
+#ifdef __x86_64__
+                       {
+                               MonoMethodSignature *fsig = mono_method_signature (cmethod);
+                               int i, n;
+
+                               /* FIXME: Remove OP_JMP from mini-amd64.c when the old JIT is removed */
+
+                               /* Handle tail calls similarly to calls */
+                               n = fsig->param_count + fsig->hasthis;
+
+                               MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
+                               call->method = cmethod;
+                               call->tail_call = TRUE;
+                               call->signature = mono_method_signature (cmethod);
+                               call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
+                               call->inst.inst_p0 = cmethod;
+                               for (i = 0; i < n; ++i)
+                                       EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
+
+                               mono_arch_emit_call (cfg, call);
+                               MONO_ADD_INS (bblock, (MonoInst*)call);
+                       }
+#else
+                       for (i = 0; i < num_args; ++i)
+                               /* Prevent arguments from being optimized away */
+                               arg_array [i]->flags |= MONO_INST_VOLATILE;
+
+                       MONO_INST_NEW_CALL (cfg, call, OP_JMP);
+                       ins = (MonoInst*)call;
                        ins->inst_p0 = cmethod;
                        MONO_ADD_INS (bblock, ins);
+#endif
+
                        ip += 5;
                        start_new_bblock = 1;
-
-                       /* FIXME: */
-                       cfg->disable_aot = 1;
                        break;
                }
                case CEE_CALLI:
@@ -5659,7 +5755,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                goto load_error;
 
                                if (mono_method_signature (cmethod)->pinvoke) {
-                                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
+                                       MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
                                        fsig = mono_method_signature (wrapper);
                                } else if (constrained_call) {
                                        fsig = mono_method_signature (cmethod);
@@ -5748,7 +5844,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                 * generic method).
                                 */
                                if (sharing_enabled && context_sharable &&
-                                               !mini_method_get_context (cmethod)->method_inst)
+                                       !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
                                        pass_vtable = TRUE;
                        }
 
@@ -5793,10 +5889,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        mono_get_vtable_var (cfg);
                        }
 
-                       // FIXME:
-                       if (!cmethod)
-                               GENERIC_SHARING_FAILURE (*ip);
-
                        if (pass_vtable) {
                                if (context_used) {
                                        MonoInst *rgctx;
@@ -5818,14 +5910,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        MonoInst *rgctx;
 
                                        EMIT_GET_RGCTX (rgctx, context_used);
-                                       vtable_arg = emit_get_rgctx_method_rgctx (cfg, context_used, rgctx, cmethod);
+                                       vtable_arg = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
                                } else {
-                                       MonoMethodRuntimeGenericContext *mrgctx;
-
-                                       mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
-                                               mini_method_get_context (cmethod)->method_inst);
-
-                                       EMIT_NEW_PCONST (cfg, vtable_arg, mrgctx);
+                                       EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
                                }
 
                                if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
@@ -5876,8 +5963,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                /* FIXME: This should be a managed pointer */
                                this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
-                               /* Because of the PCONST below */
-                               cfg->disable_aot = TRUE;
                                EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
                                if (context_used) {
                                        MonoInst *rgctx;
@@ -5886,11 +5971,10 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        iargs [1] = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod, MONO_RGCTX_INFO_METHOD);
                                        EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
                                        addr = mono_emit_jit_icall (cfg,
-                                               mono_helper_compile_generic_method_wo_context, iargs);
+                                               mono_helper_compile_generic_method, iargs);
                                } else {
                                        EMIT_NEW_METHODCONST (cfg, iargs [1], cmethod);
-                                       EMIT_NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
-                                       EMIT_NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
+                                       EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
                                        addr = mono_emit_jit_icall (cfg, mono_helper_compile_generic_method, iargs);
                                }
 
@@ -5940,9 +6024,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                }
 #endif
 
-                               /* FIXME: */
-                               cfg->disable_aot = 1;
-
                                ins = (MonoInst*)call;
                                ins->inst_p0 = cmethod;
                                ins->inst_p1 = arg_array [0];
@@ -5980,7 +6061,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
                                        /* Prevent inlining of methods that call wrappers */
                                        INLINE_FAILURE;
-                                       cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
+                                       cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
                                        allways = TRUE;
                                }
 
@@ -6090,8 +6171,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
                                        call = (MonoCallInst*)ins;
                                        mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
+                                       cfg->uses_rgctx_reg = TRUE;
 #else
-                                       GENERIC_SHARING_FAILURE (*ip);
+                                       NOT_IMPLEMENTED;
 #endif
                                } else {
                                        ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
@@ -6195,16 +6277,17 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                int rgctx_reg = mono_alloc_preg (cfg);
 
                                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
-                               ins = (MonoInst*)mono_emit_method_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
+                               ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL);
                                call = (MonoCallInst*)ins;
                                mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
+                               cfg->uses_rgctx_reg = TRUE;
 #else
-                               GENERIC_SHARING_FAILURE (*ip);                          
+                               NOT_IMPLEMENTED;
 #endif
                        } else if (imt_arg) {
-                               ins = (MonoInst*)mono_emit_imt_method_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
+                               ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
                        } else {
-                               ins = (MonoInst*)mono_emit_method_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
+                               ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL);
                        }
 
                        if (!MONO_TYPE_IS_VOID (fsig->ret))
@@ -6217,7 +6300,13 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                case CEE_RET:
                        if (cfg->method != method) {
                                /* return from inlined method */
-                               if (return_var) {
+                               /* 
+                                * If in_count == 0, that means the ret is unreachable due to
+                                * being preceeded by a throw. In that case, inline_method () will
+                                * handle setting the return value 
+                                * (test case: test_0_inline_throw ()).
+                                */
+                               if (return_var && cfg->cbb->in_count) {
                                        MonoInst *store;
                                        CHECK_STACK (1);
                                        --sp;
@@ -6425,10 +6514,12 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        MonoBasicBlock **targets;
                        MonoBasicBlock *default_bblock;
                        MonoJumpInfoBBTable *table;
+#ifndef __arm__
                        int offset_reg = alloc_preg (cfg);
                        int target_reg = alloc_preg (cfg);
                        int table_reg = alloc_preg (cfg);
                        int sum_reg = alloc_preg (cfg);
+#endif
 
                        CHECK_OPSIZE (5);
                        CHECK_STACK (1);
@@ -6977,8 +7068,11 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        if (mini_class_is_system_array (cmethod->klass)) {
                                g_assert (!context_used);
                                EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
-                               if (fsig->param_count == 2)
-                                       /* Avoid varargs in the common case */
+
+                               /* Avoid varargs in the common case */
+                               if (fsig->param_count == 1)
+                                       alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
+                               else if (fsig->param_count == 2)
                                        alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
                                else
                                        alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
@@ -6987,7 +7081,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                /* we simply pass a null pointer */
                                EMIT_NEW_PCONST (cfg, *sp, NULL); 
                                /* now call the string ctor */
-                               alloc = mono_emit_method_call (cfg, cmethod, fsig, sp, NULL);
+                               alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL);
                        } else {
                                MonoInst* callvirt_this_arg = NULL;
                                
@@ -7027,10 +7121,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                         * As a workaround, we call class cctors before allocating objects.
                                         */
                                        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, tramp, 
-                                                                                          helper_sig_class_init_trampoline,
-                                                                                          NULL);
+                                               mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
                                                if (cfg->verbose_level > 2)
                                                        printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
                                                class_inits = g_slist_prepend (class_inits, vtable);
@@ -7061,7 +7152,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                inline_costs += costs - 5;
                                        } else {
                                                INLINE_FAILURE;
-                                               mono_emit_method_call (cfg, cmethod, fsig, sp, callvirt_this_arg);
+                                               mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL);
                                        }
                                } else if (context_used &&
                                                (cmethod->klass->valuetype ||
@@ -7077,15 +7168,14 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        mono_emit_calli (cfg, fsig, sp, cmethod_addr);
                                } else {
                                        INLINE_FAILURE;
-                                       mono_emit_method_call (cfg, cmethod, fsig, sp, callvirt_this_arg);
+                                       mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL);
                                }
                        }
 
                        if (alloc == NULL) {
                                /* Valuetype */
                                EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
-                               ins->type = STACK_VTYPE;
-                               ins->klass = ins->klass;
+                               type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
                                *sp++= ins;
                        }
                        else
@@ -7152,7 +7242,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                ip += 5;
                        }
                        break;
-               case CEE_ISINST:
+               case CEE_ISINST: {
                        CHECK_STACK (1);
                        --sp;
                        CHECK_OPSIZE (5);
@@ -7162,11 +7252,24 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
  
-                       if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
-                               GENERIC_SHARING_FAILURE (CEE_ISINST);
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
-                       if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-                       
+                       if (context_used) {
+                               MonoInst *rgctx, *args [2];
+
+                               /* obj */
+                               args [0] = *sp;
+
+                               /* klass */
+                               EMIT_GET_RGCTX (rgctx, context_used);
+                               args [1] = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_KLASS);
+
+                               *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
+                               sp++;
+                               ip += 5;
+                               inline_costs += 2;
+                       } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                    
                                MonoMethod *mono_isinst;
                                MonoInst *iargs [1];
                                int costs;
@@ -7193,6 +7296,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                ip += 5;
                        }
                        break;
+               }
                case CEE_UNBOX_ANY: {
                        MonoInst *rgctx = NULL;
 
@@ -7203,6 +7307,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
  
+                       mono_save_token_info (cfg, image, token, klass);
+
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
@@ -7275,7 +7381,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                }
                case CEE_BOX: {
                        MonoInst *val;
-                       int context_used = 0;
 
                        CHECK_STACK (1);
                        --sp;
@@ -7285,12 +7390,10 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
-                       if (cfg->generic_sharing_context) {
-                               context_used = mono_class_check_context_used (klass);
+                       mono_save_token_info (cfg, image, token, klass);
 
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
-                                       GENERIC_SHARING_FAILURE (*ip);
-                       }
+                       if (cfg->generic_sharing_context)
+                               context_used = mono_class_check_context_used (klass);
 
                        if (generic_class_is_reference_type (cfg, klass)) {
                                *sp++ = val;
@@ -7324,6 +7427,11 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                CHECK_BBLOCK (target, ip, tblock);
                                ins->inst_target_bb = tblock;
                                GET_BBLOCK (cfg, tblock, ip);
+                               /* 
+                                * This leads to some inconsistency, since the two bblocks are not
+                                * really connected, but it is needed for handling stack arguments
+                                * correct (See test_0_box_brtrue_opt_regress_81102).
+                                */
                                link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, stack_start, sp - stack_start);
@@ -7337,21 +7445,16 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                        if (context_used) {
                                MonoInst *rgctx;
+                               MonoInst *data;
+                               int rgctx_info;
 
-                               if (mono_class_is_nullable (klass)) {
-                                       GENERIC_SHARING_FAILURE (CEE_BOX);
-                               } else {
-                                       MonoInst *data;
-                                       int rgctx_info;
-
-                                       EMIT_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 = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, rgctx_info);
-                                       *sp++ = handle_box_from_inst (cfg, val, klass, data);
-                               }
+                               EMIT_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 = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, rgctx_info);
+                               *sp++ = handle_box_from_inst (cfg, val, klass, context_used, rgctx, data);
                        } else {
                                *sp++ = handle_box (cfg, val, klass);
                        }
@@ -7370,6 +7473,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       mono_save_token_info (cfg, image, token, klass);
+
                        if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
@@ -7451,7 +7556,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                                inline_costs += costs;
                                                break;
                                        } else {
-                                               mono_emit_method_call (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, NULL);
+                                               mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
                                        }
                                } else {
                                        MonoInst *store;
@@ -7487,7 +7592,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        inline_costs += costs;
                                        break;
                                } else {
-                                       ins = mono_emit_method_call (cfg, wrapper, mono_method_signature (wrapper), iargs, NULL);
+                                       ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
                                        *sp++ = ins;
                                }
                        } else {
@@ -7496,10 +7601,11 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                                        /* Have to compute the address of the variable */
 
-                                       var = cfg->vreg_to_inst [sp [0]->dreg];
-                                       if (!var && sp [0]->opcode == OP_VMOVE)
-                                               var = cfg->vreg_to_inst [sp [0]->sreg1];
-                                       g_assert (var);
+                                       var = get_vreg_to_inst (cfg, sp [0]->dreg);
+                                       if (!var)
+                                               var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
+                                       else
+                                               g_assert (var->klass == klass);
                                        
                                        EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
                                        sp [0] = ins;
@@ -7616,9 +7722,10 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                         * the calling convention, so assign it manually, and make a call
                                         * using a signature without parameters.
                                         */                                     
-                                       call = (MonoCallInst*)mono_emit_native_call (cfg, mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT), helper_sig_generic_class_init_trampoline, &vtable);
+                                       call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable);
 #ifdef MONO_ARCH_VTABLE_REG
                                        mono_call_inst_add_outarg_reg (cfg, call, vtable->dreg, MONO_ARCH_VTABLE_REG, FALSE);
+                                       cfg->uses_vtable_reg = TRUE;
 #else
                                        NOT_IMPLEMENTED;
 #endif
@@ -7651,10 +7758,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                CHECK_TYPELOAD (klass);
                                if (!addr) {
                                        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, tramp, 
-                                                                                          helper_sig_class_init_trampoline,
-                                                                                          NULL);
+                                               mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
                                                if (cfg->verbose_level > 2)
                                                        printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
                                                class_inits = g_slist_prepend (class_inits, vtable);
@@ -7785,9 +7889,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        load->flags |= ins_flag;
                                        ins_flag = 0;
                                        *sp++ = load;
-
-                                       /* fixme: dont see the problem why this does not work */
-                                       //cfg->disable_aot = TRUE;
                                }
                        }
                        ip += 5;
@@ -7814,7 +7915,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        MonoInst *len_ins;
                        const char *data_ptr;
                        int data_size = 0;
-                       gboolean shared_access = FALSE;
 
                        CHECK_STACK (1);
                        --sp;
@@ -7825,33 +7925,23 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        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)
-                                       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) {
+                       if (context_used) {
                                MonoInst *rgctx;
-                               MonoInst *args [3];
+                               MonoInst *args [2];
 
                                /* FIXME: Decompose later to help abcrem */
 
-                               /* domain */
-                               EMIT_NEW_DOMAINCONST (cfg, args [0]);
-
-                               /* klass */
+                               /* vtable */
                                EMIT_GET_RGCTX (rgctx, context_used);
-                               args [1] = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_KLASS);
+                               args [0] = emit_get_rgctx_klass (cfg, context_used, rgctx, mono_array_class_get (klass, 1), MONO_RGCTX_INFO_VTABLE);
 
                                /* array len */
-                               args [2] = sp [0];
+                               args [1] = sp [0];
 
-                               ins = mono_emit_jit_icall (cfg, mono_array_new, args);
+                               ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
                        } else {
                                if (cfg->opt & MONO_OPT_SHARED) {
                                        /* Decompose now to avoid problems with references to the domainvar */
@@ -7873,6 +7963,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        MONO_ADD_INS (cfg->cbb, ins);
                                        cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
                                        cfg->cbb->has_array_access = TRUE;
+
+                                       /* Needed so mono_emit_load_get_addr () gets called */
+                                       mono_get_got_var (cfg);
                                }
                        }
 
@@ -7899,7 +7992,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
                                }
                                EMIT_NEW_ICONST (cfg, iargs [2], data_size);
-                               mono_emit_method_call (cfg, memcpy_method, memcpy_method->signature, iargs, NULL);
+                               mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
                                ip += 11;
                        }
 
@@ -8039,7 +8132,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                iargs [1] = sp [1];
                                iargs [0] = sp [0];
                                
-                               mono_emit_method_call (cfg, helper, mono_method_signature (helper), iargs, NULL);
+                               mono_emit_method_call (cfg, helper, iargs, NULL);
                        } else {
                                if (sp [1]->opcode == OP_ICONST) {
                                        int array_reg = sp [0]->dreg;
@@ -8072,12 +8165,13 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        MONO_ADD_INS (bblock, ins);
                        *sp++ = ins;
 
+                       mono_decompose_opcode (cfg, ins);
+
                        ++ip;
                        break;
                }
                case CEE_REFANYVAL: {
                        MonoInst *src_var, *src;
-                       int context_used = 0;
 
                        int klass_reg = alloc_preg (cfg);
                        int dreg = alloc_preg (cfg);
@@ -8090,25 +8184,29 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
 
-                       if (cfg->generic_sharing_context) {
+                       if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
-                               if (context_used && cfg->compile_aot)
-                                       GENERIC_SHARING_FAILURE (*ip);
-                       }
+
+                       // FIXME:
+                       src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
+                       if (!src_var)
+                               src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
+                       EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
+                       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
 
                        if (context_used) {
+                               MonoInst *rgctx, *klass_ins;
+
+                               EMIT_GET_RGCTX (rgctx, context_used);
+                               klass_ins = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_KLASS);
+
                                // FIXME:
-                               GENERIC_SHARING_FAILURE (*ip);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
+                               MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
                        } else {
-                               // FIXME:
-                               src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
-                               if (!src_var)
-                                       src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
-                               EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
-                               MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
                                mini_emit_class_check (cfg, klass_reg, klass);
-                               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
                        }
+                       EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
                        ins->type = STACK_MP;
                        *sp++ = ins;
                        ip += 5;
@@ -8116,7 +8214,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                }
                case CEE_MKREFANY: {
                        MonoInst *loc, *addr;
-                       int context_used = 0;
 
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, *ip);
@@ -8126,17 +8223,21 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
 
-                       if (cfg->generic_sharing_context) {
+                       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);
                        EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
 
                        if (context_used) {
-                               GENERIC_SHARING_FAILURE (CEE_MKREFANY);
+                               MonoInst *rgctx, *const_ins;
+                               int type_reg = alloc_preg (cfg);
+
+                               EMIT_GET_RGCTX (rgctx, context_used);
+                               const_ins = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_KLASS);
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
                        } else if (cfg->compile_aot) {
                                int const_reg = alloc_preg (cfg);
                                int type_reg = alloc_preg (cfg);
@@ -8161,7 +8262,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                case CEE_LDTOKEN: {
                        gpointer handle;
                        MonoClass *handle_class;
-                       int context_used = 0;
 
                        CHECK_STACK_OVF (1);
 
@@ -8238,16 +8338,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        if (context_used) {
                                                MonoInst *rgctx;
 
-                                               g_assert (!cfg->compile_aot);
                                                EMIT_GET_RGCTX (rgctx, context_used);
                                                ins = emit_get_rgctx_klass (cfg, context_used, rgctx, tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
                                        } 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;
                                                EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
                                        } else {
                                                EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
@@ -8263,8 +8356,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        if (context_used) {
                                                        MonoInst *rgctx;
 
-                                               g_assert (!cfg->compile_aot);
-
                                                EMIT_GET_RGCTX (rgctx, context_used);
                                                if (handle_class == mono_defaults.typehandle_class) {
                                                        ins = emit_get_rgctx_klass (cfg, context_used, rgctx,
@@ -8448,33 +8539,22 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                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 || 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) {
-                                               EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
+                               if (cfg->compile_aot && (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 */
+                                               EMIT_NEW_PCONST (cfg, ins, ptr);
                                                *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 */
-                                                       EMIT_NEW_PCONST (cfg, ins, ptr);
-                                                       *sp++ = ins;
-                                                       ip += 6;
-                                                       break;
-                                               }
-                                       }
                                }
                                /* FIXME: Generalize this */
                                if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
@@ -8491,6 +8571,27 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                cfg->disable_aot = 1;
                                break;
                        }
+                       case CEE_MONO_ICALL_ADDR: {
+                               MonoMethod *cmethod;
+                               gpointer ptr;
+
+                               CHECK_STACK_OVF (1);
+                               CHECK_OPSIZE (6);
+                               token = read32 (ip + 2);
+
+                               cmethod = mono_method_get_wrapper_data (method, token);
+
+                               if (cfg->compile_aot) {
+                                       EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
+                               } else {
+                                       ptr = mono_lookup_internal_call (cmethod);
+                                       g_assert (ptr);
+                                       EMIT_NEW_PCONST (cfg, ins, ptr);
+                               }
+                               *sp++ = ins;
+                               ip += 6;
+                               break;
+                       }
                        case CEE_MONO_VTADDR: {
                                MonoInst *src_var, *src;
 
@@ -8576,7 +8677,13 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                token = read32 (ip + 2);    
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
 
-                               EMIT_NEW_RETLOADA (cfg, ins);
+                               if (!cfg->vret_addr) {
+                                       g_assert (cfg->ret_var_is_local);
+
+                                       EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
+                               } else {
+                                       EMIT_NEW_RETLOADA (cfg, ins);
+                               }
                                mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
                                
                                if (sp != stack_start)
@@ -8717,7 +8824,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        case CEE_LDFTN: {
                                MonoInst *argconst;
                                MonoMethod *cil_method, *ctor_method;
-                               gboolean is_shared;
+                               gboolean is_shared = FALSE;
 
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
@@ -8726,14 +8833,22 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                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);
 
-                               is_shared = (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
-                                       (cmethod->klass->generic_class || cmethod->klass->generic_container) &&
-                                       mono_class_generic_sharing_enabled (cmethod->klass);
+                               mono_save_token_info (cfg, image, n, cmethod);
+
+                               if (cfg->generic_sharing_context)
+                                       context_used = mono_method_check_context_used (cmethod);
 
+                               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))
                                        METHOD_ACCESS_FAILURE;
@@ -8751,7 +8866,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                 */
 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
                                /* FIXME: SGEN support */
-                               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 (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+                               /* FIXME: handle shared static generic methods */
+                               /* 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;
@@ -8766,14 +8883,20 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                }
 #endif
 
-                               if (is_shared)
+                               if (context_used) {
+                                       MonoInst *rgctx;
+
+                                       if (is_shared)
+                                               cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
+
+                                       EMIT_GET_RGCTX (rgctx, context_used);
+                                       argconst = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod, MONO_RGCTX_INFO_METHOD);
+                               } else if (is_shared) {
                                        EMIT_NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
-                               else
+                               } else {
                                        EMIT_NEW_METHODCONST (cfg, argconst, cmethod);
-                               if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
-                                       ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
-                               else
-                                       ins = mono_emit_jit_icall (cfg, mono_ldftn_nosync, &argconst);
+                               }
+                               ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
                                *sp++ = ins;
                                
                                ip += 6;
@@ -8791,8 +8914,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        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))
@@ -8804,8 +8927,17 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                                --sp;
                                args [0] = *sp;
-                               EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
-                               *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
+
+                               if (context_used) {
+                                       MonoInst *rgctx;
+
+                                       EMIT_GET_RGCTX (rgctx, context_used);
+                                       args [1] = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod, MONO_RGCTX_INFO_METHOD);
+                                       *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
+                               } else {
+                                       EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+                                       *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
+                               }
 
                                ip += 6;
                                inline_costs += 10 * num_calls++;
@@ -8985,10 +9117,10 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        iargs [2] = sp [2];
                                        if (ip [1] == CEE_CPBLK) {
                                                MonoMethod *memcpy_method = get_memcpy_method ();
-                                               mono_emit_method_call (cfg, memcpy_method, memcpy_method->signature, iargs, NULL);
+                                               mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
                                        } else {
                                                MonoMethod *memset_method = get_memset_method ();
-                                               mono_emit_method_call (cfg, memset_method, memset_method->signature, iargs, NULL);
+                                               mono_emit_method_call (cfg, memset_method, iargs, NULL);
                                        }
                                }
                                ip += 2;
@@ -9660,7 +9792,7 @@ int
 mono_op_to_op_imm_noemul (int opcode)
 {
        switch (opcode) {
-#if SIZEOF_VOID_P == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPTS)
+#if SIZEOF_VOID_P == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
        case OP_LSHR:
        case OP_LSHL:
        case OP_LSHR_UN:
@@ -9743,14 +9875,14 @@ mono_handle_global_vregs (MonoCompile *cfg)
 
                                                if (cfg->verbose_level > 1)
                                                        printf ("LONG VREG R%d made global.\n", vreg);
-
-                                               /*
-                                                * Make the component vregs volatile since the optimizations can
-                                                * get confused otherwise.
-                                                */
-                                               get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
-                                               get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
                                        }
+
+                                       /*
+                                        * Make the component vregs volatile since the optimizations can
+                                        * get confused otherwise.
+                                        */
+                                       get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
+                                       get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
                                }
 #endif