From 0a2c8f45e8332e4ecad1e2736d6c244b221e45c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= Date: Wed, 9 Sep 2026 23:16:13 +0200 Subject: [PATCH] gh-156780: Emscripten: drop the trampoline's dependence on exports The trampoline exports _PyRuntime's address itself and reuses a placeholder's table slot, so libpython no longer needs -sEXPORTED_FUNCTIONS=__PyRuntime or a growable function table. Co-Authored-By: Claude Fable 5.1 --- Python/emscripten_trampoline.c | 21 ++++++++++++++++++--- configure | 2 +- configure.ac | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Python/emscripten_trampoline.c b/Python/emscripten_trampoline.c index 75cfde6b76f2174..547761027a3fb3d 100644 --- a/Python/emscripten_trampoline.c +++ b/Python/emscripten_trampoline.c @@ -47,6 +47,19 @@ typedef PyObject* (*TrampolineFunc)(int* success, PyObject* args, PyObject* kw); +// Lets JS reach _PyRuntime without it being in -sEXPORTED_FUNCTIONS. +EMSCRIPTEN_KEEPALIVE _PyRuntimeState *const _PyEM_runtime = &_PyRuntime; + +// Its table slot is taken over by the wasm-gc trampoline, so the table +// never grows. +static PyObject* +trampoline_placeholder(int* success, PyCFunctionWithKeywords func, + PyObject* self, PyObject* args, PyObject* kw) +{ + Py_FatalError("Emscripten trampoline slot was not set up"); +} +EMSCRIPTEN_KEEPALIVE const TrampolineFunc _PyEM_trampoline_slot = trampoline_placeholder; + /** * Backwards compatible trampoline works with all JS runtimes */ @@ -79,7 +92,9 @@ function getPyEMTrampolinePtr() { const trampolineInstance = new WebAssembly.Instance(trampolineModule, { env: { __indirect_function_table: wasmTable, memory: wasmMemory }, }); - return addFunction(trampolineInstance.exports.trampoline_call); + const slot = HEAPU32[__PyEM_trampoline_slot / 4]; + wasmTable.set(slot, trampolineInstance.exports.trampoline_call); + return slot; } // We have to be careful to work correctly with memory snapshots -- the value of // _PyRuntimeState.emscripten_trampoline needs to reflect whether wasm-gc is @@ -90,12 +105,12 @@ function getPyEMTrampolinePtr() { addOnPreRun(function setEmscriptenTrampoline() { const ptr = getPyEMTrampolinePtr(); const offset = HEAP32[__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET / 4]; - HEAP32[(__PyRuntime + offset) / 4] = ptr; + HEAP32[(HEAPU32[__PyEM_runtime / 4] + offset) / 4] = ptr; }); ); EM_JS_DEPS(_PyEM_TrampolineCall, - "$wasmTable,$wasmMemory,$addFunction,$addOnPreRun"); + "$wasmTable,$wasmMemory,$addOnPreRun"); PyObject* _PyEM_TrampolineCall(PyCFunctionWithKeywords func, diff --git a/configure b/configure index ae3f0450dc7af1b..f08584720d48578 100755 --- a/configure +++ b/configure @@ -9978,7 +9978,7 @@ fi as_fn_append LINKFORSHARED " -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js" as_fn_append LINKFORSHARED " -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV,HEAPU32,TTY,ERRNO_CODES" - as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET" + as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET" as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB" as_fn_append LINKFORSHARED " -sTEXTDECODER=2" diff --git a/configure.ac b/configure.ac index 1c42900cb975c35..6e11c8af0337f65 100644 --- a/configure.ac +++ b/configure.ac @@ -2440,7 +2440,7 @@ AS_CASE([$ac_sys_system], dnl Include file system support AS_VAR_APPEND([LINKFORSHARED], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"]) AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV,HEAPU32,TTY,ERRNO_CODES"]) - AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET"]) + AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET"]) AS_VAR_APPEND([LINKFORSHARED], [" -sSTACK_SIZE=5MB"]) dnl Avoid bugs in JS fallback string decoding path AS_VAR_APPEND([LINKFORSHARED], [" -sTEXTDECODER=2"])