Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions docs/content/limitations/webassembly-modules.mdx
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
scriptc translates WebAssembly modules to native code when it builds the program; there is no interpreter or JIT in the executable.
A build translates every module whose bytes it can see: files at paths the compiler resolves (`require.resolve`, `createRequire(...).resolve`, `import.meta.resolve`, `new URL("./x.wasm", import.meta.url)`, `path.join(__dirname, ...)`), modules inlined as base64 or byte-array literals, `.wasm` files shipped by packages whose code uses WebAssembly, and files listed in a `scriptc.wasm` array in `package.json`.
A build translates every module whose bytes it can see: files at paths the compiler resolves (`require.resolve`, `createRequire(...).resolve`, `import.meta.resolve`, `new URL("./x.wasm", import.meta.url)`, `path.join(__dirname, ...)`), including `.so` WebAssembly shared libraries such as quickjs-wasi's extensions, modules inlined as base64 or byte-array literals, `.wasm` files shipped by packages whose code uses WebAssembly, and files listed in a `scriptc.wasm` array in `package.json`.
At run time `WebAssembly.compile`, `instantiate`, `validate` and `new WebAssembly.Module` find the translated module by the SHA-256 of the bytes they are given.
Bytes the build did not see, including bytes produced at run time, reject with a `CompileError` that says the module was not translated, and `WebAssembly.validate` answers `false` for them.
`scriptc coverage` lists the modules a build finds, with their size, whether they validate, and the WebAssembly proposals they use.

Translated modules can use the WebAssembly 2.0 feature set: the MVP plus sign-extension operators, non-trapping float-to-int conversions, bulk memory, multi-value, mutable globals, reference types, and extended constant expressions.
Modules that use SIMD, threads, exception handling, tail calls, typed function references or GC, memory64, or multiple memories are not translated, so loading them rejects with the `CompileError` above; packages that fall back to a scalar build when that happens, such as undici and es-module-lexer, take their fallback.

Supported: `WebAssembly.compile`, `instantiate` (with bytes or a `Module`), `validate`, `new WebAssembly.Module`, `new WebAssembly.Instance`, and `instanceof` for every class; the error classes `CompileError`, `LinkError` and `RuntimeError`, constructed with or without `new`; `globalThis.WebAssembly` and its `compile`, `instantiate` and `validate` functions as values.
Instances expose exported functions, memories (`buffer`, `grow`), tables (`get`, `set`, `grow`, `length`) and globals (`value`).
Imports can be functions, numbers or BigInts for immutable globals, and memories, tables and globals exported by other instances.
Supported: `WebAssembly.compile`, `instantiate` (with bytes or a `Module`), `validate`, `new WebAssembly.Module`, `new WebAssembly.Instance`, `new WebAssembly.Memory`, `new WebAssembly.Table`, `new WebAssembly.Global`, `WebAssembly.Module.imports`, `exports` and `customSections`, and `instanceof` for every class; the error classes `CompileError`, `LinkError` and `RuntimeError`, constructed with or without `new`; `globalThis.WebAssembly` and its `compile`, `instantiate` and `validate` functions as values.
Instances expose exported functions, memories (`buffer`, `grow`), tables (`get`, `set`, `grow`, `length`) and globals (`value`, `valueOf`).
Imports can be functions, numbers or BigInts for immutable globals, and memories, tables and globals that the program constructs or other instances export; their limits, types and mutability are checked with Node.js's `LinkError` messages.
Function references from a table or global reach JavaScript as callable functions, and exported functions can be stored in tables and globals, which is what dynamic linkers such as quickjs-wasi's extension loader do.
Traps throw `WebAssembly.RuntimeError` with Node.js's messages, unbounded recursion throws `RangeError`, and an exception thrown by an imported function propagates through the WebAssembly frames unchanged.
A `WebAssembly.Module` can be sent to a worker through `workerData` or `postMessage`.

Not supported yet: the `Memory`, `Table`, `Global`, `Tag` and `Exception` constructors, `WebAssembly.Module.imports`, `exports` and `customSections`, `compileStreaming` and `instantiateStreaming`, and the classes used as values other than with `new` and `instanceof`.
Not supported yet: the `Tag` and `Exception` constructors, shared memories (`new WebAssembly.Memory({ shared: true, ... })` throws a `TypeError`), `compileStreaming` and `instantiateStreaming`, and the classes used as values other than with `new`, `instanceof` and `WebAssembly.Module`'s static functions.
TypeScript sources fail to build with SC2020 at each such use, and JavaScript sources throw that diagnostic when the statement runs.
Programs built for `wasm32-wasi` can't use the WebAssembly API.

