host: call fpcast-emu'd pthread entry functions with the correct ABI#841
Open
brandonpayton wants to merge 1 commit into
Open
host: call fpcast-emu'd pthread entry functions with the correct ABI#841brandonpayton wants to merge 1 commit into
brandonpayton wants to merge 1 commit into
Conversation
Kandelo user programs are post-processed with binaryen's `--fpcast-emu` (see optimize_wasm in scripts/ports/*), which rewrites every indirectly-called function to one uniform trampoline signature: N i64 parameters and an i64 result. pthread entry points are reached by the host through `table.get(fnPtr)` — an indirect reference — so they too get the emulated signature. centralizedThreadWorkerMain called the entry as `threadFn(argPtr)` with a plain JS number, which throws `TypeError: Cannot convert <ptr> to a BigInt` because the trampoline's first parameter is i64. This surfaced as the first program that is BOTH fork-instrumented and multi-threaded (pcmanfm) crashing on its first gio/glib worker thread; single-axis programs (leafpad is threaded but not fpcast-relevant here, openbox is fork-instrumented but single-threaded) never hit it, and non-fpcast programs (nginx, cpython) keep the plain (i32)->i32 entry. Add buildThreadEntryArgs(), which uses the function wrapper's parameter count to pick the ABI: a plain C entry has exactly one pointer parameter (i32 on wasm32, i64 on wasm64); an fpcast-emu trampoline has N all-i64 parameters, so pass the pointer arg first as a BigInt and zero-fill the rest. Applied at all three entry call sites (the main run loop, the non-instrumented path, and the fork-from-thread child). Programs with a 1-param entry are unaffected — that branch reproduces the previous behaviour exactly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Kandelo user programs are post-processed with binaryen's
--fpcast-emu(seeoptimize_wasminscripts/ports/*), which rewrites every indirectly-called function to one uniform trampoline signature: Ni64parameters and ani64result. pthread entry points are reached by the host throughtable.get(fnPtr)— an indirect reference — so they get the emulated signature too.centralizedThreadWorkerMaincalled the entry asthreadFn(argPtr)with a plain JS number, which throwsTypeError: Cannot convert <ptr> to a BigIntbecause the trampoline's first parameter isi64.This surfaced as the first program that is both fork-instrumented and multi-threaded (pcmanfm, in the LXDE port) crashing on its first gio/glib worker thread:
Single-axis programs never hit it — openbox is fork-instrumented but single-threaded; non-fpcast programs (nginx, cpython) keep the plain
(i32)->i32entry.Fix
Add
buildThreadEntryArgs(), which uses the function wrapper's parameter count (fn.length) to pick the ABI:i32on wasm32,i64on wasm64): pass the arg as before.i64parameters: pass the pointer arg first as aBigIntand zero-fill the remaining slots.Applied at all three entry call sites (the main run loop, the non-instrumented path, and the fork-from-thread child). Programs with a 1-param entry reproduce the previous behaviour exactly, so nginx/cpython/etc. are unaffected.
Verification
Built pcmanfm (GTK2 + libfm, fork-instrumented + threaded) and ran it under Xfbdev in the browser. Before: crashes on the first worker thread. After: pcmanfm runs and renders a full file-manager window browsing the guest VFS, with no thread-worker errors.
tsc --noEmitclean forworker-main.ts.🤖 Generated with Claude Code