@@ -2368,7 +2368,7 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
23682368 parNode ->size = ( uint ) type . GetElementSize ( ) . AsInt ;
23692369 parNode ->numFields = 0 ;
23702370 parNode ->type = CorInfoType . CORINFO_TYPE_VALUECLASS ;
2371- parNode ->hasSignificantPadding = false ;
2371+ parNode ->hasSignificantPadding = type . IsExplicitLayout || ( type . IsSequentialLayout && type . GetClassLayout ( ) . Size != 0 ) ;
23722372
23732373#if READYTORUN
23742374 // The contract of getTypeLayout is carefully crafted to still
@@ -2381,7 +2381,7 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
23812381 // amenable to the optimizations that this unlocks if they already
23822382 // went through EncodeFieldBaseOffset.
23832383 //
2384- if ( ! _compilation . IsLayoutFixedInCurrentVersionBubble ( type ) )
2384+ if ( ! parNode -> hasSignificantPadding && ! _compilation . IsLayoutFixedInCurrentVersionBubble ( type ) )
23852385 {
23862386 // For types without fixed layout the JIT is not allowed to
23872387 // rely on padding bits being insignificant, since fields could
@@ -2391,14 +2391,6 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
23912391 }
23922392#endif
23932393
2394- if ( type . IsExplicitLayout || ( type . IsSequentialLayout && type . GetClassLayout ( ) . Size != 0 ) || type . IsInlineArray )
2395- {
2396- if ( ! type . ContainsGCPointers && ! type . IsByRefLike )
2397- {
2398- parNode ->hasSignificantPadding = true ;
2399- }
2400- }
2401-
24022394 // The intrinsic SIMD/HW SIMD types have a lot of fields that the JIT does
24032395 // not care about since they are considered primitives by the JIT.
24042396 if ( type . IsIntrinsic )
@@ -2472,19 +2464,43 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
24722464 int elemSize = fieldType . GetElementSize ( ) . AsInt ;
24732465 int arrSize = type . GetElementSize ( ) . AsInt ;
24742466
2467+ // Number of fields added for each element, including all
2468+ // subfields. For example, for ValueTuple<int, int>[4]:
2469+ // [ 0]: InlineArray parent = -1
2470+ // [ 1]: ValueTuple<int, int> parent = 0 -
2471+ // [ 2]: int parent = 1 |
2472+ // [ 3]: int parent = 1 |
2473+ // [ 4]: ValueTuple<int, int> parent = 0 - stride = 3
2474+ // [ 5]: int parent = 4
2475+ // [ 6]: int parent = 4
2476+ // [ 7]: ValueTuple<int, int> parent = 0
2477+ // [ 8]: int parent = 7
2478+ // [ 9]: int parent = 7
2479+ // [10]: ValueTuple<int, int> parent = 0
2480+ // [11]: int parent = 10
2481+ // [12]: int parent = 10
2482+ uint elemFieldsStride = ( uint ) * numTreeNodes - ( structNodeIndex + 1 ) ;
2483+
2484+ // Now duplicate the fields of the previous entry for each
2485+ // additional element. For each entry we have to update the
2486+ // offset and the parent index.
24752487 for ( int elemOffset = elemSize ; elemOffset < arrSize ; elemOffset += elemSize )
24762488 {
2477- for ( nuint templateTreeNodeIndex = structNodeIndex + 1 ; templateTreeNodeIndex < treeNodeEnd ; templateTreeNodeIndex ++ )
2489+ nuint prevElemStart = * numTreeNodes - elemFieldsStride ;
2490+ for ( nuint i = 0 ; i < elemFieldsStride ; i ++ )
24782491 {
24792492 if ( * numTreeNodes >= maxTreeNodes )
24802493 return GetTypeLayoutResult . Partial ;
24812494
24822495 CORINFO_TYPE_LAYOUT_NODE * treeNode = & treeNodes [ ( * numTreeNodes ) ++ ] ;
2483- * treeNode = treeNodes [ templateTreeNodeIndex ] ;
2484- treeNode ->offset += ( uint ) elemOffset ;
2485-
2486- parNode ->numFields ++ ;
2496+ * treeNode = treeNodes [ prevElemStart + i ] ;
2497+ treeNode ->offset += ( uint ) elemSize ;
2498+ // The first field points back to the inline array
2499+ // and has no bias; the rest of them do.
2500+ treeNode ->parent += ( i == 0 ) ? 0 : elemFieldsStride ;
24872501 }
2502+
2503+ parNode ->numFields ++ ;
24882504 }
24892505 }
24902506 }
0 commit comments