Loops that test a number run as machine code, more of your functions compile, and reading page nodes is three times faster
This release removes a hidden slow path that hit a very common kind of loop: one that tests a number, like if (i & 1) or if (n % 3). Floati's fastest loop tier used to turn such loops down and run them one operation at a time; now they run as machine code, 13 to 31 times faster, and one of them faster than the reference engine. Many more functions now compile: ones with block-scoped let and const, a switch, unary minus, assignments to outer variables, or a throw, and a function's first long loop moves into compiled code while it runs. Compiled code reads page nodes such as parentNode three times faster. Thermal, the optimizing tier of Floati's own compiler Updraft, has its first stages built and measured, switched off in this release. Nine correctness bugs are fixed, one of them a crash after an error in a hot function.
Loops that test a number run as machine code
Floati's fastest loop tier works out the type of every value in a loop before it compiles it. A test such as if (i & 1), if (n % 3) or while (k) is a number, not true or false, and the tier only accepted true or false, so it turned the whole loop down. The loop then ran in the register interpreter, one operation at a time, at about 30 nanoseconds per turn. A number is now accepted as a test, with the meaning JavaScript gives it: true unless it is 0, -0 or NaN, checked in a few machine instructions. A loop that tests a bit runs 30 times faster and now beats the reference engine.
More of your functions compile
Floati compiles a function once it has run often enough to pay for it, but some ways of writing a function kept it in the slowest interpreter however hot it got: any block scope (let or const inside a block or a for, or a switch), unary minus, a function-level let or const, assigning a variable outside the function (a counter in a closure, a module variable), or a throw. On sampled pages, block scopes alone kept about two in five interpreted calls out of compiled code. All of these now compile, each with the interpreter's exact rules (a let read before its declaration still throws, every loop turn still gets its own binding). A function that runs once with a long loop, like a setup or main function, now moves into its compiled code in the middle of that loop. Compiled code also does bitwise operators and string methods such as charCodeAt itself instead of calling general helpers, and compiling a very large function no longer takes time that grows with the square of its size.
Reading page nodes is three times faster
When compiled code reads el.parentNode or el.firstChild, it used to go through a general path that matched the property name as text, checked for SVG overrides and built a fresh value for the node every time. Now each compiled site remembers what kind of member it reads and calls the node directly, and every node keeps one value that all reads hand out, as the reference engine keeps one wrapper per node. Defining your own property on a node with Object.defineProperty also behaves as in the reference browser now: it shadows the built-in one, keeps the writable and enumerable settings you gave it, and getOwnPropertyDescriptor lists only what you defined.
Thermal, the optimizing tier, is under way
Updraft is the compiler Floati is writing for itself (0.1.354 explained why). Its first tier, Gust, compiles quickly but keeps every value boxed in memory. Thermal is the tier that keeps numbers in machine registers, and its first stages are now built: it reads the shape of each function, works out how long every value lives, assigns registers, and writes ARM64 code directly, in about half a microsecond per operation, where the general-purpose code generator Floati still uses needs 80 to 400. On a numeric benchmark Thermal's code runs 2.7 times faster than what ships today with less memory, and a numeric loop comes within a factor of two of the reference engine. It is switched off in this release: it compiles only functions made of numbers so far, and the rule stays that each part of Updraft is switched on only once it beats what it replaces on every measured axis.
What changed 14 changes
Try it in your browser
Each check runs live in the browser you are reading with. Nothing is sent anywhere.