Skip to content

Commit

Permalink
Add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
hoodmane committed Oct 25, 2024
1 parent 9c52174 commit 60e2c39
Showing 1 changed file with 43 additions and 5 deletions.
48 changes: 43 additions & 5 deletions src/core/stack_switching/calculate_wasm_func_nargs_fallback.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
// Various function pointer mismatch bugs occur because people declare a
// `METH_NOARGS` function which should take 2 arguments:
// ```
// my_no_arg_meth(PyObject* module, PyObject* always_null);
// ```
// but leave off the `always_null` second argument or both arguments. Similar
// errors occur less frequently with `METH_VARARGS | METH_KWDS` functions. When
// the interpreter tries to use a call_indirect to invoke these methods, we hit
// an indirect call signature mismatch fatal error.
//
// Traditionally we used a JS trampoline to deal with this, because calls from
// JS to Wasm don't care if the wrong number of arguments are passed. However,
// these trampolines do not work with JSPI because we cannot stack switch
// through JavaScript frames.
//
// Originally JSPI implied wasm type reflection, so we could ask JS what the
// type of the function was and then select a `call_indirect` with the right
// number of arguments based on this result.
//
// The new JSPI does not imply that wasm type reflection exists, so we need a
// way to handle the case when JSPI is available but wasm type reflection is
// not. What we do here is make a tiny WebAssembly module that attempts to
// import a single function. If the signature of the function matches the
// signature of the import, it will succeed. Otherwise, we will raise a
// LinkError.
//
// We only need to handle functions with four different possible signatures:
// (n i32's) => i32 where n is between 0 and 3. So we try to link at most 4
// different Wasm modules and find out the signature.

const checkerModules = [undefined, undefined, undefined, undefined];

function makeCheckerModule(n) {
Expand All @@ -8,7 +38,7 @@ function makeCheckerModule(n) {
// )
//
// with n i32's. We'll try to import the function to this module to see if it
// has this signature.
// has this signature. If not it rasises a link error.
return new WebAssembly.Module(
// prettier-ignore
new Uint8Array([
Expand Down Expand Up @@ -41,12 +71,20 @@ function getCheckerModule(n) {

export function calculateWasmFuncNargsFallback(functionPtr) {
for (let n = 0; n < 4; n++) {
const mod = getCheckerModule(n);
const imports = {
e: { f: wasmTable.get(functionPtr) },
};
try {
new WebAssembly.Instance(getCheckerModule(n), {
e: { f: wasmTable.get(functionPtr) },
});
new WebAssembly.Instance(mod, imports);
return n;
} catch (e) {}
} catch (e) {
// Should be a LinkError, if not we have a logic error. Raise fatal error
// so it's noisy.
if (!e instanceof WebAssembly.LinkError) {
throw e;
}
}
}
return -1;
}

0 comments on commit 60e2c39

Please sign in to comment.