diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index 30c13cb70acd..8a82f386c3f2 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -726,8 +726,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) // the xor ensures that only one of the two is setup, not both assert((varNode != nullptr) ^ (addrNode != nullptr)); - BYTE gcPtrArray[MAX_ARG_REG_COUNT] = {}; // TYPE_GC_NONE = 0 - const BYTE* gcPtrs = gcPtrArray; + const BYTE* gcPtrs = nullptr; unsigned gcPtrCount; // The count of GC pointers in the struct unsigned structSize; @@ -753,9 +752,8 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) // as that is how much stack is allocated for this LclVar isHfa = varDsc->lvIsHfa(); #ifdef _TARGET_ARM64_ - gcPtrCount = varDsc->lvStructGcCount; - for (unsigned i = 0; i < gcPtrCount; ++i) - gcPtrArray[i] = varDsc->lvGcLayout[i]; + gcPtrCount = varDsc->GetLayout()->GetGCPtrCount(); + gcPtrs = varDsc->GetLayout()->GetGCPtrs(); #endif // _TARGET_ARM_ } else // we must have a GT_OBJ @@ -2736,7 +2734,7 @@ void CodeGen::genJmpMethod(GenTree* jmp) // Must be <= 16 bytes or else it wouldn't be passed in registers, except for HFA, // which can be bigger (and is handled above). noway_assert(EA_SIZE_IN_BYTES(varDsc->lvSize()) <= 16); - loadType = compiler->getJitGCType(varDsc->lvGcLayout[0]); + loadType = varDsc->GetLayout()->GetGCPtrType(0); } else { @@ -2757,7 +2755,7 @@ void CodeGen::genJmpMethod(GenTree* jmp) // Restore the second register. argRegNext = genRegArgNext(argReg); - loadType = compiler->getJitGCType(varDsc->lvGcLayout[1]); + loadType = varDsc->GetLayout()->GetGCPtrType(1); loadSize = emitActualTypeSize(loadType); getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, argRegNext, varNum, TARGET_POINTER_SIZE); @@ -2850,7 +2848,7 @@ void CodeGen::genJmpMethod(GenTree* jmp) for (unsigned ofs = 0; ofs < maxSize; ofs += REGSIZE_BYTES) { unsigned idx = ofs / REGSIZE_BYTES; - loadType = compiler->getJitGCType(varDsc->lvGcLayout[idx]); + loadType = varDsc->GetLayout()->GetGCPtrType(idx); if (varDsc->lvRegNum != argReg) { diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp index b5edb3d0c5b6..2e953004b08f 100644 --- a/src/jit/codegencommon.cpp +++ b/src/jit/codegencommon.cpp @@ -4512,8 +4512,7 @@ void CodeGen::genCheckUseBlockInit() continue; } - if (compiler->info.compInitMem || varTypeIsGC(varDsc->TypeGet()) || (varDsc->lvStructGcCount > 0) || - varDsc->lvMustInit) + if (compiler->info.compInitMem || varDsc->HasGCPtr() || varDsc->lvMustInit) { if (varDsc->lvTracked) { @@ -4559,7 +4558,7 @@ void CodeGen::genCheckUseBlockInit() CLANG_FORMAT_COMMENT_ANCHOR; if ((!varDsc->lvTracked || (varDsc->lvType == TYP_STRUCT)) && varDsc->lvOnFrame && - (!varDsc->lvIsTemp || varTypeIsGC(varDsc->TypeGet()) || (varDsc->lvStructGcCount > 0))) + (!varDsc->lvIsTemp || varDsc->HasGCPtr())) { varDsc->lvMustInit = true; @@ -4576,7 +4575,7 @@ void CodeGen::genCheckUseBlockInit() /* Ignore if not a pointer variable or value class with a GC field */ - if (!compiler->lvaTypeIsGC(varNum)) + if (!varDsc->HasGCPtr()) { continue; } @@ -4597,13 +4596,18 @@ void CodeGen::genCheckUseBlockInit() /* Is this a 'must-init' stack pointer local? */ - if (varDsc->lvMustInit && varDsc->lvOnFrame) + if (varDsc->lvMustInit && varDsc->lvOnFrame && !counted) { - if (!counted) + if (varDsc->TypeGet() == TYP_STRUCT) { - initStkLclCnt += varDsc->lvStructGcCount; - counted = true; + initStkLclCnt += varDsc->GetLayout()->GetGCPtrCount(); } + else + { + assert(varTypeIsGC(varDsc->TypeGet())); + initStkLclCnt += 1; + } + counted = true; } if ((compiler->lvaLclSize(varNum) > (3 * TARGET_POINTER_SIZE)) && (largeGcStructs <= 4)) @@ -6338,7 +6342,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, { // We only initialize the GC variables in the TYP_STRUCT const unsigned slots = (unsigned)compiler->lvaLclSize(varNum) / REGSIZE_BYTES; - const BYTE* gcPtrs = compiler->lvaGetGcLayout(varNum); + const BYTE* gcPtrs = varDsc->GetLayout()->GetGCPtrs(); for (unsigned i = 0; i < slots; i++) { @@ -7761,7 +7765,7 @@ void CodeGen::genFnProlog() /* We need to know the offset range of tracked stack GC refs */ /* We assume that the GC reference can be anywhere in the TYP_STRUCT */ - if (compiler->lvaTypeIsGC(varNum) && varDsc->lvTrackedNonStruct() && varDsc->lvOnFrame) + if (varDsc->HasGCPtr() && varDsc->lvTrackedNonStruct() && varDsc->lvOnFrame) { // For fields of PROMOTION_TYPE_DEPENDENT type of promotion, they should have been // taken care of by the parent struct. diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index f8b47bfff3e1..eb00f583f127 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -4931,28 +4931,12 @@ bool Compiler::compQuirkForPPP() // This fixes the PPP backward compat issue varDscExposedStruct->lvExactSize += 32; - // Update the GC info to indicate that the padding area does - // not contain any GC pointers. - // // The struct is now 64 bytes. - // // We're on x64 so this should be 8 pointer slots. assert((varDscExposedStruct->lvExactSize / TARGET_POINTER_SIZE) == 8); - BYTE* oldGCPtrs = varDscExposedStruct->lvGcLayout; - BYTE* newGCPtrs = getAllocator(CMK_LvaTable).allocate(8); - - for (int i = 0; i < 4; i++) - { - newGCPtrs[i] = oldGCPtrs[i]; - } - - for (int i = 4; i < 8; i++) - { - newGCPtrs[i] = TYPE_GC_NONE; - } - - varDscExposedStruct->lvGcLayout = newGCPtrs; + varDscExposedStruct->SetLayout( + varDscExposedStruct->GetLayout()->GetPPPQuirkLayout(getAllocator(CMK_ClassLayout))); return true; } diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 69dd74399568..72e5bec98321 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -566,12 +566,10 @@ class LclVarDsc unsigned char lvIsRegArg : 1; // is this a register argument? unsigned char lvFramePointerBased : 1; // 0 = off of REG_SPBASE (e.g., ESP), 1 = off of REG_FPBASE (e.g., EBP) - unsigned char lvStructGcCount : 3; // if struct, how many GC pointer (stop counting at 7). The only use of values >1 - // is to help determine whether to use block init in the prolog. - unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame - unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the - // variable is in the same register for the entire function. - unsigned char lvTracked : 1; // is this a tracked variable? + unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame + unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the + // variable is in the same register for the entire function. + unsigned char lvTracked : 1; // is this a tracked variable? bool lvTrackedNonStruct() { return lvTracked && lvType != TYP_STRUCT; @@ -1038,8 +1036,10 @@ class LclVarDsc CORINFO_FIELD_HANDLE lvFieldHnd; // field handle for promoted struct fields - BYTE* lvGcLayout; // GC layout info for structs +private: + ClassLayout* m_layout; // layout info for structs +public: #if ASSERTION_PROP BlockSet lvRefBlks; // Set of blocks that contain refs GenTreeStmt* lvDefStmt; // Pointer to the statement with the single definition @@ -1096,6 +1096,26 @@ class LclVarDsc var_types lvaArgType(); + // Returns true if this variable contains GC pointers (including being a GC pointer itself). + bool HasGCPtr() + { + return varTypeIsGC(lvType) || ((lvType == TYP_STRUCT) && m_layout->HasGCPtr()); + } + + // Returns the layout of a struct variable. + ClassLayout* GetLayout() + { + assert(varTypeIsStruct(lvType)); + return m_layout; + } + + // Sets the layout of a struct variable. + void SetLayout(ClassLayout* layout) + { + assert(varTypeIsStruct(lvType)); + m_layout = layout; + } + SsaDefArray lvPerSsaData; // Returns the address of the per-Ssa data for the given ssaNum (which is required @@ -3509,8 +3529,6 @@ class Compiler } #endif // defined(FEATURE_SIMD) - BYTE* lvaGetGcLayout(unsigned varNum); - bool lvaTypeIsGC(unsigned varNum); unsigned lvaGSSecurityCookie; // LclVar number bool lvaTempsHaveLargerOffsetThanVars(); @@ -3852,10 +3870,7 @@ class Compiler GenTree* impGetStructAddr(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel, bool willDeref); - var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd, - BYTE* gcLayout = nullptr, - unsigned* numGCVars = nullptr, - var_types* simdBaseType = nullptr); + var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd, var_types* simdBaseType = nullptr); GenTree* impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp index 9b1054272274..28152fae219d 100644 --- a/src/jit/compiler.hpp +++ b/src/jit/compiler.hpp @@ -1853,22 +1853,6 @@ inline VARSET_VALRET_TP Compiler::lvaStmtLclMask(GenTreeStmt* stmt) return lclMask; } -/***************************************************************************** - * Returns true if the lvType is a TYP_REF or a TYP_BYREF. - * When the lvType is a TYP_STRUCT it searches the GC layout - * of the struct and returns true iff it contains a GC ref. - */ - -inline bool Compiler::lvaTypeIsGC(unsigned varNum) -{ - if (lvaTable[varNum].TypeGet() == TYP_STRUCT) - { - assert(lvaTable[varNum].lvGcLayout != nullptr); // bits are intialized - return (lvaTable[varNum].lvStructGcCount != 0); - } - return (varTypeIsGC(lvaTable[varNum].TypeGet())); -} - /***************************************************************************** Is this a synchronized instance method? If so, we will need to report "this" in the GC information, so that the EE can release the object lock @@ -4127,8 +4111,8 @@ inline void Compiler::CLR_API_Leave(API_ICorJitInfo_Names ename) bool Compiler::fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block) { - bool containsGCPtr = (varDsc->lvStructGcCount > 0); - return (!info.compInitMem || ((block->bbFlags & BBF_BACKWARD_JUMP) != 0) || (!containsGCPtr && varDsc->lvIsTemp)); + return !info.compInitMem || ((block->bbFlags & BBF_BACKWARD_JUMP) != 0) || + (!varDsc->HasGCPtr() && varDsc->lvIsTemp); } /*****************************************************************************/ diff --git a/src/jit/gcencode.cpp b/src/jit/gcencode.cpp index 331796c33a81..e032f9d6b9e5 100644 --- a/src/jit/gcencode.cpp +++ b/src/jit/gcencode.cpp @@ -2319,10 +2319,10 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un } // A struct will have gcSlots only if it is at least TARGET_POINTER_SIZE. - if (varDsc->lvType == TYP_STRUCT && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE)) + if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE)) { - unsigned slots = compiler->lvaLclSize(varNum) / TARGET_POINTER_SIZE; - BYTE* gcPtrs = compiler->lvaGetGcLayout(varNum); + unsigned slots = varDsc->GetLayout()->GetSlotCount(); + const BYTE* gcPtrs = varDsc->GetLayout()->GetGCPtrs(); // walk each member of the array for (unsigned i = 0; i < slots; i++) @@ -4274,10 +4274,10 @@ void GCInfo::gcMakeRegPtrTable( // If this is a TYP_STRUCT, handle its GC pointers. // Note that the enregisterable struct types cannot have GC pointers in them. - if ((varDsc->lvType == TYP_STRUCT) && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE)) + if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE)) { - unsigned slots = compiler->lvaLclSize(varNum) / TARGET_POINTER_SIZE; - BYTE* gcPtrs = compiler->lvaGetGcLayout(varNum); + unsigned slots = varDsc->GetLayout()->GetSlotCount(); + const BYTE* gcPtrs = varDsc->GetLayout()->GetGCPtrs(); // walk each member of the array for (unsigned i = 0; i < slots; i++) diff --git a/src/jit/gcinfo.cpp b/src/jit/gcinfo.cpp index 3f980ba37076..a658e00d86f6 100644 --- a/src/jit/gcinfo.cpp +++ b/src/jit/gcinfo.cpp @@ -477,19 +477,9 @@ void GCInfo::gcCountForHeader(UNALIGNED unsigned int* untrackedCount, UNALIGNED count++; } - else if (varDsc->lvType == TYP_STRUCT && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE)) + else if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvOnFrame && (varDsc->lvExactSize >= TARGET_POINTER_SIZE)) { - unsigned slots = compiler->lvaLclSize(varNum) / TARGET_POINTER_SIZE; - BYTE* gcPtrs = compiler->lvaGetGcLayout(varNum); - - // walk each member of the array - for (unsigned i = 0; i < slots; i++) - { - if (gcPtrs[i] != TYPE_GC_NONE) - { // count only gc slots - count++; - } - } + count += varDsc->GetLayout()->GetGCPtrCount(); } } diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index 08bafccb1f23..b3af7c7506e5 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -14423,12 +14423,8 @@ GenTree* Compiler::gtNewTempAssign( if (dstTyp == TYP_UNDEF) { varDsc->lvType = dstTyp = genActualType(valTyp); - if (varTypeIsGC(dstTyp)) - { - varDsc->lvStructGcCount = 1; - } #if FEATURE_SIMD - else if (varTypeIsSIMD(dstTyp)) + if (varTypeIsSIMD(dstTyp)) { varDsc->lvSIMDType = 1; } diff --git a/src/jit/gschecks.cpp b/src/jit/gschecks.cpp index e52817a269b4..67c7419d1a42 100644 --- a/src/jit/gschecks.cpp +++ b/src/jit/gschecks.cpp @@ -425,8 +425,11 @@ void Compiler::gsParamsToShadows() lvaTable[shadowVar].lvLclFieldExpr = varDsc->lvLclFieldExpr; lvaTable[shadowVar].lvLiveAcrossUCall = varDsc->lvLiveAcrossUCall; #endif - lvaTable[shadowVar].lvVerTypeInfo = varDsc->lvVerTypeInfo; - lvaTable[shadowVar].lvGcLayout = varDsc->lvGcLayout; + lvaTable[shadowVar].lvVerTypeInfo = varDsc->lvVerTypeInfo; + if (varTypeIsStruct(type)) + { + lvaTable[shadowVar].SetLayout(varDsc->GetLayout()); + } lvaTable[shadowVar].lvIsUnsafeBuffer = varDsc->lvIsUnsafeBuffer; lvaTable[shadowVar].lvIsPtr = varDsc->lvIsPtr; diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 75c6cba2bbaf..0d90fdb45e6d 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -1511,99 +1511,58 @@ GenTree* Compiler::impGetStructAddr(GenTree* structVal, } //------------------------------------------------------------------------ -// impNormStructType: Given a (known to be) struct class handle structHnd, normalize its type, -// and optionally determine the GC layout of the struct. +// impNormStructType: Given a (known to be) struct class handle structHnd and normalize its type. // // Arguments: // structHnd - The class handle for the struct type of interest. -// gcLayout - (optional, default nullptr) - a BYTE pointer, allocated by the caller, -// into which the gcLayout will be written. -// pNumGCVars - (optional, default nullptr) - if non-null, a pointer to an unsigned, -// which will be set to the number of GC fields in the struct. // pSimdBaseType - (optional, default nullptr) - if non-null, and the struct is a SIMD // type, set to the SIMD base type // // Return Value: // The JIT type for the struct (e.g. TYP_STRUCT, or TYP_SIMD*). -// The gcLayout will be returned using the pointers provided by the caller, if non-null. // It may also modify the compFloatingPointUsed flag if the type is a SIMD type. // -// Assumptions: -// The caller must set gcLayout to nullptr OR ensure that it is large enough -// (see ICorStaticInfo::getClassGClayout in corinfo.h). -// // Notes: // Normalizing the type involves examining the struct type to determine if it should // be modified to one that is handled specially by the JIT, possibly being a candidate // for full enregistration, e.g. TYP_SIMD16. -var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, - BYTE* gcLayout, - unsigned* pNumGCVars, - var_types* pSimdBaseType) +var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, var_types* pSimdBaseType) { assert(structHnd != NO_CLASS_HANDLE); - const DWORD structFlags = info.compCompHnd->getClassAttribs(structHnd); - var_types structType = TYP_STRUCT; - - // On coreclr the check for GC includes a "may" to account for the special - // ByRef like span structs. The added check for "CONTAINS_STACK_PTR" is the particular bit. - // When this is set the struct will contain a ByRef that could be a GC pointer or a native - // pointer. - const bool mayContainGCPtrs = - ((structFlags & CORINFO_FLG_CONTAINS_STACK_PTR) != 0 || ((structFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0)); + var_types structType = TYP_STRUCT; #ifdef FEATURE_SIMD - // Check to see if this is a SIMD type. - if (supportSIMDTypes() && !mayContainGCPtrs) + if (supportSIMDTypes()) { - unsigned originalSize = info.compCompHnd->getClassSize(structHnd); + const DWORD structFlags = info.compCompHnd->getClassAttribs(structHnd); - if ((originalSize >= minSIMDStructBytes()) && (originalSize <= maxSIMDStructBytes())) + // Don't bother if the struct contains GC references of byrefs, it can't be a SIMD type. + if ((structFlags & (CORINFO_FLG_CONTAINS_GC_PTR | CORINFO_FLG_CONTAINS_STACK_PTR)) == 0) { - unsigned int sizeBytes; - var_types simdBaseType = getBaseTypeAndSizeOfSIMDType(structHnd, &sizeBytes); - if (simdBaseType != TYP_UNKNOWN) + unsigned originalSize = info.compCompHnd->getClassSize(structHnd); + + if ((originalSize >= minSIMDStructBytes()) && (originalSize <= maxSIMDStructBytes())) { - assert(sizeBytes == originalSize); - structType = getSIMDTypeForSize(sizeBytes); - if (pSimdBaseType != nullptr) + unsigned int sizeBytes; + var_types simdBaseType = getBaseTypeAndSizeOfSIMDType(structHnd, &sizeBytes); + if (simdBaseType != TYP_UNKNOWN) { - *pSimdBaseType = simdBaseType; + assert(sizeBytes == originalSize); + structType = getSIMDTypeForSize(sizeBytes); + if (pSimdBaseType != nullptr) + { + *pSimdBaseType = simdBaseType; + } + // Also indicate that we use floating point registers. + compFloatingPointUsed = true; } - // Also indicate that we use floating point registers. - compFloatingPointUsed = true; } } } #endif // FEATURE_SIMD - // Fetch GC layout info if requested - if (gcLayout != nullptr) - { - unsigned numGCVars = info.compCompHnd->getClassGClayout(structHnd, gcLayout); - - // Verify that the quick test up above via the class attributes gave a - // safe view of the type's GCness. - // - // Note there are cases where mayContainGCPtrs is true but getClassGClayout - // does not report any gc fields. - - assert(mayContainGCPtrs || (numGCVars == 0)); - - if (pNumGCVars != nullptr) - { - *pNumGCVars = numGCVars; - } - } - else - { - // Can't safely ask for number of GC pointers without also - // asking for layout. - assert(pNumGCVars == nullptr); - } - return structType; } diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp index 6b26b5de125e..17a87cab9107 100644 --- a/src/jit/lclvars.cpp +++ b/src/jit/lclvars.cpp @@ -412,7 +412,7 @@ void Compiler::lvaInitThisPtr(InitVarDscInfo* varDscInfo) if (supportSIMDTypes()) { var_types simdBaseType = TYP_UNKNOWN; - var_types type = impNormStructType(info.compClassHnd, nullptr, nullptr, &simdBaseType); + var_types type = impNormStructType(info.compClassHnd, &simdBaseType); if (simdBaseType != TYP_UNKNOWN) { assert(varTypeIsSIMD(type)); @@ -1287,11 +1287,6 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc, varDsc->lvOverlappingFields = StructHasOverlappingFields(cFlags); } - if (varTypeIsGC(type)) - { - varDsc->lvStructGcCount = 1; - } - #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) varDsc->lvIsImplicitByRef = 0; #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) @@ -2499,43 +2494,15 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool } if (varDsc->lvExactSize == 0) { - BOOL isValueClass = info.compCompHnd->isValueClass(typeHnd); - - if (isValueClass) - { - varDsc->lvExactSize = info.compCompHnd->getClassSize(typeHnd); - } - else - { - varDsc->lvExactSize = info.compCompHnd->getHeapClassSize(typeHnd); - } - - // Normalize struct types, and fill in GC info for all types - unsigned lvSize = varDsc->lvSize(); - // The struct needs to be a multiple of TARGET_POINTER_SIZE bytes for getClassGClayout() to be valid. - assert((lvSize % TARGET_POINTER_SIZE) == 0); - varDsc->lvGcLayout = getAllocator(CMK_LvaTable).allocate(lvSize / TARGET_POINTER_SIZE); - unsigned numGCVars = 0; - var_types simdBaseType = TYP_UNKNOWN; - if (isValueClass) - { - varDsc->lvType = impNormStructType(typeHnd, varDsc->lvGcLayout, &numGCVars, &simdBaseType); - } - else - { - numGCVars = info.compCompHnd->getClassGClayout(typeHnd, varDsc->lvGcLayout); - } - - // We only save the count of GC vars in a struct up to 7. - if (numGCVars >= 8) - { - numGCVars = 7; - } + ClassLayout* layout = typGetObjLayout(typeHnd); + layout->EnsureGCPtrsInitialized(this); + varDsc->SetLayout(layout); + varDsc->lvExactSize = layout->GetSize(); - varDsc->lvStructGcCount = numGCVars; - - if (isValueClass) + if (layout->IsValueClass()) { + var_types simdBaseType = TYP_UNKNOWN; + varDsc->lvType = impNormStructType(typeHnd, &simdBaseType); #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) // Mark implicit byref struct parameters @@ -2570,7 +2537,7 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool varDsc->SetHfaType(hfaType); // hfa variables can never contain GC pointers - assert(varDsc->lvStructGcCount == 0); + assert(!layout->HasGCPtr()); // The size of this struct should be evenly divisible by 4 or 8 assert((varDsc->lvExactSize % genTypeSize(hfaType)) == 0); // The number of elements in the HFA should fit into our MAX_ARG_REG_COUNT limit @@ -2833,17 +2800,6 @@ void Compiler::lvaUpdateClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HAND } } -/***************************************************************************** - * Returns the array of BYTEs containing the GC layout information - */ - -BYTE* Compiler::lvaGetGcLayout(unsigned varNum) -{ - assert(varTypeIsStruct(lvaTable[varNum].lvType) && (lvaTable[varNum].lvExactSize >= TARGET_POINTER_SIZE)); - - return lvaTable[varNum].lvGcLayout; -} - //------------------------------------------------------------------------ // lvaLclSize: returns size of a local variable, in bytes // @@ -3613,25 +3569,8 @@ var_types LclVarDsc::lvaArgType() type = TYP_INT; break; case 8: - switch (*lvGcLayout) - { - case TYPE_GC_NONE: - type = TYP_I_IMPL; - break; - - case TYPE_GC_REF: - type = TYP_REF; - break; - - case TYPE_GC_BYREF: - type = TYP_BYREF; - break; - - default: - unreached(); - } + type = m_layout->GetGCPtrType(0); break; - default: type = TYP_BYREF; break; diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 1e2f315cd8ba..b8fe342f8973 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -4717,14 +4717,14 @@ GenTree* Compiler::fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntry for (unsigned inx = 0; inx < elemCount; inx++) { - CorInfoGCType currentGcLayoutType = (CorInfoGCType)varDsc->lvGcLayout[inx]; + var_types currentGcLayoutType = varDsc->GetLayout()->GetGCPtrType(inx); // We setup the type[inx] value above using the GC info from 'objClass' // This GT_LCL_VAR must have the same GC layout info // - if (currentGcLayoutType != TYPE_GC_NONE) + if (varTypeIsGC(currentGcLayoutType)) { - noway_assert(type[inx] == getJitGCType((BYTE)currentGcLayoutType)); + noway_assert(type[inx] == currentGcLayoutType); } else { @@ -4878,7 +4878,7 @@ GenTree* Compiler::fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntry // The allocated size of our LocalVar must be at least as big as lastOffset assert(varDsc->lvSize() >= lastOffset); - if (varDsc->lvStructGcCount > 0) + if (varDsc->HasGCPtr()) { // alignment of the baseOffset is required noway_assert((baseOffset % TARGET_POINTER_SIZE) == 0); @@ -4886,7 +4886,7 @@ GenTree* Compiler::fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntry noway_assert(elemSize == TARGET_POINTER_SIZE); #endif unsigned baseIndex = baseOffset / TARGET_POINTER_SIZE; - const BYTE* gcPtrs = varDsc->lvGcLayout; // Get the GC layout for the local variable + const BYTE* gcPtrs = varDsc->GetLayout()->GetGCPtrs(); for (unsigned inx = 0; (inx < elemCount); inx++) { // The GC information must match what we setup using 'objClass' @@ -7895,7 +7895,7 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa { var_types lclType = varDsc->TypeGet(); bool isUserLocal = (varNum < info.compLocalsCount); - bool structWithGCFields = ((lclType == TYP_STRUCT) && (varDsc->lvStructGcCount > 0)); + bool structWithGCFields = ((lclType == TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr()); if (isUserLocal || structWithGCFields) { GenTree* lcl = gtNewLclvNode(varNum, lclType); @@ -10233,7 +10233,7 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) { blockWidth = genTypeSize(destLclVar->lvType); } - hasGCPtrs = destLclVar->lvStructGcCount != 0; + hasGCPtrs = destLclVar->HasGCPtr(); } else { diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp index 804d52dec03d..8e83b742314d 100644 --- a/src/jit/rationalize.cpp +++ b/src/jit/rationalize.cpp @@ -373,7 +373,7 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) GenTreeBlk* storeBlk = nullptr; unsigned int size = varDsc->lvExactSize; - if (varDsc->lvStructGcCount != 0) + if (varDsc->HasGCPtr()) { CORINFO_CLASS_HANDLE structHnd = varDsc->lvVerTypeInfo.GetClassHandle(); GenTreeObj* objNode = comp->gtNewObjNode(structHnd, location)->AsObj();