[llvmonly] Fix initialization of static gshared methods, they receive a vtable as...
authorZoltan Varga <vargaz@gmail.com>
Thu, 14 Jan 2016 21:47:29 +0000 (16:47 -0500)
committerZoltan Varga <vargaz@gmail.com>
Thu, 14 Jan 2016 21:47:56 +0000 (16:47 -0500)
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/method-to-ir.c
mono/mini/mini-generic-sharing.c
mono/mini/mini-llvm.c
mono/mini/mini-runtime.c
mono/mini/mini.h
mono/mini/patch-info.h

index 1608dd78d697c927d132f85fb346f4842cd650ed..b1b0c5b1d8e4803bec401d6c7cfdce673f61bbba 100644 (file)
@@ -5422,6 +5422,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
        case MONO_PATCH_INFO_AOT_MODULE:
                break;
        case MONO_PATCH_INFO_SIGNATURE:
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
                encode_signature (acfg, (MonoMethodSignature*)patch_info->data.target, p, &p);
                break;
        case MONO_PATCH_INFO_TLS_OFFSET:
@@ -9854,7 +9855,8 @@ static void aot_dump (MonoAotCompile *acfg)
 static const char *preinited_jit_icalls[] = {
        "mono_aot_init_llvm_method",
        "mono_aot_init_gshared_method_this",
-       "mono_aot_init_gshared_method_rgctx",
+       "mono_aot_init_gshared_method_mrgctx",
+       "mono_aot_init_gshared_method_vtable",
        "mono_llvm_throw_corlib_exception",
        "mono_init_vtable_slot",
        "mono_helper_ldstr_mscorlib"
index 1388e8c75ff5ab0a86f3563452d1741c05ce7278..b84d1ea22bdd5e2976181fe981d28d4f225604a8 100644 (file)
@@ -3544,6 +3544,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
        case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
                break;
        case MONO_PATCH_INFO_SIGNATURE:
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
                ji->data.target = decode_signature (aot_module, p, &p);
                break;
        case MONO_PATCH_INFO_TLS_OFFSET:
@@ -4171,7 +4172,7 @@ mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, Mo
 }
 
 void
-mono_aot_init_gshared_method_rgctx  (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
+mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
 {
        MonoAotModule *amodule = (MonoAotModule *)aot_module;
        gboolean res;
@@ -4188,6 +4189,29 @@ mono_aot_init_gshared_method_rgctx  (gpointer aot_module, guint32 method_index,
        g_assert (res);
 }
 
+void
+mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable)
+{
+       MonoAotModule *amodule = (MonoAotModule *)aot_module;
+       gboolean res;
+       MonoClass *klass;
+       MonoGenericContext *context;
+       MonoMethod *method;
+
+       klass = vtable->klass;
+
+       amodule_lock (amodule);
+       method = (MonoMethod *)g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
+       amodule_unlock (amodule);
+
+       g_assert (method);
+       context = mono_method_get_context (method);
+       g_assert (context);
+
+       res = init_llvm_method (amodule, method_index, NULL, klass, context);
+       g_assert (res);
+}
+
 /*
  * mono_aot_get_method:
  *
@@ -5610,7 +5634,12 @@ mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, Mo
 }
 
 void
-mono_aot_init_gshared_method_rgctx  (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
+mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx)
+{
+}
+
+void
+mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable)
 {
 }
 
index 13385f646949e6ffe0b66b99b3ed8bffe033c3d7..11eb251ebb3ea163f5c723da518b8aefe1e423e0 100644 (file)
@@ -12865,7 +12865,45 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                MONO_START_BB (cfg, end_bb);
                                        } else {
-                                               ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, addr);
+                                               /* Caller uses a normal calling conv */
+
+                                               MonoInst *callee = addr;
+                                               MonoInst *call, *localloc_ins;
+                                               MonoBasicBlock *is_gsharedvt_bb, *end_bb;
+                                               int low_bit_reg = alloc_preg (cfg);
+
+                                               NEW_BBLOCK (cfg, is_gsharedvt_bb);
+                                               NEW_BBLOCK (cfg, end_bb);
+
+                                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
+                                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
+                                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
+
+                                               /* Normal case: callee uses a normal cconv, no conversion is needed */
+                                               call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
+                                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+                                               /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
+                                               MONO_START_BB (cfg, is_gsharedvt_bb);
+                                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
+                                               NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
+                                               MONO_ADD_INS (cfg->cbb, addr);
+                                               /*
+                                                * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
+                                                */
+                                               MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
+                                               ins->dreg = alloc_preg (cfg);
+                                               ins->inst_imm = 2 * SIZEOF_VOID_P;
+                                               MONO_ADD_INS (cfg->cbb, ins);
+                                               localloc_ins = ins;
+                                               cfg->flags |= MONO_CFG_HAS_ALLOCA;
+                                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
+                                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
+
+                                               ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
+                                               ins->dreg = call->dreg;
+                                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+
+                                               MONO_START_BB (cfg, end_bb);
                                        }
                                } else {
                                        /* Same as CEE_CALLI */
index 2e88f8352324d0e0ed00042e78179581869f34b9..7317873e1b460ef84d13546fb0f84894b545f53b 100644 (file)
@@ -643,6 +643,7 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co
 
                return &inflated_class->fields [i];
        }
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
        case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
                MonoMethodSignature *sig = (MonoMethodSignature *)data;
                MonoMethodSignature *isig;
