Skip to content

Commit 7cb32e1

Browse files
Shuffle MethodTable flags (#106182)
* Move IsByRefLikeFlag from RareFlags to ExtendedFlags * Generic param count to BaseSize * Replace RareFlags with ETF_DynamicTypeFlags * Move ValueTypeFieldPadding * Move NullableValueOffset * GC.Collect --------- Co-authored-by: Filip Navara <filip.navara@gmail.com>
1 parent fb8ae3e commit 7cb32e1

File tree

16 files changed

+219
-840
lines changed

16 files changed

+219
-840
lines changed

src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs

Lines changed: 40 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -146,31 +146,6 @@ private unsafe struct RelatedTypeUnion
146146
public MethodTable* _pRelatedParameterType;
147147
}
148148

149-
private static unsafe class OptionalFieldsReader
150-
{
151-
internal static uint GetInlineField(byte* pFields, EETypeOptionalFieldTag eTag, uint uiDefaultValue)
152-
{
153-
if (pFields == null)
154-
return uiDefaultValue;
155-
156-
bool isLastField = false;
157-
while (!isLastField)
158-
{
159-
byte fieldHeader = NativePrimitiveDecoder.ReadUInt8(ref pFields);
160-
isLastField = (fieldHeader & 0x80) != 0;
161-
EETypeOptionalFieldTag eCurrentTag = (EETypeOptionalFieldTag)(fieldHeader & 0x7f);
162-
uint uiCurrentValue = NativePrimitiveDecoder.DecodeUnsigned(ref pFields);
163-
164-
// If we found a tag match return the current value.
165-
if (eCurrentTag == eTag)
166-
return uiCurrentValue;
167-
}
168-
169-
// Reached end of stream without getting a match. Field is not present so return default value.
170-
return uiDefaultValue;
171-
}
172-
}
173-
174149
/// <summary>
175150
/// Gets a value indicating whether the statically generated data structures use relative pointers.
176151
/// </summary>
@@ -200,17 +175,6 @@ internal static bool SupportsRelativePointers
200175

201176
// vtable follows
202177

203-
// These masks and paddings have been chosen so that the ValueTypePadding field can always fit in a byte of data.
204-
// if the alignment is 8 bytes or less. If the alignment is higher then there may be a need for more bits to hold
205-
// the rest of the padding data.
206-
// If paddings of greater than 7 bytes are necessary, then the high bits of the field represent that padding
207-
private const uint ValueTypePaddingLowMask = 0x7;
208-
private const uint ValueTypePaddingHighMask = 0xFFFFFF00;
209-
private const uint ValueTypePaddingMax = 0x07FFFFFF;
210-
private const int ValueTypePaddingHighShift = 8;
211-
private const uint ValueTypePaddingAlignmentMask = 0xF8;
212-
private const int ValueTypePaddingAlignmentShift = 3;
213-
214178
internal bool HasComponentSize
215179
{
216180
get
@@ -255,13 +219,13 @@ internal ushort GenericParameterCount
255219
get
256220
{
257221
Debug.Assert(IsGenericTypeDefinition);
258-
return ComponentSize;
222+
return (ushort)_uBaseSize;
259223
}
260224
#if TYPE_LOADER_IMPLEMENTATION
261225
set
262226
{
263227
Debug.Assert(IsGenericTypeDefinition);
264-
ComponentSize = value;
228+
_uBaseSize = value;
265229
}
266230
#endif
267231
}
@@ -376,14 +340,6 @@ private EETypeKind Kind
376340
}
377341
}
378342

379-
internal bool HasOptionalFields
380-
{
381-
get
382-
{
383-
return (_uFlags & (uint)EETypeFlags.OptionalFieldsFlag) != 0;
384-
}
385-
}
386-
387343
// Mark or determine that a type is generic and one or more of it's type parameters is co- or
388344
// contra-variant. This only applies to interface and delegate types.
389345
internal bool HasGenericVariance
@@ -618,7 +574,7 @@ internal bool IsByRefLike
618574
{
619575
get
620576
{
621-
return (RareFlags & EETypeRareFlags.IsByRefLikeFlag) != 0;
577+
return IsValueType && (_uFlags & (uint)EETypeFlagsEx.IsByRefLikeFlag) != 0;
622578
}
623579
}
624580

