Skip to content

Commit

Permalink
Add common parent for frozen objects (#93773)
Browse files Browse the repository at this point in the history
Frozen strings and frozen arbitrary objects were separate classes but giving them a common ancestors makes handling these easier.
  • Loading branch information
MichalStrehovsky committed Oct 21, 2023
1 parent 33ee130 commit 712d522
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 143 deletions.
Original file line number Diff line number Diff line change
@@ -1,77 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;

using Internal.Text;
using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a frozen object that is statically preallocated within the data section
/// of the executable instead of on the GC heap.
/// </summary>
public sealed class FrozenObjectNode : EmbeddedObjectNode, ISymbolDefinitionNode
public abstract class FrozenObjectNode : EmbeddedObjectNode, ISymbolDefinitionNode
{
private readonly MetadataType _owningType;
private readonly TypePreinit.ISerializableReference _data;
private readonly int _allocationSiteId;

public FrozenObjectNode(MetadataType owningType, int allocationSiteId, TypePreinit.ISerializableReference data)
{
_owningType = owningType;
_allocationSiteId = allocationSiteId;
_data = data;
}

public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix).Append("__FrozenObj_")
.Append(nameMangler.GetMangledTypeName(_owningType))
.Append(_allocationSiteId.ToStringInvariant());
}

public override bool StaticDependenciesAreComputed => true;

public TypeDesc ObjectType => _data.Type;

public bool IsKnownImmutable => _data.IsKnownImmutable;

public int GetArrayLength()
{
Debug.Assert(ObjectType.IsArray);
return _data.ArrayLength;
}

int ISymbolNode.Offset => 0;

int ISymbolDefinitionNode.Offset
{
get
{
// The frozen object symbol points at the MethodTable portion of the object, skipping over the sync block
return OffsetFromBeginningOfArray + _owningType.Context.Target.PointerSize;
// The frozen symbol points at the MethodTable portion of the object, skipping over the sync block
return OffsetFromBeginningOfArray + ObjectType.Context.Target.PointerSize;
}
}

public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
public abstract TypeDesc ObjectType { get; }

public abstract int? ArrayLength { get; }
public abstract bool IsKnownImmutable { get; }
public int Size => ObjectType.Context.Target.PointerSize + ContentSize; // SyncBlock + size of contents
protected abstract int ContentSize { get; }

public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb);

public sealed override bool StaticDependenciesAreComputed => true;

public sealed override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
// Sync Block
dataBuilder.EmitZeroPointer();
dataBuilder.EmitZeroPointer(); // Sync block

// byte contents
_data.WriteContent(ref dataBuilder, this, factory);
int sizeBefore = dataBuilder.CountBytes;
EncodeContents(ref dataBuilder, factory, relocsOnly);
Debug.Assert(dataBuilder.CountBytes == sizeBefore + ContentSize);
}

protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
public sealed override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory, true);
EncodeData(ref builder, factory, true);
var builder = new ObjectDataBuilder(factory, relocsOnly: true);
EncodeData(ref builder, factory, relocsOnly: true);
Relocation[] relocs = builder.ToObjectData().Relocs;

DependencyList dependencies = null;

if (relocs != null)
Expand All @@ -83,23 +60,15 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
}
}

_data.GetNonRelocationDependencies(ref dependencies, factory);
GetNonRelocationDependencies(ref dependencies, factory);

return dependencies;
}

public override int ClassCode => 1789429316;

public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
public virtual void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory)
{
var otherFrozenObjectNode = (FrozenObjectNode)other;
int result = comparer.Compare(otherFrozenObjectNode._owningType, _owningType);
if (result != 0)
return result;

return _allocationSiteId.CompareTo(otherFrozenObjectNode._allocationSiteId);
}

public override string ToString() => $"Frozen {_data.Type.GetDisplayNameWithoutNamespace()} object";
public abstract void EncodeContents(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly);
}
}
Original file line number Diff line number Diff line change
@@ -1,63 +1,32 @@
// 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 Internal.Text;
using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace ILCompiler.DependencyAnalysis
{
public sealed class FrozenStringNode : EmbeddedObjectNode, ISymbolDefinitionNode
public sealed class FrozenStringNode : FrozenObjectNode
{
private string _data;
private int _syncBlockSize;
private readonly DefType _stringType;

public FrozenStringNode(string data, TargetDetails target)
public FrozenStringNode(string data, CompilerTypeSystemContext context)
{
_data = data;
_syncBlockSize = target.PointerSize;
_stringType = context.GetWellKnownType(WellKnownType.String);
}

public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix).Append("__Str_").Append(nameMangler.GetMangledStringName(_data));
}

