2008-08-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / method-to-ir.c
index a3b98ec1f03369de16ec769a65a0eda0701616c4..b9586d3b99b661e63080e5716c525245b86ddc00 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;    \
@@ -2193,6 +2193,18 @@ emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
 }
 #endif
 
+static MonoJumpInfo *
+mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
+{
+       MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+
+       ji->ip.i = ip;
+       ji->type = type;
+       ji->data.target = target;
+
+       return ji;
+}
+
 inline static MonoInst*
 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
 
@@ -2306,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;
@@ -2316,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;
@@ -2431,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*
@@ -2463,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)
 {
@@ -2507,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);
        }
 }
 
@@ -2544,7 +2579,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 +2637,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 mono_emit_native_call (cfg, tramp, sig, &rgc_ptr);
+       return res;
+}
+
+static inline MonoInst*
+emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
+{
+       return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
 }
 
 static MonoInst*
 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
                                          MonoInst *rgctx, MonoClass *klass, int rgctx_type)
 {
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, cfg->generic_context);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_CLASS, klass, rgctx_type);
 
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 static MonoInst*
 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
                                           MonoInst *rgctx, MonoMethod *cmethod, int rgctx_type)
 {
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, cfg->generic_context);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);
 
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 static MonoInst*
 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
                                          MonoInst *rgctx, MonoClassField *field, int rgctx_type)
 {
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, cfg->generic_context);
+       MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_FIELD, field, rgctx_type);
 
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
-}
-
-static MonoInst*
-emit_get_rgctx_method_rgctx (MonoCompile *cfg, int context_used,
-                                                        MonoInst *rgctx, MonoMethod *rgctx_method)
-{
-       guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
-               context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
-               MONO_RGCTX_INFO_METHOD_RGCTX, cfg->generic_context);
-
-       return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
+       return emit_rgctx_fetch (cfg, rgctx, entry);
 }
 
 /**
@@ -2667,7 +2699,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);
        }
 }
 
@@ -2741,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) {
@@ -2779,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;
@@ -2801,7 +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);
-               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);
@@ -2812,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*
@@ -3511,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;
 }
@@ -3848,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;
@@ -4308,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;
@@ -4342,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*
@@ -4364,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
@@ -5174,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) */
@@ -5182,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) {
@@ -5437,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);
@@ -5601,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);
@@ -5619,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:
@@ -5828,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;
@@ -5853,7 +5905,7 @@ 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 {
                                        EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
                                }
@@ -5906,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;
@@ -5916,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);
                                }
 
@@ -5970,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];
@@ -6225,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))
@@ -7015,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);
@@ -7025,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;
                                
@@ -7065,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);
@@ -7099,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 ||
@@ -7115,7 +7161,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);
                                }
                        }
 
@@ -7189,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);
@@ -7199,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;
@@ -7230,6 +7289,7 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
                                ip += 5;
                        }
                        break;
+               }
                case CEE_UNBOX_ANY: {
                        MonoInst *rgctx = NULL;
 
@@ -7314,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;
@@ -7326,13 +7385,9 @@ mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_
 
                        mono_save_token_info (cfg, image, token, klass);
 
-                       if (cfg->generic_sharing_context) {
+                       if (cfg->generic_sharing_context)
                                context_used = mono_class_check_context_used (klass);
 
-                               if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
-                                       GENERIC_SHARING_FAILURE (*ip);
-                       }
-
                        if (generic_class_is_reference_type (cfg, klass)) {
                                *sp++ = val;
                                ip += 5;
@@ -7383,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);
                        }
@@ -7499,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;
@@ -7535,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 {
@@ -7665,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
@@ -7700,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);
@@ -7834,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;
@@ -7940,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;
                        }
 
@@ -8080,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;
@@ -8113,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);
@@ -8131,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;
@@ -8157,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);
@@ -8167,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);
@@ -8202,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);
 
@@ -8279,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) {
@@ -8304,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,
@@ -8784,6 +8832,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);
 
@@ -8865,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))
@@ -8878,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++;
@@ -9059,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;