2008-08-29 Geoff Norton <gnorton@novell.com>
[mono.git] / mono / mini / method-to-ir.c
index 651b3f1b55b420282d450688976b388efab9cc20..b9380b61f7aeab2fea976492343cf1b3f51254f5 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;    \
@@ -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);
@@ -2188,11 +2188,23 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
 
        mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
 #else
-       mono_arch_emit_imt_argument (cfg, call);
+       mono_arch_emit_imt_argument (cfg, call, imt_arg);
 #endif
 }
 #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,7 +2580,7 @@ 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);
        }
 }
 
@@ -2602,54 +2638,51 @@ emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
                (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 res;
+}
 
-       return mono_emit_native_call (cfg, tramp, sig, &rgc_ptr);
+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);
 }
 
 /**
@@ -2660,8 +2693,6 @@ 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 (context_used) {
                MonoInst *addr = emit_get_rgctx_method (cfg, context_used, rgctx, method,
@@ -2669,7 +2700,7 @@ handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int co
 
                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);
        }
 }
 
@@ -2743,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) {
@@ -2781,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;
@@ -2803,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);
@@ -2816,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*
@@ -3270,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)
 {
@@ -3517,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;
 }
@@ -3854,14 +3884,14 @@ 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;
 }
 
 static void
-mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
+mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
 {
        MonoInst *store, *temp;
        int i;
@@ -3878,8 +3908,9 @@ mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp, MonoI
                 * inline_method () if needed.
                 */
                temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
-               *args++ = temp;
-               EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
+               cfg->args [i] = temp;
+               /* This uses cfg->args [i] which is set by the preceeding line */
+               EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
                store->cil_code = sp [0]->cil_code;
                sp++;
        }
@@ -3889,50 +3920,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
 
@@ -4302,7 +4345,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;
@@ -4336,7 +4379,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*
@@ -4358,7 +4401,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
@@ -4964,6 +5007,13 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
        if (cfg->verbose_level > 2)
                printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
 
+       param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
+       if (sig->hasthis)
+               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;
+
        dont_inline = g_list_prepend (dont_inline, method);
        if (cfg->method == method) {
 
@@ -5081,8 +5131,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
        } else {
                arg_array = alloca (sizeof (MonoInst *) * num_args);
                cfg->cbb = start_bblock;
-               mono_save_args (cfg, sig, inline_args, arg_array);
                cfg->args = arg_array;
+               mono_save_args (cfg, sig, inline_args);
        }
 
        /* FIRST CODE BLOCK */
@@ -5168,7 +5218,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) */
@@ -5176,20 +5226,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) {
@@ -5217,12 +5267,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
        if (cfg->method == method)
                mono_debug_init_method (cfg, bblock, breakpoint_id);
 
-       param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
-       if (sig->hasthis)
-               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;
@@ -5431,10 +5475,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);
@@ -5595,8 +5638,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);
@@ -5613,13 +5654,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:
@@ -5688,7 +5757,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);
@@ -5822,10 +5891,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;
@@ -5847,14 +5912,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) ||
@@ -5905,8 +5965,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;
@@ -5915,11 +5973,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);
                                }
 
@@ -5969,9 +6026,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];
@@ -6009,7 +6063,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;
                                }
 
@@ -6119,8 +6173,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);
@@ -6224,16 +6279,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))
@@ -7014,8 +7070,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);
@@ -7024,7 +7083,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;
                                
@@ -7064,10 +7123,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);
@@ -7098,7 +7154,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 ||
@@ -7114,7 +7170,7 @@ 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);
                                }
                        }
 
@@ -7188,7 +7244,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);
@@ -7198,11 +7254,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;
@@ -7229,6 +7298,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                ip += 5;
                        }
                        break;
+               }
                case CEE_UNBOX_ANY: {
                        MonoInst *rgctx = NULL;
 
@@ -7239,6 +7309,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);
 
@@ -7247,7 +7319,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                if (context_used) {
                                        MonoInst *iargs [2];
 
-                                       g_assert (!method->klass->valuetype);
+                                       GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
 
                                        /* obj */
                                        iargs [0] = *sp;
@@ -7311,7 +7383,6 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                }
                case CEE_BOX: {
                        MonoInst *val;
-                       int context_used = 0;
 
                        CHECK_STACK (1);
                        --sp;
@@ -7321,12 +7392,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;
@@ -7378,21 +7447,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);
                        }
@@ -7411,6 +7475,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);
 
@@ -7492,7 +7558,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;
@@ -7528,7 +7594,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 {
@@ -7658,9 +7724,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
@@ -7693,10 +7760,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);
@@ -7827,9 +7891,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;
@@ -7933,7 +7994,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;
                        }
 
@@ -8073,7 +8134,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;
@@ -8106,12 +8167,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);
@@ -8124,25 +8186,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;
@@ -8150,7 +8216,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);
@@ -8160,17 +8225,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);
@@ -8195,7 +8264,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);
 
@@ -8272,16 +8340,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));
@@ -8297,8 +8358,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,
@@ -8482,33 +8541,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 ()) {
@@ -8525,6 +8573,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;
 
@@ -8767,6 +8836,8 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
+                               mono_save_token_info (cfg, image, n, cmethod);
+
                                if (cfg->generic_sharing_context)
                                        context_used = mono_method_check_context_used (cmethod);
 
@@ -8827,10 +8898,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                } 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;
@@ -8848,8 +8916,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))
@@ -8861,8 +8929,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++;
@@ -9042,10 +9119,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;
@@ -9069,8 +9146,10 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                                for (i = 0; i < header->num_clauses; ++i) {
                                        MonoExceptionClause *clause = &header->clauses [i];
-                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
+                                       if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
                                                handler_offset = clause->handler_offset;
+                                               break;
+                                       }
                                }
 
                                bblock->flags |= BB_EXCEPTION_UNSAFE;
@@ -9717,7 +9796,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: