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

🎁 New features

🗑️ 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. \

🚀 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

🏗︎ 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).