Commit graph

51 commits

Author SHA1 Message Date
Marcus Nilsson
bfa51c2555 LibWasm: Parse struct types and support multiple types in type section
This patch adds support for parsing structs in the type section.

It also removes the assumption that all types in the type section are
function types, adding appropriate validation.

Spec tests struct.3 and struct.4 have been disable as this would
require expanding `ValueType` to include more heap-types.
2026-02-04 14:29:22 +01:00
Ali Mohammad Pur
0dc39e9bfd LibWasm: Use the source_value() mechanism in binary_numeric_operation
This avoids a bunch of extra stack ops and some unnecessary loads for
registers.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
9964c64446 LibWasm: Implement the i32 const/local fusions for i64 too 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
a0ce33e616 LibWasm: Preserve the right number of values on loop entry 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
a5db31943e LibWasm: Fix return_call label stack shrink
The label stack should be shrunk to the frame's label_index (exclusive),
not label_index + 1. Also add the missing shrink call for
return_call_indirect.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
9d7c56d7ab LibWasm: Defer the load of addresses until after dispatch
This unlocks a significant (+50%) performance improvement that previous
commits have been building up towards.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
7f5ca14f58 LibWasm: Specialize instruction dispatch for all-stack cases too 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
2d15ef7372 LibWasm: Remove all runtime VERIFYs from the 'block' handler
All of these are already checked at the verification stage, so downgrade
them to ASSERTs.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
0e6943b17d LibWasm: Avoid unnecessary bounds checks in memory ops 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
ae9ced65b7 LibWasm: Add a bunch more fused ops
- synthetic_argument_set, synthetic_argument_tee
- synthetic_local_get_0..7, synthetic_local_set_0..7
- synthetic_br_nostack, synthetic_br_if_nostack
- synthetic_local_copy for local-to-local copies
- synthetic_i32_{sub,mul,and,or,xor,shl,shru,shrs}2local
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
9a74bf87d8 LibWasm: Minimize runtime overhead for block/branch ops
Preevaluate arity and params to avoid pointer chasing at exec time.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
921373a045 LibWasm: Implement call argument forwarding using call records 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
f180d90c20 LibWasm: Re-add trace logging to handlers 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
0d5363caff LibWasm: Compress current_ip + addresses into one u64 field
This saves a register, which then consequently saves us from spilling on
the stack (in most places that matter).
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
446240da63 LibWasm: Specialise source/dest accesses based on stack access 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
6ede78aa0a LibWasm: Validate compiled instruction stream
This helps catch a bunch of miscompilations early.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
a72127c39d LibWasm: Move out addresses into their own allocation
Instead of trying to indirectly load 2x64 bits from *cc, load addresses
directly from their own contiguous allocation.