public override bool StaticDependenciesAreComputed => true;

int ISymbolNode.Offset => 0;
protected override int ContentSize => _stringType.Context.Target.PointerSize + sizeof(int) + (_data.Length + 1) * sizeof(char);

int ISymbolDefinitionNode.Offset
public override void EncodeContents(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
get
{
// The frozen string symbol points at the MethodTable portion of the object, skipping over the sync block
return OffsetFromBeginningOfArray + _syncBlockSize;
}
}

private static IEETypeNode GetEETypeNode(NodeFactory factory)
{
DefType systemStringType = factory.TypeSystemContext.GetWellKnownType(WellKnownType.String);

IEETypeNode stringSymbol = factory.ConstructedTypeSymbol(systemStringType);

//
// The GC requires a direct reference to frozen objects' EETypes. System.String needs
// to be compiled into this binary.
//
Debug.Assert(!stringSymbol.RepresentsIndirectionCell);
return stringSymbol;
}

public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
dataBuilder.EmitZeroPointer(); // Sync block

dataBuilder.EmitPointerReloc(GetEETypeNode(factory));
dataBuilder.EmitPointerReloc(factory.ConstructedTypeSymbol(ObjectType));

dataBuilder.EmitInt(_data.Length);

Expand All @@ -72,14 +41,6 @@ public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory f

protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
return new DependencyListEntry[]
{
new DependencyListEntry(GetEETypeNode(factory), "Frozen string literal MethodTable"),
};
}

public override int ClassCode => -1733946122;

public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
Expand All @@ -89,6 +50,12 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer

public string Data => _data;

public override int? ArrayLength => _data.Length;

public override bool IsKnownImmutable => true;

public override TypeDesc ObjectType => _stringType;

public override string ToString() => $"\"{_data}\"";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,12 @@ private void CreateNodeCaches()

_frozenStringNodes = new NodeCache<string, FrozenStringNode>((string data) =>
{
return new FrozenStringNode(data, Target);
return new FrozenStringNode(data, TypeSystemContext);
});

_frozenObjectNodes = new NodeCache<SerializedFrozenObjectKey, FrozenObjectNode>(key =>
_frozenObjectNodes = new NodeCache<SerializedFrozenObjectKey, SerializedFrozenObjectNode>(key =>
{
return new FrozenObjectNode(key.OwnerType, key.AllocationSiteId, key.SerializableObject);
return new SerializedFrozenObjectNode(key.OwnerType, key.AllocationSiteId, key.SerializableObject);
});

_interfaceDispatchCells = new NodeCache<DispatchCellKey, InterfaceDispatchCellNode>(callSiteCell =>
Expand Down Expand Up @@ -1220,9 +1220,9 @@ public FrozenStringNode SerializedStringObject(string data)
return _frozenStringNodes.GetOrAdd(data);
}

private NodeCache<SerializedFrozenObjectKey, FrozenObjectNode> _frozenObjectNodes;
private NodeCache<SerializedFrozenObjectKey, SerializedFrozenObjectNode> _frozenObjectNodes;

public FrozenObjectNode SerializedFrozenObject(MetadataType owningType, int allocationSiteId, TypePreinit.ISerializableReference data)
public SerializedFrozenObjectNode SerializedFrozenObject(MetadataType owningType, int allocationSiteId, TypePreinit.ISerializableReference data)
{
return _frozenObjectNodes.GetOrAdd(new SerializedFrozenObjectKey(owningType, allocationSiteId, data));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

using Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a frozen object that is statically preallocated within the data section
/// of the executable instead of on the GC heap.
/// </summary>
public sealed class SerializedFrozenObjectNode : FrozenObjectNode
{
private readonly MetadataType _owningType;
private readonly TypePreinit.ISerializableReference _data;
private readonly int _allocationSiteId;

public MetadataType OwningType => _owningType;

public SerializedFrozenObjectNode(MetadataType owningType, int allocationSiteId, TypePreinit.ISerializableReference data)
{
_owningType = owningType;
_allocationSiteId = allocationSiteId;
_data = data;
}

public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix).Append("__FrozenObj_")
.Append(nameMangler.GetMangledTypeName(_owningType))
.Append(_allocationSiteId.ToStringInvariant());
}

public override TypeDesc ObjectType => _data.Type;

public override bool IsKnownImmutable => _data.IsKnownImmutable;

protected override int ContentSize
=> _data.Type.IsArray
? _data.Type.Context.Target.PointerSize * 2 + ((ArrayType)_data.Type).ElementType.GetElementSize().AsInt * _data.ArrayLength
: ((DefType)_data.Type).InstanceByteCount.AsInt + (_data.Type.IsValueType ? _data.Type.Context.Target.PointerSize : 0);

public override int? ArrayLength => _data.Type.IsArray ? _data.ArrayLength : null;

public override void EncodeContents(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
// byte contents
_data.WriteContent(ref dataBuilder, this, factory);
}

protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

public override void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory)
{
_data.GetNonRelocationDependencies(ref dependencies, factory);
}

