https://github.com/python/cpython/commit/0ec3aee262b03276a18aeb23cb9957e1b57c9d08
commit: 0ec3aee262b03276a18aeb23cb9957e1b57c9d08
branch: main
author: Hood Chatham <[email protected]>
committer: brettcannon <[email protected]>
date: 2026-10-09T22:25:44Z
summary:
gh-129040: Use wasm-gc to handle pointer casts in wasi (GH-158617)
This makes it so that in wasi builds if `-DPY_CALL_TRAMPOLINE` is passed, a
call trampoline adaptor is used to prevent traps when there is a call signature
mismatch between a C slot handler and the signature that the interpreter uses
to call it.
This requires Clang >= 22. PEP 11 specifies that builds of Python 3.15 use WASI
SDK version 33 which includes clang 23.1.0, so this could be used with Python
3.15 WASI builds but not earlier ones.
It requires a WebAssembly runtime that supports wasm-gc. Wasmtime has supported
wasm-gc since version 27.0 released November 25, 2024. Some other runtimes
still don't support it, but for those runtimes people can use builds with the
trampoline disabled.
This also removed the Emscripten trampoline support for JS runtimes with no
wasm-gc support. This removes a lot of implementation complexity and allows
WASI and Emscripten to share code. The main concern is that it drops support
for some very old iPhones, but every iPhone model released since 2018 is
compatible with versions of Safari that support wasm-gc.
Tests were added that define handlers with various wrong numbers of arguments.
The tests also run on non-webassembly platforms since they should work there as
well.
files:
A Include/internal/pycore_wasm_trampoline.h
A Lib/test/test_capi/test_fpcast.py
A Misc/NEWS.d/next/Build/2026-10-02-12-18-20.gh-issue-129040.6wJPY6.rst
A Modules/_testcapi/fpcast.c
A Python/wasm_trampoline.c
D Include/internal/pycore_emscripten_trampoline.h
D Platforms/emscripten/prepare_external_wasm.py
D Python/emscripten_trampoline.c
D Python/emscripten_trampoline_inner.c
M Include/internal/pycore_object.h
M Include/internal/pycore_runtime_structs.h
M Makefile.pre.in
M Modules/Setup.stdlib.in
M Modules/_testcapi/parts.h
M Modules/_testcapimodule.c
M Objects/descrobject.c
M PCbuild/_testcapi.vcxproj
M PCbuild/_testcapi.vcxproj.filters
M Platforms/WASI/_build.py
M Tools/c-analyzer/cpython/_parser.py
M Tools/c-analyzer/cpython/ignored.tsv
M configure
M configure.ac
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 3ecc5e9f0554b09..dbc0ebf994fd1e0 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -8,7 +8,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_emscripten_trampoline.h" // _PyCFunction_TrampolineCall()
+#include "pycore_wasm_trampoline.h" // _PyCFunction_TrampolineCall()
#include "pycore_gc.h" // _PyObject_GC_TRACK()
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_ACQUIRE()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
@@ -977,27 +977,6 @@ extern PyObject* _PyObject_NextNotImplemented(PyObject *);
// Export for '_datetime' shared extension
PyAPI_FUNC(PyObject*) _PyObject_GetState(PyObject *);
-/* C function call trampolines to mitigate bad function pointer casts.
- *
- * Typical native ABIs ignore additional arguments or fill in missing
- * values with 0/NULL in function pointer cast. Compilers do not show
- * warnings when a function pointer is explicitly casted to an
- * incompatible type.
- *
- * Bad fpcasts are an issue in WebAssembly. WASM's indirect_call has strict
- * function signature checks. Argument count, types, and return type must
- * match.
- *
- * Third party code unintentionally rely on problematic fpcasts. The call
- * trampoline mitigates common occurrences of bad fpcasts on Emscripten.
- */
-#if !(defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE))
-#define _PyCFunction_TrampolineCall(meth, self, args) \
- (meth)((self), (args))
-#define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
- (meth)((self), (args), (kw))
-#endif // __EMSCRIPTEN__ && PY_CALL_TRAMPOLINE
-
// Export these 2 symbols for '_pickle' shared extension
PyAPI_DATA(PyTypeObject) _PyNone_Type;
PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type;
diff --git a/Include/internal/pycore_runtime_structs.h
b/Include/internal/pycore_runtime_structs.h
index 145e66de9984ca7..5470f5858eda087 100644
--- a/Include/internal/pycore_runtime_structs.h
+++ b/Include/internal/pycore_runtime_structs.h
@@ -271,16 +271,6 @@ struct pyruntimestate {
struct _types_runtime_state types;
struct _Py_time_runtime_state time;
-#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
- // Used in "Python/emscripten_trampoline.c" to choose between wasm-gc
- // trampoline and JavaScript trampoline.
- PyObject* (*emscripten_trampoline)(int* success,
- PyCFunctionWithKeywords func,
- PyObject* self,
- PyObject* args,
- PyObject* kw);
-#endif
-
/* All the objects that are shared by the runtime's interpreters. */
struct _Py_cached_objects cached_objects;
struct _Py_static_objects static_objects;
diff --git a/Include/internal/pycore_emscripten_trampoline.h
b/Include/internal/pycore_wasm_trampoline.h
similarity index 56%
rename from Include/internal/pycore_emscripten_trampoline.h
rename to Include/internal/pycore_wasm_trampoline.h
index e37c53a64f4a723..1199bab0aca0976 100644
--- a/Include/internal/pycore_emscripten_trampoline.h
+++ b/Include/internal/pycore_wasm_trampoline.h
@@ -1,7 +1,7 @@
-#ifndef Py_EMSCRIPTEN_TRAMPOLINE_H
-#define Py_EMSCRIPTEN_TRAMPOLINE_H
+#ifndef Py_WASM_TRAMPOLINE_H
+#define Py_WASM_TRAMPOLINE_H
-#include "pycore_typedefs.h" // _PyRuntimeState
+#include "Python.h"
/**
* C function call trampolines to mitigate bad function pointer casts.
@@ -18,37 +18,44 @@
* with 0/NULL in function pointer cast. Compilers do not show warnings when a
* function pointer is explicitly casted to an incompatible type.
*
- * Bad fpcasts are an issue in WebAssembly. WASM's indirect_call has strict
+ * Bad fpcasts are an issue in WebAssembly. Wasm's indirect_call has strict
* function signature checks. Argument count, types, and return type must
match.
*
* Third party code unintentionally rely on problematic fpcasts. The call
- * trampoline mitigates common occurrences of bad fpcasts on Emscripten.
+ * trampoline mitigates common occurrences of bad fpcasts on Wasm targets.
*/
-#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
+#if defined(__wasm__) && defined(PY_CALL_TRAMPOLINE)
PyObject*
-_PyEM_TrampolineCall(PyCFunctionWithKeywords func,
- PyObject* self,
- PyObject* args,
- PyObject* kw);
+_PyWasm_TrampolineCall(PyCFunctionWithKeywords func,
+ PyObject* self,
+ PyObject* args,
+ PyObject* kw);
+
+int
+_PyWasm_TrampolineCallSetter(setter func,
+ PyObject* self,
+ PyObject* val,
+ void* closure);
#define _PyCFunction_TrampolineCall(meth, self, args) \
- _PyEM_TrampolineCall(*_PyCFunctionWithKeywords_CAST(meth), (self), (args),
NULL)
+ _PyWasm_TrampolineCall(*_PyCFunctionWithKeywords_CAST(meth), (self),
(args), NULL)
#define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
- _PyEM_TrampolineCall((meth), (self), (args), (kw))
+ _PyWasm_TrampolineCall((meth), (self), (args), (kw))
#define descr_set_trampoline_call(set, obj, value, closure) \
- ((int)_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(set), (obj), \
- (value), (PyObject*)(closure)))
+ _PyWasm_TrampolineCallSetter((set), (obj), (value), (closure))
#define descr_get_trampoline_call(get, obj, closure) \
- _PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(get), (obj), \
- (PyObject*)(closure), NULL)
+ _PyWasm_TrampolineCall(_PyCFunctionWithKeywords_CAST(get), (obj), \
+ (PyObject*)(closure), NULL)
+
+#else // defined(__wasm__) && defined(PY_CALL_TRAMPOLINE)
-#else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
+// Disable trampolines by directly calling the method.
#define _PyCFunction_TrampolineCall(meth, self, args) \
(meth)((self), (args))
@@ -62,6 +69,6 @@ _PyEM_TrampolineCall(PyCFunctionWithKeywords func,
#define descr_get_trampoline_call(get, obj, closure) \
(get)((obj), (closure))
-#endif // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
+#endif // defined(__wasm__) && defined(PY_CALL_TRAMPOLINE)
-#endif // ndef Py_EMSCRIPTEN_SIGNAL_H
+#endif // ndef Py_WASM_TRAMPOLINE_H
diff --git a/Lib/test/test_capi/test_fpcast.py
b/Lib/test/test_capi/test_fpcast.py
new file mode 100644
index 000000000000000..ae19ac11f6a191f
--- /dev/null
+++ b/Lib/test/test_capi/test_fpcast.py
@@ -0,0 +1,77 @@
+"""Tests for calling C functions through mis-cast function pointers.
+
+Extension modules frequently cast C functions with the wrong number of
+arguments to PyCFunction, getter, setter or ternaryfunc. Native ABIs tolerate
+this; on WebAssembly, call_indirect checks the signature, so CPython routes
+these calls through a trampoline (Python/wasm_trampoline.c) that detects the
+real signature. Calling each variant must work everywhere.
+"""
+import unittest
+from test.support import check_sanitizer, import_helper, is_wasm32
+
+_testcapi = import_helper.import_module('_testcapi')
+
+
+# Native ABIs tolerate these calls but they are implementation-defined
behavior.
+# -fsanitize=undefined correctly trips on them.
[email protected](check_sanitizer(ub=True),
+ "calls through mis-cast function pointers are UB natively")
+class FpcastTest(unittest.TestCase):
+ def check_calls(self, obj, prefix):
+ for arity in range(4):
+ with self.subTest(kind="noargs", arity=arity):
+ self.assertIsNone(getattr(obj, f"{prefix}noargs{arity}")())
+ with self.subTest(kind="o", arity=arity):
+ self.assertIsNone(getattr(obj, f"{prefix}o{arity}")(1))
+ with self.subTest(kind="varargs", arity=arity):
+ self.assertIsNone(getattr(obj, f"{prefix}varargs{arity}")())
+ self.assertIsNone(getattr(obj, f"{prefix}varargs{arity}")(1,
2))
+ with self.subTest(kind="kwargs", arity=arity):
+ self.assertIsNone(getattr(obj, f"{prefix}kwargs{arity}")())
+ self.assertIsNone(getattr(obj, f"{prefix}kwargs{arity}")(1,
x=2))
+
+ def test_module_functions(self):
+ self.check_calls(_testcapi, "fpcast_")
+
+ def test_methods(self):
+ self.check_calls(_testcapi.FpcastTestType(), "")
+
+ def test_tp_call(self):
+ for arity in range(4):
+ with self.subTest(arity=arity):
+ cls = getattr(_testcapi, f"FpcastCallable{arity}")
+ self.assertIsNone(cls()())
+ self.assertIsNone(cls()(1, x=2))
+
+ def test_getset(self):
+ t = _testcapi.FpcastTestType()
+ self.assertIsNone(t.getset0)
+ self.assertIsNone(t.getset1)
+ self.assertIsNone(t.getset2)
+ t.getset1 = 5
+ sentinel = object()
+ t.getset2 = sentinel
+ self.assertIs(_testcapi.fpcast_last_set_value(), sentinel)
+ with self.assertRaises(AttributeError):
+ t.getset0 = 1
+
+ @unittest.skipUnless(is_wasm32, "requires the wasm call trampoline")
+ def test_unsupported_signature(self):
+ # A function with four pointer arguments matches none of the
+ # signatures the trampoline knows about: it must raise SystemError
+ # rather than trap.
+ t = _testcapi.FpcastTestType()
+ with self.assertRaises(SystemError):
+ _testcapi.fpcast_noargs4()
+ with self.assertRaises(SystemError):
+ t.noargs4()
+ with self.assertRaises(SystemError):
+ _testcapi.FpcastCallable4()()
+ with self.assertRaises(SystemError):
+ t.getset4
+ with self.assertRaises(SystemError):
+ t.getset4 = 1
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 42480f28ad7f315..36515dbd146a1e3 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1439,6 +1439,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_uop.h \
$(srcdir)/Include/internal/pycore_uop_ids.h \
$(srcdir)/Include/internal/pycore_uop_metadata.h \
+ $(srcdir)/Include/internal/pycore_wasm_trampoline.h \
$(srcdir)/Include/internal/pycore_warnings.h \
$(srcdir)/Include/internal/pycore_weakref.h \
$(DTRACE_HEADERS) \
@@ -3153,13 +3154,6 @@ Python/asm_trampoline_universal2.o:
$(srcdir)/Python/asm_trampoline_aarch64.S $(
rm -f Python/asm_trampoline_arm64-apple-darwin.o \
Python/asm_trampoline_x86_64-apple-darwin.o
-Python/emscripten_trampoline_inner.wasm:
$(srcdir)/Python/emscripten_trampoline_inner.c
- # emcc has a path that ends with emsdk/upstream/emscripten/emcc, we're
looking for emsdk/upstream/bin/clang.
- $$(em-config LLVM_ROOT)/clang -o $@ $< -mgc -O2 -Wl,--no-entry
-Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib
-
-Python/emscripten_trampoline_wasm.c: Python/emscripten_trampoline_inner.wasm
- $(PYTHON_FOR_REGEN)
$(srcdir)/Platforms/emscripten/prepare_external_wasm.py $< $@
getWasmTrampolineModule
-
JIT_SHIM_BUILD_OBJS= @JIT_SHIM_BUILD_O@
JIT_UNWIND_INFO_H= $(if $(JIT_OBJS),jit_unwind_info.h $(patsubst
jit_stencils-%.h,jit_unwind_info-%.h,@JIT_STENCILS_H@))
JIT_BUILD_TARGETS= jit_stencils.h @JIT_STENCILS_H@ $(JIT_UNWIND_INFO_H)
$(JIT_SHIM_BUILD_OBJS)
diff --git
a/Misc/NEWS.d/next/Build/2026-10-02-12-18-20.gh-issue-129040.6wJPY6.rst
b/Misc/NEWS.d/next/Build/2026-10-02-12-18-20.gh-issue-129040.6wJPY6.rst
new file mode 100644
index 000000000000000..50f432d71e22f30
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2026-10-02-12-18-20.gh-issue-129040.6wJPY6.rst
@@ -0,0 +1,3 @@
+Added support for function call adaptor trampolines for wasi to prevent
+traps when C handlers take the wrong number of arguments. Dropped Emscripten
+function call adaptors support for JS runtimes that don't support wasm-gc.
diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in
index dd9f38e59f7a3ff..d8cd8de10dfe084 100644
--- a/Modules/Setup.stdlib.in
+++ b/Modules/Setup.stdlib.in
@@ -173,7 +173,7 @@
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c
_xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
_testinternalcapi/test_lock.c _testinternalcapi/pytime.c
_testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
_testinternalcapi/complex.c _testinternalcapi/interpreter.c
_testinternalcapi/tokenizer.c _testinternalcapi/tuple.c
_testinternalcapi/typecache.c
-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c
_testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c
_testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c
_testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c
_testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c
_testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c
_testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c
_testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c
_testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c
_testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c
_testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
_testcapi/marshal.c
+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c
_testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c
_testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c
_testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c
_testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c
_testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c
_testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c
_testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c
_testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c
_testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c
_testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
_testcapi/marshal.c _testcapi/fpcast.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c
_testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c
_testlimitedcapi/bytes.c _testlimitedcapi/capsule.c _testlimitedcapi/codec.c
_testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c
_testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c
_testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c
_testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c
_testlimitedcapi/slice.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c
_testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c
_testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
_testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c
_testlimitedcapi/run.c _testlimitedcapi/type.c _testlimitedcapi/hash.c
_testlimitedcapi/build.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
diff --git a/Modules/_testcapi/fpcast.c b/Modules/_testcapi/fpcast.c
new file mode 100644
index 000000000000000..ed6e2d3c5c5e6d9
--- /dev/null
+++ b/Modules/_testcapi/fpcast.c
@@ -0,0 +1,164 @@
+/*
+ * Tests for Python/wasm_trampoline.c
+ *
+ * Third party extensions frequently cast functions with the "wrong" number of
+ * arguments to PyCFunction, getter, setter or ternaryfunc. On native targets
+ * this works by accident. On WebAssembly, call_indirect checks the signature
+ * and traps, so CPython routes these calls through a trampoline that detects
+ * the real signature.
+ */
+
+#include "parts.h"
+
+static PyObject *
+zero(void)
+{
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+one(PyObject *self)
+{
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+two(PyObject *self, PyObject *args)
+{
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+three(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_RETURN_NONE;
+}
+
+// Using this as a handler should raise a SystemError.
+static PyObject *
+four(PyObject *self, PyObject *a, PyObject *b, PyObject *c)
+{
+ Py_RETURN_NONE;
+}
+
+static int
+set_two(PyObject *self, PyObject *value)
+{
+ return 0;
+}
+
+static PyObject *last_set_value = NULL;
+
+static int
+set_three(PyObject *self, PyObject *value, void *closure)
+{
+ Py_XSETREF(last_set_value, Py_XNewRef(value));
+ return 0;
+}
+
+static PyObject *
+get_last_set_value(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ if (last_set_value == NULL) {
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(last_set_value);
+}
+
+#define FPCAST_METHODS(prefix) \
+ {prefix "noargs0", _PyCFunction_CAST(zero), METH_NOARGS}, \
+ {prefix "noargs1", _PyCFunction_CAST(one), METH_NOARGS}, \
+ {prefix "noargs2", _PyCFunction_CAST(two), METH_NOARGS}, \
+ {prefix "noargs3", _PyCFunction_CAST(three), METH_NOARGS}, \
+ {prefix "noargs4", _PyCFunction_CAST(four), METH_NOARGS}, \
+ \
+ {prefix "o0", _PyCFunction_CAST(zero), METH_O}, \
+ {prefix "o1", _PyCFunction_CAST(one), METH_O}, \
+ {prefix "o2", _PyCFunction_CAST(two), METH_O}, \
+ {prefix "o3", _PyCFunction_CAST(three), METH_O}, \
+ \
+ {prefix "varargs0", _PyCFunction_CAST(zero), METH_VARARGS}, \
+ {prefix "varargs1", _PyCFunction_CAST(one), METH_VARARGS}, \
+ {prefix "varargs2", _PyCFunction_CAST(two), METH_VARARGS}, \
+ {prefix "varargs3", _PyCFunction_CAST(three), METH_VARARGS}, \
+ \
+ {prefix "kwargs0", _PyCFunction_CAST(zero), \
+ METH_VARARGS | METH_KEYWORDS}, \
+ {prefix "kwargs1", _PyCFunction_CAST(one), \
+ METH_VARARGS | METH_KEYWORDS}, \
+ {prefix "kwargs2", _PyCFunction_CAST(two), \
+ METH_VARARGS | METH_KEYWORDS}, \
+ {prefix "kwargs3", _PyCFunction_CAST(three), \
+ METH_VARARGS | METH_KEYWORDS}
+
+static PyMethodDef test_methods[] = {
+ FPCAST_METHODS("fpcast_"),
+ {"fpcast_last_set_value", get_last_set_value, METH_NOARGS},
+ {NULL},
+};
+
+static PyMethodDef type_methods[] = {
+ FPCAST_METHODS(""),
+ {NULL},
+};
+
+static PyGetSetDef type_getset[] = {
+ {"getset0", .get = _Py_FUNC_CAST(getter, zero)},
+ {"getset1", .get = _Py_FUNC_CAST(getter, one),
+ .set = _Py_FUNC_CAST(setter, set_two)},
+ {"getset2", .get = _Py_FUNC_CAST(getter, two),
+ .set = _Py_FUNC_CAST(setter, set_three)},
+ {"getset4", .get = _Py_FUNC_CAST(getter, four),
+ .set = _Py_FUNC_CAST(setter, four)},
+ {NULL},
+};
+
+static PyTypeObject FpcastTestType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "_testcapi.FpcastTestType",
+ .tp_basicsize = sizeof(PyObject),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = type_methods,
+ .tp_getset = type_getset,
+ .tp_new = PyType_GenericNew,
+};
+
+#define CALLABLE_TYPE(N, FUNC) \
+ static PyTypeObject FpcastCallable##N = { \
+ PyVarObject_HEAD_INIT(NULL, 0) \
+ .tp_name = "_testcapi.FpcastCallable" #N, \
+ .tp_basicsize = sizeof(PyObject), \
+ .tp_flags = Py_TPFLAGS_DEFAULT, \
+ .tp_call = _Py_FUNC_CAST(ternaryfunc, FUNC), \
+ .tp_new = PyType_GenericNew, \
+ };
+
+CALLABLE_TYPE(0, zero)
+CALLABLE_TYPE(1, one)
+CALLABLE_TYPE(2, two)
+CALLABLE_TYPE(3, three)
+CALLABLE_TYPE(4, four)
+
+#undef CALLABLE_TYPE
+
+int
+_PyTestCapi_Init_Fpcast(PyObject *mod)
+{
+ if (PyModule_AddFunctions(mod, test_methods) < 0) {
+ return -1;
+ }
+ PyTypeObject *types[] = {
+ &FpcastTestType,
+ &FpcastCallable0,
+ &FpcastCallable1,
+ &FpcastCallable2,
+ &FpcastCallable3,
+ &FpcastCallable4,
+ };
+ for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
+ if (PyModule_AddType(mod, types[i]) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h
index 1ae3f0773e42f80..e2787e7c93aef88 100644
--- a/Modules/_testcapi/parts.h
+++ b/Modules/_testcapi/parts.h
@@ -69,5 +69,6 @@ int _PyTestCapi_Init_Function(PyObject *mod);
int _PyTestCapi_Init_Module(PyObject *mod);
int _PyTestCapi_Init_Weakref(PyObject *mod);
int _PyTestCapi_Init_Marshal(PyObject *mod);
+int _PyTestCapi_Init_Fpcast(PyObject *mod);
#endif // Py_TESTCAPI_PARTS_H
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 19c02e6774e3d48..033ee3234cf604d 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3832,6 +3832,9 @@ _testcapi_exec(PyObject *m)
if (_PyTestCapi_Init_Marshal(m) < 0) {
return -1;
}
+ if (_PyTestCapi_Init_Fpcast(m) < 0) {
+ return -1;
+ }
return 0;
}
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 63023887667a50a..c0af1ed8cad8307 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -4,7 +4,7 @@
#include "pycore_abstract.h" // _PyObject_RealIsSubclass()
#include "pycore_call.h" // _PyStack_AsDict()
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
-#include "pycore_emscripten_trampoline.h" // descr_set_trampoline_call(),
descr_get_trampoline_call()
+#include "pycore_wasm_trampoline.h" // descr_set_trampoline_call(),
descr_get_trampoline_call()
#include "pycore_descrobject.h" // _PyMethodWrapper_Type
#include "pycore_modsupport.h" // _PyArg_UnpackStack()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj
index d856b70bbdd5792..9b4473b877daf44 100644
--- a/PCbuild/_testcapi.vcxproj
+++ b/PCbuild/_testcapi.vcxproj
@@ -135,6 +135,7 @@
<ClCompile Include="..\Modules\_testcapi\function.c" />
<ClCompile Include="..\Modules\_testcapi\weakref.c" />
<ClCompile Include="..\Modules\_testcapi\marshal.c" />
+ <ClCompile Include="..\Modules\_testcapi\fpcast.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc" />
diff --git a/PCbuild/_testcapi.vcxproj.filters
b/PCbuild/_testcapi.vcxproj.filters
index 554e5f3075f7ebf..238819a1d3646fb 100644
--- a/PCbuild/_testcapi.vcxproj.filters
+++ b/PCbuild/_testcapi.vcxproj.filters
@@ -138,6 +138,9 @@
<ClCompile Include="..\Modules\_testcapi\marshal.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Modules\_testcapi\fpcast.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc">
diff --git a/Platforms/WASI/_build.py b/Platforms/WASI/_build.py
index 8d9cc3c1bf281f5..87b42ea6283951a 100644
--- a/Platforms/WASI/_build.py
+++ b/Platforms/WASI/_build.py
@@ -239,6 +239,7 @@ def configure_wasi_python(context, working_dir):
f"--host={context.host_triple}",
f"--build={context.build_python_path.name}",
f"--with-build-python={build_python}",
+ "CFLAGS=-DPY_CALL_TRAMPOLINE",
]
if context.is_debug:
configure.append("--with-pydebug")
diff --git a/Platforms/emscripten/prepare_external_wasm.py
b/Platforms/emscripten/prepare_external_wasm.py
deleted file mode 100644
index 1b0a9de4b1fe8d8..000000000000000
--- a/Platforms/emscripten/prepare_external_wasm.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python3
-
-import argparse
-import sys
-from pathlib import Path
-
-JS_TEMPLATE = """
-#include "emscripten.h"
-
-EM_JS(void, {function_name}, (void), {{
- return new WebAssembly.Module(hexStringToUTF8Array("{hex_string}"));
-}}
-function hexStringToUTF8Array(hex) {{
- const bytes = [];
- for (let i = 0; i < hex.length; i += 2) {{
- bytes.push(parseInt(hex.substr(i, 2), 16));
- }}
- return new Uint8Array(bytes);
-}});
-"""
-
-
-def prepare_wasm(input_file, output_file, function_name):
- # Read the compiled WASM as binary and convert to hex
- wasm_bytes = Path(input_file).read_bytes()
-
- hex_string = "".join(f"{byte:02x}" for byte in wasm_bytes)
-
- # Generate JavaScript module
- js_content = JS_TEMPLATE.format(
- function_name=function_name, hex_string=hex_string
- )
- Path(output_file).write_text(js_content)
-
- print(f"Successfully compiled {input_file} and generated {output_file}")
- return 0
-
-
-def main():
- parser = argparse.ArgumentParser(
- description="Compile WebAssembly text files using wasm-as"
- )
- parser.add_argument("input_file", help="Input .wat file to compile")
- parser.add_argument("output_file", help="Output file name")
- parser.add_argument("function_name", help="Name of the export function")
-
- args = parser.parse_args()
-
- return prepare_wasm(args.input_file, args.output_file, args.function_name)
-
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/Python/emscripten_trampoline.c b/Python/emscripten_trampoline.c
deleted file mode 100644
index 547761027a3fb3d..000000000000000
--- a/Python/emscripten_trampoline.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#if defined(PY_CALL_TRAMPOLINE)
-
-#include <emscripten.h> // EM_JS, EM_JS_DEPS
-#include <Python.h>
-#include "pycore_runtime.h" // _PyRuntime
-
-// We use the _PyRuntime.emscripten_trampoline field to store a function
pointer
-// for a wasm-gc based trampoline if it works. Otherwise fall back to JS
-// trampoline. The JS trampoline breaks stack switching but every runtime that
-// supports stack switching also supports wasm-gc.
-//
-// We'd like to make the trampoline call into a direct call but currently we
-// need to import the wasmTable to compile trampolineModule. emcc >= 4.0.19
-// defines the table in WebAssembly and exports it so we won't have access to
it
-// until after the main module is compiled.
-//
-// To fix this, one natural solution would be to pass a funcref to the
-// trampoline instead of a table index. Several PRs would be needed to fix
-// things in llvm and emscripten in order to make this possible.
-//
-// The performance costs of an extra call_indirect aren't that large anyways.
-// The JIT should notice that the target is always the same and turn into a
-// check
-//
-// if (call_target != expected) deoptimize;
-// direct_call(call_target, args);
-
-// Offset of emscripten_trampoline in _PyRuntimeState. There's a couple of
-// alternatives:
-//
-// 1. Just make emscripten_trampoline a real C global variable instead of a
-// field of _PyRuntimeState. This would violate our rule against mutable
-// globals.
-//
-// 2. #define a preprocessor constant equal to a hard coded number and make a
-// _Static_assert(offsetof(_PyRuntimeState, emscripten_trampoline) ==
OURCONSTANT)
-// This has the disadvantage that we have to update the hard coded constant
-// when _PyRuntimeState changes
-//
-// So putting the mutable constant in _PyRuntime and using a immutable global
to
-// record the offset so we can access it from JS is probably the best way.
-EMSCRIPTEN_KEEPALIVE const int _PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET =
offsetof(_PyRuntimeState, emscripten_trampoline);
-
-typedef PyObject* (*TrampolineFunc)(int* success,
- PyCFunctionWithKeywords func,
- PyObject* self,
- 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
- */
-EM_JS(PyObject*, _PyEM_TrampolineCall_JS, (PyCFunctionWithKeywords func,
PyObject *arg1, PyObject *arg2, PyObject *arg3), {
- return wasmTable.get(func)(arg1, arg2, arg3);
-}
-// Try to compile wasm-gc trampoline if possible.
-function getPyEMTrampolinePtr() {
- // Starting with iOS 18.3.1, WebKit on iOS has an issue with the garbage
- // collector that breaks the call trampoline. See #130418 and
- // https://bugs.webkit.org/show_bug.cgi?id=293113 for details.
- let isIOS = globalThis.navigator && (
- /iPad|iPhone|iPod/.test(navigator.userAgent) ||
- // Starting with iPadOS 13, iPads might send a platform string that
looks like a desktop Mac.
- // To differentiate, we check if the platform is 'MacIntel' (common
for Macs and newer iPads)
- // AND if the device has multi-touch capabilities
(navigator.maxTouchPoints > 1)
- (navigator.platform === 'MacIntel' && typeof navigator.maxTouchPoints
!== 'undefined' && navigator.maxTouchPoints > 1)
- );
- if (isIOS) {
- return 0;
- }
- let trampolineModule;
- try {
- trampolineModule = getWasmTrampolineModule();
- } catch (e) {
- // Compilation error due to missing wasm-gc support, fall back to JS
- // trampoline
- return 0;
- }
- const trampolineInstance = new WebAssembly.Instance(trampolineModule, {
- env: { __indirect_function_table: wasmTable, memory: wasmMemory },
- });
- 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
-// available in the current runtime, not in the runtime the snapshot was taken
-// in. This writes the appropriate value to
-// _PyRuntimeState.emscripten_trampoline from JS startup code that runs every
-// time, whether we are restoring a snapshot or not.
-addOnPreRun(function setEmscriptenTrampoline() {
- const ptr = getPyEMTrampolinePtr();
- const offset = HEAP32[__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET / 4];
- HEAP32[(HEAPU32[__PyEM_runtime / 4] + offset) / 4] = ptr;
-});
-);
-
-EM_JS_DEPS(_PyEM_TrampolineCall,
- "$wasmTable,$wasmMemory,$addOnPreRun");
-
-PyObject*
-_PyEM_TrampolineCall(PyCFunctionWithKeywords func,
- PyObject* self,
- PyObject* args,
- PyObject* kw)
-{
- TrampolineFunc trampoline = _PyRuntime.emscripten_trampoline;
- if (trampoline == 0) {
- return _PyEM_TrampolineCall_JS(func, self, args, kw);
- }
- int success = 1;
- PyObject *result = trampoline(&success, func, self, args, kw);
- if (!success) {
- PyErr_SetString(PyExc_SystemError, "Handler takes too many arguments");
- }
- return result;
-}
-
-#else
-// This is exported so we need to define it even when it isn't used
-__attribute__((used)) const int _PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET = 0;
-#endif
diff --git a/Python/emscripten_trampoline_inner.c
b/Python/emscripten_trampoline_inner.c
deleted file mode 100644
index a2bad4857ed089c..000000000000000
--- a/Python/emscripten_trampoline_inner.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// This file must be compiled with -mgc to enable the extra wasm-gc
-// instructions. It has to be compiled separately because not enough JS
runtimes
-// support wasm-gc yet. If the JS runtime does not support wasm-gc (or has
buggy
-// support like iOS), we will use the JS trampoline fallback.
-
-// We can't import Python.h here because it is compiled/linked with -nostdlib.
-// We don't need to know what's inside PyObject* anyways. We could just call it
-// void* everywhere. There are two reasons to do this:
-// 1. to improve readability
-// 2. eventually when we are comfortable requiring wasm-gc, we can merge this
-// into emscripten_trampoline.c without worrying about it.
-typedef void PyObject;
-
-typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*);
-typedef PyObject* (*two_arg)(PyObject*, PyObject*);
-typedef PyObject* (*one_arg)(PyObject*);
-typedef PyObject* (*zero_arg)(void);
-
-#define TRY_RETURN_CALL(ty, args...) \
- if (__builtin_wasm_test_function_pointer_signature((ty)func)) { \
- return ((ty)func)(args); \
- }
-
-__attribute__((export_name("trampoline_call"))) PyObject*
-trampoline_call(int* success,
- void* func,
- PyObject* self,
- PyObject* args,
- PyObject* kw)
-{
- *success = 1;
- TRY_RETURN_CALL(three_arg, self, args, kw);
- TRY_RETURN_CALL(two_arg, self, args);
- TRY_RETURN_CALL(one_arg, self);
- TRY_RETURN_CALL(zero_arg);
- *success = 0;
- return 0;
-}
diff --git a/Python/wasm_trampoline.c b/Python/wasm_trampoline.c
new file mode 100644
index 000000000000000..ceef8e803387cc8
--- /dev/null
+++ b/Python/wasm_trampoline.c
@@ -0,0 +1,48 @@
+#if defined(__wasm__) && defined(PY_CALL_TRAMPOLINE)
+
+#include <Python.h>
+
+typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*);
+typedef PyObject* (*two_arg)(PyObject*, PyObject*);
+typedef PyObject* (*one_arg)(PyObject*);
+typedef PyObject* (*zero_arg)(void);
+
+#define RETCALL_IF_SIG_MATCHES(ty, args...) \
+ if (__builtin_wasm_test_function_pointer_signature((ty)func)) { \
+ return ((ty)func)(args); \
+ }
+
+PyObject*
+_PyWasm_TrampolineCall(PyCFunctionWithKeywords func,
+ PyObject* self,
+ PyObject* args,
+ PyObject* kw)
+{
+ RETCALL_IF_SIG_MATCHES(three_arg, self, args, kw);
+ RETCALL_IF_SIG_MATCHES(two_arg, self, args);
+ RETCALL_IF_SIG_MATCHES(one_arg, self);
+ RETCALL_IF_SIG_MATCHES(zero_arg);
+ PyErr_SetString(PyExc_SystemError, "Handler has incorrect signature");
+ return NULL;
+}
+
+typedef int (*setter_three_arg)(PyObject*, PyObject*, void*);
+typedef int (*setter_two_arg)(PyObject*, PyObject*);
+typedef int (*setter_one_arg)(PyObject*);
+typedef int (*setter_zero_arg)(void);
+
+int
+_PyWasm_TrampolineCallSetter(setter func,
+ PyObject* self,
+ PyObject* val,
+ void* closure)
+{
+ RETCALL_IF_SIG_MATCHES(setter_three_arg, self, val, closure);
+ RETCALL_IF_SIG_MATCHES(setter_two_arg, self, val);
+ RETCALL_IF_SIG_MATCHES(setter_one_arg, self);
+ RETCALL_IF_SIG_MATCHES(setter_zero_arg);
+ PyErr_SetString(PyExc_SystemError, "Handler has incorrect signature");
+ return -1;
+}
+
+#endif // defined(__wasm__) && defined(PY_CALL_TRAMPOLINE)
diff --git a/Tools/c-analyzer/cpython/_parser.py
b/Tools/c-analyzer/cpython/_parser.py
index 3c715f91cede109..caac194d3b7efb6 100644
--- a/Tools/c-analyzer/cpython/_parser.py
+++ b/Tools/c-analyzer/cpython/_parser.py
@@ -63,7 +63,6 @@ def format_tsv_lines(lines):
'Python/dynload_hpux.c', # dl.h
'Python/emscripten_signal.c',
'Python/emscripten_syscalls.c',
- 'Python/emscripten_trampoline_inner.c',
'Python/thread_pthread.h',
'Python/thread_pthread_stubs.h',
diff --git a/Tools/c-analyzer/cpython/ignored.tsv
b/Tools/c-analyzer/cpython/ignored.tsv
index 220e84ef1f60c2c..cc9b389ec1a9ad4 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -465,6 +465,13 @@ Modules/_testcapi/datetime.c -
test_run_counter -
Modules/_testcapi/docstring.c - DocStringNoSignatureTest -
Modules/_testcapi/docstring.c - DocStringUnrepresentableSignatureTest
-
Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type -
+Modules/_testcapi/fpcast.c - last_set_value -
+Modules/_testcapi/fpcast.c - FpcastTestType -
+Modules/_testcapi/fpcast.c - FpcastCallable0 -
+Modules/_testcapi/fpcast.c - FpcastCallable1 -
+Modules/_testcapi/fpcast.c - FpcastCallable2 -
+Modules/_testcapi/fpcast.c - FpcastCallable3 -
+Modules/_testcapi/fpcast.c - FpcastCallable4 -
Modules/_testcapi/heaptype.c - _testcapimodule -
Modules/_testcapi/mem.c - FmData -
Modules/_testcapi/mem.c - FmHook -
diff --git a/configure b/configure
index 35035e45b21a196..c777d8117c66c4c 100755
--- a/configure
+++ b/configure
@@ -9976,7 +9976,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,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET"
+ as_fn_append LINKFORSHARED "
-sEXPORTED_FUNCTIONS=_main,_Py_Version,_PyGILState_GetThisThreadState"
as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB"
as_fn_append LINKFORSHARED " -sTEXTDECODER=2"
@@ -20379,14 +20379,21 @@ PLATFORM_OBJS=
case $ac_sys_system in #(
Emscripten) :
- as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o
Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o'
+ as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o
Python/wasm_trampoline.o'
+ as_fn_append CFLAGS_NODIST " -mgc"
+
if test "x$enable_emscripten_syscalls" = xyes
then :
as_fn_append PLATFORM_OBJS ' Python/emscripten_syscalls.o'
fi
- as_fn_append PLATFORM_HEADERS '
$(srcdir)/Include/internal/pycore_emscripten_signal.h
$(srcdir)/Include/internal/pycore_emscripten_trampoline.h'
+ as_fn_append PLATFORM_HEADERS '
$(srcdir)/Include/internal/pycore_emscripten_signal.h'
+ ;; #(
+ WASI) :
+
+ as_fn_append PLATFORM_OBJS ' Python/wasm_trampoline.o'
+ as_fn_append CFLAGS_NODIST " -mgc"
;; #(
*) :
;;
diff --git a/configure.ac b/configure.ac
index 6037e79801b450b..a8760c94ac151aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2443,7 +2443,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,_PyGILState_GetThisThreadState,__PyEM_EMSCRIPTEN_TRAMPOLINE_OFFSET"])
+ AS_VAR_APPEND([LINKFORSHARED], ["
-sEXPORTED_FUNCTIONS=_main,_Py_Version,_PyGILState_GetThisThreadState"])
AS_VAR_APPEND([LINKFORSHARED], [" -sSTACK_SIZE=5MB"])
dnl Avoid bugs in JS fallback string decoding path
AS_VAR_APPEND([LINKFORSHARED], [" -sTEXTDECODER=2"])
@@ -5462,11 +5462,17 @@ PLATFORM_OBJS=
AS_CASE([$ac_sys_system],
[Emscripten], [
- AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o
Python/emscripten_trampoline.o Python/emscripten_trampoline_wasm.o'])
+ AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o
Python/wasm_trampoline.o'])
+ AS_VAR_APPEND([CFLAGS_NODIST], [" -mgc"])
+
AS_VAR_IF([enable_emscripten_syscalls], [yes], [
AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_syscalls.o'])
])
- AS_VAR_APPEND([PLATFORM_HEADERS], ['
$(srcdir)/Include/internal/pycore_emscripten_signal.h
$(srcdir)/Include/internal/pycore_emscripten_trampoline.h'])
+ AS_VAR_APPEND([PLATFORM_HEADERS], ['
$(srcdir)/Include/internal/pycore_emscripten_signal.h'])
+ ],
+ [WASI], [
+ AS_VAR_APPEND([PLATFORM_OBJS], [' Python/wasm_trampoline.o'])
+ AS_VAR_APPEND([CFLAGS_NODIST], [" -mgc"])
],
)
AC_SUBST([PLATFORM_HEADERS])
_______________________________________________
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]