d8 & debugging tools
d8 is V8's standalone developer shell: a small binary that embeds V8 and lets you run JavaScript directly, with debugging hooks the public web never exposes. It is the single most useful tool for learning V8, because it lets you watch the machinery this site describes — tiering, deopts, IC states, GC — happen on real code.
::: info Ubiquitous language
d8: the "developer shell" (the "d" + V8). Natives syntax: special
%Function() intrinsics, enabled with --allow-natives-syntax, that poke V8
internals from JS. Trace flags: --trace-* flags that log internal events.
:::
What d8 is
enum class ModuleType { kJavaScript, kJSON, kWebAssembly, kText, kBytes, kInvalid };
class SourceGroup {
bool Execute(Isolate* isolate);
void StartExecuteInThread();
…
};
It runs d8 script.js to execute a file, drops into a REPL when run bare, loads
ES modules / JSON / WASM, and can even run scripts on multiple threads (separate
isolates) via SourceGroup. Build it with
gm.py x64.release d8.
Natives syntax: poke the internals from JS
Run d8 with --allow-natives-syntax and a set of %-prefixed intrinsics become
available. These are the fastest way to see V8's internal state on a value:
// d8 --allow-natives-syntax
function add(a, b) { return a + b; }
add(1, 2); add(3, 4); // warm it up
%OptimizeFunctionOnNextCall(add); // force optimization on next call
add(5, 6);
console.log(%GetOptimizationStatus(add)); // inspect tier / status bits
const o = { x: 1, y: 2 };
%DebugPrint(o); // dump the object's Map, layout, …
console.log(%HasFastProperties(o)); // fast vs dictionary mode
The intrinsics most relevant to this site:
%DebugPrint(x)— print an object's Map, elements kind, and layout. The fastest way to see hidden classes.%HasFastProperties(x)— fast (Map-described) vs dictionary mode.%OptimizeFunctionOnNextCall(f)/%GetOptimizationStatus(f)— drive and inspect tiering.%CollectGarbage(null)— force a GC.
::: warning Internal and unstable
Natives syntax is a debug feature. The set of %-functions, their names, and
their behavior change without notice, and they are unavailable in normal
(non---allow-natives-syntax) execution. Use them to learn, never in real code.
:::
Trace flags: watch the engine work
Pass these to d8 (or Node via --v8-options) to log internal events as your code
runs — this is how you turn the abstractions on this site into observations:
| Flag | Shows | Related page |
|---|---|---|
--trace-opt / --trace-deopt |
when functions optimize / why they deopt | Deopt, Feedback |
--trace-ic |
inline-cache state transitions per site | Inline caches |
--print-bytecode |
the Ignition bytecode emitted | Bytecode gen |
--print-opt-code |
the optimized machine code | TurboFan |
--trace-gc |
every GC, its kind, and pause time | GC overview |
--trace-maglev-graph |
Maglev's IR | Maglev |
--prof |
a sampling profile (post-process with tools/) |
— |
::: tip A learning loop
The tightest way to internalize V8: write a tiny snippet, run it under
d8 --allow-natives-syntax --trace-opt --trace-deopt --trace-ic, and watch a
function climb the tier ladder, see its ICs go monomorphic,
then deliberately break its type stability and watch it deoptimize. Every claim on
this site has an observable counterpart here.
:::
Other tools in the tree
mksnapshot— builds the startup snapshot (a build-time tool).torque— the Torque compiler.tools/— profiling post-processors (tick processor), thetools/system-analyzer, and more.Inspector protocol — d8 can speak the Chrome DevTools protocol for debugging.
See also
Build system — how to get a d8 binary.
Inline caches and Deopt — what
--trace-ic/--trace-deoptreveal.Official: v8.dev/docs/d8.