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 78 and 79 Nightly release cycles.
If you like these newsletters, you may also enjoy Yulia’s weekly Compiler Compiler live stream, a guided tour of what it is like to work on SpiderMonkey and improve spec compliance.
JavaScript
🎁 New features
Firefox 78
- Iain’s regular expression engine work (see below) resulted in support for:
- André enabled Intl.ListFormat by default.
- André enabled the Unified NumberFormat API by default.
Firefox 79
- Jon enabled WeakRef and FinalizationRegistry by default.
- André enabled the new logical assignment operators (
&&=
,||=
,??=
) by default. - Jason enabled Promise.any and AggregateError by default.
- André implemented the dateStyle and timeStyle options on Intl.DateTimeFormat.
👷🏽♀️ Feature work
- Matthew has started implementing private class fields.
- Adam is implementing the Iterator Helpers proposal.
- Yulia started implementing the Top-level Await proposal.
- Jeff landed more changes for ReadableStream pipeTo/pipeThrough support.
- Tom defined Symbol.toStringTag properties on DOM prototype objects and then removed the (non-standard) code for Object.prototype.toString where it used the internal JSClass name.
- André changed Atomics methods to work on non-shared ArrayBuffers.
- André implemented the Intl.DisplayNames proposal (disabled by default).
⏩ Regular Expression engine update
- Iain fixed the last blockers and enabled the new engine by default.
- Iain then implemented support for named capture groups and added a fuzzing target for differential testing of interpreted vs compiled code with libfuzzer.
-
Finally, Iain removed the old engine in Firefox 79 and tidied up the code.
See the Mozilla Hacks blog post for more details.
🗑️ Garbage Collection
- Steve enabled incremental WeakMap marking, a big change to help reduce GC pauses.
- Steve landed changes to de-duplicate strings during nursery GC, based on work done by GC intern Krystal Yang and then rebased by Thinker Li.
- Jon added a header to nursery-allocated cells and used this to simplify code.
- Steve created a GC micro-benchmark suite that can be used to compare GC performance on various workloads in different engines / browsers.
- Jon fixed various issues with GC telemetry data.
- Jon optimized incremental sweeping by no longer collecting the nursery for every slice.
- Steve optimized string allocation by allocating a tenured string directly for certain call sites.
- Yoshi fixed sending telemetry data of promotion rate when nursery was empty.
❇️ 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 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).
- Caroline merged LazyScriptCreationData into FunctionCreationData.
- Ted moved the script atoms from RuntimeScriptData to PrivateScriptData. This allowed merging various classes into ScriptStencil.
- Ted added snapshotting for incoming scope data to better isolate the parser from the VM.
- Ted deferred allocation of functions and scripts to the end of bytecode generation, moving us closer to not doing GC-allocations in the frontend.
- Kannan factored non-GC state out of scope data and changed BindingIter to work with both GC atoms (JSAtom) and the future ParserAtom type.
- Kannan landed the ParserAtom and ParserAtomsTable types. The next part is converting the frontend to use ParserAtom instead of JSAtom, another big step towards GC-free parsing.
🐒 SmooshMonkey
SmooshMonkey is our project to reimplement the frontend in a safe language (Rust) and make it easier to implement new features and improve long-term maintainability of the code base.
- Arai is implementing function compilation, while updating the Stencil interface for function.
- Arai landed a tool and automation to improve the development workflow.
- Arai bumped the supported Unicode version to 13.
- Yulia is working on separating the error checking phase from the AST building phase. This will allow running the error checking phase without building an AST for validating JavaScript files when they are received, and also building an AST without doing the validation which would speed-up the first execution of scripts, which are compiled on-demand.
- Nicolas is rebasing the performance work implemented in a fork, in order to bring it to the main development tree of SmooshMonkey.
🚀 WarpBuilder
WarpBuilder is the JIT project to replace the frontend of our optimizing JIT (IonBuilder) and the engine’s Type Inference mechanism 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.
Since the last newsletter we’ve implemented a lot more CacheIR instructions in the transpiler (the part of WarpBuilder responsible for translating CacheIR to MIR). Although we’re still missing a lot of pieces, we’re starting to get very encouraging performance numbers.
- Tom, Caroline, and Jan added CacheIR and Warp support for many builtin functions (for example Math.floor and Array.isArray) and self-hosting intrinsics. These functions are now also properly optimized in the Baseline Interpreter and JIT.
- Tom added support for property sets, double arithmetic, TypedArray elements, and many other things to the transpiler.
- Jan added support for element sets, string concatenation and other things to the transpiler.
- Caroline added a CacheIR health report mechanism. In the future this will make it easier to analyze performance of JIT code.
- Jan improved MIR optimizations for slot/element loads followed by an unbox.
- Christian started fuzzing WarpBuilder.
📈 Miscellaneous optimizations
- André added JIT optimizations for BigInt64Array and BigUint64Array.
- Denis replaced the ELEMENT_SLOT in ScriptSourceObject with a callback function.
- Ted optimized Object.prototype.toString when called with a primitive value to not create a temporary object. This is pretty common on the web.
- André added JIT optimizations for DataView methods.
- Iain added a fast path to our JIT stubs for simple atom regular expressions.
- Jan optimized post-barriers in JIT code.
- Tom ported String.prototype.concat to self-hosted code so it can take advantage of JIT optimizations.
- André added various optimizations for Math.pow and the **-operator.
- Tom added MIR optimizations based on the type of certain objects.
- Jan optimized the generated JIT code for unboxing Values.
🧹 Miscellaneous changes
- Logan enabled async-stacks when devtools are open.
- Jon removed the GCTrace framework (it wasn’t used and didn’t even compile).
- Jason added support for using generators in self-hosted code, for implementing the Iterator Helpers proposal.
- Chris added documentation for cross-compiling SpiderMonkey for ARM64
- Jon added a NestedIterator template and used it to clean up some iterator classes.
- André added a helper method for more robust MIR type checks, using an allow list instead of deny list
- Jan simplified new.target handling for eval frames.
- Yoshi landed minor refactoring on SourceCompressionTask.
WebAssembly
🎁 New features
- Asumu (from Igalia) enabled support for JS BigInt <-> Int64 conversion in Firefox 78.
- Andy (from Igalia) enabled support for calling multi-result WebAssembly functions from JavaScript as well as having JavaScript return multiple values to WebAssembly.
- Ryan enabled support for Reference types in Firefox 79.
- Ryan enabled support for Bulk-memory operations in Firefox 79.
- Tom (from the DOM team) re-enabled shared memory in JS (for desktop systems) in Firefox 79, and in turn this enables wasm thread operations in that same release.
🧹 Other changes
- Lars added SIMD support on x64 to the Baseline and Ion compilers (behind a flag)
- Lars optimized various SIMD operations in the Ion backend.
- Ryan fixed subclassing of certain WebAssembly objects.
- Dmitry (from Igalia) started landing some changes to improve the call ABI.
- Ryan optimized freezing of the exports object to fix a performance issue.
- Benjamin, Julian, and Chris made Cranelift work on ARM64, thus providing us (soon!) with an optimizing wasm compiler for the platform.
- Chris added support for multi-values to Cranelift on ARM64.