include/ & src/api
the embedder surface
The headers Chromium and Node.js compile against, and the C++ that implements them. Everything an embedder can do — create an isolate, enter a context, install a native callback, run a script — enters here. It is deliberately narrow: the rest of the tree is not public API.
v8::Isolate::New(params);
v8::Script::Compile(ctx, src);
src/parsing
scanner, parser, preparser
Turns characters into an AST, or into as little as it can get away with. The preparser exists here alongside the real parser precisely so most function bodies can be skipped on first sight and revisited only when called.
src/parsing/parser.cc
src/parsing/preparser.cc
The bytecode generator, the instruction set, and the handlers. bytecodes.h is the list of everything V8 can be asked to do, and it is short enough to read in one sitting — a good map of the language from the engine’s side.
src/interpreter/bytecodes.h
A few thousand lines, most of it a switch over bytecodes emitting the equivalent machine code. The smallest compiler in the tree, and the clearest one to read first — there is no IR in the way between input and output.
src/baseline/baseline-compiler.cc
src/maglev
the mid-tier JIT
Builds an SSA graph straight from the bytecode, specialises it against the feedback vector, allocates registers, emits code. Newer than the rest, and written knowing what TurboFan cost — the whole design brief was most of the benefit for a fraction of the compile time.
src/maglev/maglev-graph-builder.cc
The largest directory in the engine: graph construction, typing, the reducer passes, escape analysis, scheduling, instruction selection per architecture. Everything speculative about V8 is decided here, and every guard it inserts is a place execution can fall back to the interpreter.
src/compiler/pipeline.cc
src/compiler/js-typed-lowering.cc
src/objects
the heap object model
Every shape a value can take on the heap: Map, JSObject, String and its dozen representations, FixedArray, FeedbackVector. The .tq files here declare field layouts once, and the generated accessors keep C++ and compiled code agreeing about where a field lives.
src/objects/map.h
src/objects/js-objects.tq
Spaces, the scavenger, mark-compact, incremental and concurrent marking, and the write barriers that hold it all together. cppgc lives here too — the C++ garbage collector that started as Blink’s Oilpan and now collects DOM objects with the same machinery.
src/heap/mark-compact.cc
src/heap/cppgc/
src/builtins
the standard library
Array.prototype.map, Object.assign, the string methods — implemented not in C++ or JavaScript but in Torque, a typed DSL that compiles to the same code generator the compilers use. Written once, compiled ahead of time, and baked into the binary.
src/builtins/array-map.tq
The per-architecture assemblers and macro-assemblers everything above eventually calls, plus CodeStubAssembler — a portable, structured way to emit machine code without writing an architecture back end four times. Torque compiles down to it.
src/codegen/x64/macro-assembler-x64.cc
src/codegen/code-stub-assembler.h
src/execution
Isolate & frames
isolate.h is the god object: the heap, the stack, the pending exception, the microtask queue, the compilation cache. Stack frame walking lives here too, which is what makes a JavaScript stack trace possible across three tiers of compiled code.
src/execution/isolate.h
src/execution/frames.cc
Regular expressions get their own compiler. A pattern is parsed, turned into an automaton, and either interpreted or compiled to machine code through the same assemblers — which is why a hot regex can run at native speed, and why a pathological one can hang the thread.
src/regexp/regexp-compiler.cc
src/wasm
the second front end
Module decoding and validation, the Liftoff baseline compiler, and the bridge into TurboFan for tier-up. It reuses the heap, the isolate and the code manager — WebAssembly is a different input language into the same engine, not a second engine.
src/wasm/baseline/liftoff-compiler.cc
Bootstrapping a fresh JavaScript environment means building thousands of objects. V8 does that once at build time, serialises the heap, and deserialises it on startup — so creating a context is closer to a memcpy than to running setup code. Embedders can snapshot their own state on top.
mksnapshot → embedded blob in the binary