| File: Compiler\DependencyAnalysis\ThreadStaticsNode.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using Internal.Text; using Internal.TypeSystem; namespace ILCompiler.DependencyAnalysis { /// <summary> /// Represents the thread static region of a given type. This is very similar to <see cref="GCStaticsNode"/>, /// since the actual storage will be allocated on the GC heap at runtime and is allowed to contain GC pointers. /// </summary> public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode { private MetadataType _type; private InlinedThreadStatics _inlined; public ThreadStaticsNode(MetadataType type, NodeFactory factory) { Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific)); Debug.Assert(!type.IsGenericDefinition); _type = type; } public ThreadStaticsNode(InlinedThreadStatics inlined, NodeFactory factory) { _inlined = inlined; } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); protected override void OnMarked(NodeFactory factory) { factory.ThreadStaticsRegion.AddEmbeddedObject(this); } public static Utf8String GetMangledName(TypeDesc type, NameMangler nameMangler) { return nameMangler.NodeMangler.ThreadStatics(type); } int ISymbolNode.Offset => 0; int ISymbolDefinitionNode.Offset => OffsetFromBeginningOfArray; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { Utf8String mangledName = _type == null ? new Utf8String("_inlinedThreadStatics"u8) : GetMangledName(_type, nameMangler); sb.Append(mangledName); } private ISymbolNode GetGCStaticEETypeNode(NodeFactory factory) { GCPointerMap map = _type != null ? GCPointerMap.FromThreadStaticLayout(_type) : GCPointerMap.FromInlinedThreadStatics( _inlined.GetTypes(), _inlined.GetOffsets(), _inlined.GetSize(), factory.Target.PointerSize); bool requiresAlign8 = _type is not null && _type.ThreadGcStaticFieldAlignment.AsInt > factory.Target.PointerSize; return factory.GCStaticEEType(map, requiresAlign8); } public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) { DependencyList result = new DependencyList(); result.Add(new DependencyListEntry(GetGCStaticEETypeNode(factory), "ThreadStatic MethodTable")); if (_type != null) { if (factory.PreinitializationManager.HasEagerStaticConstructor(_type)) { result.Add(new DependencyListEntry(factory.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor")); } ModuleUseBasedDependencyAlgorithm.AddDependenciesDueToModuleUse(ref result, factory, _type.Module); } else { foreach (var type in _inlined.GetTypes()) { if (factory.PreinitializationManager.HasEagerStaticConstructor(type)) { result.Add(new DependencyListEntry(factory.EagerCctorIndirection(type.GetStaticConstructor()), "Eager .cctor")); } // inlined threadstatics do not need the index for execution, but may need it for debug visualization. result.Add(new DependencyListEntry(factory.TypeThreadStaticIndex(type), "ThreadStatic index for debug visualization")); ModuleUseBasedDependencyAlgorithm.AddDependenciesDueToModuleUse(ref result, factory, type.Module); } } return result; } public override bool HasConditionalStaticDependencies => _type != null ? _type.ConvertToCanonForm(CanonicalFormKind.Specific) != _type: false; public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) { Debug.Assert(_type != null); // If we have a type loader template for this type, we need to keep track of the generated // bases in the type info hashtable. The type symbol node does such accounting. return new CombinedDependencyListEntry[] { new CombinedDependencyListEntry(factory.NecessaryTypeSymbol(_type), factory.NativeLayout.TemplateTypeLayout(_type.ConvertToCanonForm(CanonicalFormKind.Specific)), "Keeping track of template-constructable type static bases"), }; } public override bool StaticDependenciesAreComputed => true; public override void EncodeData(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly) { // At runtime, an instance of the GCStaticEEType will be created and a GCHandle to it // will be written in this location. builder.RequireInitialPointerAlignment(); builder.EmitPointerReloc(GetGCStaticEETypeNode(factory)); } public MetadataType Type => _type; public override int ClassCode => 2091208431; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { // force the type of the storage block for inlined threadstatics to be "less" // than other storage blocks, - to ensure it is serialized as the item #0 if (_type == null) { // there should only be at most one inlined storage type. Debug.Assert(other != null); return -1; } return comparer.Compare(_type, ((ThreadStaticsNode)other)._type); } internal int GetTypeStorageOffset(MetadataType type) => _inlined.GetOffsets()[type]; } }