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);
}
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);
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;
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;
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;
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);
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;
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);
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")