@@ -414,18 +414,80 @@ ClassLayout* Compiler::typGetBlkLayout(unsigned blockSize)
414
414
return typGetCustomLayout (ClassLayoutBuilder (this , blockSize));
415
415
}
416
416
417
- unsigned Compiler::typGetArrayLayoutNum (CORINFO_CLASS_HANDLE classHandle, unsigned length)
417
+ ClassLayout* Compiler::typGetArrayLayout (CORINFO_CLASS_HANDLE classHandle, unsigned length)
418
418
{
419
419
ClassLayoutBuilder b = ClassLayoutBuilder::BuildArray (this , classHandle, length);
420
- return typGetCustomLayoutNum (b);
420
+ return typGetCustomLayout (b);
421
421
}
422
422
423
- ClassLayout* Compiler::typGetArrayLayout (CORINFO_CLASS_HANDLE classHandle, unsigned length )
423
+ ClassLayout* Compiler::typGetNonGCLayout (ClassLayout* layout )
424
424
{
425
- ClassLayoutBuilder b = ClassLayoutBuilder::BuildArray (this , classHandle, length);
425
+ assert (layout->HasGCPtr ());
426
+ ClassLayoutBuilder b (this , layout->GetSize ());
427
+ b.CopyPaddingFrom (0 , layout);
428
+
429
+ #ifdef DEBUG
430
+ b.CopyNameFrom (layout, " [nongc] " );
431
+ #endif
432
+
433
+ return typGetCustomLayout (b);
434
+ }
435
+
436
+ ClassLayout* Compiler::typGetByrefLayout (ClassLayout* layout)
437
+ {
438
+ assert (layout->HasGCPtr ());
439
+ ClassLayoutBuilder b (this , layout->GetSize ());
440
+ b.CopyPaddingFrom (0 , layout);
441
+ b.CopyGCInfoFromMakeByref (0 , layout);
442
+
443
+ #ifdef DEBUG
444
+ b.CopyNameFrom (layout, " [byref] " );
445
+ #endif
446
+
426
447
return typGetCustomLayout (b);
427
448
}
428
449
450
+ #ifdef DEBUG
451
+ // ------------------------------------------------------------------------
452
+ // CopyNameFrom: Copy layout names, with optional prefix.
453
+ //
454
+ // Parameters:
455
+ // layout - layout to copy from
456
+ // prefix - prefix to add (or nullptr)
457
+ //
458
+ void ClassLayoutBuilder::CopyNameFrom (ClassLayout* layout, const char * prefix)
459
+ {
460
+ const char * layoutName = layout->GetClassName ();
461
+ const char * layoutShortName = layout->GetShortClassName ();
462
+
463
+ if (prefix != nullptr )
464
+ {
465
+ char * newName = nullptr ;
466
+ char * newShortName = nullptr ;
467
+
468
+ if (layoutName != nullptr )
469
+ {
470
+ size_t len = strlen (prefix) + strlen (layoutName) + 1 ;
471
+ newName = m_compiler->getAllocator (CMK_DebugOnly).allocate <char >(len);
472
+ sprintf_s (newName, len, " %s%s" , prefix, layoutShortName);
473
+ }
474
+
475
+ if (layoutShortName != nullptr )
476
+ {
477
+ size_t len = strlen (prefix) + strlen (layoutName) + 1 ;
478
+ newShortName = m_compiler->getAllocator (CMK_DebugOnly).allocate <char >(len);
479
+ sprintf_s (newShortName, len, " %s%s" , prefix, layoutShortName);
480
+ }
481
+
482
+ SetName (newName, newShortName);
483
+ }
484
+ else
485
+ {
486
+ SetName (layoutName, layoutShortName);
487
+ }
488
+ }
489
+ #endif // DEBUG
490
+
429
491
// ------------------------------------------------------------------------
430
492
// Create: Create a ClassLayout from an EE side class handle.
431
493
//
@@ -646,8 +708,8 @@ const SegmentList& ClassLayout::GetNonPadding(Compiler* comp)
646
708
// AreCompatible: check if 2 layouts are the same for copying.
647
709
//
648
710
// Arguments:
649
- // layout1 - the first layout;
650
- // layout2 - the second layout.
711
+ // layout1 - the first layout (copy destination)
712
+ // layout2 - the second layout (copy source)
651
713
//
652
714
// Return value:
653
715
// true if compatible, false otherwise.
@@ -658,6 +720,8 @@ const SegmentList& ClassLayout::GetNonPadding(Compiler* comp)
658
720
//
659
721
// This is an equivalence relation:
660
722
// AreCompatible(a, b) == AreCompatible(b, a)
723
+ // AreCompatible(a, a) == true
724
+ // AreCompatible(a, b) && AreCompatible(b, c) ==> AreCompatible(a, c)
661
725
//
662
726
// static
663
727
bool ClassLayout::AreCompatible (const ClassLayout* layout1, const ClassLayout* layout2)
@@ -746,9 +810,92 @@ bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* l
746
810
//
747
811
bool ClassLayout::CanAssignFrom (const ClassLayout* layout)
748
812
{
749
- // Currently this is the same as compatability
813
+ if (this == layout)
814
+ {
815
+ return true ;
816
+ }
817
+
818
+ // Do the normal compatibility check first, when possible to do so.
819
+ //
820
+ if ((IsCustomLayout () == layout->IsCustomLayout ()) || (!HasGCPtr () && !layout->HasGCPtr ()))
821
+ {
822
+ const bool areCompatible = AreCompatible (this , layout);
823
+
824
+ if (areCompatible)
825
+ {
826
+ return true ;
827
+ }
828
+ }
829
+
830
+ // Must be same size
831
+ //
832
+ if (GetSize () != layout->GetSize ())
833
+ {
834
+ return false ;
835
+ }
836
+
837
+ // Must be same IR type
838
+ //
839
+ if (GetType () != layout->GetType ())
840
+ {
841
+ return false ;
842
+ }
843
+
844
+ // Dest is GC, source is GC. Allow, slotwise:
750
845
//
751
- return AreCompatible (this , layout);
846
+ // byref <- ref, byref, nint
847
+ // ref <- ref
848
+ // nint <- nint
849
+ //
850
+ if (HasGCPtr () && layout->HasGCPtr ())
851
+ {
852
+ const unsigned slotsCount = GetSlotCount ();
853
+ assert (slotsCount == layout->GetSlotCount ());
854
+
855
+ for (unsigned i = 0 ; i < slotsCount; ++i)
856
+ {
857
+ var_types slotType = GetGCPtrType (i);
858
+ var_types layoutSlotType = layout->GetGCPtrType (i);
859
+
860
+ if ((slotType != TYP_BYREF) && (slotType != layoutSlotType))
861
+ {
862
+ return false ;
863
+ }
864
+ }
865
+ return true ;
866
+ }
867
+
868
+ // Dest is GC, source is noGC. Allow, slotwise:
869
+ //
870
+ // byref <- nint
871
+ // nint <- nint
872
+ //
873
+ if (HasGCPtr () && !layout->HasGCPtr ())
874
+ {
875
+ const unsigned slotsCount = GetSlotCount ();
876
+
877
+ for (unsigned i = 0 ; i < slotsCount; ++i)
878
+ {
879
+ var_types slotType = GetGCPtrType (i);
880
+ if (slotType == TYP_REF)
881
+ {
882
+ return false ;
883
+ }
884
+ }
885
+ return true ;
886
+ }
887
+
888
+ // Dest is noGC, source is GC. Disallow.
889
+ //
890
+ if (!HasGCPtr () && layout->HasGCPtr ())
891
+ {
892
+ assert (!HasGCPtr ());
893
+ return false ;
894
+ }
895
+
896
+ // Dest is noGC, source is noGC, and they're not compatible.
897
+ //
898
+ return false ;
752
899
}
753
900
754
901
// ------------------------------------------------------------------------
@@ -814,7 +961,7 @@ ClassLayoutBuilder ClassLayoutBuilder::BuildArray(Compiler* compiler, CORINFO_CL
814
961
unsigned offset = OFFSETOF__CORINFO_Array__data;
815
962
for (unsigned i = 0 ; i < length; i++)
816
963
{
817
- builder.CopyInfoFrom (offset, elementLayout, /* copy padding */ false );
964
+ builder.CopyGCInfoFrom (offset, elementLayout);
818
965
offset += elementSize;
819
966
}
820
967
}
@@ -919,14 +1066,13 @@ void ClassLayoutBuilder::SetGCPtrType(unsigned slot, var_types type)
919
1066
}
920
1067
921
1068
// ------------------------------------------------------------------------
922
- // CopyInfoFrom : Copy GC pointers and padding information from another layout.
1069
+ // CopyInfoGCFrom : Copy GC pointers from another layout.
923
1070
//
924
1071
// Arguments:
925
1072
// offset - Offset in this builder to start copy information into.
926
1073
// layout - Layout to get information from.
927
- // copyPadding - Whether padding info should also be copied from the layout.
928
1074
//
929
- void ClassLayoutBuilder::CopyInfoFrom (unsigned offset, ClassLayout* layout, bool copyPadding )
1075
+ void ClassLayoutBuilder::CopyGCInfoFrom (unsigned offset, ClassLayout* layout)
930
1076
{
931
1077
assert (offset + layout->GetSize () <= m_size);
932
1078
@@ -939,18 +1085,53 @@ void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout, bool
939
1085
SetGCPtr (startSlot + slot, layout->GetGCPtr (slot));
940
1086
}
941
1087
}
1088
+ }
942
1089
943
- if (copyPadding)
944
- {
945
- AddPadding (SegmentList::Segment (offset, offset + layout->GetSize ()));
1090
+ // ------------------------------------------------------------------------
1091
+ // CopyInfoGCFromMakeByref: Copy GC pointers from another layout,and change
1092
+ // all gc references to be TYP_BYREF (TYPE_GC_BYREF)
1093
+ //
1094
+ // Arguments:
1095
+ // offset - Offset in this builder to start copy information into.
1096
+ // layout - Layout to get information from.
1097
+ //
1098
+ void ClassLayoutBuilder::CopyGCInfoFromMakeByref (unsigned offset, ClassLayout* layout)
1099
+ {
1100
+ assert (offset + layout->GetSize () <= m_size);
946
1101
947
- for (const SegmentList::Segment& nonPadding : layout->GetNonPadding (m_compiler))
1102
+ if (layout->GetGCPtrCount () > 0 )
1103
+ {
1104
+ assert (offset % TARGET_POINTER_SIZE == 0 );
1105
+ unsigned startSlot = offset / TARGET_POINTER_SIZE;
1106
+ for (unsigned slot = 0 ; slot < layout->GetSlotCount (); slot++)
948
1107
{
949
- RemovePadding (SegmentList::Segment (offset + nonPadding.Start , offset + nonPadding.End ));
1108
+ CorInfoGCType gcType = layout->GetGCPtr (slot);
1109
+ if (gcType == TYPE_GC_REF)
1110
+ {
1111
+ gcType = TYPE_GC_BYREF;
1112
+ }
1113
+ SetGCPtr (startSlot + slot, gcType);
950
1114
}
951
1115
}
952
1116
}
953
1117
1118
+ // ------------------------------------------------------------------------
1119
+ // CopyInfoPaddingFrom: Copy padding from another layout.
1120
+ //
1121
+ // Arguments:
1122
+ // offset - Offset in this builder to start copy information into.
1123
+ // layout - Layout to get information from.
1124
+ //
1125
+ void ClassLayoutBuilder::CopyPaddingFrom (unsigned offset, ClassLayout* layout)
1126
+ {
1127
+ AddPadding (SegmentList::Segment (offset, offset + layout->GetSize ()));
1128
+
1129
+ for (const SegmentList::Segment& nonPadding : layout->GetNonPadding (m_compiler))
1130
+ {
1131
+ RemovePadding (SegmentList::Segment (offset + nonPadding.Start , offset + nonPadding.End ));
1132
+ }
1133
+ }
1134
+
954
1135
// ------------------------------------------------------------------------
955
1136
// GetOrCreateNonPadding: Get the non padding segment list, or create it if it
956
1137
// does not exist.
0 commit comments