| 
									
										
										
										
											2023-09-15 15:04:21 -07: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 11:25:09 +02: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 15:04:21 -07: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 11:25:09 +02:00
										 |  |  |     n = Module.PyEM_CountArgs(func); | 
					
						
							| 
									
										
										
										
											2023-09-15 15:04:21 -07: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
 |