@bytecodealliance/jco 1.10.2 → 1.11.1

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/src/cmd/opt.js CHANGED
@@ -1,61 +1,61 @@
1
- import { $init, tools } from "../../obj/wasm-tools.js";
1
+ import { $init, tools } from '../../obj/wasm-tools.js';
2
2
  const { metadataShow, print } = tools;
3
- import { writeFile } from "fs/promises";
4
- import { fileURLToPath } from "url";
5
- import c from "chalk-template";
3
+ import { writeFile } from 'fs/promises';
4
+ import { fileURLToPath } from 'url';
5
+ import c from 'chalk-template';
6
6
  import {
7
- readFile,
8
- sizeStr,
9
- fixedDigitDisplay,
10
- table,
11
- spawnIOTmp,
12
- setShowSpinner,
13
- getShowSpinner,
14
- } from "../common.js";
15
- import ora from "#ora";
7
+ readFile,
8
+ sizeStr,
9
+ fixedDigitDisplay,
10
+ table,
11
+ spawnIOTmp,
12
+ setShowSpinner,
13
+ getShowSpinner,
14
+ } from '../common.js';
15
+ import ora from '#ora';
16
16
 
17
17
  export async function opt(componentPath, opts, program) {
18
- await $init;
19
- const varIdx = program.parent.rawArgs.indexOf("--");
20
- if (varIdx !== -1) opts.optArgs = program.parent.rawArgs.slice(varIdx + 1);
21
- const componentBytes = await readFile(componentPath);
18
+ await $init;
19
+ const varIdx = program.parent.rawArgs.indexOf('--');
20
+ if (varIdx !== -1) opts.optArgs = program.parent.rawArgs.slice(varIdx + 1);
21
+ const componentBytes = await readFile(componentPath);
22
22
 
23
- if (!opts.quiet) setShowSpinner(true);
24
- const optPromise = optimizeComponent(componentBytes, opts);
25
- const { component, compressionInfo } = await optPromise;
23
+ if (!opts.quiet) setShowSpinner(true);
24
+ const optPromise = optimizeComponent(componentBytes, opts);
25
+ const { component, compressionInfo } = await optPromise;
26
26
 
27
- await writeFile(opts.output, component);
27
+ await writeFile(opts.output, component);
28
28
 
29
- let totalBeforeBytes = 0,
30
- totalAfterBytes = 0;
29
+ let totalBeforeBytes = 0,
30
+ totalAfterBytes = 0;
31
31
 
32
- if (!opts.quiet)
33
- console.log(c`
32
+ if (!opts.quiet)
33
+ console.log(c`
34
34
  {bold Optimized WebAssembly Component Internal Core Modules:}
35
35
 
36
36
  ${table(
37
- [
38
- ...compressionInfo.map(({ beforeBytes, afterBytes }, i) => {
39
- totalBeforeBytes += beforeBytes;
40
- totalAfterBytes += afterBytes;
41
- return [
42
- ` - Core Module ${i + 1}: `,
43
- sizeStr(beforeBytes),
44
- " -> ",
45
- c`{cyan ${sizeStr(afterBytes)}} `,
46
- `(${fixedDigitDisplay((afterBytes / beforeBytes) * 100, 2)}%)`,
47
- ];
48
- }),
49
- ["", "", "", "", ""],
50
37
  [
51
- ` = Total: `,
52
- `${sizeStr(totalBeforeBytes)}`,
53
- ` => `,
54
- c`{cyan ${sizeStr(totalAfterBytes)}} `,
55
- `(${fixedDigitDisplay((totalAfterBytes / totalBeforeBytes) * 100, 2)}%)`,
38
+ ...compressionInfo.map(({ beforeBytes, afterBytes }, i) => {
39
+ totalBeforeBytes += beforeBytes;
40
+ totalAfterBytes += afterBytes;
41
+ return [
42
+ ` - Core Module ${i + 1}: `,
43
+ sizeStr(beforeBytes),
44
+ ' -> ',
45
+ c`{cyan ${sizeStr(afterBytes)}} `,
46
+ `(${fixedDigitDisplay((afterBytes / beforeBytes) * 100, 2)}%)`,
47
+ ];
48
+ }),
49
+ ['', '', '', '', ''],
50
+ [
51
+ ` = Total: `,
52
+ `${sizeStr(totalBeforeBytes)}`,
53
+ ` => `,
54
+ c`{cyan ${sizeStr(totalAfterBytes)}} `,
55
+ `(${fixedDigitDisplay((totalAfterBytes / totalBeforeBytes) * 100, 2)}%)`,
56
+ ],
56
57
  ],
57
- ],
58
- [, , , , "right"]
58
+ [, , , , 'right']
59
59
  )}`);
60
60
  }
61
61
 
@@ -65,12 +65,12 @@ ${table(
65
65
  * @returns {number}
66
66
  */
67
67
  function byteLengthLEB128(val) {
68
- let len = 0;
69
- do {
70
- val >>>= 7;
71
- len++;
72
- } while (val !== 0);
73
- return len;
68
+ let len = 0;
69
+ do {
70
+ val >>>= 7;
71
+ len++;
72
+ } while (val !== 0);
73
+ return len;
74
74
  }
75
75
 
76
76
  /**
@@ -80,165 +80,190 @@ function byteLengthLEB128(val) {
80
80
  * @returns {Promise<{ component: Uint8Array, compressionInfo: { beforeBytes: number, afterBytes: number }[] >}
81
81
  */
82
82
  export async function optimizeComponent(componentBytes, opts) {
83
- await $init;
84
- const showSpinner = getShowSpinner();
85
- let spinner;
86
- try {
87
- let componentMetadata = metadataShow(componentBytes);
88
- componentMetadata.forEach((metadata, index) => {
89
- // add index to the metadata object
90
- metadata.index = index;
91
- const size = metadata.range[1] - metadata.range[0];
92
- // compute previous LEB128 encoding length
93
- metadata.prevLEBLen = byteLengthLEB128(size);
94
- });
95
- const coreModules = componentMetadata
96
- .filter(({ metaType }) => metaType.tag === "module");
83
+ await $init;
84
+ const showSpinner = getShowSpinner();
85
+ let spinner;
86
+ try {
87
+ let componentMetadata = metadataShow(componentBytes);
88
+ componentMetadata.forEach((metadata, index) => {
89
+ // add index to the metadata object
90
+ metadata.index = index;
91
+ const size = metadata.range[1] - metadata.range[0];
92
+ // compute previous LEB128 encoding length
93
+ metadata.prevLEBLen = byteLengthLEB128(size);
94
+ });
95
+ const coreModules = componentMetadata.filter(
96
+ ({ metaType }) => metaType.tag === 'module'
97
+ );
97
98
 
98
- // log number of core Wasm modules to be run with wasm-opt
99
- let completed = 0;
100
- const spinnerText = () =>
101
- c`{cyan ${completed} / ${coreModules.length}} Running Binaryen on WebAssembly Component Internal Core Modules \n`;
102
- if (showSpinner) {
103
- spinner = ora({
104
- color: "cyan",
105
- spinner: "bouncingBar",
106
- }).start();
107
- spinner.text = spinnerText();
108
- }
99
+ // log number of core Wasm modules to be run with wasm-opt
100
+ let completed = 0;
101
+ const spinnerText = () =>
102
+ c`{cyan ${completed} / ${coreModules.length}} Running Binaryen on WebAssembly Component Internal Core Modules \n`;
103
+ if (showSpinner) {
104
+ spinner = ora({
105
+ color: 'cyan',
106
+ spinner: 'bouncingBar',
107
+ }).start();
108
+ spinner.text = spinnerText();
109
+ }
109
110
 
110
- // gather the options for wasm-opt. optionally, adding the asyncify flag
111
- const args = opts?.optArgs ?
112
- [...opts.optArgs] :
113
- ['-Oz', '--low-memory-unused', '--enable-bulk-memory', '--strip-debug'];
114
- if (opts?.asyncify) args.push('--asyncify');
111
+ // gather the options for wasm-opt. optionally, adding the asyncify flag
112
+ const args = opts?.optArgs
113
+ ? [...opts.optArgs]
114
+ : [
115
+ '-Oz',
116
+ '--low-memory-unused',
117
+ '--enable-bulk-memory',
118
+ '--strip-debug',
119
+ ];
120
+ if (opts?.asyncify) args.push('--asyncify');
115
121
 
122
+ // process core Wasm modules with wasm-opt
123
+ await Promise.all(
124
+ coreModules.map(async (metadata) => {
125
+ if (metadata.metaType.tag === 'module') {
126
+ // store the wasm-opt processed module in the metadata
127
+ metadata.optimized = await wasmOpt(
128
+ componentBytes.subarray(
129
+ metadata.range[0],
130
+ metadata.range[1]
131
+ ),
132
+ args
133
+ );
116
134
 
117
- // process core Wasm modules with wasm-opt
118
- await Promise.all(
119
- coreModules.map(async (metadata) => {
120
- if (metadata.metaType.tag === "module") {
121
- // store the wasm-opt processed module in the metadata
122
- metadata.optimized = await wasmOpt(
123
- componentBytes.subarray(metadata.range[0], metadata.range[1]),
124
- args);
135
+ // compute the size change, including the change to
136
+ // the LEB128 encoding of the size change
137
+ const prevModuleSize =
138
+ metadata.range[1] - metadata.range[0];
139
+ const newModuleSize = metadata.optimized.byteLength;
140
+ metadata.newLEBLen = byteLengthLEB128(newModuleSize);
141
+ metadata.sizeChange = newModuleSize - prevModuleSize;
125
142
 
126
- // compute the size change, including the change to
127
- // the LEB128 encoding of the size change
128
- const prevModuleSize = metadata.range[1] - metadata.range[0];
129
- const newModuleSize = metadata.optimized.byteLength;
130
- metadata.newLEBLen = byteLengthLEB128(newModuleSize);
131
- metadata.sizeChange = newModuleSize - prevModuleSize;
143
+ if (spinner) {
144
+ completed++;
145
+ spinner.text = spinnerText();
146
+ }
147
+ }
148
+ })
149
+ );
132
150
 
133
- if (spinner) {
134
- completed++;
135
- spinner.text = spinnerText();
136
- }
137
- }
138
- }));
151
+ // organize components in modules into tree parent and children
152
+ const nodes = componentMetadata.slice(1);
153
+ const getChildren = (parentIndex) => {
154
+ const children = [];
155
+ for (let i = 0; i < nodes.length; i++) {
156
+ const metadata = nodes[i];
157
+ if (metadata.parentIndex === parentIndex) {
158
+ nodes.splice(i, 1); // remove from nodes
159
+ i--;
160
+ metadata.children = getChildren(metadata.index);
161
+ metadata.sizeChange = metadata.children.reduce(
162
+ (total, { prevLEBLen, newLEBLen, sizeChange }) => {
163
+ return sizeChange
164
+ ? total + sizeChange + newLEBLen - prevLEBLen
165
+ : total;
166
+ },
167
+ metadata.sizeChange || 0
168
+ );
169
+ const prevSize = metadata.range[1] - metadata.range[0];
170
+ metadata.newLEBLen = byteLengthLEB128(
171
+ prevSize + metadata.sizeChange
172
+ );
173
+ children.push(metadata);
174
+ }
175
+ }
176
+ return children;
177
+ };
178
+ const componentTree = getChildren(0);
139
179
 
140
- // organize components in modules into tree parent and children
141
- const nodes = componentMetadata.slice(1);
142
- const getChildren = (parentIndex) => {
143
- const children = [];
144
- for (let i = 0; i < nodes.length; i++) {
145
- const metadata = nodes[i];
146
- if (metadata.parentIndex === parentIndex) {
147
- nodes.splice(i, 1); // remove from nodes
148
- i--;
149
- metadata.children = getChildren(metadata.index);
150
- metadata.sizeChange = metadata.children
151
- .reduce((total, {prevLEBLen, newLEBLen, sizeChange}) => {
152
- return sizeChange ?
153
- total + sizeChange + newLEBLen - prevLEBLen :
154
- total;
180
+ // compute the total size change in the component binary
181
+ const sizeChange = componentTree.reduce(
182
+ (total, { prevLEBLen, newLEBLen, sizeChange }) => {
183
+ return total + (sizeChange || 0) + newLEBLen - prevLEBLen;
155
184
  },
156
- metadata.sizeChange || 0);
157
- const prevSize = metadata.range[1] - metadata.range[0];
158
- metadata.newLEBLen = byteLengthLEB128(prevSize + metadata.sizeChange);
159
- children.push(metadata);
160
- }
161
- }
162
- return children;
163
- };
164
- const componentTree = getChildren(0);
185
+ 0
186
+ );
187
+
188
+ let outComponentBytes = new Uint8Array(
189
+ componentBytes.byteLength + sizeChange
190
+ );
191
+ let nextReadPos = 0,
192
+ nextWritePos = 0;
165
193
 
166
- // compute the total size change in the component binary
167
- const sizeChange = componentTree
168
- .reduce((total, {prevLEBLen, newLEBLen, sizeChange}) => {
169
- return total + (sizeChange || 0) + newLEBLen - prevLEBLen;
170
- }, 0);
194
+ const write = ({
195
+ prevLEBLen,
196
+ range,
197
+ optimized,
198
+ children,
199
+ sizeChange,
200
+ }) => {
201
+ // write from the last read to the LEB byte start
202
+ outComponentBytes.set(
203
+ componentBytes.subarray(nextReadPos, range[0] - prevLEBLen),
204
+ nextWritePos
205
+ );
206
+ nextWritePos += range[0] - prevLEBLen - nextReadPos;
171
207
 
172
- let outComponentBytes = new Uint8Array(
173
- componentBytes.byteLength + sizeChange);
174
- let nextReadPos = 0, nextWritePos = 0;
208
+ // write the new LEB bytes
209
+ let val = range[1] - range[0] + sizeChange;
210
+ do {
211
+ const byte = val & 0x7f;
212
+ val >>>= 7;
213
+ outComponentBytes[nextWritePos++] =
214
+ val === 0 ? byte : byte | 0x80;
215
+ } while (val !== 0);
175
216
 
176
- const write = ({prevLEBLen, range, optimized, children, sizeChange}) => {
177
- // write from the last read to the LEB byte start
178
- outComponentBytes.set(
179
- componentBytes.subarray(nextReadPos, range[0] - prevLEBLen),
180
- nextWritePos
181
- );
182
- nextWritePos += range[0] - prevLEBLen - nextReadPos;
217
+ if (optimized) {
218
+ // write the core module
219
+ outComponentBytes.set(optimized, nextWritePos);
220
+ nextReadPos = range[1];
221
+ nextWritePos += optimized.byteLength;
222
+ } else if (children.length > 0) {
223
+ // write child components / modules
224
+ nextReadPos = range[0];
225
+ children.forEach(write);
226
+ } else {
227
+ // write component
228
+ outComponentBytes.set(
229
+ componentBytes.subarray(range[0], range[1]),
230
+ nextWritePos
231
+ );
232
+ nextReadPos = range[1];
233
+ nextWritePos += range[1] - range[0];
234
+ }
235
+ };
183
236
 
184
- // write the new LEB bytes
185
- let val = range[1] - range[0] + sizeChange;
186
- do {
187
- const byte = val & 0x7f;
188
- val >>>= 7;
189
- outComponentBytes[nextWritePos++] = val === 0 ? byte : byte | 0x80;
190
- } while (val !== 0);
237
+ // write each top-level component / module
238
+ componentTree.forEach(write);
191
239
 
192
- if (optimized) {
193
- // write the core module
194
- outComponentBytes.set(optimized, nextWritePos);
195
- nextReadPos = range[1];
196
- nextWritePos += optimized.byteLength;
197
- } else if (children.length > 0) {
198
- // write child components / modules
199
- nextReadPos = range[0];
200
- children.forEach(write);
201
- } else {
202
- // write component
240
+ // write remaining
203
241
  outComponentBytes.set(
204
- componentBytes.subarray(range[0], range[1]),
205
- nextWritePos
242
+ componentBytes.subarray(nextReadPos),
243
+ nextWritePos
206
244
  );
207
- nextReadPos = range[1];
208
- nextWritePos += range[1] - range[0];
209
- }
210
- };
211
-
212
- // write each top-level component / module
213
- componentTree.forEach(write);
214
245
 
215
- // write remaining
216
- outComponentBytes.set(
217
- componentBytes.subarray(nextReadPos),
218
- nextWritePos
219
- );
246
+ // verify it still parses ok
247
+ if (!opts?.noVerify) {
248
+ try {
249
+ await print(outComponentBytes);
250
+ } catch (e) {
251
+ throw new Error(
252
+ `Internal error performing optimization.\n${e.message}`
253
+ );
254
+ }
255
+ }
220
256
 
221
- // verify it still parses ok
222
- if (!opts?.noVerify) {
223
- try {
224
- await print(outComponentBytes);
225
- } catch (e) {
226
- throw new Error(
227
- `Internal error performing optimization.\n${e.message}`
228
- );
229
- }
257
+ return {
258
+ component: outComponentBytes,
259
+ compressionInfo: coreModules.map(({ range, optimized }) => ({
260
+ beforeBytes: range[1] - range[0],
261
+ afterBytes: optimized?.byteLength,
262
+ })),
263
+ };
264
+ } finally {
265
+ if (spinner) spinner.stop();
230
266
  }
231
-
232
- return {
233
- component: outComponentBytes,
234
- compressionInfo: coreModules.map(({range, optimized}) => ({
235
- beforeBytes: range[1] - range[0],
236
- afterBytes: optimized?.byteLength,
237
- })),
238
- };
239
- } finally {
240
- if (spinner) spinner.stop();
241
- }
242
267
  }
243
268
 
244
269
  /**
@@ -247,15 +272,21 @@ export async function optimizeComponent(componentBytes, opts) {
247
272
  * @returns {Promise<Uint8Array>}
248
273
  */
249
274
  async function wasmOpt(source, args) {
250
- const wasmOptPath = fileURLToPath(
251
- import.meta.resolve("binaryen/bin/wasm-opt")
252
- );
275
+ const wasmOptPath = fileURLToPath(
276
+ import.meta.resolve('binaryen/bin/wasm-opt')
277
+ );
278
+
279
+ try {
280
+ return await spawnIOTmp(wasmOptPath, source, [...args, '-o']);
281
+ } catch (e) {
282
+ if (e.toString().includes('BasicBlock requested'))
283
+ return wasmOpt(source, args);
284
+ throw e;
285
+ }
286
+ }
253
287
 
254
- try {
255
- return await spawnIOTmp(wasmOptPath, source, [...args, "-o"]);
256
- } catch (e) {
257
- if (e.toString().includes("BasicBlock requested"))
258
- return wasmOpt(source, args);
259
- throw e;
260
- }
288
+ // see: https://github.com/vitest-dev/vitest/issues/6953#issuecomment-2505310022
289
+ if (typeof __vite_ssr_import_meta__ !== 'undefined') {
290
+ __vite_ssr_import_meta__.resolve = (path) =>
291
+ 'file://' + globalCreateRequire(import.meta.url).resolve(path);
261
292
  }