jspi: retire the asyncify pipeline — knob, post-link tail, binaryen hooks

Phase 8 in the parent repo. Deleted: asyncify-scheduler.js, apply-asyncify.sh,
apply-finalize.sh, inject-dyncall-shims.sh, asyncify-imports/removelist.txt,
the wasm-opt/finalize stub pair, scripts/binaryen-hoist-pass/ (the fork stays
a dormant submodule; removal is a follow-up), bench/wasm-opt-bench.sh (README
marked historical), wasm/shims/context_sleep.cpp, and the sched-context
harness app + Makefile targets.

PCBJAM_ASYNC_BACKEND is gone: build-wx-wasm.sh hardcodes the jspi stamp
(still force-cleans pre-migration trees), build-kicad-target.sh gives editors
the JSPI link surface and the CLIs nothing (they pin ASYNCIFY=0), the stub
dance is replaced by an unconditional .real-restore, build-wasm-test.sh lost
its whole post-link loop, docker/build.sh's postprocess is the ENV shim only,
and Makefile.wasm links every app JSPI with the scheduler shim as a tracked
prerequisite. pcbjam_async_policy.h keys on __EMSCRIPTEN__.

jspi-scheduler.js: wxWasmMainLoopPump dropped from the wrap census (the
export died with the D5 detach); inert [TRACE] instrumentation removed.

CI: wasm-build.yml rewritten for the single-cache pipeline (one output cache
keyed on compile inputs; post-processed bytes cached after the shim);
opt_level input removed from both callers. wasm-cache-hash.mjs inputs now
cover patch-env-shim.mjs + jspi-scheduler.js + jspi-exports.txt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NDeBaKKhQztd8KiVtHuyXr
This commit is contained in:
Viktor Vaczi 2026-08-13 08:39:12 +02:00
commit e14faeca8b
36 changed files with 170 additions and 3348 deletions

View file

