From 27e268b65cbf4498e2971ac9f51849c336ac6dce Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 23 Sep 2026 14:33:27 +0100 Subject: [PATCH] JavaScriptCore: NaN-box f32 register arguments in buildFrame operationJSToWasmEntryWrapperBuildFrame() packs an f32 register argument as a bare zero-extended 32-bit value. The shared trampoline then loads the slot with loadDouble, so on an architecture that enforces NaN-boxing for single-precision operations, such as RV64GC, the wasm body's flw/fsw on that FPR reads the canonical NaN rather than the value passed in. Set the upper 32 bits to all ones so the slot holds a properly NaN-boxed single. i32 arguments keep the plain zero-extended form. Signed-off-by: Daniel Golle --- Source/JavaScriptCore/wasm/WasmOperations.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) --- a/Source/JavaScriptCore/wasm/WasmOperations.cpp +++ b/Source/JavaScriptCore/wasm/WasmOperations.cpp @@ -133,8 +133,17 @@ JSC_DEFINE_JIT_OPERATION(operationJSToWa dataLogLnIf(WasmOperationsInternal::verbose, "* Register Arg ", i, " ", dst); - if (type.isI32() || type.isF32()) + if (type.isI32()) value = static_cast(static_cast(value)); + else if (type.isF32()) { + // Pack as NaN-boxed single (high 32 = 0xFFFFFFFF) so that + // the shared trampoline's loadDouble into the FPR yields a + // properly NaN-boxed single. Otherwise on architectures + // that enforce NaN-boxing for single-precision ops + // (RV64GC), the wasm body's subsequent flw/fsw on the f-arg + // sees the canonical NaN instead of the actual f32 value. + value = static_cast(static_cast(value)) | 0xFFFFFFFF00000000ULL; + } *access.operator()(registerSpace, dst) = value; } }