From 64fbb178ddd2a60b21a29f83318782de77ca09c7 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Fri, 15 Mar 2024 15:04:21 -0700 Subject: [PATCH 1/5] Add additional checks to optimization of constant static field loads In `fgGetStaticFieldSeqAndAddress`, if we have a static field address altered by a tree of `ADD CNS_INS` nodes, we need to verify that the address is within the found field sequence. It might not be after shared constant CSE kicks in (e.g., under OptRepeat), where the sequence of ADDs might be the alter an arbitrary constant address from one type into the address of the static field of a different type. So we can't use the FieldSeq of the base address when considering the full offset. --- src/coreclr/jit/compiler.h | 2 ++ src/coreclr/jit/fginline.cpp | 6 ++-- src/coreclr/jit/gentree.cpp | 55 ++++++++++++++++++------------------ src/coreclr/jit/valuenum.cpp | 30 ++++++++++++++++---- 4 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4e9ec67b31a467..4ed27ec258d27a 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5591,6 +5591,8 @@ class Compiler void fgValueNumberFieldStore( GenTree* storeNode, GenTree* baseAddr, FieldSeq* fieldSeq, ssize_t offset, unsigned storeSize, ValueNum value); + bool fgGetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, FieldSeq** pFseq); + bool fgValueNumberConstLoad(GenTreeIndir* tree); // Compute the value number for a byref-exposed load of the given type via the given pointerVN. diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 6ebe709888a4b1..8ea17f2bff05a0 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -590,9 +590,9 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorlvSingleDef) { - bool isExact = false; - bool isNonNull = false; - CORINFO_CLASS_HANDLE newClass = m_compiler->gtGetClassHandle(value, &isExact, &isNonNull); + bool isExact; + bool isNonNull; + CORINFO_CLASS_HANDLE newClass = m_compiler->gtGetClassHandle(value, &isExact, &isNonNull); if (newClass != NO_CLASS_HANDLE) { diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 0ada2ec1425c09..839a7d95d74e8e 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -14124,13 +14124,13 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) objOp = opOther->AsCall()->gtArgs.GetThisArg()->GetNode(); } - bool pIsExact = false; - bool pIsNonNull = false; - CORINFO_CLASS_HANDLE objCls = gtGetClassHandle(objOp, &pIsExact, &pIsNonNull); + bool isExact = false; + bool isNonNull = false; + CORINFO_CLASS_HANDLE objCls = gtGetClassHandle(objOp, &isExact, &isNonNull); // if both classes are "final" (e.g. System.String[]) we can replace the comparison // with `true/false` + null check. - if ((objCls != NO_CLASS_HANDLE) && (pIsExact || info.compCompHnd->isExactType(objCls))) + if ((objCls != NO_CLASS_HANDLE) && (isExact || info.compCompHnd->isExactType(objCls))) { TypeCompareState tcs = info.compCompHnd->compareTypesForEquality(objCls, clsHnd); if (tcs != TypeCompareState::May) @@ -14139,7 +14139,7 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) const bool typesAreEqual = tcs == TypeCompareState::Must; GenTree* compareResult = gtNewIconNode((operatorIsEQ ^ typesAreEqual) ? 0 : 1); - if (!pIsNonNull) + if (!isNonNull) { // we still have to emit a null-check // obj.GetType == typeof() -> (nullcheck) true/false @@ -18398,24 +18398,23 @@ bool Compiler::gtStoreDefinesField( // otherwise actual type may be a subtype. // *pIsNonNull set true if tree value is known not to be null, // otherwise a null value is possible. - +// CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull) { // Set default values for our out params. - *pIsNonNull = false; - *pIsExact = false; - CORINFO_CLASS_HANDLE objClass = nullptr; + *pIsNonNull = false; + *pIsExact = false; // Bail out if the tree is not a ref type. - var_types treeType = tree->TypeGet(); - if (treeType != TYP_REF) + if (!tree->TypeIs(TYP_REF)) { - return objClass; + return nullptr; } // Tunnel through commas. - GenTree* obj = tree->gtEffectiveVal(); - const genTreeOps objOp = obj->OperGet(); + GenTree* obj = tree->gtEffectiveVal(); + const genTreeOps objOp = obj->OperGet(); + CORINFO_CLASS_HANDLE objClass = nullptr; switch (objOp) { @@ -18564,7 +18563,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b assert(runtimeType != NO_CLASS_HANDLE); objClass = runtimeType; - *pIsExact = false; *pIsNonNull = true; } @@ -18608,9 +18606,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b { objClass = gtGetArrayElementClassHandle(base->AsArrElem()->gtArrObj); } - - *pIsExact = false; - *pIsNonNull = false; } else if (base->OperGet() == GT_ADD) { @@ -18647,7 +18642,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b FieldSeq* fldSeq = base->AsIntCon()->gtFieldSeq; if ((fldSeq != nullptr) && (fldSeq->GetOffset() == base->AsIntCon()->IconValue())) { - CORINFO_FIELD_HANDLE fldHandle = base->AsIntCon()->gtFieldSeq->GetFieldHandle(); + CORINFO_FIELD_HANDLE fldHandle = fldSeq->GetFieldHandle(); objClass = gtGetFieldClassHandle(fldHandle, pIsExact, pIsNonNull); } } @@ -18714,7 +18709,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b // Return Value: // nullptr if helper call result is not a ref class, or the class handle // is unknown, otherwise the class handle. - +// CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull) { assert(call->gtCallType == CT_HELPER); @@ -18856,7 +18851,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, boo // // Return Value: // nullptr if element class handle is unknown, otherwise the class handle. - +// CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array) { bool isArrayExact = false; @@ -18898,9 +18893,12 @@ CORINFO_CLASS_HANDLE Compiler::gtGetArrayElementClassHandle(GenTree* array) // is unknown, otherwise the class handle. // // May examine runtime state of static field instances. - +// CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull) { + *pIsExact = false; + *pIsNonNull = false; + CORINFO_CLASS_HANDLE fieldClass = NO_CLASS_HANDLE; CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &fieldClass); @@ -18915,9 +18913,10 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH #if DEBUG char fieldNameBuffer[128]; char classNameBuffer[128]; - JITDUMP("\nQuerying runtime about current class of field %s (declared as %s)\n", - eeGetFieldName(fieldHnd, true, fieldNameBuffer, sizeof(fieldNameBuffer)), - eeGetClassName(fieldClass, classNameBuffer, sizeof(classNameBuffer))); + eeGetFieldName(fieldHnd, true, fieldNameBuffer, sizeof(fieldNameBuffer)); + eeGetClassName(fieldClass, classNameBuffer, sizeof(classNameBuffer)); + JITDUMP("\nQuerying runtime about current class of field %s (declared as %s)\n", fieldNameBuffer, + classNameBuffer); #endif // DEBUG // Is this a fully initialized init-only static field? @@ -18933,9 +18932,9 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH *pIsNonNull = true; #ifdef DEBUG char buffer[128]; - JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", - eeGetClassName(fieldClass, buffer, sizeof(buffer))); -#endif + eeGetClassName(fieldClass, buffer, sizeof(buffer)); + JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", buffer); +#endif // DEBUG } else { diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 28abf35f37e828..5eba11c989b873 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10939,7 +10939,10 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl) // Return Value: // true if the given tree is a static field address // -static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, FieldSeq** pFseq) +bool Compiler::fgGetStaticFieldSeqAndAddress(ValueNumStore* vnStore, + GenTree* tree, + ssize_t* byteOffset, + FieldSeq** pFseq) { VNFuncApp funcApp; if (vnStore->GetVNFunc(tree->gtVNPair.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToStatic)) @@ -10954,7 +10957,6 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s return true; } } - ssize_t val = 0; // Special cases for NativeAOT: // ADD(ICON_STATIC, CNS_INT) // nonGC-static base @@ -10972,6 +10974,7 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s } // Accumulate final offset + ssize_t val = 0; while (tree->OperIs(GT_ADD)) { GenTree* op1 = tree->gtGetOp1(); @@ -11006,11 +11009,26 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s if (fldSeq != nullptr) { assert(fldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress); - *pFseq = fldSeq; - *byteOffset = vnStore->CoercedConstantValue(treeVN) - fldSeq->GetOffset() + val; - return true; + + // Is the offset within the field? There might be a sequence of adds on top of a constant static field + // address due to shared constant CSE such that `treeVN` is not the static field base address. + // Check if the entire access doesn't span across the field and any other field. This simple check is + // just that the access starts within the field. + CORINFO_FIELD_HANDLE fieldHandle = fldSeq->GetFieldHandle(); + CORINFO_CLASS_HANDLE fieldClsHnd; + var_types fieldType = eeGetFieldType(fieldHandle, &fieldClsHnd); + ssize_t fieldSize = (fieldType == TYP_STRUCT) ? info.compCompHnd->getClassSize(fieldClsHnd) + : (ssize_t)genTypeSize(fieldType); + ssize_t tmpByteOffset = vnStore->CoercedConstantValue(treeVN) - fldSeq->GetOffset() + val; + if ((0 <= tmpByteOffset) && (tmpByteOffset < fieldSize)) + { + *pFseq = fldSeq; + *byteOffset = tmpByteOffset; + return true; + } } } + return false; } @@ -11094,7 +11112,7 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree) const int maxElementSize = sizeof(simd_t); if (!tree->TypeIs(TYP_BYREF, TYP_STRUCT) && - GetStaticFieldSeqAndAddress(vnStore, tree->gtGetOp1(), &byteOffset, &fieldSeq)) + fgGetStaticFieldSeqAndAddress(vnStore, tree->gtGetOp1(), &byteOffset, &fieldSeq)) { CORINFO_FIELD_HANDLE fieldHandle = fieldSeq->GetFieldHandle(); if ((fieldHandle != nullptr) && (size > 0) && (size <= maxElementSize) && ((size_t)byteOffset < INT_MAX)) From 4192f9595e4d82e72aa2e35242d388e72000ff65 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Fri, 15 Mar 2024 23:36:03 -0700 Subject: [PATCH 2/5] Review feedback 1. Use `eeGetFieldName` / `eeGetClassName` return pointer 2. Only query extra metadata under `verbose || JitConfig.EnableExtraSuperPmiQueries()` --- src/coreclr/jit/gentree.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 839a7d95d74e8e..1627c6e0a9b4c2 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18911,12 +18911,14 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH if (queryForCurrentClass) { #if DEBUG - char fieldNameBuffer[128]; - char classNameBuffer[128]; - eeGetFieldName(fieldHnd, true, fieldNameBuffer, sizeof(fieldNameBuffer)); - eeGetClassName(fieldClass, classNameBuffer, sizeof(classNameBuffer)); - JITDUMP("\nQuerying runtime about current class of field %s (declared as %s)\n", fieldNameBuffer, - classNameBuffer); + if (verbose || JitConfig.EnableExtraSuperPmiQueries()) + { + char fieldNameBuffer[128]; + char classNameBuffer[128]; + const char* fieldName = eeGetFieldName(fieldHnd, true, fieldNameBuffer, sizeof(fieldNameBuffer)); + const char* className = eeGetClassName(fieldClass, classNameBuffer, sizeof(classNameBuffer)); + JITDUMP("\nQuerying runtime about current class of field %s (declared as %s)\n", fieldName, className); + } #endif // DEBUG // Is this a fully initialized init-only static field? @@ -18931,9 +18933,12 @@ CORINFO_CLASS_HANDLE Compiler::gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldH *pIsExact = true; *pIsNonNull = true; #ifdef DEBUG - char buffer[128]; - eeGetClassName(fieldClass, buffer, sizeof(buffer)); - JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", buffer); + if (verbose || JitConfig.EnableExtraSuperPmiQueries()) + { + char classNameBuffer2[128]; + const char* className2 = eeGetClassName(fieldClass, classNameBuffer2, sizeof(classNameBuffer2)); + JITDUMP("Runtime reports field is init-only and initialized and has class %s\n", className2); + } #endif // DEBUG } else From 8fe24c9d6a5412c3743466160deca491e60b315e Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Tue, 26 Mar 2024 17:37:47 -0700 Subject: [PATCH 3/5] Convert asserts in CEEInfo::getStaticFieldContent() to 'if' checks --- src/coreclr/jit/gentree.cpp | 4 ++-- src/coreclr/jit/valuenum.cpp | 20 +++----------------- src/coreclr/vm/jitinterface.cpp | 12 ++++++------ 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 1627c6e0a9b4c2..60c99db2db3752 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -18408,13 +18408,13 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b // Bail out if the tree is not a ref type. if (!tree->TypeIs(TYP_REF)) { - return nullptr; + return NO_CLASS_HANDLE; } // Tunnel through commas. GenTree* obj = tree->gtEffectiveVal(); const genTreeOps objOp = obj->OperGet(); - CORINFO_CLASS_HANDLE objClass = nullptr; + CORINFO_CLASS_HANDLE objClass = NO_CLASS_HANDLE; switch (objOp) { diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 5eba11c989b873..b529d4b5096c72 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -11009,23 +11009,9 @@ bool Compiler::fgGetStaticFieldSeqAndAddress(ValueNumStore* vnStore, if (fldSeq != nullptr) { assert(fldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress); - - // Is the offset within the field? There might be a sequence of adds on top of a constant static field - // address due to shared constant CSE such that `treeVN` is not the static field base address. - // Check if the entire access doesn't span across the field and any other field. This simple check is - // just that the access starts within the field. - CORINFO_FIELD_HANDLE fieldHandle = fldSeq->GetFieldHandle(); - CORINFO_CLASS_HANDLE fieldClsHnd; - var_types fieldType = eeGetFieldType(fieldHandle, &fieldClsHnd); - ssize_t fieldSize = (fieldType == TYP_STRUCT) ? info.compCompHnd->getClassSize(fieldClsHnd) - : (ssize_t)genTypeSize(fieldType); - ssize_t tmpByteOffset = vnStore->CoercedConstantValue(treeVN) - fldSeq->GetOffset() + val; - if ((0 <= tmpByteOffset) && (tmpByteOffset < fieldSize)) - { - *pFseq = fldSeq; - *byteOffset = tmpByteOffset; - return true; - } + *pFseq = fldSeq; + *byteOffset = vnStore->CoercedConstantValue(treeVN) - fldSeq->GetOffset() + val; + return true; } } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index b5b8ec66d2d61a..0846f8a1ab0c4e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11777,13 +11777,13 @@ bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buff { if (field->IsObjRef()) { - GCX_COOP(); - - _ASSERT(!field->IsRVA()); - _ASSERT(valueOffset == 0); // there is no point in returning a chunk of a gc handle - _ASSERT((UINT)bufferSize == field->GetSize()); + // there is no point in returning a chunk of a gc handle + if ((valueOffset == 0) && (field->GetSize() <= (UINT)bufferSize) && !field->IsRVA()) + { + GCX_COOP(); - result = getStaticObjRefContent(field->GetStaticOBJECTREF(), buffer, ignoreMovableObjects); + result = getStaticObjRefContent(field->GetStaticOBJECTREF(), buffer, ignoreMovableObjects); + } } else { From 8edac1e43cea202b16656a52274ff5c2340c4efd Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Tue, 26 Mar 2024 17:45:06 -0700 Subject: [PATCH 4/5] Make fgGetStaticFieldSeqAndAddress static --- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/valuenum.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4ed27ec258d27a..3f239a3d29c919 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5591,7 +5591,7 @@ class Compiler void fgValueNumberFieldStore( GenTree* storeNode, GenTree* baseAddr, FieldSeq* fieldSeq, ssize_t offset, unsigned storeSize, ValueNum value); - bool fgGetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, FieldSeq** pFseq); + static bool fgGetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, FieldSeq** pFseq); bool fgValueNumberConstLoad(GenTreeIndir* tree); diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index b529d4b5096c72..adab2ead88a12f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10939,6 +10939,7 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl) // Return Value: // true if the given tree is a static field address // +/* static */ bool Compiler::fgGetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, From ddb7c5e96ab9bdb1d6f08c6d1beb249e8cd72844 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Tue, 26 Mar 2024 20:11:24 -0700 Subject: [PATCH 5/5] Code review feedback --- .../JitInterface/CorInfoImpl.RyuJit.cs | 31 +++++++++++-------- src/coreclr/vm/jitinterface.cpp | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index f98d7b0fc06505..0c283d9f53a67a 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2336,12 +2336,16 @@ private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buf if (value == null) { - Debug.Assert(valueOffset == 0); - Debug.Assert(bufferSize == targetPtrSize); - - // Write "null" to buffer - new Span(buffer, targetPtrSize).Clear(); - return true; + if ((valueOffset == 0) && (bufferSize == targetPtrSize)) + { + // Write "null" to buffer + new Span(buffer, targetPtrSize).Clear(); + return true; + } + else + { + return false; + } } if (value.GetRawData(_compilation.NodeFactory, out object data)) @@ -2357,13 +2361,14 @@ private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buf return false; case FrozenObjectNode: - Debug.Assert(valueOffset == 0); - Debug.Assert(bufferSize == targetPtrSize); - - // save handle's value to buffer - nint handle = ObjectToHandle(data); - new Span(&handle, targetPtrSize).CopyTo(new Span(buffer, targetPtrSize)); - return true; + if ((valueOffset == 0) && (bufferSize == targetPtrSize)) + { + // save handle's value to buffer + nint handle = ObjectToHandle(data); + new Span(&handle, targetPtrSize).CopyTo(new Span(buffer, targetPtrSize)); + return true; + } + return false; } } } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 0846f8a1ab0c4e..4f92c805a7347d 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11778,7 +11778,7 @@ bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buff if (field->IsObjRef()) { // there is no point in returning a chunk of a gc handle - if ((valueOffset == 0) && (field->GetSize() <= (UINT)bufferSize) && !field->IsRVA()) + if ((valueOffset == 0) && (sizeof(CORINFO_OBJECT_HANDLE) <= (UINT)bufferSize) && !field->IsRVA()) { GCX_COOP();