Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove pointer relocs from GC statics #78794

Merged
merged 1 commit into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,14 @@ private static unsafe object[] InitializeStatics(IntPtr gcStaticRegionStart, int
ref object rawSpineData = ref Unsafe.As<byte, object>(ref Unsafe.As<RawArrayData>(spine).Data);

int currentBase = 0;
for (IntPtr* block = (IntPtr*)gcStaticRegionStart; block < (IntPtr*)gcStaticRegionEnd; block++)
for (IntPtr** block = (IntPtr**)gcStaticRegionStart; block < (IntPtr**)gcStaticRegionEnd; block++)
{
// Gc Static regions can be shared by modules linked together during compilation. To ensure each
// is initialized once, the static region pointer is stored with lowest bit set in the image.
// The first time we initialize the static region its pointer is replaced with an object reference
// whose lowest bit is no longer set.
IntPtr* pBlock = (IntPtr*)*block;
nint blockAddr = *pBlock;
IntPtr* pBlock = *block;
nint blockAddr = MethodTable.SupportsRelativePointers ? (nint)ReadRelPtr32(pBlock) : *pBlock;
if ((blockAddr & GCStaticRegionConstants.Uninitialized) == GCStaticRegionConstants.Uninitialized)
{
object? obj = null;
Expand All @@ -215,7 +215,7 @@ private static unsafe object[] InitializeStatics(IntPtr gcStaticRegionStart, int
// which are pointer relocs to GC objects in frozen segment.
// It actually has all GC fields including non-preinitialized fields and we simply copy over the
// entire blob to this object, overwriting everything.
IntPtr pPreInitDataAddr = *(pBlock + 1);
void* pPreInitDataAddr = MethodTable.SupportsRelativePointers ? ReadRelPtr32((int*)pBlock + 1) : (void*)*(pBlock + 1);
RuntimeImports.RhBulkMoveWithWriteBarrier(ref obj.GetRawData(), ref *(byte *)pPreInitDataAddr, obj.GetRawObjectDataSize());
}

Expand All @@ -231,6 +231,9 @@ private static unsafe object[] InitializeStatics(IntPtr gcStaticRegionStart, int
}

return spine;

static void* ReadRelPtr32(void* address)
=> (byte*)address + *(int*)address;
}

private static unsafe void RehydrateData(IntPtr dehydratedData, int length)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace ILCompiler.DependencyAnalysis
public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolNode
{
private readonly MetadataType _type;
private readonly TypePreinit.PreinitializationInfo _preinitializationInfo;
private readonly GCStaticsPreInitDataNode _preinitializationInfo;

public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
Expand All @@ -21,7 +21,10 @@ public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
_type = type;

if (preinitManager.IsPreinitialized(type))
_preinitializationInfo = preinitManager.GetPreinitializationInfo(_type);
{
var info = preinitManager.GetPreinitializationInfo(_type);
_preinitializationInfo = new GCStaticsPreInitDataNode(info);
}
}

protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
Expand All @@ -45,12 +48,6 @@ private ISymbolNode GetGCStaticEETypeNode(NodeFactory factory)
return factory.GCStaticEEType(map);
}

public GCStaticsPreInitDataNode NewPreInitDataNode()
{
Debug.Assert(_preinitializationInfo != null && _preinitializationInfo.IsPreinitialized);
return new GCStaticsPreInitDataNode(_preinitializationInfo);
}

protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
{
DependencyList dependencyList = new DependencyList();
Expand Down Expand Up @@ -79,19 +76,37 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);

// Even though we're only generating 32-bit relocs here (if SupportsRelativePointers),
// align the blob at pointer boundary since at runtime we're going to write a pointer in here.
builder.RequireInitialPointerAlignment();

int delta = GCStaticRegionConstants.Uninitialized;

// Set the flag that indicates next pointer following MethodTable is the preinit data
bool isPreinitialized = _preinitializationInfo != null && _preinitializationInfo.IsPreinitialized;
bool isPreinitialized = _preinitializationInfo != null;
if (isPreinitialized)
delta |= GCStaticRegionConstants.HasPreInitializedData;

builder.EmitPointerReloc(GetGCStaticEETypeNode(factory), delta);
if (factory.Target.SupportsRelativePointers)
builder.EmitReloc(GetGCStaticEETypeNode(factory), RelocType.IMAGE_REL_BASED_RELPTR32, delta);
else
builder.EmitPointerReloc(GetGCStaticEETypeNode(factory), delta);

if (isPreinitialized)
builder.EmitPointerReloc(factory.GCStaticsPreInitDataNode(_type));
{
if (factory.Target.SupportsRelativePointers)
builder.EmitReloc(_preinitializationInfo, RelocType.IMAGE_REL_BASED_RELPTR32);
else
builder.EmitPointerReloc(_preinitializationInfo);
}
else if (factory.Target.SupportsRelativePointers && factory.Target.PointerSize == 8)
{
// At runtime, we replace the EEType pointer with a full pointer to the data on the GC
// heap. If the EEType pointer was 32-bit relative, and we don't have a 32-bit relative
// pointer to the preinit data following it, and the pointer size on the target
// machine is 8, we need to emit additional 4 bytes to make room for the full pointer.
builder.EmitZeros(4);
}

builder.AddSymbol(this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,6 @@ private void CreateNodeCaches()
}
});

_GCStaticsPreInitDataNodes = new NodeCache<MetadataType, GCStaticsPreInitDataNode>((MetadataType type) =>
{
ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type);
Debug.Assert(gcStaticsNode is GCStaticsNode);
return ((GCStaticsNode)gcStaticsNode).NewPreInitDataNode();
});

_GCStaticIndirectionNodes = new NodeCache<MetadataType, EmbeddedObjectNode>((MetadataType type) =>
{
ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type);
Expand Down Expand Up @@ -627,13 +620,6 @@ public ISortableSymbolNode TypeGCStaticsSymbol(MetadataType type)
return _GCStatics.GetOrAdd(type);
}

private NodeCache<MetadataType, GCStaticsPreInitDataNode> _GCStaticsPreInitDataNodes;

public GCStaticsPreInitDataNode GCStaticsPreInitDataNode(MetadataType type)
{
return _GCStaticsPreInitDataNodes.GetOrAdd(type);
}

private NodeCache<MetadataType, EmbeddedObjectNode> _GCStaticIndirectionNodes;

public EmbeddedObjectNode GCStaticIndirection(MetadataType type)
Expand Down