encode_method_ref (acfg, patch_info->data.virt_method->method, p, &p);
break;
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
+ case MONO_PATCH_INFO_GET_TLS_TRAMP:
break;
default:
g_warning ("unable to handle jump info %d", patch_info->type);
get_got_offset (acfg, FALSE, ji);
get_got_offset (acfg, TRUE, ji);
+ ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
+ ji->type = MONO_PATCH_INFO_GET_TLS_TRAMP;
+ 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;
static int i8_align;
static gpointer single_step_tramp, breakpoint_tramp;
+static gpointer get_tls_tramp;
/*
* The code generated for sequence points reads from this location, which is
static void mono_arch_compute_omit_fp (MonoCompile *cfg);
#endif
+static guint8*
+emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointer data);
+
const char*
mono_arch_regname (int reg)
{
{
#ifdef HAVE_FAST_TLS
code = mono_arm_emit_load_imm (code, ARMREG_R0, tls_offset);
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
- "mono_get_tls_key");
- code = emit_call_seq (cfg, code);
+ if (cfg->compile_aot) {
+ /*
+ * This opcode is generated by CEE_MONO_JIT_ATTACH, so it can execute on
+ * threads which are not yet attached to the runtime. This means we can't
+ * call it directly, since the call would go through the trampoline code
+ * which assumes the thread is attached. So use a separate patch info type
+ * for it, and load it from a preinitialized GOT slot.
+ */
+ code = emit_aotconst (cfg, code, ARMREG_R1, MONO_PATCH_INFO_GET_TLS_TRAMP, NULL);
+ code = emit_call_reg (code, ARMREG_R1);
+ } else {
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ "mono_get_tls_key");
+ code = emit_call_seq (cfg, code);
+ }
if (dreg != ARMREG_R0)
ARM_MOV_REG_REG (code, dreg, ARMREG_R0);
#else
#ifdef HAVE_FAST_TLS
if (tls_offset_reg != ARMREG_R0)
ARM_MOV_REG_REG (code, ARMREG_R0, tls_offset_reg);
- mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
- "mono_get_tls_key");
- code = emit_call_seq (cfg, code);
+ if (cfg->compile_aot) {
+ code = emit_aotconst (cfg, code, ARMREG_R1, MONO_PATCH_INFO_GET_TLS_TRAMP, NULL);
+ code = emit_call_reg (code, ARMREG_R1);
+ } else {
+ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+ "mono_get_tls_key");
+ code = emit_call_seq (cfg, code);
+ }
if (dreg != ARMREG_R0)
ARM_MOV_REG_REG (code, dreg, ARMREG_R0);
#else
mono_register_jit_icall (tls_imp.get_tls_thunk, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
mono_register_jit_icall (tls_imp.set_tls_thunk, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
+ get_tls_tramp = tls_imp.get_tls_thunk;
+
if (tls_imp.get_tls_thunk_end) {
mono_tramp_info_register (
mono_tramp_info_create (
{
return get_call_info (mp, sig);
}
+
+gpointer
+mono_arch_get_get_tls_tramp (void)
+{
+ return get_tls_tramp;
+}
+
+static guint8*
+emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointer data)
+{
+ /* OP_AOTCONST */
+ mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
+ ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
+ ARM_B (code, 0);
+ *(gpointer*)code = NULL;
+ code += 4;
+ /* Load the value from the GOT */
+ ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg);
+ return code;
+}
case MONO_PATCH_INFO_GOT_OFFSET:
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
case MONO_PATCH_INFO_AOT_MODULE:
+ case MONO_PATCH_INFO_GET_TLS_TRAMP:
return (ji->type << 8);
case MONO_PATCH_INFO_CASTCLASS_CACHE:
return (ji->type << 8) | (ji->data.index);
case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
break;
+ case MONO_PATCH_INFO_GET_TLS_TRAMP:
+#ifdef MONO_ARCH_HAVE_GET_TLS_TRAMP
+ target = mono_arch_get_get_tls_tramp ();
+#else
+ g_assert_not_reached ();
+#endif
+ break;
default:
g_assert_not_reached ();
}