Skip to content

Commit

Permalink
Remove pointer relocs from GC statics (#78794)
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalStrehovsky authored Nov 24, 2022
1 parent 78b3f9d commit 8606a91
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 29 deletions.
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

0 comments on commit 8606a91

Please sign in to comment.