UNPKG

2.59 kBJavaScriptView Raw
1import { assert, assertEquals } from "../deps/deno.land/std@0.134.0/testing/asserts.js";
2
3/**
4 * @typedef {object} WasmExports
5 * @property {WebAssembly.Memory} memory
6 * @property {function} asyncify_get_state
7 * @property {function} asyncify_start_unwind
8 * @property {function} asyncify_stop_unwind
9 * @property {function} asyncify_start_rewind
10 * @property {function} asyncify_stop_rewind
11 */
12
13/**
14 * @type {WasmExports}
15 */
16let wasm;
17
18/**
19 * @param {WasmExports} wasmExports
20 */
21function setWasmExports(wasmExports) {
22 wasm = wasmExports;
23}
24
25/**
26 * @type {Int32Array}
27 */
28let cachedInt32Memory = null;
29
30/**
31 * @returns {Int32Array}
32 */
33function getInt32Memory() {
34 if (
35 cachedInt32Memory === null ||
36 cachedInt32Memory.buffer !== wasm.memory.buffer
37 ) {
38 cachedInt32Memory = new Int32Array(wasm.memory.buffer);
39 }
40 return cachedInt32Memory;
41}
42
43// https://github.com/WebAssembly/binaryen/blob/fb9de9d391a7272548dcc41cd8229076189d7398/src/passes/Asyncify.cpp#L99
44const State = {
45 NONE: 0,
46 UNWINDING: 1,
47 REWINDING: 2,
48};
49
50function assertNoneState() {
51 assertEquals(wasm.asyncify_get_state(), State.NONE);
52}
53
54/**
55 * Maps `HTMLRewriter`s (their `asyncifyStackPtr`s) to `Promise`s.
56 * `asyncifyStackPtr` acts as unique reference to `HTMLRewriter`.
57 * Each rewriter MUST have AT MOST ONE pending promise at any time.
58 * @type {Map<number, Promise>}
59 */
60const promises = new Map();
61
62/**
63 * @param {number} stackPtr
64 * @param {Promise} promise
65 */
66function awaitPromise(stackPtr, promise) {
67 if (wasm.asyncify_get_state() === State.REWINDING) {
68 wasm.asyncify_stop_rewind();
69 return;
70 }
71
72 assertNoneState();
73
74 // https://github.com/WebAssembly/binaryen/blob/fb9de9d391a7272548dcc41cd8229076189d7398/src/passes/Asyncify.cpp#L106
75 assertEquals(stackPtr % 4, 0);
76 getInt32Memory().set([stackPtr + 8, stackPtr + 1024], stackPtr / 4);
77
78 wasm.asyncify_start_unwind(stackPtr);
79
80 assert(!promises.has(stackPtr));
81 promises.set(stackPtr, promise);
82}
83
84/**
85 * @param {HTMLRewriter} rewriter
86 * @param {Function} fn
87 * @param args
88 */
89async function wrap(rewriter, fn, ...args) {
90 const stackPtr = rewriter.asyncifyStackPtr;
91
92 assertNoneState();
93 let result = fn(...args);
94
95 while (wasm.asyncify_get_state() === State.UNWINDING) {
96 wasm.asyncify_stop_unwind();
97
98 assertNoneState();
99 assert(promises.has(stackPtr));
100 await promises.get(stackPtr);
101 promises.delete(stackPtr);
102
103 assertNoneState();
104 wasm.asyncify_start_rewind(stackPtr);
105 result = fn();
106 }
107
108 assertNoneState();
109 return result;
110}
111
112export { awaitPromise, setWasmExports, wrap };