Floati's JavaScript engine now works out facts about a hot function before compiling it, such as which values are always numbers and which loop counters stay whole numbers in range, and leaves out every check those facts make unnecessary. A special test mode puts each removed check back as a hard stop, so our whole test corpus confirms every fact. Tree-walking code like a virtual DOM diff runs about 13 percent faster, loops that test for undefined fields run up to 60 times faster, and freeing a very deep structure no longer crashes the tab.
Checks the engine can prove it does not need are gone. Before compiling a hot function, Floati now builds a map of its values (an SSA graph: every value named once) and proves facts about them: comparisons give true or false, arithmetic on numbers gives numbers, an array's length is a number, and a loop counter that starts at 0 and stays below a length is a whole number in range. The compiled code then skips the type checks and array index checks those facts cover. Equality tests against undefined, null, true or false became a single comparison.
JavaScript & JIT
Every removed check can be switched back on as a trap. In a special test mode each check the engine left out is compiled back in as an instruction that stops the program if it would ever fail, and our full test corpus runs that way on every change. A wrong fact cannot quietly compute on the wrong kind of value: it stops at the first one. Two deliberately planted wrong facts were each caught this way.
JavaScript & JIT
Loops that test whether a field is undefined now compile. Code like if (options.x === undefined) inside a hot loop, or in a small function the loop calls, used to make the loop fall back to the slowest tier. It now runs as compiled code: 50 times faster when the field is missing and 50 times faster when it is present, about 6 times faster than the reference browser's engine on the same test.
Memory & reading
Reading a property an object does not have is faster. Compiled code remembers that a name is missing for a given object shape and answers undefined straight away until a prototype changes: about 2.3 times faster on a missing-field test.
JavaScript & JIT
for (k in obj) loops read values straight from their slots. When the keys come from an object's own layout in order, reading another object with the same layout by those keys is a direct slot read instead of a lookup by name.
Memory & reading
Math.max and similar are looked up once. Functions read off objects like Math and JSON, and off prototypes, are remembered while nothing changes those objects; any change, including a replaced or redefined function, is seen at once.
Memory & reading
Less reference counting. The engine counts references to objects so it can free them the moment they are no longer used. Counting now skips values it has proven can never be objects, and freeing a large tree of objects runs as one loop instead of one nested call per object, so a structure a million levels deep no longer overflows the stack and crashes the tab when it is freed.
Rendering
Strings like 'item' + i are built once. Joining a short piece of text and a small whole number now reuses the text made the last time for the same pair, since two strings with the same characters cannot be told apart.
JavaScript & JIT
Fixed: after a page defined a getter over Math.max with Object.defineProperty, a compiled loop kept calling the built-in function. It now calls the getter.