Thermal, Floati's own optimizing compiler, is on: hot loops keep their numbers and strings in registers
This release switches on Thermal, the optimizing tier of Updraft, the compiler Floati writes for itself. When a function with a loop gets hot, Thermal compiles it straight to ARM64 machine code with its numbers, whole numbers, true/false values and plain-text strings held in the processor's registers instead of in memory, and reads a string's characters where they already are. Loops that hash strings, mix bits or count run 2.4 to 5.8 times faster than in 0.1.357, and a class-name hash of the kind news sites run is now within about twice the reference engine. Functions with a short loop called many times now compile as a whole instead of entering the loop tier on every call, functions that use the bitwise NOT (~) compile at all, and very large functions no longer pay a big optimizing compile that did not make them faster. Eleven real pages measure the same as before, and every page in Floati's test set draws pixel for pixel as it did.
Thermal: values in registers, not in memory
Gust, Updraft's first tier, compiles a function in well under a microsecond per operation, but keeps every value boxed in memory: each turn of a loop loads its variables, checks what kind of value each one holds, and stores them back. Thermal is the second tier. It reads the shape of a hot function, works out how long each value lives, gives the busiest ones a processor register for the whole loop, and writes ARM64 code directly, still in about half a microsecond per operation where the general-purpose code generator Floati still uses needs 80 to 400. Numbers stay as numbers, whole numbers stay as integers so bitwise operators and counters need no conversions, and a string the function was given is read in place: s.charCodeAt(i) becomes one byte read, checked once when the function starts rather than on every turn, which is safe because Thermal code never runs other scripts that could change String.prototype in between.
When a guess is wrong, nothing is lost
Thermal compiles for what a function has done so far: that a sum stays a whole number, that a position is inside the string. When one of those guesses fails, a sum past 2^53 or a position past the end, it writes the function's values into the frame the interpreter uses and the interpreter finishes the call from that exact operation; there is nothing to translate, because Floati's interpreter, Gust and Thermal all keep a call's values in the same frame. A function that keeps leaving, or that is called with values Thermal does not take (a string with accents, an object), is handed back to Gust and Cranelift as before. Every test map was also run with Thermal forced to leave at every third operation, and gave the same answers.
Why Floati turned it on now
Updraft has one rule: a tier replaces what it replaces only once it is better on every measured axis. Before switching Thermal on, every page in Floati's test set was drawn with it and without it and compared pixel for pixel, and eleven recorded real pages were timed both ways. The comparison found three mistakes that tests had missed, among them a string returned from a compiled loop coming back as true or false, which broke a table on a documentation site; each is fixed and has a test that fails without the fix. With them fixed, all pages draw identically and the eleven pages time the same (0.997 of before), so Thermal is on for Apple Silicon. Intel and Windows machines still use Cranelift until Updraft can write x86-64 code.
What changed 6 changes
Try it in your browser
Each check runs live in the browser you are reading with. Nothing is sent anywhere.