[jit] Allow the inlining of generic class init trampolines on some platforms. Enable...
authorZoltan Varga <vargaz@gmail.com>
Sat, 16 May 2015 06:49:01 +0000 (08:49 +0200)
committerZoltan Varga <vargaz@gmail.com>
Sat, 16 May 2015 06:49:01 +0000 (08:49 +0200)
mono/mini/cpu-amd64.md
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-amd64.h
mono/mini/mini-llvm.c
mono/mini/mini-ops.h
mono/mini/mini-runtime.c
mono/mini/tramp-amd64.c

index 4fd06a36d5d885e889b9db7e624dfb4f25b1bb65..7e6133abf42d5b4d40673cdcac36d24c2148e82e 100755 (executable)
@@ -796,3 +796,4 @@ gc_liveness_use: len:0
 gc_spill_slot_liveness_def: len:0
 gc_param_slot_liveness_def: len:0
 
+generic_class_init: src1:i len:32
index 1cd57572bb1ba8ffb493f17f1c8ba62ee43a5f13..eaa569450e5dc619016ebba223dbc3ffcb5521ff 100644 (file)
@@ -3642,12 +3642,24 @@ emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
                EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
        }
 
+#ifdef MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT
+       MonoInst *ins;
+
+       /*
+        * For LLVM, this requires that the code in the generic trampoline obtain the vtable argument according to
+        * the normal calling convention of the platform.
+        */
+       MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
+       ins->sreg1 = vtable_arg->dreg;
+       MONO_ADD_INS (cfg->cbb, ins);
+#else
        if (COMPILE_LLVM (cfg))
                call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
        else
                call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
        mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
        cfg->uses_vtable_reg = TRUE;
+#endif
 }
 
 static void
index 6dec1e35442eac4276b04a8817929fe6a3151448..958e19e9293a0233d39f1721ae5021ef096c518c 100644 (file)
@@ -4831,6 +4831,28 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        amd64_pop_reg (code, AMD64_RDI);
                        break;
                }
+               case OP_GENERIC_CLASS_INIT: {
+                       static int byte_offset = -1;
+                       static guint8 bitmask;
+                       guint8 *jump;
+
+                       if (byte_offset < 0)
+                               mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
+
+                       amd64_test_membase_imm_size (code, ins->sreg1, byte_offset, bitmask, 1);
+                       jump = code;
+                       amd64_branch8 (code, X86_CC_NZ, -1, 1);
+
+                       if (ins->sreg1 != MONO_AMD64_ARG_REG1)
+                               amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, ins->sreg1, 8);
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_generic_class_init", FALSE);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
+
+                       x86_patch (jump, code);
+                       break;
+               }
+
                case OP_X86_LEA:
                        amd64_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
                        break;
