Commit graph

159 commits

Author SHA1 Message Date
Ali Mohammad Pur
b3f3d68291 LibWeb+LibWasm: Keep WebAssembly cache storage stable
These need to stay in place across rehashes so we can avoid querying
their address on every collection cycle.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
530c95fde5 LibWasm: Remove all gc, function-refs and EH test exceptions 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
8a74f52571 LibWasm: Partially implement the (new) exception handling proposal
This implements try_table and throw_ref execution in the interpreter.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
16d1486cc9 LibWasm: Implement the wasm-gc instruction set in the BC interpreter 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
87961e3c92 LibWasm: Back wasm-gc aggregate instances with the LibGC heap 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
62cb073ada LibWasm: Validate the wasm-gc and function-references instructions
Actual implementations are still trap-on-exec.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
42c0a430f5 LibWasm: Implement the spec's type matching relations 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
3ca552b37b LibWasm: Parse wasm-gc types
No more unsupported heap refs.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
340d87efd6 LibWasm: Catch SIGFPE on jitted code too
SIGFPE can happen if we emit a bare idiv.
2026-06-15 16:09:51 +02:00
Andreas Kling
8a8625b399 LibWasm: Require virtual storage for wasm32 memory
Reserve the wasm32 virtual address space when creating an i32 memory.
Crash if the reservation fails instead of using ByteBuffer storage.

This keeps wasm32 memory on the virtual path used for fault recovery.
2026-06-10 17:34:16 +02:00
Ali Mohammad Pur
90b86fd82b LibWasm: Correctly track section ordering requirements 2026-06-10 14:10:57 +02:00
Ali Mohammad Pur
a51383e8af LibWasm: Constrain code section to its declared size 2026-06-10 14:10:57 +02:00
Ali Mohammad Pur
34fd6d87f4 LibWasm: Delete Frame's move operator=
This is not used and is a footgun anyway.
2026-06-10 14:10:57 +02:00
Ali Mohammad Pur
c414f31ecf LibWasm: Correctly handle memory64's addr types in the interpreter 2026-06-10 14:10:57 +02:00
Ali Mohammad Pur
f81717d4c8 LibWasm: Allow allocating max-size wasm32 memories
We used to disallow allocating 65536 pages, but that's fine as per spec.
2026-06-10 14:10:57 +02:00
Ali Mohammad Pur
6d2470dcad LibWasm: Refer to cranelift-compiler by relative path and env override 2026-06-05 19:59:03 +02:00
Ali Mohammad Pur
08221aebab LibWasm: Start execution immediately after validation
This adds a tier-up mechanism at loop edges, making it so we can
seamlessly (ish) transition between interpreted and native code so we
can start running wasm code immediately after validation while
compilation happens in the background, and switching to native code
eventually once we hit a big enough function that would benefit from
being compiled to begin with.
2026-06-05 00:08:11 +02:00
Ali Mohammad Pur
3c89c36158 LibWasm+LibWeb: Restore disk cache for compiled wasm modules
Also untangle the confusing validation layering on async compilation.
2026-06-05 00:08:11 +02:00
Andreas Kling
164ed80244 Meta: Enable exit-time destructor warnings for libraries
Enable -Wexit-time-destructors for all in-tree library targets and
update process-lifetime library statics so they no longer register
exit-time destructors. Long-lived caches, lookup tables, singleton
registries, and generated constants now use NeverDestroyed or leaked
references where the data is intended to live until process exit.

Update LibWeb, LibLine, and the binding generators so regenerated
sources follow the same rule instead of reintroducing destructed
statics.
2026-06-04 19:20:49 +02:00
François Guerraz
be4173af81 LibWasm: Validate a tag's type index before dereferencing it
The throw and try_table validators looked up the tag referenced by the
instruction, then indexed m_context.types with the tag's type index
without checking it was in range. validate(TagIndex) only validates the
tag index itself, and the tag section is validated after the code
section, so a module whose tag carries an out-of-range type index
reached the unchecked m_context.types[...] access and tripped a Vector
bounds assertion during validation.

Any WebAssembly.compile() of such a module aborts the WebContent
process.

Validate the tag's type index before using it, the same check
validate(TagType) already performs.
2026-06-04 13:54:58 +02:00
Andreas Kling
716ab93c1a LibWasm: Block while waiting for Cranelift compilation
The background Cranelift pass can race with the first call into a
module. In that case ensure_cranelift_compiled() waited by repeatedly
polling the module state and burning CPU until the compiler thread
finished.

