diff --git a/src/mono/mono/mini/cpu-arm64.mdesc b/src/mono/mono/mini/cpu-arm64.mdesc index 1b075a0926dcc..3981c54434778 100644 --- a/src/mono/mono/mini/cpu-arm64.mdesc +++ b/src/mono/mono/mini/cpu-arm64.mdesc @@ -523,5 +523,6 @@ expand_r8: dest:x src1:f len:4 generic_class_init: src1:a len:44 clob:c gc_safe_point: src1:i len:12 clob:c +init_mrgctx: src1:a src2:i len:44 clob:c fill_prof_call_ctx: src1:i len:128 diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index caf7e1b28d32a..503935feac2eb 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -6762,7 +6762,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_PCONST (cfg, args [1], info); cfg->init_method_rgctx_ins_arg = args [1]; - cfg->init_method_rgctx_ins = mono_emit_jit_icall (cfg, mini_init_method_rgctx, args); + if (COMPILE_LLVM (cfg) || cfg->backend->have_init_mrgctx) { + MONO_INST_NEW (cfg, ins, OP_INIT_MRGCTX); + ins->sreg1 = args [0]->dreg; + ins->sreg2 = args [1]->dreg; + MONO_ADD_INS (cfg->cbb, ins); + cfg->init_method_rgctx_ins = ins; + } else { + cfg->init_method_rgctx_ins = mono_emit_jit_icall (cfg, mini_init_method_rgctx, args); + } } if (cfg->gsharedvt && cfg->method == method) { diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 96822e9b9b4fa..dcdbafa631dd4 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -5023,6 +5023,27 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_arm_patch (jump, code, MONO_R_ARM64_CBZ); break; } + case OP_INIT_MRGCTX: { + int field_offset; + guint8 *jump; + + field_offset = MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, entries); + + /* Load mrgxtx->entries */ + arm_ldrx (code, ARMREG_IP0, sreg1, field_offset); + jump = code; + arm_cbnzx (code, ARMREG_IP0, 0); + + /* Slowpath */ + g_assert (sreg1 == ARMREG_R0); + if (sreg2 != ARMREG_R1) + arm_movx (code, ARMREG_R1, sreg2); + code = emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID, + GUINT_TO_POINTER (MONO_JIT_ICALL_mini_init_method_rgctx)); + + mono_arm_patch (jump, code, MONO_R_ARM64_CBZ); + break; + } case OP_CHECK_THIS: arm_ldrb (code, ARMREG_LR, sreg1, 0); diff --git a/src/mono/mono/mini/mini-arm64.h b/src/mono/mono/mini/mini-arm64.h index 7dfe8eed08c06..7d8e24c3763df 100644 --- a/src/mono/mono/mini/mini-arm64.h +++ b/src/mono/mono/mini/mini-arm64.h @@ -179,6 +179,7 @@ typedef struct { #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1 #define MONO_ARCH_FLOAT32_SUPPORTED 1 #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP 1 +#define MONO_ARCH_HAVE_INIT_MRGCTX 1 #define MONO_ARCH_LLVM_TARGET_LAYOUT "e-i64:64-i128:128-n32:64-S128" #ifdef TARGET_OSX #define MONO_ARCH_FORCE_FLOAT32 1 diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 1d78c8dd81d82..93fde86ad77fe 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -7415,6 +7415,52 @@ MONO_RESTORE_WARNING break; } + case OP_INIT_MRGCTX: { + LLVMValueRef val, cmp, callee; + LLVMBasicBlockRef poll_bb, cont_bb; + LLVMValueRef args [2]; + static LLVMTypeRef icall_sig; + + g_assert (cfg->compile_aot); + + /* + * if (!((MonoMethodRuntimeGenericContext)->lhs)->entries) + * mini_init_method_rgctx (lhs, rhs); + */ + + LLVMValueRef offset = const_int32 (MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, entries)); + LLVMValueRef ptr = LLVMBuildAdd (builder, convert (ctx, lhs, IntPtrType ()), convert (ctx, offset, IntPtrType ()), ""); + + val = emit_load (builder, IntPtrType (), convert (ctx, ptr, pointer_type (IntPtrType ())), "", TRUE); + cmp = LLVMBuildICmp (builder, LLVMIntEQ, val, LLVMConstNull (LLVMTypeOf (val)), ""); + poll_bb = gen_bb (ctx, "POLL_BB"); + cont_bb = gen_bb (ctx, "CONT_BB"); + + args [0] = cmp; + args [1] = LLVMConstInt (LLVMInt1Type (), 0, FALSE); + cmp = call_intrins (ctx, INTRINS_EXPECT_I1, args, ""); + + mono_llvm_build_weighted_branch (builder, cmp, poll_bb, cont_bb, 1, 1000); + + ctx->builder = builder = create_builder (ctx); + LLVMPositionBuilderAtEnd (builder, poll_bb); + + if (!icall_sig) + icall_sig = LLVMFunctionType2 (LLVMVoidType (), IntPtrType (), IntPtrType (), FALSE); + + args [0] = convert (ctx, lhs, IntPtrType ()); + args [1] = convert (ctx, rhs, IntPtrType ()); + + callee = get_callee (ctx, icall_sig, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mini_init_method_rgctx)); + LLVMBuildCall2 (builder, icall_sig, callee, args, 2, ""); + LLVMBuildBr (builder, cont_bb); + + ctx->builder = builder = create_builder (ctx); + LLVMPositionBuilderAtEnd (builder, cont_bb); + ctx->bblocks [bb->block_num].end_bblock = cont_bb; + break; + } + /* * Overflow opcodes. */ diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 162711201ad14..ece6964839c5a 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -1307,6 +1307,13 @@ MINI_OP(OP_GC_SAFE_POINT, "gc_safe_point", NONE, IREG, NONE) */ MINI_OP(OP_GENERIC_CLASS_INIT, "generic_class_init", NONE, IREG, NONE) +/* + * Call mini_init_method_rgctx () if needed. + * sreg1 is a MonoMethodRuntimeGenericContext. + * sreg2 is a MonoGSharedMethodInfo. + */ +MINI_OP(OP_INIT_MRGCTX, "init_mrgctx", NONE, IREG, IREG) + /* Arch specific opcodes */ #if defined(TARGET_X86) || defined(TARGET_AMD64) MINI_OP(OP_X86_TEST_NULL, "x86_test_null", NONE, IREG, NONE) diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index f025de7f5ba59..7f4a675bdbc04 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -3018,6 +3018,9 @@ init_backend (MonoBackend *backend) #ifdef MONO_ARCH_FORCE_FLOAT32 backend->force_float32 = 1; #endif +#ifdef MONO_ARCH_HAVE_INIT_MRGCTX + backend->have_init_mrgctx = 1; +#endif } static gboolean diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 943242eadb494..b70d344340ec9 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -1246,6 +1246,7 @@ typedef struct { gboolean have_op_tailcall_membase : 1; gboolean have_op_tailcall_reg : 1; gboolean have_volatile_non_param_register : 1; + guint have_init_mrgctx : 1; guint gshared_supported : 1; guint ilp32 : 1; guint need_got_var : 1;