Skip to content

[SUB-BISECT] bcd47e7f3fe7 C++-only (asm stays reverted)#191

Closed
Jarred-Sumner wants to merge 9 commits into
mainfrom
ipint-revert-asm-only
Closed

[SUB-BISECT] bcd47e7f3fe7 C++-only (asm stays reverted)#191
Jarred-Sumner wants to merge 9 commits into
mainfrom
ipint-revert-asm-only

Conversation

@Jarred-Sumner

@Jarred-Sumner Jarred-Sumner commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator

Context

Windows-x64-only WebAssembly OOB crash in pglite (RuntimeError: Out of bounds memory access at invoke_vi) appeared after the WebKit upgrade in oven-sh/bun#29393. JSC_useWasmIPInt=0 hides it. Bisect history:

Build WebKit What Windows pglite
WebKit#47292 f8513c72 (#190) 7 IPInt commits reverted ❌ fails
WebKit#47370 1987e88f (#190) 7 + bcd47e7f3fe7 (wide-arith) reverted ✅ passes

bcd47e7f3fe7 is the culprit. But disassembly of LowLevelInterpreter.cpp.obj from both Windows preview builds shows all 728 ipint_* handlers are byte-identical after address normalization — the only diff is 256 bytes of .balign 512 padding before the atomic section. Conversion handler addresses 0x35000–0x36100 (slots 0xFC 0x00–0x11) are identical in both. So the IPInt asm cannot be the cause.

This branch

Starts from working 1987e88f (all 8 reverted), keeps InPlaceInterpreter64.asm + offlineasm/ reverted, and re-applies only the C++/generator/assembler parts of bcd47e7f3fe7:

  • OptionsList.h (appends useWasmWideArithmetic bool → grows OptionsStorage)
  • wasm.json + generateWasmOpsHeader.py (Ext1OpType enum entries 0x13–0x16)
  • WasmFunctionParser.h (gated parser cases)
  • WasmIPIntGenerator.cpp / WasmConstExprGenerator.cpp (stubs)
  • WasmBBQJIT.{h,cpp} / WasmBBQJIT64.cpp (topValue refactor + BBQ impls)
  • WasmOMGIRGenerator.cpp (OMG impls)
  • assembler/X86Assembler.h / MacroAssemblerX86_64.h / MacroAssemblerARM64.h (adcq/sbbq/addCarry64/subBorrow64)

