Skip to content

Commit 03f0e64

Browse files
authored
Merge pull request #97 from eqrion/dart-todomvc
Replace Dart-flute-complex with Dart-flute-todomvc
2 parents dc051d2 + 5702d02 commit 03f0e64

11 files changed

+746
-3112
lines changed

Dart/benchmark.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class Benchmark {
282282
const framesToDraw = 100;
283283
const initialFramesToSkip = 0;
284284
const dartArgs = [
285-
startTimeSinceEpochSeconds,
285+
startTimeSinceEpochSeconds.toString(),
286286
framesToDraw.toString(),
287287
initialFramesToSkip.toString()
288288
];

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+
-e Built on Wed Aug 13 13:03:46 CDT 2025
22
Cloning into 'wasm_gc_benchmarks'...
3-
f80892d Update Dart SDK, switch wasm to -O2, recompile performance benchmarks
3+
13951e1 Roll new version of flute and regenerate flute-based benchmarks
44
Copying files from wasm_gc_benchmarks/ into build/
55
Build success

Dart/build.sh

Lines changed: 5 additions & 4 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
@@ -18,8 +18,9 @@ echo "Copying files from wasm_gc_benchmarks/ into build/" | tee -a "$BUILD_LOG"
1818
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"
21-
# "Flute Complex" benchmark application.
22-
cp wasm_gc_benchmarks/benchmarks-out/flute.dart2wasm.{mjs,wasm} build/ | tee -a "$BUILD_LOG"
21+
# Two Flute benchmark applications: complex and todomvc
22+
cp wasm_gc_benchmarks/benchmarks-out/flute.complex.dart2wasm.{mjs,wasm} build/ | tee -a "$BUILD_LOG"
23+
cp wasm_gc_benchmarks/benchmarks-out/flute.todomvc.dart2wasm.{mjs,wasm} build/ | tee -a "$BUILD_LOG"
2324

2425
echo "Build success" | tee -a "$BUILD_LOG"
2526

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
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+
_6: (o,s,v) => o[s] = v,
89+
_39: x0 => x0.length,
90+
_41: (x0,x1) => x0[x1],
91+
_69: () => Symbol("jsBoxedDartObjectProperty"),
92+
_70: (decoder, codeUnits) => decoder.decode(codeUnits),
93+
_71: () => new TextDecoder("utf-8", {fatal: true}),
94+
_72: () => new TextDecoder("utf-8", {fatal: false}),
95+
_73: (s) => +s,
96+
_74: Date.now,
97+
_76: s => new Date(s * 1000).getTimezoneOffset() * 60,
98+
_77: s => {
99+
if (!/^\s*[+-]?(?:Infinity|NaN|(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(s)) {
100+
return NaN;
101+
}
102+
return parseFloat(s);
103+
},
104+
_78: () => {
105+
let stackString = new Error().stack.toString();
106+
let frames = stackString.split('\n');
107+
let drop = 2;
108+
if (frames[0] === 'Error') {
109+
drop += 1;
110+
}
111+
return frames.slice(drop).join('\n');
112+
},
113+
_79: () => typeof dartUseDateNowForTicks !== "undefined",
114+
_80: () => 1000 * performance.now(),
115+
_81: () => Date.now(),
116+
_84: () => new WeakMap(),
117+
_85: (map, o) => map.get(o),
118+
_86: (map, o, v) => map.set(o, v),
119+
_99: s => JSON.stringify(s),
120+
_100: s => printToConsole(s),
121+
_101: (o, p, r) => o.replaceAll(p, () => r),
122+
_103: Function.prototype.call.bind(String.prototype.toLowerCase),
123+
_104: s => s.toUpperCase(),
124+
_105: s => s.trim(),
125+
_106: s => s.trimLeft(),
126+
_107: s => s.trimRight(),
127+
_108: (string, times) => string.repeat(times),
128+
_109: Function.prototype.call.bind(String.prototype.indexOf),
129+
_110: (s, p, i) => s.lastIndexOf(p, i),
130+
_111: (string, token) => string.split(token),
131+
_112: Object.is,
132+
_113: o => o instanceof Array,
133+
_118: a => a.pop(),
134+
_119: (a, i) => a.splice(i, 1),
135+
_120: (a, s) => a.join(s),
136+
_121: (a, s, e) => a.slice(s, e),
137+
_124: a => a.length,
138+
_126: (a, i) => a[i],
139+
_127: (a, i, v) => a[i] = v,
140+
_130: (o, offsetInBytes, lengthInBytes) => {
141+
var dst = new ArrayBuffer(lengthInBytes);
142+
new Uint8Array(dst).set(new Uint8Array(o, offsetInBytes, lengthInBytes));
143+
return new DataView(dst);
144+
},
145+
_132: o => o instanceof Uint8Array,
146+
_133: (o, start, length) => new Uint8Array(o.buffer, o.byteOffset + start, length),
147+
_135: (o, start, length) => new Int8Array(o.buffer, o.byteOffset + start, length),
148+
_137: (o, start, length) => new Uint8ClampedArray(o.buffer, o.byteOffset + start, length),
149+
_139: (o, start, length) => new Uint16Array(o.buffer, o.byteOffset + start, length),
150+
_141: (o, start, length) => new Int16Array(o.buffer, o.byteOffset + start, length),
151+
_143: (o, start, length) => new Uint32Array(o.buffer, o.byteOffset + start, length),
152+
_145: (o, start, length) => new Int32Array(o.buffer, o.byteOffset + start, length),
153+
_147: (o, start, length) => new BigInt64Array(o.buffer, o.byteOffset + start, length),
154+
_149: (o, start, length) => new Float32Array(o.buffer, o.byteOffset + start, length),
155+
_151: (o, start, length) => new Float64Array(o.buffer, o.byteOffset + start, length),
156+
_152: (t, s) => t.set(s),
157+
_154: (o) => new DataView(o.buffer, o.byteOffset, o.byteLength),
158+
_156: o => o.buffer,
159+
_157: o => o.byteOffset,
160+
_158: Function.prototype.call.bind(Object.getOwnPropertyDescriptor(DataView.prototype, 'byteLength').get),
161+
_159: (b, o) => new DataView(b, o),
162+
_160: (b, o, l) => new DataView(b, o, l),
163+
_161: Function.prototype.call.bind(DataView.prototype.getUint8),
164+
_162: Function.prototype.call.bind(DataView.prototype.setUint8),
165+
_163: Function.prototype.call.bind(DataView.prototype.getInt8),
166+
_164: Function.prototype.call.bind(DataView.prototype.setInt8),
167+
_165: Function.prototype.call.bind(DataView.prototype.getUint16),
168+
_166: Function.prototype.call.bind(DataView.prototype.setUint16),
169+
_167: Function.prototype.call.bind(DataView.prototype.getInt16),
170+
_168: Function.prototype.call.bind(DataView.prototype.setInt16),
171+
_169: Function.prototype.call.bind(DataView.prototype.getUint32),
172+
_170: Function.prototype.call.bind(DataView.prototype.setUint32),
173+
_171: Function.prototype.call.bind(DataView.prototype.getInt32),
174+
_172: Function.prototype.call.bind(DataView.prototype.setInt32),
175+
_175: Function.prototype.call.bind(DataView.prototype.getBigInt64),
176+
_176: Function.prototype.call.bind(DataView.prototype.setBigInt64),
177+
_177: Function.prototype.call.bind(DataView.prototype.getFloat32),
178+
_178: Function.prototype.call.bind(DataView.prototype.setFloat32),
179+
_179: Function.prototype.call.bind(DataView.prototype.getFloat64),
180+
_180: Function.prototype.call.bind(DataView.prototype.setFloat64),
181+
_193: (ms, c) =>
182+
setTimeout(() => dartInstance.exports.$invokeCallback(c),ms),
183+
_194: (handle) => clearTimeout(handle),
184+
_197: (c) =>
185+
queueMicrotask(() => dartInstance.exports.$invokeCallback(c)),
186+
_232: (x0,x1) => x0.matchMedia(x1),
187+
_233: (s, m) => {
188+
try {
189+
return new RegExp(s, m);
190+
} catch (e) {
191+
return String(e);
192+
}
193+
},
194+
_234: (x0,x1) => x0.exec(x1),
195+
_235: (x0,x1) => x0.test(x1),
196+
_236: x0 => x0.pop(),
197+
_238: o => o === undefined,
198+
_240: o => typeof o === 'function' && o[jsWrappedDartFunctionSymbol] === true,
199+
_243: o => o instanceof RegExp,
200+
_244: (l, r) => l === r,
201+
_245: o => o,
202+
_246: o => o,
203+
_247: o => o,
204+
_249: o => o.length,
205+
_251: (o, i) => o[i],
206+
_252: f => f.dartFunction,
207+
_253: () => ({}),
208+
_263: o => String(o),
209+
_265: o => {
210+
if (o === undefined) return 1;
211+
var type = typeof o;
212+
if (type === 'boolean') return 2;
213+
if (type === 'number') return 3;
214+
if (type === 'string') return 4;
215+
if (o instanceof Array) return 5;
216+
if (ArrayBuffer.isView(o)) {
217+
if (o instanceof Int8Array) return 6;
218+
if (o instanceof Uint8Array) return 7;
219+
if (o instanceof Uint8ClampedArray) return 8;
220+
if (o instanceof Int16Array) return 9;
221+
if (o instanceof Uint16Array) return 10;
222+
if (o instanceof Int32Array) return 11;
223+
if (o instanceof Uint32Array) return 12;
224+
if (o instanceof Float32Array) return 13;
225+
if (o instanceof Float64Array) return 14;
226+
if (o instanceof DataView) return 15;
227+
}
228+
if (o instanceof ArrayBuffer) return 16;
229+
// Feature check for `SharedArrayBuffer` before doing a type-check.
230+
if (globalThis.SharedArrayBuffer !== undefined &&
231+
o instanceof SharedArrayBuffer) {
232+
return 17;
233+
}
234+
return 18;
235+
},
236+
_271: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
237+
const setValue = dartInstance.exports.$wasmI8ArraySet;
238+
for (let i = 0; i < length; i++) {
239+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
240+
}
241+
},
242+
_275: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
243+
const setValue = dartInstance.exports.$wasmI32ArraySet;
244+
for (let i = 0; i < length; i++) {
245+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
246+
}
247+
},
248+
_277: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
249+
const setValue = dartInstance.exports.$wasmF32ArraySet;
250+
for (let i = 0; i < length; i++) {
251+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
252+
}
253+
},
254+
_279: (jsArray, jsArrayOffset, wasmArray, wasmArrayOffset, length) => {
255+
const setValue = dartInstance.exports.$wasmF64ArraySet;
256+
for (let i = 0; i < length; i++) {
257+
setValue(wasmArray, wasmArrayOffset + i, jsArray[jsArrayOffset + i]);
258+
}
259+
},
260+
_283: x0 => x0.index,
261+
_285: x0 => x0.flags,
262+
_286: x0 => x0.multiline,
263+
_287: x0 => x0.ignoreCase,
264+
_288: x0 => x0.unicode,
265+
_289: x0 => x0.dotAll,
266+
_290: (x0,x1) => { x0.lastIndex = x1 },
267+
_295: x0 => x0.random(),
268+
_298: () => globalThis.Math,
269+
_299: Function.prototype.call.bind(Number.prototype.toString),
270+
_300: Function.prototype.call.bind(BigInt.prototype.toString),
271+
_301: Function.prototype.call.bind(Number.prototype.toString),
272+
_302: (d, digits) => d.toFixed(digits),
273+
_2062: () => globalThis.window,
274+
_8706: x0 => x0.matches,
275+
_12689: x0 => { globalThis.window.flutterCanvasKit = x0 },
276+
277+
};
278+
279+
const baseImports = {
280+
dart2wasm: dart2wasm,
281+
Math: Math,
282+
Date: Date,
283+
Object: Object,
284+
Array: Array,
285+
Reflect: Reflect,
286+
S: new Proxy({}, { get(_, prop) { return prop; } }),
287+
288+
};
289+
290+
const jsStringPolyfill = {
291+
"charCodeAt": (s, i) => s.charCodeAt(i),
292+
"compare": (s1, s2) => {
293+
if (s1 < s2) return -1;
294+
if (s1 > s2) return 1;
295+
return 0;
296+
},
297+
"concat": (s1, s2) => s1 + s2,
298+
"equals": (s1, s2) => s1 === s2,
299+
"fromCharCode": (i) => String.fromCharCode(i),
300+
"length": (s) => s.length,
301+
"substring": (s, a, b) => s.substring(a, b),
302+
"fromCharCodeArray": (a, start, end) => {
303+
if (end <= start) return '';
304+
305+
const read = dartInstance.exports.$wasmI16ArrayGet;
306+
let result = '';
307+
let index = start;
308+
const chunkLength = Math.min(end - index, 500);
309+
let array = new Array(chunkLength);
310+
while (index < end) {
311+
const newChunkLength = Math.min(end - index, 500);
312+
for (let i = 0; i < newChunkLength; i++) {
313+
array[i] = read(a, index++);
314+
}
315+
if (newChunkLength < chunkLength) {
316+
array = array.slice(0, newChunkLength);
317+
}
318+
result += String.fromCharCode(...array);
319+
}
320+
return result;
321+
},
322+
"intoCharCodeArray": (s, a, start) => {
323+
if (s === '') return 0;
324+
325+
const write = dartInstance.exports.$wasmI16ArraySet;
326+
for (var i = 0; i < s.length; ++i) {
327+
write(a, start++, s.charCodeAt(i));
328+
}
329+
return s.length;
330+
},
331+
"test": (s) => typeof s == "string",
332+
};
333+
334+
335+
336+
337+
dartInstance = await WebAssembly.instantiate(this.module, {
338+
...baseImports,
339+
...additionalImports,
340+
341+
"wasm:js-string": jsStringPolyfill,
342+
});
343+
344+
return new InstantiatedApp(this, dartInstance);
345+
}
346+
}
347+
348+
class InstantiatedApp {
349+
constructor(compiledApp, instantiatedModule) {
350+
this.compiledApp = compiledApp;
351+
this.instantiatedModule = instantiatedModule;
352+
}
353+
354+
// Call the main function with the given arguments.
355+
invokeMain(...args) {
356+
this.instantiatedModule.exports.$invokeMain(args);
357+
}
358+
}
1.3 MB
Binary file not shown.

0 commit comments

Comments
 (0)