Skip to content

Commit 9c98271

Browse files
committed
Only recreate instance after returning panic in wasm demo
1 parent 8a923ab commit 9c98271

File tree

3 files changed

+53
-28
lines changed

3 files changed

+53
-28
lines changed

crates/aoc_wasm/web/aoc.mjs

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ export class Aoc {
3636
#instance;
3737
/** @type {WebAssembly.Memory} */
3838
#memory;
39-
/** @type {Worker[]} */
39+
/** @type {Worker[]|undefined} */
4040
#workers;
41+
/** @type {number|undefined} */
42+
#workerCount;
4143

4244
/**
4345
* @param {WebAssembly.Module} module
@@ -101,38 +103,33 @@ export class Aoc {
101103

102104
/**
103105
* @param {WebAssembly.Module} module
104-
* @param {WebAssembly.Instance} [instance]
106+
* @param {{instance?: WebAssembly.Instance, workerCount?: number}} [options]
105107
*/
106-
constructor(module, instance) {
108+
constructor(module, options) {
109+
options ??= {};
107110
const imports = WebAssembly.Module.imports(module);
108111
if (imports.length === 0) {
109112
this.#multithreaded = false;
110113
this.#module = module;
111-
this.#instance = instance ?? new WebAssembly.Instance(module);
112-
this.#memory = this.#exports.memory;
114+
this.#instance = options.instance;
115+
if (this.#instance) this.#memory = this.#exports.memory;
116+
if (options.workerCount !== undefined) throw new Error("workerCount can only be provided for multithreaded modules");
113117
} else if (imports.length === 1 && imports[0].module === "env" && imports[0].name === "memory" && imports[0].kind === "memory") {
114118
this.#multithreaded = true;
115119
this.#module = module;
116-
if (instance) throw new Error("Instance cannot be provided for multithreaded modules");
117-
this.newInstance();
120+
this.#workers = [];
121+
this.#workerCount = options.workerCount ?? navigator.hardwareConcurrency;
122+
if (options.instance) throw new Error("instance cannot be provided for multithreaded modules");
118123
} else {
119124
throw new Error("Unsupported module");
120125
}
121126
}
122127

123-
/** @param {number} [numWorkers] */
124-
newInstance(numWorkers) {
125-
if (this.#multithreaded) {
126-
if (this.#workers?.length > 0) {
127-
// Stop existing workers
128-
for (const worker of this.#workers) {
129-
worker.terminate();
130-
}
131-
numWorkers ??= this.#workers.length;
132-
this.#workers = [];
133-
}
134-
numWorkers ??= navigator.hardwareConcurrency;
128+
newInstance() {
129+
this.stopInstance();
135130

131+
if (this.#multithreaded) {
132+
console.debug("creating multithreaded instance");
136133
this.#memory = new WebAssembly.Memory({initial: 96, maximum: 2048, shared: true});
137134
this.#instance = new WebAssembly.Instance(this.#module, {env: {memory: this.#memory}});
138135

@@ -151,21 +148,45 @@ export class Aoc {
151148
//
152149
// Allocate all the stacks at once to avoid memory growing as workers start, which seems to cause problems.
153150
const stacks = [];
154-
for (let i = 0; i < numWorkers; i++) {
151+
for (let i = 0; i < this.#workerCount; i++) {
155152
stacks.push(this.#exports.allocate_stack(stackSize + tlsSize, align));
156153
}
157154

158155
this.#workers = [];
159-
for (let i = 0; i < numWorkers; i++) {
156+
for (let i = 0; i < this.#workerCount; i++) {
160157
const worker = new Worker("./worker.mjs", {type: "module"});
161158
worker.postMessage(["thread", this.#module, this.#memory, stacks[i] + stackSize]);
162159
this.#workers.push(worker);
163160
}
164161
} else {
162+
console.debug("creating single-threaded instance");
165163
this.#instance = new WebAssembly.Instance(this.#module);
164+
this.#memory = this.#exports.memory;
165+
}
166+
}
167+
168+
ensureInstance() {
169+
if (this.#instance === undefined) {
170+
this.newInstance();
166171
}
167172
}
168173

174+
stopInstance() {
175+
if (this.#multithreaded && this.#workers !== undefined) {
176+
for (const worker of this.#workers) {
177+
try {
178+
worker.terminate();
179+
} catch (e) {
180+
console.warn(e);
181+
}
182+
}
183+
this.#workers = [];
184+
}
185+
186+
this.#instance = undefined;
187+
this.#memory = undefined;
188+
}
189+
169190
/**
170191
* @param {number} year
171192
* @param {number} day
@@ -176,6 +197,8 @@ export class Aoc {
176197
* @return {{success: true, part1: string, part2: string} | {success: false, error: string, stack?: string, panic_location?: string}}
177198
*/
178199
run(year, day, input, isExample = false, part1 = true, part2 = true) {
200+
this.ensureInstance();
201+
179202
let success;
180203
try {
181204
this.#write(input);
@@ -191,7 +214,7 @@ export class Aoc {
191214
console.warn(e2);
192215
}
193216

194-
this.newInstance()
217+
this.stopInstance();
195218

196219
if (panic_payload.length > 0) {
197220
return {

crates/aoc_wasm/web/web.mjs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Aoc} from "./aoc.mjs";
22

33
const COMMIT = "${GIT_COMMIT}";
4-
console.log("Commit", COMMIT);
4+
console.log("commit", COMMIT);
55

66
const MODULE_PATHS = [
77
"./aoc-simd128.wasm",
@@ -15,11 +15,11 @@ let module;
1515
for (const path of MODULE_PATHS) {
1616
try {
1717
module = await WebAssembly.compileStreaming(fetch(path));
18-
console.log("Using " + path);
18+
console.log("using " + path);
1919
break;
2020
} catch (err) {
2121
if (err instanceof WebAssembly.CompileError) {
22-
console.warn("Compiling " + path + " failed: " + err);
22+
console.warn("compiling " + path + " failed: " + err);
2323
} else {
2424
throw err;
2525
}
@@ -291,7 +291,7 @@ inputTextarea.addEventListener("drop", (e) => {
291291

292292
const file = e.dataTransfer.files[0];
293293
if (file !== undefined) {
294-
console.log("Loading input from file: ", file);
294+
console.log("loading input from file: ", file);
295295

296296
const reader = new FileReader();
297297
reader.onload = (event) => {
@@ -305,14 +305,14 @@ inputTextarea.addEventListener("drop", (e) => {
305305

306306
const text = e.dataTransfer.getData("text/plain");
307307
if (text !== undefined) {
308-
console.log("Loading input from drag text");
308+
console.log("loading input from drag text");
309309
inputTextarea.value = text;
310310
saveInput();
311311

312312
return;
313313
}
314314

315-
console.warn("No supported drag data");
315+
console.warn("no supported drag data");
316316
});
317317
inputTextarea.addEventListener("change", saveInput);
318318
inputTextarea.addEventListener("input", saveInput);

crates/aoc_wasm/web/worker.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ onmessage = (e) => {
77
switch (e.data.shift()) {
88
case "init":
99
instance = new Aoc(...e.data);
10+
instance.ensureInstance();
1011
break;
1112
case "run":
1213
console.time("solution");
1314
const result = instance.run(...e.data);
1415
console.timeEnd("solution");
1516
postMessage(result);
1617
console.log(result);
18+
instance.ensureInstance();
1719
break;
1820
case "thread":
1921
const [module, memory, ptr] = e.data;

0 commit comments

Comments
 (0)