From: Zoltan Varga Date: Sat, 16 May 2015 06:49:01 +0000 (+0200) Subject: [jit] Allow the inlining of generic class init trampolines on some platforms. Enable... X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=0a8467536f1913e5c07c1409d3b6d3690cc596b5;p=mono.git [jit] Allow the inlining of generic class init trampolines on some platforms. Enable it for amd64. --- diff --git a/mono/mini/cpu-amd64.md b/mono/mini/cpu-amd64.md index 4fd06a36d5d..7e6133abf42 100755 --- a/mono/mini/cpu-amd64.md +++ b/mono/mini/cpu-amd64.md @@ -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 diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 1cd57572bb1..eaa569450e5 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -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 diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index 6dec1e35442..958e19e9293 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -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; diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h index 32c4654ffb1..1859db4a353 100644 --- a/mono/mini/mini-amd64.h +++ b/mono/mini/mini-amd64.h @@ -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 diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index d3baa203e55..a5784392cfb 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -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]; diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h index 2484e6cc9be..b2a08666096 100644 --- a/mono/mini/mini-ops.h +++ b/mono/mini/mini-ops.h @@ -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 */ diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 5ad8ef1f667..4d606860022 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -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); diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c index 22e66acb802..05b7ce856d7 100644 --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -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);