| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent f64f5df commit 177ed3b
16 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -696,6 +696,74 @@ node --experimental-wasm-modules index.mjs | |||
| 696 | 696 | ||
| 697 | 697 | would provide the exports interface for the instantiation of `module.wasm`. | |
| 698 | 698 | ||
| 699 | + ### JavaScript String Builtins | ||
| 700 | + | ||
| 701 | + <!-- YAML | ||
| 702 | + added: REPLACEME | ||
| 703 | + --> | ||
| 704 | + | ||
| 705 | + When importing WebAssembly modules, the | ||
| 706 | + [WebAssembly JS String Builtins Proposal][] is automatically enabled through the | ||
| 707 | + ESM Integration. This allows WebAssembly modules to directly use efficient | ||
| 708 | + compile-time string builtins from the `wasm:js-string` namespace. | ||
| 709 | + | ||
| 710 | + For example, the following Wasm module exports a string `getLength` function using | ||
| 711 | + the `wasm:js-string` `length` builtin: | ||
| 712 | + | ||
| 713 | + ```text | ||
| 714 | + (module | ||
| 715 | + ;; Compile-time import of the string length builtin. | ||
| 716 | + (import "wasm:js-string" "length" (func $string_length (param externref) (result i32))) | ||
| 717 | + | ||
| 718 | + ;; Define getLength, taking a JS value parameter assumed to be a string, | ||
| 719 | + ;; calling string length on it and returning the result. | ||
| 720 | + (func $getLength (param $str externref) (result i32) | ||
| 721 | + local.get $str | ||
| 722 | + call $string_length | ||
| 723 | + ) | ||
| 724 | + | ||
| 725 | + ;; Export the getLength function. | ||
| 726 | + (export "getLength" (func $get_length)) | ||
| 727 | + ) | ||
| 728 | + ``` | ||
| 729 | + | ||
| 730 | + ```js | ||
| 731 | + import { getLength } from './string-len.wasm'; | ||
| 732 | + getLength('foo'); // Returns 3. | ||
| 733 | + ``` | ||
| 734 | + | ||
| 735 | + Wasm builtins are compile-time imports that are linked during module compilation | ||
| 736 | + rather than during instantiation. They do not behave like normal module graph | ||
| 737 | + imports and they cannot be inspected via `WebAssembly.Module.imports(mod)` | ||
| 738 | + or virtualized unless recompiling the module using the direct | ||
| 739 | + `WebAssembly.compile` API with string builtins disabled. | ||
| 740 | + | ||
| 741 | + Importing a module in the source phase before it has been instantiated will also | ||
| 742 | + use the compile-time builtins automatically: | ||
| 743 | + | ||
| 744 | + ```js | ||
| 745 | + import source mod from './string-len.wasm'; | ||
| 746 | + const { exports: { getLength } } = await WebAssembly.instantiate(mod, {}); | ||
| 747 | + getLength('foo'); // Also returns 3. | ||
| 748 | + ``` | ||
| 749 | + | ||
| 750 | + ### Reserved Wasm Namespaces | ||
| 751 | + | ||
| 752 | + <!-- YAML | ||
| 753 | + added: REPLACEME | ||
| 754 | + --> | ||
| 755 | + | ||
| 756 | + When importing WebAssembly modules through the ESM Integration, they cannot use | ||
| 757 | + import module names or import/export names that start with reserved prefixes: | ||
| 758 | + | ||
| 759 | + * `wasm-js:` - reserved in all module import names, module names and export | ||
| 760 | + names. | ||
| 761 | + * `wasm:` - reserved in module import names and export names (imported module | ||
| 762 | + names are allowed in order to support future builtin polyfills). | ||
| 763 | + | ||
| 764 | + Importing a module using the above reserved names will throw a | ||
| 765 | + `WebAssembly.LinkError`. | ||
| 766 | + | ||
| 699 | 767 | <i id="esm_experimental_top_level_await"></i> | |
| 700 | 768 | ||
| 701 | 769 | ## Top-level `await` | |
@@ -1134,6 +1202,7 @@ resolution for ESM specifiers is [commonjs-extension-resolution-loader][]. | |||
| 1134 | 1202 | [Node.js Module Resolution And Loading Algorithm]: #resolution-algorithm-specification | |
| 1135 | 1203 | [Terminology]: #terminology | |
| 1136 | 1204 | [URL]: https://url.spec.whatwg.org/ | |
| 1205 | + [WebAssembly JS String Builtins Proposal]: https://github.com/WebAssembly/js-string-builtins | ||
| 1137 | 1206 | [`"exports"`]: packages.md#exports | |
| 1138 | 1207 | [`"type"`]: packages.md#type | |
| 1139 | 1208 | [`--experimental-default-type`]: cli.md#--experimental-default-typetype | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -444,7 +444,9 @@ translators.set('wasm', async function(url, source) { | |||
| 444 | 444 | // TODO(joyeecheung): implement a translator that just uses | |
| 445 | 445 | // compiled = new WebAssembly.Module(source) to compile it | |
| 446 | 446 | // synchronously. | |
| 447 | - compiled = await WebAssembly.compile(source); | ||
| 447 | + compiled = await WebAssembly.compile(source, { | ||
| 448 | + builtins: ['js-string'], | ||
| 449 | + }); | ||
| 448 | 450 | } catch (err) { | |
| 449 | 451 | err.message = errPath(url) + ': ' + err.message; | |
| 450 | 452 | throw err; | |
@@ -456,6 +458,13 @@ translators.set('wasm', async function(url, source) { | |||
| 456 | 458 | if (impt.kind === 'global') { | |
| 457 | 459 | ArrayPrototypePush(wasmGlobalImports, impt); | |
| 458 | 460 | } | |
| 461 | + // Prefix reservations per https://webassembly.github.io/esm-integration/js-api/index.html#parse-a-webassembly-module. | ||
| 462 | + if (impt.module.startsWith('wasm-js:')) { | ||
| 463 | + throw new WebAssembly.LinkError(`Invalid Wasm import "${impt.module}" in ${url}`); | ||
| 464 | + } | ||
| 465 | + if (impt.name.startsWith('wasm:') || impt.name.startsWith('wasm-js:')) { | ||
| 466 | + throw new WebAssembly.LinkError(`Invalid Wasm import name "${impt.module}" in ${url}`); | ||
| 467 | + } | ||
| 459 | 468 | importsList.add(impt.module); | |
| 460 | 469 | } | |
| 461 | 470 | ||
@@ -465,6 +474,9 @@ translators.set('wasm', async function(url, source) { | |||
| 465 | 474 | if (expt.kind === 'global') { | |
| 466 | 475 | wasmGlobalExports.add(expt.name); | |
| 467 | 476 | } | |
| 477 | + if (expt.name.startsWith('wasm:') || expt.name.startsWith('wasm-js:')) { | ||
| 478 | + throw new WebAssembly.LinkError(`Invalid Wasm export name "${expt.name}" in ${url}`); | ||
| 479 | + } | ||
| 468 | 480 | exportsList.add(expt.name); | |
| 469 | 481 | } | |
| 470 | 482 | ||
@@ -487,6 +499,7 @@ translators.set('wasm', async function(url, source) { | |||
| 487 | 499 | reflect.imports[impt] = wrappedModule; | |
| 488 | 500 | } | |
| 489 | 501 | } | |
| 502 | + | ||
| 490 | 503 | // In cycles importing unexecuted Wasm, wasmInstance will be undefined, which will fail during | |
| 491 | 504 | // instantiation, since all bindings will be in the Temporal Deadzone (TDZ). | |
| 492 | 505 | const { exports } = new WebAssembly.Instance(compiled, reflect.imports); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -826,6 +826,11 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args, | |||
| 826 | 826 | env_opts->abort_on_uncaught_exception = true; | |
| 827 | 827 | } | |
| 828 | 828 | ||
| 829 | + // Support stable Phase 5 WebAssembly proposals | ||
| 830 | + v8_args.emplace_back("--experimental-wasm-imported-strings"); | ||
| 831 | + v8_args.emplace_back("--experimental-wasm-memory64"); | ||
| 832 | + v8_args.emplace_back("--experimental-wasm-exnref"); | ||
| 833 | + | ||
| 829 | 834 | #ifdef __POSIX__ | |
| 830 | 835 | // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the | |
| 831 | 836 | // performance penalty of frequent EINTR wakeups when the profiler is running. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -410,4 +410,95 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () => | |||
| 410 | 410 | strictEqual(stdout, ''); | |
| 411 | 411 | notStrictEqual(code, 0); | |
| 412 | 412 | }); | |
| 413 | + | ||
| 414 | + it('should reject wasm: import names', async () => { | ||
| 415 | + const { code, stderr, stdout } = await spawnPromisified(execPath, [ | ||
| 416 | + '--no-warnings', | ||
| 417 | + '--experimental-wasm-modules', | ||
| 418 | + '--input-type=module', | ||
| 419 | + '--eval', | ||
| 420 | + `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-name.wasm'))})`, | ||
| 421 | + ]); | ||
| 422 | + | ||
| 423 | + match(stderr, /Invalid Wasm import name/); | ||
| 424 | + strictEqual(stdout, ''); | ||
| 425 | + notStrictEqual(code, 0); | ||
| 426 | + }); | ||
| 427 | + | ||
| 428 | + it('should reject wasm-js: import names', async () => { | ||
| 429 | + const { code, stderr, stdout } = await spawnPromisified(execPath, [ | ||
| 430 | + '--no-warnings', | ||
| 431 | + '--experimental-wasm-modules', | ||
| 432 | + '--input-type=module', | ||
| 433 | + '--eval', | ||
| 434 | + `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-name-wasm-js.wasm'))})`, | ||
| 435 | + ]); | ||
| 436 | + | ||
| 437 | + match(stderr, /Invalid Wasm import name/); | ||
| 438 | + strictEqual(stdout, ''); | ||
| 439 | + notStrictEqual(code, 0); | ||
| 440 | + }); | ||
| 441 | + | ||
| 442 | + it('should reject wasm-js: import module names', async () => { | ||
| 443 | + const { code, stderr, stdout } = await spawnPromisified(execPath, [ | ||
| 444 | + '--no-warnings', | ||
| 445 | + '--experimental-wasm-modules', | ||
| 446 | + '--input-type=module', | ||
| 447 | + '--eval', | ||
| 448 | + `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-module.wasm'))})`, | ||
| 449 | + ]); | ||
| 450 | + | ||
| 451 | + match(stderr, /Invalid Wasm import/); | ||
| 452 | + strictEqual(stdout, ''); | ||
| 453 | + notStrictEqual(code, 0); | ||
| 454 | + }); | ||
| 455 | + | ||
| 456 | + it('should reject wasm: export names', async () => { | ||
| 457 | + const { code, stderr, stdout } = await spawnPromisified(execPath, [ | ||
| 458 | + '--no-warnings', | ||
| 459 | + '--experimental-wasm-modules', | ||
| 460 | + '--input-type=module', | ||
| 461 | + '--eval', | ||
| 462 | + `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-export-name.wasm'))})`, | ||
| 463 | + ]); | ||
| 464 | + | ||
| 465 | + match(stderr, /Invalid Wasm export/); | ||
| 466 | + strictEqual(stdout, ''); | ||
| 467 | + notStrictEqual(code, 0); | ||
| 468 | + }); | ||
| 469 | + | ||
| 470 | + it('should reject wasm-js: export names', async () => { | ||
| 471 | + const { code, stderr, stdout } = await spawnPromisified(execPath, [ | ||
| 472 | + '--no-warnings', | ||
| 473 | + '--experimental-wasm-modules', | ||
| 474 | + '--input-type=module', | ||
| 475 | + '--eval', | ||
| 476 | + `import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-export-name-wasm-js.wasm'))})`, | ||
| 477 | + ]); | ||
| 478 | + | ||
| 479 | + match(stderr, /Invalid Wasm export/); | ||
| 480 | + strictEqual(stdout, ''); | ||
| 481 | + notStrictEqual(code, 0); | ||
| 482 | + }); | ||
| 483 | + | ||
| 484 | + it('should support js-string builtins', async () => { | ||
| 485 | + const { code, stderr, stdout } = await spawnPromisified(execPath, [ | ||
| 486 | + '--no-warnings', | ||
| 487 | + '--experimental-wasm-modules', | ||
| 488 | + '--input-type=module', | ||
| 489 | + '--eval', | ||
| 490 | + [ | ||
| 491 | + 'import { strictEqual } from "node:assert";', | ||
| 492 | + `import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/js-string-builtins.wasm'))};`, | ||
| 493 | + 'strictEqual(wasmExports.getLength("hello"), 5);', | ||
| 494 | + 'strictEqual(wasmExports.concatStrings("hello", " world"), "hello world");', | ||
| 495 | + 'strictEqual(wasmExports.compareStrings("test", "test"), 1);', | ||
| 496 | + 'strictEqual(wasmExports.compareStrings("test", "different"), 0);', | ||
| 497 | + ].join('\n'), | ||
| 498 | + ]); | ||
| 499 | + | ||
| 500 | + strictEqual(stderr, ''); | ||
| 501 | + strictEqual(stdout, ''); | ||
| 502 | + strictEqual(code, 0); | ||
| 503 | + }); | ||
| 413 | 504 | }); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + ;; Test WASM module with invalid export name starting with 'wasm-js:' | ||
| 2 | + (module | ||
| 3 | + (func $test (result i32) | ||
| 4 | + i32.const 42 | ||
| 5 | + ) | ||
| 6 | + (export "wasm-js:invalid" (func $test)) | ||
| 7 | + ) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + ;; Test WASM module with invalid export name starting with 'wasm:' | ||
| 2 | + (module | ||
| 3 | + (func $test (result i32) | ||
| 4 | + i32.const 42 | ||
| 5 | + ) | ||
| 6 | + (export "wasm:invalid" (func $test)) | ||
| 7 | + ) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,8 @@ | |||
| 1 | + ;; Test WASM module with invalid import module name starting with 'wasm-js:' | ||
| 2 | + (module | ||
| 3 | + (import "wasm-js:invalid" "test" (func $invalidImport (result i32))) | ||
| 4 | + (export "test" (func $test)) | ||
| 5 | + (func $test (result i32) | ||
| 6 | + call $invalidImport | ||
| 7 | + ) | ||
| 8 | + ) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments