From c953ca1703f60b1cbe1e2315b4721448065f5912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 9 Dec 2022 15:17:40 +0900 Subject: [PATCH 1/2] Only create MethodTable optional fields when needed Noticed a difference between statically built and dynamically built `MethodTable` for `int*[]`. --- .../Internal/Runtime/TypeLoader/EETypeCreator.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs index f9b419a5d8c124..13b4fff7153553 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs @@ -217,14 +217,14 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo if (state.ThreadDataSize != 0) rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics; - optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags); + if (rareFlags != 0) + optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags); // Dispatch map is fetched from template type optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap); // 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) @@ -243,7 +243,7 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo numVtableSlots, runtimeInterfacesLength, hasFinalizer, - true, + cbOptionalFieldsSize > 0, (rareFlags & (int)EETypeRareFlags.HasSealedVTableEntriesFlag) != 0, isGeneric, allocatedNonGCDataSize != 0, @@ -278,10 +278,11 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo Debug.Assert(pEEType->HasGCPointers == (cbGCDesc != 0)); // Copy the encoded optional fields buffer to the newly allocated memory, and update the OptionalFields field on the MethodTable - // It is important to set the optional fields first on the newly created MethodTable, because all other 'setters' - // will assert that the type is dynamic, just to make sure we are not making any changes to statically compiled types - pEEType->OptionalFieldsPtr = (byte*)pEEType + cbEEType; - optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize); + if (cbOptionalFieldsSize > 0) + { + pEEType->OptionalFieldsPtr = (byte*)pEEType + cbEEType; + optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize); + } // Copy VTable entries from template type IntPtr* pVtable = (IntPtr*)((byte*)pEEType + sizeof(MethodTable)); From ecf5f0d8ea866b088a8c9a7924142ea1caa72ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 9 Dec 2022 18:13:29 +0900 Subject: [PATCH 2/2] Hmm --- .../src/Internal/Runtime/MethodTable.cs | 24 ++++++++++++------- .../Runtime/TypeLoader/EETypeCreator.cs | 4 ++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs index 0f3393241e4b59..dea7300358734b 100644 --- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs +++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs @@ -858,10 +858,13 @@ internal bool HasDispatchMap if (NumInterfaces == 0) return false; byte* optionalFields = OptionalFieldsPtr; - if (optionalFields == null) - return false; - uint idxDispatchMap = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.DispatchMap, 0xffffffff); - if (idxDispatchMap == 0xffffffff) + + const uint NoDispatchMap = 0xffffffff; + uint idxDispatchMap = NoDispatchMap; + if (optionalFields != null) + idxDispatchMap = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.DispatchMap, NoDispatchMap); + + if (idxDispatchMap == NoDispatchMap) { if (IsDynamicType) return DynamicTemplateType->HasDispatchMap; @@ -878,12 +881,15 @@ internal DispatchMap* DispatchMap if (NumInterfaces == 0) return null; byte* optionalFields = OptionalFieldsPtr; - if (optionalFields == null) - return null; - uint idxDispatchMap = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.DispatchMap, 0xffffffff); - if (idxDispatchMap == 0xffffffff && IsDynamicType) + const uint NoDispatchMap = 0xffffffff; + uint idxDispatchMap = NoDispatchMap; + if (optionalFields != null) + idxDispatchMap = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.DispatchMap, NoDispatchMap); + if (idxDispatchMap == NoDispatchMap) { - return DynamicTemplateType->DispatchMap; + if (IsDynamicType) + return DynamicTemplateType->DispatchMap; + return null; } if (SupportsRelativePointers) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs index 13b4fff7153553..4e36b395a2a47c 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs @@ -226,6 +226,10 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo // Compute size of optional fields encoding cbOptionalFieldsSize = optionalFields.Encode(); + // Clear the optional fields flag. We'll set it if we set optional fields later in this method. + if (cbOptionalFieldsSize == 0) + flags &= ~(uint)EETypeFlags.OptionalFieldsFlag; + // 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) ushort numVtableSlots = state.NumVTableSlots;