@@ -960,12 +960,6 @@ bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNum,
960
960
return false ;
961
961
}
962
962
963
- if (comp->info .compCompHnd ->getTypeForBoxOnStack (clsHnd) == NO_CLASS_HANDLE)
964
- {
965
- *reason = " [no boxed type available]" ;
966
- return false ;
967
- }
968
-
969
963
classSize = comp->info .compCompHnd ->getClassSize (clsHnd);
970
964
}
971
965
else
@@ -1061,6 +1055,7 @@ ObjectAllocator::ObjectAllocationType ObjectAllocator::AllocationKind(GenTree* t
1061
1055
return allocType;
1062
1056
}
1063
1057
1058
+ // ------------------------------------------------------------------------
1064
1059
// MorphAllocObjNodes: Morph each GT_ALLOCOBJ node either into an
1065
1060
// allocation helper call or stack allocation.
1066
1061
//
@@ -1203,13 +1198,11 @@ bool ObjectAllocator::MorphAllocObjNodes()
1203
1198
// ------------------------------------------------------------------------
1204
1199
1205
1200
CORINFO_CLASS_HANDLE clsHnd = data->AsAllocObj ()->gtAllocObjClsHnd ;
1206
- CORINFO_CLASS_HANDLE stackClsHnd = clsHnd;
1207
1201
const bool isValueClass = comp->info .compCompHnd ->isValueClass (clsHnd);
1208
1202
1209
1203
if (isValueClass)
1210
1204
{
1211
1205
comp->Metrics .NewBoxedValueClassHelperCalls ++;
1212
- stackClsHnd = comp->info .compCompHnd ->getTypeForBoxOnStack (clsHnd);
1213
1206
}
1214
1207
else
1215
1208
{
@@ -1221,29 +1214,31 @@ bool ObjectAllocator::MorphAllocObjNodes()
1221
1214
// reason set by the call
1222
1215
canStack = false ;
1223
1216
}
1224
- else if (stackClsHnd == NO_CLASS_HANDLE)
1225
- {
1226
- assert (isValueClass);
1227
- onHeapReason = " [no class handle for this boxed value class]" ;
1228
- canStack = false ;
1229
- }
1230
1217
else
1231
1218
{
1232
1219
JITDUMP (" Allocating V%02u on the stack\n " , lclNum);
1233
1220
canStack = true ;
1234
- const unsigned int stackLclNum =
1235
- MorphAllocObjNodeIntoStackAlloc (data->AsAllocObj (), stackClsHnd, isValueClass, block, stmt);
1236
- m_HeapLocalToStackLocalMap.AddOrUpdate (lclNum, stackLclNum);
1221
+
1222
+ ClassLayout* layout = nullptr ;
1237
1223
1238
1224
if (isValueClass)
1239
1225
{
1226
+ CORINFO_CLASS_HANDLE boxedClsHnd = comp->info .compCompHnd ->getTypeForBox (clsHnd);
1227
+ assert (boxedClsHnd != NO_CLASS_HANDLE);
1228
+ ClassLayout* structLayout = comp->typGetObjLayout (boxedClsHnd);
1229
+ layout = GetBoxedLayout (structLayout);
1240
1230
comp->Metrics .StackAllocatedBoxedValueClasses ++;
1241
1231
}
1242
1232
else
1243
1233
{
1234
+ layout = comp->typGetObjLayout (clsHnd);
1244
1235
comp->Metrics .StackAllocatedRefClasses ++;
1245
1236
}
1246
1237
1238
+ const unsigned int stackLclNum =
1239
+ MorphAllocObjNodeIntoStackAlloc (data->AsAllocObj (), layout, block, stmt);
1240
+ m_HeapLocalToStackLocalMap.AddOrUpdate (lclNum, stackLclNum);
1241
+
1247
1242
bashCall = true ;
1248
1243
}
1249
1244
}
@@ -1449,8 +1444,7 @@ unsigned int ObjectAllocator::MorphNewArrNodeIntoStackAlloc(GenTreeCall*
1449
1444
// allocation.
1450
1445
// Arguments:
1451
1446
// allocObj - GT_ALLOCOBJ that will be replaced by a stack allocation
1452
- // clsHnd - class representing the stack allocated object
1453
- // isValueClass - we are stack allocating a boxed value class
1447
+ // layout - layout for the stack allocated objectd
1454
1448
// block - a basic block where allocObj is
1455
1449
// stmt - a statement where allocObj is
1456
1450
//
@@ -1460,24 +1454,29 @@ unsigned int ObjectAllocator::MorphNewArrNodeIntoStackAlloc(GenTreeCall*
1460
1454
// Notes:
1461
1455
// This function can insert additional statements before stmt.
1462
1456
//
1463
- unsigned int ObjectAllocator::MorphAllocObjNodeIntoStackAlloc (
1464
- GenTreeAllocObj* allocObj, CORINFO_CLASS_HANDLE clsHnd, bool isValueClass, BasicBlock* block, Statement* stmt)
1457
+ unsigned int ObjectAllocator::MorphAllocObjNodeIntoStackAlloc (GenTreeAllocObj* allocObj,
1458
+ ClassLayout* layout,
1459
+ BasicBlock* block,
1460
+ Statement* stmt)
1465
1461
{
1466
1462
assert (allocObj != nullptr );
1467
1463
assert (m_AnalysisDone);
1468
- assert (clsHnd != NO_CLASS_HANDLE);
1469
1464
1470
- const bool shortLifetime = false ;
1471
- const unsigned int lclNum = comp->lvaGrabTemp (shortLifetime DEBUGARG (
1472
- isValueClass ? " stack allocated boxed value class temp " : " stack allocated ref class temp " ));
1465
+ # ifdef DEBUG
1466
+ const char * lclName = comp->printfAlloc ( " stack allocated %.110s " , layout-> GetShortClassName ());
1467
+ # endif
1473
1468
1474
- comp->lvaSetStruct (lclNum, clsHnd, /* unsafeValueClsCheck */ false );
1469
+ const bool shortLifetime = false ;
1470
+ const unsigned int lclNum = comp->lvaGrabTemp (shortLifetime DEBUGARG (lclName));
1471
+ comp->lvaSetStruct (lclNum, layout, /* unsafeValueClsCheck */ false );
1475
1472
1476
- // Initialize the object memory if necessary.
1477
- bool bbInALoop = block->HasFlag (BBF_BACKWARD_JUMP);
1478
- bool bbIsReturn = block->KindIs (BBJ_RETURN);
1479
1473
LclVarDsc* const lclDsc = comp->lvaGetDesc (lclNum);
1480
1474
lclDsc->lvStackAllocatedObject = true ;
1475
+
1476
+ // Initialize the object memory if necessary.
1477
+ bool bbInALoop = block->HasFlag (BBF_BACKWARD_JUMP);
1478
+ bool bbIsReturn = block->KindIs (BBJ_RETURN);
1479
+
1481
1480
if (comp->fgVarNeedsExplicitZeroInit (lclNum, bbInALoop, bbIsReturn))
1482
1481
{
1483
1482
// ------------------------------------------------------------------------
@@ -2317,15 +2316,15 @@ void ObjectAllocator::RewriteUses()
2317
2316
if (newType == TYP_I_IMPL)
2318
2317
{
2319
2318
// New layout with no gc refs + padding
2320
- newLayout = comp-> typGetNonGCLayout (layout);
2319
+ newLayout = GetNonGCLayout (layout);
2321
2320
JITDUMP (" Changing layout of struct V%02u to block\n " , lclNum);
2322
2321
lclVarDsc->ChangeLayout (newLayout);
2323
2322
}
2324
2323
else
2325
2324
{
2326
2325
// New layout with all gc refs as byrefs + padding
2327
2326
// (todo, perhaps: see if old layout was already all byrefs)
2328
- newLayout = comp-> typGetByrefLayout (layout);
2327
+ newLayout = GetByrefLayout (layout);
2329
2328
JITDUMP (" Changing layout of struct V%02u to byref\n " , lclNum);
2330
2329
lclVarDsc->ChangeLayout (newLayout);
2331
2330
}
@@ -4077,3 +4076,80 @@ void ObjectAllocator::CloneAndSpecialize()
4077
4076
4078
4077
assert (numberOfClonedRegions == m_regionsToClone);
4079
4078
}
4079
+
4080
+ // ------------------------------------------------------------------------------
4081
+ // GetBoxedLayout: get a layout for a boxed version of a struct
4082
+ //
4083
+ // Arguments:
4084
+ // layout - layout of the struct
4085
+ //
4086
+ // Notes:
4087
+ // For Nullable<T>, layout class should be T
4088
+ //
4089
+ ClassLayout* ObjectAllocator::GetBoxedLayout (ClassLayout* layout)
4090
+ {
4091
+ assert (layout->IsValueClass ());
4092
+
4093
+ ClassLayoutBuilder b (comp, TARGET_POINTER_SIZE + layout->GetSize ());
4094
+ b.CopyPaddingFrom (TARGET_POINTER_SIZE, layout);
4095
+ b.CopyGCInfoFrom (TARGET_POINTER_SIZE, layout);
4096
+
4097
+ #ifdef DEBUG
4098
+ b.CopyNameFrom (layout, " [boxed] " );
4099
+ #endif
4100
+
4101
+ return comp->typGetCustomLayout (b);
4102
+ }
4103
+
4104
+ // ------------------------------------------------------------------------------
4105
+ // GetNonGCLayout: get a layout with the same size and padding as an existing
4106
+ // layout, but with no GC fields.
4107
+ //
4108
+ // Arguments:
4109
+ // layout - existing layout to use as template
4110
+ //
4111
+ ClassLayout* ObjectAllocator::GetNonGCLayout (ClassLayout* layout)
4112
+ {
4113
+ assert (layout->HasGCPtr ());
4114
+ ClassLayoutBuilder b (comp, layout->GetSize ());
4115
+ b.CopyPaddingFrom (0 , layout);
4116
+
4117
+ #ifdef DEBUG
4118
+ b.CopyNameFrom (layout, " [nongc] " );
4119
+ #endif
4120
+
4121
+ return comp->typGetCustomLayout (b);
4122
+ }
4123
+
4124
+ // ------------------------------------------------------------------------------
4125
+ // GetByrefLayout: get a layout with the same size and padding as an existing
4126
+ // layout, but with all GC fields retyped to byref.
4127
+ //
4128
+ // Arguments:
4129
+ // layout - existing layout to use as template
4130
+ //
4131
+ ClassLayout* ObjectAllocator::GetByrefLayout (ClassLayout* layout)
4132
+ {
4133
+ assert (layout->HasGCPtr ());
4134
+ ClassLayoutBuilder b (comp, layout->GetSize ());
4135
+ b.CopyPaddingFrom (0 , layout);
4136
+
4137
+ if (layout->GetGCPtrCount () > 0 )
4138
+ {
4139
+ for (unsigned slot = 0 ; slot < layout->GetSlotCount (); slot++)
4140
+ {
4141
+ var_types gcType = layout->GetGCPtrType (slot);
4142
+ if (gcType == TYP_REF)
4143
+ {
4144
+ gcType = TYP_BYREF;
4145
+ }
4146
+ b.SetGCPtrType (slot, gcType);
4147
+ }
4148
+ }
4149
+
4150
+ #ifdef DEBUG
4151
+ b.CopyNameFrom (layout, " [byref] " );
4152
+ #endif
4153
+
4154
+ return comp->typGetCustomLayout (b);
4155
+ }
0 commit comments