wasm-bindgen-lite 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -0
- package/LICENSE +1 -0
- package/package.json +3 -2
- package/scripts/build.js +1 -1
- package/scripts/test-examples.sh +1 -0
- package/src/cli/build.js +26 -20
- package/src/cli/config.js +70 -79
- package/src/cli/emit.js +408 -271
- package/src/cli/index.js +0 -1
- package/src/cli/pkg.js +1 -7
- package/src/js/util.js +1 -1
package/Cargo.toml
CHANGED
package/LICENSE
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wasm-bindgen-lite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI tool to build Rust crates into minimal, SIMD-optimized WASM packages with JS loaders",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"build": "node bin/wasm-bindgen-lite.js build --crate . --out dist --no-update-package-json",
|
|
32
|
-
"test": "cargo test && node scripts/test.js",
|
|
32
|
+
"test": "npm run test:unit && cargo test && node scripts/test.js",
|
|
33
|
+
"test:unit": "node --test test/*.test.js",
|
|
33
34
|
"test:examples": "./scripts/test-examples.sh",
|
|
34
35
|
"lint": "npm run lint:js && npm run lint:rust",
|
|
35
36
|
"lint:js": "eslint . && prettier --check .",
|
package/scripts/build.js
CHANGED
package/scripts/test-examples.sh
CHANGED
package/src/cli/build.js
CHANGED
|
@@ -2,6 +2,15 @@ import { execSync } from 'node:child_process'
|
|
|
2
2
|
import { copyFileSync, mkdirSync } from 'node:fs'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
|
|
5
|
+
function exec(cmd, options = {}) {
|
|
6
|
+
try {
|
|
7
|
+
execSync(cmd, { stdio: 'inherit', ...options })
|
|
8
|
+
} catch {
|
|
9
|
+
console.error(`\nError: Command failed: ${cmd}`)
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
5
14
|
function runCargoBuild({ crateDir, release, simd }) {
|
|
6
15
|
const args = ['build', '--target', 'wasm32-unknown-unknown']
|
|
7
16
|
if (release) args.push('--release')
|
|
@@ -13,9 +22,8 @@ function runCargoBuild({ crateDir, release, simd }) {
|
|
|
13
22
|
env.RUSTFLAGS = [base, extra].filter(Boolean).join(' ').trim()
|
|
14
23
|
}
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
exec(`cargo ${args.join(' ')}`, {
|
|
17
26
|
cwd: crateDir,
|
|
18
|
-
stdio: 'inherit',
|
|
19
27
|
env,
|
|
20
28
|
})
|
|
21
29
|
}
|
|
@@ -42,7 +50,7 @@ function maybeRunWasmOpt(wasmFile, wasmOpt) {
|
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
const args = ['wasm-opt', ...wasmOpt.args, wasmFile, '-o', wasmFile]
|
|
45
|
-
|
|
53
|
+
exec(args.join(' '))
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
export function buildArtifacts({
|
|
@@ -58,26 +66,24 @@ export function buildArtifacts({
|
|
|
58
66
|
const wasmOutDir = join(outDir, 'wasm')
|
|
59
67
|
mkdirSync(wasmOutDir, { recursive: true })
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
let simdPath = null
|
|
69
|
+
const paths = { baselinePath: null, simdPath: null, wasmOutDir }
|
|
63
70
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
copyFileSync(built, baselinePath)
|
|
70
|
-
maybeRunWasmOpt(baselinePath, wasmOpt)
|
|
71
|
-
}
|
|
71
|
+
const build = (isSimd, suffix) => {
|
|
72
|
+
const label = isSimd ? 'SIMD' : 'baseline'
|
|
73
|
+
console.log(`Building ${label} wasm...`)
|
|
74
|
+
|
|
75
|
+
runCargoBuild({ crateDir, release, simd: isSimd })
|
|
72
76
|
|
|
73
|
-
if (targets.simd) {
|
|
74
|
-
console.log('Building SIMD wasm...')
|
|
75
|
-
runCargoBuild({ crateDir, release, simd: true })
|
|
76
77
|
const built = wasmPath({ crateDir, release, wasmFileStem })
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
const dest = join(wasmOutDir, `${artifactBaseName}.${suffix}.wasm`)
|
|
79
|
+
|
|
80
|
+
copyFileSync(built, dest)
|
|
81
|
+
maybeRunWasmOpt(dest, wasmOpt)
|
|
82
|
+
return dest
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
if (targets.baseline) paths.baselinePath = build(false, 'base')
|
|
86
|
+
if (targets.simd) paths.simdPath = build(true, 'simd')
|
|
87
|
+
|
|
88
|
+
return paths
|
|
83
89
|
}
|
package/src/cli/config.js
CHANGED
|
@@ -104,90 +104,81 @@ export function loadConfigFromCli(cliOpts = {}) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
const crateName = readCrateName(crateDir)
|
|
107
|
-
const artifactBaseName =
|
|
108
|
-
cliOpts.artifactBaseName ??
|
|
109
|
-
fileConfig.artifactBaseName ??
|
|
110
|
-
DEFAULT_CONFIG.artifactBaseName
|
|
111
|
-
|
|
112
|
-
const outDir = resolve(
|
|
113
|
-
crateDir,
|
|
114
|
-
cliOpts.out ?? fileConfig.outDir ?? DEFAULT_CONFIG.outDir
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
const release =
|
|
118
|
-
typeof cliOpts.release === 'boolean'
|
|
119
|
-
? cliOpts.release
|
|
120
|
-
: (fileConfig.release ?? DEFAULT_CONFIG.release)
|
|
121
|
-
|
|
122
|
-
const targets = {
|
|
123
|
-
baseline:
|
|
124
|
-
cliOpts.baseline ??
|
|
125
|
-
fileConfig.targets?.baseline ??
|
|
126
|
-
DEFAULT_CONFIG.targets.baseline,
|
|
127
|
-
simd:
|
|
128
|
-
typeof cliOpts.simd === 'boolean'
|
|
129
|
-
? cliOpts.simd
|
|
130
|
-
: (fileConfig.targets?.simd ?? DEFAULT_CONFIG.targets.simd),
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const inline =
|
|
134
|
-
typeof cliOpts.inline === 'boolean'
|
|
135
|
-
? cliOpts.inline
|
|
136
|
-
: (fileConfig.inline ?? DEFAULT_CONFIG.inline)
|
|
137
|
-
|
|
138
|
-
const wasmOpt = normalizeWasmOpt(
|
|
139
|
-
cliOpts.wasmOptMode
|
|
140
|
-
? { mode: cliOpts.wasmOptMode, args: cliOpts.wasmOptArgs }
|
|
141
|
-
: (fileConfig.wasmOpt ?? DEFAULT_CONFIG.wasmOpt)
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
const jsEmit = normalizeEmit(fileConfig.js?.emit ?? DEFAULT_CONFIG.js.emit)
|
|
145
|
-
const jsCustom = fileConfig.js?.custom ?? DEFAULT_CONFIG.js.custom
|
|
146
|
-
|
|
147
|
-
const exportsList =
|
|
148
|
-
fileConfig.exports &&
|
|
149
|
-
Array.isArray(fileConfig.exports) &&
|
|
150
|
-
fileConfig.exports.length
|
|
151
|
-
? fileConfig.exports
|
|
152
|
-
: DEFAULT_CONFIG.exports
|
|
153
|
-
|
|
154
|
-
const autoInit =
|
|
155
|
-
fileConfig.autoInit === 'lazy' ||
|
|
156
|
-
fileConfig.autoInit === 'eager' ||
|
|
157
|
-
fileConfig.autoInit === 'off'
|
|
158
|
-
? fileConfig.autoInit
|
|
159
|
-
: DEFAULT_CONFIG.autoInit
|
|
160
|
-
|
|
161
|
-
const streamCfg = {
|
|
162
|
-
enable: fileConfig.stream?.enable ?? DEFAULT_CONFIG.stream.enable,
|
|
163
|
-
export:
|
|
164
|
-
fileConfig.stream?.export ??
|
|
165
|
-
exportsList[0]?.name ??
|
|
166
|
-
DEFAULT_CONFIG.stream.export,
|
|
167
|
-
delimiter: fileConfig.stream?.delimiter ?? DEFAULT_CONFIG.stream.delimiter,
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const wasmDelivery = {
|
|
171
|
-
type: fileConfig.wasmDelivery?.type ?? DEFAULT_CONFIG.wasmDelivery.type,
|
|
172
|
-
package: fileConfig.wasmDelivery?.package ?? fileConfig.name ?? crateName,
|
|
173
|
-
version: fileConfig.wasmDelivery?.version ?? fileConfig.version ?? 'latest',
|
|
174
|
-
}
|
|
175
107
|
|
|
108
|
+
// Merge defaults, file config, and CLI options
|
|
176
109
|
const config = {
|
|
177
110
|
crateDir,
|
|
178
111
|
crateName,
|
|
179
112
|
wasmFileStem: crateName.replace(/-/g, '_'),
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
113
|
+
|
|
114
|
+
artifactBaseName:
|
|
115
|
+
cliOpts.artifactBaseName ??
|
|
116
|
+
fileConfig.artifactBaseName ??
|
|
117
|
+
DEFAULT_CONFIG.artifactBaseName,
|
|
118
|
+
|
|
119
|
+
outDir: resolve(
|
|
120
|
+
crateDir,
|
|
121
|
+
cliOpts.out ?? fileConfig.outDir ?? DEFAULT_CONFIG.outDir
|
|
122
|
+
),
|
|
123
|
+
|
|
124
|
+
release:
|
|
125
|
+
typeof cliOpts.release === 'boolean'
|
|
126
|
+
? cliOpts.release
|
|
127
|
+
: (fileConfig.release ?? DEFAULT_CONFIG.release),
|
|
128
|
+
|
|
129
|
+
targets: {
|
|
130
|
+
baseline:
|
|
131
|
+
cliOpts.baseline ??
|
|
132
|
+
fileConfig.targets?.baseline ??
|
|
133
|
+
DEFAULT_CONFIG.targets.baseline,
|
|
134
|
+
simd:
|
|
135
|
+
typeof cliOpts.simd === 'boolean'
|
|
136
|
+
? cliOpts.simd
|
|
137
|
+
: (fileConfig.targets?.simd ?? DEFAULT_CONFIG.targets.simd),
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
inline:
|
|
141
|
+
typeof cliOpts.inline === 'boolean'
|
|
142
|
+
? cliOpts.inline
|
|
143
|
+
: (fileConfig.inline ?? DEFAULT_CONFIG.inline),
|
|
144
|
+
|
|
145
|
+
wasmOpt: normalizeWasmOpt(
|
|
146
|
+
cliOpts.wasmOptMode
|
|
147
|
+
? { mode: cliOpts.wasmOptMode, args: cliOpts.wasmOptArgs }
|
|
148
|
+
: (fileConfig.wasmOpt ?? DEFAULT_CONFIG.wasmOpt)
|
|
149
|
+
),
|
|
150
|
+
|
|
151
|
+
js: {
|
|
152
|
+
emit: normalizeEmit(fileConfig.js?.emit ?? DEFAULT_CONFIG.js.emit),
|
|
153
|
+
custom: fileConfig.js?.custom ?? DEFAULT_CONFIG.js.custom,
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
exports:
|
|
157
|
+
fileConfig.exports && Array.isArray(fileConfig.exports)
|
|
158
|
+
? fileConfig.exports
|
|
159
|
+
: DEFAULT_CONFIG.exports,
|
|
160
|
+
|
|
161
|
+
autoInit: ['lazy', 'eager', 'off'].includes(fileConfig.autoInit)
|
|
162
|
+
? fileConfig.autoInit
|
|
163
|
+
: DEFAULT_CONFIG.autoInit,
|
|
164
|
+
|
|
165
|
+
stream: {
|
|
166
|
+
enable: fileConfig.stream?.enable ?? DEFAULT_CONFIG.stream.enable,
|
|
167
|
+
export:
|
|
168
|
+
fileConfig.stream?.export ??
|
|
169
|
+
fileConfig.exports?.[0]?.name ??
|
|
170
|
+
DEFAULT_CONFIG.stream.export,
|
|
171
|
+
delimiter:
|
|
172
|
+
fileConfig.stream?.delimiter ?? DEFAULT_CONFIG.stream.delimiter,
|
|
173
|
+
blockSize: fileConfig.stream?.blockSize ?? null,
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
wasmDelivery: {
|
|
177
|
+
type: fileConfig.wasmDelivery?.type ?? DEFAULT_CONFIG.wasmDelivery.type,
|
|
178
|
+
package: fileConfig.wasmDelivery?.package ?? fileConfig.name ?? crateName,
|
|
179
|
+
version:
|
|
180
|
+
fileConfig.wasmDelivery?.version ?? fileConfig.version ?? 'latest',
|
|
181
|
+
},
|
|
191
182
|
}
|
|
192
183
|
|
|
193
184
|
return config
|
package/src/cli/emit.js
CHANGED
|
@@ -4,331 +4,468 @@ import { fileURLToPath } from 'node:url'
|
|
|
4
4
|
|
|
5
5
|
const UTIL_PATH = fileURLToPath(new URL('../js/util.js', import.meta.url))
|
|
6
6
|
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
case "u8": return 1;
|
|
28
|
-
case "u32_array":
|
|
29
|
-
case "i32_array":
|
|
30
|
-
case "f32_array": return 1024 * 1024; // Default large buffer for arrays, or we can improve this
|
|
31
|
-
default: return 0;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
`
|
|
35
|
-
const decodeHelper = `function decodeReturn(view, type) {
|
|
36
|
-
switch (type) {
|
|
37
|
-
case "f32": return view.getFloat32(0, true);
|
|
38
|
-
case "f64": return view.getFloat64(0, true);
|
|
39
|
-
case "i32": return view.getInt32(0, true);
|
|
40
|
-
case "u32": return view.getUint32(0, true);
|
|
41
|
-
case "i16": return view.getInt16(0, true);
|
|
42
|
-
case "u16": return view.getUint16(0, true);
|
|
43
|
-
case "i8": return view.getInt8(0);
|
|
44
|
-
case "u8": return view.getUint8(0);
|
|
45
|
-
case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));
|
|
46
|
-
case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));
|
|
47
|
-
case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));
|
|
48
|
-
default: return null;
|
|
49
|
-
}
|
|
7
|
+
export function buildWrapperIR(exportsList) {
|
|
8
|
+
return exportsList.map((entry) => {
|
|
9
|
+
const { abi, name, return: retType, reuseBuffer, outSize } = entry
|
|
10
|
+
const returnType = retType || 'bytes'
|
|
11
|
+
const fnName = name || abi
|
|
12
|
+
const outSizeExpr =
|
|
13
|
+
returnType !== 'bytes'
|
|
14
|
+
? `(scalarSize('${returnType}') || 4)`
|
|
15
|
+
: outSize
|
|
16
|
+
? outSize.replace(/\blen\b/g, 'len')
|
|
17
|
+
: 'Math.max(len, 4)'
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
abi,
|
|
21
|
+
fnName,
|
|
22
|
+
returnType,
|
|
23
|
+
reuseBuffer: !!reuseBuffer,
|
|
24
|
+
outSizeExpr,
|
|
25
|
+
}
|
|
26
|
+
})
|
|
50
27
|
}
|
|
51
|
-
`
|
|
52
|
-
|
|
53
|
-
const wrappers = exportsList
|
|
54
|
-
.map(({ abi, name, return: retType, reuseBuffer }) => {
|
|
55
|
-
const returnType = retType || 'bytes'
|
|
56
|
-
const fnName = name || abi
|
|
57
|
-
const outSizeExpr =
|
|
58
|
-
returnType === 'bytes'
|
|
59
|
-
? 'Math.max(len, 4)'
|
|
60
|
-
: `(scalarSize('${returnType}') || 4)`
|
|
61
|
-
|
|
62
|
-
const stateVars = reuseBuffer
|
|
63
|
-
? `let _${fnName}_in = { ptr: 0, len: 0 };
|
|
64
|
-
let _${fnName}_out = { ptr: 0, len: 0 };`
|
|
65
|
-
: ''
|
|
66
|
-
|
|
67
|
-
const allocIn = reuseBuffer
|
|
68
|
-
? `if (_${fnName}_in.len < len) {
|
|
69
|
-
if (_${fnName}_in.ptr) free(_${fnName}_in.ptr, _${fnName}_in.len);
|
|
70
|
-
_${fnName}_in.ptr = alloc(len);
|
|
71
|
-
_${fnName}_in.len = len;
|
|
72
|
-
}
|
|
73
|
-
const inPtr = _${fnName}_in.ptr;`
|
|
74
|
-
: `const inPtr = alloc(len);`
|
|
75
|
-
|
|
76
|
-
const allocOut = reuseBuffer
|
|
77
|
-
? `if (_${fnName}_out.len < outLen) {
|
|
78
|
-
if (_${fnName}_out.ptr) free(_${fnName}_out.ptr, _${fnName}_out.len);
|
|
79
|
-
_${fnName}_out.ptr = alloc(outLen);
|
|
80
|
-
_${fnName}_out.len = outLen;
|
|
81
|
-
}
|
|
82
|
-
const outPtr = _${fnName}_out.ptr;`
|
|
83
|
-
: `const outPtr = alloc(outLen);`
|
|
84
|
-
|
|
85
|
-
const freeIn = reuseBuffer ? '' : `free(inPtr, len);`
|
|
86
|
-
const freeOut = reuseBuffer ? '' : `free(outPtr, outLen);`
|
|
87
|
-
|
|
88
|
-
const body = `
|
|
89
|
-
if (!_inst) throw new Error("WASM instance not initialized");
|
|
90
|
-
const view = toBytes(input);
|
|
91
|
-
const len = view.byteLength;
|
|
92
|
-
${allocIn}
|
|
93
|
-
memoryU8().set(view, inPtr);
|
|
94
|
-
const outLen = ${outSizeExpr};
|
|
95
|
-
${allocOut}
|
|
96
|
-
const written = _inst.exports.${abi}(
|
|
97
|
-
inPtr, len,
|
|
98
|
-
outPtr, outLen
|
|
99
|
-
);
|
|
100
|
-
if (written < 0) {
|
|
101
|
-
${reuseBuffer ? '' : `free(inPtr, len); free(outPtr, outLen);`}
|
|
102
|
-
throw new Error("${abi} failed: " + written);
|
|
103
|
-
}
|
|
104
|
-
${
|
|
105
|
-
returnType === 'bytes'
|
|
106
|
-
? `const result = memoryU8().slice(outPtr, outPtr + written);`
|
|
107
|
-
: `const retView = new DataView(memoryU8().buffer, outPtr, written);
|
|
108
|
-
const ret = decodeReturn(retView, "${returnType}");`
|
|
109
|
-
}
|
|
110
|
-
${freeIn}
|
|
111
|
-
${freeOut}
|
|
112
|
-
${returnType === 'bytes' ? 'return result;' : 'return ret;'}`
|
|
113
28
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
29
|
+
export function createCore({ exportsList, autoInit, stream }) {
|
|
30
|
+
const needsEnsure = autoInit === 'lazy'
|
|
31
|
+
const wrappersIR = buildWrapperIR(exportsList)
|
|
32
|
+
const b = code()
|
|
33
|
+
|
|
34
|
+
b.line('let _inst = null;')
|
|
35
|
+
b.line('let _memU8 = null;')
|
|
36
|
+
b.line('let _initFn = null;')
|
|
37
|
+
b.blank()
|
|
38
|
+
|
|
39
|
+
b.line('function refreshViews() {')
|
|
40
|
+
b.indent(() => {
|
|
41
|
+
b.line('_memU8 = new Uint8Array(_inst.exports.memory.buffer);')
|
|
42
|
+
})
|
|
43
|
+
b.line('}')
|
|
44
|
+
b.blank()
|
|
45
|
+
|
|
46
|
+
b.line('export function setInstance(instance) {')
|
|
47
|
+
b.indent(() => {
|
|
48
|
+
b.line('_inst = instance;')
|
|
49
|
+
b.line('refreshViews();')
|
|
50
|
+
})
|
|
51
|
+
b.line('}')
|
|
52
|
+
b.blank()
|
|
53
|
+
|
|
54
|
+
b.line('export function wasmExports() {')
|
|
55
|
+
b.indent(() => {
|
|
56
|
+
b.line('return _inst.exports;')
|
|
57
|
+
})
|
|
58
|
+
b.line('}')
|
|
59
|
+
b.blank()
|
|
60
|
+
|
|
61
|
+
if (needsEnsure) {
|
|
62
|
+
b.line('let _ready = null;')
|
|
63
|
+
b.line('export function registerInit(fn) { _initFn = fn; }')
|
|
64
|
+
b.blank()
|
|
65
|
+
b.line('async function ensureReady() {')
|
|
66
|
+
b.indent(() => {
|
|
67
|
+
b.line('if (_ready) return _ready;')
|
|
68
|
+
b.line('if (!_initFn) throw new Error("init not registered");')
|
|
69
|
+
b.line('_ready = _initFn();')
|
|
70
|
+
b.line('return _ready;')
|
|
119
71
|
})
|
|
120
|
-
.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
? `
|
|
124
|
-
const __exports = { ${exportsList.map(({ name, abi }) => `${name || abi}: ${name || abi}`).join(', ')} };
|
|
125
|
-
|
|
126
|
-
export function createTransformStream(fnName = "${stream.export}") {
|
|
127
|
-
const fn = __exports[fnName];
|
|
128
|
-
if (!fn) throw new Error("Unknown export for streaming: " + fnName);
|
|
129
|
-
|
|
130
|
-
${
|
|
131
|
-
stream.delimiter !== null
|
|
132
|
-
? `let buffer = new Uint8Array(0);
|
|
133
|
-
const delimiter = ${stream.delimiter};`
|
|
134
|
-
: ''
|
|
72
|
+
b.line('}')
|
|
73
|
+
} else {
|
|
74
|
+
b.line('export function registerInit(fn) { _initFn = fn; }')
|
|
135
75
|
}
|
|
76
|
+
b.blank()
|
|
136
77
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
78
|
+
b.line('export function memoryU8() {')
|
|
79
|
+
b.indent(() => {
|
|
80
|
+
b.line(
|
|
81
|
+
'if (_memU8 && _memU8.buffer !== _inst.exports.memory.buffer) refreshViews();'
|
|
82
|
+
)
|
|
83
|
+
b.line('return _memU8;')
|
|
84
|
+
})
|
|
85
|
+
b.line('}')
|
|
86
|
+
b.blank()
|
|
87
|
+
|
|
88
|
+
b.line('export function alloc(len) {')
|
|
89
|
+
b.indent(() => {
|
|
90
|
+
b.line('return _inst.exports.alloc_bytes(len) >>> 0;')
|
|
91
|
+
})
|
|
92
|
+
b.line('}')
|
|
93
|
+
b.blank()
|
|
94
|
+
|
|
95
|
+
b.line('export function free(ptr, len) {')
|
|
96
|
+
b.indent(() => {
|
|
97
|
+
b.line('_inst.exports.free_bytes(ptr >>> 0, len >>> 0);')
|
|
98
|
+
})
|
|
99
|
+
b.line('}')
|
|
100
|
+
b.blank()
|
|
101
|
+
|
|
102
|
+
// Runtime Helpers
|
|
103
|
+
b.line('function toBytes(input) {')
|
|
104
|
+
b.indent(() => {
|
|
105
|
+
b.line('if (input instanceof Uint8Array) return input;')
|
|
106
|
+
b.line(
|
|
107
|
+
'if (ArrayBuffer.isView(input)) return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);'
|
|
108
|
+
)
|
|
109
|
+
b.line('if (input instanceof ArrayBuffer) return new Uint8Array(input);')
|
|
110
|
+
b.line('throw new TypeError("Expected a TypedArray or ArrayBuffer");')
|
|
111
|
+
})
|
|
112
|
+
b.line('}')
|
|
113
|
+
b.blank()
|
|
114
|
+
|
|
115
|
+
b.line('function scalarSize(type) {')
|
|
116
|
+
b.indent(() => {
|
|
117
|
+
b.line('switch (type) {')
|
|
118
|
+
b.line(' case "f64": return 8;')
|
|
119
|
+
b.line(' case "f32":')
|
|
120
|
+
b.line(' case "i32":')
|
|
121
|
+
b.line(' case "u32": return 4;')
|
|
122
|
+
b.line(' case "i16":')
|
|
123
|
+
b.line(' case "u16": return 2;')
|
|
124
|
+
b.line(' case "i8":')
|
|
125
|
+
b.line(' case "u8": return 1;')
|
|
126
|
+
b.line(' case "u32_array":')
|
|
127
|
+
b.line(' case "i32_array":')
|
|
128
|
+
b.line(' case "f32_array": return 1024 * 1024;')
|
|
129
|
+
b.line(' default: return 0;')
|
|
130
|
+
b.line('}')
|
|
131
|
+
})
|
|
132
|
+
b.line('}')
|
|
133
|
+
b.blank()
|
|
134
|
+
|
|
135
|
+
b.line('function decodeReturn(view, type) {')
|
|
136
|
+
b.indent(() => {
|
|
137
|
+
b.line('switch (type) {')
|
|
138
|
+
b.line(' case "f32": return view.getFloat32(0, true);')
|
|
139
|
+
b.line(' case "f64": return view.getFloat64(0, true);')
|
|
140
|
+
b.line(' case "i32": return view.getInt32(0, true);')
|
|
141
|
+
b.line(' case "u32": return view.getUint32(0, true);')
|
|
142
|
+
b.line(' case "i16": return view.getInt16(0, true);')
|
|
143
|
+
b.line(' case "u16": return view.getUint16(0, true);')
|
|
144
|
+
b.line(' case "i8": return view.getInt8(0);')
|
|
145
|
+
b.line(' case "u8": return view.getUint8(0);')
|
|
146
|
+
b.line(
|
|
147
|
+
' case "u32_array": return new Uint32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
|
|
148
|
+
)
|
|
149
|
+
b.line(
|
|
150
|
+
' case "i32_array": return new Int32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
|
|
151
|
+
)
|
|
152
|
+
b.line(
|
|
153
|
+
' case "f32_array": return new Float32Array(view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength));'
|
|
154
|
+
)
|
|
155
|
+
b.line(' default: return null;')
|
|
156
|
+
b.line('}')
|
|
157
|
+
})
|
|
158
|
+
b.line('}')
|
|
159
|
+
b.blank()
|
|
160
|
+
|
|
161
|
+
b.line('function callWasm(abi, input, outLen, reuse) {')
|
|
162
|
+
b.indent(() => {
|
|
163
|
+
b.line('if (!_inst) throw new Error("WASM instance not initialized");')
|
|
164
|
+
b.line('const view = toBytes(input);')
|
|
165
|
+
b.line('const len = view.byteLength;')
|
|
166
|
+
b.blank()
|
|
167
|
+
b.line('let inPtr, outPtr;')
|
|
168
|
+
b.line('if (reuse) {')
|
|
169
|
+
b.indent(() => {
|
|
170
|
+
b.line('if (reuse.in.len < len) {')
|
|
171
|
+
b.indent(() => {
|
|
172
|
+
b.line('if (reuse.in.ptr) free(reuse.in.ptr, reuse.in.len);')
|
|
173
|
+
b.line('reuse.in.ptr = alloc(len);')
|
|
174
|
+
b.line('reuse.in.len = len;')
|
|
175
|
+
})
|
|
176
|
+
b.line('}')
|
|
177
|
+
b.line('if (reuse.out.len < outLen) {')
|
|
178
|
+
b.indent(() => {
|
|
179
|
+
b.line('if (reuse.out.ptr) free(reuse.out.ptr, reuse.out.len);')
|
|
180
|
+
b.line('reuse.out.ptr = alloc(outLen);')
|
|
181
|
+
b.line('reuse.out.len = outLen;')
|
|
182
|
+
})
|
|
183
|
+
b.line('}')
|
|
184
|
+
b.line('inPtr = reuse.in.ptr;')
|
|
185
|
+
b.line('outPtr = reuse.out.ptr;')
|
|
186
|
+
})
|
|
187
|
+
b.line('} else {')
|
|
188
|
+
b.indent(() => {
|
|
189
|
+
b.line('inPtr = alloc(len);')
|
|
190
|
+
b.line('outPtr = alloc(outLen);')
|
|
191
|
+
})
|
|
192
|
+
b.line('}')
|
|
193
|
+
b.blank()
|
|
194
|
+
b.line('memoryU8().set(view, inPtr);')
|
|
195
|
+
b.line('const written = _inst.exports[abi](inPtr, len, outPtr, outLen);')
|
|
196
|
+
b.line('if (written < 0) {')
|
|
197
|
+
b.indent(() => {
|
|
198
|
+
b.line('if (!reuse) { free(inPtr, len); free(outPtr, outLen); }')
|
|
199
|
+
b.line('throw new Error(abi + " failed: " + written);')
|
|
200
|
+
})
|
|
201
|
+
b.line('}')
|
|
202
|
+
b.blank()
|
|
203
|
+
b.line('return { inPtr, outPtr, len, outLen, written };')
|
|
204
|
+
})
|
|
205
|
+
b.line('}')
|
|
206
|
+
b.blank()
|
|
207
|
+
|
|
208
|
+
// Wrappers
|
|
209
|
+
wrappersIR.forEach((w) => {
|
|
210
|
+
if (w.reuseBuffer) {
|
|
211
|
+
b.line(
|
|
212
|
+
`const _${w.fnName}_reuse = { in: { ptr: 0, len: 0 }, out: { ptr: 0, len: 0 } };`
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
const asyncPrefix = needsEnsure ? 'async ' : ''
|
|
216
|
+
b.line(`${asyncPrefix}function ${w.fnName}(input) {`)
|
|
217
|
+
b.indent(() => {
|
|
218
|
+
if (needsEnsure) b.line('await ensureReady();')
|
|
219
|
+
b.line('const view = toBytes(input);')
|
|
220
|
+
b.line('const len = view.byteLength;')
|
|
221
|
+
b.line(`const outLen = ${w.outSizeExpr};`)
|
|
222
|
+
b.line(
|
|
223
|
+
`const { outPtr, written, inPtr } = callWasm("${w.abi}", view, outLen, ${w.reuseBuffer ? `_${w.fnName}_reuse` : 'null'});`
|
|
224
|
+
)
|
|
225
|
+
b.blank()
|
|
226
|
+
if (w.returnType === 'bytes') {
|
|
227
|
+
b.line('const result = memoryU8().slice(outPtr, outPtr + written);')
|
|
228
|
+
} else {
|
|
229
|
+
b.line(
|
|
230
|
+
'const retView = new DataView(memoryU8().buffer, outPtr, written);'
|
|
231
|
+
)
|
|
232
|
+
b.line(`const result = decodeReturn(retView, "${w.returnType}");`)
|
|
155
233
|
}
|
|
156
|
-
|
|
157
|
-
|
|
234
|
+
b.blank()
|
|
235
|
+
if (!w.reuseBuffer) {
|
|
236
|
+
b.line('free(inPtr, len);')
|
|
237
|
+
b.line('free(outPtr, outLen);')
|
|
158
238
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
async function ensureReady() {
|
|
180
|
-
if (_ready) return _ready;
|
|
181
|
-
if (!_initFn) throw new Error("init not registered");
|
|
182
|
-
_ready = _initFn();
|
|
183
|
-
return _ready;
|
|
184
|
-
}
|
|
185
|
-
`
|
|
186
|
-
: `
|
|
187
|
-
export function registerInit(fn) {
|
|
188
|
-
_initFn = fn;
|
|
189
|
-
}
|
|
190
|
-
`
|
|
239
|
+
b.line('return result;')
|
|
240
|
+
})
|
|
241
|
+
b.line('}')
|
|
242
|
+
b.line(`export { ${w.fnName} };`)
|
|
243
|
+
b.blank()
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
// Streaming
|
|
247
|
+
if (stream?.enable) {
|
|
248
|
+
b.line('const __exports = {')
|
|
249
|
+
b.indent(() => {
|
|
250
|
+
exportsList.forEach((e) => {
|
|
251
|
+
b.line(
|
|
252
|
+
`${e.name || e.abi}: { fn: ${e.name || e.abi}, blockSize: ${e.blockSize || 'null'} },`
|
|
253
|
+
)
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
b.line('};')
|
|
257
|
+
b.blank()
|
|
191
258
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
259
|
+
b.line(
|
|
260
|
+
'export function createChunkTransform(processFn, { blockSize = null, delimiter = null } = {}) {'
|
|
261
|
+
)
|
|
262
|
+
b.indent(() => {
|
|
263
|
+
b.line('let buffer = new Uint8Array(0);')
|
|
264
|
+
b.line('return new TransformStream({')
|
|
265
|
+
b.indent(() => {
|
|
266
|
+
b.line('async transform(chunk, controller) {')
|
|
267
|
+
b.indent(() => {
|
|
268
|
+
b.line('const bytes = toBytes(chunk);')
|
|
269
|
+
b.line('let input = bytes;')
|
|
270
|
+
b.blank()
|
|
271
|
+
b.line(
|
|
272
|
+
'if (buffer.length > 0 || blockSize !== null || delimiter !== null) {'
|
|
273
|
+
)
|
|
274
|
+
b.indent(() => {
|
|
275
|
+
b.line(
|
|
276
|
+
'const combined = new Uint8Array(buffer.length + bytes.length);'
|
|
277
|
+
)
|
|
278
|
+
b.line('combined.set(buffer, 0);')
|
|
279
|
+
b.line('combined.set(bytes, buffer.length);')
|
|
280
|
+
b.line('input = combined;')
|
|
281
|
+
})
|
|
282
|
+
b.line('}')
|
|
283
|
+
b.blank()
|
|
284
|
+
b.line('if (delimiter !== null) {')
|
|
285
|
+
b.indent(() => {
|
|
286
|
+
b.line('let start = 0;')
|
|
287
|
+
b.line('for (let i = 0; i < input.length; i++) {')
|
|
288
|
+
b.indent(() => {
|
|
289
|
+
b.line('if (input[i] === delimiter) {')
|
|
290
|
+
b.indent(() => {
|
|
291
|
+
b.line(
|
|
292
|
+
'controller.enqueue(await processFn(input.subarray(start, i)));'
|
|
293
|
+
)
|
|
294
|
+
b.line('start = i + 1;')
|
|
295
|
+
})
|
|
296
|
+
b.line('}')
|
|
297
|
+
})
|
|
298
|
+
b.line('}')
|
|
299
|
+
b.line('buffer = input.slice(start);')
|
|
300
|
+
})
|
|
301
|
+
b.line('} else if (blockSize !== null) {')
|
|
302
|
+
b.indent(() => {
|
|
303
|
+
b.line(
|
|
304
|
+
'const processLen = input.length - (input.length % blockSize);'
|
|
305
|
+
)
|
|
306
|
+
b.line('if (processLen > 0) {')
|
|
307
|
+
b.indent(() => {
|
|
308
|
+
b.line(
|
|
309
|
+
'controller.enqueue(await processFn(input.subarray(0, processLen)));'
|
|
310
|
+
)
|
|
311
|
+
b.line('buffer = input.slice(processLen);')
|
|
312
|
+
})
|
|
313
|
+
b.line('} else {')
|
|
314
|
+
b.indent(() => {
|
|
315
|
+
b.line('buffer = input;')
|
|
316
|
+
})
|
|
317
|
+
b.line('}')
|
|
318
|
+
})
|
|
319
|
+
b.line('} else {')
|
|
320
|
+
b.indent(() => {
|
|
321
|
+
b.line('controller.enqueue(await processFn(input));')
|
|
322
|
+
b.line('buffer = new Uint8Array(0);')
|
|
323
|
+
})
|
|
324
|
+
b.line('}')
|
|
325
|
+
})
|
|
326
|
+
b.line('},')
|
|
327
|
+
b.line('async flush(controller) {')
|
|
328
|
+
b.indent(() => {
|
|
329
|
+
b.line('if (buffer.length > 0) {')
|
|
330
|
+
b.indent(() => {
|
|
331
|
+
b.line('controller.enqueue(await processFn(buffer));')
|
|
332
|
+
b.line('buffer = new Uint8Array(0);')
|
|
333
|
+
})
|
|
334
|
+
b.line('}')
|
|
335
|
+
})
|
|
336
|
+
b.line('}')
|
|
337
|
+
})
|
|
338
|
+
b.line('});')
|
|
339
|
+
})
|
|
340
|
+
b.line('}')
|
|
341
|
+
b.blank()
|
|
195
342
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
343
|
+
b.line(
|
|
344
|
+
`export function createTransformStream(fnName = "${stream.export}") {`
|
|
345
|
+
)
|
|
346
|
+
b.indent(() => {
|
|
347
|
+
b.line('const entry = __exports[fnName];')
|
|
348
|
+
b.line(
|
|
349
|
+
'if (!entry) throw new Error("Unknown export for streaming: " + fnName);'
|
|
350
|
+
)
|
|
351
|
+
b.line('const { fn, blockSize: entryBlockSize } = entry;')
|
|
352
|
+
b.line(
|
|
353
|
+
`const blockSize = entryBlockSize ?? ${stream.blockSize !== null ? stream.blockSize : 'null'};`
|
|
354
|
+
)
|
|
355
|
+
b.line(
|
|
356
|
+
`const delimiter = ${stream.delimiter !== null ? stream.delimiter : 'null'};`
|
|
357
|
+
)
|
|
358
|
+
b.line('return createChunkTransform(fn, { blockSize, delimiter });')
|
|
359
|
+
})
|
|
360
|
+
b.line('}')
|
|
361
|
+
}
|
|
199
362
|
|
|
200
|
-
|
|
201
|
-
_inst = instance;
|
|
202
|
-
refreshViews();
|
|
363
|
+
return b.toString()
|
|
203
364
|
}
|
|
204
365
|
|
|
205
|
-
export function
|
|
206
|
-
|
|
366
|
+
export function code() {
|
|
367
|
+
const lines = []
|
|
368
|
+
let indent = 0
|
|
369
|
+
const api = {
|
|
370
|
+
line(s = '') {
|
|
371
|
+
lines.push(' '.repeat(indent) + s)
|
|
372
|
+
return api
|
|
373
|
+
},
|
|
374
|
+
blank() {
|
|
375
|
+
lines.push('')
|
|
376
|
+
return api
|
|
377
|
+
},
|
|
378
|
+
indent(fn) {
|
|
379
|
+
indent++
|
|
380
|
+
fn()
|
|
381
|
+
indent--
|
|
382
|
+
return api
|
|
383
|
+
},
|
|
384
|
+
toString() {
|
|
385
|
+
return lines.join('\n')
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
return api
|
|
207
389
|
}
|
|
208
390
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
391
|
+
export function createLoader({ exportFrom, autoInit, getBytesSrc }) {
|
|
392
|
+
const eager =
|
|
393
|
+
autoInit === 'eager'
|
|
394
|
+
? '\nregisterInit(init);\ninit();'
|
|
395
|
+
: '\nregisterInit(init);'
|
|
215
396
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
397
|
+
return `import { setInstance, registerInit } from "./core.js";
|
|
398
|
+
import { instantiateWithFallback } from "./util.js";
|
|
399
|
+
${getBytesSrc}
|
|
219
400
|
|
|
220
|
-
|
|
221
|
-
|
|
401
|
+
let _ready = null;
|
|
402
|
+
export function init(imports = {}) {
|
|
403
|
+
return (_ready ??= (async () => {
|
|
404
|
+
const { simdBytes, baseBytes } = await getWasmBytes();
|
|
405
|
+
const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
|
|
406
|
+
setInstance(instance);
|
|
407
|
+
})());
|
|
222
408
|
}
|
|
223
|
-
|
|
224
|
-
${
|
|
225
|
-
${scalarSizeHelper}
|
|
226
|
-
${decodeHelper}
|
|
227
|
-
${toBytesHelper}
|
|
228
|
-
${streamHelper}
|
|
409
|
+
${eager}
|
|
410
|
+
export * from "${exportFrom}";
|
|
229
411
|
`
|
|
230
412
|
}
|
|
231
413
|
|
|
232
414
|
function createBrowserLoader({ name, autoInit, customJs, wasmDelivery }) {
|
|
233
|
-
const eager =
|
|
234
|
-
autoInit === 'eager'
|
|
235
|
-
? '\nregisterInit(init);\ninit();'
|
|
236
|
-
: '\nregisterInit(init);'
|
|
237
415
|
const exportFrom = customJs ? './custom.js' : './core.js'
|
|
238
416
|
|
|
239
417
|
let simdUrl, baseUrl
|
|
240
418
|
if (wasmDelivery.type === 'jsdelivr') {
|
|
241
419
|
const pkg = wasmDelivery.package
|
|
242
420
|
const ver = wasmDelivery.version
|
|
243
|
-
simdUrl = `https://cdn.jsdelivr.net/npm/${pkg}@${ver}/dist/wasm/${name}.simd.wasm`
|
|
244
|
-
baseUrl = `https://cdn.jsdelivr.net/npm/${pkg}@${ver}/dist/wasm/${name}.base.wasm`
|
|
421
|
+
simdUrl = `"https://cdn.jsdelivr.net/npm/${pkg}@${ver}/dist/wasm/${name}.simd.wasm"`
|
|
422
|
+
baseUrl = `"https://cdn.jsdelivr.net/npm/${pkg}@${ver}/dist/wasm/${name}.base.wasm"`
|
|
245
423
|
} else {
|
|
246
424
|
simdUrl = `new URL("./wasm/${name}.simd.wasm", import.meta.url)`
|
|
247
425
|
baseUrl = `new URL("./wasm/${name}.base.wasm", import.meta.url)`
|
|
248
426
|
}
|
|
249
427
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const simdUrl = ${wasmDelivery.type === 'jsdelivr' ? `"${simdUrl}"` : simdUrl};
|
|
254
|
-
const baseUrl = ${wasmDelivery.type === 'jsdelivr' ? `"${baseUrl}"` : baseUrl};
|
|
255
|
-
|
|
256
|
-
let _ready = null;
|
|
257
|
-
|
|
258
|
-
export function init(imports = {}) {
|
|
259
|
-
return (_ready ??= (async () => {
|
|
260
|
-
const [simdRes, baseRes] = await Promise.all([
|
|
261
|
-
fetch(simdUrl),
|
|
262
|
-
fetch(baseUrl)
|
|
263
|
-
]);
|
|
264
|
-
|
|
265
|
-
const [simdBytes, baseBytes] = await Promise.all([
|
|
266
|
-
simdRes.arrayBuffer(),
|
|
267
|
-
baseRes.arrayBuffer()
|
|
268
|
-
]);
|
|
428
|
+
const getBytesSrc = `
|
|
429
|
+
const simdUrl = ${simdUrl};
|
|
430
|
+
const baseUrl = ${baseUrl};
|
|
269
431
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
432
|
+
async function getWasmBytes() {
|
|
433
|
+
const [simdRes, baseRes] = await Promise.all([fetch(simdUrl), fetch(baseUrl)]);
|
|
434
|
+
const [simdBytes, baseBytes] = await Promise.all([simdRes.arrayBuffer(), baseRes.arrayBuffer()]);
|
|
435
|
+
return { simdBytes, baseBytes };
|
|
273
436
|
}
|
|
274
|
-
${eager}
|
|
275
|
-
export * from "${exportFrom}";
|
|
276
437
|
`
|
|
438
|
+
return createLoader({ exportFrom, autoInit, getBytesSrc })
|
|
277
439
|
}
|
|
278
440
|
|
|
279
441
|
function createNodeLoader({ name, autoInit, customJs }) {
|
|
280
|
-
const eager =
|
|
281
|
-
autoInit === 'eager'
|
|
282
|
-
? '\nregisterInit(init);\ninit();'
|
|
283
|
-
: '\nregisterInit(init);'
|
|
284
442
|
const exportFrom = customJs ? './custom.js' : './core.js'
|
|
285
|
-
|
|
443
|
+
const getBytesSrc = `
|
|
444
|
+
import { readFile } from "node:fs/promises";
|
|
286
445
|
import { fileURLToPath } from "node:url";
|
|
287
|
-
import { setInstance, registerInit } from "./core.js";
|
|
288
|
-
import { instantiateWithFallback } from "./util.js";
|
|
289
446
|
|
|
290
447
|
const simdPath = fileURLToPath(new URL("./wasm/${name}.simd.wasm", import.meta.url));
|
|
291
448
|
const basePath = fileURLToPath(new URL("./wasm/${name}.base.wasm", import.meta.url));
|
|
292
449
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return (_ready ??= (async () => {
|
|
297
|
-
const [simdBytes, baseBytes] = await Promise.all([
|
|
298
|
-
readFile(simdPath),
|
|
299
|
-
readFile(basePath)
|
|
300
|
-
]);
|
|
301
|
-
const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
|
|
302
|
-
setInstance(instance);
|
|
303
|
-
})());
|
|
450
|
+
async function getWasmBytes() {
|
|
451
|
+
const [simdBytes, baseBytes] = await Promise.all([readFile(simdPath), readFile(basePath)]);
|
|
452
|
+
return { simdBytes, baseBytes };
|
|
304
453
|
}
|
|
305
|
-
${eager}
|
|
306
|
-
export * from "${exportFrom}";
|
|
307
454
|
`
|
|
455
|
+
return createLoader({ exportFrom, autoInit, getBytesSrc })
|
|
308
456
|
}
|
|
309
457
|
|
|
310
458
|
function createInlineLoader({ name, autoInit, customJs }) {
|
|
311
|
-
const eager =
|
|
312
|
-
autoInit === 'eager'
|
|
313
|
-
? '\nregisterInit(init);\ninit();'
|
|
314
|
-
: '\nregisterInit(init);'
|
|
315
459
|
const exportFrom = customJs ? './custom.js' : './core.js'
|
|
316
|
-
|
|
460
|
+
const getBytesSrc = `
|
|
461
|
+
import { wasmBytes as simdBytes } from "./wasm-inline/${name}.simd.wasm.js";
|
|
317
462
|
import { wasmBytes as baseBytes } from "./wasm-inline/${name}.base.wasm.js";
|
|
318
|
-
import { setInstance, registerInit } from "./core.js";
|
|
319
|
-
import { instantiateWithFallback } from "./util.js";
|
|
320
|
-
|
|
321
|
-
let _ready = null;
|
|
322
463
|
|
|
323
|
-
|
|
324
|
-
return
|
|
325
|
-
const { instance } = await instantiateWithFallback(simdBytes, baseBytes, imports);
|
|
326
|
-
setInstance(instance);
|
|
327
|
-
})());
|
|
464
|
+
async function getWasmBytes() {
|
|
465
|
+
return { simdBytes, baseBytes };
|
|
328
466
|
}
|
|
329
|
-
${eager}
|
|
330
|
-
export * from "${exportFrom}";
|
|
331
467
|
`
|
|
468
|
+
return createLoader({ exportFrom, autoInit, getBytesSrc })
|
|
332
469
|
}
|
|
333
470
|
|
|
334
471
|
function createInlineModule(bytes) {
|
package/src/cli/index.js
CHANGED
package/src/cli/pkg.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
2
2
|
import { join, relative } from 'node:path'
|
|
3
3
|
|
|
4
|
-
export function updatePackageJson({
|
|
5
|
-
crateDir,
|
|
6
|
-
outDir,
|
|
7
|
-
artifactBaseName,
|
|
8
|
-
js,
|
|
9
|
-
inline,
|
|
10
|
-
}) {
|
|
4
|
+
export function updatePackageJson({ crateDir, outDir, js, inline }) {
|
|
11
5
|
const pkgPath = join(crateDir, 'package.json')
|
|
12
6
|
if (!existsSync(pkgPath)) return
|
|
13
7
|
|
package/src/js/util.js
CHANGED
|
@@ -6,7 +6,7 @@ export async function instantiateWithFallback(
|
|
|
6
6
|
try {
|
|
7
7
|
const { instance } = await WebAssembly.instantiate(trySimdBytes, imports)
|
|
8
8
|
return { instance, backend: 'wasm-simd' }
|
|
9
|
-
} catch
|
|
9
|
+
} catch {
|
|
10
10
|
// If SIMD fails (not supported), try baseline
|
|
11
11
|
const { instance } = await WebAssembly.instantiate(baseBytes, imports)
|
|
12
12
|
return { instance, backend: 'wasm' }
|