diff --git a/mono/mini/generics.cs b/mono/mini/generics.cs index 857ad44f3e05c..0c6346c63d48d 100644 --- a/mono/mini/generics.cs +++ b/mono/mini/generics.cs @@ -1462,6 +1462,28 @@ struct OneThing { var t = FromResult>(new OneThing {Item1 = 42}); return t.Item1; } + + class ThreadLocalClass { + [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 (); + c.Value = "FOO"; + return c.Value == "FOO" ? 0 : 1; + } } #if !__MOBILE__ diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 5334e10513d7d..606655a0eca7a 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -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 @@ -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); diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index 279fbaf3e4827..5ee4434e1d235 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -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);