mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-31 17:59:03 +00:00
31fff2c9a3
* runtime: run syscall/js finalizers on wasm without a manual GC * runtime: address review feedback on finalizer idle GC * runtime: clear a finished task's args pointer so its arguments are collectable * runtime: skip the finalizer scan with a per-block registration bit * runtime: guard the finalizer registration bitmap with gcLock * testdata: cover finalizer invariants on every scheduler * main_test: limit the finalizer scheduler variants to linux and darwin * testdata: wait for the finalizer queue to drain before asserting * testdata: make the finalizer counters atomic and wait for a known drain count * runtime: add finalizer bookkeeping asserts under runtime_asserts * runtime: address finalizer GC review feedback * testdata: strengthen blocked stack finalizer test * runtime: fix finalizer cleanup edge cases * runtime: decouple wasm export scheduling from finalizers * runtime: avoid redundant wakeups for re-entrant wasm exports * runtime: simplify finalizer comments
75 lines
2.3 KiB
JavaScript
75 lines
2.3 KiB
JavaScript
const fs = require('fs');
|
|
|
|
require('../targets/wasm_exec.js');
|
|
|
|
let finalized = 0;
|
|
let backgroundRuns = 0;
|
|
let instance;
|
|
const go = new Go();
|
|
const sleepTicks = go.importObject.gojs['runtime.sleepTicks'];
|
|
let zeroRearms = 0;
|
|
go.importObject.gojs['runtime.sleepTicks'] = timeout => {
|
|
if (Number(timeout) === 0) {
|
|
zeroRearms++;
|
|
}
|
|
return sleepTicks(timeout);
|
|
};
|
|
go.importObject.tester = {
|
|
finalizerRan: () => {
|
|
finalized++;
|
|
},
|
|
backgroundRan: () => {
|
|
backgroundRuns++;
|
|
},
|
|
callNestedExport: () => {
|
|
instance.exports.launchBackground();
|
|
},
|
|
};
|
|
|
|
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then(async result => {
|
|
instance = result.instance;
|
|
await go.run(instance);
|
|
|
|
const topLevelRearms = zeroRearms;
|
|
instance.exports.launchBackground();
|
|
if (backgroundRuns !== 0) {
|
|
throw new Error('wasm export ran a background goroutine before returning');
|
|
}
|
|
if (zeroRearms !== topLevelRearms + 1) {
|
|
throw new Error('top-level wasm export did not schedule exactly one wakeup');
|
|
}
|
|
for (let i = 0; i < 500 && backgroundRuns === 0; i++) {
|
|
await new Promise(resolve => setTimeout(resolve, 1));
|
|
}
|
|
if (backgroundRuns !== 1) {
|
|
throw new Error('wasm scheduler did not resume after an export without finalizers');
|
|
}
|
|
|
|
instance.exports.installNestedCallback();
|
|
const nestedRearms = zeroRearms;
|
|
global.nestedExportCallback();
|
|
if (zeroRearms !== nestedRearms) {
|
|
throw new Error('re-entrant wasm export scheduled a redundant wakeup');
|
|
}
|
|
if (backgroundRuns !== 2) {
|
|
throw new Error('outer scheduler did not drain work from a re-entrant wasm export');
|
|
}
|
|
|
|
instance.exports.registerFinalizers();
|
|
if (backgroundRuns !== 2) {
|
|
throw new Error('wasm export ran an unrelated goroutine before returning');
|
|
}
|
|
for (let i = 0; i < 500 && (finalized === 0 || backgroundRuns < 3); i++) {
|
|
await new Promise(resolve => setTimeout(resolve, 1));
|
|
}
|
|
if (finalized === 0) {
|
|
throw new Error('no wasm-export finalizer ran after returning to JavaScript');
|
|
}
|
|
if (backgroundRuns !== 3) {
|
|
throw new Error('wasm scheduler did not resume after a finalizer export');
|
|
}
|
|
}).catch(err => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|