You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
WASM: free-threaded CPython 3.15t with pthreads, cross-origin isolation by default #175
User decision (2026-10-04), following #158 (free-threaded 3.15t is the only build):
The wasm interpreter is also 3.15t, built by us (tools/wasm/build-cpython.sh) with pthreads; not Pyodide's GIL build. Unverified so far: whether --disable-gil builds for emscripten (CPython's bundled mimalloc has no emscripten-specific path); first task is that build.
Cross-origin isolation (COOP: same-origin, COEP: require-corp or credentialless) is the default: toolchain generates the headers for the dev server and hosting config, and ships a service-worker fallback (coi-serviceworker style) for hosts that cannot set headers. The runtime checks crossOriginIsolated at start and fails with an explanation if it is false.
Documented limits: embedding in third-party iframes, popup-based OAuth/payment (opener severed), cross-origin resources without CORP/CORS.
Cost accepted: Pyodide's emscripten wheels do not load; compiled dependencies are built by pypackpack for wasm.
Update docs/platforms/wasm-design.md and SPEC accordingly. Related: pypackpack Android release java resources consume generatePythonProperties without a task dependency #72, toolchain (header generation), pythonx-concurrent §3/§7 (wasm dispatchers become threads).
Source-only investigation, 2026-11-13 (agent; nothing was built, so none of this proves a build links or runs).
--disable-gil on emscripten: CPython 3.15.0's configure accepts it, with no platform guard (configure.ac:1757-1768). mimalloc is not disabled for emscripten; the vendored mimalloc 2.1.2 treats emscripten as WASI and uses sbrk, which is atomic with shared memory. Upstream gh-158996 / PR gh-158997 (no pthreads) built a t ABI and ran the test suite: 372 test files passed and 9 failed, mostly "can't start new thread".
The link fails unless libffi and mpdec are rebuilt with -pthread.
The call trampoline imports non-shared memory (Makefile.pre.in:3214-3216).
In this library: Kotlin/Wasm's memory import is not shared, which revives the .wasm patch wasm-design.md calls obsolete.
Thread.start() waits for the new thread, so the first start can deadlock without a pre-created worker pool.
Python threads calling back into Kotlin need the function table on every Worker.
Flags to try first (agent proposal, not confirmed): Platforms/emscripten with --host-runner node --disable-gil --enable-wasm-pthreads; -pthread in CFLAGS/LDFLAGS; -sPTHREAD_POOL_SIZE=8 -sMAXIMUM_MEMORY=2GB.
Open: which Emscripten to pin. CPython 3.15.0 pins 4.0.19; our script pins 5.0.3.
Running the build experiment needs a CI job, and none exists for it. That job is waiting on a decision (asked through the boost coordinator).
Step 1 landed in develop via #397. The free-threaded 3.15t wasm build with pthreads builds and runs.
Run: build-ft-wasm.yml run 43301962045.
Build: Emscripten 4.0.19, --disable-gil --enable-wasm-pthreads, libffi and mpdec with atomics, Py_GIL_DISABLED 1, ABIFLAGS=t, stdlib lib/python3.15t.
Smoke test under node:FT-WASM-SMOKE-OK gil=False threads=4 abiflags=t version=3.15.0, both in the build tree and from the unpacked archive. The artifact python-3.15.0t-wasm32-emscripten is 9.1 MB.
Patch: one small patch, so the call trampoline falls back to the JS trampoline under shared memory.
Not verified: browsers (only node ran), the cost of the JS trampoline, and thread safety beyond the smoke test.
Left for later steps:
Kotlin/Wasm's shared memory import.
A worker pool for the first Thread.start from Kotlin.
Function tables on every Worker for upcalls.
Staging this archive as the wasmJs runtime.
Cross-origin isolation headers, the service-worker fallback, and the crossOriginIsolated start check.
The Emscripten pin: 4.0.19, CPython's own, versus 5.0.3 in the existing runtime.
Activity
b-re-w commentedon Nov 12, 2026
Source-only investigation, 2026-11-13 (agent; nothing was built, so none of this proves a build links or runs).
configure.ac:1757-1768). mimalloc is not disabled for emscripten; the vendored mimalloc 2.1.2 treats emscripten as WASI and uses sbrk, which is atomic with shared memory. Upstream gh-158996 / PR gh-158997 (no pthreads) built atABI and ran the test suite: 372 test files passed and 9 failed, mostly "can't start new thread".-pthread.Makefile.pre.in:3214-3216)..wasmpatchwasm-design.mdcalls obsolete.Thread.start()waits for the new thread, so the first start can deadlock without a pre-created worker pool.Platforms/emscriptenwith--host-runner node --disable-gil --enable-wasm-pthreads;-pthreadin CFLAGS/LDFLAGS;-sPTHREAD_POOL_SIZE=8 -sMAXIMUM_MEMORY=2GB.Running the build experiment needs a CI job, and none exists for it. That job is waiting on a decision (asked through the boost coordinator).
Merge pull request #397 from thisisthepy/feat/wasm-ft-build
b-re-w commentedon Nov 12, 2026
Step 1 landed in develop via #397. The free-threaded 3.15t wasm build with pthreads builds and runs.
--disable-gil --enable-wasm-pthreads, libffi and mpdec with atomics,Py_GIL_DISABLED 1,ABIFLAGS=t, stdliblib/python3.15t.FT-WASM-SMOKE-OK gil=False threads=4 abiflags=t version=3.15.0, both in the build tree and from the unpacked archive. The artifactpython-3.15.0t-wasm32-emscriptenis 9.1 MB.Not verified: browsers (only node ran), the cost of the JS trampoline, and thread safety beyond the smoke test.
Left for later steps:
Thread.startfrom Kotlin.crossOriginIsolatedstart check.