deps(tinycc): enable bun:ffi on Windows ARM64 - #29476
Conversation
Bumps oven-sh/tinycc to c49c2204 which adds the arm64-coff/PE backend, drops the windows-arm64 build exclusion, and removes the corresponding test skips so CI exercises bun:ffi on that target.
|
Updated 10:22 AM PT - Jul 7th, 2026
❌ @autofix-ci[bot], your commit 7a45e12 has 5 failures in
🧪 To try this PR locally: bunx bun-pr 29476That installs a local version of the PR into your bun-29476 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (8)
WalkthroughThis PR enables TinyCC support on Windows ARM64 by changing its default feature flag to Changes
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Test message |
|
Found 1 issue this PR may fix:
Generated with Claude Code |
|
Found 1 issue this PR may fix:
🤖 Generated with Claude Code |
There was a problem hiding this comment.
LGTM — mechanical commit bump, config default update, and skip-guard removal all align correctly with the upstream ARM64-COFF support landing in oven-sh/tinycc.
Extended reasoning...
Overview
The PR touches three areas: the TinyCC dependency definition (, , ) and test skip guards across four test files. The core change is bumping from to and removing the platform exclusion that was the only thing preventing TinyCC from building on Windows ARM64.
Security Risks
None. This is a dependency commit bump for an embedded C compiler used at runtime by bun:ffi. The change doesn't touch auth, crypto, permissions, or any code path accessible from untrusted input beyond what was already exercised by FFI on other platforms.
Level of Scrutiny
Low. The changes are mechanical: the build config default goes from a conditional to true, the commit hash is bumped, and test skip guards () are removed. The tinycc.ts DirectBuild spec already had the correct conditional source lists — arm64-gen.c, arm64-link.c, arm64-asm.c for cfg.arm64, and tccpe.c for cfg.windows — so the infrastructure was already in place; only the gate and the pinned commit needed updating.
Other Factors
The PR author explicitly notes CI is being used to validate ("opening to see what windows-aarch64 CI says"), which is the right approach. No bugs were found by the automated system. The patch noted as still applying cleanly is a good signal. The comment cleanups in and are accurate and non-breaking.
Conflict resolution keeps main's newer tinycc gate exclusions (android, freebsd) and drops only the windows-arm64 term this PR removes. In the FFI tests it drops the windows-arm64 half of isFFIUnavailable everywhere main added it, including the two skip sites (cc.test.ts:394,460) that did not exist when this branch was written, while keeping the canBuildNodeAddons() guard main introduced in napi-value-ffi.test.ts.
|
Merged Conflict resolution. The tinycc gate in The real blocker isn't the diff. On the last full CI run before this (build #46411), the windows-aarch64 lane — the only target this PR exists to enable — crashed on the newly un-skipped tests ( Heads-up on #32013. That PR adds a |
The tinycc term was removed from cfg.tinycc in scripts/build/config.ts, but two Rust-side mirrors of that predicate (both marked "keep in sync with cfg.tinycc") still excluded windows-aarch64, so libtcc.a was built there while bun_core::Environment::ENABLE_TINYCC stayed false and every bun:ffi entry point kept returning "TinyCC is disabled": - scripts/build/buildOptionsRs.ts: drop the all(windows, aarch64) term from the emitted ENABLE_TINYCC cfg - src/tcc_sys/tcc.rs: drop it from both cfg lists around tcc_externs! so the real extern block (not the unreachable!() stubs) is used, and fix the stale "no aarch64-pe-coff backend" comment Also finish the test sweep the earlier pass missed: - test/js/bun/ffi/ffi.test.js: remove isFFIUnavailable (isWindows && isArm64) and its two skipIf uses - test/js/node/fs/cp.test.ts: un-gate the bun:ffi dlopen handle-leak repro on Windows arm64 - test/js/bun/ffi/cc.test.ts: delete the stale "disabled on Windows ARM64" comment - test/js/node/process/process.test.js: update the expected process.versions tinycc commit to the bumped TINYCC_COMMIT cargo check passes for all 10 CI targets including aarch64-pc-windows-msvc.
|
Pushed 6dd7783 addressing the review comments. The two Rust mirror predicates are now updated (#29476 (comment)): The two extra skip sites are un-gated (#29476 (comment)): Exhaustive sweep over the repo (
Verified locally: One important note on reading CI history for this PR: all previous windows-aarch64 failures/crashes on this branch are not evidence that FFI crashes on that platform. Until this commit the Rust runtime gate ( |
|
The fresh
I believe this is a missing instruction-cache flush in TinyCC's Windows JIT path, and it's ~5 lines.
#ifdef _WIN32
...
if (!VirtualProtect(ptr, length, protect[mode], &old)) /* no icache flush */
return -1;
#else
...
if (mprotect(ptr, length, protect[mode]))
return -1;
# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
if (mode == 0 || mode == 3) {
void __clear_cache(void *beginning, void *end);
__clear_cache(ptr, (char *)ptr + length); /* icache flush: POSIX arm ONLY */
}
# endif
#endifThe post-JIT instruction-cache flush exists only in the POSIX arm. That was always harmless, because Windows TinyCC has only ever run on x86/x86_64, whose i-cache is hardware-coherent with the d-cache. AArch64's is not: JIT'd code written through the d-cache and then executed without an explicit flush runs whatever stale bytes are in the i-cache — which presents as exactly The fix is textbook, and the API is already in TinyCC's own bundled Win32 headers ( #ifdef _WIN32
DWORD old;
if (!VirtualProtect(ptr, length, protect[mode], &old))
return -1;
# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
if (mode == 0 || mode == 3)
FlushInstructionCache(GetCurrentProcess(), ptr, length);
# endif
#elseGuarded to Confidence, stated honestly: the mechanism is proven absent from the source and required by the architecture, it is present on every sibling aarch64 platform, and it matches the observed crash signatures exactly — but I cannot execute windows-aarch64 here, so it is a very-high-confidence static conclusion, not an observation. The Where the fix should live. The real home is one commit in Secondary suspect, explicitly unverified: cc @dylan-conway (your PR) — with this, #28055 looks like it goes from "needs hardware and unknown work" to a 5-line upstream fix. |
|
Update on my icache analysis above — good news, and it changes the conclusion: The flush already exists. The one thing this PR needs to know: it cannot simply bump its own This PR depends on #33653. Merge order: land #33653 first, then rebase this branch onto |
|
Correction and, I think, the resolution — my two comments above are superseded and I want the record straight rather than someone acting on them. The icache flush is real but necessary-and-not-sufficient. A deeper investigation (see #33696) already established that with the flush present the win-aarch64 FFI failures persist, and found the actual remaining killer: TinyCC's arm64 backend tests "fits in an add/sub immediate" with The complete, working enablement already exists: #33696 (TinyCC upgrade + both fixes + Which makes this PR, as far as I can tell, superseded by #33696 (this branch is strictly behind: it has the enablement but neither TinyCC fix nor the |
|
Superseded by #33696, which carries the same windows-arm64 un-gating plus the two TinyCC fork fixes (LLP64 immediate masks, arm64 |
## Summary Supersedes #33653 (the TinyCC upgrade; the first commit here is that PR's content) and #29476. Enables `bun:ffi` on Windows ARM64: drops the windows-arm64 exclusion from `cfg.tinycc`, the generated `ENABLE_TINYCC` constant, and the `tcc_sys` link stubs, un-skips the FFI tests that were gated on the platform, and bumps the TinyCC pin to [`oven-sh/tinycc@05f0fafa`](oven-sh/tinycc@05f0faf) (which is [`8a6cbc12`](oven-sh/tinycc@8a6cbc1) plus oven-sh/tinycc#3). ### The windows-arm64 bug this uncovered (root-caused and fixed in the TinyCC fork) Enabling the platform made the windows-11-aarch64 CI lane run the FFI suites on real hardware for the first time, which exposed wrong doubles (`sum(0.5…9.5)` = 46 instead of 50) and segfaults in every JSCallback test. Root cause, proven with an in-CI probe that dumped the JIT machine code from the runner: TinyCC's arm64 backend decides whether a 64-bit constant fits an ADD/SUB immediate with `!(val & ~0xffful)`. On an **LLP64 host** (which is exactly how Bun builds TinyCC into `bun.exe` on Windows via clang-cl) `unsigned long` is 32 bits, so `~0xffful` zero-extends to `0x00000000fffff000`, and any constant with no bits in [12,32) "fits". `1ll << 49` is JSC's `DoubleEncodeOffset`, used by every `bun:ffi` trampoline, and it compiled to `add xN, xN, #0`: - machine code on the CI runner: `… ldur x0,[x29,#-8]; add x0,x0,#0 …` - same source, LP64-built tcc: `… mov x30,#0x2000000000000; add x0,x0,x30 …` So every double crossing the FFI boundary lost the NaN-boxing offset (JS saw `bits − 2^49`: 12.25→11.25, 50→46) and pointer arguments decoded to wild addresses (the segfaults). LP64-built TinyCC (Linux/macOS) is unaffected; the fix produces byte-identical output there, which is why the bug only ever existed on Windows ARM64. Fixed in the fork (`arm64_gen_opic`, `arm64_check_offset`, `arm64_sym`) by using `uint64_t`-typed masks; TinyCC's own test suite passes, and oven-sh/tinycc#3 adds regression cases to `tests2/73_arm64`. This also affects any natively-built windows-arm64 TinyCC upstream. ### Known parity notes (pre-existing, unchanged) - `cc()` code with a >4 KB stack frame needs `__chkstk`, which Bun doesn't provide on any Windows target. - `long double` soft-float helpers aren't provided on any arm64 target. ## Test plan - [x] Linux/macOS/Windows-x64 behavior unchanged (same suites as #33653; LP64 tcc output byte-identical across the fix) - [x] Cross-built windows-arm64 `bun.exe` from Linux links with TinyCC enabled - [x] windows-11-aarch64 CI lane: `bun:ffi` suites green with the LLP64 fix (build #71302, and re-verified locally on Windows 11 ARM64 at `e83d3d00`) Fixes #28055 --------- Co-authored-by: robobun <117481402+robobun@users.noreply.github.com>
oven-sh/tinycc gained an arm64-coff/PE backend in oven-sh/tinycc#1 and the follow-up commits on
mob, but Bun was still pinned to the commit before that work landed.This PR:
TINYCC_COMMITfrom12882eeetoc49c2204(currentmobHEAD).!(windows && arm64)default forcfg.tinyccso the dep builds on all targets.isFFIUnavailable = isWindows && isArm64skip guards from the FFI/cc/napi tests and thefs.writeSyncSetStdHandle repro so CI exercisesbun:ffion windows-aarch64.Left untouched: the
esbuild/require-cachewin-arm64 skips, which are about npm packages lacking win32-arm64 prebuilts and unrelated to FFI.The existing
tcc.h.patchstill applies cleanly; the upstream diff only touches lines further down. tinycc compiles with the new commit on linux-x64.Opening to see what windows-aarch64 CI says.