@@ -809,19 +765,8 @@ internal uint ValueTypeFieldPadding
809765
{
810766
get
811767
{
812-
byte* optionalFields = OptionalFieldsPtr;
813-
814-
// If there are no optional fields then the padding must have been the default, 0.
815-
if (optionalFields == null)
816-
return 0;
817-
818-
// Get the value from the optional fields. The default is zero if that particular field was not included.
819-
// The low bits of this field is the ValueType field padding, the rest of the byte is the alignment if present
820-
uint ValueTypeFieldPaddingData = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.ValueTypeFieldPadding, 0);
821-
uint padding = ValueTypeFieldPaddingData & ValueTypePaddingLowMask;
822-
// If there is additional padding, the other bits have that data
823-
padding |= (ValueTypeFieldPaddingData & ValueTypePaddingHighMask) >> (ValueTypePaddingHighShift - ValueTypePaddingAlignmentShift);
824-
return padding;
768+
Debug.Assert(IsValueType);
769+
return (_uFlags & (uint)EETypeFlagsEx.ValueTypeFieldPaddingMask) >> ValueTypeFieldPaddingConsts.Shift;
825770
}
826771
}
827772

@@ -956,17 +901,8 @@ internal byte NullableValueOffset
956901
get
957902
{
958903
Debug.Assert(IsNullable);
959-
960-
// Grab optional fields. If there aren't any then the offset was the default of 1 (immediately after the
961-
// Nullable's boolean flag).
962-
byte* optionalFields = OptionalFieldsPtr;
963-
if (optionalFields == null)
964-
return 1;
965-
966-
// The offset is never zero (Nullable has a boolean there indicating whether the value is valid). So the
967-
// offset is encoded - 1 to save space. The zero below is the default value if the field wasn't encoded at
968-
// all.
969-
return (byte)(OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.NullableValueOffset, 0) + 1);
904+
int log2valueoffset = (int)(_uFlags & (ushort)EETypeFlagsEx.NullableValueOffsetMask) >> NullableValueOffsetConsts.Shift;
905+
return (byte)(1 << log2valueoffset);
970906
}
971907
}
972908

@@ -1033,32 +969,6 @@ internal IntPtr GetSealedVirtualSlot(ushort slotNumber)
1033969
}
1034970
}
1035971

1036-
internal byte* OptionalFieldsPtr
1037-
{
1038-
get
1039-
{
1040-
if (!HasOptionalFields)
1041-
return null;
1042-
1043-
uint offset = GetFieldOffset(EETypeField.ETF_OptionalFieldsPtr);
1044-
1045-
if (IsDynamicType || !SupportsRelativePointers)
1046-
return GetField<Pointer<byte>>(offset).Value;
1047-
1048-
return GetField<RelativePointer<byte>>(offset).Value;
1049-
}
1050-
#if TYPE_LOADER_IMPLEMENTATION
1051-
set
1052-
{
1053-
Debug.Assert(IsDynamicType);
1054-
1055-
_uFlags |= (uint)EETypeFlags.OptionalFieldsFlag;
1056-
1057-
GetField<IntPtr>(EETypeField.ETF_OptionalFieldsPtr) = (IntPtr)value;
1058-
}
1059-
#endif
1060-
}
1061-
1062972
internal MethodTable* DynamicTemplateType
1063973
{
1064974
get
@@ -1079,21 +989,21 @@ internal bool IsDynamicTypeWithCctor
1079989
{
1080990
get
1081991
{
1082-
return (RareFlags & EETypeRareFlags.IsDynamicTypeWithLazyCctor) != 0;
992+
return (DynamicTypeFlags & DynamicTypeFlags.HasLazyCctor) != 0;
1083993
}
1084994
}
1085995

1086996
internal IntPtr DynamicGcStaticsData
1087997
{
1088998
get
1089999
{
1090-
Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
1000+
Debug.Assert((DynamicTypeFlags & DynamicTypeFlags.HasGCStatics) != 0);
10911001
return GetField<IntPtr>(EETypeField.ETF_DynamicGcStatics);
10921002
}
10931003
#if TYPE_LOADER_IMPLEMENTATION
10941004
set
10951005
{
1096-
Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
1006+
Debug.Assert((DynamicTypeFlags & DynamicTypeFlags.HasGCStatics) != 0);
10971007
GetField<IntPtr>(EETypeField.ETF_DynamicGcStatics) = value;
10981008
}
10991009
#endif
@@ -1103,13 +1013,13 @@ internal IntPtr DynamicNonGcStaticsData
11031013
{
11041014
get
11051015
{
1106-
Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0);
1016+
Debug.Assert((DynamicTypeFlags & DynamicTypeFlags.HasNonGCStatics) != 0);
11071017
return GetField<IntPtr>(EETypeField.ETF_DynamicNonGcStatics);
11081018
}
11091019
#if TYPE_LOADER_IMPLEMENTATION
11101020
set
11111021
{
1112-
Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0);
1022+
Debug.Assert((DynamicTypeFlags & DynamicTypeFlags.HasNonGCStatics) != 0);
11131023
GetField<IntPtr>(EETypeField.ETF_DynamicNonGcStatics) = value;
11141024
}
11151025
#endif
@@ -1119,13 +1029,13 @@ internal IntPtr DynamicThreadStaticsIndex
11191029
{
11201030
get
11211031
{
1122-
Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithThreadStatics) != 0);
1032+
Debug.Assert((DynamicTypeFlags & DynamicTypeFlags.HasThreadStatics) != 0);
11231033
return GetField<IntPtr>(EETypeField.ETF_DynamicThreadStaticOffset);
11241034
}
11251035
#if TYPE_LOADER_IMPLEMENTATION
11261036
set
11271037
{
1128-
Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithThreadStatics) != 0);
1038+
Debug.Assert((DynamicTypeFlags & DynamicTypeFlags.HasThreadStatics) != 0);
11291039
GetField<IntPtr>(EETypeField.ETF_DynamicThreadStaticOffset) = value;
11301040
}
11311041
#endif
@@ -1191,37 +1101,20 @@ internal void* WritableData
11911101
#endif
11921102
}
11931103