@@ -1641,6 +1642,17 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
 
                return method->context.method_inst;
        }
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: {
+               MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
+               MonoMethodSignature *sig = (MonoMethodSignature *)data;
+               gpointer addr;
+
+               /*
+                * This is an indirect call to the address passed by the caller in the rgctx reg.
+                */
+               addr = mini_get_gsharedvt_wrapper (TRUE, NULL, sig, gsig, -1, TRUE);
+               return addr;
+       }
        case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: {
                MonoMethodSignature *gsig = (MonoMethodSignature *)oti->data;
                MonoMethodSignature *sig = (MonoMethodSignature *)data;
@@ -1905,6 +1917,7 @@ mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
        case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
        case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
        case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI";
        case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: return "SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI";
        case MONO_RGCTX_INFO_MEMCPY: return "MEMCPY";
        case MONO_RGCTX_INFO_BZERO: return "BZERO";
@@ -2006,6 +2019,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
        case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
        case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
        case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
+       case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
        case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
                return data1 == data2;
        case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
index baa562449d6c62d8e114a72f101d1280ab0ca91d..82b391a089174304e0f6d33b4e80ef70c8c30d8a 100644 (file)
@@ -78,7 +78,7 @@ typedef struct {
        const char *jit_got_symbol;
        const char *eh_frame_symbol;
        LLVMValueRef get_method, get_unbox_tramp;
-       LLVMValueRef init_method, init_method_gshared_rgctx, init_method_gshared_this;
+       LLVMValueRef init_method, init_method_gshared_mrgctx, init_method_gshared_this, init_method_gshared_vtable;
        LLVMValueRef code_start, code_end;
        LLVMValueRef inited_var;
        int max_inited_idx, max_method_idx;
@@ -2408,7 +2408,6 @@ emit_get_unbox_tramp (MonoLLVMModule *module)
        func = LLVMAddFunction (lmodule, module->get_unbox_tramp_symbol, LLVMFunctionType1 (rtype, LLVMInt32Type (), FALSE));
        LLVMSetLinkage (func, LLVMExternalLinkage);
        LLVMSetVisibility (func, LLVMHiddenVisibility);
-       LLVMAddFunctionAttr (func, LLVMNoUnwindAttribute);
        module->get_unbox_tramp = func;
 
        entry_bb = LLVMAppendBasicBlock (func, "ENTRY");
@@ -2486,6 +2485,8 @@ emit_init_icall_wrapper (MonoLLVMModule *module, const char *name, const char *i
                sig = LLVMFunctionType2 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), FALSE);
                break;
        case 1:
+       case 3:
+               /* mrgctx/vtable */
                func = LLVMAddFunction (lmodule, name, LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), IntPtrType (), FALSE));
                sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE);
                break;
@@ -2550,8 +2551,9 @@ static void
 emit_init_icall_wrappers (MonoLLVMModule *module)
 {
        module->init_method = emit_init_icall_wrapper (module, "init_method", "mono_aot_init_llvm_method", 0);
-       module->init_method_gshared_rgctx = emit_init_icall_wrapper (module, "init_method_gshared_rgctx", "mono_aot_init_gshared_method_rgctx", 1);
+       module->init_method_gshared_mrgctx = emit_init_icall_wrapper (module, "init_method_gshared_mrgctx", "mono_aot_init_gshared_method_mrgctx", 1);
        module->init_method_gshared_this = emit_init_icall_wrapper (module, "init_method_gshared_this", "mono_aot_init_gshared_method_this", 2);
+       module->init_method_gshared_vtable = emit_init_icall_wrapper (module, "init_method_gshared_vtable", "mono_aot_init_gshared_method_vtable", 3);
 }
 
 static void
