Repository navigation
x86_64: check OSXSAVE+XCR0 for AVX, read BMI1/AVX2 from EBX - #198
Merged
Jarred-Sumner merged 1 commit intoApr 24, 2026
Merged
Conversation
collectCPUFeatures() on Linux/Windows was deciding AVX is available based solely on CPUID.1:ECX[28]. That bit only says the CPU implements AVX; it says nothing about whether the OS has enabled XSAVE and set XCR0 to preserve YMM state. Under several hypervisors (Xen, Hyper-V, some KVM configurations, Windows VMs without AVX passthrough) the AVX feature bit is passed through from the host while OSXSAVE/XCR0 is not, so every VEX-encoded instruction raises #UD. The JIT's supportsAVX() guard returned true in these environments and the generated code faulted with SIGILL. Follow the Intel SDM detection sequence: require ECX[28] (AVX) and ECX[27] (OSXSAVE), then execute XGETBV and require XCR0[2:1]==11b before reporting AVX as usable. Separately, the non-Darwin leaf-7 probe was reading ECX for BMI1 and AVX2. Those bits live in EBX (BMI1=EBX[3], AVX2=EBX[5]); ECX[3]/ECX[5] are PKU/WAITPKG. Read EBX instead, and additionally gate AVX2 on the AVX result since AVX2 instructions are VEX-encoded and need the same OS state.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughModified CPU feature detection for x86-64 architecture. AVX usability now requires XCR0 check via Changes
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
This was referenced Jul 15, 2026
tobocop2
added a commit
to tobocop2/WebKit
that referenced
this pull request
Jul 15, 2026
JSC assumed every x86_64 Mac has AVX in two places, so it emitted VEX-encoded
instructions on CPUs that cannot decode them and died with SIGILL:
- collectCPUFeatures() hardcoded s_avxCheckState = Set on Darwin, so
supportsAVX() reported true and the ~10 VEX codegen sites in
MacroAssemblerX86_64.h emitted AVX once code tiered up.
- The probe trampoline used vmovaps unconditionally on Darwin, and probe()
selected it without consulting supportsAVX(). This is reachable from
WebAssembly (WasmBBQJIT loop OSR entry and tier-up, WasmOMGIRGenerator's
catch prologue), not only from the debug-gated OSR-exit paths.
oven-sh#198 fixed the first bug for Linux/Windows and guarded the new code with
#if !OS(DARWIN), leaving Darwin on the old assumption. Use the same runtime
checks and the same dual-trampoline selection on Darwin, and un-gate readXCR0()
so it is available there.
Also gate Darwin's AVX2 detection on the AVX result, matching the non-Darwin
path. AVX2 is VEX-encoded and needs OS-enabled YMM state, so now that AVX is a
runtime check the two must not be able to disagree.
The assumption holds for every Mac Apple shipped with a supported macOS (Sandy
Bridge, 2011, and later). It does not hold on an older Mac running current macOS
via OpenCore, nor under Rosetta 2, which reports no AVX.
Non-Darwin is unaffected: the preprocessed output of this file for
!OS(DARWIN) is byte-identical before and after.
Reported by Wolfgang Fahl on a Xeon X5690 (Westmere, no AVX).
This was referenced Aug 18, 2026
Bundled Bun binary lacks AVX baseline support — crashes on non-AVX CPUs
anthropics/claude-code#33153
Open
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.
What
Fixes two bugs in
MacroAssemblerX86_64::collectCPUFeatures()on Linux/Windows that cause the JIT to emit VEX-encoded (AVX) instructions on machines where AVX is not actually usable.1. AVX detection missing OSXSAVE / XCR0 check
The non-Darwin path decided AVX was available based on
CPUID.1:ECX[28]alone:Per the Intel SDM, software must verify three things before executing AVX:
CPUID.1:ECX.AVX[28] = 1— CPU supports AVXCPUID.1:ECX.OSXSAVE[27] = 1— OS has enabledXGETBVXCR0[2:1] = 11b— OS saves XMM and YMM state on context switchChecking only (1) is insufficient. Under many hypervisors (Xen, Hyper-V, older KVM configs, cloud VMs without AVX passthrough),
ECX[28]is passed through from the physical CPU while the guest kernel has not enabled XSAVE/YMM state. Every VEX-encoded instruction then raises#UD→SIGILL.Every
if (supportsAVX())guard inMacroAssemblerX86_64.h(~80 sites),MacroAssembler::probe(),isX86_64_AVX()→Options::useWasmSIMD(), and the Yarr JIT all sit downstream of this — so a false positive here means the JIT emits VEX everywhere and crashes when the code runs.This is the cause of the "baseline build SIGILL in JIT code" class of Bun crash reports on VMs:
Bun's own
bun_cpu_features()uses__builtin_cpu_supports("avx")/IsProcessorFeaturePresent(PF_AVX_INSTRUCTIONS_AVAILABLE), both of which do perform the full OSXSAVE/XCR0 check — which is why Bun's crash reporter correctly printsno_avxwhile JSC's JIT simultaneously believes AVX is available.Fix: require
ECX[27](OSXSAVE), thenXGETBV(0)and check(XCR0 & 0x6) == 0x6before settings_avxCheckState. Same approach as simdutf (Source/WTF/wtf/simdutf/simdutf_impl.h:1029-1038), compiler-rt, and every other correct AVX detector.2. BMI1 / AVX2 read from wrong CPUID register
getCPUIDExreturns[EAX, EBX, ECX, EDX]. For leaf 7 sub-leaf 0, BMI1 is EBX[3] and AVX2 is EBX[5]. The code was readingcpuid[2](ECX) — sosupportsBMI1()actually reported PKU andsupportsAVX2()reported WAITPKG. On most modern Intel server CPUs this mis-reports AVX2 as unavailable (verified: Xeon Platinum 8375C hasEBX[5]=1butECX[5]=0).Fix: read
cpuid[1](EBX). Also gate AVX2 on the AVX result since AVX2 is VEX-encoded and requires the same OS YMM state.Scope
Linux and Windows only (
#if !OS(DARWIN)branches). Darwin is unchanged — it hardcodess_avxCheckState = Setand usessysctlbynamefor BMI1/AVX2, which is correct since every x86-64 Mac has AVX and macOS always enables it. There is nodarwin-x64-baselineBun build.The same code exists in upstream WebKit
main— this is not a fork regression; probably worth upstreaming.