diff options
author | Michal Strehovský <michals@microsoft.com> | 2015-10-28 06:23:17 +0300 |
---|---|---|
committer | Michal Strehovský <michals@microsoft.com> | 2015-10-28 19:17:32 +0300 |
commit | 59c931b0493534094f344b309bee79a707c3ba9f (patch) | |
tree | 3ca0e799de458e93c864a34e55836b9523141b1f | |
parent | 3c3b4b37f021be3c689058d4602d581778c29620 (diff) |
Half-implement thread statics
The implementation mirrors the way we implement GC statics. The actual
storage for thread static fields will be allocated at runtime on the GC
heap and the helper to get to the static base will need to indirect
through the GC handle table. Most of the piping within the compiler is
present. What is not present is:
* Actually allocating an object that represents the static block. We
will need to decide whether we want to do it lazily, or on thread
attach, or...
* Putting the "region of handles to thread static blocks" in a thread
static section of the executable. This likely needs some work on the
ObjWriter side.
* The helper to get the thread static base is implemented as INT3.
This way we don't need to blacklist 3 methods for Linux Hello World.
9 files changed, 150 insertions, 1 deletions
diff --git a/src/Common/src/TypeSystem/Common/DefType.FieldLayout.cs b/src/Common/src/TypeSystem/Common/DefType.FieldLayout.cs index be3aa292a..1d4ae11e6 100644 --- a/src/Common/src/TypeSystem/Common/DefType.FieldLayout.cs +++ b/src/Common/src/TypeSystem/Common/DefType.FieldLayout.cs @@ -72,6 +72,24 @@ namespace Internal.TypeSystem { get; } + + /// <summary> + /// How many bytes must be allocated to represent the (potentially GC visible) thread static + /// fields of this type. + /// </summary> + public abstract int ThreadStaticFieldSize + { + get; + } + + /// <summary> + /// What is the alignment required for allocating the (potentially GC visible) thread static + /// fields of this type. + /// </summary> + public abstract int ThreadStaticFieldAlignment + { + get; + } } }
\ No newline at end of file diff --git a/src/Common/src/TypeSystem/Common/MetadataType.FieldLayout.cs b/src/Common/src/TypeSystem/Common/MetadataType.FieldLayout.cs index 2a9e45060..9b72fe6ef 100644 --- a/src/Common/src/TypeSystem/Common/MetadataType.FieldLayout.cs +++ b/src/Common/src/TypeSystem/Common/MetadataType.FieldLayout.cs @@ -131,6 +131,30 @@ namespace Internal.TypeSystem } } + public override int ThreadStaticFieldSize + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.HasStaticFieldLayout)) + { + ComputeStaticFieldLayout(); + } + return _staticBlockInfo == null ? 0 : _staticBlockInfo.ThreadStatics.Size; + } + } + + public override int ThreadStaticFieldAlignment + { + get + { + if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.HasStaticFieldLayout)) + { + ComputeStaticFieldLayout(); + } + return _staticBlockInfo == null ? 0 : _staticBlockInfo.ThreadStatics.LargestAlignment; + } + } + internal void ComputeInstanceFieldLayout() { var computedLayout = FieldLayoutAlgorithm.ComputeInstanceFieldLayout(this); diff --git a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 52a09392c..48962d778 100644 --- a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -81,6 +81,11 @@ namespace ILToNative.DependencyAnalysis return new GCStaticsNode(type, this); }); + _threadStatics = new NodeCache<MetadataType, ThreadStaticsNode>((MetadataType type) => + { + return new ThreadStaticsNode(type, this); + }); + _GCStaticEETypes = new NodeCache<bool[], GCStaticEETypeNode>((bool[] gcdesc) => { return new GCStaticEETypeNode(gcdesc, this); @@ -166,6 +171,13 @@ namespace ILToNative.DependencyAnalysis return _GCStatics.GetOrAdd(type); } + private NodeCache<MetadataType, ThreadStaticsNode> _threadStatics; + + public ThreadStaticsNode TypeThreadStaticsSymbol(MetadataType type) + { + return _threadStatics.GetOrAdd(type); + } + class BoolArrayEqualityComparer : IEqualityComparer<bool[]> { bool IEqualityComparer<bool[]>.Equals(bool[] x, bool[] y) @@ -285,6 +297,7 @@ namespace ILToNative.DependencyAnalysis } public ArrayOfEmbeddedDataNode GCStaticsRegion = new ArrayOfEmbeddedDataNode("__GCStaticRegionStart", "__GCStaticRegionEnd", null); + public ArrayOfEmbeddedDataNode ThreadStaticsRegion = new ArrayOfEmbeddedDataNode("__ThreadStaticRegionStart", "__ThreadStaticRegionEnd", null); public ArrayOfEmbeddedDataNode StringTable = new ArrayOfEmbeddedDataNode("__str_fixup", "__str_fixup_end", null); public Dictionary<TypeDesc, List<MethodDesc>> VirtualSlots = new Dictionary<TypeDesc, List<MethodDesc>>(); @@ -294,6 +307,7 @@ namespace ILToNative.DependencyAnalysis public void AttachToDependencyGraph(DependencyAnalysisFramework.DependencyAnalyzerBase<NodeFactory> graph) { graph.AddRoot(GCStaticsRegion, "GC StaticsRegion is always generated"); + graph.AddRoot(ThreadStaticsRegion, "ThreadStaticsRegion is always generated"); graph.AddRoot(StringTable, "StringTable is always generated"); } } diff --git a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs index cb3bd21ac..73a80bcbc 100644 --- a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs +++ b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs @@ -39,6 +39,11 @@ namespace ILToNative.DependencyAnalysis.X64 EmitRel32RelocFor1ByteOpcode(symbol); } + public void EmitINT3() + { + Builder.EmitByte(0xCC); + } + public void EmitJmpToAddrMode(ref AddrMode addrMode) { EmitIndirInstruction(0xFF, 0x4, ref addrMode); diff --git a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs index 5af67c1c6..626430c7f 100644 --- a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs +++ b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs @@ -96,6 +96,10 @@ namespace ILToNative.DependencyAnalysis } break; + case ReadyToRunHelperId.GetThreadStaticBase: + encoder.EmitINT3(); + break; + case ReadyToRunHelperId.GetGCStaticBase: if (!((MetadataType)Helper.Target).HasStaticConstructor) { diff --git a/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/ThreadStaticsNode.cs b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/ThreadStaticsNode.cs new file mode 100644 index 000000000..49c7f0ac7 --- /dev/null +++ b/src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/ThreadStaticsNode.cs @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Internal.TypeSystem; +using System.Collections.Generic; + +namespace ILToNative.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, ISymbolNode + { + MetadataType _type; + + public ThreadStaticsNode(MetadataType type, NodeFactory factory) + { + _type = type; + } + + public override string GetName() + { + return ((ISymbolNode)this).MangledName; + } + + protected override void OnMarked(NodeFactory factory) + { + factory.ThreadStaticsRegion.AddEmbeddedObject(this); + } + + string ISymbolNode.MangledName + { + get + { + return "__ThreadStaticBase_" + NodeFactory.NameMangler.GetMangledTypeName(_type); + } + } + + public ISymbolNode GetGCStaticEETypeNode(NodeFactory context) + { + // TODO Replace with better gcDesc computation algorithm when we add gc handling to the type system + // TODO This logic should be shared with GCStaticsNode. + bool[] gcDesc = new bool[_type.ThreadStaticFieldSize / context.Target.PointerSize + 1]; + return context.GCStaticEEType(gcDesc); + } + + public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) + { + + return new DependencyListEntry[] { new DependencyListEntry(context.ThreadStaticsRegion, "ThreadStatics Region"), + new DependencyListEntry(GetGCStaticEETypeNode(context), "ThreadStatic EEType")}; + } + + int ISymbolNode.Offset + { + get + { + return Offset; + } + } + + public override bool StaticDependenciesAreComputed + { + get + { + return true; + } + } + + public override void EncodeData(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly) + { + builder.RequirePointerAlignment(); + + // At runtime, an instance of the GCStaticEEType will be created and a GCHandle to it + // will be written in this location. + builder.EmitPointerReloc(GetGCStaticEETypeNode(factory)); + } + } +} diff --git a/src/ILToNative.Compiler/src/Compiler/ReadyToRunHelper.cs b/src/ILToNative.Compiler/src/Compiler/ReadyToRunHelper.cs index 5fa420136..4a632f329 100644 --- a/src/ILToNative.Compiler/src/Compiler/ReadyToRunHelper.cs +++ b/src/ILToNative.Compiler/src/Compiler/ReadyToRunHelper.cs @@ -20,6 +20,7 @@ namespace ILToNative CastClass, GetNonGCStaticBase, GetGCStaticBase, + GetThreadStaticBase, DelegateCtor, } @@ -58,6 +59,8 @@ namespace ILToNative return "__GetNonGCStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target); case ReadyToRunHelperId.GetGCStaticBase: return "__GetGCStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target); + case ReadyToRunHelperId.GetThreadStaticBase: + return "__GetThreadStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target); case ReadyToRunHelperId.DelegateCtor: return "__DelegateCtor_" + _compilation.NameMangler.GetMangledMethodName(((DelegateInfo)this.Target).Target); default: diff --git a/src/ILToNative.Compiler/src/ILToNative.Compiler.csproj b/src/ILToNative.Compiler/src/ILToNative.Compiler.csproj index 522d789fa..651059275 100644 --- a/src/ILToNative.Compiler/src/ILToNative.Compiler.csproj +++ b/src/ILToNative.Compiler/src/ILToNative.Compiler.csproj @@ -56,6 +56,7 @@ <Compile Include="Compiler\DependencyAnalysis\ReadyToRunHelperNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\Relocation.cs" /> <Compile Include="Compiler\DependencyAnalysis\Target_X64\X64JumpStubNode.cs" /> + <Compile Include="Compiler\DependencyAnalysis\ThreadStaticsNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\VirtualMethodUseNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\Target_X64\Register.cs" /> <Compile Include="Compiler\DependencyAnalysis\Target_X64\X64Emitter.cs" /> diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index a4ffc22f7..72154bf23 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -1167,7 +1167,7 @@ namespace Internal.JitInterface ReadyToRunHelperId helperId; if (field.IsThreadStatic) { - throw new NotImplementedException(); + helperId = ReadyToRunHelperId.GetThreadStaticBase; } else if (field.HasGCStaticBase) { |