From Sea of Nodes to Turboshaft: V8's Evolution in Compiler Intermediate Representations

By

V8, Google's high-performance JavaScript engine, has long been known for its use of the Sea of Nodes (SoN) intermediate representation (IR) in its top-tier optimizing compiler, Turbofan. However, over the past three years, the V8 team has been systematically replacing SoN with a more traditional Control-Flow Graph (CFG) IR called Turboshaft. This shift marks a significant milestone in compiler design, driven by practical engineering challenges and the need for maintainability and performance. Today, the entire JavaScript backend of Turbofan runs on Turboshaft, and WebAssembly uses it throughout its pipeline. Only two legacy parts—the builtin pipeline and the frontend of the JavaScript pipeline—still rely on SoN, with replacements in progress. This article explores the reasons behind this transition and what it means for the future of V8.

The Origins of Turbofan and Sea of Nodes

Twelve years ago, in 2013, V8's sole optimizing compiler was Crankshaft, which used a control-flow graph IR. Crankshaft delivered impressive performance gains for its time but was limited in scope and plagued by technical debt. The team continued to enhance it, but several critical issues emerged:

From Sea of Nodes to Turboshaft: V8's Evolution in Compiler Intermediate Representations
Source: v8.dev
  • Excessive hand-written assembly – Each new IR operator required manual assembly translation for four architectures (x64, ia32, arm, arm64), slowing development.
  • asm.js optimization challenges – Asm.js, then seen as a key path to high-performance JavaScript, was difficult to optimize effectively.
  • Inability to introduce control flow during lowering – Control flow was fixed at graph building time. This prevented typical compiler transformations, like lowering high-level operations (e.g., JSAdd(x,y)) into conditional code (e.g., if (x is String and y is String) { StringAdd(x,y) } else { ... }).
  • Try-catch unsupported – Despite months of effort by multiple engineers, try-catch blocks could not be supported, a major limitation for modern JavaScript.
  • Performance cliffs and bailouts – Using certain features or hitting edge cases could cause 100x performance drops, making code performance unpredictable.
  • Deoptimization loops – Crankshaft would reoptimize a function with the same speculative assumptions after deoptimization, leading to endless cycles.

Facing these issues, the V8 team sought a new IR that could address the pain points while enabling more aggressive optimizations. This led to the adoption of the Sea of Nodes IR for Turbofan, which allowed a flexible representation where nodes were not tied to a fixed control flow.

Why Sea of Nodes Was Initially Chosen

Sea of Nodes offered several advantages over Crankshaft's CFG. It allowed operations to be reordered and combined freely, facilitated scheduling after optimization, and inherently supported speculative optimizations by separating the effects of operations from control flow. Turbofan, built on SoN, successfully addressed many of Crankshaft's limitations: it supported try-catch, reduced performance cliffs, and enabled dynamic lowering with control flow. For years, SoN was considered a key innovation that gave V8 a competitive edge.

The Hidden Costs of Sea of Nodes

Despite its strengths, SoN introduced its own set of challenges:

  • Complexity of scheduling – Reconstructing a linear order from SoN's graph proved algorithmically heavy and error-prone.
  • Memory overhead – The graph could become bloated with dependencies, consuming significant memory.
  • Debugging difficulty – The non-linear nature made it hard for developers to understand and fix optimization bugs.
  • Limited tooling – Traditional compiler analysis and debugging tools expected a CFG, requiring custom solutions.

The Shift to Turboshaft: A Pragmatic Return to CFG

Recognizing these drawbacks, the V8 team began developing Turboshaft, a new IR based on a classic control-flow graph. Turboshaft retains the critical optimization capabilities of SoN—such as speculative optimizations and flexible lowering—but does so in a more structured, linear representation. This shift offers multiple benefits:

  • Simpler scheduling – A CFG naturally provides a linear order, reducing scheduling overhead and complexity.
  • Lower memory usage – The IR is more compact, as control flow is explicit rather than implicit in the graph.
  • Easier debugging and tooling – CFG is a well-understood format, compatible with standard compiler tools.
  • Faster compilation – The linear structure allows for faster passes and better cache locality.

Replacing the JavaScript Backend

Over the past three years, the V8 team systematically migrated Turbofan's JavaScript backend from SoN to Turboshaft. This was a gradual process, ensuring no regression in performance or correctness. Today, all JavaScript optimization pipelines in Turbofan's backend use Turboshaft. The result is not only a more maintainable compiler but also one that compiles code more quickly without sacrificing the quality of generated code.

WebAssembly Adoption

WebAssembly (Wasm), another critical V8 frontend, now uses Turboshaft throughout its entire compilation pipeline. This uniformity simplifies the codebase and allows optimizations to benefit both JavaScript and Wasm workloads. The CFG-based approach works particularly well for Wasm's lower-level, statically-typed nature.

Ongoing Transition: Leaving the Sea of Nodes

Two parts of Turbofan still rely on SoN: the builtin pipeline (for internal runtime functions) and the frontend of the JavaScript pipeline. The builtin pipeline is being slowly replaced by Turboshaft as well. The JavaScript frontend is being replaced by Maglev, a new mid-tier compiler that also uses a CFG-based IR. Maglev bridges the gap between the fast baseline compiler and the optimizing Turboshaft, providing quicker optimization for frequently executed code without the overhead of SoN.

Conclusion: A Pragmatic Evolution

The move from Sea of Nodes to Turboshaft represents a pragmatic evolution in compiler design. While SoN was a groundbreaking innovation that enabled significant performance advances, its long-term maintenance costs and complexity eventually outweighed its benefits. By returning to a control-flow graph, V8 achieves a simpler, faster, and more maintainable compiler that still delivers top-tier optimization. This transition underscores an important lesson: even the most elegant ideas must be weighed against practical engineering realities. V8's path from Crankshaft to Turbofan to Turboshaft demonstrates a commitment to continuous improvement, ensuring that JavaScript and WebAssembly remain performant and reliable for developers worldwide.

Tags:

Related Articles

Recommended

Discover More

Century-Old Swedish Newspapers Reveal Dramatic Decline of Baltic Porpoises7 Critical Developments in Press Freedom and Palestinian Media Rights Since October 2023Browser-Based Vue Testing: A Step-by-Step Guide Without NodeFive Facts You Need to Know About the Franklin Expedition's Latest DNA IdentificationsMaximize Your Apple Card: Step-by-Step Guide to Getting $100 Bonus Daily Cash by Adding a Co-Owner