How to Turbocharge V8’s Mutable Heap Numbers for Faster Math.random

By ✦ min read

Introduction

At V8, we are always looking for ways to make JavaScript faster. One recent optimization gave us a 2.5x speedup in the async-fs benchmark from JetStream2. The trick was to replace immutable heap numbers with mutable ones, especially in the custom Math.random implementation used by the benchmark. While this change was sparked by a benchmark, the pattern appears in real JavaScript code and can yield big performance wins. In this guide, you’ll learn step by step how to identify and fix similar bottlenecks in V8’s handling of mutable heap numbers.

How to Turbocharge V8’s Mutable Heap Numbers for Faster Math.random
Source: v8.dev

What You Need

Step 1: Understand How V8 Stores Numbers in ScriptContext

Every JavaScript ScriptContext is an array of tagged values. On 64-bit systems each slot is 32 bits. The least significant bit (LSB) indicates the type:

Numbers that cannot fit as SMI (like large integers or floating-point numbers) are stored as HeapNumber objects on the heap. By default, these HeapNumbers are immutable. Once created, they cannot be changed; any assignment creates a new HeapNumber.

Step 2: Identify the Bottleneck in Math.random

In the async-fs benchmark, the custom Math.random is implemented as a closure that keeps a seed variable in the ScriptContext. The seed is updated on every call using a series of bitwise operations. Because the seed is a floating-point number (or a large integer), it cannot be stored as SMI. Consequently, each update allocates a new immutable HeapNumber, causing:

To confirm, profile the Math.random function using V8’s --trace-deopt or a sampling profiler. You’ll see many allocations and GC stalls.

Step 3: Design a Mutable Heap Number Object

The fix is to allow the HeapNumber to be mutable. Instead of allocating a new object every time, we modify the same object in place. This requires changes in V8’s runtime to support mutation of HeapNumbers. Key design points:

Step 4: Implement Mutable Heap Numbers in V8’s Runtime

Edit the V8 source code to add a new MutableHeapNumber class (or extend the existing one). Modify the object allocation code to create mutable versions when needed. For the ScriptContext slot, when storing a number that will be frequently updated, replace it with a mutable HeapNumber.

In the runtime (C++ code), add a function like SetMutableHeapNumberValue(isolate, object, new_value) that writes the new double into the object’s value field without allocation. Ensure the garbage collector does not move or compact these objects (they are still movable, but their value field is updated in place).

Tip: Look at V8’s existing MutableHeapNumber used for the NaN boxed representation – you can reuse similar logic.

Step 5: Update Math.random to Use a Mutable Heap Number

Make the JIT-compiled Math.random function (or the interpreter) aware of the mutable HeapNumber. When compiling the inline cache or the load/store operations, check if the heap number is mutable. If yes, generate code that directly updates its value inline (e.g., using STORE_DOUBLE_FIELD). This avoids the allocation path.

In the IC (Inline Cache) handler for property stores, add a fast path for mutable heap numbers. Similarly, the load path can read the double directly without an allocation check.

Step 6: Verify Performance Gains

  1. Build V8 with the changes.
  2. Run the async-fs benchmark in isolation: d8 test/benchmarks/JetStream2/async-fs.js
  3. Compare the total score and the number of GC events before and after.
  4. Check for no regressions in other benchmarks (e.g., other JetStream2 tests, Octane, SunSpider).
  5. Use --trace-opt to confirm the optimized Math.random is now using mutable heap numbers.

In our implementation, this change alone gave a 2.5x speedup in the async-fs benchmark and lifted the overall JetStream2 score.

Tips and Best Practices

Tags:

Recommended

Discover More

AI-Assisted Hacking Wave Hits Mexican Government as Cyber Threats Surge: Breaking ReportHow Russian GRU Hackers Hijacked Routers to Steal OAuth Tokens: A Technical Breakdown10 Key Facts About the US Space Force's Golden Dome Space-Based Missile Interceptors8 Critical Facts About the New xlabs_v1 Botnet Hijacking IoT Devices via ADBHarnessing Wave Energy Through Advanced Modeling: A Developer's Guide