wasm-bindgen-lite 0.3.1 → 0.3.3
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/README.md +78 -0
- package/bin/wasm-bindgen-lite.js +12 -1
- package/package.json +4 -1
- package/src/cli/bench.js +887 -0
- package/src/cli/build.js +61 -9
- package/src/cli/config.js +9 -1
- package/src/cli/emit.js +72 -20
- package/src/cli/index.js +29 -1
- package/src/js/browser-inline.js +23 -10
- package/src/js/browser.js +22 -17
- package/src/js/node-inline.js +23 -10
- package/src/js/node.js +21 -12
- package/src/js/util.js +30 -0
package/src/cli/build.js
CHANGED
|
@@ -11,16 +11,47 @@ function exec(cmd, options = {}) {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function
|
|
14
|
+
function resolveTargetDir(crateDir) {
|
|
15
|
+
try {
|
|
16
|
+
const raw = execSync('cargo metadata --format-version 1 --no-deps', {
|
|
17
|
+
cwd: crateDir,
|
|
18
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
19
|
+
}).toString()
|
|
20
|
+
const meta = JSON.parse(raw)
|
|
21
|
+
if (meta?.target_directory) return meta.target_directory
|
|
22
|
+
} catch {
|
|
23
|
+
console.warn(
|
|
24
|
+
'Warning: failed to read cargo metadata, defaulting to local target dir'
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
return join(crateDir, 'target')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function runCargoBuild({ crateDir, release, simd, targetDir, features }) {
|
|
15
31
|
const args = ['build', '--target', 'wasm32-unknown-unknown']
|
|
16
32
|
if (release) args.push('--release')
|
|
33
|
+
if (features) {
|
|
34
|
+
args.push('--features', features)
|
|
35
|
+
}
|
|
17
36
|
|
|
18
37
|
const env = { ...process.env }
|
|
38
|
+
|
|
39
|
+
if (release) {
|
|
40
|
+
// Explicitly force opt-level 3 for fastest execution
|
|
41
|
+
env.CARGO_PROFILE_RELEASE_OPT_LEVEL = '3'
|
|
42
|
+
env.CARGO_PROFILE_RELEASE_PANIC = 'abort'
|
|
43
|
+
env.CARGO_PROFILE_RELEASE_CODEGEN_UNITS = '1'
|
|
44
|
+
env.CARGO_PROFILE_RELEASE_LTO = 'fat'
|
|
45
|
+
}
|
|
46
|
+
|
|
19
47
|
if (simd) {
|
|
20
|
-
const base =
|
|
48
|
+
const base = env.RUSTFLAGS || ''
|
|
21
49
|
const extra = '-C target-feature=+simd128'
|
|
22
50
|
env.RUSTFLAGS = [base, extra].filter(Boolean).join(' ').trim()
|
|
23
51
|
}
|
|
52
|
+
if (targetDir) {
|
|
53
|
+
env.CARGO_TARGET_DIR = targetDir
|
|
54
|
+
}
|
|
24
55
|
|
|
25
56
|
exec(`cargo ${args.join(' ')}`, {
|
|
26
57
|
cwd: crateDir,
|
|
@@ -28,18 +59,17 @@ function runCargoBuild({ crateDir, release, simd }) {
|
|
|
28
59
|
})
|
|
29
60
|
}
|
|
30
61
|
|
|
31
|
-
function wasmPath({
|
|
62
|
+
function wasmPath({ targetDir, release, wasmFileStem }) {
|
|
32
63
|
const profile = release ? 'release' : 'debug'
|
|
33
64
|
return join(
|
|
34
|
-
|
|
35
|
-
'target',
|
|
65
|
+
targetDir,
|
|
36
66
|
'wasm32-unknown-unknown',
|
|
37
67
|
profile,
|
|
38
68
|
`${wasmFileStem}.wasm`
|
|
39
69
|
)
|
|
40
70
|
}
|
|
41
71
|
|
|
42
|
-
function maybeRunWasmOpt(wasmFile, wasmOpt) {
|
|
72
|
+
function maybeRunWasmOpt(wasmFile, wasmOpt, release) {
|
|
43
73
|
if (wasmOpt.mode === 'off') return
|
|
44
74
|
if (wasmOpt.mode === 'auto') {
|
|
45
75
|
try {
|
|
@@ -49,7 +79,24 @@ function maybeRunWasmOpt(wasmFile, wasmOpt) {
|
|
|
49
79
|
}
|
|
50
80
|
}
|
|
51
81
|
|
|
52
|
-
const args = ['wasm-opt'
|
|
82
|
+
const args = ['wasm-opt']
|
|
83
|
+
|
|
84
|
+
if (release) {
|
|
85
|
+
// Only strip metadata and debug info for fastest performance
|
|
86
|
+
args.push('--strip-debug')
|
|
87
|
+
args.push('--strip-producers')
|
|
88
|
+
args.push('--strip-target-features')
|
|
89
|
+
|
|
90
|
+
// We EXPLICITLY avoid -O passes here to maintain absolute fastest speed
|
|
91
|
+
// unless the user provided specific args
|
|
92
|
+
if (wasmOpt.args.length > 0) {
|
|
93
|
+
args.push(...wasmOpt.args)
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
args.push(...wasmOpt.args)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
args.push(wasmFile, '-o', wasmFile)
|
|
53
100
|
exec(args.join(' '))
|
|
54
101
|
}
|
|
55
102
|
|
|
@@ -62,6 +109,7 @@ export function buildArtifacts({
|
|
|
62
109
|
release,
|
|
63
110
|
wasmOpt,
|
|
64
111
|
}) {
|
|
112
|
+
const targetDir = resolveTargetDir(crateDir)
|
|
65
113
|
mkdirSync(outDir, { recursive: true })
|
|
66
114
|
const wasmOutDir = join(outDir, 'wasm')
|
|
67
115
|
mkdirSync(wasmOutDir, { recursive: true })
|
|
@@ -72,9 +120,13 @@ export function buildArtifacts({
|
|
|
72
120
|
const label = isSimd ? 'SIMD' : 'baseline'
|
|
73
121
|
console.log(`Building ${label} wasm...`)
|
|
74
122
|
|
|
75
|
-
|
|
123
|
+
const simdFeatures = isSimd ? targets.simdFeatures : null
|
|
124
|
+
const baselineFeatures = !isSimd ? targets.baselineFeatures : null
|
|
125
|
+
const features = simdFeatures || baselineFeatures
|
|
126
|
+
|
|
127
|
+
runCargoBuild({ crateDir, release, simd: isSimd, targetDir, features })
|
|
76
128
|
|
|
77
|
-
const built = wasmPath({
|
|
129
|
+
const built = wasmPath({ targetDir, release, wasmFileStem })
|
|
78
130
|
const dest = join(wasmOutDir, `${artifactBaseName}.${suffix}.wasm`)
|
|
79
131
|
|
|
80
132
|
copyFileSync(built, dest)
|
package/src/cli/config.js
CHANGED
|
@@ -21,7 +21,7 @@ const DEFAULT_CONFIG = {
|
|
|
21
21
|
inline: true,
|
|
22
22
|
types: true,
|
|
23
23
|
},
|
|
24
|
-
custom: null, // path to custom JS file to include and re-export
|
|
24
|
+
custom: null, // path to custom JS/TS file to include and re-export
|
|
25
25
|
},
|
|
26
26
|
exports: [
|
|
27
27
|
{
|
|
@@ -138,6 +138,8 @@ export function loadConfigFromCli(cliOpts = {}) {
|
|
|
138
138
|
typeof cliOpts.simd === 'boolean'
|
|
139
139
|
? cliOpts.simd
|
|
140
140
|
: (fileConfig.targets?.simd ?? DEFAULT_CONFIG.targets.simd),
|
|
141
|
+
simdFeatures: fileConfig.targets?.simdFeatures ?? null,
|
|
142
|
+
baselineFeatures: fileConfig.targets?.baselineFeatures ?? null,
|
|
141
143
|
},
|
|
142
144
|
|
|
143
145
|
inline:
|
|
@@ -182,6 +184,12 @@ export function loadConfigFromCli(cliOpts = {}) {
|
|
|
182
184
|
version:
|
|
183
185
|
fileConfig.wasmDelivery?.version ?? fileConfig.version ?? 'latest',
|
|
184
186
|
},
|
|
187
|
+
|
|
188
|
+
// SIMD variant configuration
|
|
189
|
+
simd: fileConfig.simd ?? null,
|
|
190
|
+
|
|
191
|
+
// Benchmark configuration
|
|
192
|
+
bench: fileConfig.bench ?? null,
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
return config
|
package/src/cli/emit.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
2
|
+
import { join, extname } from 'node:path'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
3
4
|
import { fileURLToPath } from 'node:url'
|
|
4
5
|
|
|
5
6
|
const UTIL_PATH = fileURLToPath(new URL('../js/util.js', import.meta.url))
|
|
7
|
+
const require = createRequire(import.meta.url)
|
|
8
|
+
const TS_EXTS = new Set(['.ts', '.tsx', '.cts', '.mts'])
|
|
6
9
|
|
|
7
10
|
export function buildWrapperIR(exportsList) {
|
|
8
11
|
return exportsList.map((entry) => {
|
|
@@ -449,7 +452,10 @@ export function code() {
|
|
|
449
452
|
}
|
|
450
453
|
|
|
451
454
|
export function createLoaderTypes({ exportFrom }) {
|
|
452
|
-
return `export
|
|
455
|
+
return `export interface InitOptions {
|
|
456
|
+
backend?: 'auto' | 'simd' | 'base';
|
|
457
|
+
}
|
|
458
|
+
export function init(imports?: WebAssembly.Imports, opts?: InitOptions): Promise<void>;
|
|
453
459
|
export * from "${exportFrom}";
|
|
454
460
|
`
|
|
455
461
|
}
|
|
@@ -461,14 +467,17 @@ export function createLoader({ exportFrom, autoInit, getBytesSrc }) {
|
|
|
461
467
|
: '\nregisterInit(init);'
|
|
462
468
|
|
|
463
469
|
return `import { setInstance, registerInit } from "./core.js";
|
|
464
|
-
import {
|
|
470
|
+
import { instantiateWithBackend } from "./util.js";
|
|
465
471
|
${getBytesSrc}
|
|
466
472
|
|
|
467
473
|
let _ready = null;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
474
|
+
let _backend = null;
|
|
475
|
+
export function init(imports = {}, opts = {}) {
|
|
476
|
+
const backend = opts.backend || 'auto';
|
|
477
|
+
if (_ready && _backend === backend) return _ready;
|
|
478
|
+
_backend = backend;
|
|
479
|
+
return (_ready = (async () => {
|
|
480
|
+
const { instance } = await instantiateWithBackend({ getSimdBytes, getBaseBytes, imports, backend });
|
|
472
481
|
setInstance(instance);
|
|
473
482
|
})());
|
|
474
483
|
}
|
|
@@ -495,10 +504,14 @@ function createBrowserLoader({ name, autoInit, customJs, wasmDelivery }) {
|
|
|
495
504
|
const simdUrl = ${simdUrl};
|
|
496
505
|
const baseUrl = ${baseUrl};
|
|
497
506
|
|
|
498
|
-
async function
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
507
|
+
async function getSimdBytes() {
|
|
508
|
+
const res = await fetch(simdUrl);
|
|
509
|
+
return res.arrayBuffer();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function getBaseBytes() {
|
|
513
|
+
const res = await fetch(baseUrl);
|
|
514
|
+
return res.arrayBuffer();
|
|
502
515
|
}
|
|
503
516
|
`
|
|
504
517
|
return createLoader({ exportFrom, autoInit, getBytesSrc })
|
|
@@ -513,9 +526,12 @@ import { fileURLToPath } from "node:url";
|
|
|
513
526
|
const simdPath = fileURLToPath(new URL("./wasm/${name}.simd.wasm", import.meta.url));
|
|
514
527
|
const basePath = fileURLToPath(new URL("./wasm/${name}.base.wasm", import.meta.url));
|
|
515
528
|
|
|
516
|
-
async function
|
|
517
|
-
|
|
518
|
-
|
|
529
|
+
async function getSimdBytes() {
|
|
530
|
+
return readFile(simdPath);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
async function getBaseBytes() {
|
|
534
|
+
return readFile(basePath);
|
|
519
535
|
}
|
|
520
536
|
`
|
|
521
537
|
return createLoader({ exportFrom, autoInit, getBytesSrc })
|
|
@@ -524,11 +540,15 @@ async function getWasmBytes() {
|
|
|
524
540
|
function createInlineLoader({ name, autoInit, customJs }) {
|
|
525
541
|
const exportFrom = customJs ? './custom.js' : './core.js'
|
|
526
542
|
const getBytesSrc = `
|
|
527
|
-
import { wasmBytes as
|
|
528
|
-
import { wasmBytes as
|
|
543
|
+
import { wasmBytes as _simdBytes } from "./wasm-inline/${name}.simd.wasm.js";
|
|
544
|
+
import { wasmBytes as _baseBytes } from "./wasm-inline/${name}.base.wasm.js";
|
|
529
545
|
|
|
530
|
-
async function
|
|
531
|
-
return
|
|
546
|
+
async function getSimdBytes() {
|
|
547
|
+
return _simdBytes;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
async function getBaseBytes() {
|
|
551
|
+
return _baseBytes;
|
|
532
552
|
}
|
|
533
553
|
`
|
|
534
554
|
return createLoader({ exportFrom, autoInit, getBytesSrc })
|
|
@@ -540,6 +560,38 @@ export const wasmBytes = new Uint8Array([${bytes.join(',')}]);
|
|
|
540
560
|
`
|
|
541
561
|
}
|
|
542
562
|
|
|
563
|
+
function loadCustomModule(crateDir, customJs) {
|
|
564
|
+
const customPath = join(crateDir, customJs)
|
|
565
|
+
const source = readFileSync(customPath, 'utf8')
|
|
566
|
+
const ext = extname(customJs).toLowerCase()
|
|
567
|
+
|
|
568
|
+
if (!TS_EXTS.has(ext)) return source
|
|
569
|
+
|
|
570
|
+
let ts
|
|
571
|
+
try {
|
|
572
|
+
ts = require('typescript')
|
|
573
|
+
} catch {
|
|
574
|
+
throw new Error(
|
|
575
|
+
"Custom TypeScript runtime requires the 'typescript' package. Install it with `npm install typescript` in your project."
|
|
576
|
+
)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const { outputText } = ts.transpileModule(source, {
|
|
580
|
+
fileName: customPath,
|
|
581
|
+
compilerOptions: {
|
|
582
|
+
module: ts.ModuleKind.ESNext,
|
|
583
|
+
target: ts.ScriptTarget.ES2020,
|
|
584
|
+
jsx: ts.JsxEmit.ReactJSX,
|
|
585
|
+
esModuleInterop: true,
|
|
586
|
+
allowSyntheticDefaultImports: true,
|
|
587
|
+
sourceMap: false,
|
|
588
|
+
},
|
|
589
|
+
reportDiagnostics: false,
|
|
590
|
+
})
|
|
591
|
+
|
|
592
|
+
return outputText
|
|
593
|
+
}
|
|
594
|
+
|
|
543
595
|
function writeInlineModules({
|
|
544
596
|
outDir,
|
|
545
597
|
artifactBaseName,
|
|
@@ -580,11 +632,11 @@ export function emitRuntime({
|
|
|
580
632
|
mkdirSync(outDir, { recursive: true })
|
|
581
633
|
|
|
582
634
|
if (customJs) {
|
|
583
|
-
const customJsContent =
|
|
635
|
+
const customJsContent = loadCustomModule(crateDir, customJs)
|
|
584
636
|
writeFileSync(join(outDir, 'custom.js'), customJsContent)
|
|
585
637
|
|
|
586
638
|
if (emitTypes) {
|
|
587
|
-
const customTsPath = customJs.replace(/\.
|
|
639
|
+
const customTsPath = customJs.replace(/\.[^.]+$/, '.d.ts')
|
|
588
640
|
if (existsSync(join(crateDir, customTsPath))) {
|
|
589
641
|
writeFileSync(
|
|
590
642
|
join(outDir, 'custom.d.ts'),
|
package/src/cli/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { loadConfigFromCli, summarizeConfig } from './config.js'
|
|
|
3
3
|
import { buildArtifacts } from './build.js'
|
|
4
4
|
import { emitRuntime } from './emit.js'
|
|
5
5
|
import { updatePackageJson } from './pkg.js'
|
|
6
|
+
import { runBench } from './bench.js'
|
|
6
7
|
|
|
7
8
|
export async function runBuild(cliOpts) {
|
|
8
9
|
const cfg = loadConfigFromCli(cliOpts)
|
|
@@ -56,12 +57,19 @@ export async function runClean(cliOpts) {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
export async function runBenchCmd(cliOpts) {
|
|
61
|
+
const cfg = loadConfigFromCli(cliOpts)
|
|
62
|
+
console.log('Configuration:', summarizeConfig(cfg))
|
|
63
|
+
await runBench(cfg, cliOpts)
|
|
64
|
+
}
|
|
65
|
+
|
|
59
66
|
export function printHelp() {
|
|
60
67
|
const help = `
|
|
61
68
|
wasm-bindgen-lite <command> [options]
|
|
62
69
|
|
|
63
70
|
Commands:
|
|
64
71
|
build Build wasm artifacts and emit JS loaders (default release)
|
|
72
|
+
bench Build variant matrix and run SIMD analysis
|
|
65
73
|
clean Remove the configured output directory
|
|
66
74
|
help Show this message
|
|
67
75
|
|
|
@@ -74,7 +82,27 @@ Options (for build):
|
|
|
74
82
|
--simd | --no-simd Build SIMD variant (default: simd on)
|
|
75
83
|
--wasm-opt | --no-wasm-opt Force enable/disable wasm-opt (default: auto detect)
|
|
76
84
|
--wasm-opt-args "<args>" Extra args, default "-Oz"
|
|
77
|
-
--no-update-package-json Do not modify package.json exports
|
|
85
|
+
--no-update-package-json Do not modify package.json exports
|
|
86
|
+
|
|
87
|
+
Options (for bench):
|
|
88
|
+
--crate <path> Crate root (default: .)
|
|
89
|
+
--config <path> Path to config JSON
|
|
90
|
+
--clean Clean output directory before building
|
|
91
|
+
--skip-build Skip building, use existing variants
|
|
92
|
+
|
|
93
|
+
SIMD Configuration (in wasm-bindgen-lite.config.json):
|
|
94
|
+
{
|
|
95
|
+
"simd": {
|
|
96
|
+
"features": {
|
|
97
|
+
"explicit-simd-encode": { "name": "encode" },
|
|
98
|
+
"explicit-simd-decode": { "name": "decode" }
|
|
99
|
+
},
|
|
100
|
+
"allFeature": "explicit-simd"
|
|
101
|
+
},
|
|
102
|
+
"bench": {
|
|
103
|
+
"outputDir": "bench_out"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
78
106
|
`
|
|
79
107
|
console.log(help)
|
|
80
108
|
}
|
package/src/js/browser-inline.js
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import { wasmBytes as
|
|
2
|
-
import { wasmBytes as
|
|
1
|
+
import { wasmBytes as _simdBytes } from './wasm-inline/mod.simd.wasm.js'
|
|
2
|
+
import { wasmBytes as _baseBytes } from './wasm-inline/mod.base.wasm.js'
|
|
3
3
|
import { setInstance } from './core.js'
|
|
4
|
-
import {
|
|
4
|
+
import { instantiateWithBackend } from './util.js'
|
|
5
|
+
|
|
6
|
+
async function getSimdBytes() {
|
|
7
|
+
return _simdBytes
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function getBaseBytes() {
|
|
11
|
+
return _baseBytes
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
let _ready = null
|
|
15
|
+
let _backend = null
|
|
7
16
|
|
|
8
|
-
export function init(imports = {}) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
export function init(imports = {}, opts = {}) {
|
|
18
|
+
const backend = opts.backend || 'auto'
|
|
19
|
+
if (_ready && _backend === backend) return _ready
|
|
20
|
+
_backend = backend
|
|
21
|
+
return (_ready = (async () => {
|
|
22
|
+
const { instance } = await instantiateWithBackend({
|
|
23
|
+
getSimdBytes,
|
|
24
|
+
getBaseBytes,
|
|
25
|
+
imports,
|
|
26
|
+
backend,
|
|
27
|
+
})
|
|
15
28
|
setInstance(instance)
|
|
16
29
|
})())
|
|
17
30
|
}
|
package/src/js/browser.js
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
import { setInstance } from './core.js'
|
|
2
|
-
import {
|
|
2
|
+
import { instantiateWithBackend } from './util.js'
|
|
3
3
|
|
|
4
4
|
const simdUrl = new URL('./wasm/mod.simd.wasm', import.meta.url)
|
|
5
5
|
const baseUrl = new URL('./wasm/mod.base.wasm', import.meta.url)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
async function getSimdBytes() {
|
|
8
|
+
const res = await fetch(simdUrl)
|
|
9
|
+
return res.arrayBuffer()
|
|
10
|
+
}
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
fetch(baseUrl),
|
|
14
|
-
])
|
|
12
|
+
async function getBaseBytes() {
|
|
13
|
+
const res = await fetch(baseUrl)
|
|
14
|
+
return res.arrayBuffer()
|
|
15
|
+
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
baseRes.arrayBuffer(),
|
|
19
|
-
])
|
|
17
|
+
let _ready = null
|
|
18
|
+
let _backend = null
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
export function init(imports = {}, opts = {}) {
|
|
21
|
+
const backend = opts.backend || 'auto'
|
|
22
|
+
if (_ready && _backend === backend) return _ready
|
|
23
|
+
_backend = backend
|
|
24
|
+
return (_ready = (async () => {
|
|
25
|
+
const { instance } = await instantiateWithBackend({
|
|
26
|
+
getSimdBytes,
|
|
27
|
+
getBaseBytes,
|
|
28
|
+
imports,
|
|
29
|
+
backend,
|
|
30
|
+
})
|
|
26
31
|
setInstance(instance)
|
|
27
32
|
})())
|
|
28
33
|
}
|
package/src/js/node-inline.js
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import { wasmBytes as
|
|
2
|
-
import { wasmBytes as
|
|
1
|
+
import { wasmBytes as _simdBytes } from './wasm-inline/mod.simd.wasm.js'
|
|
2
|
+
import { wasmBytes as _baseBytes } from './wasm-inline/mod.base.wasm.js'
|
|
3
3
|
import { setInstance } from './core.js'
|
|
4
|
-
import {
|
|
4
|
+
import { instantiateWithBackend } from './util.js'
|
|
5
|
+
|
|
6
|
+
async function getSimdBytes() {
|
|
7
|
+
return _simdBytes
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function getBaseBytes() {
|
|
11
|
+
return _baseBytes
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
let _ready = null
|
|
15
|
+
let _backend = null
|
|
7
16
|
|
|
8
|
-
export function init(imports = {}) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
export function init(imports = {}, opts = {}) {
|
|
18
|
+
const backend = opts.backend || 'auto'
|
|
19
|
+
if (_ready && _backend === backend) return _ready
|
|
20
|
+
_backend = backend
|
|
21
|
+
return (_ready = (async () => {
|
|
22
|
+
const { instance } = await instantiateWithBackend({
|
|
23
|
+
getSimdBytes,
|
|
24
|
+
getBaseBytes,
|
|
25
|
+
imports,
|
|
26
|
+
backend,
|
|
27
|
+
})
|
|
15
28
|
setInstance(instance)
|
|
16
29
|
})())
|
|
17
30
|
}
|
package/src/js/node.js
CHANGED
|
@@ -1,24 +1,33 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { setInstance } from './core.js'
|
|
4
|
-
import {
|
|
4
|
+
import { instantiateWithBackend } from './util.js'
|
|
5
5
|
|
|
6
6
|
const simdPath = fileURLToPath(new URL('./wasm/mod.simd.wasm', import.meta.url))
|
|
7
7
|
const basePath = fileURLToPath(new URL('./wasm/mod.base.wasm', import.meta.url))
|
|
8
8
|
|
|
9
|
+
async function getSimdBytes() {
|
|
10
|
+
return readFile(simdPath)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function getBaseBytes() {
|
|
14
|
+
return readFile(basePath)
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
let _ready = null
|
|
18
|
+
let _backend = null
|
|
10
19
|
|
|
11
|
-
export function init(imports = {}) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
20
|
+
export function init(imports = {}, opts = {}) {
|
|
21
|
+
const backend = opts.backend || 'auto'
|
|
22
|
+
if (_ready && _backend === backend) return _ready
|
|
23
|
+
_backend = backend
|
|
24
|
+
return (_ready = (async () => {
|
|
25
|
+
const { instance } = await instantiateWithBackend({
|
|
26
|
+
getSimdBytes,
|
|
27
|
+
getBaseBytes,
|
|
28
|
+
imports,
|
|
29
|
+
backend,
|
|
30
|
+
})
|
|
22
31
|
setInstance(instance)
|
|
23
32
|
})())
|
|
24
33
|
}
|
package/src/js/util.js
CHANGED
|
@@ -12,3 +12,33 @@ export async function instantiateWithFallback(
|
|
|
12
12
|
return { instance, backend: 'wasm' }
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
export async function instantiateWithBackend({
|
|
17
|
+
getSimdBytes,
|
|
18
|
+
getBaseBytes,
|
|
19
|
+
imports,
|
|
20
|
+
backend = 'auto',
|
|
21
|
+
}) {
|
|
22
|
+
if (backend === 'base') {
|
|
23
|
+
const baseBytes = await getBaseBytes()
|
|
24
|
+
const { instance } = await WebAssembly.instantiate(baseBytes, imports)
|
|
25
|
+
return { instance, backend: 'wasm' }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (backend === 'simd') {
|
|
29
|
+
const simdBytes = await getSimdBytes()
|
|
30
|
+
const { instance } = await WebAssembly.instantiate(simdBytes, imports)
|
|
31
|
+
return { instance, backend: 'wasm-simd' }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// auto: try simd first, then fallback to baseline
|
|
35
|
+
try {
|
|
36
|
+
const simdBytes = await getSimdBytes()
|
|
37
|
+
const { instance } = await WebAssembly.instantiate(simdBytes, imports)
|
|
38
|
+
return { instance, backend: 'wasm-simd' }
|
|
39
|
+
} catch {
|
|
40
|
+
const baseBytes = await getBaseBytes()
|
|
41
|
+
const { instance } = await WebAssembly.instantiate(baseBytes, imports)
|
|
42
|
+
return { instance, backend: 'wasm' }
|
|
43
|
+
}
|
|
44
|
+
}
|