https://github.com/python/cpython/commit/d0b2e0735f4cd7368cc52d9227f6712169fd4448
commit: d0b2e0735f4cd7368cc52d9227f6712169fd4448
branch: main
author: Clément Péron <[email protected]>
committer: freakboy3742 <[email protected]>
date: 2026-09-11T09:22:36+08:00
summary:

gh-156780: Emscripten: drop the trampoline's dependence on exports (#157238)

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 <[email protected]>

files:
M Python/emscripten_trampoline.c
M configure
M configure.ac

diff --git a/Python/emscripten_trampoline.c b/Python/emscripten_trampoline.c
index 75cfde6b76f217..547761027a3fb3 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 7d6c321ae38130..8b930f9ad5b836 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 0cf27376015aef..d11af71ae4950a 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"])

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to