Skip to content

wasm2c: Save memory base locally as a perf optimization - #2804

Open
shravanrn wants to merge 2 commits into
WebAssembly:mainfrom
UT-Security:local-base
Open

wasm2c: Save memory base locally as a perf optimization#2804
shravanrn wants to merge 2 commits into
WebAssembly:mainfrom
UT-Security:local-base

Conversation

@shravanrn

@shravanrn shravanrn commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

For Wasm modules with a single unshared wasm-32 memory, and when using the MMap based memory allocation (which guarantees that the base won't move over the Wasm instance lifetime), this change caches the memory base in a local variable and uses that instead of fetching the value each time from the instance pointer.

While this seems like it really shouldn't do much, it unlocks a bunch of optimizations in C compilers, as they don't seem to be able to reason that the base pointer hasn't changed after most function calls with the Wasm code. The end result is some dramatic improvements.

As a reference, this approach is able to claw back a lot of the same performance overheads of segue (i.e., using the segment register) in wasm2c except without segment registers, meaning this will work on all platforms. This makes some intuitive sense, as I expect that segue is more important to classic SFI tools (like LFI) rather than a Wasm like system. (But there are other benchmarks that segue still is a huge win --- on average, segue still remains the best option if supported on the target platform)

Here are the performance numbers from two use cases in Firefox: Expat XML parsing, Graphite font rendering that use Wasm sandboxes. The number is the overhead over native code (so bigger is worse)

Note the "local base" row is the new row below

Expat XML parsing overhead

Baseline: native

Wasm2c (Mmap + guard pages, no segue): +37.6%
Wasm2c (Mmap + guard pages, segue): +13.7%
Wasm2c (Mmap + guard pages, local base): +18.7%

Wasm2c (Mmap + bounds checks, no segue): +50.7%
Wasm2c (Mmap + bounds checks, segue): +37.4%
Wasm2c (Mmap + bounds checks, local base): +32.8%

Graphite font overhead

Baseline: native

Wasm2c (Mmap + guard pages, no segue): +41.2%
Wasm2c (Mmap + guard pages, segue): +18.2%
Wasm2c (Mmap + guard pages, local base): +14.1%

Wasm2c (Mmap + bounds checks, no segue): +60.0%
Wasm2c (Mmap + bounds checks, segue): +43.3%
Wasm2c (Mmap + bounds checks, local base): +41.8%

I intend to enable this optimization in Firefox's builds asap once it is landed here.

@sbc100

sbc100 commented Aug 3, 2026

Copy link
Copy Markdown
Member

Can you update the PR description now that part 1 has landed?

@shravanrn

shravanrn commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Did some cleanup to simplify the code and reduce the code-diff and updated the PR description.

@sbc100

sbc100 commented Aug 3, 2026

Copy link
Copy Markdown
Member

In your benchmark results I guess +37.6% means 37% overhead compared to native? i.e. bigger is worse?

Comment thread src/template/wasm2c.declarations.c
@shravanrn
shravanrn requested a review from sbc100 August 7, 2026 19:20
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