Skip to content

Commit 03a0621

Browse files
committed
Add Dart-flute-todomvc in addition to complex
Update to the latest wasm_gc_benchmarks commit, and pull in the todomvc benchmark too. I had to update the benchmark runner polyfill. I just copy pasted things from tools/run_wasm.js until it worked for me. This part likely needs some filtering and clean up.
1 parent e803e0b commit 03a0621

11 files changed

+1020
-3339
lines changed

Dart/benchmark.js

Lines changed: 252 additions & 225 deletions
Large diffs are not rendered by default.

Dart/build.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Built on 2025-03-06 09:52:17+01:00
1+
Built on Mon Jul 21 11:06:59 CDT 2025
22
Cloning into 'wasm_gc_benchmarks'...
3-
f80892d Update Dart SDK, switch wasm to -O2, recompile performance benchmarks
3+
0fc62a9 Roll third_party/flute, rename benchmarks/{flute->flute.complex}.dart, add benchmarks/flute.todomvc.dart
44
Copying files from wasm_gc_benchmarks/ into build/
55
Build success

Dart/build.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ rm -rf wasm_gc_benchmarks/
77
rm -rf build/
88

99
BUILD_LOG="$(realpath build.log)"
10-
echo -e "Built on $(date --rfc-3339=seconds)" | tee "$BUILD_LOG"
10+
echo -e "Built on $(date)" | tee "$BUILD_LOG"
1111

12-
git clone https://github.com/mkustermann/wasm_gc_benchmarks |& tee -a "$BUILD_LOG"
12+
git clone https://github.com/mkustermann/wasm_gc_benchmarks 2>&1 | tee -a "$BUILD_LOG"
1313
pushd wasm_gc_benchmarks/
1414
git log -1 --oneline | tee -a "$BUILD_LOG"
1515
popd
@@ -19,7 +19,10 @@ mkdir -p build/ | tee -a "$BUILD_LOG"
1919
# Generic Dart2wasm runner.
2020
cp wasm_gc_benchmarks/tools/run_wasm.js build/ | tee -a "$BUILD_LOG"
2121
# "Flute Complex" benchmark application.
22-
cp wasm_gc_benchmarks/benchmarks-out/flute.dart2wasm.{mjs,wasm} build/ | tee -a "$BUILD_LOG"
22+
# cp wasm_gc_benchmarks/benchmarks-out/flute.complex.dart2wasm.mjs build/flute.dart2wasm.mjs | tee -a "$BUILD_LOG"
23+
# cp wasm_gc_benchmarks/benchmarks-out/flute.complex.dart2wasm.wasm build/flute.dart2wasm.wasm | tee -a "$BUILD_LOG"
24+
cp wasm_gc_benchmarks/benchmarks-out/flute.complex.dart2wasm.{mjs,wasm} build/ | tee -a "$BUILD_LOG"
25+
cp wasm_gc_benchmarks/benchmarks-out/flute.todomvc.dart2wasm.{mjs,wasm} build/ | tee -a "$BUILD_LOG"
2326

