SpiderMonkey Newsletter 10 (Firefox 88-89)

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 88 and 89 Nightly release cycles.

In this newsletter we bid a fond farewell to module owner emeritus Jason Orendorff, and say hello to Jan de Mooij as the new JavaScript Engine module owner.

If you like these newsletters, you may also enjoy Yulia’s Compiler Compiler live stream.

🏆 New contributors

We’d like to thank our new contributors. We are working with Outreachy for the May 2021 cohort, and so have been fortunate enough to have more than the usual number of new contributors.

👷🏽‍♀️ JS features

⚡ WebAssembly

  • We enabled support for large ArrayBuffers and 4 GB Wasm memories in Firefox 89.
  • We enabled support for SIMD on x86 and x64 in Firefox 89.
  • Igalia finished the implementation of the Exception Handling proposal in the Baseline Compiler.
  • We implemented support for arrays and rtt-based downcasting in our Wasm GC prototype.
  • We’ve enabled the Ion backend for ARM64 in Nightly builds.
  • We’ve landed many changes and optimizations for SIMD support.
  • We removed various prefs for features we’ve been shipping for some time.

❇️ Stencil

Stencil is our project to create an explicit interface between the frontend (parser, bytecode emitter) and the rest of the VM, decoupling those components. This lets us improve web-browsing performance, simplify a lot of code and improve bytecode caching.

  • We implemented a mechanism for function delazification information to be merged with the initial stencil before writing to caches.
  • We added support for modules and off-thread compilation to the Stencil API.
  • We optimized use of CompilationState in the parser for certain cases.
  • We added magic values to the Stencil bytecode serialization format to detect corrupt data and handle this more gracefully.
  • We fixed the Stencil bytecode serialization format to deduplicate bytecode.
  • We’re getting closer to sharing Stencil information for self-hosted code across content processes. We expect significant memory usage and performance improvements from this in the coming weeks.

🧹 Garbage Collection

  • We simplified and optimized the WeakMap code a bit.
  • We disabled nursery poisoning for Nightly release builds. The poisoning was pretty expensive and often caused slowdowns compared to release builds that didn’t have the poisoning.
  • We added support for decommitting free arenas on Apple’s M1 hardware. This required some changes due to the 16 KB page size.
  • We changed the pre-write barrier to use a buffering mechanism instead of marking directly.
  • GC markers now describe what they are, hopefully reducing confusion over whether the browser is paused throughout a major GC


  • We changed how arguments objects are optimized. Instead of doing an (expensive) analysis for all functions that use arguments, we now use Scalar Replacement in the Warp backend to optimize away arguments allocations. The new implementation is simpler, more self-contained, and lets us avoid doing the analysis for cold functions.
  • We fixed the Scalar Replacement code for arrays and objects to work with Warp.
  • We also added back support for branch pruning with Warp.
  • We added CacheIR support for optimizing GetElem, SetElem and in operations with null or undefined property keys. This turned out to be very common on certain websites.
  • We optimized DOM getters for window.foo (WindowProxy objects).
  • We improved function inlining in Warp for certain self-hosted functions (for example Array.prototype.map) that benefit from inlining.
  • We added a browser pref to control the function inlining size threshold, to help us investigate performance issues.

📐 ReShape

Now that Warp is on by default and we’ve removed the old backend and Type Inference mechanism, we’re able to optimize our object representation more. Modern websites spend a significant amount of time doing property lookups, and property information takes up a lot of space, so we expect improvements in this area to pay off.

  • We’ve merged ObjectGroup (used by the old Type Inference system) into Shape and BaseShape. This removed a word from every JS object and is also simpler.
  • We cleaned up and deduplicated our property lookup code.
  • We’ve replaced the old JSGetterOp and JSSetterOp getters/setters with a property attribute.
  • We changed our implementation of getter/setter properties: instead of storing the getter and setter objects in the shape tree, we now store them in object slots. This fixes some performance cliffs and unblocks future Shape changes.
  • We’ve started adding better abstractions for property information stored in shapes. This will make it easier to experiment with different representations in the coming weeks.

🛠 Testing

  • We made SpiderMonkey’s test suites on Android about four times faster by optimizing the test runner, copying fewer files to the device, and reducing the number of jit-test configurations.
  • We removed the Rust API crates because upstream Servo uses its own version instead of the one we maintained in-tree.
  • We landed support for the Fuzzilli JS engine fuzzer in the JS shell.

📚 Miscellaneous

  • We cleaned up the lexical environment class hierarchy.
  • We optimized Object.assign. Modern JS frameworks use this function a lot.
  • The bytecode emitter now emits optimized bytecode for name lookups in strict-mode eval.
  • We updated irregexp to the latest upstream version.
  • We optimized checks for strings representing an index by adding a flag for this to atoms.
  • Function delazification is now properly reported in the profiler.
  • The profiler reports more useful stacks for JS code because it’s now able to retrieve registers from the JIT trampoline to resume stack walking.
  • We added memory reporting for external ArrayBuffer memory and also reduced heap-unclassified memory by adding some new memory reporters.
  • We added documentation for the LifoAlloc allocator.
  • We fixed Clang static analysis and formatting issues in the Wasm code.
  • We’ve started cleaning up PropertyDescriptor by using Maybe<PropertyDescriptor>.