fix(wasm): dynCall signature-mismatch fallback + eeschema collab wire converters

Two things, both verified in the real web app (two-tab eeschema collab).

1. dynCall crash fix (all apps) — scripts/common/shims/dyncall-binding.js.tmpl.
   Programmatic editor edits trapped with 'indirect call signature mismatch': the
   asyncify-instrumented wasmExports[dynCall_<sig>] trampoline does call_indirect with a
   stale type for some table indices (post-asyncify+O2) even though the table entry is
   valid. Proven by patching the built js: at the trap getWasmTableEntry(index) SUCCEEDS
   where the trampoline fails. Fix: the shim now catches the 'signature mismatch'
   RuntimeError and falls back to getWasmTableEntry; the Asyncify unwind sentinel and real
   exceptions re-throw, so instrumentation/unwind is untouched for normal calls. This
   unblocks ALL programmatic edits, not just collab (e.g. eeschema SCH_ITEM::Move).

2. eeschema collab apply converters (wasm/bindings/eeschema_embind.cpp).
   doApply now handles added-item construction (build the SCH_ITEM with the delta's uuid
   via const_cast — as the s-expr parser does — + commit.Add) and richer SCH_LINE
   serialization (start/end/layer) so wire edits reconstruct on the peer. Implemented for
   SCH_LINE (wires) + SCH_JUNCTION; other types log 'no converter for added type' and are
   skipped (next batch). eeschema re-enabled in the web app collab gate.

Tests: eeschema-collab.spec snapshot (green); apply/two-tab skipped — they no-op headless
because the e2e harness's kicadOpenFile returns false (OpenProjectFiles bails before
building the connectivity graph), so SCH_COMMIT::Push doesn't persist. Verified in-app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Gergő Törcsvári 2026-06-03 19:37:15 +02:00
commit b5b1a0ac05
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
5 changed files with 228 additions and 55 deletions

View file

@ -1,5 +1,6 @@
#!/bin/bash
# Post-process Emscripten-generated pcbnew.js for KiCad WASM.
# Post-process the Emscripten-generated <app>.js for KiCad WASM (pcbnew, eeschema,
# pl_editor, calculator, …).
#
# The actual JavaScript that gets injected lives in readable, standalone files in
# scripts/common/shims/ (not inline heredocs):

View file

@ -4,9 +4,22 @@
//
// Binds the bare name to the REAL asyncify-instrumented wasm export
// (wasmExports["dynCall_<sig>"], present because the build links -sDYNCALLS=1).
// Falls back to getWasmTableEntry only if no such export exists.
// Falls back to getWasmTableEntry if no such export exists, OR if the instrumented
// trampoline traps with "indirect call signature mismatch": post-asyncify+O2 the
// trampoline can call_indirect with a stale type for some table indices even though
// the table entry itself is valid (hit by programmatic editor edits, e.g. eeschema
// SCH_ITEM::Move via invoke_vii — see features/yjs-bridge/0003). The direct
// getWasmTableEntry call uses the correct per-entry signature and succeeds. Only the
// mismatch trap is caught; the Asyncify unwind sentinel and real exceptions re-throw,
// so instrumentation/unwind still work for every normal indirect call.
function dynCall_@SIG@(@ARGS@) {
var f = (typeof wasmExports !== 'undefined') && wasmExports["dynCall_@SIG@"];
if (f) return f(@ARGS@);
if (f) {
try { return f(@ARGS@); }
catch (_dce) {
if (!(_dce instanceof WebAssembly.RuntimeError) || !/signature mismatch/.test(_dce.message))
throw _dce;
}
}
return getWasmTableEntry(index)(@CALLARGS@);
}