2427
echo "Build success" | tee -a "$BUILD_LOG"
2528

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
// Compiles a dart2wasm-generated main module from `source` which can then
2+
// instantiatable via the `instantiate` method.
3+
//
4+
// `source` needs to be a `Response` object (or promise thereof) e.g. created
5+
// via the `fetch()` JS API.
6+
export async function compileStreaming(source) {
7+
const builtins = {builtins: ['js-string']};
8+
return new CompiledApp(
9+
await WebAssembly.compileStreaming(source, builtins), builtins);
10+
}
11+
12+
// Compiles a dart2wasm-generated wasm modules from `bytes` which is then
13+
// instantiatable via the `instantiate` method.
14+
export async function compile(bytes) {
15+
const builtins = {builtins: ['js-string']};
16+
return new CompiledApp(await WebAssembly.compile(bytes, builtins), builtins);
17+
}
18+
19+
// DEPRECATED: Please use `compile` or `compileStreaming` to get a compiled app,
20+
// use `instantiate` method to get an instantiated app and then call
21+
// `invokeMain` to invoke the main function.
22+
export async function instantiate(modulePromise, importObjectPromise) {
23+
var moduleOrCompiledApp = await modulePromise;
24+
if (!(moduleOrCompiledApp instanceof CompiledApp)) {
25+
moduleOrCompiledApp = new CompiledApp(moduleOrCompiledApp);
26+
}
27+
const instantiatedApp = await moduleOrCompiledApp.instantiate(await importObjectPromise);
28+
return instantiatedApp.instantiatedModule;
29+
}
30+
31+
// DEPRECATED: Please use `compile` or `compileStreaming` to get a compiled app,
32+
// use `instantiate` method to get an instantiated app and then call
33+
// `invokeMain` to invoke the main function.
34+
export const invoke = (moduleInstance, ...args) => {
35+
moduleInstance.exports.$invokeMain(args);
36+
}
37+
38+
class CompiledApp {
39+
constructor(module, builtins) {
40+
this.module = module;
41+
this.builtins = builtins;
42+
}
43+
44+
// The second argument is an options object containing:
45+
// `loadDeferredWasm` is a JS function that takes a module name matching a
46+
// wasm file produced by the dart2wasm compiler and returns the bytes to
47+
// load the module. These bytes can be in either a format supported by
48+
// `WebAssembly.compile` or `WebAssembly.compileStreaming`.
49+
// `loadDynamicModule` is a JS function that takes two string names matching,
50+
// in order, a wasm file produced by the dart2wasm compiler during dynamic
51+
// module compilation and a corresponding js file produced by the same
52+
// compilation. It should return a JS Array containing 2 elements. The first
53+
// should be the bytes for the wasm module in a format supported by
54+
// `WebAssembly.compile` or `WebAssembly.compileStreaming`. The second
55+
// should be the result of using the JS 'import' API on the js file path.
56+
async instantiate(additionalImports, {loadDeferredWasm, loadDynamicModule} = {}) {
57+
let dartInstance;
58+
59+
// Prints to the console
60+
function printToConsole(value) {
61+
if (typeof dartPrint == "function") {
62+
dartPrint(value);
63+
return;
64+
}
65+
if (typeof console == "object" && typeof console.log != "undefined") {
66+
console.log(value);
67+
return;
68+
}
69+
if (typeof print == "function") {
70+
print(value);
71+
return;
72+
}
73+
74+
throw "Unable to print message: " + value;
75+
}
76+
77+
// A special symbol attached to functions that wrap Dart functions.
78+
const jsWrappedDartFunctionSymbol = Symbol("JSWrappedDartFunction");
79+
80+
function finalizeWrapper(dartFunction, wrapped) {
81+
wrapped.dartFunction = dartFunction;
82+
wrapped[jsWrappedDartFunctionSymbol] = true;
83+
return wrapped;
84+
}
85+
86+
// Imports
87+
const dart2wasm = {
88+
_4: (o, c) => o instanceof c,
89+
_6: (o,s,v) => o[s] = v,
90+
_39: x0 => x0.length,
91+
_41: (x0,x1) => x0[x1],
92+
_69: () => Symbol("jsBoxedDartObjectProperty"),
93+
_70: (decoder, codeUnits) => decoder.decode(codeUnits),
94+
_71: () => new TextDecoder("utf-8", {fatal: true}),
95+
_72: () => new TextDecoder("utf-8", {fatal: false}),
96+
_73: (s) => +s,
97+
_74: Date.now,
98+
_76: s => new Date(s * 1000).getTimezoneOffset() * 60,
99+
_77: s => {
100+
if (!/^\s*[+-]?(?:Infinity|NaN|(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(s)) {
101+
return NaN;
102+
}
103+
return parseFloat(s);
104+
},
105+
_78: () => {
106+
let stackString = new Error().stack.toString();
107+
let frames = stackString.split('\n');
108+
let drop = 2;
109+
if (frames[0] === 'Error') {
110+
drop += 1;
111+
}
112+
return frames.slice(drop).join('\n');
113+
},
114+
_79: () => typeof dartUseDateNowForTicks !== "undefined",
115+
_80: () => 1000 * performance.now(),
116+
_81: () => Date.now(),
117+
_84: () => new WeakMap(),
118+
_85: (map, o) => map.get(o),
119+
_86: (map, o, v) => map.set(o, v),
120+
_99: s => JSON.stringify(s),
121+
_100: s => printToConsole(s),
122+
_101: (o, p, r) => o.replaceAll(p, () => r),
123+
_103: Function.prototype.call.bind(String.prototype.toLowerCase),
124+
_104: s => s.toUpperCase(),
125+
_105: s => s.trim(),
126+
_106: s => s.trimLeft(),
127+
_107: s => s.trimRight(),
128+
_108: (string, times) => string.repeat(times),
129+
_109: Function.prototype.call.bind(String.prototype.indexOf),
130+
_110: (s, p, i) => s.lastIndexOf(p, i),
131+
_111: (string, token) => string.split(token),
132+
_112: Object.is,
133+
_113: o => o instanceof Array,
134+
_118: a => a.pop(),
135+
_119: (a, i) => a.splice(i, 1),
136+
_120: (a, s) => a.join(s),
137+
_121: (a, s, e) => a.slice(s, e),
138+
_124: a => a.length,
139+
_126: (a, i) => a[i],
140+
_127: (a, i, v) => a[i] = v,
141+
_130: (o, offsetInBytes, lengthInBytes) => {
142+
var dst = new ArrayBuffer(lengthInBytes);
143+
new Uint8Array(dst).set(new Uint8Array(o, offsetInBytes, lengthInBytes));
144+
return new DataView(dst);
145+
},
146+
_132: o => o instanceof Uint8Array,
147+
_133: (o, start, length) => new Uint8Array(o.buffer, o.byteOffset + start, length),
148+
_135: (o, start, length) => new Int8Array(o.buffer, o.byteOffset + start, length),
149+
_137: (o, start, length) => new Uint8ClampedArray(o.buffer, o.byteOffset + start, length),
150+
_139: (o, start, length) => new Uint16Array(o.buffer, o.byteOffset + start, length),
151+
_141: (o, start, length) => new Int16Array(o.buffer, o.byteOffset + start, length),
152+
_143: (o, start, length) => new Uint32Array(o.buffer, o.byteOffset + start, length),
153+
_145: (o, start, length) => new Int32Array(o.buffer, o.byteOffset + start, length),
154+
_147: (o, start, length) => new BigInt64Array(o.buffer, o.byteOffset + start, length),
155+
_149: (o, start, length) => new Float32Array(o.buffer, o.byteOffset + start, length),
156+
_151: (o, start, length) => new Float64Array(o.buffer, o.byteOffset + start, length),
157+
_152: (t, s) => t.set(s),
158+
_154: (o) => new DataView(o.buffer, o.byteOffset, o.byteLength),
159+
_156: o => o.buffer,
160+
_157: o => o.byteOffset,
161+
_158: Function.prototype.call.bind(Object.getOwnPropertyDescriptor(DataView.prototype, 'byteLength').get),
162+
_159: (b, o) => new DataView(b, o),
163+
_160: (b, o, l) => new DataView(b, o, l),
164+
_161: Function.prototype.call.bind(DataView.prototype.getUint8),
165+
_162: Function.prototype.call.bind(DataView.prototype.setUint8),
166+
_163: Function.prototype.call.bind(DataView.prototype.getInt8),
167+
_164: Function.prototype.call.bind(DataView.prototype.setInt8),
168+
_165: Function.prototype.call.bind(DataView.prototype.getUint16),
169+
_166: Function.prototype.call.bind(DataView.prototype.setUint16),
170+
_167: Function.prototype.call.bind(DataView.prototype.getInt16),
171+
_168: Function.prototype.call.bind(DataView.prototype.setInt16),
172+
_169: Function.prototype.call.bind(DataView.prototype.getUint32),
173+
_170: Function.prototype.call.bind(DataView.prototype.setUint32),
174+
_171: Function.prototype.call.bind(DataView.prototype.getInt32),
175+
_172: Function.prototype.call.bind(DataView.prototype.setInt32),
176+
_175: Function.prototype.call.bind(DataView.prototype.getBigInt64),
177+
_176: Function.prototype.call.bind(DataView.prototype.setBigInt64),
178+
_177: Function.prototype.call.bind(DataView.prototype.getFloat32),
179+
_178: Function.prototype.call.bind(DataView.prototype.setFloat32),
180+
_179: Function.prototype.call.bind(DataView.prototype.getFloat64),
181+
_180: Function.prototype.call.bind(DataView.prototype.setFloat64),
182+
_182: () => globalThis.performance,
183+
_183: () => globalThis.JSON,
184+
_184: x0 => x0.measure,
185+
_185: x0 => x0.mark,
186+
_186: x0 => x0.clearMeasures,
187+
_187: x0 => x0.clearMarks,
188+
_188: (x0,x1,x2,x3) => x0.measure(x1,x2,x3),
189+
_189: (x0,x1,x2) => x0.mark(x1,x2),
190+
_190: x0 => x0.clearMeasures(),
191+
_191: x0 => x0.clearMarks(),
192+
_192: (x0,x1) => x0.parse(x1),
193+
_193: (ms, c) =>
194+
setTimeout(() => dartInstance.exports.$invokeCallback(c),ms),
195+
_194: (handle) => clearTimeout(handle),
196+
_197: (c) =>
197+
queueMicrotask(() => dartInstance.exports.$invokeCallback(c)),
198+
_232: (x0,x1) => x0.matchMedia(x1),
199+
_233: (s, m) => {
200+
try {
201+
return new RegExp(s, m);
202+
} catch (e) {
203+
return String(e);
204+
}
205+
},
206+
_234: (x0,x1) => x0.exec(x1),
207+
_235: (x0,x1) => x0.test(x1),
208+
_236: x0 => x0.pop(),
209+
_238: o => o === undefined,
210+
_240: o => typeof o === 'function' && o[jsWrappedDartFunctionSymbol] === true,
211+
_243: o => o instanceof RegExp,
212+
_244: (l, r) => l === r,
213+
_245: o => o,
214+
_246: o => o,
215+
_247: o => o,
216+
_249: o => o.length,
217+
_251: (o, i) => o[i],
218+
_252: f => f.dartFunction,
219+
_253: () => ({}),
220+
_256: () => globalThis,
221+
_263: o => String(o),
222+
_265: o => {
223+
if (o === undefined) return 1;
224+
var type = typeof o;
225+
if (type === 'boolean') return 2;
226+
if (type === 'number') return 3;
227+
if (type === 'string') return 4;
228+
if (o instanceof Array) return 5;
229+
if (ArrayBuffer.isView(o)) {
230+
if (o instanceof Int8Array) return 6;
231+
if (o instanceof Uint8Array) return 7;
232+
if (o instanceof Uint8ClampedArray) return 8;
233+
if (o instanceof Int16Array) return 9;
234+
if (o instanceof Uint16Array) return 10;
235+
if (o instanceof Int32Array) return 11;
236+
if (o instanceof Uint32Array) return 12;
237+
if (o instanceof Float32Array) return 13;
238+
if (o instanceof Float64Array) return 14;
239+
if (o instanceof DataView) return 15;
240+
}
241+
if (o instanceof ArrayBuffer) return 16;
242+
return 17;
243+
},
244+
_271: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
245+
const setValue = dartInstance.exports.$wasmI8ArraySet;
246+
for (let i = 0; i < length; i++) {
247+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
248+
}
249+
},
250+
_275: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
251+
const setValue = dartInstance.exports.$wasmI32ArraySet;
252+
for (let i = 0; i < length; i++) {
253+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
254+
}
255+
},
256+
_277: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
257+
const setValue = dartInstance.exports.$wasmF32ArraySet;
258+
for (let i = 0; i < length; i++) {
259+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
260+
}
261+
},
262+
_279: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
263+
const setValue = dartInstance.exports.$wasmF64ArraySet;
264+
for (let i = 0; i < length; i++) {
265+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
266+
}
267+
},
268+
_283: x0 => x0.index,
269+
_285: x0 => x0.flags,
270+
_286: x0 => x0.multiline,
271+
_287: x0 => x0.ignoreCase,
272+
_288: x0 => x0.unicode,
273+
_289: x0 => x0.dotAll,
274+
_290: (x0,x1) => { x0.lastIndex = x1 },
275+
_292: (o, p) => o[p],
276+
_295: x0 => x0.random(),
277+
_298: () => globalThis.Math,
278+
_299: Function.prototype.call.bind(Number.prototype.toString),
279+
_300: Function.prototype.call.bind(BigInt.prototype.toString),
280+
_301: Function.prototype.call.bind(Number.prototype.toString),
281+
_302: (d, digits) => d.toFixed(digits),
282+
_2062: () => globalThis.window,
283+
_8706: x0 => x0.matches,
284+
_12689: x0 => { globalThis.window.flutterCanvasKit = x0 },
285+
286+
};
287+
288+
const baseImports = {
289+
dart2wasm: dart2wasm,
290+
Math: Math,
291+
Date: Date,
292+
Object: Object,
293+
Array: Array,
294+
Reflect: Reflect,
295+
S: new Proxy({}, { get(_, prop) { return prop; } }),
296+
297+
};
298+
299+
const jsStringPolyfill = {
300+
"charCodeAt": (s, i) => s.charCodeAt(i),
301+
"compare": (s1, s2) => {
302+
if (s1 < s2) return -1;
303+
if (s1 > s2) return 1;
304+
return 0;
305+
},
306+
"concat": (s1, s2) => s1 + s2,
307+
"equals": (s1, s2) => s1 === s2,
308+
"fromCharCode": (i) => String.fromCharCode(i),
309+
"length": (s) => s.length,
310+
"substring": (s, a, b) => s.substring(a, b),
311+
"fromCharCodeArray": (a, start, end) => {
312+
if (end <= start) return '';
313+
314+
const read = dartInstance.exports.$wasmI16ArrayGet;
315+
let result = '';
316+
let index = start;
317+
const chunkLength = Math.min(end - index, 500);
318+
let array = new Array(chunkLength);
319+
while (index < end) {
320+
const newChunkLength = Math.min(end - index, 500);
321+
for (let i = 0; i < newChunkLength; i++) {
322+
array[i] = read(a, index++);
323+
}
324+
if (newChunkLength < chunkLength) {
325+
array = array.slice(0, newChunkLength);
326+
}
327+
result += String.fromCharCode(...array);
328+
}
329+
return result;
330+
},
331+
"intoCharCodeArray": (s, a, start) => {
332+
if (s === '') return 0;
333+
334+
const write = dartInstance.exports.$wasmI16ArraySet;
335+
for (var i = 0; i < s.length; ++i) {
336+
write(a, start++, s.charCodeAt(i));
337+
}
338+
return s.length;
339+
},
340+
"test": (s) => typeof s == "string",
341+
};
342+
343+
344+
345+
346+
dartInstance = await WebAssembly.instantiate(this.module, {
347+
...baseImports,
348+
...additionalImports,
349+
350+
"wasm:js-string": jsStringPolyfill,
351+
});
352+
353+
return new InstantiatedApp(this, dartInstance);
354+
}
355+
}
356+
357+
class InstantiatedApp {
358+
constructor(compiledApp, instantiatedModule) {
359+
this.compiledApp = compiledApp;
360+
this.instantiatedModule = instantiatedModule;
361+
}
362+
363+
// Call the main function with the given arguments.
364+
invokeMain(...args) {
365+
this.instantiatedModule.exports.$invokeMain(args);
366+
}
367+
}
1.32 MB
Binary file not shown.

0 commit comments

Comments
 (0)