~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs

0
0
main
41 lines · 2.2 KB Raw History
// Runs one call of a compiled module off the page's thread, so a module that never
// returns can be terminated. Same JSON ABI as emdash's in-process runner: exports memory,
// alloc and entry; entry(ptr, len) returns an i64 packing (outputPtr << 32 | outputLen).
// Failures are messages starting with their WASM_* code.

function run(compiled, entry, inputJson, limits) {
	const { exports } = new WebAssembly.Instance(compiled, {});
	const { memory, alloc } = exports;
	if (!(memory instanceof WebAssembly.Memory) || typeof alloc !== "function" || typeof exports[entry] !== "function") {
		throw new Error(`WASM_ABI_INVALID: module must export memory, alloc and ${entry}`);
	}
	const input = new TextEncoder().encode(inputJson);
	let packed;
	try {
		const pointer = Number(alloc(input.byteLength));
		new Uint8Array(memory.buffer, pointer, input.byteLength).set(input);
		packed = exports[entry](pointer, input.byteLength);
	} catch (error) {
		throw new Error(`WASM_TRAP: ${error.message}`);
	}
	// wasmAccess capped the memory's maximum before compiling (capMemory): this is a backstop.
	if (memory.buffer.byteLength > limits.memoryPages * 65536) throw new Error(`WASM_TOO_LARGE: memory exceeds ${limits.memoryPages} pages`);
	if (typeof packed !== "bigint") throw new Error(`WASM_ABI_INVALID: ${entry} must return i64`);
	const outputPointer = Number(BigInt.asUintN(64, packed) >> 32n);
	const outputLength = Number(BigInt.asUintN(32, packed));
	if (outputLength > limits.outputBytes) throw new Error(`WASM_OUTPUT_INVALID: output exceeds ${limits.outputBytes} bytes`);
	if (outputPointer + outputLength > memory.buffer.byteLength) throw new Error("WASM_OUTPUT_INVALID: output points outside memory");
	try {
		return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(memory.buffer, outputPointer, outputLength)));
	} catch {
		throw new Error("WASM_OUTPUT_INVALID: output is not JSON");
	}
}

self.onmessage = ({ data: { compiled, entry, inputJson, limits } }) => {
	try {
		self.postMessage({ output: run(compiled, entry, inputJson, limits) });
	} catch (error) {
		self.postMessage({ error: error.message.startsWith("WASM_") ? error.message : `WASM_TRAP: ${error.message}` });
	}
};