1194-
internal unsafe EETypeRareFlags RareFlags
1104+
internal DynamicTypeFlags DynamicTypeFlags
11951105
{
11961106
get
11971107
{
1198-
// If there are no optional fields then none of the rare flags have been set.
1199-
// Get the flags from the optional fields. The default is zero if that particular field was not included.
1200-
return HasOptionalFields ? (EETypeRareFlags)OptionalFieldsReader.GetInlineField(OptionalFieldsPtr, EETypeOptionalFieldTag.RareFlags, 0) : 0;
1108+
Debug.Assert(IsDynamicType);
1109+
return (DynamicTypeFlags)GetField<nint>(EETypeField.ETF_DynamicTypeFlags);
12011110
}
1202-
}
1203-
1204-
internal int FieldAlignmentRequirement
1205-
{
1206-
get
1111+
#if TYPE_LOADER_IMPLEMENTATION
1112+
set
12071113
{
1208-
byte* optionalFields = OptionalFieldsPtr;
1209-
1210-
// If there are no optional fields then the alignment must have been the default, IntPtr.Size.
1211-
// (This happens for all reference types, and for valuetypes with default alignment and no padding)
1212-
if (optionalFields == null)
1213-
return IntPtr.Size;
1214-
1215-
// Get the value from the optional fields. The default is zero if that particular field was not included.
1216-
// The low bits of this field is the ValueType field padding, the rest of the value is the alignment if present
1217-
uint alignmentValue = (OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.ValueTypeFieldPadding, 0) & ValueTypePaddingAlignmentMask) >> ValueTypePaddingAlignmentShift;
1218-
1219-
// Alignment is stored as 1 + the log base 2 of the alignment, except a 0 indicates standard pointer alignment.
1220-
if (alignmentValue == 0)
1221-
return IntPtr.Size;
1222-
else
1223-
return 1 << ((int)alignmentValue - 1);
1114+
Debug.Assert(IsDynamicType);
1115+
GetField<nint>(EETypeField.ETF_DynamicTypeFlags) = (nint)value;
12241116
}
1117+
#endif
12251118
}
12261119

12271120
internal EETypeElementType ElementType
@@ -1283,15 +1176,6 @@ public uint GetFieldOffset(EETypeField eField)
12831176
if (IsFinalizable)
12841177
cbOffset += relativeOrFullPointerOffset;
12851178

1286-
// Followed by the pointer to the optional fields.
1287-
if (eField == EETypeField.ETF_OptionalFieldsPtr)
1288-
{
1289-
Debug.Assert(HasOptionalFields);
1290-
return cbOffset;
1291-
}
1292-
if (HasOptionalFields)
1293-
cbOffset += relativeOrFullPointerOffset;
1294-
12951179
// Followed by the pointer to the sealed virtual slots
12961180
if (eField == EETypeField.ETF_SealedVirtualSlots)
12971181
return cbOffset;
@@ -1338,26 +1222,37 @@ public uint GetFieldOffset(EETypeField eField)
13381222
if (IsDynamicType)
13391223
cbOffset += (uint)IntPtr.Size;
13401224