Differences from Node.js:

- `Memory.prototype.grow` does not detach the previous `ArrayBuffer`.
The memory never moves, so views created before the growth stay valid but keep their old length.
- Growing a memory, from JavaScript or inside the module, does not detach the previous `ArrayBuffer`.
The memory never moves, so views created before the growth stay valid but keep their old length; code that reads `memory.buffer` again after growing, as WebAssembly glue code does, behaves as in Node.js.
- `valueOf()` answers a `WebAssembly.Global`'s value only when the receiver's static type is `WebAssembly.Global`; through an untyped value it answers the object, and converting a `Global` to a primitive uses the object rather than its value.
- Instances are never freed, together with their memories, imports and exports.
- A function reference (`funcref`) can reach JavaScript only as a function the module exports; other function references throw a `TypeError`.
- A load whose result the module never uses may be removed instead of trapping when its address is out of bounds.
Loads whose result is dropped explicitly still trap.
- NaN payloads may differ, for example when a signaling NaN passes through arithmetic or a JavaScript number.
Expand Down
6 changes: 5 additions & 1 deletion internal/compatibility/generated/node-v24-backlog.json
Original file line number Diff line number Diff line change
Expand Up @@ -34248,7 +34248,11 @@
"tests/corpus/webassembly-spec-float/main.mjs",
"tests/corpus/webassembly-spec-control/main.mjs",
"tests/corpus/webassembly-spec-memory/main.mjs",
"tests/corpus/webassembly-spec-table/main.mjs"
"tests/corpus/webassembly-spec-table/main.mjs",
"tests/corpus/webassembly-spec-imports/main.mjs",
"tests/corpus/webassembly-jsapi.mjs",
"tests/corpus/webassembly-wpt-jsapi.mjs",
"tests/corpus/webassembly-dylink/main.mjs"
]
}
}
Expand Down
10 changes: 9 additions & 1 deletion internal/compatibility/generated/node-v24-internal.json
Original file line number Diff line number Diff line change
Expand Up @@ -52299,13 +52299,17 @@
"tests/corpus/6331-jose-root-entry/main.ts",
"tests/corpus/text-codec-values/main.ts",
"tests/corpus/webassembly-api.mjs",
"tests/corpus/webassembly-dylink/main.mjs",
"tests/corpus/webassembly-jsapi.mjs",
"tests/corpus/webassembly-spec-control/main.mjs",
"tests/corpus/webassembly-spec-float/main.mjs",
"tests/corpus/webassembly-spec-imports/main.mjs",
"tests/corpus/webassembly-spec-int/main.mjs",
"tests/corpus/webassembly-spec-memory/main.mjs",
"tests/corpus/webassembly-spec-table/main.mjs",
"tests/corpus/webassembly-typed.ts",
"tests/corpus/webassembly-worker.ts",
"tests/corpus/webassembly-wpt-jsapi.mjs",
"tests/fixtures/node-types/navigator.ts",
"tests/harness/fetch-conformance.test.ts",
"tests/harness/project-config.test.ts"
Expand Down Expand Up @@ -53667,7 +53671,11 @@
"tests/corpus/webassembly-spec-float/main.mjs",
"tests/corpus/webassembly-spec-control/main.mjs",
"tests/corpus/webassembly-spec-memory/main.mjs",
"tests/corpus/webassembly-spec-table/main.mjs"
"tests/corpus/webassembly-spec-table/main.mjs",
"tests/corpus/webassembly-spec-imports/main.mjs",
"tests/corpus/webassembly-jsapi.mjs",
"tests/corpus/webassembly-wpt-jsapi.mjs",
"tests/corpus/webassembly-dylink/main.mjs"
]
},
"anchorSource": "exact"
Expand Down
2 changes: 1 addition & 1 deletion internal/compatibility/static-support.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"webstreams": "unreviewed"
},
"evidenceByManifestPrefix": {
"stdlib.webassembly": ["tests/corpus/webassembly-api.mjs", "tests/corpus/webassembly-typed.ts", "tests/corpus/webassembly-worker.ts", "tests/corpus/webassembly-spec-int/main.mjs", "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", "tests/corpus/webassembly-spec-table/main.mjs"],
"stdlib.webassembly": ["tests/corpus/webassembly-api.mjs", "tests/corpus/webassembly-typed.ts", "tests/corpus/webassembly-worker.ts", "tests/corpus/webassembly-spec-int/main.mjs", "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", "tests/corpus/webassembly-spec-table/main.mjs", "tests/corpus/webassembly-spec-imports/main.mjs", "tests/corpus/webassembly-jsapi.mjs", "tests/corpus/webassembly-wpt-jsapi.mjs", "tests/corpus/webassembly-dylink/main.mjs"],
"node-builtin.fs.readFileSync": ["tests/corpus/1403-buffer-fs.ts", "tests/corpus/2595-fs-arg-ladders.cjs", "tests/corpus/2919-fs-function-values.ts", "tests/corpus/2920-fs-promises-function-values.ts", "tests/corpus/fs-read-encodings.ts"],
"syntax.using-declarations": ["tests/corpus/2841-using-sync.ts"],
"syntax.await-using-declarations": ["tests/corpus/2842-await-using.ts"],
Expand Down
8 changes: 8 additions & 0 deletions packages/compiler/src/backend/llvm/lib-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,14 @@ export const LIB_FN_SYMS: Record<string, string> = {
"wasm.instanceNew": "scr_wasm_instance_new",
"wasm.is": "scr_wasm_is",
"wasm.errorNew": "scr_wasm_error_new",
"wasm.memoryNew": "scr_wasm_memory_construct",
"wasm.tableNew": "scr_wasm_table_construct",
"wasm.globalNew": "scr_wasm_global_construct",
"wasm.withoutNew": "scr_wasm_construct_without_new",
"wasm.moduleImports": "scr_wasm_module_imports",
"wasm.moduleExports": "scr_wasm_module_exports",
"wasm.moduleCustomSections": "scr_wasm_module_custom_sections",
"wasm.valueOf": "scr_wasm_value_of",
"wasm.function": "scr_wasm_function",
"wasm.namespace": "scr_wasm_namespace",
"wasm.globalView": "scr_wasm_global_view",
Expand Down
5 changes: 4 additions & 1 deletion packages/compiler/src/backend/llvm/wasm-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ export function emitWasmModules(
if (bytes === null) continue;
let translation;
try {
translation = translateWasmModule(bytes, hexBytes(module.sha256), { boundsChecks });
translation = translateWasmModule(bytes, hexBytes(module.sha256), {
boundsChecks,
customSections: mod.wasmCustomSections === true,
});
} catch (error) {
if (error instanceof WasmTranslateError) continue;
throw error;
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/coverage/surface-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
kind: "stdlib",
name: "globalThis.WebAssembly",
status: "static",
note: `compile, instantiate, validate, Module, Instance, instanceof, the error classes, exports, memories, tables, globals and Module transfer to workers, over the modules translated at build time; the rest refuses with ${refusal.code} (${refusal.hint ?? ""})`,
note: `compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, instanceof, the error classes, exports, imports and Module transfer to workers, over the modules translated at build time; the rest refuses with ${refusal.code} (${refusal.hint ?? ""})`,
});
}

Expand Down
15 changes: 8 additions & 7 deletions packages/compiler/src/diagnostics/diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -741,18 +741,19 @@ export function noLoweringDiag(
}

/** A REACHED use of a part of the WebAssembly API scriptc does not
* implement yet (SC2020): the Memory, Table and Global constructors,
* Module.imports/exports/customSections, the streaming functions, the
* classes as values. compile, instantiate, validate, Module, Instance and
* the error classes lower (builtins/webassembly.ts). `surface` names what
* was used ('new WebAssembly.Memory', 'WebAssembly.Module.imports'). */
* implement yet (SC2020): the streaming functions, Tag and Exception, the
* classes as values. compile, instantiate, validate, the Module, Instance,
* Memory, Table and Global constructors, Module.imports/exports/
* customSections and the error classes lower (builtins/webassembly.ts).
* `surface` names what was used ('WebAssembly.compileStreaming',
* 'WebAssembly.Memory'). */
export function webAssemblyDiag(surface: string, loc: SrcLoc): ScrDiagnostic {
return {
code: "SC2020",
message: `'${surface}' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API`,
message: `'${surface}' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, and the error classes over modules translated at build time, but not this part of the API`,
loc,
milestone: "later",
hint: "the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations)",
hint: "the streaming functions, Tag and Exception, and the classes used as values other than with new and instanceof are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations)",
};
}

Expand Down
Loading
Loading