SpiderMonkey is the JavaScript engine used in Mozilla Firefox. This newsletter gives an overview of the JavaScript and WebAssembly work we’ve done as part of the Firefox 76 and 77 Nightly cycles.
JavaScript
🏆 New contributors
- Kousuke Takaki fixed bug 1601734, tidying up some naming.
- Tuan fixed bug 1566116, deleting dead code.
🎁 New features
- Firefox 76: André updated ICU to version 66 with support for Unicode 13.
- Firefox 76:
numberingSystem
andcalendar
forIntl
objects can now be set through options. - Firefox 77:
String.prototype.replaceAll
is no longer Nightly-only and will ride the trains to release. - Firefox 77 (Nightly-only): André implemented the Logical Assignment Operators proposal (adds the
||=
,&&=
,??=
operators).
🗑️ Garbage Collection
- Jon made various changes to GC heuristics to avoid non-incremental GCs.
- Steve landed and enabled incremental marking for WeakMaps, a big change that will help reduce long GC slices, but to reduce risk this was backed out for Firefox 77. We’re hoping this sticks in Firefox 78!
- Jon made tracing of ‘auto rooters’ faster. He also noticed regressions on Linux64 from parallel unmarking and made performance improvements to fix that.
- Jon optimized tracing of certain DOM objects in Firefox by allowing per-Zone tracing instead of tracing all of them.
- Jon fixed various OOM (out of memory) crashes by adding memory accounting for malloc buffers associated with nursery cells and by improving GC malloc triggers.
- Steve updated the static analysis for rooting hazards to GCC 9.
⏩ Regular expression engine update
Iain finished implementing the SpiderMonkey shims and JIT support for the new regular expression engine and is planning to land these in the FF 78 cycle to switch to the new engine in Nightly! This will bring support for lookbehind assertions, the dotAll flag and unicode escape sequences.
Iain has also started working on supporting named groups and match indices.
📚 JSScript/LazyScript unification
With all the groundwork in place (see previous newsletters), Ted was able to unify JSScript and LazyScript! Functions no longer require a separate LazyScript and JSScript and delazification and relazification now happen in-place.
He then removed the LazyScript type completely and landed various follow-up changes to take advantage of the new system.
❇️ Stencil
Stencil is our project to create an interface between the frontend (parser, bytecode emitter) and the rest of the VM, decoupling those components. This lets us improve performance, simplify a lot of code and improve bytecode caching. It also makes it possible to rewrite our frontend in Rust (see SmooshMonkey item below).
The team is making good progress:
- Caroline split the script flags into multiple categories so it’s easier to assert correctness and reason about them. She also made various other changes to improve the script flags.
- Ted also simplified some flags and then fixed their documentation.
- Matthew removed more dependencies on JSScript and was then able to defer JSScript allocation to a later point in the bytecode emitter.
- Matthew disconnected FunctionBox from ScriptStencil and started removing dependencies on JSFunction. This will allow us to defer JSFunction allocation as well.
- André finished deferring RegExpObject allocation, unlocking more code simplifications.
- Jason and Caroline landed changes to make ImmutableScriptData a part of the Stencil interface instead of its field being duplicated in ScriptStencil.
- Kannan is making progress removing the frontend dependency on JSAtoms.
🐒 SmooshMonkey
SmooshMonkey is a reimplementation of the front end, with the goal of making it easier to add new features to the engine, and improve the long term perspective of maintaining the codebase. \
- Nicolas Improved the generated parser speed by a factor of 2, and continues to make progress on further speed improvements to catch up with SpiderMonkey’s current hand-written parser. At the moment, we are only 47% behind SpiderMonkey.
- Arai implemented scope analysis, and started working on functions.
- Jason cleaned up parts of the python codebase and improved the safety of the rust code
- Yulia implemented Labels, Breaks, Continues and For/Do/While loops
- The team is 55% through the ES3 implementation, and 50% through the MVP implementation.
🚀 WarpBuilder
WarpBuilder is the JIT project to replace the frontend of our optimizing JIT (IonBuilder) and Type Inference with a new MIR builder based on compiling CacheIR to MIR. WarpBuilder will let us improve security, performance, memory usage and maintainability of the whole engine.
- Jan implemented support for most bytecode instructions (the slow paths) and added a tier 2 ‘warp’ job to Treeherder that runs jit-tests with WarpBuilder enabled.
- Jan added the CacheIR Transpiler for transpiling CacheIR to MIR and started using it for certain instructions.
- Tom implemented support for various GetProp, GetElem cases in the transpiler.
- Jan moved the list of all CacheIR instructions into a YAML file and used this to auto-generate reader/writer boilerplate and better debug printing code. This makes it easier and less error-prone to add new CacheIR instructions and to support new instructions in the transpiler.
💣 Exception handling improvements
- Tom removed the “extra warnings” mode. If the pref for this was enabled, the engine would report warnings in certain situations. Modern linters do a better job at many of these things.
- Tom then removed the “werror” (warnings-as-errors) mode.
- Tom fixed location information for non-error uncaught exceptions.
- Tom is now working on making it possible to inspect uncaught exceptions in the Web Console. Nicolas from the DevTools team is implementing the Console UI code for this.
📈 Miscellaneous performance improvements
- Jeff changed the UTF-8 parsing functions to never inflate to UTF-16.
- Ted removed metadata source notes from self-hosted code. This saved about 40 KB per process.
- Tom implemented CacheIR support for binary operations involving a number and string to speed up paper.io
- André moved the
Object.prototype.__proto__
getter to self-hosted code so it benefits from JIT inlining support for getPrototypeOf. - Christian fixed some slow logging code that affected all debug builds.
- André improved CacheIR support for
JSOp::Pow
(the**
-operator). - André added CacheIR support for
JSop::Pos
(the+
-operator) and optimized+string
(to convert strings to numbers). - Jan added CacheIR support for
JSOp::ToNumeric
to improve WarpBuilder code generation.
🧹 Miscellaneous code cleanups
- Arai converted the source notes code from old C macros to modern C++.
- Jeff landed a lot of patches to clean up object creation code.
- André removed a lot of dead code from various MIR instructions.
- Tom continued converting some ancient jsid functions to PropertyKey methods.
- Ted added a TrailingArray type and used it for various classes with variable-size trailing arrays.
- André converted code to use <type_traits> instead of our own mfbt/TypeTraits.h
- Jeff started using the C++17 if/switch statements with initializers.
- André and Jan simplified some code with C++17 fold expressions.
- Jon converted code using std type traits to the more concise *_v and *_t versions since C++17.
- Jon gave all Cells a CellHeader type for the first word to improve the safety of GC flags and to make the code easier to understand.
✏️ Miscellaneous
- Jason worked around a CPU bug that affected the bytecode emitter.
- Yoshi is making changes to the helper thread system to make it possible to eventually use Gecko’s shared thread pool for SpiderMonkey’s background tasks.
- Jeff is landing code changes for ReadableStream pipeTo/pipeThrough support.
- Jeff and Tom Tung are working on conditionally hiding the SharedArrayBuffer constructor.
- A last minute time zone data update made it just in time for Firefox 76. Big thanks to the release team for their prompt reaction!
- Matthew added in-tree documentation on how to build and test the SpiderMonkey shell with mach.
WebAssembly
- Andy from Igalia implemented support for calling multi-result WebAssembly functions from JavaScript as well as having JavaScript return multiple values to WebAssembly. With this work, the multi-value feature is complete! This feature will ride the train for Firefox 78. Thanks to Bloomberg for their support implementing this feature.
- Andy wrote an introductory article on the design of SpiderMonkey’s WebAssembly compiler tiers, as well as an article diving into the performance of the baseline compiler
- Andy also wrote a couple of articles on the implementation of the multi-value feature.
- Andy also extended support in the debugger to access multi-value and i64 results from return breakpoints.
- Lars implemented support for the WebAssembly SIMD proposal in the x64 baseline compiler.
- Ryan made a heroic patch set that culminated in the replacement of SpiderMonkey’s nonstandard wasmTextToBinary debugging function with the standards-conforming wat crate, written in Rust.
- Ryan also re-imported the upstream WebAssembly conformance tests as part of Firefox’s web-platform tests.
- Ryan also updated SpiderMonkey’s support for the experimental WebAssembly GC proposal in response to upstream changes.
🏗︎ Cranelift
Cranelift is a low-level code generator written in Rust. While available in Firefox Nightly as backend for WebAssembly with the right about:config
prefs, Cranelift is disabled by default, being still a work-in-progress. We’re continuing to refine performance and fill in some additional feature support before making this the default setting.
Experimental WebAssembly (MVP) support for the AArch64 (ARM64) instruction set has landed in Cranelift and in Firefox, and large WebAssembly programs can now run correctly using it!
The new backend also brings with it an updated machine-backend design for Cranelift, which we believe will make future work and contributions easier to develop. We’ve developed a new register allocator as part of this that is designed to be a reusable library (Rust crate) called regalloc.rs. Finally, the AArch64 support also benefits other users of Cranelift, such as Wasmtime.
This is the result of months of work carried out by Chris, Julian and Benjamin, with the help of Joey Gouly (of ARM).