Shuffle some `MethodTable` flags (#85634)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Wed, 3 May 2023 07:05:50 +0000 (16:05 +0900)
committerGitHub <noreply@github.com>
Wed, 3 May 2023 07:05:50 +0000 (16:05 +0900)
* `IDynamicInterfaceCastableFlag` cannot be set on types that have a component size, so move it from the valuable location in `Flags` to `FlagsEx`.
* Move `HasSealedVTableEntriesFlag` from rare flags to flags. This flag is not so rare. All async state machine types set it, for example.
* Delete `IsAbstractClassFlag`. This was introduce in .NET Native for `GetUninitializedObject` since accessing `Type.IsAbstract` could trigger a `MissingMetadataException` there. We got rid of that concept in NativeAOT because it cannot be reconciled with ILLink trimming. Rewrite the code to use `Type.IsAbstract`.

Saves 15 kB on BasicMinimalApis, which is nice. Also makes things faster since we avoid reading optional fields and rare flags.

src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs
src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs
src/coreclr/tools/Common/Internal/Runtime/MethodTable.Constants.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs

index 76dbab0d94ec496e6038c268c20e175759cd274e..a6897c8b11ba257e3005b47aef88f7a1a509642f 100644 (file)
@@ -619,14 +619,6 @@ namespace Internal.Runtime
             }
         }
 
-        internal bool IsAbstract
-        {
-            get
-            {
-                return IsInterface || (RareFlags & EETypeRareFlags.IsAbstractClassFlag) != 0;
-            }
-        }
-
         internal bool IsByRefLike
         {
             get
@@ -753,7 +745,7 @@ namespace Internal.Runtime
         {
             get
             {
-                return ((_uFlags & (uint)EETypeFlags.IDynamicInterfaceCastableFlag) != 0);
+                return ((ExtendedFlags & (ushort)EETypeFlagsEx.IDynamicInterfaceCastableFlag) != 0);
             }
         }
 
@@ -774,6 +766,14 @@ namespace Internal.Runtime
             }
         }
 
+        internal bool HasSealedVTableEntries
+        {
+            get
+            {
+                return (_uFlags & (uint)EETypeFlags.HasSealedVTableEntriesFlag) != 0;
+            }
+        }
+
         internal bool ContainsGCPointers
         {
             get
@@ -1044,7 +1044,7 @@ namespace Internal.Runtime
 #endif
         void* GetSealedVirtualTable()
         {
-            Debug.Assert((RareFlags & EETypeRareFlags.HasSealedVTableEntriesFlag) != 0);
+            Debug.Assert(HasSealedVTableEntries);
 
             uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
             byte* pThis = (byte*)Unsafe.AsPointer(ref this);
@@ -1367,10 +1367,8 @@ namespace Internal.Runtime
             if (eField == EETypeField.ETF_SealedVirtualSlots)
                 return cbOffset;
 
-            EETypeRareFlags rareFlags = RareFlags;
-
             // in the case of sealed vtable entries on static types, we have a UInt sized relative pointer
-            if ((rareFlags & EETypeRareFlags.HasSealedVTableEntriesFlag) != 0)
+            if (HasSealedVTableEntries)
                 cbOffset += relativeOrFullPointerOffset;
 
             if (eField == EETypeField.ETF_GenericDefinition)
@@ -1411,6 +1409,7 @@ namespace Internal.Runtime
             if (IsDynamicType)
                 cbOffset += (uint)IntPtr.Size;
 
+            EETypeRareFlags rareFlags = RareFlags;
             if (eField == EETypeField.ETF_DynamicGcStatics)
             {
                 Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
index 1048c76d583a0689e463a32e14a752bc56cc7501..bcbc4008351d0a436fba096184bb9be9edebf069 100644 (file)
@@ -304,7 +304,7 @@ namespace System.Runtime.CompilerServices
                 throw new SerializationException(SR.Format(SR.Serialization_InvalidType, type));
             }
 
-            if (type.HasElementType || type.IsGenericParameter)
+            if (type.HasElementType || type.IsGenericParameter || type.IsFunctionPointer)
             {
                 throw new ArgumentException(SR.Argument_InvalidValue);
             }
@@ -319,6 +319,11 @@ namespace System.Runtime.CompilerServices
                 throw new NotSupportedException(SR.NotSupported_ManagedActivation);
             }
 
+            if (type.IsAbstract)
+            {
+                throw new MemberAccessException(SR.Acc_CreateAbst);
+            }
+
             MethodTable* mt = type.TypeHandle.ToMethodTable();
 
             if (mt->ElementType == Internal.Runtime.EETypeElementType.Void)
@@ -337,11 +342,6 @@ namespace System.Runtime.CompilerServices
                 throw new MemberAccessException();
             }
 