index 32c4654ffb1b7ccd78cb760377d3447367554bb2..1859db4a35324db1de6e2a5c57bb35eaba648285 100644 (file)
@@ -355,6 +355,7 @@ typedef struct {
 #define MONO_ARCH_HAVE_DUMMY_INIT 1
 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1
 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
+#define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
 
 #if defined(TARGET_OSX) || defined(__linux__)
 #define MONO_ARCH_HAVE_TLS_GET_REG 1
index d3baa203e55f29656aa9a0cc12e2eca3b669fdb6..a5784392cfb3e15dd1584daf103d7d059aabe9ed 100644 (file)
@@ -46,6 +46,7 @@ void bzero (void *to, size_t count) { memset (to, 0, count); }
 typedef struct {
        LLVMModuleRef module;
        LLVMValueRef throw, rethrow, throw_corlib_exception;
+       LLVMValueRef generic_class_init_tramp;
        GHashTable *llvm_types;
        LLVMValueRef got_var;
        const char *got_symbol;
@@ -3679,6 +3680,54 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        CHECK_FAILURE (ctx);
                        break;
                }
+               case OP_GENERIC_CLASS_INIT: {
+                       static int byte_offset = -1;
+                       static guint8 bitmask;
+                       LLVMValueRef flags_load, cmp;
+                       MonoMethodSignature *sig;
+                       const char *icall_name;
+                       LLVMValueRef callee;
+                       LLVMBasicBlockRef init_bb, noinit_bb;
+
+                       if (byte_offset < 0)
+                               mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
+
+                       flags_load = emit_load (ctx, bb, &builder, 1, convert (ctx, lhs, LLVMPointerType (LLVMInt8Type(), 0)), "", FALSE);
+                       set_metadata_flag (flags_load, "mono.nofail.load");
+                       cmp = LLVMBuildICmp (builder, LLVMIntEQ, LLVMBuildAnd (builder, flags_load, LLVMConstInt (LLVMInt8Type (), bitmask, 0), ""), LLVMConstInt (LLVMInt1Type (), 1, FALSE), "");
+
+                       callee = ctx->lmodule->generic_class_init_tramp;
+                       if (!callee) {
+                               icall_name = "specific_trampoline_generic_class_init";
+                               sig = mono_metadata_signature_alloc (mono_get_corlib (), 1);
+                               sig->ret = &mono_get_void_class ()->byval_arg;
+                               sig->params [0] = &mono_get_int64_class ()->byval_arg;
+                               if (cfg->compile_aot) {
+                                       callee = get_plt_entry (ctx, sig_to_llvm_sig (ctx, sig), MONO_PATCH_INFO_INTERNAL_METHOD, icall_name);
+                               } else {
+                                       callee = LLVMAddFunction (module, icall_name, sig_to_llvm_sig (ctx, sig));
+                                       LLVMAddGlobalMapping (ctx->lmodule->ee, callee, resolve_patch (cfg, MONO_PATCH_INFO_INTERNAL_METHOD, icall_name));
+                               }
+                               mono_memory_barrier ();
+                               ctx->lmodule->generic_class_init_tramp = callee;
+                       }
+
+                       init_bb = gen_bb (ctx, "INIT_BB");
+                       noinit_bb = gen_bb (ctx, "NOINIT_BB");
+
+                       LLVMBuildCondBr (ctx->builder, cmp, noinit_bb, init_bb);
+
+                       builder = create_builder (ctx);
+                       ctx->builder = builder;
+                       LLVMPositionBuilderAtEnd (builder, init_bb);
+                       emit_call (ctx, bb, &builder, callee, &lhs, 1);
+                       LLVMBuildBr (builder, noinit_bb);
+
+                       builder = create_builder (ctx);
+                       ctx->builder = builder;
+                       LLVMPositionBuilderAtEnd (builder, noinit_bb);
+                       break;
+               }
                case OP_AOTCONST: {
                        guint32 got_offset;
                        LLVMValueRef indexes [2];
index 2484e6cc9beb0d5c7a66be0e9058631963609a4c..b2a08666096f48f91f8b6b5fa65898484be9caaa 100644 (file)
@@ -1067,6 +1067,14 @@ MINI_OP(OP_GC_SPILL_SLOT_LIVENESS_DEF, "gc_spill_slot_liveness_def", NONE, NONE,
  */
 MINI_OP(OP_GC_PARAM_SLOT_LIVENESS_DEF, "gc_param_slot_liveness_def", NONE, NONE, NONE)
 
+/*
+ * Check if the class given by sreg1 was inited, if not, call
+ * mono_generic_class_init_trampoline () though a trampoline.
+ * Since the trampoline saves all registers, this doesn't clobber
+ * any registers.
+ */
+MINI_OP(OP_GENERIC_CLASS_INIT, "generic_class_init", NONE, IREG, NONE)
+
 /* Arch specific opcodes */
 /* #if defined(__native_client_codegen__) || defined(__native_client__) */
 /* We have to define these in terms of the TARGET defines, not NaCl defines */
index 5ad8ef1f6678d43a3e9d703866771b5e2fa4dae4..4d6068600225ed15885e73b873676b22bb5e6128 100644 (file)
@@ -3416,6 +3416,8 @@ register_icalls (void)
        register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
 
        register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
+       register_icall (mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, mono_get_root_domain (), NULL),
+                                       "specific_trampoline_generic_class_init", "void", TRUE);
 
 #ifdef TARGET_IOS
        register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
index 22e66acb8029dbc845557ba325f56046a4d40d3e..05b7ce856d75973959eb5dbce6b5f1201ebe242a 100644 (file)
@@ -902,39 +902,17 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info
 gpointer
 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot)
 {
-       guint8 *tramp;
        guint8 *code, *buf;
-       static int byte_offset = -1;
-       static guint8 bitmask;
-       guint8 *jump;
        int tramp_size;
        GSList *unwind_ops = NULL;
        MonoJumpInfo *ji = NULL;
 
-       tramp_size = 64;
+       tramp_size = 16;
 
        code = buf = mono_global_codeman_reserve (tramp_size);
 
-       if (byte_offset < 0)
-               mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
-
-       amd64_test_membase_imm_size (code, MONO_AMD64_ARG_REG1, byte_offset, bitmask, 1);
-       jump = code;
-       amd64_branch8 (code, X86_CC_Z, -1, 1);
-
-       amd64_ret (code);
-
-       x86_patch (jump, code);
-
-       if (aot) {
-               code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_generic_class_init");
-               amd64_jump_reg (code, AMD64_R11);
-       } else {
-               tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, mono_get_root_domain (), NULL);
-
-               /* jump to the actual trampoline */
-               amd64_jump_code (code, tramp);
-       }
+       /* Not used on amd64 */
+       amd64_breakpoint (code);
 
        nacl_global_codeman_validate (&buf, tramp_size, &code);