Created
February 25, 2024 03:44
-
-
Save ABCxFF/9cad88c17d2d3452ddc259fabcd121dc to your computer and use it in GitHub Desktop.
async WebAssembly.Function polyfill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For Firefox or other browsers that don't provide WebAssembly.Function APIs, | |
// this polyfill, albeit async, can be used as a substitute. | |
// | |
// Using WASM, this polyfill is accepted by WebAssembly.Tables, and can be inserted | |
// into them without failure | |
if (!WebAssembly.Function) { | |
const vu32 = (x) => { | |
let out = []; | |
do { | |
let byte = x & 0x7F; | |
x >>= 7; | |
if (x) byte |= 0x80 | |
out.push(byte); | |
} while (x); | |
return out; | |
} | |
const deepFlat = arr => arr.flatMap(e => Array.isArray(e) ? deepFlat(e.flat()) : e); | |
const vector = (arr) => vu32(arr.length).concat(deepFlat(arr)); | |
const string = (str) => vector(Array.from(new TextEncoder().encode(str))) | |
const types = { | |
"i32": 0x7F, | |
"i64": 0x7E, | |
"f32": 0x7D, | |
"f64": 0x7C, | |
"v128": 0x7B, | |
"funcref": 0x70, | |
"externref": 0x6F | |
} | |
class WebAssemblyFunction { | |
constructor({ parameters, results }, callable) { | |
return new Promise(async (resolve, reject) => { | |
for (let i = 0; i < parameters.length; ++i) { | |
if (!types.hasOwnProperty(parameters[i])) { | |
return reject(new TypeError(`Argument 0 parameter type at index #${i} must be a value type`)); | |
} | |
} | |
for (let i = 0; i < results.length; ++i) { | |
if (!types.hasOwnProperty(results[i])) { | |
return reject(new TypeError(`Argument 0 result type at index #${i} must be a value type`)); | |
} | |
} | |
if (typeof callable !== "function") { | |
return reject(new TypeError("Argument 1 must be a function")); | |
} | |
const w = await WebAssembly.instantiate(new Uint8Array(deepFlat([ | |
[0x00, 0x61, 0x73, 0x6d], // magic | |
[0x01, 0x00, 0x00, 0x00], // version | |
[ | |
0x1, // type section | |
vector(deepFlat(vector([ | |
[ | |
0x60, | |
vector(parameters.map(n => types[n])), | |
vector(results.map(n => types[n])) | |
] | |
]))) | |
], | |
[ | |
0x2, // import section | |
vector(deepFlat(vector([ | |
[ | |
string("m"), | |
string("c"), | |
0, | |
vu32(0) | |
] | |
]))) | |
], | |
[ | |
0x3, // function section | |
vector(deepFlat(vector([ | |
[ | |
vu32(0) | |
] | |
]))) | |
], | |
[ | |
0x7, // export section | |
vector(deepFlat(vector([ | |
[ | |
string("e"), | |
0, | |
vu32(1) | |
] | |
]))) | |
], | |
[ | |
0xA, // function section | |
vector(deepFlat(vector([ | |
vector(deepFlat([ | |
vector([]), | |
...parameters.flatMap((_,i) => [0x20, ...vu32(i)]), | |
0x10, vu32(0), // call $0 | |
0x0B // end | |
])) | |
]))) | |
], | |
])), { m: { c: callable } }); | |
resolve(w.instance.exports.e.bind()); | |
}); | |
} | |
} | |
WebAssembly.Function = WebAssemblyFunction; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment