diff --git a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs index 7df723cb5b7..3abd8ab3c05 100644 --- a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs +++ b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs @@ -119,6 +119,20 @@ public ObjectNode GetFieldRvaData(FieldDesc field) } } + public ISymbolNode GetFieldData(FieldDesc field) + { + if (field.HasRva) + { + return (ISymbolNode)GetFieldRvaData(field); + } + else + { + Debug.Assert(field.IsStatic && !field.IsThreadStatic && !field.HasGCStaticBase); + ISymbolNode baseAddr = NodeFactory.TypeNonGCStaticsSymbol((MetadataType)field.OwningType); + return NodeFactory.SymbolWithOffset(baseAddr, field.Offset.AsInt); + } + } + public bool HasLazyStaticConstructor(TypeDesc type) { return TypeSystemContext.HasLazyStaticConstructor(type); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index be26fcd9111..92c7217c68e 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -420,6 +420,11 @@ private void CreateNodeCaches() return new NamedJumpStubNode(id.Item1, id.Item2); }); + _symbolWithOffsetNodes = new NodeCache((SymbolWithOffsetKey key) => + { + return new SymbolWithOffsetNode(key.Symbol, key.Offset); + }); + _vTableNodes = new NodeCache((TypeDesc type ) => { if (CompilationModuleGroup.ShouldProduceFullVTable(type)) @@ -975,7 +980,14 @@ public ISymbolNode NamedJumpStub(string name, ISymbolNode target) { return _namedJumpStubNodes.GetOrAdd(new Tuple(name, target)); } - + + private NodeCache _symbolWithOffsetNodes; + + public ISymbolNode SymbolWithOffset(ISymbolNode symbol, int offset) + { + return _symbolWithOffsetNodes.GetOrAdd(new SymbolWithOffsetKey(symbol, offset)); + } + /// /// Returns alternative symbol name that object writer should produce for given symbols /// in addition to the regular one. @@ -1145,6 +1157,27 @@ public override int GetHashCode() } } + protected struct SymbolWithOffsetKey : IEquatable + { + public readonly ISymbolNode Symbol; + public readonly int Offset; + + public SymbolWithOffsetKey(ISymbolNode symbol, int offset) + { + Symbol = symbol; + Offset = offset; + } + + public bool Equals(SymbolWithOffsetKey other) => Symbol == other.Symbol && Offset == other.Offset; + public override bool Equals(object obj) => obj is SymbolWithOffsetKey && Equals((SymbolWithOffsetKey)obj); + public override int GetHashCode() + { + int hashCode = Symbol.GetHashCode(); + hashCode = hashCode * 23 + Offset; + return hashCode; + } + } + protected struct ReadOnlyDataBlobKey : IEquatable { public readonly Utf8String Name; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SymbolWithOffsetNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SymbolWithOffsetNode.cs new file mode 100644 index 00000000000..067806dde1d --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/SymbolWithOffsetNode.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; + +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + internal class SymbolWithOffsetNode : DependencyNodeCore, ISymbolNode + { + private ISymbolNode _target; + private int _offset; + + public SymbolWithOffsetNode(ISymbolNode target, int offset) + { + _target = target; + _offset = offset; + } + + public int Offset => _offset; + + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool HasDynamicDependencies => false; + public override bool HasConditionalStaticDependencies => false; + public override bool StaticDependenciesAreComputed => true; + public bool RepresentsIndirectionCell => false; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + _target.AppendMangledName(nameMangler, sb); + } + + public override IEnumerable GetConditionalStaticDependencies(NodeFactory context) + { + return null; + } + + public override IEnumerable GetStaticDependencies(NodeFactory context) + { + return new DependencyListEntry[] + { + new DependencyListEntry(_target, "Target"), + }; + } + + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory context) + { + return null; + } + + protected override string GetName(NodeFactory context) + { + return "__offs_" + _offset.ToStringInvariant() + "_from_" + _target.GetMangledName(context.NameMangler); + } + } +} diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index 7b86399ea27..7c6f325bede 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -107,6 +107,7 @@ + diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index 1a0c2bbb785..e36b7effac4 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -2162,9 +2162,8 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET pResult.fieldLookup = CreateConstLookupToSymbol(helper); } } - else + else if (field.IsThreadStatic || field.HasGCStaticBase) { - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; pResult.helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE; @@ -2173,23 +2172,10 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET { helperId = ReadyToRunHelperId.GetThreadStaticBase; } - else if (field.HasGCStaticBase) - { - helperId = ReadyToRunHelperId.GetGCStaticBase; - } else { - var owningType = field.OwningType; - if ((owningType.IsWellKnownType(WellKnownType.IntPtr) || - owningType.IsWellKnownType(WellKnownType.UIntPtr)) && - field.Name == "Zero") - { - fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_ZERO; - } - else - { - helperId = ReadyToRunHelperId.GetNonGCStaticBase; - } + Debug.Assert(field.HasGCStaticBase); + helperId = ReadyToRunHelperId.GetGCStaticBase; } if (helperId != ReadyToRunHelperId.Invalid) @@ -2197,6 +2183,26 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET pResult.fieldLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ReadyToRunHelper(helperId, field.OwningType)); } } + else + { + var owningType = field.OwningType; + if ((owningType.IsWellKnownType(WellKnownType.IntPtr) || + owningType.IsWellKnownType(WellKnownType.UIntPtr)) && + field.Name == "Zero") + { + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INTRINSIC_ZERO; + } + else + { + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_ADDRESS; + + // We are not going through a helper. The constructor has to be triggered explicitly. + if (_compilation.HasLazyStaticConstructor(field.OwningType)) + { + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS; + } + } + } } else { @@ -3416,8 +3422,7 @@ private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirectio private void* getFieldAddress(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) { FieldDesc fieldDesc = HandleToObject(field); - Debug.Assert(fieldDesc.HasRva); - return (void*)ObjectToHandle(_compilation.GetFieldRvaData(fieldDesc)); + return (void*)ObjectToHandle(_compilation.GetFieldData(fieldDesc)); } private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, ref void* ppIndirection) diff --git a/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs b/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs index 2c5f06f72e5..2f1aad4432c 100644 --- a/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs +++ b/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs @@ -50,6 +50,11 @@ public ObjectNode GetFieldRvaData(FieldDesc field) throw new NotImplementedException(); } + public ObjectNode GetFieldData(FieldDesc field) + { + throw new NotImplementedException(); + } + internal MethodIL GetMethodIL(MethodDesc method) { // Flush the cache when it grows too big