Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Strehovský <michals@microsoft.com>2015-10-28 06:23:17 +0300
committerMichal Strehovský <michals@microsoft.com>2015-10-28 19:17:32 +0300
commit59c931b0493534094f344b309bee79a707c3ba9f (patch)
tree3ca0e799de458e93c864a34e55836b9523141b1f
parent3c3b4b37f021be3c689058d4602d581778c29620 (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.
-rw-r--r--src/Common/src/TypeSystem/Common/DefType.FieldLayout.cs18
-rw-r--r--src/Common/src/TypeSystem/Common/MetadataType.FieldLayout.cs24
-rw-r--r--src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs14
-rw-r--r--src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs5
-rw-r--r--src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs4
-rw-r--r--src/ILToNative.Compiler/src/Compiler/DependencyAnalysis/ThreadStaticsNode.cs80
-rw-r--r--src/ILToNative.Compiler/src/Compiler/ReadyToRunHelper.cs3
-rw-r--r--src/ILToNative.Compiler/src/ILToNative.Compiler.csproj1
-rw-r--r--src/JitInterface/src/CorInfoImpl.cs2
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)
{