Add support for multiple `start` functions
Summary
This PR adds the ability to define multiple start functions in a wasm-bindgen project by introducing a new multiple-start feature flag.
Motivation
When building WebAssembly modules that need to initialize global (shared) registries at module startup, there's often a need to run multiple initialization functions before user code executes. For example, if you have multiple crates or modules that each need to register themselves into a global registry, each requires its own start function to populate that registry.
Previously, wasm-bindgen would error with "cannot specify two 'start' functions" when multiple start functions were detected. This limitation made it difficult to compose modules that each have their own initialization requirements.
Implementation
The solution introduces a StartFunctionsHandler struct that acts as a coordinator for multiple start functions:
-
Wrapper Function Creation: When the first start function is encountered, a wrapper function named
__wbindgen_start_wrapperis created. This wrapper becomes the "module's official" start function. -
Aggregating Start Functions: Each subsequent start function is appended to the wrapper function's body via a
callinstruction. This ensures all start functions are executed in the order they were discovered. -
Respecting Existing Transforms: The implementation preserves the existing behavior where start functions from thread/externref transforms run first (before user code), maintaining backward compatibility.
-
Cfg-Gated: The feature is opt-in via the
wasm_bindgen_allow_multiple_start_functionscfg flag to avoid any breaking changes for existing users.
Changes
-
crates/cli-support/src/wit/mod.rs: AddedStartFunctionsHandlerstruct and refactoredadd_start_function()to support multiple start functions when the cfg flag is enabled
CodSpeed Performance Report
Merging #4842 will not alter performance
Comparing JoakoI98:multiple-start-functions (bd82afc) with main (3ef6481)
Summary
✅ 4 untouched
I'm not sure how I feel about this - is it not possible to define a start function that simply calls the other start functions? What inhibits doing this at this level that you'd need something upstream here?