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
đ JIT
- 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>
.