@@ -2368,7 +2368,7 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
2368
2368
parNode ->size = ( uint ) type . GetElementSize ( ) . AsInt ;
2369
2369
parNode ->numFields = 0 ;
2370
2370
parNode ->type = CorInfoType . CORINFO_TYPE_VALUECLASS ;
2371
- parNode ->hasSignificantPadding = false ;
2371
+ parNode ->hasSignificantPadding = type . IsExplicitLayout || ( type . IsSequentialLayout && type . GetClassLayout ( ) . Size != 0 ) ;
2372
2372
2373
2373
#if READYTORUN
2374
2374
// The contract of getTypeLayout is carefully crafted to still
@@ -2381,7 +2381,7 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
2381
2381
// amenable to the optimizations that this unlocks if they already
2382
2382
// went through EncodeFieldBaseOffset.
2383
2383
//
2384
- if ( ! _compilation . IsLayoutFixedInCurrentVersionBubble ( type ) )
2384
+ if ( ! parNode -> hasSignificantPadding && ! _compilation . IsLayoutFixedInCurrentVersionBubble ( type ) )
2385
2385
{
2386
2386
// For types without fixed layout the JIT is not allowed to
2387
2387
// rely on padding bits being insignificant, since fields could
@@ -2391,14 +2391,6 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
2391
2391
}
2392
2392
#endif
2393
2393
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
-
2402
2394
// The intrinsic SIMD/HW SIMD types have a lot of fields that the JIT does
2403
2395
// not care about since they are considered primitives by the JIT.
2404
2396
if ( type . IsIntrinsic )
@@ -2472,19 +2464,43 @@ private GetTypeLayoutResult GetTypeLayoutHelper(MetadataType type, uint parentIn
2472
2464
int elemSize = fieldType . GetElementSize ( ) . AsInt ;
2473
2465
int arrSize = type . GetElementSize ( ) . AsInt ;
2474
2466
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.
2475
2487
for ( int elemOffset = elemSize ; elemOffset < arrSize ; elemOffset += elemSize )
2476
2488
{
2477
- for ( nuint templateTreeNodeIndex = structNodeIndex + 1 ; templateTreeNodeIndex < treeNodeEnd ; templateTreeNodeIndex ++ )
2489
+ nuint prevElemStart = * numTreeNodes - elemFieldsStride ;
2490
+ for ( nuint i = 0 ; i < elemFieldsStride ; i ++ )
2478
2491
{
2479
2492
if ( * numTreeNodes >= maxTreeNodes )
2480
2493
return GetTypeLayoutResult . Partial ;
2481
2494
2482
2495
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 ;
2487
2501
}
2502
+
2503
+ parNode ->numFields ++ ;
2488
2504
}
2489
2505
}
2490
2506
}
0 commit comments