-            if (mt->IsAbstract)
-            {
-                throw new MemberAccessException(SR.Acc_CreateAbst);
-            }
-
             if (mt->IsByRefLike)
             {
                 throw new NotSupportedException(SR.NotSupported_ByRefLike);
index 67f633e53dc4265087d2a91ef73eb0801f6ab977..0509ea7217f9603823bb6472326e6e38f96b33fc 100644 (file)
@@ -159,6 +159,7 @@ namespace Internal.Runtime.TypeLoader
                 bool isNullable;
                 bool isArray;
                 bool isGeneric;
+                bool hasSealedVTable;
                 uint flags;
                 ushort runtimeInterfacesLength = 0;
                 IntPtr typeManager = IntPtr.Zero;
@@ -175,6 +176,7 @@ namespace Internal.Runtime.TypeLoader
                 flags = pTemplateEEType->Flags;
                 isArray = pTemplateEEType->IsArray;
                 isGeneric = pTemplateEEType->IsGeneric;
+                hasSealedVTable = pTemplateEEType->HasSealedVTableEntries;
                 typeManager = pTemplateEEType->PointerToTypeManager;
                 Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength);
 
@@ -251,7 +253,7 @@ namespace Internal.Runtime.TypeLoader
                         runtimeInterfacesLength,
                         hasFinalizer,
                         cbOptionalFieldsSize > 0,
-                        (rareFlags & (int)EETypeRareFlags.HasSealedVTableEntriesFlag) != 0,
+                        hasSealedVTable,
                         isGeneric,
                         numFunctionPointerTypeParameters,
                         allocatedNonGCDataSize != 0,
@@ -306,7 +308,7 @@ namespace Internal.Runtime.TypeLoader
                 }
 
                 // Copy the sealed vtable entries if they exist on the template type
-                if ((rareFlags & (int)EETypeRareFlags.HasSealedVTableEntriesFlag) != 0)
+                if (hasSealedVTable)
                 {
                     uint cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
                     *((void**)((byte*)pEEType + cbSealedVirtualSlotsTypeOffset)) = pTemplateEEType->GetSealedVirtualTable();
index 914b44d7df76c6d13d7fc1ebc0773414d0da6b1b..d61d2d41d427ef13af96f06d62c8190ec6421890 100644 (file)
@@ -123,6 +123,11 @@ namespace Internal.Runtime
                 flagsEx |= (ushort)EETypeFlagsEx.IsTrackedReferenceWithFinalizerFlag;
             }
 
+            if (type.IsIDynamicInterfaceCastable)
+            {
+                flagsEx |= (ushort)EETypeFlagsEx.IDynamicInterfaceCastableFlag;
+            }
+
             return flagsEx;
         }
 
index 10edf5bf58ccf258bf701aec80e151b02f9453fa..29a1044f2c80686307890974273255555f655edf 100644 (file)
@@ -34,9 +34,9 @@ namespace Internal.Runtime
         HasPointersFlag = 0x00200000,
 
         /// <summary>
-        /// This type implements IDynamicInterfaceCastable to allow dynamic resolution of interface casts.
+        /// This MethodTable has sealed vtable entries
         /// </summary>
-        IDynamicInterfaceCastableFlag = 0x00400000,
+        HasSealedVTableEntriesFlag = 0x00400000,
 
         /// <summary>
         /// This type is generic and one or more of its type parameters is co- or contra-variant. This
@@ -81,6 +81,11 @@ namespace Internal.Runtime
         HasEagerFinalizerFlag = 0x0001,
         HasCriticalFinalizerFlag = 0x0002,
         IsTrackedReferenceWithFinalizerFlag = 0x0004,
+
+        /// <summary>
+        /// This type implements IDynamicInterfaceCastable to allow dynamic resolution of interface casts.
+        /// </summary>
+        IDynamicInterfaceCastableFlag = 0x0008,
     }
 
     internal enum EETypeKind : uint