@@ -2666,10 +2668,16 @@ emit_init_method (EmitContext *ctx)
        LLVMPositionBuilderAtEnd (ctx->builder, notinited_bb);
 
        // FIXME: Cache
-       if (ctx->rgctx_arg) {
+       if (ctx->rgctx_arg && cfg->method->is_inflated && mono_method_get_context (cfg->method)->method_inst) {
+               args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
+               args [1] = convert (ctx, ctx->rgctx_arg, IntPtrType ());
+               callee = ctx->module->init_method_gshared_mrgctx;
+               call = LLVMBuildCall (builder, callee, args, 2, "");
+       } else if (ctx->rgctx_arg) {
+               /* A vtable is passed as the rgctx argument */
                args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
                args [1] = convert (ctx, ctx->rgctx_arg, IntPtrType ());
-               callee = ctx->module->init_method_gshared_rgctx;
+               callee = ctx->module->init_method_gshared_vtable;
                call = LLVMBuildCall (builder, callee, args, 2, "");
        } else if (cfg->gshared) {
                args [0] = LLVMConstInt (LLVMInt32Type (), cfg->method_index, 0);
index 886d6d0540f770c825360849db44e59d928f58c2..2886c059be11f838a01e2edec959662332aa59e7 100644 (file)
@@ -1262,6 +1262,8 @@ mono_patch_info_hash (gconstpointer data)
        }
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
                return (ji->type << 8) | g_str_hash (ji->data.target);
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               return (ji->type << 8) | mono_signature_hash (ji->data.sig);
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@ -1326,6 +1328,8 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                if (ji1->data.target == ji2->data.target)
                        return 1;
                return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 0 : 1;
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -1698,6 +1702,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
                break;
        }
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -3857,7 +3864,8 @@ register_icalls (void)
 
        register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
        register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
-       register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
+       register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
+       register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
 
        register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
        register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
index f28b32eaf6ce24076704bab95df50cdec19288dd..976e7fec25fdc4c48a19701adada6b60f120e0f9 100644 (file)
 #endif
 
 /* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 130
+#define MONO_AOT_FILE_VERSION 131
 
 //TODO: This is x86/amd64 specific.
 #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
@@ -1220,6 +1220,7 @@ typedef enum {
        MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT,
        /* Same for calli, associated with a signature */
        MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI,
+       MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI,
        /* One of MONO_GSHAREDVT_BOX_TYPE */
        MONO_RGCTX_INFO_CLASS_BOX_TYPE,
        /* Resolves to a MonoGSharedVtMethodRuntimeInfo */
@@ -2451,7 +2452,8 @@ void     mono_aot_register_jit_icall        (const char *name, gpointer addr);
 guint32  mono_aot_find_method_index         (MonoMethod *method);
 void     mono_aot_init_llvm_method          (gpointer aot_module, guint32 method_index);
 void     mono_aot_init_gshared_method_this  (gpointer aot_module, guint32 method_index, MonoObject *this_ins);
-void     mono_aot_init_gshared_method_rgctx  (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx);
+void     mono_aot_init_gshared_method_mrgctx  (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx);
+void     mono_aot_init_gshared_method_vtable  (gpointer aot_module, guint32 method_index, MonoVTable *vtable);
 
 /* This is an exported function */
 MONO_API void     mono_aot_register_module           (gpointer *aot_info);
index c9b9885e18ba3906b59224c477e92b7c81289047..a29cdafe8002eba9a9b33d34b86a6039d1c253cb 100644 (file)
@@ -58,3 +58,4 @@ PATCH_INFO(NONE, "none")
 PATCH_INFO(AOT_MODULE, "aot_module")
 PATCH_INFO(AOT_JIT_INFO, "aot_jit_info")
 PATCH_INFO(GC_NURSERY_BITS, "gc_nursery_bits")
+PATCH_INFO(GSHAREDVT_IN_WRAPPER, "gsharedvt_in_wrapper")