From f796170947881b43f2f842b1be812de7497b10c7 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Mon, 27 Mar 2023 22:58:20 -0400 Subject: [PATCH] [mono][jit] Add an option to use an mrgctx for all gshared methods. Enable it by default on WASM. In this mode, all gshared methods get an mrgctx, which means they can access their data using a simple load from the mrgctx instead of having to call a rgctx fetch trampoline. Upsides: - much simpler. - faster access to gshared data - smaller code and data size in the AOT case - if enabled by default on all platforms, large amount of gshared code can be removed Downsides: - the methods have to initialize their mrgctx in their prolog - on non-wasm platforms, indirect calls to gshared methods (like virtual calls) will need to use rgctx trampolines more often to pass the mrgctx. --- src/mono/mono/mini/aot-compiler.c | 3 ++- src/mono/mono/mini/method-to-ir.c | 8 ++++++-- src/mono/mono/mini/mini-arm64.c | 8 ++++---- src/mono/mono/mini/mini-generic-sharing.c | 11 ++++++++++- src/mono/mono/mini/mini.c | 5 ++++- src/mono/mono/utils/options-def.h | 6 ++++++ 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 82b9698765a32b..20a90856b6a643 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -7248,7 +7248,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint case MONO_PATCH_INFO_DELEGATE_INFO: case MONO_PATCH_INFO_VIRT_METHOD: case MONO_PATCH_INFO_GSHAREDVT_METHOD: - case MONO_PATCH_INFO_GSHAREDVT_CALL: { + case MONO_PATCH_INFO_GSHAREDVT_CALL: + case MONO_PATCH_INFO_SIGNATURE: { tmp.type = patch_type; tmp.data.target = data; encode_patch (acfg, &tmp, p, &p); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 6578497e745008..8c222db5868c8d 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -2474,6 +2474,9 @@ mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass static gboolean context_used_is_mrgctx (MonoCompile *cfg, int context_used) { + if (mono_opt_experimental_gshared_mrgctx) + return context_used != 0; + /* gshared dim methods use an mrgctx */ if (mini_method_is_default_method (cfg->method)) return context_used != 0; @@ -2598,6 +2601,7 @@ get_gshared_info_slot (MonoCompile *cfg, MonoJumpInfo *patch_info, MonoRgctxInfo case MONO_PATCH_INFO_DELEGATE_INFO: case MONO_PATCH_INFO_GSHAREDVT_METHOD: case MONO_PATCH_INFO_GSHAREDVT_CALL: + case MONO_PATCH_INFO_SIGNATURE: data = (gpointer)patch_info->data.target; break; default: @@ -7972,7 +7976,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX); - if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod))) { + if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) && !delegate_invoke) { if (virtual_) check_this = TRUE; virtual_ = FALSE; @@ -8392,7 +8396,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b g_assert (!called_is_supported_tailcall || !tailcall || tailcall_cmethod == cmethod); g_assert (!called_is_supported_tailcall || tailcall_fsig == fsig); g_assert (!called_is_supported_tailcall || tailcall_virtual == virtual_); - g_assert (!called_is_supported_tailcall || tailcall_extra_arg == (vtable_arg || imt_arg || will_have_imt_arg || mono_class_is_interface (cmethod->klass))); + //g_assert (!called_is_supported_tailcall || tailcall_extra_arg == (vtable_arg || imt_arg || will_have_imt_arg || mono_class_is_interface (cmethod->klass))); if (common_call) // FIXME goto call_end && !common_call often skips tailcall processing. ins = mini_emit_method_call_full (cfg, cmethod, fsig, tailcall, sp, virtual_ ? sp [0] : NULL, diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index e9e9ff6b0edcbe..63f287a0e3e43c 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1064,7 +1064,7 @@ emit_thunk (guint8 *code, gconstpointer target) } static gpointer -create_thunk (MonoCompile *cfg, guchar *code, const guchar *target) +create_thunk (MonoCompile *cfg, guchar *code, const guchar *target, int relocation) { MonoJitInfo *ji; MonoThunkJitInfo *info; @@ -1136,7 +1136,7 @@ create_thunk (MonoCompile *cfg, guchar *code, const guchar *target) if (!target_thunk) { jit_mm_unlock (jit_mm); - g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, cfg ? mono_method_full_name (cfg->method, TRUE) : mono_method_full_name (jinfo_get_method (ji), TRUE)); + g_print ("thunk failed %p->%p, thunk space=%d method %s, relocation %d", code, target, thunks_size, cfg ? mono_method_full_name (cfg->method, TRUE) : mono_method_full_name (jinfo_get_method (ji), TRUE), relocation); g_assert_not_reached (); } @@ -1159,7 +1159,7 @@ arm_patch_full (MonoCompile *cfg, guint8 *code, guint8 *target, int relocation) } else { gpointer thunk; - thunk = create_thunk (cfg, code, target); + thunk = create_thunk (cfg, code, target, relocation); g_assert (arm_is_bl_disp (code, thunk)); arm_b (code, thunk); } @@ -1193,7 +1193,7 @@ arm_patch_full (MonoCompile *cfg, guint8 *code, guint8 *target, int relocation) } else { gpointer thunk; - thunk = create_thunk (cfg, code, target); + thunk = create_thunk (cfg, code, target, relocation); g_assert (arm_is_bl_disp (code, thunk)); arm_bl (code, thunk); } diff --git a/src/mono/mono/mini/mini-generic-sharing.c b/src/mono/mono/mini/mini-generic-sharing.c index 54ea2a8e147d8b..cfb7d4358c8ca3 100644 --- a/src/mono/mono/mini/mini-generic-sharing.c +++ b/src/mono/mono/mini/mini-generic-sharing.c @@ -2956,6 +2956,8 @@ mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type) case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return MONO_PATCH_INFO_GSHAREDVT_CALL; + case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI: + return MONO_PATCH_INFO_SIGNATURE; default: printf ("%d\n", info_type); g_assert_not_reached (); @@ -3726,6 +3728,9 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v if (!mono_method_is_generic_sharable (method, allow_type_vars)) return FALSE; + if (mono_opt_experimental_gshared_mrgctx) + return method->is_inflated; + if (method->is_inflated && mono_method_get_context (method)->method_inst) return TRUE; @@ -4081,7 +4086,11 @@ mini_method_needs_mrgctx (MonoMethod *m) return TRUE; if (m->flags & METHOD_ATTRIBUTE_STATIC || m_class_is_valuetype (m->klass)) return TRUE; - return (mini_method_get_context (m) && mini_method_get_context (m)->method_inst); + + if (mono_opt_experimental_gshared_mrgctx) + return mini_method_get_context (m) != NULL; + else + return (mini_method_get_context (m) && mini_method_get_context (m)->method_inst); } /* diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index 497ed8365eca6c..89f6ebdb46701d 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -3051,7 +3051,10 @@ mini_get_rgctx_access_for_method (MonoMethod *method) if (method->flags & METHOD_ATTRIBUTE_STATIC || m_class_is_valuetype (method->klass)) return MONO_RGCTX_ACCESS_MRGCTX; - return MONO_RGCTX_ACCESS_THIS; + if (mono_opt_experimental_gshared_mrgctx) + return MONO_RGCTX_ACCESS_MRGCTX; + else + return MONO_RGCTX_ACCESS_THIS; } /* diff --git a/src/mono/mono/utils/options-def.h b/src/mono/mono/utils/options-def.h index 1c892f18e86388..14b971b9e2f67e 100644 --- a/src/mono/mono/utils/options-def.h +++ b/src/mono/mono/utils/options-def.h @@ -145,6 +145,12 @@ DEFINE_INT(jiterpreter_interp_entry_queue_flush_threshold, "jiterpreter-interp-e DEFINE_INT(jiterpreter_wasm_bytes_limit, "jiterpreter-wasm-bytes-limit", 6 * 1024 * 1024, "Disable jiterpreter code generation once this many bytes of WASM have been generated") #endif // HOST_BROWSER +#ifdef HOST_WASM +DEFINE_BOOL_READONLY(experimental_gshared_mrgctx, "experimental-gshared-mrgctx", TRUE, "Use a mrgctx for all gshared methods") +#else +DEFINE_BOOL(experimental_gshared_mrgctx, "experimental-gshared-mrgctx", FALSE, "Use a mrgctx for all gshared methods") +#endif + /* Cleanup */ #undef DEFINE_OPTION_FULL #undef DEFINE_OPTION_READONLY