@@ -140,10 +145,7 @@ namespace Internal.Runtime
         /// </summary>
         IsHFAFlag = 0x00000100,
 
-        /// <summary>
-        /// This MethodTable has sealed vtable entries
-        /// </summary>
-        HasSealedVTableEntriesFlag = 0x00000200,
+        // Unused = 0x00000200,
 
         /// <summary>
         /// This dynamically created types has gc statics
@@ -162,10 +164,7 @@ namespace Internal.Runtime
 
         // UNUSED = 0x00002000,
 
-        /// <summary>
-        /// This MethodTable is an abstract class (but not an interface).
-        /// </summary>
-        IsAbstractClassFlag = 0x00004000,
+        // UNUSED = 0x00004000,
 
         /// <summary>
         /// This MethodTable is for a Byref-like class (TypedReference, Span&lt;T&gt;,...)
index 6b019dfa88b9c5a38de59d91dab1dd24912ea081..01cde356ab263e3e27c741377b5f87edb57dcfbe 100644 (file)
@@ -648,7 +648,7 @@ namespace ILCompiler.DependencyAnalysis
             ComputeOptionalEETypeFields(factory, relocsOnly);
 
             OutputGCDesc(ref objData);
-            OutputFlags(factory, ref objData);
+            OutputFlags(factory, ref objData, relocsOnly);
             objData.EmitInt(BaseSize);
             OutputRelatedType(factory, ref objData);
 
@@ -715,7 +715,7 @@ namespace ILCompiler.DependencyAnalysis
             Debug.Assert(GCDescSize == 0);
         }
 
-        private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData)
+        private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData, bool relocsOnly)
         {
             uint flags = EETypeBuilderHelpers.ComputeFlags(_type);
 
@@ -733,9 +733,11 @@ namespace ILCompiler.DependencyAnalysis
                 flags |= (uint)EETypeFlags.GenericVarianceFlag;
             }
 
-            if (_type.IsIDynamicInterfaceCastable)
+            if (EmitVirtualSlotsAndInterfaces && !_type.IsArrayTypeWithoutGenericInterfaces())
             {
-                flags |= (uint)EETypeFlags.IDynamicInterfaceCastableFlag;
+                SealedVTableNode sealedVTable = factory.SealedVTable(_type.ConvertToCanonForm(CanonicalFormKind.Specific));
+                if (sealedVTable.BuildSealedVTableSlots(factory, relocsOnly) && sealedVTable.NumSealedVTableEntries > 0)
+                    flags |= (uint)EETypeFlags.HasSealedVTableEntriesFlag;
             }
 
             if (HasOptionalFields)
@@ -1209,12 +1211,12 @@ namespace ILCompiler.DependencyAnalysis
                 _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.DispatchMap, checked((uint)factory.InterfaceDispatchMapIndirection(canonType).IndexFromBeginningOfArray));
             }
 
-            ComputeRareFlags(factory, relocsOnly);
+            ComputeRareFlags(factory);
             ComputeNullableValueOffset();
             ComputeValueTypeFieldPadding();
         }
 
-        private void ComputeRareFlags(NodeFactory factory, bool relocsOnly)
+        private void ComputeRareFlags(NodeFactory factory)
         {
             uint flags = 0;
 
@@ -1239,23 +1241,11 @@ namespace ILCompiler.DependencyAnalysis
                 flags |= (uint)EETypeRareFlags.IsHFAFlag;
             }
 
-            if (metadataType != null && !_type.IsInterface && metadataType.IsAbstract)
-            {
-                flags |= (uint)EETypeRareFlags.IsAbstractClassFlag;
-            }
-
             if (_type.IsByRefLike)
             {
                 flags |= (uint)EETypeRareFlags.IsByRefLikeFlag;
             }
 
-            if (EmitVirtualSlotsAndInterfaces && !_type.IsArrayTypeWithoutGenericInterfaces())
-            {
-                SealedVTableNode sealedVTable = factory.SealedVTable(_type.ConvertToCanonForm(CanonicalFormKind.Specific));
-                if (sealedVTable.BuildSealedVTableSlots(factory, relocsOnly) && sealedVTable.NumSealedVTableEntries > 0)
-                    flags |= (uint)EETypeRareFlags.HasSealedVTableEntriesFlag;
-            }
-
             if (flags != 0)
             {
                 _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, flags);