Skip to content

Conversation

EngoDev
Copy link

@EngoDev EngoDev commented Oct 7, 2025

The goal of this PR is to decrease the time it takes to compile a JS file into a WASM component.

AI disclaimer

I used AI in the creation of this PR. Specifically the Cursor composer (Claude-4.5-sonnet and GPT-5) for:

  • The serialization logic at: crates/spidermonkey-embedding-splicer/src/bin/splicer.rs
  • The splicer testing at: test/splicer.js
  • Modifying the Makefile
  • Extracting logic from src/componentize.js to src/splicer.js

TL;DR

The two optimizations I introduced are:

  1. Upping the version of wirm (previously known as orca_wasm) to the latest version and enabling the parallel feature.
  2. Giving the option to do bindings and WASI stubbing using the CLI version of spidermonkey-embedding-splicer to take advantage of the multi threading capabilities of wirm.

Research

I found that most of the time for compiling the JS code into WASM is being used in Module::parse (A wirm function) and the hot path for it is this code right here:

image

Module::parse is called multiple times during compilation and every time its called the code_sections creation takes about 95% of the run time for Module::parse which was around 350ms for me. As the great guys over at wirm already did fantastic work by giving the option to parallelize this code the only thing left to do was to enable the feature parallel but because WASM doesn't support multi threading yet just enabling the parallel feature for wirm doesn't do anything.

So to get around that I added a new option --splicer-bin that will use the spidermonkey-embedding-splicer CLI instead of the compiled WASM module so it can take advantage of multi threading and that made it possible to go from ~4.5s compilation time to ~750ms compilation time.

Performance Numbers

All testing took place on a Apple M4 Pro with 48GB of RAM.

I used a simple JS file for my testing:

export async function run(context) {
	return "Hello World!";
}

With a simple WIT world:

package test:entry;

world entry {
	export run: func(context: string) -> string;

	import wasi:random/random@0.2.7;
	import wasi:clocks/wall-clock@0.2.5;
}

Running jco on it took 4.5s on average.
image

Running componentize-js with the wirm up to date took 1.5s on average.
image

Running componentize-js with the wirm up to date and leveraging the CLI splicer for multithreading took 750ms on average.
image

Question

This PR right now doesn't have anything in the README on --splicer-bin, I wanted to know first what is the approach you would want to take regarding the packaging of the CLI splicer, right now it's not published and in the npm pacakge there is only the WASM module. I thought of two ways we can tackle user consumption but if you have another approach I'm happy to implement :)

  1. Add a section in the readme from beginning to end on how to use the --splicer-bin which will include compiling
  2. Add cross compiling for the major platforms in CI to compile the CLI tool and package that into the npm package as well.

@EngoDev EngoDev force-pushed the engodev/improve-compile-time branch from d84a746 to b99befd Compare October 7, 2025 16:21
@EngoDev EngoDev marked this pull request as ready for review October 7, 2025 16:21
@tschneidereit
Copy link
Member

Thank you for looking into this!

If I understand your results correctly, most of the improvement comes from updating wirm, cutting the time by 66%, right? If so, would you be up for splitting that change off into its own PR? That seems uncontroversial, so we could land it quickly.

The change to use parallelization and hence moving to a native build seems much more involved: we'd have to publish native versions for at least three, ideally four or five platforms, same as we already do for Wizer. That's not the end of the world for sure, but if we get most of the improvement without such an invasive change, we should consider not doing it.

This is in part because we're planning on completely changing how we do bindings generation for StarlingMonkey, by adopting the new wit-dylib tool. At that point, everything done to ComponentizeJS as it is right now will become moot, so I think we shouldn't stay away from involved changes.

@EngoDev
Copy link
Author

EngoDev commented Oct 7, 2025

Yeah that makes sense, I'll open another PR with only the wirm update.

I do think it's worth considering the CLI change as it does add a significant performance boost for little to no effort and it's an opt in feature so users aren't bothered with it.

@EngoDev
Copy link
Author

EngoDev commented Oct 7, 2025

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