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

Use static sealed vtable for dynamically created types #79332

Merged
merged 1 commit into from
Dec 7, 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
46 changes: 22 additions & 24 deletions src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,41 +1091,39 @@ private static IntPtr FollowRelativePointer(int* pDist)
return result;
}

internal IntPtr GetSealedVirtualSlot(ushort slotNumber)
#if TYPE_LOADER_IMPLEMENTATION
internal
#else
private
#endif
void* GetSealedVirtualTable()
{
Debug.Assert((RareFlags & EETypeRareFlags.HasSealedVTableEntriesFlag) != 0);

fixed (MethodTable* pThis = &this)
uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
byte* pThis = (byte*)Unsafe.AsPointer(ref this);
if (IsDynamicType || !SupportsRelativePointers)
{
if (IsDynamicType || !SupportsRelativePointers)
{
uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
IntPtr* pSealedVirtualsSlotTable = *(IntPtr**)((byte*)pThis + cbSealedVirtualSlotsTypeOffset);
return pSealedVirtualsSlotTable[slotNumber];
}
else
{
uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
int* pSealedVirtualsSlotTable = (int*)FollowRelativePointer((int*)((byte*)pThis + cbSealedVirtualSlotsTypeOffset));
IntPtr result = FollowRelativePointer(&pSealedVirtualsSlotTable[slotNumber]);
return result;
}
return *(void**)(pThis + cbSealedVirtualSlotsTypeOffset);
}
else
{
return (void*)FollowRelativePointer((int*)(pThis + cbSealedVirtualSlotsTypeOffset));
}
}

#if TYPE_LOADER_IMPLEMENTATION
internal void SetSealedVirtualSlot(IntPtr value, ushort slotNumber)
internal IntPtr GetSealedVirtualSlot(ushort slotNumber)
{
Debug.Assert(IsDynamicType);

fixed (MethodTable* pThis = &this)
void* pSealedVtable = GetSealedVirtualTable();
if (!SupportsRelativePointers)
{
uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
IntPtr* pSealedVirtualsSlotTable = *(IntPtr**)((byte*)pThis + cbSealedVirtualSlotsTypeOffset);
pSealedVirtualsSlotTable[slotNumber] = value;
return ((IntPtr*)pSealedVtable)[slotNumber];
}
else
{
return FollowRelativePointer(&((int*)pSealedVtable)[slotNumber]);
}
}
#endif

internal byte* OptionalFieldsPtr
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,82 +237,76 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo

// Optional fields encoding
int cbOptionalFieldsSize;
OptionalFieldsRuntimeBuilder optionalFields;
{
optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType != null ? pTemplateEEType->OptionalFieldsPtr : null);

uint rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0);
OptionalFieldsRuntimeBuilder optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType->OptionalFieldsPtr);

if (state.NumSealedVTableEntries > 0)
rareFlags |= (uint)EETypeRareFlags.HasSealedVTableEntriesFlag;
uint rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0);

if (state.NonGcDataSize != 0)
rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics;
if (state.NonGcDataSize != 0)
rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics;

if (state.GcDataSize != 0)
rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics;
if (state.GcDataSize != 0)
rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics;

if (state.ThreadDataSize != 0)
rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics;
if (state.ThreadDataSize != 0)
rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics;

#if TARGET_ARM
if (state.FieldAlignment == 8)
rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
else
rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag;
if (state.FieldAlignment == 8)
rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
else
rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag;
#endif

#if TARGET_ARM || TARGET_ARM64
if (state.IsHFA)
rareFlags |= (uint)EETypeRareFlags.IsHFAFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag;
if (state.IsHFA)
rareFlags |= (uint)EETypeRareFlags.IsHFAFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag;
#endif
if (state.HasStaticConstructor)
rareFlags |= (uint)EETypeRareFlags.HasCctorFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag;
if (state.HasStaticConstructor)
rareFlags |= (uint)EETypeRareFlags.HasCctorFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag;

if (isAbstractClass)
rareFlags |= (uint)EETypeRareFlags.IsAbstractClassFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.IsAbstractClassFlag;
if (isAbstractClass)
rareFlags |= (uint)EETypeRareFlags.IsAbstractClassFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.IsAbstractClassFlag;