Keep the atomic state for the completed fast path, but pair the
compiling state with a condition variable. Completion now broadcasts
while holding the associated mutex, so waiting callers sleep and cannot
miss the transition to finished.
2026-06-04 00:15:26 +02:00
Ali Mohammad Pur
841572f358 LibWeb+LibWasm: Don't wait for JIT-compilation of wasm modules
Return from the jsapi calls when we have a module that satisfies the
state required by the spec, and let jit compilation (if it's happening)
continue in the background.
This also means we no longer do the full compilation pipeline for
validate().
2026-06-03 11:51:43 +02:00
Ali Mohammad Pur
5c1d2004b7 LibWasm: Handle traps emitted from cranelift 2026-06-03 11:51:43 +02:00
Ali Mohammad Pur
68f6c03a67 LibWasm: Correctly handle failed validation 2026-06-03 11:51:43 +02:00
Ali Mohammad Pur
123d37b299 LibWasm: Enable the JIT by default 2026-05-31 20:26:22 +02:00
Ali Mohammad Pur
01db906039 LibWasm: Disable direct threading on ASAN builds
ASAN changes tailcall semantics that break the code.
2026-05-31 20:26:22 +02:00
Ali Mohammad Pur
67c03ee103 LibWasm: Declare extern "C" functions instead of disabling the warning
Clang will complain about the diagnostic anyway.
2026-05-31 20:26:22 +02:00
Ali Mohammad Pur
402e151b62 LibWasm: Move the "rest" of br_if.nostack into a separate function
...instead of a lambda, so gcc doesn't have to deal with annotations on
lambdas.
2026-05-28 10:34:26 +02:00
Vanand Gasparyan
f3a3488cda Rust: Set import granularity to Item
By default, `rustfmt` persists the import granularity. In practice, most
Rust code has import granularity "Module" due to LSP's actions.

"Item" gets rid of import groupings and achieves cleaner diffs and
better conflict resolution. Better greppability is a positive side
effect.

Note: it's an unstable rustfmt feature. `cargo +nightly fmt` must be
used instead of `cargo fmt`.
2026-05-28 06:52:18 +02:00
Ali Mohammad Pur
f54ad4ca25 LibWasm: Only build the compiled function table once per module 2026-05-27 09:52:34 +02:00
Ali Mohammad Pur
842e8a6796 LibWasm+LibWeb: Add per-module wasm compile stats 2026-05-27 09:52:34 +02:00
Ali Mohammad Pur
2419cce8d8 LibWasm+LibWeb: Serialize and save compiled wasm as a cache blob 2026-05-27 09:52:34 +02:00
Ali Mohammad Pur
f31519c393 LibWasm: Add runtime checks to nostack br/br_if
synthetic_br_nostack and synthetic_br_if_nostack assumed the runtime
value stack already matches the target label's expected size. The
register allocator can leave more values on the stack than the
validator's abstract count predicted, so the bare nostack variants get
us out of sync and we crash later. This makes it so they drop to regular
br/br_if behaviour if they notice that the size is not as expected.
2026-05-27 09:52:34 +02:00
Ali Mohammad Pur
8e8a8f9270 LibWasm: Tighten the cranelift direct-call lookup paths
Switches the compiled function table from HashMap<u32, ...> to a Vector
indexed by function index. The keys are densely packed up to
functions.size() so the hash probe wasn't buying us anything.

Also drops the bounds check from MemoryInstance::unsafe_get to match
FunctionInstance::unsafe_get; the caller has already proved the address
is in range by the time we get here.
2026-05-27 09:52:34 +02:00
sideshowbarker
59eb221d7c LibWasm: Fix “return” leaking intermediate value-stack entries to caller
Problem: Loading WebAssembly modules that use “return” mid-function can
corrupt the heap and crash the browser.

Cause: HANDLE_INSTRUCTION(return_) shrank the label stack but left any
working values pushed before the “return” instruction on the shared
value stack. Those residuals leaked into the caller’s frame and
accumulated across calls — until they overflowed the value stack’s
inline storage and corrupted adjacent allocator metadata.

Fix: After shrinking the label stack down to the function-level label,
also remove value-stack entries between that label’s recorded
stack_height and the top .arity() result values — mirroring the cleanup
that branch_to_label<true> already performs for br/br_if.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9614
2026-05-25 09:00:44 +02:00
Andreas Kling
f374e72c54 LibWasm: Store try_table catches out of line
TryTableArgs only needs catches for try_table instructions. Reuse the
structured-instruction layout with catch storage in place of the else
target, and keep the catch elements in a FixedArray.

This avoids storing a full Vector inline in every Instruction variant
alternative and keeps the catch storage copyable for the variant.
2026-05-14 12:19:38 +02:00
Andreas Kling
d893700808 LibWasm: Store ValueType payload directly
ValueType only needs a TypeIndex payload for TypeUseReference values.
Store that directly instead of using a Variant with an Empty payload,
shrinking ValueType from 12 bytes to 8 bytes.
2026-05-14 12:19:38 +02:00
Andreas Kling
571bbba042 LibWasm: Use chunked synthetic instruction storage
Keep synthetic instruction pointers stable by storing them in fixed
chunks instead of one large Vector. This removes the old oversized
reserve. Expressions without synthetic instructions now avoid extra
instruction storage entirely.
2026-05-14 12:19:38 +02:00
Andreas Kling
8775f48436 LibWasm: Store structured metadata directly
Validation always fills structured instruction metadata before compiled
expressions are executed. Store the metadata directly instead of using
Optional, and update execution and printing paths accordingly.
2026-05-14 12:19:38 +02:00
Andreas Kling
66149938b7 LibWasm: Use sentinel optionals for instructions
Specialize Optional for InstructionPointer and Instruction. Use each
type's maximum value to represent the empty state.

This keeps each optional as small as the wrapped value.
2026-05-14 12:19:38 +02:00
Andreas Kling
f22dec54ef LibWasm: Store opcodes in 32 bits
Wasm opcodes only need one byte plus a 24-bit selector for
prefixed instructions. Store them in u32 instead of u64 and reject
selectors that would not fit. Update the Rust opcode generator to
accept the new integer suffixes used by Opcode.h.
2026-05-14 12:19:38 +02:00
Andreas Kling
2dab9f53d2 LibWasm: Use mmap to read shm fd on macOS in cranelift-compiler
macOS POSIX shared memory objects returned by shm_open() only support
mmap() and ftruncate(). Calls to read(), write(), pread() or pwrite()
all fail with ESPIPE. The cranelift-compiler child was using pread/
pwrite via File::read_exact_at/write_all_at, which works fine on
Linux where the parent uses memfd_create(), but fails on macOS where
the parent uses shm_open().

Add a macOS-specific path that mmaps the inherited shm fd with
MAP_SHARED, mirroring the Windows MapViewOfFile path. Writes through
the mapping are automatically visible to the parent, so the explicit
write-back step at the end is also skipped on macOS.
2026-05-11 09:57:33 +02:00
Andreas Kling
c9e135cdff LibWasm: Clear FD_CLOEXEC on shm fd before spawning Cranelift child
On macOS, the cranelift JIT compilation step works by creating an
anonymous shared memory segment via shm_open() in the parent process
and passing the fd as an argument to the spawned cranelift-compiler
child. POSIX requires shm_open() to set FD_CLOEXEC on the returned
fd, which caused the child to immediately fail with EBADF when it
tried to read from the inherited fd number.

Clear FD_CLOEXEC after shm_open() so the fd actually survives the
spawn. The Linux memfd_create() path is unaffected since we call it
with flags=0 (no MFD_CLOEXEC), and Windows passes an inheritable
HANDLE instead of an fd.
2026-05-11 09:57:33 +02:00
Ali Mohammad Pur
9bda97a11b LibWasm: Avoid huge switches in all handlers' log functions
This explodes the debug info size, making the CI runner OOM when
building this file :)
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
a36f6abedb LibWasm+LibWeb: Properly track module lifetime with function refs 2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
a33e148339 LibWasm+Meta: Add Cranelift AOT compilation backend
Add an optional Cranelift-based AOT compiler for WebAssembly functions,
enabled via -DENABLE_CRANELIFT_JIT=ON.
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
96c3a5ed73 LibWasm: Add a regression test for cross-module memory access
This is not well-covered in neither the spectests nor our own tests.
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
5ab2eaed8c LibWasm: Fix some signedness bugs
- memory.grow page count
- memory.copy offsets and underflow in copy op
- table_{set,get} index exec
2026-05-10 16:41:42 +02:00
Ali Mohammad Pur
f181d24dc0 LibWasm: Prepare for VM and direct function calls
Introduce MemoryBuffer, a memory backing store that uses mmap to reserve
the full wasm32 address space (4 GiB + guard pages) upfront, growing
without a copy and falling back to a ByteBuffer when mmap fails.
Also let Frame know how to handle non-owned locals (to e.g. allow
allocating them on the native stack.)
2026-05-10 16:41:42 +02:00
Andreas Kling
eb789e790e Everywhere: Use AK::SaturatingMath and remove Checked saturating APIs
Port all callers of Checked<T>::saturating_add/sub/mul to the new
standalone functions in AK/SaturatingMath.h, and remove the old
APIs from Checked.
2026-03-21 18:20:09 -05:00