2023-09-15 22:04:21 +00:00
|
|
|
#if defined(PY_CALL_TRAMPOLINE)
|
|
|
|
|
|
|
|
#include <emscripten.h> // EM_JS
|
|
|
|
#include <Python.h>
|
|
|
|
#include "pycore_runtime.h" // _PyRuntime
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the GoogleChromeLabs approved way to feature detect type-reflection:
|
|
|
|
* https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/type-reflection/index.js
|
|
|
|
*/
|
|
|
|
EM_JS(int, _PyEM_detect_type_reflection, (), {
|
2024-07-14 09:25:09 +00:00
|
|
|
if (!("Function" in WebAssembly)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (WebAssembly.Function.type) {
|
|
|
|
// Node v20
|
|
|
|
Module.PyEM_CountArgs = (func) => WebAssembly.Function.type(wasmTable.get(func)).parameters.length;
|
|
|
|
} else {
|
|
|
|
// Node >= 22, v8-based browsers
|
|
|
|
Module.PyEM_CountArgs = (func) => wasmTable.get(func).type().parameters.length;
|
|
|
|
}
|
|
|
|
return true;
|
2023-09-15 22:04:21 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
void
|
|
|
|
_Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime)
|
|
|
|
{
|
|
|
|
runtime->wasm_type_reflection_available = _PyEM_detect_type_reflection();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Backwards compatible trampoline works with all JS runtimes
|
|
|
|
*/
|
|
|
|
EM_JS(PyObject*,
|
|
|
|
_PyEM_TrampolineCall_JavaScript, (PyCFunctionWithKeywords func,
|
|
|
|
PyObject *arg1,
|
|
|
|
PyObject *arg2,
|
|
|
|
PyObject *arg3),
|
|
|
|
{
|
|
|
|
return wasmTable.get(func)(arg1, arg2, arg3);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In runtimes with WebAssembly type reflection, count the number of parameters
|
|
|
|
* and cast to the appropriate signature
|
|
|
|
*/
|
|
|
|
EM_JS(int, _PyEM_CountFuncParams, (PyCFunctionWithKeywords func),
|
|
|
|
{
|
|
|
|
let n = _PyEM_CountFuncParams.cache.get(func);
|
|
|
|
|
|
|
|
if (n !== undefined) {
|
|
|
|
return n;
|
|
|
|
}
|
2024-07-14 09:25:09 +00:00
|
|
|
n = Module.PyEM_CountArgs(func);
|
2023-09-15 22:04:21 +00:00
|
|
|
_PyEM_CountFuncParams.cache.set(func, n);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
_PyEM_CountFuncParams.cache = new Map();
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
typedef PyObject* (*zero_arg)(void);
|
|
|
|
typedef PyObject* (*one_arg)(PyObject*);
|
|
|
|
typedef PyObject* (*two_arg)(PyObject*, PyObject*);
|
|
|
|
typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*);
|
|
|
|
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
_PyEM_TrampolineCall_Reflection(PyCFunctionWithKeywords func,
|
|
|
|
PyObject* self,
|
|
|
|
PyObject* args,
|
|
|
|
PyObject* kw)
|
|
|
|
{
|
|
|
|
switch (_PyEM_CountFuncParams(func)) {
|
|
|
|
case 0:
|
|
|
|
return ((zero_arg)func)();
|
|
|
|
case 1:
|
|
|
|
return ((one_arg)func)(self);
|
|
|
|
case 2:
|
|
|
|
return ((two_arg)func)(self, args);
|
|
|
|
case 3:
|
|
|
|
return ((three_arg)func)(self, args, kw);
|
|
|
|
default:
|
|
|
|
PyErr_SetString(PyExc_SystemError,
|
|
|
|
"Handler takes too many arguments");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|