@@ -308,9 +308,11 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
308308 {
309309 // Instance slice size is the total size of instance not including the base type.
310310 // It is calculated as the field whose offset and size add to the greatest value.
311+ LayoutInt offsetBias = ! type . IsValueType ? new LayoutInt ( type . Context . Target . PointerSize ) : LayoutInt . Zero ;
311312 LayoutInt cumulativeInstanceFieldPos =
312313 type . HasBaseType && ! type . IsValueType ? type . BaseType . InstanceByteCount : LayoutInt . Zero ;
313314 LayoutInt instanceSize = cumulativeInstanceFieldPos ;
315+ cumulativeInstanceFieldPos -= offsetBias ;
314316
315317 var layoutMetadata = type . GetClassLayout ( ) ;
316318
@@ -333,7 +335,7 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
333335 if ( fieldAndOffset . Offset == FieldAndOffset . InvalidOffset )
334336 ThrowHelper . ThrowTypeLoadException ( ExceptionStringID . ClassLoadBadFormat , type ) ;
335337
336- LayoutInt computedOffset = fieldAndOffset . Offset + cumulativeInstanceFieldPos ;
338+ LayoutInt computedOffset = fieldAndOffset . Offset + cumulativeInstanceFieldPos + offsetBias ;
337339
338340 // GC pointers MUST be aligned.
339341 // We treat byref-like structs as GC pointers too.
@@ -379,29 +381,20 @@ protected static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(Metadata
379381 return computedLayout ;
380382 }
381383
382- private static LayoutInt AlignUpInstanceFieldOffset ( TypeDesc typeWithField , LayoutInt cumulativeInstanceFieldPos , LayoutInt alignment , TargetDetails target , bool armAlignFromStartOfFields = false )
384+ private static LayoutInt AlignUpInstanceFieldOffset ( TypeDesc typeWithField , LayoutInt cumulativeInstanceFieldPos , LayoutInt alignment , TargetDetails target )
383385 {
384- if ( ! typeWithField . IsValueType && ( target . Architecture == TargetArchitecture . X86 || ( armAlignFromStartOfFields && target . Architecture == TargetArchitecture . ARM ) ) && cumulativeInstanceFieldPos != new LayoutInt ( 0 ) )
385- {
386- // Alignment of fields is relative to the start of the field list, not the start of the object
387- //
388- // The code in the VM is written as if this is the rule for all architectures, but for ARM 32bit platforms
389- // there is an additional adjustment via dwOffsetBias that aligns fields based on the start of the object
390- cumulativeInstanceFieldPos = cumulativeInstanceFieldPos - new LayoutInt ( target . PointerSize ) ;
391- return LayoutInt . AlignUp ( cumulativeInstanceFieldPos , alignment , target ) + new LayoutInt ( target . PointerSize ) ;
392- }
393- else
394- {
395- return LayoutInt . AlignUp ( cumulativeInstanceFieldPos , alignment , target ) ;
396- }
386+ return LayoutInt . AlignUp ( cumulativeInstanceFieldPos , alignment , target ) ;
397387 }
398388
399- protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout ( MetadataType type , int numInstanceFields )
389+ protected ComputedInstanceFieldLayout ComputeSequentialFieldLayout ( MetadataType type , int numInstanceFields )
400390 {
401391 var offsets = new FieldAndOffset [ numInstanceFields ] ;
402392
403393 // For types inheriting from another type, field offsets continue on from where they left off
404- LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType ( type ) ;
394+ // For reference types, we calculate field alignment as if the address after the method table pointer
395+ // has offset 0 (on 32-bit platforms, this location is guaranteed to be 8-aligned).
396+ LayoutInt offsetBias = ! type . IsValueType ? new LayoutInt ( type . Context . Target . PointerSize ) : LayoutInt . Zero ;
397+ LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset ( type , requiresAlign8 : false , requiresAlignedBase : false ) - offsetBias ;
405398
406399 var layoutMetadata = type . GetClassLayout ( ) ;
407400
@@ -421,18 +414,15 @@ protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(Metada
421414
422415 largestAlignmentRequirement = LayoutInt . Max ( fieldSizeAndAlignment . Alignment , largestAlignmentRequirement ) ;
423416
424- cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset ( type , cumulativeInstanceFieldPos , fieldSizeAndAlignment . Alignment , type . Context . Target ,
425- armAlignFromStartOfFields : true // In what appears to have been a bug in the design of the arm32 type layout code
426- // this portion of the layout algorithm does not layout from the start of the object
427- ) ;
428- offsets [ fieldOrdinal ] = new FieldAndOffset ( field , cumulativeInstanceFieldPos ) ;
417+ cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset ( type , cumulativeInstanceFieldPos , fieldSizeAndAlignment . Alignment , type . Context . Target ) ;
418+ offsets [ fieldOrdinal ] = new FieldAndOffset ( field , cumulativeInstanceFieldPos + offsetBias ) ;
429419 cumulativeInstanceFieldPos = checked ( cumulativeInstanceFieldPos + fieldSizeAndAlignment . Size ) ;
430420
431421 fieldOrdinal ++ ;
432422 }
433423
434424 SizeAndAlignment instanceByteSizeAndAlignment ;
435- var instanceSizeAndAlignment = ComputeInstanceSize ( type , cumulativeInstanceFieldPos , largestAlignmentRequirement , layoutMetadata . Size , out instanceByteSizeAndAlignment ) ;
425+ var instanceSizeAndAlignment = ComputeInstanceSize ( type , cumulativeInstanceFieldPos + offsetBias , largestAlignmentRequirement , layoutMetadata . Size , out instanceByteSizeAndAlignment ) ;
436426
437427 ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout ( ) ;
438428 computedLayout . FieldAlignment = instanceSizeAndAlignment . Alignment ;
@@ -445,14 +435,12 @@ protected static ComputedInstanceFieldLayout ComputeSequentialFieldLayout(Metada
445435 return computedLayout ;
446436 }
447437
448- protected virtual void AlignBaseOffsetIfNecessary ( MetadataType type , ref LayoutInt baseOffset , bool requiresAlign8 )
438+ protected virtual void AlignBaseOffsetIfNecessary ( MetadataType type , ref LayoutInt baseOffset , bool requiresAlign8 , bool requiresAlignedBase )
449439 {
450440 }
451441
452442 protected ComputedInstanceFieldLayout ComputeAutoFieldLayout ( MetadataType type , int numInstanceFields )
453443 {
454- // For types inheriting from another type, field offsets continue on from where they left off
455- LayoutInt cumulativeInstanceFieldPos = ComputeBytesUsedInParentType ( type ) ;
456444 TypeSystemContext context = type . Context ;
457445
458446 var layoutMetadata = type . GetClassLayout ( ) ;
@@ -463,7 +451,6 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
463451 var offsets = new FieldAndOffset [ numInstanceFields ] ;
464452 int fieldOrdinal = 0 ;
465453
466-
467454 // Iterate over the instance fields and keep track of the number of fields of each category
468455 // For the non-GC Pointer fields, we will keep track of the number of fields by log2(size)
469456 int maxLog2Size = CalculateLog2 ( TargetDetails . MaximumPrimitiveSize ) ;
@@ -552,18 +539,15 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
552539 largestAlignmentRequired = context . Target . GetObjectAlignment ( largestAlignmentRequired ) ;
553540 bool requiresAlign8 = ! largestAlignmentRequired . IsIndeterminate && largestAlignmentRequired . AsInt > 4 ;
554541
555- if ( ! type . IsValueType )
542+ // For types inheriting from another type, field offsets continue on from where they left off
543+ // Base alignment is not always required, it's only applied when there's a version bubble boundary
544+ // between base type and the current type.
545+ LayoutInt cumulativeInstanceFieldPos = CalculateFieldBaseOffset ( type , requiresAlign8 , requiresAlignedBase : false ) ;
546+ LayoutInt offsetBias = LayoutInt . Zero ;
547+ if ( ! type . IsValueType && cumulativeInstanceFieldPos != LayoutInt . Zero && type . Context . Target . Architecture == TargetArchitecture . X86 )
556548 {
557- DefType baseType = type . BaseType ;
558- if ( baseType != null && ! baseType . IsObject )
559- {
560- if ( ! requiresAlign8 && baseType . RequiresAlign8 ( ) )
561- {
562- requiresAlign8 = true ;
563- }
564-
565- AlignBaseOffsetIfNecessary ( type , ref cumulativeInstanceFieldPos , requiresAlign8 ) ;
566- }
549+ offsetBias = new LayoutInt ( type . Context . Target . PointerSize ) ;
550+ cumulativeInstanceFieldPos -= offsetBias ;
567551 }
568552
569553 // We've finished placing the fields into their appropriate arrays
@@ -638,7 +622,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
638622 // Place the field
639623 j = instanceNonGCPointerFieldsCount [ i ] ;
640624 FieldDesc field = instanceNonGCPointerFieldsArr [ i ] [ j ] ;
641- PlaceInstanceField ( field , packingSize , offsets , ref cumulativeInstanceFieldPos , ref fieldOrdinal ) ;
625+ PlaceInstanceField ( field , packingSize , offsets , ref cumulativeInstanceFieldPos , ref fieldOrdinal , offsetBias ) ;
642626
643627 instanceNonGCPointerFieldsCount [ i ] ++ ;
644628 }
@@ -655,14 +639,14 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
655639 {
656640 for ( int j = 0 ; j < instanceGCPointerFieldsArr . Length ; j ++ )
657641 {
658- PlaceInstanceField ( instanceGCPointerFieldsArr [ j ] , packingSize , offsets , ref cumulativeInstanceFieldPos , ref fieldOrdinal ) ;
642+ PlaceInstanceField ( instanceGCPointerFieldsArr [ j ] , packingSize , offsets , ref cumulativeInstanceFieldPos , ref fieldOrdinal , offsetBias ) ;
659643 }
660644 }
661645
662646 // The start index will be the index that may have been increased in the previous optimization
663647 for ( int j = instanceNonGCPointerFieldsCount [ i ] ; j < instanceNonGCPointerFieldsArr [ i ] . Length ; j ++ )
664648 {
665- PlaceInstanceField ( instanceNonGCPointerFieldsArr [ i ] [ j ] , packingSize , offsets , ref cumulativeInstanceFieldPos , ref fieldOrdinal ) ;
649+ PlaceInstanceField ( instanceNonGCPointerFieldsArr [ i ] [ j ] , packingSize , offsets , ref cumulativeInstanceFieldPos , ref fieldOrdinal , offsetBias ) ;
666650 }
667651 }
668652
@@ -685,7 +669,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
685669 LayoutInt AlignmentRequired = LayoutInt . Max ( fieldSizeAndAlignment . Alignment , context . Target . LayoutPointerSize ) ;
686670 cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset ( type , cumulativeInstanceFieldPos , AlignmentRequired , context . Target ) ;
687671 }
688- offsets [ fieldOrdinal ] = new FieldAndOffset ( instanceValueClassFieldsArr [ i ] , cumulativeInstanceFieldPos ) ;
672+ offsets [ fieldOrdinal ] = new FieldAndOffset ( instanceValueClassFieldsArr [ i ] , cumulativeInstanceFieldPos + offsetBias ) ;
689673
690674 // If the field has an indeterminate size, align the cumulative field offset to the indeterminate value
691675 // Otherwise, align the cumulative field offset to the aligned-instance field size
@@ -720,7 +704,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
720704 }
721705
722706 SizeAndAlignment instanceByteSizeAndAlignment ;
723- var instanceSizeAndAlignment = ComputeInstanceSize ( type , cumulativeInstanceFieldPos , minAlign , 0 /* specified field size unused */ , out instanceByteSizeAndAlignment ) ;
707+ var instanceSizeAndAlignment = ComputeInstanceSize ( type , cumulativeInstanceFieldPos + offsetBias , minAlign , 0 /* specified field size unused */ , out instanceByteSizeAndAlignment ) ;
724708
725709 ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout ( ) ;
726710 computedLayout . FieldAlignment = instanceSizeAndAlignment . Alignment ;
@@ -733,12 +717,12 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
733717 return computedLayout ;
734718 }
735719
736- private static void PlaceInstanceField ( FieldDesc field , int packingSize , FieldAndOffset [ ] offsets , ref LayoutInt instanceFieldPos , ref int fieldOrdinal )
720+ private static void PlaceInstanceField ( FieldDesc field , int packingSize , FieldAndOffset [ ] offsets , ref LayoutInt instanceFieldPos , ref int fieldOrdinal , LayoutInt offsetBias )
737721 {
738722 var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment ( field . FieldType , packingSize , out bool _ ) ;
739723
740724 instanceFieldPos = AlignUpInstanceFieldOffset ( field . OwningType , instanceFieldPos , fieldSizeAndAlignment . Alignment , field . Context . Target ) ;
741- offsets [ fieldOrdinal ] = new FieldAndOffset ( field , instanceFieldPos ) ;
725+ offsets [ fieldOrdinal ] = new FieldAndOffset ( field , instanceFieldPos + offsetBias ) ;
742726 instanceFieldPos = checked ( instanceFieldPos + fieldSizeAndAlignment . Size ) ;
743727
744728 fieldOrdinal ++ ;
@@ -775,13 +759,22 @@ private static bool IsByValueClass(TypeDesc type)
775759 return type . IsValueType && ! type . IsPrimitive && ! type . IsEnum ;
776760 }
777761
778- private static LayoutInt ComputeBytesUsedInParentType ( DefType type )
762+ public LayoutInt CalculateFieldBaseOffset ( MetadataType type , bool requiresAlign8 , bool requiresAlignedBase )
779763 {
780764 LayoutInt cumulativeInstanceFieldPos = LayoutInt . Zero ;
781765
782766 if ( ! type . IsValueType && type . HasBaseType )
783767 {
784768 cumulativeInstanceFieldPos = type . BaseType . InstanceByteCountUnaligned ;
769+ if ( ! type . BaseType . InstanceByteCountUnaligned . IsIndeterminate )
770+ {
771+ cumulativeInstanceFieldPos = type . BaseType . InstanceByteCountUnaligned ;
772+ if ( type . BaseType . IsZeroSizedReferenceType && ( ( MetadataType ) type . BaseType ) . HasLayout ( ) )
773+ {
774+ cumulativeInstanceFieldPos += LayoutInt . One ;
775+ }
776+ AlignBaseOffsetIfNecessary ( type , ref cumulativeInstanceFieldPos , requiresAlign8 , requiresAlignedBase ) ;
777+ }
785778 }
786779
787780 return cumulativeInstanceFieldPos ;
0 commit comments