@ -53,23 +53,15 @@ CXXFLAGS += -MMD -MP
# Native wasm-EH is the only build mode: compile + link with -fwasm-exceptions (legacy encoding) +
# wasm setjmp/longjmp, matching the libwx build (scripts/build-wx-wasm.sh) and scripts/common/env.sh.
# The in-link Asyncify (emsdk Binaryen v121) crashes on wasm-EH, so build-wasm-test.sh stubs it and
# runs the real pipeline (--hoist-cpp-catches + --asyncify via apply-asyncify.sh) post-link.
# Async backend switch (experiment/jspi): PCBJAM_ASYNC_BACKEND=jspi links the
# apps with JSPI instead of Asyncify. Requires the wx libs built with the same
# knob (build-wx-wasm.sh). -sDYNCALLS is asyncify-only machinery and a FATAL
# link error under -sJSPI; -DPCBJAM_JSPI selects the JSPI lanes in the wasm
# port sources and libcontext.
PCBJAM_ASYNC_BACKEND ?= asyncify
ifeq ($(PCBJAM_ASYNC_BACKEND),jspi)
EH_FLAGS = -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -sWASM_LEGACY_EXCEPTIONS=1 -DPCBJAM_JSPI=1
# JSPI is the only suspension backend since the migration (-sDYNCALLS and the
# whole Asyncify/binaryen post-link pipeline are retired).
EH_FLAGS = -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -sWASM_LEGACY_EXCEPTIONS=1
# Promising entry exports: every JS->wasm entry that can transitively suspend
# (fresh census 2026-08-12 of EMSCRIPTEN_KEEPALIVE in wxwidgets/src/wasm; the
# Sched*/abandon probes never suspend and stay plain). pcbjam_libctx_entry is
# libcontext's coroutine entry (only present in apps that link libcontext —
# emscripten warns-and-ignores absent names).
WX_JSPI_EXPORTS = main,wx_dom_event,wx_dom_mouse,wx_window_close,wx_window_move,wx_window_resize,ProcessEvents,wxWasmMailboxTick,wxWasmTopLevelTick,wxWasmMainLoopPump,wxWasmJobTick,pcbjam_libctx_entry
# (census of EMSCRIPTEN_KEEPALIVE in wxwidgets/src/wasm; the Sched*/abandon
# probes never suspend and stay plain). pcbjam_libctx_entry is libcontext's
# coroutine entry (only present in apps that link libcontext — emscripten
# warns-and-ignores absent names).
WX_JSPI_EXPORTS = main,wx_dom_event,wx_dom_mouse,wx_window_close,wx_window_move,wx_window_resize,ProcessEvents,wxWasmMailboxTick,wxWasmTopLevelTick,wxWasmJobTick,pcbjam_libctx_entry
# Per-app suspending test levers (fresh-stack ccalls that park or swap a
# coroutine). Appended as a LAST -sJSPI_EXPORTS on the app's link line, which
# wins over the one inside ASYNC_LDFLAGS (emcc last-wins). The non-parking
@ -82,27 +74,10 @@ ASYNC_LDFLAGS = -sJSPI \
-s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32','ccall','stackSave','stackRestore']" \
--pre-js $(JSPI_SHIM)
ASYNC_CORO_LDFLAGS = $(ASYNC_LDFLAGS)
ASYNC_SCHED_CTX_LDFLAGS = $(ASYNC_LDFLAGS)
else
EH_FLAGS = -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -sWASM_LEGACY_EXCEPTIONS=1 -sDYNCALLS=1
ASYNC_LDFLAGS = -s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32','ccall']" \
-sASYNCIFY=1 \
-sASYNCIFY_STACK_SIZE=65536 \
-sASYNCIFY_IMPORTS=['js_writeTextToClipboard','js_readTextFromClipboard','js_clipboardHasText','js_clearClipboard','js_enumerateFonts']
ASYNC_CORO_LDFLAGS = -s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32','ccall']" \
-sASYNCIFY=1 \
-sASYNCIFY_STACK_SIZE=65536 \
-sASYNCIFY_IMPORTS=['js_writeTextToClipboard','js_readTextFromClipboard','js_clipboardHasText','js_clearClipboard','js_enumerateFonts','emscripten_fiber_swap']
ASYNC_SCHED_CTX_LDFLAGS = -s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32','ccall']" \
-sASYNCIFY=1 \
-sASYNCIFY_STACK_SIZE=65536 \
-sASYNCIFY_IMPORTS=['emscripten_fiber_swap']
endif
CXXFLAGS += $(EH_FLAGS)
# Base Emscripten flags (for all apps)
# ASYNCIFY enables blocking modal dialogs (ShowModal waits for user)
# ASYNCIFY_IMPORTS tells Emscripten which imported JS functions can unwind the stack
# JSPI enables blocking modal dialogs (ShowModal suspends its promising activation)
# - js_writeTextToClipboard, js_readTextFromClipboard, js_clipboardHasText, js_clearClipboard: for clipboard
# - js_enumerateFonts: for font enumeration via Local Font Access API
BASE_LDFLAGS = $(EH_FLAGS) -sALLOW_MEMORY_GROWTH -sERROR_ON_UNDEFINED_SYMBOLS=0 \
@ -141,23 +116,14 @@ COROUTINE_BASE_LDFLAGS = $(EH_FLAGS) -sALLOW_MEMORY_GROWTH -sERROR_ON_UNDEFINED_
$(ASYNC_CORO_LDFLAGS)
LDFLAGS_COROUTINE = $(DEBUG_LDFLAGS) $(COROUTINE_BASE_LDFLAGS) $(WX_LDFLAGS_NOGL)
# The asyncify-races harness must match PRODUCTION asyncify semantics: the KiCad
# The suspend-races harness must match PRODUCTION suspension semantics: the KiCad
# apps ship with assertions off and rely on the shim layer, while emscripten's
# debug assert ("We cannot start an async operation when one is already flight")
# forbids the very multi-parked-sleep states the harness exists to exercise.
LDFLAGS_RACES = $(DEBUG_LDFLAGS) $(COROUTINE_BASE_LDFLAGS) -sASSERTIONS=0 $(WX_LDFLAGS_NOGL)
# Scheduler-context harness (docs/features/async/20 D1). Deliberately does NOT
# link wx: the contexts layer is pure emscripten fibers + Asyncify, and keeping
# wx out means a failure here can only be the primitives. Assertions stay ON —
# unlike the races harness this must NOT tolerate a "cannot start an async
# operation" state; hitting one is the bug.
LDFLAGS_SCHED_CTX = $(DEBUG_LDFLAGS) $(EH_FLAGS) -sALLOW_MEMORY_GROWTH \
-sERROR_ON_UNDEFINED_SYMBOLS=0 \
$(ASYNC_SCHED_CTX_LDFLAGS)
# LDFLAGS for the raytracer thread-deadlock repro. Same pthread + pool config as
# LDFLAGS_PTHREAD, but built on COROUTINE_BASE_LDFLAGS for the 65536 ASYNCIFY
# LDFLAGS_PTHREAD, but built on COROUTINE_BASE_LDFLAGS for the
# stack KiCad actually ships (emscripten_sleep needs Asyncify to yield).
LDFLAGS_RAYTRACE = $(DEBUG_LDFLAGS) $(COROUTINE_BASE_LDFLAGS) -pthread \
-sPTHREAD_POOL_SIZE='navigator.hardwareConcurrency' \
@ -177,11 +143,9 @@ LDFLAGS_REALPOOL = $(DEBUG_LDFLAGS) $(COROUTINE_BASE_LDFLAGS) -pthread \
# depend on them — otherwise editing a shim wouldn't trigger a relink.
JS = $(TOOLS_ROOT)/wx.js --pre-js $(TOOLS_ROOT)/wx-dom.js
JS_FILES = $(TOOLS_ROOT)/wx.js $(TOOLS_ROOT)/wx-dom.js
# The scheduler shim is a pre-js on every jspi link (ASYNC_LDFLAGS): apps
# whose objects are up to date must still relink when it changes.
ifeq ($(PCBJAM_ASYNC_BACKEND),jspi)
# The scheduler shim is a pre-js on every link (ASYNC_LDFLAGS): apps whose
# objects are up to date must still relink when it changes.
JS_FILES += $(JSPI_SHIM)
endif
HTML = $(TOOLS_ROOT)/template.html
# wxWidgets library directory - used as dependency to rebuild when libs change
@ -249,7 +213,6 @@ all: minimal_test.html \
$(S)/coroutine/coroutine_test.html \
$(S)/coroutine-nested/nested_test.html \
$(S)/asyncify-races/races_test.html \
$(S)/sched-context/sched_context_test.html \
$(S)/coroutine-pthread/coroutine_test_wxpt.html \
$(S)/coroutine-pthread/embind_repro.html \
$(S)/coroutine-pthread/gl_repro.html \
@ -794,18 +757,6 @@ $(S)/coroutine-nested/nested_test.html: $(S)/coroutine-nested/nested_test.o $(S)
$(CXX) $(filter %.o %.a,$^) $(LDFLAGS_COROUTINE) --pre-js $(JS) --shell-file $(HTML) -o $@
../../scripts/common/inject-dyncall-shims.sh $(basename $@).js
# Asyncify race-condition red-green harness (tests/asyncify/). Three variants of
# Scheduler-context harness (docs/features/async/20 D1/D2, 21). The layer is
# header-only in wx's wasm port (wx/wasm/private/sched_context.h — D2 puts wx's
# own dispatch on it), so this app needs no wx LIBRARY, just the include path:
# a failure here can still only be the contexts layer.
SCHED_CTX_INC = ../../wxwidgets/include
$(S)/sched-context/sched_context_test.o: $(S)/sched-context/sched_context_test.cpp $(SCHED_CTX_INC)/wx/wasm/private/sched_context.h
$(CXX) -c $(CXXFLAGS) -I$(SCHED_CTX_INC) $< -o $@
$(S)/sched-context/sched_context_test.html: $(S)/sched-context/sched_context_test.o
$(CXX) $^ $(LDFLAGS_SCHED_CTX) --shell-file $(HTML) -o $@
../../scripts/common/inject-dyncall-shims.sh $(basename $@).js
# (The trampoline-heal / handleSleep ablation variants — races_test_noheal /
@ -890,7 +841,6 @@ retinascale: $(S)/retinascale/retinascale_test.html
coroutine: $(S)/coroutine/coroutine_test.html
coroutine-nested: $(S)/coroutine-nested/nested_test.html
asyncify-races: $(S)/asyncify-races/races_test.html
sched-context: $(S)/sched-context/sched_context_test.html
# Only delete generated app files (*_test*, *_repro*) — a bare $(S)/*/*.js would
# also delete checked-in sources like coroutine-pthread/worker_dom_stub.js.

View file

@ -1,6 +1,6 @@
#!/bin/bash
# Ad-hoc build for the jspi-coroutine harness (Makefile.wasm wiring in Phase 3).
# Compiles the REAL kicad/thirdparty/libcontext with -DPCBJAM_JSPI.
# Compiles the REAL kicad/thirdparty/libcontext (JSPI backend).
set -eo pipefail
cd "$(dirname "$0")"
ROOT="$(cd ../../../.. && pwd)"
@ -9,7 +9,7 @@ LIBCTX="$ROOT/kicad/thirdparty/libcontext"
"$EMXX" coroutine_jspi_test.cpp "$LIBCTX/libcontext.cpp" \
-I"$LIBCTX" \
-DPCBJAM_JSPI=1 \
\
-O1 \
-fwasm-exceptions -sSUPPORT_LONGJMP=wasm -sWASM_LEGACY_EXCEPTIONS=1 \
-sJSPI -sJSPI_EXPORTS=pcbjam_libctx_entry,main \

File diff suppressed because it is too large Load diff