Thermal runs on Windows and Intel machines, a register fix for compiled code on Windows, try / catch compiles, and reading a growing string is 200 times faster
Thermal, the optimizing compiler Floati writes for itself, now runs on x86-64 as well as on ARM64: it builds Updraft IR, Floati's own compiler core, which lowers it for both processors. On an x86-64 machine a murmur3 hash went from 1,606 to 166 ms and a Math.imul hash from 1,844 to 87 ms, so Windows and Intel machines now sit as close to the reference engine as Apple silicon Macs do. This release also fixes a bug on Windows: compiled code used three floating-point registers the Windows calling convention says a function must leave as it found them, and compiled code now saves them; it also tells Windows how to walk through its frames, so crash reports and debuggers see the whole stack. Functions with try / catch now run on the plan interpreter instead of the slowest tier, a loop that adds to a string and reads the newest character went from 1,079 to 5 ms (the reference engine takes 66), and two places where Floati differed from the standard are fixed: a throwing Symbol.hasInstance getter, and a getter defined over a built-in array method.
One Thermal for both processors
Thermal compiles a hot loop with its numbers kept in the processor's registers. Until now it wrote ARM64 instructions directly, so on x86-64 hot hashing and numeric loops never reached it. Thermal now builds Updraft IR, the compiler core every other Floati compiler already uses, and Updraft lowers it for ARM64 and x86-64 alike: one Thermal, both processors, with the IR's register allocation and loop optimizations underneath. Two refinements came with it, on both processors. A parameter that has only ever held integers is kept as an integer (checked at the function's entry, and any other value runs the function in its other tiers), so a hash whose state starts from a parameter stays in an integer register instead of becoming a double at the top of its loop. And a 32-bit value that was just widened is not narrowed again by a separate instruction. The IR version is checked against the ARM64 emitter on every test map in two more test configurations, one of which leaves compiled code at every third operation, on Apple silicon and on x86-64 Linux.
Compiled code on Windows keeps the caller's registers
On Windows, the registers xmm6 to xmm15 belong to the caller: a function that uses one must put back what it held. Floati's compiled code used xmm13 to xmm15 as scratch registers without saving them, which is fine on macOS and Linux and wrong on Windows. A new test that fills every register Windows says must survive a call, calls compiled code, and checks each one afterwards found it at once. Compiled code on Windows now saves and restores them. Compiled code is also registered with Windows' unwinder now: each function's prologue is described the way the operating system expects, so a crash report, a debugger or a profiler can walk from compiled code back to its caller.
try / catch, growing strings, and two standard fixes
A function with try / catch used to stay in the bytecode interpreter, the slowest tier, and minified code often names a catch binding after a parameter (function(e){ try {...} catch(e) {...} }), which also kept a function there. Both now run on the plan interpreter: a thrown error inside a try goes to its catch with the operand stack restored, an error a callee throws is caught the same way, and a caught error carries the stack trace it would have had. Budget stops and interrupts stay uncatchable, as they are in the interpreter. Appending to a long string builds a rope (the pieces are not copied each time), but reading one character flattened the whole rope into a flat string, so a loop that appends and reads the newest character was quadratic. Characters are now read from the rope where they sit. A Symbol.hasInstance defined as a getter that throws now throws from instanceof, as the standard says, and a getter defined over a built-in array method such as push is what arrays call.
What changed 7 changes
Try it in your browser
Each check runs live in the browser you are reading with. Nothing is sent anywhere.