From ca7b288837334c7d6b6eccb2f6799ab4696e7a89 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Mon, 19 Jun 2017 13:49:31 -0400 Subject: [PATCH] [jit] Treat the mono_threads_attach_coop () icall specially, since it can be called from native-to-managed wrappers on unattached threads, so calling it shouldn't go through the trampoline infrastructure. (#5056) --- mono/metadata/marshal.c | 4 ++++ mono/mini/aot-compiler.c | 10 +++++++++- mono/mini/aot-runtime.c | 3 ++- mono/mini/method-to-ir.c | 15 ++++++++++++++- mono/mini/mini-runtime.c | 5 ++++- mono/mini/patch-info.h | 5 +++++ 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 46c34f76a6f..25fc058351e 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -8595,6 +8595,10 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN); mono_mb_emit_ldloc_addr (mb, attach_dummy_local); + /* + * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads. + * Keep this in sync with the CEE_JIT_ICALL code in the JIT. + */ mono_mb_emit_icall (mb, mono_threads_attach_coop); mono_mb_emit_stloc (mb, attach_cookie_local); } diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 61991b5eb0f..a640300219a 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -5751,7 +5751,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint encode_value (patch_info->data.index, p, &p); break; case MONO_PATCH_INFO_INTERNAL_METHOD: - case MONO_PATCH_INFO_JIT_ICALL_ADDR: { + case MONO_PATCH_INFO_JIT_ICALL_ADDR: + case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: { guint32 len = strlen (patch_info->data.name); encode_value (len, p, &p); @@ -11373,6 +11374,13 @@ add_preinit_got_slots (MonoAotCompile *acfg) get_got_offset (acfg, FALSE, ji); get_got_offset (acfg, TRUE, ji); + /* Called by native-to-managed wrappers on possibly unattached threads */ + ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo)); + ji->type = MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL; + ji->data.name = "mono_threads_attach_coop"; + get_got_offset (acfg, FALSE, ji); + get_got_offset (acfg, TRUE, ji); + for (i = 0; i < sizeof (preinited_jit_icalls) / sizeof (char*); ++i) { ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile)); ji->type = MONO_PATCH_INFO_INTERNAL_METHOD; diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index a93776da15a..fbbc07a485a 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -3541,7 +3541,8 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin break; } case MONO_PATCH_INFO_INTERNAL_METHOD: - case MONO_PATCH_INFO_JIT_ICALL_ADDR: { + case MONO_PATCH_INFO_JIT_ICALL_ADDR: + case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: { guint32 len = decode_value (p, &p); ji->data.name = (char*)p; diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 0c37dc1533c..ee2665821d1 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -11457,7 +11457,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b CHECK_STACK (info->sig->param_count); sp -= info->sig->param_count; - ins = mono_emit_jit_icall (cfg, info->func, sp); + if (cfg->compile_aot && !strcmp (info->name, "mono_threads_attach_coop")) { + MonoInst *addr; + + /* + * This is called on unattached threads, so it cannot go through the trampoline + * infrastructure. Use an indirect call through a got slot initialized at load time + * instead. + */ + EMIT_NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL, (char*)info->name); + ins = mini_emit_calli (cfg, info->sig, sp, addr, NULL, NULL); + } else { + ins = mono_emit_jit_icall (cfg, info->func, sp); + } + if (!MONO_TYPE_IS_VOID (info->sig->ret)) *sp++ = ins; diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index f67497d6836..73c880ecf54 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -1237,6 +1237,7 @@ mono_patch_info_hash (gconstpointer data) return (ji->type << 8) | (gssize)info->klass | (gssize)info->method; } case MONO_PATCH_INFO_JIT_ICALL_ADDR: + case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: 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); @@ -1301,6 +1302,7 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) case MONO_PATCH_INFO_VIRT_METHOD: return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method; case MONO_PATCH_INFO_JIT_ICALL_ADDR: + case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: if (ji1->data.target == ji2->data.target) return 1; return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0; @@ -1353,7 +1355,8 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = mono_icall_get_wrapper (mi); break; } - case MONO_PATCH_INFO_JIT_ICALL_ADDR: { + case MONO_PATCH_INFO_JIT_ICALL_ADDR: + case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: { MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name); if (!mi) { g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name); diff --git a/mono/mini/patch-info.h b/mono/mini/patch-info.h index 5869eed77b1..8a4ba056ee0 100644 --- a/mono/mini/patch-info.h +++ b/mono/mini/patch-info.h @@ -58,3 +58,8 @@ PATCH_INFO(ICALL_ADDR_CALL, "icall_addr_call") PATCH_INFO(GET_TLS_TRAMP, "get_tls_tramp") PATCH_INFO(JIT_THREAD_ATTACH, "jit_thread_attach") PATCH_INFO(SET_TLS_TRAMP, "set_tls_tramp") +/* + * The address of a C function implementing a JIT icall. + * Same as JIT_ICALL_ADDR, but not treated as a call. + */ +PATCH_INFO(JIT_ICALL_ADDR_NOCALL, "jit_icall_addr_nocall") -- 2.25.1