2008-08-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / method-to-ir.c
index b3a0e4ccb55748c9939de319fc8d5f09a7ba3ba6..b9586d3b99b661e63080e5716c525245b86ddc00 100644 (file)
 
 #include <config.h>
 #include <signal.h>
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
 #include <math.h>
+
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
@@ -92,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;    \
@@ -121,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
@@ -314,7 +321,21 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                MONO_ADD_INS ((cfg)->cbb, (dest)); \
        } while (0)
 #endif
-                       
+
+#if SIZEOF_VOID_P == 8
+#define ADD_WIDEN_OP(ins, arg1, arg2) do { \
+               /* FIXME: Need to add many more cases */ \
+               if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) { \
+                       MonoInst *widen; \
+                       int dr = alloc_preg (cfg); \
+                       EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
+                       (ins)->sreg2 = widen->dreg; \
+               } \
+       } while (0)
+#else
+#define ADD_WIDEN_OP(ins, arg1, arg2)
+#endif
+
 #define ADD_BINOP(op) do {     \
                MONO_INST_NEW (cfg, ins, (op)); \
                sp -= 2;        \
@@ -322,6 +343,8 @@ mono_print_bb (MonoBasicBlock *bb, const char *msg)
                ins->sreg2 = sp [1]->dreg;      \
                type_from_op (ins, sp [0], sp [1]);     \
                CHECK_TYPE (ins);       \
+               /* Have to insert a widening op */               \
+        ADD_WIDEN_OP (ins, sp [0], sp [1]); \
         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
         MONO_ADD_INS ((cfg)->cbb, (ins)); \
                *sp++ = ins;    \
@@ -2170,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);
 
@@ -2283,8 +2318,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;
@@ -2293,7 +2328,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;
@@ -2408,10 +2443,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*
@@ -2440,6 +2474,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)
 {
@@ -2484,7 +2542,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);
        }
 }
 
@@ -2521,15 +2579,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;
 
@@ -2570,61 +2633,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);
-
-       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);
+       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);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 /**
@@ -2635,16 +2692,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);
        }
 }
 
@@ -2718,7 +2773,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) {
@@ -2756,12 +2811,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;
@@ -2778,9 +2830,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);
@@ -2791,17 +2841,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*
@@ -3148,6 +3204,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);
 
@@ -3162,6 +3220,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);
@@ -3220,8 +3301,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)
 {
@@ -3467,7 +3546,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;
 }
@@ -3804,7 +3883,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;
@@ -3839,50 +3918,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
 
@@ -3896,6 +3987,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;
@@ -3935,8 +4027,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);
@@ -3946,6 +4036,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;
@@ -3968,6 +4060,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;
 
@@ -4250,7 +4343,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;
@@ -4284,7 +4377,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*
@@ -4306,7 +4399,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
@@ -4931,9 +5024,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);
@@ -5032,6 +5123,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 */
@@ -5117,7 +5209,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) */
@@ -5125,20 +5217,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) {
@@ -5171,6 +5263,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;
@@ -5379,10 +5472,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);
@@ -5543,8 +5635,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);
@@ -5561,13 +5651,37 @@ 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
+                       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:
@@ -5636,7 +5750,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);
@@ -5725,7 +5839,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;
                        }
 
@@ -5770,10 +5884,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;
@@ -5795,14 +5905,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) ||
@@ -5853,8 +5958,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;
@@ -5863,11 +5966,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);
                                }
 
@@ -5917,9 +6019,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];
@@ -5957,7 +6056,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;
                                }
 
@@ -6172,16 +6271,16 @@ 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);
 #else
                                GENERIC_SHARING_FAILURE (*ip);                          
 #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))
@@ -6194,7 +6293,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;
@@ -6402,10 +6507,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);
@@ -6595,6 +6702,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                        ins->sreg2 = sp [1]->dreg;
                        type_from_op (ins, sp [0], sp [1]);
                        CHECK_TYPE (ins);
+                       ADD_WIDEN_OP (ins, sp [0], sp [1]);
                        ins->dreg = alloc_dreg ((cfg), (ins)->type);
 
                        /* FIXME: Pass opcode to is_inst_imm */
@@ -6953,8 +7061,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);
@@ -6963,7 +7074,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;
                                
