@@ -960,12 +960,6 @@ bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNum,
960960 return false ;
961961 }
962962
963- if (comp->info .compCompHnd ->getTypeForBoxOnStack (clsHnd) == NO_CLASS_HANDLE)
964- {
965- *reason = " [no boxed type available]" ;
966- return false ;
967- }
968-
969963 classSize = comp->info .compCompHnd ->getClassSize (clsHnd);
970964 }
971965 else
@@ -1061,6 +1055,7 @@ ObjectAllocator::ObjectAllocationType ObjectAllocator::AllocationKind(GenTree* t
10611055 return allocType;
10621056}
10631057
1058+ // ------------------------------------------------------------------------
10641059// MorphAllocObjNodes: Morph each GT_ALLOCOBJ node either into an
10651060// allocation helper call or stack allocation.
10661061//
@@ -1203,13 +1198,11 @@ bool ObjectAllocator::MorphAllocObjNodes()
12031198 // ------------------------------------------------------------------------
12041199
12051200 CORINFO_CLASS_HANDLE clsHnd = data->AsAllocObj ()->gtAllocObjClsHnd ;
1206- CORINFO_CLASS_HANDLE stackClsHnd = clsHnd;
12071201 const bool isValueClass = comp->info .compCompHnd ->isValueClass (clsHnd);
12081202
12091203 if (isValueClass)
12101204 {
12111205 comp->Metrics .NewBoxedValueClassHelperCalls ++;
1212- stackClsHnd = comp->info .compCompHnd ->getTypeForBoxOnStack (clsHnd);
12131206 }
12141207 else
12151208 {
@@ -1221,29 +1214,31 @@ bool ObjectAllocator::MorphAllocObjNodes()
12211214 // reason set by the call
12221215 canStack = false ;
12231216 }
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- }
12301217 else
12311218 {
12321219 JITDUMP (" Allocating V%02u on the stack\n " , lclNum);
12331220 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 ;
12371223
12381224 if (isValueClass)
12391225 {
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);
12401230 comp->Metrics .StackAllocatedBoxedValueClasses ++;
12411231 }
12421232 else
12431233 {
1234+ layout = comp->typGetObjLayout (clsHnd);
12441235 comp->Metrics .StackAllocatedRefClasses ++;
12451236 }
12461237
1238+ const unsigned int stackLclNum =
1239+ MorphAllocObjNodeIntoStackAlloc (data->AsAllocObj (), layout, block, stmt);
1240+ m_HeapLocalToStackLocalMap.AddOrUpdate (lclNum, stackLclNum);
1241+
12471242 bashCall = true ;
12481243 }
12491244 }
@@ -1449,8 +1444,7 @@ unsigned int ObjectAllocator::MorphNewArrNodeIntoStackAlloc(GenTreeCall*
14491444// allocation.
14501445// Arguments:
14511446// 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
14541448// block - a basic block where allocObj is
14551449// stmt - a statement where allocObj is
14561450//
@@ -1460,24 +1454,29 @@ unsigned int ObjectAllocator::MorphNewArrNodeIntoStackAlloc(GenTreeCall*
14601454// Notes:
14611455// This function can insert additional statements before stmt.
14621456//
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)
14651461{
14661462 assert (allocObj != nullptr );
14671463 assert (m_AnalysisDone);
1468- assert (clsHnd != NO_CLASS_HANDLE);
14691464
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
14731468
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 );
14751472
1476- // Initialize the object memory if necessary.
1477- bool bbInALoop = block->HasFlag (BBF_BACKWARD_JUMP);
1478- bool bbIsReturn = block->KindIs (BBJ_RETURN);
14791473 LclVarDsc* const lclDsc = comp->lvaGetDesc (lclNum);
14801474 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+
14811480 if (comp->fgVarNeedsExplicitZeroInit (lclNum, bbInALoop, bbIsReturn))
14821481 {
14831482 // ------------------------------------------------------------------------
@@ -2317,15 +2316,15 @@ void ObjectAllocator::RewriteUses()
23172316 if (newType == TYP_I_IMPL)
23182317 {
23192318 // New layout with no gc refs + padding
2320- newLayout = comp-> typGetNonGCLayout (layout);
2319+ newLayout = GetNonGCLayout (layout);
23212320 JITDUMP (" Changing layout of struct V%02u to block\n " , lclNum);
23222321 lclVarDsc->ChangeLayout (newLayout);
23232322 }
23242323 else
23252324 {
23262325 // New layout with all gc refs as byrefs + padding
23272326 // (todo, perhaps: see if old layout was already all byrefs)
2328- newLayout = comp-> typGetByrefLayout (layout);
2327+ newLayout = GetByrefLayout (layout);
23292328 JITDUMP (" Changing layout of struct V%02u to byref\n " , lclNum);
23302329 lclVarDsc->ChangeLayout (newLayout);
23312330 }
@@ -4077,3 +4076,80 @@ void ObjectAllocator::CloneAndSpecialize()
40774076
40784077 assert (numberOfClonedRegions == m_regionsToClone);
40794078}
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