1341-
EETypeRareFlags rareFlags = RareFlags;
1225+
DynamicTypeFlags dynamicTypeFlags = 0;
1226+
if (eField == EETypeField.ETF_DynamicTypeFlags)
1227+
{
1228+
Debug.Assert(IsDynamicType);
1229+
return cbOffset;
1230+
}
1231+
if (IsDynamicType)
1232+
{
1233+
dynamicTypeFlags = (DynamicTypeFlags)GetField<nint>(cbOffset);
1234+
cbOffset += (uint)IntPtr.Size;
1235+
}
1236+
13421237
if (eField == EETypeField.ETF_DynamicGcStatics)
13431238
{
1344-
Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
1239+
Debug.Assert((dynamicTypeFlags & DynamicTypeFlags.HasGCStatics) != 0);
13451240
return cbOffset;
13461241
}
1347-
if ((rareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0)
1242+
if ((dynamicTypeFlags & DynamicTypeFlags.HasGCStatics) != 0)
13481243
cbOffset += (uint)IntPtr.Size;
13491244

13501245
if (eField == EETypeField.ETF_DynamicNonGcStatics)
13511246
{
1352-
Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0);
1247+
Debug.Assert((dynamicTypeFlags & DynamicTypeFlags.HasNonGCStatics) != 0);
13531248
return cbOffset;
13541249
}
1355-
if ((rareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0)
1250+
if ((dynamicTypeFlags & DynamicTypeFlags.HasNonGCStatics) != 0)
13561251
cbOffset += (uint)IntPtr.Size;
13571252

13581253
if (eField == EETypeField.ETF_DynamicThreadStaticOffset)
13591254
{
1360-
Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithThreadStatics) != 0);
1255+
Debug.Assert((dynamicTypeFlags & DynamicTypeFlags.HasThreadStatics) != 0);
13611256
return cbOffset;
13621257
}
13631258

@@ -1383,7 +1278,6 @@ internal static uint GetSizeofEEType(
13831278
ushort cInterfaces,
13841279
bool fHasDispatchMap,
13851280
bool fHasFinalizer,
1386-
bool fRequiresOptionalFields,
13871281
bool fHasSealedVirtuals,
13881282
bool fHasGenericInfo,
13891283
int cFunctionPointerTypeParameters,
@@ -1398,10 +1292,10 @@ internal static uint GetSizeofEEType(
13981292
sizeof(IntPtr) + // WritableData
13991293
(fHasDispatchMap ? sizeof(UIntPtr) : 0) +
14001294
(fHasFinalizer ? sizeof(UIntPtr) : 0) +
1401-
(fRequiresOptionalFields ? sizeof(IntPtr) : 0) +
14021295
(fHasSealedVirtuals ? sizeof(IntPtr) : 0) +
14031296
cFunctionPointerTypeParameters * sizeof(IntPtr) +
14041297
(fHasGenericInfo ? sizeof(IntPtr) * 2 : 0) + // pointers to GenericDefinition and GenericComposition
1298+
sizeof(IntPtr) + // dynamic type flags
14051299
(fHasNonGcStatics ? sizeof(IntPtr) : 0) + // pointer to data
14061300
(fHasGcStatics ? sizeof(IntPtr) : 0) + // pointer to data
14071301
(fHasThreadStatics ? sizeof(IntPtr) : 0)); // threadstatic index cell

src/coreclr/nativeaot/Runtime/inc/MethodTable.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ enum EETypeField
6363
ETF_TypeManagerIndirection,
6464
ETF_WritableData,
6565
ETF_Finalizer,
66-
ETF_OptionalFieldsPtr,
6766
ETF_SealedVirtualSlots,
6867
ETF_DynamicTemplateType,
6968
ETF_GenericDefinition,
@@ -126,9 +125,6 @@ class MethodTable
126125
// simplified version of MethodTable. See LimitedEEType definition below.
127126
EETypeKindMask = 0x00030000,
128127

129-
// This type has optional fields present.
130-
OptionalFieldsFlag = 0x00040000,
131-
132128
// GC depends on this bit, this bit must be zero
133129
CollectibleFlag = 0x00200000,
134130

@@ -162,6 +158,9 @@ class MethodTable
162158
HasCriticalFinalizerFlag = 0x0002,
163159
IsTrackedReferenceWithFinalizerFlag = 0x0004,
164160

161+
// This MethodTable is for a Byref-like class (TypedReference, Span<T>, ...)
162+
IsByRefLikeFlag = 0x0010,
163+
165164
// This type requires 8-byte alignment for its fields on certain platforms (ARM32, WASM)
166165
RequiresAlign8Flag = 0x1000
167166
};

0 commit comments

Comments
 (0)