Decision matrix (vs #192 which re-applies only the config slice)

#191 (this) #192 Conclusion
❌ fails ❌ fails OptionsStorage growth or Ext1OpType enum
❌ fails ✅ passes WasmBBQJIT* / WasmOMGIRGenerator / WasmFunctionParser.h / assembler/*
✅ passes ✅ passes bug IS in asm despite identical handler bytes (COFF section/reloc?)

Not for merge — bisect preview only. See #190 for the full thread.

sosukesuzuki and others added 9 commits April 22, 2026 23:03
…f it does not call functions"

This reverts commit ef40cab.
This reverts commit bcd47e7.

This is the 8th and final IPInt-touching commit from the d550dd3
upstream merge. With this revert stacked on the 7 prior reverts,
InPlaceInterpreter64.asm, InPlaceInterpreter.asm, offlineasm/x86.rb,
and WasmIPIntGenerator.cpp are now byte-identical to d924138
(the previous upstream sync point). If the Windows-x64 pglite OOB
still reproduces on this preview, the IPInt source path is provably
unchanged from the last-good build and the cause is elsewhere.

Conflict resolution: _conversion_prefix guard restored to 0x12 with
the decodeLEBVarUInt32 macro the earlier reverts already brought back.
…reverted)

Disassembly proves all 728 IPInt handlers are byte-identical between
the broken (f8513c7) and working (1987e88) Windows x64 builds, so
the InPlaceInterpreter64.asm + offlineasm changes cannot be the cause.

This branch keeps the asm/offlineasm reverted and re-applies only:
OptionsList.h, wasm.json, generateWasmOpsHeader.py, WasmFunctionParser.h,
WasmIPIntGenerator.cpp, WasmBBQJIT*.{h,cpp}, WasmOMGIRGenerator.cpp,
WasmConstExprGenerator.cpp, assembler/MacroAssembler{X86_64,ARM64}.h,
assembler/X86Assembler.h.

If this fails pglite on Windows, the bug is in one of these files.
If it passes, the disassembly comparison missed something.
@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

Walkthrough

This pull request removes deprecated WebAssembly test files, refactors the IPInt interpreter to use a dedicated PL register for locals access, consolidates metadata generation around LEB128 constant encoding, removes quad arithmetic opcode support from offline assembly, and updates debugger infrastructure to track locals via a direct pointer.

Changes

Cohort / File(s) Summary
Test Deletions
JSTests/wasm/ipint-tests/ipint-test-leb-decode.js, JSTests/wasm/ipint-tests/ipint-test-simd-memory.js, JSTests/wasm/ipint-tests/ipint-test-simd-multi-byte-leb.js, JSTests/wasm/stress/atomic-cmpxchg-large-offset.js, JSTests/wasm/stress/memory64-atomics.js, JSTests/wasm/stress/wide-arithmetic.js
Removed WebAssembly interpreter test suites covering LEB128 decoding, SIMD memory operations, atomic compare-exchange, memory64 atomics, and wide arithmetic operations.
IPInt Interpreter Core
Source/JavaScriptCore/llint/InPlaceInterpreter.asm, Source/JavaScriptCore/llint/InPlaceInterpreter.cpp, Source/JavaScriptCore/llint/InPlaceInterpreter.h
Introduced dedicated PL register for locals pointer, replaced constant-offset locals computation with direct PL usage, refactored LEB128 decoding macros with one-byte fast path, added slow-path label standardization, updated OSR and exception paths to preserve/restore PL, and extended call preservation with stack alignment adjustments.
Quad Opcode Removal
Source/JavaScriptCore/offlineasm/arm64.rb, Source/JavaScriptCore/offlineasm/x86.rb, Source/JavaScriptCore/offlineasm/instructions.rb
Removed ARM64 and x86_64 lowering support for quad-width arithmetic opcodes (addqs, subqs, adcq, sbcq, smulhq, umulhq), which now fall through to default instruction handling.
IPInt Metadata Generation
Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.cpp, Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.h, Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp, Source/JavaScriptCore/wasm/WasmIPIntGenerator.h
Refactored metadata API from per-instruction helpers to LEB128 constant-focused encoding, introduced MemoryIndexMetadata, replaced per-operation metadata structs (table/ref/elem/data/atomic), updated memory/atomic/SIMD operations to accept explicit offset/memoryIndex parameters with named argument style, and added type-based constant metadata emissions.
IPInt Slow Paths
Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.cpp, Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.h
Removed FrameAccess-based pointer math, refactored OSR scratch-buffer construction and exception handlers to use IPIntLocal* pl pointer directly, simplified call preparation logic by consolidating instance selection, and updated exception retrieval to read rethrow slots via locals indexing.
Debugger Integration
Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.cpp, Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.h, Source/JavaScriptCore/wasm/debugger/WasmExecutionHandler.cpp, Source/JavaScriptCore/wasm/debugger/WasmExecutionHandler.h, Source/JavaScriptCore/wasm/debugger/WasmQueryHandler.cpp
Updated debugger to track and propagate IPIntLocal* locals pointer through trap handling, stop data capture, and local variable inspection; added localsFromFrame helper to recompute locals from frame/callee; refactored local value lookup to use direct array indexing instead of FrameAccess.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title '[SUB-BISECT] bcd47e7 C++-only (asm stays reverted)' is descriptive and clearly indicates this is a bisect preview focused on C++ changes while keeping assembly reverted.
Description check ✅ Passed The description comprehensively explains the context (Windows OOB crash), bisect history, the culprit commit, disassembly findings, the branch's scope (C++/generator/assembler parts only), decision matrix for testing, and explicitly notes this is not for merge but a bisect preview.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.cpp (1)

342-347: ⚠️ Potential issue | 🟠 Major

Initialize locals in the prologue-stop constructor too.

This overload is still the one used for function-entry/prologue stops, but it leaves StopData::locals unset. Frame-0 local queries now rely on that pointer, so locals inspection at a prologue breakpoint will keep seeing null/stale data unless this path also computes localsFromFrame(callFrame, callee).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.cpp` around
lines 342 - 347, The prologue-stop constructor StopData::StopData(IPIntCallee*
callee, JSWebAssemblyInstance* instance, CallFrame* callFrame) fails to
initialize StopData::locals, so prologue/frame-0 local inspection can read
null/stale data; update that constructor to compute and assign locals by calling
localsFromFrame(callFrame, callee) (same way the other StopData overload does)
so StopData::locals is properly populated for prologue/function-entry stops.
Source/JavaScriptCore/llint/InPlaceInterpreter.asm (1)

112-122: ⚠️ Potential issue | 🔴 Critical

PL is not actually dedicated on ARMv7.

Line 112 makes PL and sc3 aliases of the same register (t7). Any ARMv7 path that uses sc3 as scratch will clobber the locals base and corrupt local/rethrow-slot accesses. This needs a distinct register allocation, or ARMv7 needs to stay on the old layout.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/llint/InPlaceInterpreter.asm` around lines 112 - 122,
PL (locals base) is incorrectly aliased to sc3 via t7, so using sc3 will clobber
the locals base on ARMv7; update the register allocation so PL and sc3 are
distinct (e.g., stop aliasing PL to t7 or pick a different temp for sc3 such as
t6 or another free GPR) and ensure the ARMv7 path either uses the old register
layout or the new layout with unique bindings for PL and sc3 (adjust the const
PL, sc3, and any related aliases like t7 accordingly so locals/rethrow-slot
accesses are not corrupted).
Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp (3)

309-310: ⚠️ Potential issue | 🟠 Major

Add instruction-length metadata to memory.size and memory.grow operations.

addGrowMemory and addCurrentMemory record only the memory index but omit the instruction-length metadata, unlike all other memory operations (addMemoryFill, addMemoryCopy, addMemoryInit) and SIMD operations in this file, which consistently call m_metadata->addLength(getCurrentInstructionLength()). This metadata is necessary to correctly advance past variable-length immediates during bytecode interpretation.

Fix
[[nodiscard]] PartialResult IPIntGenerator::addGrowMemory(ExpressionType, ExpressionType&, uint8_t memoryIndex)
{
    m_metadata->addMemoryIndex(memoryIndex);
+   m_metadata->addLength(getCurrentInstructionLength());
    return { };
}

[[nodiscard]] PartialResult IPIntGenerator::addCurrentMemory(ExpressionType&, uint8_t memoryIndex)
{
    changeStackSize(1);
    m_metadata->addMemoryIndex(memoryIndex);
+   m_metadata->addLength(getCurrentInstructionLength());
    return { };
}

Also applies to: lines 1120–1130

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp` around lines 309 - 310,
The addGrowMemory and addCurrentMemory implementations record only the memory
index and omit instruction-length metadata; update both functions (addGrowMemory
and addCurrentMemory in WasmIPIntGenerator.cpp) to call
m_metadata->addLength(getCurrentInstructionLength()) at the same point other
memory ops do so (after recording the memory index/immediate) so the interpreter
advances past variable-length immediates correctly; apply the same change in the
corresponding code path later in the file where these functions/logic are
duplicated.

318-325: ⚠️ Potential issue | 🟠 Major

Update atomic operations to support memory64 offsets consistently with scalar load/store.

The atomic functions (atomicLoad, atomicStore, atomicBinaryRMW, atomicCompareExchange, atomicWait, atomicNotify) currently accept only uint32_t offsets and use addLEB128ConstantInt32AndLength(), which prevents them from representing offsets above 4 GiB in shared memory64. The scalar load() and store() operations already implement the correct pattern: accepting uint64_t offsets with a conditional check for isMemory64() to use the appropriate encoding. Atomic operations must follow the same approach per the WebAssembly threads specification.

Suggested fix
-[[nodiscard]] PartialResult atomicLoad(ExtAtomicOpType, Type, ExpressionType, ExpressionType&, uint32_t, uint8_t);
-[[nodiscard]] PartialResult atomicStore(ExtAtomicOpType, Type, ExpressionType, ExpressionType, uint32_t, uint8_t);
-[[nodiscard]] PartialResult atomicBinaryRMW(ExtAtomicOpType, Type, ExpressionType, ExpressionType, ExpressionType&, uint32_t, uint8_t);
-[[nodiscard]] PartialResult atomicCompareExchange(ExtAtomicOpType, Type, ExpressionType, ExpressionType, ExpressionType, ExpressionType&, uint32_t, uint8_t);
-[[nodiscard]] PartialResult atomicWait(ExtAtomicOpType, ExpressionType, ExpressionType, ExpressionType, ExpressionType&, uint32_t, uint8_t);
-[[nodiscard]] PartialResult atomicNotify(ExtAtomicOpType, ExpressionType, ExpressionType, ExpressionType&, uint32_t, uint8_t);
+[[nodiscard]] PartialResult atomicLoad(ExtAtomicOpType, Type, ExpressionType, ExpressionType&, uint64_t, uint8_t);
+[[nodiscard]] PartialResult atomicStore(ExtAtomicOpType, Type, ExpressionType, ExpressionType, uint64_t, uint8_t);
+[[nodiscard]] PartialResult atomicBinaryRMW(ExtAtomicOpType, Type, ExpressionType, ExpressionType, ExpressionType&, uint64_t, uint8_t);
+[[nodiscard]] PartialResult atomicCompareExchange(ExtAtomicOpType, Type, ExpressionType, ExpressionType, ExpressionType, ExpressionType&, uint64_t, uint8_t);
+[[nodiscard]] PartialResult atomicWait(ExtAtomicOpType, ExpressionType, ExpressionType, ExpressionType, ExpressionType&, uint64_t, uint8_t);
+[[nodiscard]] PartialResult atomicNotify(ExtAtomicOpType, ExpressionType, ExpressionType, ExpressionType&, uint64_t, uint8_t);

-    m_metadata->addLEB128ConstantInt32AndLength(offset, getCurrentInstructionLength());
+    if (m_info.memory(memoryIndex).isMemory64())
+        m_metadata->addLEB128ConstantInt64AndLength(offset, getCurrentInstructionLength());
+    else
+        m_metadata->addLEB128ConstantInt32AndLength(static_cast<uint32_t>(offset), getCurrentInstructionLength());

Also applies to: 1166-1215

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp` around lines 318 - 325,
The atomic operation declarations and implementations (atomicLoad, atomicStore,
atomicBinaryRMW, atomicCompareExchange, atomicWait, atomicNotify) must accept
uint64_t offsets (not uint32_t) and mirror the scalar load/store encoding: when
emitting offset immediates, check isMemory64() and call
addLEB128ConstantInt64AndLength() for memory64 or keep
addLEB128ConstantInt32AndLength() for memory32; update all call sites to pass
uint64_t offsets and ensure the emitted op encoding uses the correct offset
encoding branch; leave atomicFence signature as-is. Include the changed function
signatures (e.g., atomicLoad(..., uint64_t, uint8_t)) and corresponding encoding
changes inside those routines so offsets above 4 GiB are representable for
shared memory64.

249-259: ⚠️ Potential issue | 🟠 Major

Apply memory64 offset handling to SIMD memarg helpers.

Vector loads/stores use a memarg immediate with offset encoding. The scalar memory operations (load, store) already branch on isMemory64() to emit either int64 or int32 metadata for the offset. The SIMD memarg helpers—addSIMDLoad, addSIMDStore, addSIMDLoadLane, addSIMDStoreLane, and their delegates (addSIMDLoadSplat, addSIMDLoadExtend, addSIMDLoadPad)—still take uint32_t offset and unconditionally emit int32 metadata, causing offsets above 4 GiB to be truncated in memory64 modules.

Change all SIMD offset parameters from uint32_t to uint64_t and add the same isMemory64() branching logic used in scalar operations.

Suggested fix pattern
-[[nodiscard]] PartialResult addSIMDLoad(ExpressionType, uint32_t, ExpressionType&, uint8_t);
+[[nodiscard]] PartialResult addSIMDLoad(ExpressionType, uint64_t, ExpressionType&, uint8_t);

-[[nodiscard]] PartialResult IPIntGenerator::addSIMDLoad(ExpressionType, uint32_t offset, ExpressionType&, uint8_t memoryIndex)
+[[nodiscard]] PartialResult IPIntGenerator::addSIMDLoad(ExpressionType, uint64_t offset, ExpressionType&, uint8_t memoryIndex)
 {
     changeStackSize(0);
     m_metadata->addMemoryIndex(memoryIndex);
-    m_metadata->addLEB128ConstantInt32AndLength(offset, getCurrentInstructionLength());
+    if (m_info.memory(memoryIndex).isMemory64())
+        m_metadata->addLEB128ConstantInt64AndLength(offset, getCurrentInstructionLength());
+    else
+        m_metadata->addLEB128ConstantInt32AndLength(static_cast<uint32_t>(offset), getCurrentInstructionLength());
     return { };
 }

Apply the same pattern to addSIMDStore, addSIMDLoadLane, and addSIMDStoreLane.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp` around lines 249 - 259,
The SIMD memarg helpers currently take uint32_t offsets and always emit 32-bit
offset metadata; update all SIMD offset parameters from uint32_t to uint64_t for
addSIMDLoad, addSIMDStore, addSIMDLoadLane, addSIMDStoreLane and their delegates
addSIMDLoadSplat, addSIMDLoadExtend, addSIMDLoadPad, then add the same
isMemory64() branching used by scalar loads/stores to emit either int64 or int32
offset metadata (use isMemory64() to choose emitting 64-bit offset metadata vs
32-bit) so offsets >4GiB are preserved in memory64 modules.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Source/JavaScriptCore/llint/InPlaceInterpreter.asm`:
- Around line 1205-1209: The saved frame slot order for [PL, callee/ws0] must be
normalized before invoking the debugger slow path; update the sequence around
push PC, MC / push PL, ws0 and the preparation of a2/sp so that the memory
layout matches the expectation in _ipint_extern_handle_debugger_trap_if_needed
(sp[0]==PL, sp[1]==ws0) on all architectures—e.g., detect or account for the
platform-specific multi-register push order and swap or reorder the saved PL and
callee/ws0 slots (the values used to compute a2/sp passed to operationCall of
_ipint_extern_handle_debugger_trap_if_needed) so the handler never reads swapped
pointers.

In `@Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.cpp`:
- Around line 95-103: The code in the i32 fast path (inside the type.isI32()
branch) writes the wrong value into IPInt::InstructionLengthMetadata.length by
using (value >> 7) & 1; change this to store the actual instruction length (i.e.
2) when length == 2: set IPInt::InstructionLengthMetadata.mdConst.length =
safeCast<uint8_t>(2) (instead of the immediate bit), then continue to grow
m_metadata and WRITE_TO_METADATA as before so metadata-driven decoding remains
in sync; reference the IPInt::InstructionLengthMetadata struct, m_metadata,
WRITE_TO_METADATA, and the length variable when locating the fix.

---

Outside diff comments:
In `@Source/JavaScriptCore/llint/InPlaceInterpreter.asm`:
- Around line 112-122: PL (locals base) is incorrectly aliased to sc3 via t7, so
using sc3 will clobber the locals base on ARMv7; update the register allocation
so PL and sc3 are distinct (e.g., stop aliasing PL to t7 or pick a different
temp for sc3 such as t6 or another free GPR) and ensure the ARMv7 path either
uses the old register layout or the new layout with unique bindings for PL and
sc3 (adjust the const PL, sc3, and any related aliases like t7 accordingly so
locals/rethrow-slot accesses are not corrupted).

In `@Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.cpp`:
- Around line 342-347: The prologue-stop constructor
StopData::StopData(IPIntCallee* callee, JSWebAssemblyInstance* instance,
CallFrame* callFrame) fails to initialize StopData::locals, so prologue/frame-0
local inspection can read null/stale data; update that constructor to compute
and assign locals by calling localsFromFrame(callFrame, callee) (same way the
other StopData overload does) so StopData::locals is properly populated for
prologue/function-entry stops.

In `@Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp`:
- Around line 309-310: The addGrowMemory and addCurrentMemory implementations
record only the memory index and omit instruction-length metadata; update both
functions (addGrowMemory and addCurrentMemory in WasmIPIntGenerator.cpp) to call
m_metadata->addLength(getCurrentInstructionLength()) at the same point other
memory ops do so (after recording the memory index/immediate) so the interpreter
advances past variable-length immediates correctly; apply the same change in the
corresponding code path later in the file where these functions/logic are
duplicated.
- Around line 318-325: The atomic operation declarations and implementations
(atomicLoad, atomicStore, atomicBinaryRMW, atomicCompareExchange, atomicWait,
atomicNotify) must accept uint64_t offsets (not uint32_t) and mirror the scalar
load/store encoding: when emitting offset immediates, check isMemory64() and
call addLEB128ConstantInt64AndLength() for memory64 or keep
addLEB128ConstantInt32AndLength() for memory32; update all call sites to pass
uint64_t offsets and ensure the emitted op encoding uses the correct offset
encoding branch; leave atomicFence signature as-is. Include the changed function
signatures (e.g., atomicLoad(..., uint64_t, uint8_t)) and corresponding encoding
changes inside those routines so offsets above 4 GiB are representable for
shared memory64.
- Around line 249-259: The SIMD memarg helpers currently take uint32_t offsets
and always emit 32-bit offset metadata; update all SIMD offset parameters from
uint32_t to uint64_t for addSIMDLoad, addSIMDStore, addSIMDLoadLane,
addSIMDStoreLane and their delegates addSIMDLoadSplat, addSIMDLoadExtend,
addSIMDLoadPad, then add the same isMemory64() branching used by scalar
loads/stores to emit either int64 or int32 offset metadata (use isMemory64() to
choose emitting 64-bit offset metadata vs 32-bit) so offsets >4GiB are preserved
in memory64 modules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9286e060-c15c-4683-85b6-eeb3d97635a3

📥 Commits

Reviewing files that changed from the base of the PR and between 7ab1748 and 62f63bf.

📒 Files selected for processing (24)
  • JSTests/wasm/ipint-tests/ipint-test-leb-decode.js
  • JSTests/wasm/ipint-tests/ipint-test-simd-memory.js
  • JSTests/wasm/ipint-tests/ipint-test-simd-multi-byte-leb.js
  • JSTests/wasm/stress/atomic-cmpxchg-large-offset.js
  • JSTests/wasm/stress/memory64-atomics.js
  • JSTests/wasm/stress/wide-arithmetic.js
  • Source/JavaScriptCore/llint/InPlaceInterpreter.asm
  • Source/JavaScriptCore/llint/InPlaceInterpreter.cpp
  • Source/JavaScriptCore/llint/InPlaceInterpreter.h
  • Source/JavaScriptCore/llint/InPlaceInterpreter64.asm
  • Source/JavaScriptCore/offlineasm/arm64.rb
  • Source/JavaScriptCore/offlineasm/instructions.rb
  • Source/JavaScriptCore/offlineasm/x86.rb
  • Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.cpp
  • Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.h
  • Source/JavaScriptCore/wasm/WasmIPIntGenerator.cpp
  • Source/JavaScriptCore/wasm/WasmIPIntGenerator.h
  • Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.cpp
  • Source/JavaScriptCore/wasm/WasmIPIntSlowPaths.h
  • Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.cpp
  • Source/JavaScriptCore/wasm/debugger/WasmDebugServerUtilities.h
  • Source/JavaScriptCore/wasm/debugger/WasmExecutionHandler.cpp
  • Source/JavaScriptCore/wasm/debugger/WasmExecutionHandler.h
  • Source/JavaScriptCore/wasm/debugger/WasmQueryHandler.cpp
💤 Files with no reviewable changes (8)
  • JSTests/wasm/stress/memory64-atomics.js
  • JSTests/wasm/ipint-tests/ipint-test-leb-decode.js
  • JSTests/wasm/stress/atomic-cmpxchg-large-offset.js
  • JSTests/wasm/ipint-tests/ipint-test-simd-memory.js
  • JSTests/wasm/ipint-tests/ipint-test-simd-multi-byte-leb.js
  • Source/JavaScriptCore/offlineasm/arm64.rb
  • Source/JavaScriptCore/offlineasm/x86.rb
  • JSTests/wasm/stress/wide-arithmetic.js

Comment on lines 1205 to 1209
push PC, MC
push ws0, ws0 # sp[0]=ws0 (unused), sp[1]=ws0 (IPIntCallee*), sp[2]=PC, sp[3]=MC
push PL, ws0 # sp[0]=PL, sp[1]=ws0 (IPIntCallee*), sp[2]=PC, sp[3]=MC
move cfr, a1
move sp, a2 # a2 = pointer to saved [ws0, ws0, PC, MC]
move sp, a2 # a2 = pointer to saved [PL, ws0, PC, MC]
operationCall(macro() cCall3(_ipint_extern_handle_debugger_trap_if_needed) end)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Normalize the saved [PL, callee] layout before calling the debugger slow path.

This code assumes sp[0] == PL and sp[1] == ws0, but elsewhere in this file you already note that multi-register push order differs between ARM64 and X86_64. On X86_64, handle_debugger_trap_if_needed can read swapped pointers and treat the callee as the locals base.

💡 Suggested fix
 macro handleDebuggerTrapIfNeeded()
     push PC, MC
-    push PL, ws0    # sp[0]=PL, sp[1]=ws0 (IPIntCallee*), sp[2]=PC, sp[3]=MC
+    if ARM64 or ARM64E
+        push PL, ws0    # sp[0]=PL, sp[1]=ws0, sp[2]=PC, sp[3]=MC
+    elsif X86_64
+        push ws0
+        push PL         # force the same logical layout seen by C++
+    end
     move cfr, a1
     move sp, a2     # a2 = pointer to saved [PL, ws0, PC, MC]
     operationCall(macro() cCall3(_ipint_extern_handle_debugger_trap_if_needed) end)
     addp 4 * MachineRegisterSize, sp
 end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/llint/InPlaceInterpreter.asm` around lines 1205 - 1209,
The saved frame slot order for [PL, callee/ws0] must be normalized before
invoking the debugger slow path; update the sequence around push PC, MC / push
PL, ws0 and the preparation of a2/sp so that the memory layout matches the
expectation in _ipint_extern_handle_debugger_trap_if_needed (sp[0]==PL,
sp[1]==ws0) on all architectures—e.g., detect or account for the
platform-specific multi-register push order and swap or reorder the saved PL and
callee/ws0 slots (the values used to compute a2/sp passed to operationCall of
_ipint_extern_handle_debugger_trap_if_needed) so the handler never reads swapped
pointers.

Comment on lines +95 to +103
if (type.isI32()) {
size_t size = m_metadata.size();
if (length == 2) {
IPInt::InstructionLengthMetadata mdConst {
.length = safeCast<uint8_t>((value >> 7) & 1)
};
m_metadata.grow(size + sizeof(mdConst));
WRITE_TO_METADATA(m_metadata.mutableSpan().data() + size, mdConst, IPInt::InstructionLengthMetadata);
} else {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

The 2-byte i32 fast path stores the wrong metadata value.

Line 99 writes (value >> 7) & 1 into InstructionLengthMetadata.length. That is a bit from the immediate, not the instruction length, so 2-byte immediates end up with length == 0/1 instead of 2, and metadata-driven decoding will drift immediately after the first such instruction.

💡 Suggested fix
         if (length == 2) {
             IPInt::InstructionLengthMetadata mdConst {
-                .length = safeCast<uint8_t>((value >> 7) & 1)
+                .length = safeCast<uint8_t>(length)
             };
             m_metadata.grow(size + sizeof(mdConst));
             WRITE_TO_METADATA(m_metadata.mutableSpan().data() + size, mdConst, IPInt::InstructionLengthMetadata);
         } else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Source/JavaScriptCore/wasm/WasmFunctionIPIntMetadataGenerator.cpp` around
lines 95 - 103, The code in the i32 fast path (inside the type.isI32() branch)
writes the wrong value into IPInt::InstructionLengthMetadata.length by using
(value >> 7) & 1; change this to store the actual instruction length (i.e. 2)
when length == 2: set IPInt::InstructionLengthMetadata.mdConst.length =
safeCast<uint8_t>(2) (instead of the immediate bit), then continue to grow
m_metadata and WRITE_TO_METADATA as before so metadata-driven decoding remains
in sync; reference the IPInt::InstructionLengthMetadata struct, m_metadata,
WRITE_TO_METADATA, and the length variable when locating the fix.

@github-actions

Copy link
Copy Markdown

Preview Builds

Commit Release Date
62f63bf3 autobuild-preview-pr-191-62f63bf3 2026-04-23 00:47:52 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants