From 976c3b6d16e04735d3bdbb01cbfbbc296ada1e23 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 16 Oct 2025 17:49:50 +0000 Subject: [PATCH] [SPLIT_MODULE] Support multi-split loading Currently, if the primary module name is `test.wasm` and when a placeholder function is called, the emscripten JS runtime loads `test.deferred.wasm`, which is hardcoded. But as we want emscripten to support multi-split, the runtime has to know which secondary module to load. Binaryen's #??? changes the placeholder import module naming scheme. Currently placeholder's import modules are all `placeholder`: https://github.com/WebAssembly/binaryen/blob/dcc704ce20e4723ae42012039bdb3b84ec2035f9/test/lit/wasm-split/multi-split.wast#L291-L295 But #???? will change this to the format of `placeholder.[secondaryName]`. Then Emscripten runtime will parse this module name to learn which secondary file to load. For example, if the import module is `placeholder.2` and the import base is `3` and the primary wasm file is `test.wasm`, ```wast (import "placeholder.2" "3" (func $placeholder_3 (result i32))) ``` when `placeholder_3` function is loaded, the runtime will parse `placeholder.2` and correctly figure out that it should load `test.2.wasm`. This PR still supports the old `placeholder` namespace, because this PR has to land first for ???? to land. After ???? lands, we can remove the `placeholder` handling part. Companion PR: --- src/preamble.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/preamble.js b/src/preamble.js index a8c91274d6e6c..66fb8d679ffd0 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -490,20 +490,25 @@ async function getWasmBinary(binaryFile) { var splitModuleProxyHandler = { get(target, moduleName, receiver) { if (moduleName.startsWith('placeholder')) { + let secondaryFile; + if (moduleName == 'placeholder') { // old format + secondaryFile = wasmBinaryFile.slice(0, -5) + '.deferred.wasm'; + } else { // new format + let moduleID = moduleName.split('.')[1]; + secondaryFile = wasmBinaryFile.slice(0, -5) + '.' + moduleID + '.wasm'; + } return new Proxy({}, { get(target, base, receiver) { return (...args) => { #if ASYNCIFY == 2 throw new Error('Placeholder function "' + base + '" should not be called when using JSPI.'); #else - // TODO: Implement multi-split module loading #if RUNTIME_DEBUG dbg(`placeholder function called: ${base}`); #endif var imports = {'primary': wasmExports}; // Replace '.wasm' suffix with '.deferred.wasm'. - var deferred = wasmBinaryFile.slice(0, -5) + '.deferred.wasm' - loadSplitModule(deferred, imports, base); + loadSplitModule(secondaryFile, imports, base); #if RUNTIME_DEBUG dbg('instantiated deferred module, continuing'); #endif