@@ -7003,10 +7114,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);
@@ -7037,7 +7145,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 ||
@@ -7053,15 +7161,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
@@ -7128,7 +7235,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);
@@ -7138,11 +7245,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;
@@ -7169,6 +7289,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                ip += 5;
                        }
                        break;
+               }
                case CEE_UNBOX_ANY: {
                        MonoInst *rgctx = NULL;
 
@@ -7179,6 +7300,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);
 
@@ -7251,7 +7374,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                }
                case CEE_BOX: {
                        MonoInst *val;
-                       int context_used = 0;
 
                        CHECK_STACK (1);
                        --sp;
@@ -7261,12 +7383,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;
@@ -7300,6 +7420,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);
@@ -7313,21 +7438,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);
                        }
@@ -7346,6 +7466,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);
 
@@ -7427,7 +7549,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;
@@ -7463,7 +7585,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 {
@@ -7472,8 +7594,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];
-                                       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;
@@ -7590,7 +7715,7 @@ 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);
 #else
@@ -7625,10 +7750,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);
@@ -7759,9 +7881,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;
@@ -7788,7 +7907,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;
@@ -7799,33 +7917,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 */
@@ -7847,6 +7955,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);
                                }
                        }
 
@@ -7873,7 +7984,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;
                        }
 
@@ -8013,7 +8124,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;
@@ -8046,12 +8157,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);
@@ -8064,25 +8176,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;
@@ -8090,7 +8206,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);
@@ -8100,17 +8215,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);
@@ -8135,7 +8254,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);
 
@@ -8212,7 +8330,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);
                                                ins = emit_get_rgctx_klass (cfg, context_used, rgctx, tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
                                        } else if (cfg->compile_aot) {
@@ -8237,8 +8354,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,
@@ -8422,33 +8537,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 ()) {
@@ -8465,6 +8569,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;
 
@@ -8550,7 +8675,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)
@@ -8691,7 +8822,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);
@@ -8700,14 +8831,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;
@@ -8725,7 +8864,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;
@@ -8740,10 +8881,19 @@ 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
@@ -8765,8 +8915,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))
@@ -8778,8 +8928,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++;
@@ -8959,10 +9118,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;
@@ -9385,9 +9544,12 @@ mono_load_membase_to_load_mem (int opcode)
 }
 
 static inline int
-op_to_op_dest_membase (int opcode)
+op_to_op_dest_membase (int store_opcode, int opcode)
 {
 #if defined(__i386__)
+       if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
+               return -1;
+
        switch (opcode) {
        case OP_IADD:
                return OP_X86_ADD_MEMBASE_REG;
@@ -9420,6 +9582,9 @@ op_to_op_dest_membase (int opcode)
 #endif
 
 #if defined(__x86_64__)
+       if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
+               return -1;
+
        switch (opcode) {
        case OP_IADD:
                return OP_X86_ADD_MEMBASE_REG;
@@ -9628,7 +9793,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:
@@ -9711,14 +9876,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
 
@@ -10035,9 +10200,11 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                MonoInst *store_ins;
                                int store_opcode;
 
+                               store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
+
                                if (var->opcode == OP_REGVAR) {
                                        ins->dreg = var->dreg;
-                               } else if ((ins->dreg == ins->sreg1) && (spec [MONO_INST_DEST] == 'i') && (spec [MONO_INST_SRC1] == 'i') && !vreg_to_lvreg [ins->dreg] && (op_to_op_dest_membase (ins->opcode) != -1)) {
+                               } else if ((ins->dreg == ins->sreg1) && (spec [MONO_INST_DEST] == 'i') && (spec [MONO_INST_SRC1] == 'i') && !vreg_to_lvreg [ins->dreg] && (op_to_op_dest_membase (store_opcode, ins->opcode) != -1)) {
                                        /* 
                                         * Instead of emitting a load+store, use a _membase opcode.
                                         */
@@ -10045,7 +10212,7 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        if (ins->opcode == OP_MOVE) {
                                                NULLIFY_INS (ins);
                                        } else {
-                                               ins->opcode = op_to_op_dest_membase (ins->opcode);
+                                               ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
                                                ins->inst_basereg = var->inst_basereg;
                                                ins->inst_offset = var->inst_offset;
                                                ins->dreg = -1;
@@ -10053,7 +10220,6 @@ mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
                                        spec = INS_INFO (ins->opcode);
                                } else {
                                        guint32 lvreg;
-                                       store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
 
                                        g_assert (var->opcode == OP_REGOFFSET);