#!/bin/bash # Post-process the Emscripten-generated .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): # - handlesleep.js nested-Asyncify handleSleep currData save/restore (#9153) # - diagnostics.js optional logging-only instrumentation (see SHIM_DIAGNOSTICS) # # Native wasm-EH is the only build mode, so the .js has no invoke_* wrappers / dynCall_ call # sites to bind. The build still links -sDYNCALLS=1, so asyncify-INSTRUMENTED dynCall_* trampolines # exist as wasm EXPORTS; the empty-callback fixes below route function-pointer stubs through # wasmExports["dynCall_"]. This MUST be the wasm trampoline, NOT getWasmTableEntry — the latter # bypasses the instrumentation and breaks unwind/rewind through indirect calls ("indirect call # signature mismatch" — caught every frame in Firefox; a hard renderer crash in Chrome/V8). # # Usage: # inject-dyncall-shims.sh # SHIM_DIAGNOSTICS=1 inject-dyncall-shims.sh # also inject diagnostics.js set -e JS_FILE="$1" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SHIM_DIR="$SCRIPT_DIR/shims" # One-line toggle for the diagnostics module (default OFF). SHIM_DIAGNOSTICS="${SHIM_DIAGNOSTICS:-0}" if [ -z "$JS_FILE" ] || [ ! -f "$JS_FILE" ]; then echo "Error: JS file not found: $JS_FILE" echo "Usage: $0 " exit 1 fi for f in handlesleep.js diagnostics.js; do if [ ! -f "$SHIM_DIR/$f" ]; then echo "Error: missing shim source $SHIM_DIR/$f" exit 1 fi done # --- 1. Empty-callback fixes --------------------------------------------------- # Emscripten+pthreads emits some direct-call paths as no-op ((a1)=>{}) stubs that ARE used. Native # wasm-EH eliminates the invoke_* wrappers, so the .js has no dynCall_ call sites to bind — but # the DYNCALLS=1 trampolines are still EXPORTED on the wasm, so route each function-pointer stub # through wasmExports["dynCall_"]. This MUST be the wasm trampoline, NOT getWasmTableEntry: the # fiber entry runs a coroutine that suspends+rewinds via Asyncify, and an Asyncify rewind cannot # resume through getWasmTableEntry's JS wrapper — the fiber would re-enter from the top and the tool's # Wait() re-runs (tool_manager ScheduleWait "!pendingWait" assert + busy-loop). The instrumented # dynCall_ export rewinds correctly. (Without these fixes the libcontext fiber entry stays the # empty (a1=>{}) stub, so tool coroutines never start and every GAL app stalls at InvokeTool.) echo "Fixing empty callback arrow functions..." TOTAL_FIXED=0 apply_fix() { #