diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index dde66e58d2eb1..8e5200d37d509 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -4360,7 +4360,7 @@ SIZE_T GetSetFrameHelper::GetValueClassSize(MetaSig* pSig) // - but we don't care if it's shared (since it will be the same size either way) _ASSERTE(!vcType.IsNull() && vcType.IsValueType()); - return (vcType.GetMethodTable()->GetAlignedNumInstanceFieldBytes()); + return (vcType.GetMethodTable()->GetNumInstanceFieldBytes()); } // diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 7d43b40389458..a9b27973eaff3 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -15,15 +15,17 @@ #define READYTORUN_SIGNATURE 0x00525452 // 'RTR' // Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs -#define READYTORUN_MAJOR_VERSION 0x0005 -#define READYTORUN_MINOR_VERSION 0x0004 +#define READYTORUN_MAJOR_VERSION 0x0006 +#define READYTORUN_MINOR_VERSION 0x0000 -#define MINIMUM_READYTORUN_MAJOR_VERSION 0x003 +#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006 // R2R Version 2.1 adds the InliningInfo section // R2R Version 2.2 adds the ProfileDataInfo section // R2R Version 3.0 changes calling conventions to correctly handle explicit structures to spec. // R2R 3.0 is not backward compatible with 2.x. +// R2R Version 6.0 changes managed layout for sequential types with any unmanaged non-blittable fields. +// R2R 6.0 is not backward compatible with 5.x or earlier. struct READYTORUN_CORE_HEADER { diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index 434f9a9ee1c88..12a9ba0327f74 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -14,8 +14,8 @@ internal struct ReadyToRunHeaderConstants { public const uint Signature = 0x00525452; // 'RTR' - public const ushort CurrentMajorVersion = 5; - public const ushort CurrentMinorVersion = 4; + public const ushort CurrentMajorVersion = 6; + public const ushort CurrentMinorVersion = 0; } #pragma warning disable 0169 diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 362fd1763d230..249faef7cd040 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -103,7 +103,6 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp type.Context.Target.GetWellKnownTypeSize(type), type.Context.Target.GetWellKnownTypeAlignment(type), 0, - alignUpInstanceByteSize: true, out instanceByteSizeAndAlignment ); @@ -291,8 +290,6 @@ protected virtual void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContex { } - protected virtual bool AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(TypeDesc type) => true; - protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType type, int numInstanceFields) { // Instance slice size is the total size of instance not including the base type. @@ -312,7 +309,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty foreach (var fieldAndOffset in layoutMetadata.Offsets) { TypeDesc fieldType = fieldAndOffset.Field.FieldType; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -355,7 +352,6 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty instanceSize, largestAlignmentRequired, layoutMetadata.Size, - alignUpInstanceByteSize: AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(type), out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); @@ -398,7 +394,7 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType if (field.IsStatic) continue; - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType.UnderlyingType, hasLayout: true, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; @@ -417,7 +413,6 @@ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout(MetadataType cumulativeInstanceFieldPos + offsetBias, largestAlignmentRequirement, layoutMetadata.Size, - alignUpInstanceByteSize: true, out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); @@ -442,8 +437,8 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, bool hasLayout = type.HasLayout(); var layoutMetadata = type.GetClassLayout(); - int packingSize = ComputePackingSize(type, layoutMetadata); - packingSize = Math.Min(context.Target.MaximumAutoLayoutPackingSize, packingSize); + // Auto-layout in CoreCLR does not respect packing size. + int packingSize = type.Context.Target.MaximumAlignment; var offsets = new FieldAndOffset[numInstanceFields]; int fieldOrdinal = 0; @@ -543,7 +538,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, LayoutInt offsetBias = LayoutInt.Zero; if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && type.Context.Target.Architecture == TargetArchitecture.X86) { - offsetBias = new LayoutInt(type.Context.Target.PointerSize); + offsetBias = type.Context.Target.LayoutPointerSize; cumulativeInstanceFieldPos -= offsetBias; } @@ -650,29 +645,14 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, // Place value class fields last for (int i = 0; i < instanceValueClassFieldsArr.Length; i++) { - // If the field has an indeterminate alignment, align the cumulative field offset to the indeterminate value - // Otherwise, align the cumulative field offset to the PointerSize - // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments + // Align the cumulative field offset to the indeterminate value var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(instanceValueClassFieldsArr[i].FieldType, hasLayout, packingSize, out bool fieldLayoutAbiStable); if (!fieldLayoutAbiStable) layoutAbiStable = false; - if (fieldSizeAndAlignment.Alignment.IsIndeterminate) - { - cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, context.Target); - } - else - { - LayoutInt AlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, context.Target.LayoutPointerSize); - cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, AlignmentRequired, context.Target); - } + cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, context.Target); offsets[fieldOrdinal] = new FieldAndOffset(instanceValueClassFieldsArr[i], cumulativeInstanceFieldPos + offsetBias); - - // If the field has an indeterminate size, align the cumulative field offset to the indeterminate value - // Otherwise, align the cumulative field offset to the aligned-instance field size - // This avoids issues with Universal Generic Field layouts whose fields may have Indeterminate sizes or alignments - LayoutInt alignedInstanceFieldBytes = fieldSizeAndAlignment.Size.IsIndeterminate ? fieldSizeAndAlignment.Size : GetAlignedNumInstanceFieldBytes(fieldSizeAndAlignment.Size); - cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + alignedInstanceFieldBytes); + cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size); fieldOrdinal++; } @@ -687,11 +667,18 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, } else if (cumulativeInstanceFieldPos.AsInt > context.Target.PointerSize) { - minAlign = context.Target.LayoutPointerSize; - if (requiresAlign8 && minAlign.AsInt == 4) + if (requiresAlign8) { minAlign = new LayoutInt(8); } + else if (type.ContainsGCPointers) + { + minAlign = context.Target.LayoutPointerSize; + } + else + { + minAlign = largestAlignmentRequired; + } } else { @@ -705,8 +692,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type, cumulativeInstanceFieldPos + offsetBias, minAlign, classLayoutSize: 0, - alignUpInstanceByteSize: true, - out instanceByteSizeAndAlignment); + byteCount: out instanceByteSizeAndAlignment); ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout(); computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; @@ -790,10 +776,10 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, { if (fieldType.IsValueType) { - DefType metadataType = (DefType)fieldType; - result.Size = metadataType.InstanceFieldSize; - result.Alignment = metadataType.InstanceFieldAlignment; - layoutAbiStable = metadataType.LayoutAbiStable; + DefType defType = (DefType)fieldType; + result.Size = defType.InstanceFieldSize; + result.Alignment = defType.InstanceFieldAlignment; + layoutAbiStable = defType.LayoutAbiStable; } else { @@ -816,14 +802,11 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, result.Alignment = fieldType.Context.Target.LayoutPointerSize; } + // For non-auto layouts, we need to respect tighter packing requests for alignment. if (hasLayout) { result.Alignment = LayoutInt.Min(result.Alignment, new LayoutInt(packingSize)); } - else - { - result.Alignment = LayoutInt.Min(result.Alignment, fieldType.Context.Target.GetObjectAlignment(result.Alignment)); - } return result; } @@ -831,12 +814,12 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, private static int ComputePackingSize(MetadataType type, ClassLayoutMetadata layoutMetadata) { if (layoutMetadata.PackingSize == 0) - return type.Context.Target.DefaultPackingSize; + return type.Context.Target.MaximumAlignment; else return layoutMetadata.PackingSize; } - private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, bool alignUpInstanceByteSize, out SizeAndAlignment byteCount) + private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt instanceSize, LayoutInt alignment, int classLayoutSize, out SizeAndAlignment byteCount) { SizeAndAlignment result; @@ -864,9 +847,7 @@ private static SizeAndAlignment ComputeInstanceSize(MetadataType type, LayoutInt { if (type.IsValueType) { - instanceSize = LayoutInt.AlignUp(instanceSize, - alignUpInstanceByteSize ? alignment : LayoutInt.Min(alignment, target.LayoutPointerSize), - target); + instanceSize = LayoutInt.AlignUp(instanceSize, alignment, target); } } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs b/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs index 21ea040857855..e5626ed8f976d 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs @@ -324,20 +324,5 @@ public int MaxHomogeneousAggregateElementCount return 4; } } - - public int MaximumAutoLayoutPackingSize - { - get - { - if (Abi == TargetAbi.CoreRT) - { - if (Architecture == TargetArchitecture.X86) - { - return PointerSize; - } - } - return MaximumAlignment; - } - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 76e237cec5c1c..f507cabb4d3e3 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -196,9 +196,9 @@ protected override ModuleFieldLayout CreateValueFromKey(EcmaModule module) } } - if (nonGcBytes[StaticIndex.Regular] != 0 || + if (nonGcBytes[StaticIndex.Regular] != 0 || nonGcBytes[StaticIndex.ThreadLocal] != 0 || - gcBytes[StaticIndex.Regular] != 0 || + gcBytes[StaticIndex.Regular] != 0 || gcBytes[StaticIndex.ThreadLocal] != 0) { OffsetsForType offsetsForType = new OffsetsForType(LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate); @@ -290,14 +290,14 @@ private void GetElementTypeInfoGeneric( } private void GetElementTypeInfo( - EcmaModule module, + EcmaModule module, FieldDesc fieldDesc, - EntityHandle valueTypeHandle, + EntityHandle valueTypeHandle, CorElementType elementType, int pointerSize, bool moduleLayout, - out int alignment, - out int size, + out int alignment, + out int size, out bool isGcPointerField, out bool isGcBoxedField) { @@ -357,7 +357,7 @@ private void GetElementTypeInfo( ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, fieldDesc.OwningType); break; - // Statics for valuetypes where the valuetype is defined in this module are handled here. + // Statics for valuetypes where the valuetype is defined in this module are handled here. // Other valuetype statics utilize the pessimistic model below. case CorElementType.ELEMENT_TYPE_VALUETYPE: if (IsTypeByRefLike(valueTypeHandle, module.MetadataReader)) @@ -522,7 +522,7 @@ public FieldAndOffset[] CalculateTypeLayout(DefType defType, EcmaModule module, offsetsForType.GcOffsets[StaticIndex.ThreadLocal], }; - LayoutInt[] gcPointerFieldOffsets = new LayoutInt[StaticIndex.Count] + LayoutInt[] gcPointerFieldOffsets = new LayoutInt[StaticIndex.Count] { offsetsForType.GcOffsets[StaticIndex.Regular] + new LayoutInt(gcBoxedCount[StaticIndex.Regular] * pointerSize), offsetsForType.GcOffsets[StaticIndex.ThreadLocal] + new LayoutInt(gcBoxedCount[StaticIndex.ThreadLocal] * pointerSize) @@ -768,10 +768,10 @@ private class ModuleFieldLayout private ConcurrentDictionary _genericTypeToFieldMap; public ModuleFieldLayout( - EcmaModule module, - StaticsBlock gcStatics, - StaticsBlock nonGcStatics, - StaticsBlock threadGcStatics, + EcmaModule module, + StaticsBlock gcStatics, + StaticsBlock nonGcStatics, + StaticsBlock threadGcStatics, StaticsBlock threadNonGcStatics, IReadOnlyDictionary typeOffsets) { @@ -802,8 +802,7 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada { return ComputeExplicitFieldLayout(type, numInstanceFields); } - else - if (type.IsEnum || MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type)) + else if (type.IsSequentialLayout && !type.ContainsGCPointers) { return ComputeSequentialFieldLayout(type, numInstanceFields); } @@ -814,7 +813,7 @@ protected override ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metada } /// - /// This method decides whether the type needs aligned base offset in order to have layout resilient to + /// This method decides whether the type needs aligned base offset in order to have layout resilient to /// base class layout changes. /// protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref LayoutInt baseOffset, bool requiresAlign8, bool requiresAlignedBase) @@ -826,44 +825,5 @@ protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref Layout baseOffset = LayoutInt.AlignUp(baseOffset, alignment, type.Context.Target); } } - - protected override bool AlignUpInstanceByteSizeForExplicitFieldLayoutCompatQuirk(TypeDesc type) - { - return MarshalUtils.IsBlittableType(type) || IsManagedSequentialType(type); - } - - public static bool IsManagedSequentialType(TypeDesc type) - { - if (type.IsPointer) - { - return true; - } - - if (!type.IsValueType) - { - return false; - } - - MetadataType metadataType = (MetadataType)type; - if (metadataType.IsExplicitLayout || !metadataType.IsSequentialLayout) - { - return false; - } - - if (type.IsPrimitive) - { - return true; - } - - foreach (FieldDesc field in type.GetFields()) - { - if (!field.IsStatic && !IsManagedSequentialType(field.FieldType.UnderlyingType)) - { - return false; - } - } - - return true; - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 0cab49cddd794..1a01729b6c2dd 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -970,8 +970,8 @@ private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RE private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, MethodDesc methodDesc, out object context, ref TypeDesc constrainedType) { - if (methodDesc != null && (_compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(methodDesc) - || (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_DevirtualizedMethod) + if (methodDesc != null && (_compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(methodDesc) + || (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_DevirtualizedMethod) || methodDesc.IsPInvoke)) { if ((CorTokenType)(unchecked((uint)pResolvedToken.token) & 0xFF000000u) == CorTokenType.mdtMethodDef && @@ -1129,7 +1129,7 @@ private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* var { _debugVarInfos[i] = vars[i]; } - + // JIT gave the ownership of this to us, so need to free this. freeArray(vars); } @@ -1146,7 +1146,7 @@ private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping { _debugLocInfos[i] = pMap[i]; } - + // JIT gave the ownership of this to us, so need to free this. freeArray(pMap); } @@ -2338,17 +2338,6 @@ private bool NeedsTypeLayoutCheck(TypeDesc type) return !_compilation.IsLayoutFixedInCurrentVersionBubble(type) || (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !((MetadataType)type).IsNonVersionable()); } - private bool HasLayoutMetadata(TypeDesc type) - { - if (type.IsValueType && (MarshalUtils.IsBlittableType(type) || ReadyToRunMetadataFieldLayoutAlgorithm.IsManagedSequentialType(type))) - { - // Sequential layout - return true; - } - - return false; - } - /// /// Throws if the JIT inlines a method outside the current version bubble and that inlinee accesses /// fields also outside the version bubble. ReadyToRun currently cannot encode such references. @@ -2410,17 +2399,6 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, } // ENCODE_NONE } - else if (HasLayoutMetadata(pMT)) - { - PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod); - - // We won't try to be smart for classes with layout. - // They are complex to get right, and very rare anyway. - // ENCODE_FIELD_OFFSET - pResult->offset = 0; - pResult->fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE_WITH_BASE; - pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.FieldOffset(field)); - } else { PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod); diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index a83c577b72c86..f08c256dadb51 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -660,7 +660,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy } else if (index == 0) { - skip = pElemMT->GetAlignedNumInstanceFieldBytes() - numPtrsInBytes; + skip = pElemMT->GetNumInstanceFieldBytes() - numPtrsInBytes; } else { diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 1817658119d17..0ccacd36a9f91 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -574,6 +574,9 @@ class EEClassOptionalFields unsigned int m_eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; #endif // UNIX_AMD64_ABI + // Required alignment for this fields of this type (only set in auto-layout structures when different from pointer alignment) + BYTE m_requiredFieldAlignment; + // Set default values for optional fields. inline void Init(); @@ -1195,6 +1198,16 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! LIMITED_METHOD_CONTRACT; m_VMFlags |= VMFLAG_PREFER_ALIGN8; } + inline BOOL HasCustomFieldAlignment() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_HAS_CUSTOM_FIELD_ALIGNMENT); + } + inline void SetHasCustomFieldAlignment() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_HAS_CUSTOM_FIELD_ALIGNMENT; + } #ifdef _DEBUG inline void SetDestroyed() { @@ -1479,6 +1492,13 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! bool CheckForHFA(); #endif // FEATURE_HFA + inline int GetOverriddenFieldAlignmentRequirement() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + return GetOptionalFields()->m_requiredFieldAlignment; + } + #ifdef FEATURE_COMINTEROP inline TypeHandle GetCoClassForInterface() { @@ -1672,7 +1692,7 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! // unused = 0x00010000, VMFLAG_NO_GUID = 0x00020000, VMFLAG_HASNONPUBLICFIELDS = 0x00040000, - // unused = 0x00080000, + VMFLAG_HAS_CUSTOM_FIELD_ALIGNMENT = 0x00080000, VMFLAG_CONTAINS_STACK_PTR = 0x00100000, VMFLAG_PREFER_ALIGN8 = 0x00200000, // Would like to have 8-byte alignment VMFLAG_ONLY_ABSTRACT_METHODS = 0x00400000, // Type only contains abstract methods diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index 749620609dfdd..90315764cfbc5 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -264,10 +264,9 @@ namespace #else // TARGET_X86 && UNIX_X86_ABI pManagedPlacementInfo->m_alignment = pManagedPlacementInfo->m_size; #endif - return FALSE; } - else if (corElemType == ELEMENT_TYPE_PTR) + else if (corElemType == ELEMENT_TYPE_PTR || corElemType == ELEMENT_TYPE_FNPTR) { pManagedPlacementInfo->m_size = TARGET_POINTER_SIZE; pManagedPlacementInfo->m_alignment = TARGET_POINTER_SIZE; @@ -282,16 +281,31 @@ namespace pManagedPlacementInfo->m_size = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes()); - if (pNestedType.GetMethodTable()->HasLayout()) +#if !defined(TARGET_64BIT) && (DATA_ALIGNMENT > 4) + if (pManagedPlacementInfo->m_size >= DATA_ALIGNMENT) + { + pManagedPlacementInfo->m_alignment = DATA_ALIGNMENT; + } + else +#elif defined(FEATURE_64BIT_ALIGNMENT) + if (pNestedType.RequiresAlign8()) { - pManagedPlacementInfo->m_alignment = pNestedType.GetMethodTable()->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers; + pManagedPlacementInfo->m_alignment = 8; } else +#endif // FEATURE_64BIT_ALIGNMENT + if (pNestedType.GetMethodTable()->ContainsPointers()) { + // this field type has GC pointers in it, which need to be pointer-size aligned + // so do this if it has not been done already pManagedPlacementInfo->m_alignment = TARGET_POINTER_SIZE; } - - return !pNestedType.GetMethodTable()->IsManagedSequential(); + else + { + pManagedPlacementInfo->m_alignment = pNestedType.GetMethodTable()->GetFieldAlignmentRequirement(); + } + // Types that have GC Pointer fields (objects or byrefs) are disqualified from ManagedSequential layout. + return pNestedType.GetMethodTable()->ContainsPointers() != FALSE; } // No other type permitted for ManagedSequential. diff --git a/src/coreclr/vm/managedmdimport.hpp b/src/coreclr/vm/managedmdimport.hpp index ffc1efb2b7a64..72e3703c376d4 100644 --- a/src/coreclr/vm/managedmdimport.hpp +++ b/src/coreclr/vm/managedmdimport.hpp @@ -28,9 +28,6 @@ typedef struct { I4Array * largeResult; int length; -#ifdef HOST_64BIT - int padding; -#endif int smallResult[16]; } MetadataEnumResult; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 1d63103cb36f1..4a6c301e8a289 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -8107,6 +8107,19 @@ NOINLINE BYTE *MethodTable::GetLoaderAllocatorObjectForGC() return retVal; } +int MethodTable::GetFieldAlignmentRequirement() +{ + if (HasLayout()) + { + return GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers; + } + else if (GetClass()->HasCustomFieldAlignment()) + { + return GetClass()->GetOverriddenFieldAlignmentRequirement(); + } + return min(GetNumInstanceFieldBytes(), TARGET_POINTER_SIZE); +} + UINT32 MethodTable::GetNativeSize() { CONTRACTL diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index a56c575636318..37ea84b4e08b3 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1601,11 +1601,9 @@ class MethodTable // inline DWORD GetNumInstanceFieldBytes(); - inline WORD GetNumIntroducedInstanceFields(); - - // Does this always return the same (or related) size as GetBaseSize()? - inline DWORD GetAlignedNumInstanceFieldBytes(); + int GetFieldAlignmentRequirement(); + inline WORD GetNumIntroducedInstanceFields(); // Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp. DWORD ContainsPointers() diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 1ff15d02975e6..d14a73532b6e1 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -181,13 +181,6 @@ inline WORD MethodTable::GetNumIntroducedInstanceFields() return(wNumFields); } -//========================================================================================== -inline DWORD MethodTable::GetAlignedNumInstanceFieldBytes() -{ - WRAPPER_NO_CONTRACT; - return((GetNumInstanceFieldBytes() + 3) & (~3)); -} - //========================================================================================== inline PTR_FieldDesc MethodTable::GetApproxFieldDescListRaw() { diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index d5feeae4425e2..14d49a7f7f921 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -4428,7 +4428,9 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8 // bytes (this mimics what the native compiler does and ensures we match up calling conventions during // interop). - if (HasLayout() && GetLayoutInfo()->GetPackingSize() < 8) + // We don't do this for types that are marked as sequential but end up with auto-layout due to containing pointers, + // as auto-layout ignores any Pack directives. + if (HasLayout() && (HasExplicitFieldOffsetLayout() || IsManagedSequential()) && GetLayoutInfo()->GetPackingSize() < 8) { fFieldRequiresAlign8 = false; } @@ -8111,10 +8113,10 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach continue; // Align instance fields if we aren't already -#ifdef FEATURE_64BIT_ALIGNMENT - DWORD dwDataAlignment = 1 << i; -#else +#if defined(TARGET_X86) && defined(UNIX_X86_ABI) DWORD dwDataAlignment = min(1 << i, DATA_ALIGNMENT); +#else + DWORD dwDataAlignment = 1 << i; #endif dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwDataAlignment); @@ -8169,35 +8171,62 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach else dwNumGCPointerSeries = bmtParent->NumParentPointerSeries; + bool containsGCPointers = bmtFP->NumInstanceGCPointerFields > 0; // Place by value class fields last // Update the number of GC pointer series + // Calculate largest alignment requirement + int largestAlignmentRequirement = 1; for (i = 0; i < bmtEnumFields->dwNumInstanceFields; i++) { if (pFieldDescList[i].IsByValue()) { MethodTable * pByValueMT = pByValueClassCache[i]; - // value classes could have GC pointers in them, which need to be pointer-size aligned - // so do this if it has not been done already - #if !defined(TARGET_64BIT) && (DATA_ALIGNMENT > 4) - dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, - (pByValueMT->GetNumInstanceFieldBytes() >= DATA_ALIGNMENT) ? DATA_ALIGNMENT : TARGET_POINTER_SIZE); -#else // !(!defined(TARGET_64BIT) && (DATA_ALIGNMENT > 4)) -#ifdef FEATURE_64BIT_ALIGNMENT + if (pByValueMT->GetNumInstanceFieldBytes() >= DATA_ALIGNMENT) + { + dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, DATA_ALIGNMENT); + largestAlignmentRequirement = max(largestAlignmentRequirement, DATA_ALIGNMENT); + } + else +#elif defined(FEATURE_64BIT_ALIGNMENT) if (pByValueMT->RequiresAlign8()) + { dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, 8); + largestAlignmentRequirement = max(largestAlignmentRequirement, 8); + } else #endif // FEATURE_64BIT_ALIGNMENT + if (pByValueMT->ContainsPointers()) + { + // this field type has GC pointers in it, which need to be pointer-size aligned + // so do this if it has not been done already dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, TARGET_POINTER_SIZE); -#endif // !(!defined(TARGET_64BIT) && (DATA_ALIGNMENT > 4)) + largestAlignmentRequirement = max(largestAlignmentRequirement, TARGET_POINTER_SIZE); + containsGCPointers = true; + } + else + { + int fieldAlignmentRequirement = pByValueMT->GetFieldAlignmentRequirement(); + largestAlignmentRequirement = max(largestAlignmentRequirement, fieldAlignmentRequirement); + dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, fieldAlignmentRequirement); + } pFieldDescList[i].SetOffset(dwCumulativeInstanceFieldPos - dwOffsetBias); - dwCumulativeInstanceFieldPos += pByValueMT->GetAlignedNumInstanceFieldBytes(); + dwCumulativeInstanceFieldPos += pByValueMT->GetNumInstanceFieldBytes(); - // Add pointer series for by-value classes - dwNumGCPointerSeries += pByValueMT->ContainsPointers() ? - (DWORD)CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries() : 0; + if (pByValueMT->ContainsPointers()) + { + // Add pointer series for by-value classes + dwNumGCPointerSeries += (DWORD)CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries(); + } + } + else + { + // non-value-type fields always require pointer alignment + // This does not account for types that are marked IsAlign8Candidate due to 8-byte fields + // but that is explicitly handled when we calculate the final alignment for the type. + largestAlignmentRequirement = max(largestAlignmentRequirement, TARGET_POINTER_SIZE); } } @@ -8223,7 +8252,7 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach else #endif // FEATURE_64BIT_ALIGNMENT if (dwNumInstanceFieldBytes > TARGET_POINTER_SIZE) { - minAlign = TARGET_POINTER_SIZE; + minAlign = containsGCPointers ? TARGET_POINTER_SIZE : (unsigned)largestAlignmentRequirement; } else { minAlign = 1; @@ -8231,6 +8260,13 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach minAlign *= 2; } + if (minAlign != min(dwNumInstanceFieldBytes, TARGET_POINTER_SIZE)) + { + EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap()); + GetHalfBakedClass()->GetOptionalFields()->m_requiredFieldAlignment = (BYTE)minAlign; + GetHalfBakedClass()->SetHasCustomFieldAlignment(); + } + dwNumInstanceFieldBytes = (dwNumInstanceFieldBytes + minAlign-1) & ~(minAlign-1); } @@ -8336,7 +8372,6 @@ MethodTableBuilder::HandleExplicitLayout( UINT instanceSliceSize = 0; DWORD firstObjectOverlapOffset = ((DWORD)(-1)); - UINT i; for (i = 0; i < bmtMetaData->cFields; i++) { @@ -8567,15 +8602,6 @@ MethodTableBuilder::HandleExplicitLayout( SetHasOverLayedFields(); } - if (IsBlittable() || IsManagedSequential()) - { - // Bug 849333: We shouldn't update "bmtFP->NumInstanceFieldBytes" - // for Blittable/ManagedSequential types. As this will break backward compatiblity - // for the size of types that return true for HasExplicitFieldOffsetLayout() - // - return; - } - FindPointerSeriesExplicit(instanceSliceSize, pFieldLayout); // Fixup the offset to include parent as current offsets are relative to instance slice @@ -8612,6 +8638,16 @@ MethodTableBuilder::HandleExplicitLayout( numInstanceFieldBytes = S_UINT32(clstotalsize); } } + else + { + // align up to the alignment requirements of the members of this value type. + numInstanceFieldBytes.AlignUp(GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers); + if (numInstanceFieldBytes.IsOverflow()) + { + // addition overflow or cast truncation + BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL); + } + } } // The GC requires that all valuetypes containing orefs be sized to a multiple of TARGET_POINTER_SIZE. diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index 69cba82dcf6f4..1dcc726213640 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -2180,7 +2180,7 @@ MarshalInfo::MarshalInfo(Module* pModule, IfFailGoto(E_FAIL, lFail); } - UINT managedSize = m_pMT->GetAlignedNumInstanceFieldBytes(); + UINT managedSize = m_pMT->GetNumInstanceFieldBytes(); UINT nativeSize = 0; if ( nativeSize > 0xfff0 || diff --git a/src/coreclr/vm/object.cpp b/src/coreclr/vm/object.cpp index af2201cbf4dce..6b64f72e5e280 100644 --- a/src/coreclr/vm/object.cpp +++ b/src/coreclr/vm/object.cpp @@ -390,7 +390,7 @@ void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, Meth if (argDest->IsHFA()) { - argDest->CopyHFAStructToRegister(src, pMT->GetAlignedNumInstanceFieldBytes()); + argDest->CopyHFAStructToRegister(src, pMT->GetNumInstanceFieldBytes()); return; } diff --git a/src/tests/Interop/StructPacking/StructPacking.cs b/src/tests/Interop/StructPacking/StructPacking.cs index ec59227b21243..e27181c40e3bb 100644 --- a/src/tests/Interop/StructPacking/StructPacking.cs +++ b/src/tests/Interop/StructPacking/StructPacking.cs @@ -127,7 +127,7 @@ static int Main(string[] args) succeeded &= TestVector128(); succeeded &= TestVector256(); - // Test custom data types with explicit size/packing + // Test custom data types with explicit size/packing succeeded &= TestMyVector64(); succeeded &= TestMyVector128(); succeeded &= TestMyVector256(); @@ -1140,65 +1140,42 @@ static bool TestVector64() expectedOffsetByte: 0, expectedOffsetValue: 8 ); - + succeeded &= Test>>( expectedSize: 16, expectedOffsetByte: 0, expectedOffsetValue: 8 ); - + succeeded &= Test>>( expectedSize: 9, expectedOffsetByte: 0, expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 16, expectedOffsetByte: 0, expectedOffsetValue: 8 ); - - if (RuntimeInformation.ProcessArchitecture != Architecture.X86) - { - succeeded &= Test>>( - expectedSize: 16, - expectedOffsetByte: 0, - expectedOffsetValue: 8 - ); - - succeeded &= Test>>( - expectedSize: 16, - expectedOffsetByte: 0, - expectedOffsetValue: 8 - ); - - succeeded &= Test>>( - expectedSize: 16, - expectedOffsetByte: 0, - expectedOffsetValue: 8 - ); - } - else - { - succeeded &= Test>>( - expectedSize: 12, - expectedOffsetByte: 0, - expectedOffsetValue: 4 - ); - - succeeded &= Test>>( - expectedSize: 12, - expectedOffsetByte: 0, - expectedOffsetValue: 4 - ); - - succeeded &= Test>>( - expectedSize: 12, - expectedOffsetByte: 0, - expectedOffsetValue: 4 - ); - } + + succeeded &= Test>>( + expectedSize: 16, + expectedOffsetByte: 0, + expectedOffsetValue: 8 + ); + + succeeded &= Test>>( + expectedSize: 16, + expectedOffsetByte: 0, + expectedOffsetValue: 8 + ); + + succeeded &= Test>>( + expectedSize: 16, + expectedOffsetByte: 0, + expectedOffsetValue: 8 + ); return succeeded; } @@ -1256,15 +1233,17 @@ static bool TestVector128() expectedOffsetValue: 1 ); - if (RuntimeInformation.ProcessArchitecture != Architecture.X86) + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm) { + // The Procedure Call Standard for ARM defines this type as having 8-byte alignment + succeeded &= Test>>( expectedSize: 24, expectedOffsetByte: 0, expectedOffsetValue: 8 ); - succeeded &= Test>>( + succeeded &= Test>>( expectedSize: 24, expectedOffsetByte: 0, expectedOffsetValue: 8 @@ -1279,21 +1258,21 @@ static bool TestVector128() else { succeeded &= Test>>( - expectedSize: 20, + expectedSize: 32, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 16 ); succeeded &= Test>>( - expectedSize: 20, + expectedSize: 32, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 16 ); succeeded &= Test>>( - expectedSize: 20, + expectedSize: 32, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 16 ); } @@ -1325,6 +1304,23 @@ static bool TestVector256() expectedOffsetByte: 0, expectedOffsetValue: 8 ); + succeeded &= Test>>( + expectedSize: 40, + expectedOffsetByte: 0, + expectedOffsetValue: 8 + ); + + succeeded &= Test>>( + expectedSize: 40, + expectedOffsetByte: 0, + expectedOffsetValue: 8 + ); + + succeeded &= Test>>( + expectedSize: 40, + expectedOffsetByte: 0, + expectedOffsetValue: 8 + ); } else if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) { @@ -1347,6 +1343,23 @@ static bool TestVector256() expectedOffsetByte: 0, expectedOffsetValue: 16 ); + succeeded &= Test>>( + expectedSize: 48, + expectedOffsetByte: 0, + expectedOffsetValue: 16 + ); + + succeeded &= Test>>( + expectedSize: 48, + expectedOffsetByte: 0, + expectedOffsetValue: 16 + ); + + succeeded &= Test>>( + expectedSize: 48, + expectedOffsetByte: 0, + expectedOffsetValue: 16 + ); } else { @@ -1367,54 +1380,31 @@ static bool TestVector256() expectedOffsetByte: 0, expectedOffsetValue: 32 ); - } - - succeeded &= Test>>( - expectedSize: 33, - expectedOffsetByte: 0, - expectedOffsetValue: 1 - ); - if (RuntimeInformation.ProcessArchitecture != Architecture.X86) - { succeeded &= Test>>( - expectedSize: 40, + expectedSize: 64, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 32 ); succeeded &= Test>>( - expectedSize: 40, + expectedSize: 64, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 32 ); succeeded &= Test>>( - expectedSize: 40, + expectedSize: 64, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 32 ); } - else - { - succeeded &= Test>>( - expectedSize: 36, - expectedOffsetByte: 0, - expectedOffsetValue: 4 - ); - succeeded &= Test>>( - expectedSize: 36, - expectedOffsetByte: 0, - expectedOffsetValue: 4 - ); - - succeeded &= Test>>( - expectedSize: 36, - expectedOffsetByte: 0, - expectedOffsetValue: 4 - ); - } + succeeded &= Test>>( + expectedSize: 33, + expectedOffsetByte: 0, + expectedOffsetValue: 1 + ); return succeeded; } @@ -1428,43 +1418,43 @@ static bool TestMyVector64() expectedOffsetByte: 0, expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 9, expectedOffsetByte: 0, expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 9, expectedOffsetByte: 0, expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 9, expectedOffsetByte: 0, expectedOffsetValue: 1 ); - + if (Environment.Is64BitProcess) { succeeded &= Test>>( expectedSize: 16, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 16, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 16, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); } else @@ -1472,19 +1462,19 @@ static bool TestMyVector64() succeeded &= Test>>( expectedSize: 12, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 12, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); - + succeeded &= Test>>( expectedSize: 12, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); } @@ -1524,19 +1514,19 @@ static bool TestMyVector128() succeeded &= Test>>( expectedSize: 24, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 24, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 24, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); } else @@ -1544,19 +1534,19 @@ static bool TestMyVector128() succeeded &= Test>>( expectedSize: 20, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 20, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 20, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); } @@ -1596,19 +1586,19 @@ static bool TestMyVector256() succeeded &= Test>>( expectedSize: 40, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 40, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 40, expectedOffsetByte: 0, - expectedOffsetValue: 8 + expectedOffsetValue: 1 ); } else @@ -1616,19 +1606,19 @@ static bool TestMyVector256() succeeded &= Test>>( expectedSize: 36, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 36, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); succeeded &= Test>>( expectedSize: 36, expectedOffsetByte: 0, - expectedOffsetValue: 4 + expectedOffsetValue: 1 ); } diff --git a/src/tests/JIT/Methodical/xxobj/sizeof/sizeof.il b/src/tests/JIT/Methodical/xxobj/sizeof/sizeof.il index 93f41fdf01f7b..08c4d16769da9 100644 --- a/src/tests/JIT/Methodical/xxobj/sizeof/sizeof.il +++ b/src/tests/JIT/Methodical/xxobj/sizeof/sizeof.il @@ -12,7 +12,7 @@ { } .assembly extern xunit.core {} -.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .namespace JitTest { .class private sequential ansi sealed beforefieldinit SimpleStruct @@ -99,7 +99,7 @@ IL_0028: call void [System.Console]System.Console::WriteLine(string) IL_002d: ldc.i4.s 102 IL_002f: stloc.0 - IL_0030: br.s EXIT + IL_0030: br EXIT IL_0032: sizeof JitTest.ComplexStruct2 IL_0038: sizeof JitTest.ComplexStruct IL_003e: ldc.i4.s 18 @@ -110,38 +110,40 @@ IL_004d: ldc.i4.s 103 IL_004f: stloc.0 IL_0050: br.s EXIT - + NEXT1: sizeof JitTest.RefComplexStruct - ldc.i4.s 68 + ldc.i4.s 72 beq.s NEXT2 - + ldstr "sizeof(RefComplexStruct) failed." call void [System.Console]System.Console::WriteLine(string) ldc.i4.s 104 stloc.0 br.s EXIT - - NEXT2: + + NEXT2: sizeof JitTest.RefComplexStruct2 sizeof JitTest.ComplexStruct2 ldc.i4.1 shl - ldc.i4.4 + ldc.i4.4 // Add 4 for the AppDomain field + add + ldc.i4.4 // Add 4 to ensure alignment for ComplexStruct2 (which contains longs) add beq.s OK - + ldstr "sizeof(RefComplexStruct2) failed." call void [System.Console]System.Console::WriteLine(string) ldc.i4.s 105 stloc.0 br.s EXIT - + OK: ldstr "sizeof passed" IL_0057: call void [System.Console]System.Console::WriteLine(string) IL_005c: ldc.i4 100 IL_005d: stloc.0 - + EXIT: ldloc.0 ret } diff --git a/src/tests/JIT/Methodical/xxobj/sizeof/sizeof32.il b/src/tests/JIT/Methodical/xxobj/sizeof/sizeof32.il index 6bde46d8d5325..1bf7400723517 100644 --- a/src/tests/JIT/Methodical/xxobj/sizeof/sizeof32.il +++ b/src/tests/JIT/Methodical/xxobj/sizeof/sizeof32.il @@ -5,7 +5,7 @@ .assembly extern mscorlib { } .assembly sizeof32 { } .assembly extern xunit.core {} -.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .namespace JitTest { .class private sequential ansi sealed beforefieldinit SimpleStruct @@ -128,7 +128,7 @@ IL_00b9: and IL_00ba: stloc.0 IL_00bb: ldloc.0 - IL_00bc: ldc.i4.s 28 + IL_00bc: ldc.i4.s 20 IL_00be: add IL_00bf: stloc.1 IL_00c0: br.s IL_00c2