if (isByRefLike)
rareFlags |= (uint)EETypeRareFlags.IsByRefLikeFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.IsByRefLikeFlag;
if (isByRefLike)
rareFlags |= (uint)EETypeRareFlags.IsByRefLikeFlag;
else
rareFlags &= ~(uint)EETypeRareFlags.IsByRefLikeFlag;

if (isNullable)
{
uint nullableValueOffset = state.NullableValueOffset;
if (isNullable)
{
uint nullableValueOffset = state.NullableValueOffset;

// The stored offset is never zero (Nullable has a boolean there indicating whether the value is valid).
// If the real offset is one, then the field isn't set. Otherwise the offset is encoded - 1 to save space.
if (nullableValueOffset == 1)
optionalFields.ClearField(EETypeOptionalFieldTag.NullableValueOffset);
else
optionalFields.SetFieldValue(EETypeOptionalFieldTag.NullableValueOffset, checked(nullableValueOffset - 1));
}
else
{
// The stored offset is never zero (Nullable has a boolean there indicating whether the value is valid).
// If the real offset is one, then the field isn't set. Otherwise the offset is encoded - 1 to save space.
if (nullableValueOffset == 1)
optionalFields.ClearField(EETypeOptionalFieldTag.NullableValueOffset);
}
else
optionalFields.SetFieldValue(EETypeOptionalFieldTag.NullableValueOffset, checked(nullableValueOffset - 1));
}
else
{
optionalFields.ClearField(EETypeOptionalFieldTag.NullableValueOffset);
}

optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags);
optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags);

// Dispatch map is fetched from template type
optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap);
// Dispatch map is fetched from template type
optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap);

optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding);
optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding);

if (valueTypeFieldPaddingEncoded != 0)
optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded);
if (valueTypeFieldPaddingEncoded != 0)
optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded);

// Compute size of optional fields encoding
cbOptionalFieldsSize = optionalFields.Encode();
Debug.Assert(cbOptionalFieldsSize > 0);
}
// Compute size of optional fields encoding
cbOptionalFieldsSize = optionalFields.Encode();
Debug.Assert(cbOptionalFieldsSize > 0);

// Note: The number of vtable slots on the MethodTable to create is not necessary equal to the number of
// vtable slots on the template type for universal generics (see ComputeVTableLayout)
Expand All @@ -332,7 +326,7 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo
runtimeInterfacesLength,
hasFinalizer,
true,
state.NumSealedVTableEntries > 0,
(rareFlags & (int)EETypeRareFlags.HasSealedVTableEntriesFlag) != 0,
isGeneric,
state.NonGcDataSize != 0,
state.GcDataSize != 0,
Expand Down Expand Up @@ -385,18 +379,10 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo
}

// Copy the sealed vtable entries if they exist on the template type
if (state.NumSealedVTableEntries > 0)
if ((rareFlags & (int)EETypeRareFlags.HasSealedVTableEntriesFlag) != 0)
{
state.HalfBakedSealedVTable = MemoryHelpers.AllocateMemory((int)state.NumSealedVTableEntries * IntPtr.Size);

uint cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
*((IntPtr*)((byte*)pEEType + cbSealedVirtualSlotsTypeOffset)) = state.HalfBakedSealedVTable;

for (ushort i = 0; i < state.NumSealedVTableEntries; i++)
{
IntPtr value = pTemplateEEType->GetSealedVirtualSlot(i);
pEEType->SetSealedVirtualSlot(value, i);
}
*((void**)((byte*)pEEType + cbSealedVirtualSlotsTypeOffset)) = pTemplateEEType->GetSealedVirtualTable();
}

if (MethodTable.SupportsWritableData)
Expand Down Expand Up @@ -455,7 +441,6 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo
state.HalfBakedDictionary = state.Dictionary.Allocate();

Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());
Debug.Assert((state.NumSealedVTableEntries == 0 && state.HalfBakedSealedVTable == IntPtr.Zero) || (state.NumSealedVTableEntries > 0 && state.HalfBakedSealedVTable != IntPtr.Zero));
Debug.Assert((state.Dictionary == null && state.HalfBakedDictionary == IntPtr.Zero) || (state.Dictionary != null && state.HalfBakedDictionary != IntPtr.Zero));

