From 5ed537f03ea33df3516e530b55a5c1f0fc219e24 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 9 Feb 2024 01:33:58 +0900 Subject: [PATCH] feat(vm): support wasm module (#5131) --- eslint.config.js | 1 + .../vitest/src/runtime/external-executor.ts | 13 +- .../vitest/src/runtime/vm/esm-executor.ts | 19 ++- .../core/src/wasm-bindgen-no-cyclic/README.md | 15 +++ .../src/wasm-bindgen-no-cyclic/index.d.ts | 6 + test/core/src/wasm-bindgen-no-cyclic/index.js | 4 + .../src/wasm-bindgen-no-cyclic/index_bg.js | 117 ++++++++++++++++++ .../src/wasm-bindgen-no-cyclic/index_bg.wasm | Bin 0 -> 51231 bytes .../wasm-bindgen-no-cyclic/index_bg.wasm.d.ts | 6 + .../src/wasm-bindgen-no-cyclic/package.json | 20 +++ test/core/test/vm-wasm.test.ts | 13 +- test/core/vite.config.ts | 4 +- 12 files changed, 205 insertions(+), 13 deletions(-) create mode 100644 test/core/src/wasm-bindgen-no-cyclic/README.md create mode 100644 test/core/src/wasm-bindgen-no-cyclic/index.d.ts create mode 100644 test/core/src/wasm-bindgen-no-cyclic/index.js create mode 100644 test/core/src/wasm-bindgen-no-cyclic/index_bg.js create mode 100644 test/core/src/wasm-bindgen-no-cyclic/index_bg.wasm create mode 100644 test/core/src/wasm-bindgen-no-cyclic/index_bg.wasm.d.ts create mode 100644 test/core/src/wasm-bindgen-no-cyclic/package.json diff --git a/eslint.config.js b/eslint.config.js index 0525bdb0b49d..b08780dcc707 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,6 +11,7 @@ export default antfu( '**/bench.json', '**/fixtures', 'test/core/src/self', + 'test/core/src/wasm-bindgen-no-cyclic', 'test/workspaces/results.json', 'test/reporters/fixtures/with-syntax-error.test.js', 'test/network-imports/public/slash@3.0.0.js', diff --git a/packages/vitest/src/runtime/external-executor.ts b/packages/vitest/src/runtime/external-executor.ts index b08d5e93ec83..81aec41db0e9 100644 --- a/packages/vitest/src/runtime/external-executor.ts +++ b/packages/vitest/src/runtime/external-executor.ts @@ -27,7 +27,7 @@ export interface ExternalModulesExecutorOptions { } interface ModuleInformation { - type: 'data' | 'builtin' | 'vite' | 'module' | 'commonjs' + type: 'data' | 'builtin' | 'vite' | 'wasm' | 'module' | 'commonjs' url: string path: string } @@ -165,7 +165,7 @@ export class ExternalModulesExecutor { const pathUrl = isFileUrl ? fileURLToPath(identifier.split('?')[0]) : identifier const fileUrl = isFileUrl ? identifier : pathToFileURL(pathUrl).toString() - let type: 'module' | 'commonjs' | 'vite' + let type: 'module' | 'commonjs' | 'vite' | 'wasm' if (this.vite.canResolve(fileUrl)) { type = 'vite' } @@ -175,6 +175,11 @@ export class ExternalModulesExecutor { else if (extension === '.cjs') { type = 'commonjs' } + else if (extension === '.wasm') { + // still experimental on NodeJS --experimental-wasm-modules + // cf. ESM_FILE_FORMAT(url) in https://nodejs.org/docs/latest-v20.x/api/esm.html#resolution-algorithm + type = 'wasm' + } else { const pkgData = this.findNearestPackageData(normalize(pathUrl)) type = pkgData.type === 'module' ? 'module' : 'commonjs' @@ -188,7 +193,7 @@ export class ExternalModulesExecutor { // create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path // https://github.com/nodejs/node/pull/49038 - if ((type === 'module' || type === 'commonjs') && !existsSync(path)) { + if ((type === 'module' || type === 'commonjs' || type === 'wasm') && !existsSync(path)) { const error = new Error(`Cannot find module '${path}'`) ;(error as any).code = 'ERR_MODULE_NOT_FOUND' throw error @@ -203,6 +208,8 @@ export class ExternalModulesExecutor { } case 'vite': return await this.vite.createViteModule(url) + case 'wasm': + return await this.esm.createWebAssemblyModule(url, this.fs.readBuffer(path)) case 'module': return await this.esm.createEsModule(url, this.fs.readFile(path)) case 'commonjs': { diff --git a/packages/vitest/src/runtime/vm/esm-executor.ts b/packages/vitest/src/runtime/vm/esm-executor.ts index 575987962fe7..cd429aa538e1 100644 --- a/packages/vitest/src/runtime/vm/esm-executor.ts +++ b/packages/vitest/src/runtime/vm/esm-executor.ts @@ -77,6 +77,15 @@ export class EsmExecutor { return m } + public async createWebAssemblyModule(fileUrl: string, code: Buffer) { + const cached = this.moduleCache.get(fileUrl) + if (cached) + return cached + const m = this.loadWebAssemblyModule(code, fileUrl) + this.moduleCache.set(fileUrl, m) + return m + } + public async loadWebAssemblyModule(source: Buffer, identifier: string) { const cached = this.moduleCache.get(identifier) if (cached) @@ -90,23 +99,21 @@ export class EsmExecutor { const moduleLookup: Record = {} for (const { module } of imports) { if (moduleLookup[module] === undefined) { - const resolvedModule = await this.executor.resolveModule( + moduleLookup[module] = await this.executor.resolveModule( module, identifier, ) - - moduleLookup[module] = await this.evaluateModule(resolvedModule) } } const syntheticModule = new SyntheticModule( exports.map(({ name }) => name), - () => { + async () => { const importsObject: WebAssembly.Imports = {} for (const { module, name } of imports) { if (!importsObject[module]) importsObject[module] = {} - + await this.evaluateModule(moduleLookup[module]) importsObject[module][name] = (moduleLookup[module].namespace as any)[name] } const wasmInstance = new WebAssembly.Instance( @@ -150,7 +157,7 @@ export class EsmExecutor { if (encoding !== 'base64') throw new Error(`Invalid data URI encoding: ${encoding}`) - const module = await this.loadWebAssemblyModule( + const module = this.loadWebAssemblyModule( Buffer.from(match.groups.code, 'base64'), identifier, ) diff --git a/test/core/src/wasm-bindgen-no-cyclic/README.md b/test/core/src/wasm-bindgen-no-cyclic/README.md new file mode 100644 index 000000000000..8e1f4d10811a --- /dev/null +++ b/test/core/src/wasm-bindgen-no-cyclic/README.md @@ -0,0 +1,15 @@ +The recent version of the wasm-bindgen bundler output does not use cyclic imports between wasm and js. + +For this non-cyclic version to work, both `index_bg.js` and `index_bg.wasm` need to be externalized +since otherwise a dual package hazard on `index_bg.js` would make it non-functional. + +The code is copied from https://github.com/rustwasm/wasm-bindgen/tree/8198d2d25920e1f4fc593e9f8eb9d199e004d731/examples/hello_world + +```sh +npm i +npm run build +# then +# 1. copy `examples/hello_world/pkg` to this directory +# 2. add { "type": "module" } to `package.json` +# (this will be automatically included after https://github.com/rustwasm/wasm-pack/pull/1061) +``` diff --git a/test/core/src/wasm-bindgen-no-cyclic/index.d.ts b/test/core/src/wasm-bindgen-no-cyclic/index.d.ts new file mode 100644 index 000000000000..4215d5c07f43 --- /dev/null +++ b/test/core/src/wasm-bindgen-no-cyclic/index.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +* @param {string} name +*/ +export function greet(name: string): void; diff --git a/test/core/src/wasm-bindgen-no-cyclic/index.js b/test/core/src/wasm-bindgen-no-cyclic/index.js new file mode 100644 index 000000000000..7d5064881780 --- /dev/null +++ b/test/core/src/wasm-bindgen-no-cyclic/index.js @@ -0,0 +1,4 @@ +import * as wasm from "./index_bg.wasm"; +import { __wbg_set_wasm } from "./index_bg.js"; +__wbg_set_wasm(wasm); +export * from "./index_bg.js"; diff --git a/test/core/src/wasm-bindgen-no-cyclic/index_bg.js b/test/core/src/wasm-bindgen-no-cyclic/index_bg.js new file mode 100644 index 000000000000..581941a2e2dc --- /dev/null +++ b/test/core/src/wasm-bindgen-no-cyclic/index_bg.js @@ -0,0 +1,117 @@ +let wasm; +export function __wbg_set_wasm(val) { + wasm = val; +} + + +const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder; + +let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + +cachedTextDecoder.decode(); + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +function logError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + let error = (function () { + try { + return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString(); + } catch(_) { + return ""; + } + }()); + console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error); + throw e; + } +} + +let WASM_VECTOR_LEN = 0; + +const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder; + +let cachedTextEncoder = new lTextEncoder('utf-8'); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +} + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; +}); + +function passStringToWasm0(arg, malloc, realloc) { + + if (typeof(arg) !== 'string') throw new Error('expected a string argument'); + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + if (ret.read !== arg.length) throw new Error('failed to pass whole string'); + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} +/** +* @param {string} name +*/ +export function greet(name) { + const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len0 = WASM_VECTOR_LEN; + wasm.greet(ptr0, len0); +} + +export function __wbg_alert_9ea5a791b0d4c7a3() { return logError(function (arg0, arg1) { + alert(getStringFromWasm0(arg0, arg1)); +}, arguments) }; + +export function __wbindgen_throw(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); +}; + diff --git a/test/core/src/wasm-bindgen-no-cyclic/index_bg.wasm b/test/core/src/wasm-bindgen-no-cyclic/index_bg.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a1ea0e0591fc7e318b88ac90a2beda39d16ff0c4 GIT binary patch literal 51231 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 { expect(add(1, 2)).toBe(3) @@ -54,7 +54,7 @@ test('imports from "data:application/wasm" URI with invalid encoding fail', asyn ).rejects.toThrow('Invalid data URI encoding: charset=utf-8') }) -test('supports wasm files that import js resources (wasm-bindgen)', async () => { +test('supports wasm/js cyclic import (old wasm-bindgen output)', async () => { globalThis.alert = vi.fn() // @ts-expect-error not typed @@ -63,3 +63,12 @@ test('supports wasm files that import js resources (wasm-bindgen)', async () => expect(globalThis.alert).toHaveBeenCalledWith('Hello, World!') }) + +test('supports wasm-bindgen', async () => { + globalThis.alert = vi.fn() + + const { greet } = await import('../src/wasm-bindgen-no-cyclic/index.js') + greet('No Cyclic') + + expect(globalThis.alert).toHaveBeenCalledWith('Hello, No Cyclic!') +}) diff --git a/test/core/vite.config.ts b/test/core/vite.config.ts index f4e13ad7ad24..ed7efb47b955 100644 --- a/test/core/vite.config.ts +++ b/test/core/vite.config.ts @@ -45,7 +45,7 @@ export default defineConfig({ }, test: { name: 'core', - exclude: ['**/fixtures/**', '**/vm-wasm.test.ts', ...defaultExclude], + exclude: ['**/fixtures/**', ...defaultExclude], slowTestThreshold: 1000, testTimeout: 2000, setupFiles: [ @@ -75,7 +75,7 @@ export default defineConfig({ }, server: { deps: { - external: ['tinyspy', /src\/external/, /esm\/esm/, /\.wasm$/], + external: ['tinyspy', /src\/external/, /esm\/esm/, /\.wasm$/, /\/wasm-bindgen-no-cyclic\/index_bg/], inline: ['inline-lib'], }, },