This allows a future optimisation where we defer loading addresses to
reduce memory port pressure.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
70f839ccb2 LibWasm: Take call arguments as references and recycle the allocations
This opens the way for a allocated-at-start call frame optimisation
(that will come in a future commit).
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
be9d8288ef LibWasm: Take call arguments and results on registers if possible 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
b89ecfc6bc LibWasm: Split parameters from locals 2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
ac979648bd AK+LibJS: Zero out new Vector allocs instead of calling trivial ctor
As JS::Value is marked "trivial" without actually being trivial, make
the one user that would lead to garbage JS::Value entries provide a
default value instead.
2026-02-02 14:11:49 +01:00
Ali Mohammad Pur
b93c17e5e7 LibWasm: Implement (n)madd/vetor dot arguments the right way
Previously we were reading the arguments in an incorrect order, and
placing the result in the wrong slot.
This also removes the hacky implementation of accumulative relaxed dot,
and just implements it directly as a new operator.
2025-12-12 19:12:53 +01:00
Rocco Corsi
c9e9208dca LibWasm: Make debug messages have unique wording 2025-12-12 19:12:19 +01:00
Rocco Corsi
bc77eb5869 LibWasm: Memory access out of bound debug enabled permanently 2025-12-12 01:26:30 +01:00
Ali Mohammad Pur
c8043dbb73 LibWasm: Disable direct threading entirely if musttail is not available
Otherwise we can end up crashing due to stack overflow (see #7009).
2025-12-08 02:22:13 +01:00
Ali Mohammad Pur
d99f663b1a LibWasm: Implement parsing/validation for proposal exception-handling
Actual execution traps for now.
2025-10-15 01:26:29 +02:00
Ali Mohammad Pur
d6f3f5fd51 LibWasm: Implement proposal 'relaxed-simd' 2025-10-15 01:26:29 +02:00
Ali Mohammad Pur
6a6f747701 LibWasm: Add support for proposal 'tail-call' 2025-10-15 01:26:29 +02:00
Ali Mohammad Pur
9ceb8052c8 LibWasm: Avoid revalidating memory/address for every element in memory.*
This also "fixes" the "address leak" detected by GCC (which is not
actually leaked to the tailcalled function).
2025-10-06 16:00:02 +02:00
Ali Mohammad Pur
31da9ab4e8 LibWasm: Take memory_fill arguments in the right order
This makes ruffle.rs work again :^)
2025-10-04 11:17:08 +02:00
Ali Mohammad Pur
353febfab6 LibWasm: Remove confusing newline after a few TAILCALLs 2025-10-04 11:17:08 +02:00
Ali Mohammad Pur
2397ae4af5 LibWasm: Use [[gnu::musttail]] on new-enough GCC versions
This is supported starting GCC 15.
The warning -Wmaybe-musttail-local-addr complained about &value possibly
escaping (it cannot, but gcc is being pessimistic about
store_to_memory), so a little rearrangement of that function was
necessary.
2025-10-01 23:47:29 +02:00
Ali Mohammad Pur
02b3c4f8a9 LibWasm: Utilise direct threading if/when possible
~50% performance improvement on coremark.
2025-10-01 23:47:29 +02:00
Ali Mohammad Pur
cf30d61d8b LibWasm: Use a faster way to detect live registers
Instead of doing a naive O(n^2) liveness detection loop, use a bitmap
for values allocated to registers.
This cuts down validating time from 20% to 1.4% of runtime on the same
game as last commit.
2025-10-01 23:47:29 +02:00
Pavel Shliak
a125bc97c4 LibWasm: Fix memory.fill ignoring memory index and unsafe bounds check
Previously, the memory.fill instruction always wrote to memory 0,
ignoring the selected memory index. This caused incorrect behavior
in multi-memory modules (e.g. filling mem0 instead of mem1).
Additionally, the bounds check used `destination_offset + count`
without overflow checking, which could wrap and bypass validation.

This patch:
- Passes `args.memory_index` into store_to_memory, so the correct
  memory is filled.
- Uses Checked<u32> for destination_offset + count, consistent
  with memory.copy and memory.init, to prevent overflow.

Minimal repro:

    (module
      (memory $m0 1)
      (memory $m1 1)

      (func (export "go") (result i32)
        ;; Fill mem1[0] with 0xAA
        i32.const 0
        i32.const 170
        i32.const 1
        memory.fill (memory 1)

        ;; Return (mem1[0] << 8) | mem0[0]
        i32.const 0
        i32.load8_u (memory 1)
        i32.const 8
        i32.shl
        i32.const 0
        i32.load8_u (memory 0)
        i32.or
      )
    )

Before fix: returns 170 (0x00AA).
After fix:  returns 43520 (0xAA00).
2025-09-06 08:51:11 +02:00
Ali Mohammad Pur
22448b0c35 LibWasm: Move the interpreter IP out of the configuration object
This, along with moving the sources and destination out of the config
object, makes it so we don't have to double-deref to get to them on each
instruction, leading to a ~15% perf improvement on dispatch.
2025-08-26 15:20:33 +02:00
Ali Mohammad Pur
f7bdc596b4 LibWasm: Avoid allocations for the label stack as much as possible
Namely, find an upper bound at validation time so we can allocate the
space when entering the frame.

Also drop labels at once instead of popping them off one at a time now
that we're using a Vector.
2025-08-26 15:20:33 +02:00
Ali Mohammad Pur
6732e1cdc3 LibWasm: Don't clobber registers on (most) calls
This still passes the values on the stack, but registers are now allowed
to cross a call boundary.
This is a very significant (>50%) improvement on the small call
microbenchmarks on my machine.
2025-08-26 15:20:33 +02:00
ayeteadoe
78a08bac82 LibWasm: Fix Windows build 2025-08-09 16:41:37 -06:00
Ali Mohammad Pur
b97ad99014 LibWasm: Remove unnecessary C-style casts
Or replace them with static-cast when necessary.
2025-08-08 12:54:06 +02:00
Ali Mohammad Pur
33cd5ae08c LibWasm: Fuse some very common instruction combos into specialised ops
Largely combinations of i32.const and local.get.
This shaves off at most single-digit% number of instructions from
dispatch, which translates to at most ~10% reduced dispatch time.

Across most benchmarks, this gains around ~5% perf increase.
2025-08-08 12:54:06 +02:00
Ali Mohammad Pur
0e5ecef848 LibWasm: Try really hard to avoid touching the value stack
This commit adds a register allocator, with 8 available "register"
slots.
In testing with various random blobs, this moves anywhere from 30% to
74% of value accesses into predefined slots, and is about a ~20% perf
increase end-to-end.

To actually make this usable, a few structural changes were also made:
- we no longer do one instruction per interpret call
- trapping is an (unlikely) exit condition
- the label and frame stacks are replaced with linked lists with a huge
  node cache size, as we only need to touch the last element and
  push/pop is very frequent.
2025-08-08 12:54:06 +02:00
Ali Mohammad Pur
bd7c188b86 LibWasm: Avoid memory copy in read_value<T>() if possible
If the address is already aligned properly, just read a T from it;
otherwise copy it to a local aligned array. This was a bottleneck on
memory-heavy benchmarks.
2025-08-08 12:54:06 +02:00
Ali Mohammad Pur
83995ada1f LibWasm: Quit early in memory_fill if store_to_memory traps
We shouldn't try to run the next 'instruction' if we trap.
Unbreaks the memory-fill test in wpt.
2025-05-22 07:35:58 +01:00
Ali Mohammad Pur
bfc1ebb2d4 LibWasm: Disable spammy 'memory access oob' debug prints 2025-05-22 07:35:58 +01:00
Ali Mohammad Pur
d79d5b70a5 LibWasm: Validate indirect calls at runtime
This is required by the spec, and also unbreaks all of the call-indirect
wpt tests.
2025-05-22 07:35:58 +01:00
Ali Mohammad Pur
39b637a446 LibWasm+LibWeb: Throw a js stack-overflow error if wasm stack overflows
Follows the spec.
2025-05-22 07:35:58 +01:00
Tim Ledbetter
58ffc56c38 LibWas: Unbreak compilation with WASM_TRACE_DEBUG enabled 2025-05-19 10:20:40 +01:00
Timothy Flynn
7280ed6312 Meta: Enforce newlines around namespaces
This has come up several times during code review, so let's just enforce
it using a new clang-format 20 option.
2025-05-14 02:01:59 -06:00
Ali Mohammad Pur
51bab5b186 LibWasm: Make traps hold on to externally-managed data
...instead of specially handling JS::Completion.
This makes it possible for LibWeb/LibJS to have full control over how
these things are made, stored, and visited (whenever).

Fixes an issue where we couldn't roundtrip a JS exception through Wasm.
2025-04-22 08:43:46 -06:00