From 31edb0b4a8cfc7a405a30ba1cf9e46ff0da6ae32 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Thu, 13 Aug 2026 12:30:04 +0200 Subject: [PATCH] JIT: Strip GC/reloc flags from the size in arm64 instGen_Set_Reg_To_Imm The immediate encoding helpers (emitIns_valid_imm_for_mov, canEncodeHalfwordImm, canEncodeBitMaskImm) take a plain 4/8 byte data size and assert on anything else. Every other caller strips the flags first, but instGen_Set_Reg_To_Imm only did so when relocations were disabled, so with relocations enabled a non-null byref constant reached them as EA_BYREF and tripped Assertion failed 'isValidGeneralDatasize(size)' in emitarm64.cpp:3025 The movz/movk fallback had the same problem: its 'size == EA_8BYTE' tests would compute a 32 bit width for EA_BYREF and drop the upper halfwords. Only reproduces when compiling ahead of time (crossgen2/NativeAOT), where compReloc is set. Fixes #132268 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17ed5289-947f-4243-a31e-6468f680a54c --- src/coreclr/jit/codegenarm64.cpp | 8 ++-- .../JitBlue/Runtime_132268/Runtime_132268.cs | 47 +++++++++++++++++++ .../JIT/Regression/Regression_ro_2.csproj | 1 + 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index b1dfa28f51720f..85bebf191cc2ec 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -2196,7 +2196,9 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, } else { - if (emitter::emitIns_valid_imm_for_mov(imm, size)) + emitAttr immSize = EA_SIZE(size); + + if (emitter::emitIns_valid_imm_for_mov(imm, immSize)) { GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm, INS_OPTS_NONE, INS_SCALABLE_OPTS_NONE DEBUGARG(targetHandle) DEBUGARG(gtFlags)); @@ -2214,7 +2216,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, // Determine whether movn or movz will require the fewest instructions to populate the immediate int preferMovn = 0; - for (int i = (size == EA_8BYTE) ? 48 : 16; i >= 0; i -= 16) + for (int i = (immSize == EA_8BYTE) ? 48 : 16; i >= 0; i -= 16) { if (uint16_t(imm >> i) == 0xffff) ++preferMovn; // a single movk 0xffff could be skipped if movn was used @@ -2229,7 +2231,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, // This can allow skipping filling a halfword uint16_t skipVal = (preferMovn > 0) ? 0xffff : 0; - unsigned bits = (size == EA_8BYTE) ? 64 : 32; + unsigned bits = (immSize == EA_8BYTE) ? 64 : 32; // Iterate over imm examining 16 bits at a time for (unsigned i = 0; i < bits; i += 16) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs b/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs new file mode 100644 index 00000000000000..2c2e116d3c7e1e --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Regression test for https://github.com/dotnet/runtime/issues/132268 +// +// Requires an arm64 AOT compilation (crossgen2/NativeAOT) to hit the byref constant path. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +namespace Runtime_132268; + +public unsafe class Runtime_132268 +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte GetNonNullPinnableReference(Span buffer) + { + return ref buffer.Length != 0 ? ref MemoryMarshal.GetReference(buffer) : ref Unsafe.AsRef((void*)1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Consume(byte* p, int length) => p is null ? -1 : length; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Pin(Span destination) + { + fixed (byte* p = &GetNonNullPinnableReference(destination)) + { + int status = Consume(p, destination.Length); + + if (status != 0) + { + throw new InvalidOperationException(); + } + + return status; + } + } + + [Fact] + public static void TestEntryPoint() + { + Assert.Equal(0, Pin(default)); + } +} diff --git a/src/tests/JIT/Regression/Regression_ro_2.csproj b/src/tests/JIT/Regression/Regression_ro_2.csproj index ecfbfd02be8a71..509acf83e4717a 100644 --- a/src/tests/JIT/Regression/Regression_ro_2.csproj +++ b/src/tests/JIT/Regression/Regression_ro_2.csproj @@ -128,6 +128,7 @@ +