From 226dff41ba5ab8c5c5f7bd59668af432ac3f085a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 5 Jun 2026 14:27:03 +0900 Subject: [PATCH 1/2] Preserve JIT handle bits in cross-target builds Ensure RyuJIT keeps host-sized handle values when cross-targeting from 64-bit to 32-bit builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/jit/assertionprop.cpp | 30 +++++++++++++++---- src/coreclr/jit/compiler.hpp | 2 +- src/coreclr/jit/importer.cpp | 5 ++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 1 + .../JitInterface/CorInfoImpl.RyuJit.cs | 12 +++++--- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 7255607103f7af..ef237819dae1f4 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1414,8 +1414,16 @@ bool Compiler::optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pCon var_types vnType = vnStore->TypeOfVN(vn); if (vnType == TYP_INT) { - *pConstant = vnStore->ConstantValue(vn); - *pFlags = vnStore->IsVNHandle(vn) ? vnStore->GetHandleFlags(vn) : GTF_EMPTY; + if (vnStore->IsVNHandle(vn)) + { + *pConstant = vnStore->ConstantValue(vn); + *pFlags = vnStore->GetHandleFlags(vn); + } + else + { + *pConstant = vnStore->ConstantValue(vn); + *pFlags = GTF_EMPTY; + } return true; } #ifdef TARGET_64BIT @@ -4612,12 +4620,16 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, } else { - printf("%d (gcref)\n", static_cast(vnStore->ConstantValue(vnCns))); + assert(vnStore->IsVNHandle(vnCns)); + printf("%p (gcref)\n", dspPtr(vnStore->ConstantValue(vnCns))); } } else if (op1->TypeIs(TYP_BYREF)) { - printf("%d (byref)\n", static_cast(vnStore->ConstantValue(vnCns))); + ssize_t constant = vnStore->IsVNHandle(vnCns) + ? vnStore->ConstantValue(vnCns) + : static_cast(vnStore->ConstantValue(vnCns)); + printf("%p (byref)\n", dspPtr(constant)); } else { @@ -4666,11 +4678,17 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, } else if (op1->TypeIs(TYP_REF)) { - op1->BashToConst(static_cast(vnStore->ConstantValue(vnCns)), TYP_REF); + ssize_t constant = vnStore->IsVNHandle(vnCns) + ? vnStore->ConstantValue(vnCns) + : static_cast(vnStore->ConstantValue(vnCns)); + op1->BashToConst(constant, TYP_REF); } else if (op1->TypeIs(TYP_BYREF)) { - op1->BashToConst(static_cast(vnStore->ConstantValue(vnCns)), TYP_BYREF); + ssize_t constant = vnStore->IsVNHandle(vnCns) + ? vnStore->ConstantValue(vnCns) + : static_cast(vnStore->ConstantValue(vnCns)); + op1->BashToConst(constant, TYP_BYREF); } else { diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 392cdf16b21fe6..f196abb2ab89dc 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -2095,7 +2095,7 @@ void GenTree::BashToConst(T value, var_types type /* = TYP_UNDEF */) assert(type != TYP_LONG); #endif assert(varTypeIsIntegral(type) || varTypeIsGC(type)); - if (genTypeSize(type) <= genTypeSize(TYP_INT)) + if (!varTypeIsGC(type) && (genTypeSize(type) <= genTypeSize(TYP_INT))) { assert(FitsIn(value)); } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 9b726ad9541580..1af8cbfbd3434f 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3984,8 +3984,9 @@ GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORI uint8_t buffer[bufferSize] = {0}; if (varTypeIsIntegral(fieldType) || varTypeIsFloating(fieldType) || (fieldType == TYP_REF)) { - assert(bufferSize >= genTypeSize(fieldType)); - if (info.compCompHnd->getStaticFieldContent(field, buffer, genTypeSize(fieldType))) + const int fieldValueSize = (fieldType == TYP_REF) ? (int)sizeof(ssize_t) : genTypeSize(fieldType); + assert(bufferSize >= fieldValueSize); + if (info.compCompHnd->getStaticFieldContent(field, buffer, fieldValueSize)) { GenTree* cnsValue = gtNewGenericCon(fieldType, buffer); if (cnsValue != nullptr) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 5fc46db5a8978b..d64e5123e9087c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -768,6 +768,7 @@ private object HandleToObject(void* handle) { Debug.Assert(handle != null); #if DEBUG + Debug.Assert((s_handleHighBitSet & (nint)handle) != 0); handle = (void*)(~s_handleHighBitSet & (nint)handle); #endif int index = ((int)handle - handleBase) / handleMultiplier; 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 6c22da04d78a90..987241d466dc0a 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2346,13 +2346,15 @@ private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buf .GetPreinitializationInfo(owningType).GetFieldValue(field); int targetPtrSize = _compilation.TypeSystemContext.Target.PointerSize; + bool isObjectHandleBuffer = + (valueOffset == 0) && ((bufferSize == targetPtrSize) || (bufferSize == sizeof(nint))); if (value == null) { - if ((valueOffset == 0) && (bufferSize == targetPtrSize)) + if (isObjectHandleBuffer) { // Write "null" to buffer - new Span(buffer, targetPtrSize).Clear(); + new Span(buffer, bufferSize).Clear(); return true; } else @@ -2374,11 +2376,13 @@ private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buf return false; case FrozenObjectNode: - if ((valueOffset == 0) && (bufferSize == targetPtrSize)) + if (isObjectHandleBuffer) { // save handle's value to buffer nint handle = ObjectToHandle(data); - new Span(&handle, targetPtrSize).CopyTo(new Span(buffer, targetPtrSize)); + Span destination = new Span(buffer, bufferSize); + destination.Clear(); + new ReadOnlySpan(&handle, Math.Min(sizeof(nint), bufferSize)).CopyTo(destination); return true; } return false; From 3d5b982b4ecd1b40bb3e86748aab847f2349d7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 5 Jun 2026 14:31:14 +0900 Subject: [PATCH 2/2] Tests --- src/tests/JIT/Methodical/jitinterface/bug603649.cs | 1 - src/tests/Regressions/coreclr/15647/interfacestatics.ilproj | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/tests/JIT/Methodical/jitinterface/bug603649.cs b/src/tests/JIT/Methodical/jitinterface/bug603649.cs index 04fb49d2ee02a6..46600a1ca703b7 100644 --- a/src/tests/JIT/Methodical/jitinterface/bug603649.cs +++ b/src/tests/JIT/Methodical/jitinterface/bug603649.cs @@ -11,7 +11,6 @@ public class foo private static object s_o = typeof(string); [Fact] [OuterLoop] - [ActiveIssue("https://github.com/dotnet/runtime/issues/122013", typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNativeAot), nameof(TestLibrary.Utilities.Is32))] public static int TestEntryPoint() { bool f = typeof(string) == s_o as Type; diff --git a/src/tests/Regressions/coreclr/15647/interfacestatics.ilproj b/src/tests/Regressions/coreclr/15647/interfacestatics.ilproj index d4d95de5764ab1..e2c3ed6fb730e7 100644 --- a/src/tests/Regressions/coreclr/15647/interfacestatics.ilproj +++ b/src/tests/Regressions/coreclr/15647/interfacestatics.ilproj @@ -1,10 +1,7 @@ - + true - - partial - true