design-b D-1: bump wxwidgets (gating + legacy twins deleted) + shim cleanup

wxwidgets c44c684f7d (D-1c: scheduler lanes unconditional,
wxWasmMailboxEnabled gone, fail-fast shim assert) + 24843897e8 (D-1d:
startModal / wxWasmRunNestedLoop / popup pump / resolver stacks / bare
emscripten_async_call timer entries deleted).

pcbjam side of D-1d: the scheduler shim's delivery-tick error path uses
wait-registry containment (resolveTopWait nested+modal) instead of the
deleted _wxNestedLoopExit stack, and diagnostics.js tracks modal
lifecycle via pendingWaits('modal') instead of the deleted
Module._endModal hook.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEHGiiXMShNXbBr7gSJ7iz
This commit is contained in:
Gergő Törcsvári 2026-08-05 20:10:33 +02:00
commit de27ecf327
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
3 changed files with 19 additions and 19 deletions

View file

@ -63,8 +63,11 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) {
} catch (e) {
self._tickArmed = false;
if (Module["_wx_dispatch_abandon"]) Module["_wx_dispatch_abandon"]();
var exits = Module["_wxNestedLoopExit"];
if (exits && exits.length) (exits.pop())();
// Same containment as the top-level tick's error path (evtloop.cpp):
// a throwing handler must not leave a parked quasi-modal unresolved.
// No-ops when no such wait is open (5101 = wxID_CANCEL).
self.resolveTopWait('nested', 0);
self.resolveTopWait('modal', 5101);
throw e;
}
if (self.mailbox.length > 0) {
@ -158,7 +161,7 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) {
// pre-resolves the promise — yieldUntil then returns immediately. Per-kind
// LIFO stacks give wx modal/nested semantics ("innermost first") without
// the legacy per-wait resolver stacks (_wxModalResolvers /
// _wxNestedLoopExit), which die on scheduler builds. Resolution flows
// _wxNestedLoopExit — deleted at doc 20 D-1). Resolution flows
// through the S2 deferred-wake law automatically: resolving a wait wakes
// its parked sleep via the wrapped handleSleep path.
waits: new Map(), // token → {kind, promise, resolve, resolved}

View file

@ -87,27 +87,24 @@
};
}
// 5. Modal lifecycle (startModal sets Module._endModal; detect appear/disappear).
// 5. Modal lifecycle: poll the scheduler wait registry ("modal" waits).
// (The legacy Module._endModal hook was deleted at doc 20 D-1.)
if (typeof Module !== "undefined") {
var seen = false;
var lastModalWaits = 0;
setInterval(function() {
if (Module._endModal && !seen) {
seen = true; modalActive = true;
console.log("[DIAG_MODAL] modal started, state=" + asyncState());
var __origEnd = Module._endModal;
Module._endModal = function(code) {
console.log("[DIAG_MODAL] EndModal code=" + code + " state=" + asyncState());
modalActive = false;
return __origEnd(code);
};
} else if (!Module._endModal && seen) {
seen = false;
console.log("[DIAG_MODAL] modal cleanup, state=" + asyncState());
var S = globalThis.__wxScheduler;
if (!S || typeof S.pendingWaits !== "function") return;
var n = S.pendingWaits("modal");
if (n !== lastModalWaits) {
console.log("[DIAG_MODAL] modal waits " + lastModalWaits + " -> " + n +
", state=" + asyncState());
modalActive = n > 0;
lastModalWaits = n;
}
}, 100);
}
// 6. EM_ASYNC_JS sleeps (startModal, js_enumerateFonts, clipboard, etc.) — log
// 6. EM_ASYNC_JS sleeps (wxWasmYieldUntilJs, js_enumerateFonts, clipboard, etc.) — log
// enter/wake so we can see whether an async sleep is NESTED with a fiber swap
// at the crash (the #9153 collision). Logging only; delegates unchanged.
if (typeof Asyncify !== "undefined" && typeof Asyncify.handleSleep === "function") {

@ -1 +1 @@
Subproject commit a395abd019b733ba186543ff668a068e461abd96
Subproject commit 24843897e8f381def1fb3e8ac0d02c3f46fc39bc