successful = true;
Expand All @@ -466,8 +451,6 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo
{
if (eeTypePtrPlusGCDesc != IntPtr.Zero)
MemoryHelpers.FreeMemory(eeTypePtrPlusGCDesc);
if (state.HalfBakedSealedVTable != IntPtr.Zero)
MemoryHelpers.FreeMemory(state.HalfBakedSealedVTable);
if (state.HalfBakedDictionary != IntPtr.Zero)
MemoryHelpers.FreeMemory(state.HalfBakedDictionary);
if (gcStaticData != IntPtr.Zero)
Expand Down Expand Up @@ -749,7 +732,6 @@ public static RuntimeTypeHandle CreateEEType(TypeDesc type, TypeBuilderState sta
Debug.Assert(false == state.HasStaticConstructor);
Debug.Assert(0 == state.GcDataSize);
Debug.Assert(0 == state.ThreadStaticOffset);
Debug.Assert(0 == state.NumSealedVTableEntries);
Debug.Assert(IntPtr.Zero == state.GcStaticDesc);
Debug.Assert(IntPtr.Zero == state.ThreadStaticDesc);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,6 @@ internal void ParseNativeLayoutInfo(TypeBuilderState state, TypeDesc type)
typeInfoParser.SkipInteger(); // Handled in type layout algorithm
break;

case BagElementKind.SealedVTableEntries:
TypeLoaderLogger.WriteLine("Found BagElementKind.SealedVTableEntries");
state.NumSealedVTableEntries = typeInfoParser.GetUnsigned();
break;

case BagElementKind.DictionaryLayout:
TypeLoaderLogger.WriteLine("Found BagElementKind.DictionaryLayout");
Debug.Assert(!isTemplateUniversalCanon, "Universal template nativelayout do not have DictionaryLayout");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public TypeBuilderState(TypeDesc typeBeingBuilt)

public RuntimeTypeHandle HalfBakedRuntimeTypeHandle;
public IntPtr HalfBakedDictionary;
public IntPtr HalfBakedSealedVTable;

private bool _templateComputed;
private bool _nativeLayoutTokenComputed;
Expand Down Expand Up @@ -344,7 +343,6 @@ public bool HasStaticConstructor
public IntPtr GcStaticDesc;
public IntPtr ThreadStaticDesc;
public uint ThreadStaticOffset;
public uint NumSealedVTableEntries;
public GenericVariance[] GenericVarianceFlags;

// Sentinel static to allow us to initialize _instanceLayout to something
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ enum BagElementKind : uint
ThreadStaticOffset = 0x4a,
FieldLayout = 0x4b,
// unused = 0x4c,
SealedVTableEntries = 0x4d,
// unused = 0x4d,
ClassConstructorPointer = 0x4e,
// unused = 0x4f,
GenericVarianceInfo = 0x50,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1229,16 +1229,6 @@ public override Vertex WriteVertex(NodeFactory factory)
layoutInfo.Append(BagElementKind.BaseType, factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.TypeSignatureVertex(_type.BaseType)).WriteVertex(factory));
}

if (!_type.IsArrayTypeWithoutGenericInterfaces() && ConstructedEETypeNode.CreationAllowed(_type))
{
SealedVTableNode sealedVTable = factory.SealedVTable(_type.ConvertToCanonForm(CanonicalFormKind.Specific));

sealedVTable.BuildSealedVTableSlots(factory, relocsOnly: false /* This is the final emission phase */);

if (sealedVTable.NumSealedVTableEntries > 0)
layoutInfo.AppendUnsigned(BagElementKind.SealedVTableEntries, (uint)sealedVTable.NumSealedVTableEntries);
}

if (_type.GetTypeDefinition().HasVariance || factory.TypeSystemContext.IsGenericArrayInterfaceType(_type))
{
// Runtime casting logic relies on all interface types implemented on arrays
Expand Down