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 2255fde37cf097..f9b419a5d8c124 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 @@ -161,7 +161,6 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo pTemplateEEType = pTemplateEEType->DynamicTemplateType; } - uint valueTypeFieldPaddingEncoded = 0; int baseSize = 0; bool isValueType; @@ -171,8 +170,6 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo bool isGeneric; uint flags; ushort runtimeInterfacesLength = 0; - bool isAbstractClass; - bool isByRefLike; IntPtr typeManager = IntPtr.Zero; if (state.RuntimeInterfaces != null) @@ -180,10 +177,6 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo runtimeInterfacesLength = checked((ushort)state.RuntimeInterfaces.Length); } - valueTypeFieldPaddingEncoded = EETypeBuilderHelpers.ComputeValueTypeFieldPaddingFieldValue( - pTemplateEEType->ValueTypeFieldPadding, - (uint)pTemplateEEType->FieldAlignmentRequirement, - IntPtr.Size); baseSize = (int)pTemplateEEType->BaseSize; isValueType = pTemplateEEType->IsValueType; hasFinalizer = pTemplateEEType->IsFinalizable; @@ -191,48 +184,18 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo flags = pTemplateEEType->Flags; isArray = pTemplateEEType->IsArray; isGeneric = pTemplateEEType->IsGeneric; - isAbstractClass = pTemplateEEType->IsAbstract && !pTemplateEEType->IsInterface; - isByRefLike = pTemplateEEType->IsByRefLike; typeManager = pTemplateEEType->PointerToTypeManager; Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength); flags |= (uint)EETypeFlags.IsDynamicTypeFlag; - // TODO! Change to if template is Universal or non-Existent - - // FEATURE_UNIVERSAL_GENERICS? - if (state.TypeSize.HasValue) + if (state.TypeBeingBuilt.IsMdArray) { - baseSize = state.TypeSize.Value; - - int baseSizeBeforeAlignment = baseSize; - - baseSize = MemoryHelpers.AlignUp(baseSize, IntPtr.Size); - - if (isValueType) - { - // Compute the valuetype padding size based on size before adding the object type pointer field to the size - uint cbValueTypeFieldPadding = (uint)(baseSize - baseSizeBeforeAlignment); - - // Add Object type pointer field to base size - baseSize += IntPtr.Size; - - valueTypeFieldPaddingEncoded = (uint)EETypeBuilderHelpers.ComputeValueTypeFieldPaddingFieldValue(cbValueTypeFieldPadding, (uint)state.FieldAlignment.Value, IntPtr.Size); - } - - // Minimum base size is 3 pointers, and requires us to bump the size of an empty class type - if (baseSize <= IntPtr.Size) - { - // ValueTypes should already have had their size bumped up by the normal type layout process - Debug.Assert(!isValueType); - baseSize += IntPtr.Size; - } - - // Add sync block skew - baseSize += IntPtr.Size; - - // Minimum basesize is 3 pointers - Debug.Assert(baseSize >= (IntPtr.Size * 3)); + // If we're building an MDArray, the template is object[,] and we + // need to recompute the base size. + baseSize = IntPtr.Size + // sync block + 2 * IntPtr.Size + // EETypePtr + Length + state.ArrayRank.Value * sizeof(int) * 2; // 2 ints per rank for bounds } // Optional fields encoding @@ -241,7 +204,11 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo uint rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0); - if (state.NonGcDataSize != 0) + int allocatedNonGCDataSize = state.NonGcDataSize; + if (state.HasStaticConstructor) + allocatedNonGCDataSize += -TypeBuilder.ClassConstructorOffset; + + if (allocatedNonGCDataSize != 0) rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics; if (state.GcDataSize != 0) @@ -250,60 +217,11 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo if (state.ThreadDataSize != 0) rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics; -#if TARGET_ARM - 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; -#endif - if (state.HasStaticConstructor) - rareFlags |= (uint)EETypeRareFlags.HasCctorFlag; - else - rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag; - - if (isAbstractClass) - rareFlags |= (uint)EETypeRareFlags.IsAbstractClassFlag; - else - rareFlags &= ~(uint)EETypeRareFlags.IsAbstractClassFlag; - - if (isByRefLike) - rareFlags |= (uint)EETypeRareFlags.IsByRefLikeFlag; - else - rareFlags &= ~(uint)EETypeRareFlags.IsByRefLikeFlag; - - 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 - { - optionalFields.ClearField(EETypeOptionalFieldTag.NullableValueOffset); - } - optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags); // Dispatch map is fetched from template type optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap); - optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding); - - if (valueTypeFieldPaddingEncoded != 0) - optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded); - // Compute size of optional fields encoding cbOptionalFieldsSize = optionalFields.Encode(); Debug.Assert(cbOptionalFieldsSize > 0); @@ -328,7 +246,7 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo true, (rareFlags & (int)EETypeRareFlags.HasSealedVTableEntriesFlag) != 0, isGeneric, - state.NonGcDataSize != 0, + allocatedNonGCDataSize != 0, state.GcDataSize != 0, state.ThreadDataSize != 0); @@ -401,7 +319,7 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo nonGCStaticDataOffset = state.HasStaticConstructor ? -TypeBuilder.ClassConstructorOffset : 0; // If we have a class constructor, our NonGcDataSize MUST be non-zero - Debug.Assert(!state.HasStaticConstructor || (state.NonGcDataSize != 0)); + Debug.Assert(!state.HasStaticConstructor || (allocatedNonGCDataSize != 0)); } if (isGeneric) @@ -409,11 +327,11 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo genericComposition = MemoryHelpers.AllocateMemory(MethodTable.GetGenericCompositionSize(arity, pEEType->HasGenericVariance)); pEEType->SetGenericComposition(genericComposition); - if (state.NonGcDataSize > 0) + if (allocatedNonGCDataSize > 0) { - nonGcStaticData = MemoryHelpers.AllocateMemory(state.NonGcDataSize); - MemoryHelpers.Memset(nonGcStaticData, state.NonGcDataSize, 0); - Debug.Assert(nonGCStaticDataOffset <= state.NonGcDataSize); + nonGcStaticData = MemoryHelpers.AllocateMemory(allocatedNonGCDataSize); + MemoryHelpers.Memset(nonGcStaticData, allocatedNonGCDataSize, 0); + Debug.Assert(nonGCStaticDataOffset <= allocatedNonGCDataSize); pEEType->DynamicNonGcStaticsData = (IntPtr)((byte*)nonGcStaticData + nonGCStaticDataOffset); } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs deleted file mode 100644 index f619b47d513196..00000000000000 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Internal.TypeSystem; -using System.Diagnostics; -using Internal.NativeFormat; -using System.Collections.Generic; -using Internal.Runtime.Augments; - -namespace Internal.Runtime.TypeLoader -{ - /// - /// Reads field layout based on native layout data - /// information - /// - internal class NativeLayoutFieldAlgorithm : FieldLayoutAlgorithm - { - private NoMetadataFieldLayoutAlgorithm _noMetadataFieldLayoutAlgorithm = new NoMetadataFieldLayoutAlgorithm(); - private const int InstanceAlignmentEntry = 4; - - public override unsafe bool ComputeContainsGCPointers(DefType type) - { - Debug.Assert(type.IsTemplateCanonical()); - return type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->HasGCPointers; - } - - public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) - { - Debug.Assert(!type.IsTemplateUniversal() && (layoutKind == InstanceLayoutKind.TypeOnly)); - DefType template = (DefType)type.ComputeTemplate(); - return _noMetadataFieldLayoutAlgorithm.ComputeInstanceLayout(template, InstanceLayoutKind.TypeOnly); - } - - public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind) - { - Debug.Assert(!type.IsTemplateUniversal() && (layoutKind == StaticLayoutKind.StaticRegionSizes)); - return ParseStaticRegionSizesFromNativeLayout(type); - } - - private static ComputedStaticFieldLayout ParseStaticRegionSizesFromNativeLayout(TypeDesc type) - { - LayoutInt nonGcDataSize = LayoutInt.Zero; - LayoutInt gcDataSize = LayoutInt.Zero; - LayoutInt threadDataSize = LayoutInt.Zero; - - TypeBuilderState state = type.GetOrCreateTypeBuilderState(); - NativeParser typeInfoParser = state.GetParserForNativeLayoutInfo(); - - BagElementKind kind; - while ((kind = typeInfoParser.GetBagElementKind()) != BagElementKind.End) - { - switch (kind) - { - case BagElementKind.NonGcStaticDataSize: - TypeLoaderLogger.WriteLine("Found BagElementKind.NonGcStaticDataSize"); - // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later) - nonGcDataSize = new LayoutInt(checked((int)typeInfoParser.GetUnsigned())); - break; - - case BagElementKind.GcStaticDataSize: - TypeLoaderLogger.WriteLine("Found BagElementKind.GcStaticDataSize"); - // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later) - gcDataSize = new LayoutInt(checked((int)typeInfoParser.GetUnsigned())); - break; - - case BagElementKind.ThreadStaticDataSize: - TypeLoaderLogger.WriteLine("Found BagElementKind.ThreadStaticDataSize"); - // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later) - threadDataSize = new LayoutInt(checked((int)typeInfoParser.GetUnsigned())); - break; - - default: - typeInfoParser.SkipInteger(); - break; - } - } - - ComputedStaticFieldLayout staticLayout = new ComputedStaticFieldLayout() - { - GcStatics = new StaticsBlock() { Size = gcDataSize, LargestAlignment = DefType.MaximumAlignmentPossible }, - NonGcStatics = new StaticsBlock() { Size = nonGcDataSize, LargestAlignment = DefType.MaximumAlignmentPossible }, - Offsets = null, // We're not computing field offsets here, so return null - ThreadGcStatics = new StaticsBlock() { Size = threadDataSize, LargestAlignment = DefType.MaximumAlignmentPossible }, - ThreadNonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero }, - }; - - return staticLayout; - } - - public override unsafe ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) - { - // Use this constant to make the code below more laconic - const ValueTypeShapeCharacteristics NotHA = ValueTypeShapeCharacteristics.None; - - Debug.Assert(type.IsValueType); - - TargetArchitecture targetArch = type.Context.Target.Architecture; - if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64)) - return NotHA; - - if (!type.IsValueType) - return NotHA; - - // There is no reason to compute the entire field layout for the HA type/flag if - // the template type is not a universal generic type (information stored in rare flags on the MethodTable) - TypeDesc templateType = type.ComputeTemplate(false); - Debug.Assert(templateType != null && !templateType.IsCanonicalSubtype(CanonicalFormKind.Universal)); - MethodTable* pEETemplate = templateType.GetRuntimeTypeHandle().ToEETypePtr(); - if (!pEETemplate->IsHFA) - return NotHA; - - if (pEETemplate->RequiresAlign8) - return ValueTypeShapeCharacteristics.Float64Aggregate; - else - return ValueTypeShapeCharacteristics.Float32Aggregate; - } - - public override bool ComputeIsUnsafeValueType(DefType type) - { - throw new NotSupportedException(); - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs deleted file mode 100644 index 38124252019de0..00000000000000 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Internal.TypeSystem; -using System.Diagnostics; - -namespace Internal.Runtime.TypeLoader -{ - /// - /// Useable when we have runtime MethodTable structures. Can represent the field layout necessary - /// to represent the size/alignment of the overall type, but must delegate to either NativeLayoutFieldAlgorithm - /// or MetadataFieldLayoutAlgorithm to get information about individual fields. - /// - internal class NoMetadataFieldLayoutAlgorithm : FieldLayoutAlgorithm - { - private static NativeLayoutFieldAlgorithm s_nativeLayoutFieldAlgorithm = new NativeLayoutFieldAlgorithm(); - - public override unsafe bool ComputeContainsGCPointers(DefType type) - { - return type.RuntimeTypeHandle.ToEETypePtr()->HasGCPointers; - } - - /// - /// Reads the minimal information about type layout encoded in the - /// MethodTable. That doesn't include field information. - /// - public override unsafe ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) - { - // If we need the field information, delegate to the native layout algorithm or metadata algorithm - if (layoutKind != InstanceLayoutKind.TypeOnly) - { - Debug.Assert(type.HasNativeLayout); - return s_nativeLayoutFieldAlgorithm.ComputeInstanceLayout(type, layoutKind); - } - - type.RetrieveRuntimeTypeHandleIfPossible(); - Debug.Assert(!type.RuntimeTypeHandle.IsNull()); - MethodTable* MethodTable = type.RuntimeTypeHandle.ToEETypePtr(); - - ComputedInstanceFieldLayout layout = new ComputedInstanceFieldLayout() - { - ByteCountAlignment = new LayoutInt(IntPtr.Size), - ByteCountUnaligned = new LayoutInt(MethodTable->IsInterface ? IntPtr.Size : checked((int)MethodTable->FieldByteCountNonGCAligned)), - FieldAlignment = new LayoutInt(MethodTable->FieldAlignmentRequirement), - Offsets = (layoutKind == InstanceLayoutKind.TypeOnly) ? null : Array.Empty(), // No fields in EETypes - }; - - if (MethodTable->IsValueType) - { - int valueTypeSize = checked((int)MethodTable->ValueTypeSize); - layout.FieldSize = new LayoutInt(valueTypeSize); - } - else - { - layout.FieldSize = new LayoutInt(IntPtr.Size); - } - - if ((MethodTable->RareFlags & EETypeRareFlags.RequiresAlign8Flag) == EETypeRareFlags.RequiresAlign8Flag) - { - layout.ByteCountAlignment = new LayoutInt(8); - } - - return layout; - } - - public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind) - { - Debug.Assert(false); - return default; - } - - public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) - { - if (type.Context.Target.Architecture == TargetArchitecture.ARM) - { - unsafe - { - // On ARM, the HFA type is encoded into the MethodTable directly - type.RetrieveRuntimeTypeHandleIfPossible(); - Debug.Assert(!type.RuntimeTypeHandle.IsNull()); - MethodTable* MethodTable = type.RuntimeTypeHandle.ToEETypePtr(); - - if (!MethodTable->IsHFA) - return ValueTypeShapeCharacteristics.None; - - if (MethodTable->RequiresAlign8) - return ValueTypeShapeCharacteristics.Float64Aggregate; - else - return ValueTypeShapeCharacteristics.Float32Aggregate; - } - } - else - { - Debug.Assert( - type.Context.Target.Architecture == TargetArchitecture.X86 || - type.Context.Target.Architecture == TargetArchitecture.X64); - - return ValueTypeShapeCharacteristics.None; - } - } - - public override bool ComputeIsUnsafeValueType(DefType type) - { - throw new NotSupportedException(); - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs index 4d0da15912ae49..65c981592a1cda 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs @@ -260,9 +260,6 @@ internal void PrepareType(TypeDesc type) { Debug.Assert(typeAsArrayType.IsMdArray || typeAsArrayType.ElementType.IsPointer); } - - // Assert that non-valuetypes are considered to have pointer size - Debug.Assert(typeAsArrayType.ParameterType.IsValueType || state.ComponentSize == IntPtr.Size); } } else @@ -276,11 +273,7 @@ internal void PrepareType(TypeDesc type) PrepareBaseTypeAndDictionaries(type); PrepareRuntimeInterfaces(type); - TypeLoaderLogger.WriteLine("Layout for type " + type.ToString() + " complete." + - " IsHFA = " + (state.IsHFA ? "true" : "false") + - " Type size = " + (state.TypeSize.HasValue ? state.TypeSize.Value.LowLevelToString() : "UNDEF") + - " Fields size = " + (state.UnalignedTypeSize.HasValue ? state.UnalignedTypeSize.Value.LowLevelToString() : "UNDEF") + - " Type alignment = " + (state.FieldAlignment.HasValue ? state.FieldAlignment.Value.LowLevelToString() : "UNDEF")); + TypeLoaderLogger.WriteLine("Layout for type " + type.ToString() + " complete."); } } @@ -400,13 +393,6 @@ internal void ParseNativeLayoutInfo(TypeBuilderState state, TypeDesc type) NativeParser baseTypeParser = new NativeParser(); - int nonGcDataSize = 0; - int gcDataSize = 0; - int threadDataSize = 0; - bool staticSizesMeaningful = (type is DefType) // Is type permitted to have static fields - && !isTemplateUniversalCanon; // Non-universal templates always specify their statics sizes - // if the size can be greater than 0 - BagElementKind kind; while ((kind = typeInfoParser.GetBagElementKind()) != BagElementKind.End) { @@ -432,22 +418,19 @@ internal void ParseNativeLayoutInfo(TypeBuilderState state, TypeDesc type) case BagElementKind.NonGcStaticDataSize: TypeLoaderLogger.WriteLine("Found BagElementKind.NonGcStaticDataSize"); // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later) - nonGcDataSize = checked((int)typeInfoParser.GetUnsigned()); - Debug.Assert(staticSizesMeaningful); + state.NonGcDataSize = checked((int)typeInfoParser.GetUnsigned()); break; case BagElementKind.GcStaticDataSize: TypeLoaderLogger.WriteLine("Found BagElementKind.GcStaticDataSize"); // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later) - gcDataSize = checked((int)typeInfoParser.GetUnsigned()); - Debug.Assert(staticSizesMeaningful); + state.GcDataSize = checked((int)typeInfoParser.GetUnsigned()); break; case BagElementKind.ThreadStaticDataSize: TypeLoaderLogger.WriteLine("Found BagElementKind.ThreadStaticDataSize"); // Use checked typecast to int to ensure there aren't any overflows/truncations (size value used in allocation of memory later) - threadDataSize = checked((int)typeInfoParser.GetUnsigned()); - Debug.Assert(staticSizesMeaningful); + state.ThreadDataSize = checked((int)typeInfoParser.GetUnsigned()); break; case BagElementKind.GcStaticDesc: @@ -493,13 +476,6 @@ internal void ParseNativeLayoutInfo(TypeBuilderState state, TypeDesc type) } } - if (staticSizesMeaningful) - { - Debug.Assert((state.NonGcDataSize + (state.HasStaticConstructor ? TypeBuilder.ClassConstructorOffset : 0)) == nonGcDataSize); - Debug.Assert(state.GcDataSize == gcDataSize); - Debug.Assert(state.ThreadDataSize == threadDataSize); - } - type.ParseBaseType(context, baseTypeParser); } @@ -847,9 +823,16 @@ private void FinishRuntimeType(TypeDesc type) { if (type is ArrayType typeAsSzArrayType) { - state.HalfBakedRuntimeTypeHandle.SetRelatedParameterType(GetRuntimeTypeHandle(typeAsSzArrayType.ElementType)); + RuntimeTypeHandle elementTypeHandle = GetRuntimeTypeHandle(typeAsSzArrayType.ElementType); + state.HalfBakedRuntimeTypeHandle.SetRelatedParameterType(elementTypeHandle); - state.HalfBakedRuntimeTypeHandle.SetComponentSize(state.ComponentSize.Value); + ushort componentSize = (ushort)IntPtr.Size; + unsafe + { + if (typeAsSzArrayType.ElementType.IsValueType) + componentSize = checked((ushort)elementTypeHandle.ToEETypePtr()->ValueTypeSize); + } + state.HalfBakedRuntimeTypeHandle.SetComponentSize(componentSize); FinishInterfaces(state); } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs index 8305f1e492916c..7cf922fd75f4d7 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs @@ -280,59 +280,9 @@ public ushort NumVTableSlots public GenericTypeDictionary Dictionary; - public int NonGcDataSize - { - get - { - DefType defType = TypeBeingBuilt as DefType; - - // The NonGCStatic fields hold the class constructor data if it exists in the negative space - // of the memory region. The ClassConstructorOffset is negative, so it must be negated to - // determine the extra space that is used. - - if (defType != null) - { - return defType.NonGCStaticFieldSize.AsInt - (HasStaticConstructor ? TypeBuilder.ClassConstructorOffset : 0); - } - else - { - return -(HasStaticConstructor ? TypeBuilder.ClassConstructorOffset : 0); - } - } - } - - public int GcDataSize - { - get - { - DefType defType = TypeBeingBuilt as DefType; - if (defType != null) - { - return defType.GCStaticFieldSize.AsInt; - } - else - { - return 0; - } - } - } - - public int ThreadDataSize - { - get - { - DefType defType = TypeBeingBuilt as DefType; - if (defType != null && !defType.IsGenericDefinition) - { - return defType.ThreadGcStaticFieldSize.AsInt; - } - else - { - // Non-DefType's and GenericEETypeDefinitions do not have static fields of any form - return 0; - } - } - } + public int NonGcDataSize; + public int GcDataSize; + public int ThreadDataSize; public bool HasStaticConstructor { @@ -522,180 +472,5 @@ public int? ArrayRank } } } - - public int? BaseTypeSize - { - get - { - if (TypeBeingBuilt.BaseType == null) - { - return null; - } - else - { - return TypeBeingBuilt.BaseType.InstanceByteCountUnaligned.AsInt; - } - } - } - - public int? TypeSize - { - get - { - DefType defType = TypeBeingBuilt as DefType; - if (defType != null) - { - // Generic Type Definition EETypes do not have size - if (defType.IsGenericDefinition) - return null; - - if (defType.IsValueType) - { - return defType.InstanceFieldSize.AsInt; - } - else - { - if (defType.IsInterface) - return IntPtr.Size; - - return defType.InstanceByteCountUnaligned.AsInt; - } - } - else if (TypeBeingBuilt is ArrayType) - { - int basicArraySize = 2 * IntPtr.Size; // EETypePtr + Length - if (TypeBeingBuilt.IsMdArray) - { - // MD Arrays are arranged like normal arrays, but they also have 2 int's per rank for the individual dimension loBounds and range. - basicArraySize += ((ArrayType)TypeBeingBuilt).Rank * sizeof(int) * 2; - } - return basicArraySize; - } - else - { - return null; - } - } - } - - public int? UnalignedTypeSize - { - get - { - DefType defType = TypeBeingBuilt as DefType; - if (defType != null) - { - return defType.InstanceByteCountUnaligned.AsInt; - } - else if (TypeBeingBuilt is ArrayType) - { - // Arrays use the same algorithm for TypeSize as for UnalignedTypeSize - return TypeSize; - } - else - { - return 0; - } - } - } - - public int? FieldAlignment - { - get - { - if (TypeBeingBuilt is DefType) - { - return checked((ushort)((DefType)TypeBeingBuilt).InstanceFieldAlignment.AsInt); - } - else if (TypeBeingBuilt is ArrayType arrayType) - { - if (arrayType.ElementType is DefType) - { - return checked((ushort)((DefType)arrayType.ElementType).InstanceFieldAlignment.AsInt); - } - else - { - return (ushort)arrayType.Context.Target.PointerSize; - } - } - else if (TypeBeingBuilt is PointerType || TypeBeingBuilt is ByRefType) - { - return (ushort)TypeBeingBuilt.Context.Target.PointerSize; - } - else - { - return null; - } - } - } - - public ushort? ComponentSize - { - get - { - ArrayType arrayType = TypeBeingBuilt as ArrayType; - if (arrayType != null) - { - if (arrayType.ElementType is DefType) - { - uint size = (uint)((DefType)arrayType.ElementType).InstanceFieldSize.AsInt; - - if (size > ArrayTypesConstants.MaxSizeForValueClassInArray && arrayType.ElementType.IsValueType) - ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadValueClassTooLarge, arrayType.ElementType); - - return checked((ushort)size); - } - else - { - return (ushort)arrayType.Context.Target.PointerSize; - } - } - else - { - return null; - } - } - } - - public uint NullableValueOffset - { - get - { - if (!TypeBeingBuilt.IsNullable) - return 0; - - Debug.Assert(TypeBeingBuilt.IsTemplateCanonical()); - // Pull the GC Desc from the canonical instantiation - TypeDesc templateType = TypeBeingBuilt.ComputeTemplate(); - bool success = templateType.RetrieveRuntimeTypeHandleIfPossible(); - Debug.Assert(success); - unsafe - { - return templateType.RuntimeTypeHandle.ToEETypePtr()->NullableValueOffset; - } - } - } - -#pragma warning disable CA1822 - public bool IsHFA - { - get - { -#if TARGET_ARM - if (TypeBeingBuilt.IsValueType && TypeBeingBuilt is DefType) - { - return ((DefType)TypeBeingBuilt).IsHomogeneousAggregate; - } - else - { - return false; - } -#else - // On Non-ARM platforms, HFA'ness is not encoded in the MethodTable as it doesn't effect ABI - return false; -#endif - } - } -#pragma warning restore CA1822 } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderTypeSystemContext.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderTypeSystemContext.cs index 7dd6bbc01a326c..c6120c5f80a570 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderTypeSystemContext.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderTypeSystemContext.cs @@ -14,30 +14,13 @@ namespace Internal.Runtime.TypeLoader /// public partial class TypeLoaderTypeSystemContext : TypeSystemContext { - private static readonly NoMetadataFieldLayoutAlgorithm s_noMetadataFieldLayoutAlgorithm = new NoMetadataFieldLayoutAlgorithm(); private static readonly NoMetadataRuntimeInterfacesAlgorithm s_noMetadataRuntimeInterfacesAlgorithm = new NoMetadataRuntimeInterfacesAlgorithm(); - private static readonly NativeLayoutFieldAlgorithm s_nativeLayoutFieldAlgorithm = new NativeLayoutFieldAlgorithm(); private static readonly NativeLayoutInterfacesAlgorithm s_nativeLayoutInterfacesAlgorithm = new NativeLayoutInterfacesAlgorithm(); public TypeLoaderTypeSystemContext(TargetDetails targetDetails) : base(targetDetails) { } - public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) - { - if (type.RetrieveRuntimeTypeHandleIfPossible()) - { - // If the type is already constructed, use the NoMetadataFieldLayoutAlgorithm. - // its more efficient than loading from native layout or metadata. - return s_noMetadataFieldLayoutAlgorithm; - } - if (type.HasNativeLayout) - { - return s_nativeLayoutFieldAlgorithm; - } - return s_noMetadataFieldLayoutAlgorithm; - } - protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) { if (type.RetrieveRuntimeTypeHandleIfPossible()) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj index b658cc35b155cc..478156e0371dc3 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj @@ -281,10 +281,8 @@ - - diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index 04a5b32c9acbc5..132b4ba679269d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -1134,11 +1134,8 @@ private void ComputeNullableValueOffset() protected virtual void ComputeValueTypeFieldPadding() { - // All objects that can have appreciable which can be derived from size compute ValueTypeFieldPadding. - // Unfortunately, the name ValueTypeFieldPadding is now wrong to avoid integration conflicts. - - // Interfaces, sealed types, and non-DefTypes cannot be derived from - if (_type.IsInterface || !_type.IsDefType || (_type.IsSealed() && !_type.IsValueType)) + // Only valuetypes need to compute the padding. + if (!_type.IsValueType) return; DefType defType = _type as DefType; @@ -1154,22 +1151,18 @@ protected virtual void ComputeValueTypeFieldPadding() { int numInstanceFieldBytes = defType.InstanceByteCountUnaligned.AsInt; - // Check if we have a type derived from System.ValueType or System.Enum, but not System.Enum itself - if (defType.IsValueType) - { - // Value types should have at least 1 byte of size - Debug.Assert(numInstanceFieldBytes >= 1); + // Value types should have at least 1 byte of size + Debug.Assert(numInstanceFieldBytes >= 1); - // The size doesn't currently include the MethodTable pointer size. We need to add this so that - // the number of instance field bytes consistently represents the boxed size. - numInstanceFieldBytes += _type.Context.Target.PointerSize; - } + // The size of value types doesn't include the MethodTable pointer. We need to add this so that + // the number of instance field bytes consistently represents the boxed size. + numInstanceFieldBytes += _type.Context.Target.PointerSize; // For unboxing to work correctly and for supporting dynamic type loading for derived types we need // to record the actual size of the fields of a type without any padding for GC heap allocation (since // we can unbox into locals or arrays where this padding is not used, and because field layout for derived // types is effected by the unaligned base size). We don't want to store this information for all EETypes - // since it's only relevant for value types, and derivable types so it's added as an optional field. It's + // since it's only relevant for value types, so it's added as an optional field. It's // also enough to simply store the size of the padding (between 0 and 4 or 8 bytes for 32-bit and 0 and 8 or 16 bytes // for 64-bit) which cuts down our storage requirements.