Skip to content

Commit

Permalink
[jit] Implement fast TLS access in gshared methods. (#18377)
Browse files Browse the repository at this point in the history
Fixes #18370.
  • Loading branch information
vargaz committed Jan 8, 2020
1 parent d0a3fb1 commit e999846
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
22 changes: 22 additions & 0 deletions mono/mini/generics.cs
Expand Up @@ -1462,6 +1462,28 @@ struct OneThing<T1> {
var t = FromResult<OneThing<int>>(new OneThing<int> {Item1 = 42});
return t.Item1;
}

class ThreadLocalClass<T> {
[ThreadStatic]
static T v;

public T Value {
[MethodImpl (MethodImplOptions.NoInlining)]
get {
return v;
}
[MethodImpl (MethodImplOptions.NoInlining)]
set {
v = value;
}
}
}

public static int test_0_tls_gshared () {
var c = new ThreadLocalClass<string> ();
c.Value = "FOO";
return c.Value == "FOO" ? 0 : 1;
}
}

#if !__MOBILE__
Expand Down
16 changes: 10 additions & 6 deletions mono/mini/method-to-ir.c
Expand Up @@ -9385,7 +9385,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
thread_ins = NULL;

/* Generate IR to compute the field address */
if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) &&
!(context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))) {
/*
* Fast access to TLS data
* Inline version of get_thread_static_data () in
Expand All @@ -9394,17 +9395,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
guint32 offset;
int idx, static_data_reg, array_reg, dreg;

if (context_used && cfg->gsharedvt && mini_is_gsharedvt_klass (klass))
GSHAREDVT_FAILURE (il_op);

static_data_reg = alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));

if (cfg->compile_aot) {
if (cfg->compile_aot || context_used) {
int offset_reg, offset2_reg, idx_reg;

/* For TLS variables, this will return the TLS offset */
EMIT_NEW_SFLDACONST (cfg, ins, field);
if (context_used) {
MonoInst *addr_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
/* The value is offset by 1 */
EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, addr_ins->dreg, addr_ins->dreg, 1);
} else {
EMIT_NEW_SFLDACONST (cfg, ins, field);
}
offset_reg = ins->dreg;
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
idx_reg = alloc_ireg (cfg);
Expand Down
15 changes: 15 additions & 0 deletions mono/mini/mini-generic-sharing.c
Expand Up @@ -2255,6 +2255,21 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
case MONO_RGCTX_INFO_FIELD_OFFSET: {
MonoClassField *field = (MonoClassField *)data;

if (mono_class_field_is_special_static (field)) {
gpointer addr;

mono_class_vtable_checked (domain, klass, error);
mono_error_assert_ok (error);

/* Return the TLS offset */
g_assert (domain->special_static_fields);
mono_domain_lock (domain);
addr = g_hash_table_lookup (domain->special_static_fields, field);
mono_domain_unlock (domain);
g_assert (addr);
return (guint8*)addr + 1;
}

/* The value is offset by 1 */
if (m_class_is_valuetype (field->parent) && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
return GUINT_TO_POINTER (field->offset - MONO_ABI_SIZEOF (MonoObject) + 1);
Expand Down

0 comments on commit e999846

Please sign in to comment.