public override int ClassCode => 1789429316;

public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
var otherFrozenObjectNode = (SerializedFrozenObjectNode)other;
int result = comparer.Compare(otherFrozenObjectNode._owningType, _owningType);
if (result != 0)
return result;

return _allocationSiteId.CompareTo(otherFrozenObjectNode._allocationSiteId);
}

public override string ToString() => $"Frozen {_data.Type.GetDisplayNameWithoutNamespace()} object";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public abstract class MetadataManager : ICompilationRootProvider
private readonly SortedSet<MethodDesc> _reflectableMethods = new SortedSet<MethodDesc>(TypeSystemComparer.Instance);
private readonly SortedSet<GenericDictionaryNode> _genericDictionariesGenerated = new SortedSet<GenericDictionaryNode>(CompilerComparer.Instance);
private readonly SortedSet<IMethodBodyNode> _methodBodiesGenerated = new SortedSet<IMethodBodyNode>(CompilerComparer.Instance);
private readonly SortedSet<EmbeddedObjectNode> _frozenObjects = new SortedSet<EmbeddedObjectNode>(CompilerComparer.Instance);
private readonly SortedSet<FrozenObjectNode> _frozenObjects = new SortedSet<FrozenObjectNode>(CompilerComparer.Instance);
private readonly SortedSet<TypeGVMEntriesNode> _typeGVMEntries
= new SortedSet<TypeGVMEntriesNode>(Comparer<TypeGVMEntriesNode>.Create((a, b) => TypeSystemComparer.Instance.Compare(a.AssociatedType, b.AssociatedType)));
private readonly SortedSet<DefType> _typesWithDelegateMarshalling = new SortedSet<DefType>(TypeSystemComparer.Instance);
Expand Down Expand Up @@ -293,11 +293,6 @@ protected virtual void Graph_NewMarkedNode(DependencyNodeCore<NodeFactory> obj)
_frozenObjects.Add(frozenObj);
}

if (obj is FrozenStringNode frozenStr)
{
_frozenObjects.Add(frozenStr);
}

if (obj is GenericStaticBaseInfoNode genericStaticBaseInfo)
{
_typesWithGenericStaticBaseInfo.Add(genericStaticBaseInfo.Type);
Expand Down Expand Up @@ -751,7 +746,7 @@ public IEnumerable<TypeDesc> GetTypeTemplates()
return _typeTemplates;
}

public IEnumerable<EmbeddedObjectNode> GetFrozenObjects()
public IEnumerable<FrozenObjectNode> GetFrozenObjects()
{
return _frozenObjects;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@
<Compile Include="Compiler\DependencyAnalysis\DynamicDependencyAttributesOnEntityNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ExternSymbolsImportedNodeProvider.cs" />
<Compile Include="Compiler\DependencyAnalysis\FieldRvaDataNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\FrozenObjectNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\FunctionPointerMapNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\GenericMethodsHashtableEntryNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\GenericStaticBaseInfoNode.cs" />
Expand Down Expand Up @@ -460,7 +461,7 @@
<Compile Include="Compiler\InlinedThreadStatics.cs" />
<Compile Include="Compiler\MstatObjectDumper.cs" />
<Compile Include="Compiler\NoMetadataBlockingPolicy.cs" />
<Compile Include="Compiler\DependencyAnalysis\FrozenObjectNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\SerializedFrozenObjectNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\GCStaticsPreInitDataNode.cs" />
<Compile Include="Compiler\MetadataBlockingPolicy.cs" />
<Compile Include="Compiler\DependencyAnalysis\MethodMetadataNode.cs" />
Expand Down
Loading

0 comments on commit 712d522

Please sign in to comment.