FEX 2608 Tagged

After what felt like a very quick month, it’s time for another FEX release. We’re busy writing improvements for next month’s release already, so let’s not distract for too long and smash through these changes!

Removal of deprecated FEXInterpreter binary

Back in the FEX-2510 release we completely removed a FEXLoader binary with a deprecation of the FEXInterpreter binary, renaming it to just FEX. We kept the FEXInterpreter binary around for a while because downstream projects had hardcoded the binary in their scripts and we wanted to give some time for them to migrate. After nearly a year we’re hoping that everyone has migrated to the new binary name. If your project is still using the old binary name then we recommend fix them!

The typical JIT improvements

As typical there are a bunch of JIT changes this month. Let’s breakdown what was fixed.

  • Use SVE XAR for SHA1 emulation as a minor optimization.
  • Fix JIT telemetry value unconstrained predictable problem on ARMv8.0
    • Would only cause some missed telemetry on ARMv8.0 platforms, very minor.
  • Optimize VMOVMASKPD/PS instructions.
    • Cutting from 11/10 instructions down to 7.
  • Fix incorrect emulation of BFP store instruction
  • Fixes crash if ProcessorID IR op was encountered on WINE
    • Silly little assert check that crashed.
  • A bunch more improvements to hardware with 256-bit SVE
  • Actually a ton of little bug fixes and edge cases getting patched up.

Fix VirtualProtect on win32

This change is fairly spicy because it means some of our memory protections were silently failing under WINE. With this fixed, it should fix some weird edge case crashes that weren’t able to be explained.

Fix overwriting memory region in allocation tracking

This is a bit of a weird case where FEX’s memory allocations on 48-bit VA systems were silently only ever using one allocation region. It was accidentally overwriting all regions with whatever the smallest allocation happened to be. Luckily on 48-bit systems, the smallest region would still be very large and unlikely to run out, but a bug fix is a bug fix.

Fix inactive JIT guard pages not being ignored

A funny little quirk of our JIT is that we rely on SIGSEGV to handle memory overflows safely. Where we try to calculate a size of code memory that gets generated from IR through a heuristic and if the size is calculated incorrectly we safely fault and longjump to try again. The times in which the heuristic is incorrect isn’t very frequent so the performance win of not range checking as heavily is a big win.

One problem is we forgot to turn off the JIT guard page checking when outside of the JIT, so if an application happens to access from [0, 4096), we would long jump back in to our JIT and hilarious crashes would occur. Oops!

Fixes AVX signal state saving and restoring

While signals are fairly rare, we implementing saving the AVX state incorrectly, which could cause us the fail to restore it if the application jumps to a new location. This is now fixed which should probably resolve a few crashes.

Spinloop using WFE on WINE

On WINE we had some spinloops that are required when an application is in the process of suspending a thread. We now spin using the WFE instruction which puts the ARM CPU in lower-power state while waiting on an atomic. This can shave off watts of power in this edge case, so it’s worth supporting!

Fix untracked thread handling

When a process creates a new thread using the Clone syscall API, there’s a lot of tricky edge cases to support. In one of those paths we were accidentally losing tracking of a thread in our frontend. Usually this is pretty benign but it could result in some broken TLS tracking due to a new thread data structure actually pointing to the parent thread. Oops!


See the 2608 Release Notes or the detailed change log in Github.

Written on August 4, 2026