completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Meet the engines

Explore V8, SpiderMonkey, JavaScriptCore, smaller engines, shared pipelines, hosts, embedders, and tools for engine work.

By the end, you can
  • 01
    Name the enginesSay where V8, SpiderMonkey, JavaScriptCore, Hermes, QuickJS, and other small engines run.
  • 02
    Follow the stepsFollow source text through tokens, a tree, bytecode, the interpreter, feedback, fast code, deopt, and garbage collection.
  • 03
    Tell engine and host apartDecide whether a feature comes from the language (ECMA-262), the host, or the embedder that sets up the engine.

What a JavaScript engine does

You met engines and hosts in Engines, runtimes & hosts. Then you met Node, Deno, Bun, and edge runtimes in Runtimes. This lesson starts a new stage, called Inside the engine. The stage looks at what happens inside the engine itself. This first lesson gives you the big picture. Later lessons look at each part up close.

Plain definition

A JavaScript engine is the program that runs JavaScript. It follows the rules in ECMA-262, the official JavaScript standard. Its main jobs are:

  • Read your source text and split it into tokens: small pieces such as numbers, names, and +.
  • Check the grammar and build a tree that shows how the code fits together.
  • Turn that tree into simple instructions, and run them.
  • Make code that runs often faster, and undo that safely when a guess turns out wrong.
  • Free memory that nothing uses any more. This job is called garbage collection.

The host is the program around the engine, such as a browser or Node. The host decides what else your code can reach, such as the page, files, or timers.

Real-life analogyEngine and vehicle

Knowing the engine helps you read speed reports and strange error messages. But the car around the engine still matters. An error about the page usually comes from the browser. A note that fast code was thrown away comes from the engine. A failed build may come from neither.

In real life: The engine makes the car move
In JavaScript: The JavaScript engine turns your code into actions
In real life: The car body adds seats, lights, and doors
In JavaScript: The host adds the page, timers, files, and modules
In real life: A mechanic can study the engine without studying the road
In JavaScript: You can study parsing, bytecode, and memory without learning every browser feature
In real life: One engine model can go into different cars
In JavaScript: V8 is inside Chrome, Edge, Node.js, and Deno, and each one adds different extras

The last lesson was Finding memory leaks. There you used tools that look at a program from the outside. This lesson names the parts on the inside. The next lesson, Scanning source text, covers the very first step: turning characters into tokens.

V8, SpiderMonkey & JavaScriptCore

BIG THREE

Most web developers meet three big engines:

  • V8 is built by Google's V8 project. It runs in Chrome, Edge, Node.js, and Deno.
  • SpiderMonkey is built by Mozilla. It runs in Firefox.
  • JavaScriptCore is the engine of WebKit, the browser engine behind Safari. Bun uses it too.

Each engine runs code in tiers. A tier is one way of running code. A low tier starts quickly but runs slowly. A high tier takes longer to prepare but runs fast. The tier names in the table below were checked against each engine's own docs in September 2026. Engine teams rename and replace tiers often, so use the names as a rough map.

Every engine must print the same totalPop out in the code editor (opens in a new tab)JavaScript
const prices = [4, 6];const total = prices.reduce((sum, price) => sum + price, 0);console.log(total);

Line 1 makes an array of two prices, 4 and 6. Line 2 adds them up with reduce. The reduce method walks through the array and keeps a running total, starting at 0. Line 3 prints 10. Every engine must give this same result. Inside, each engine may use different instructions to get there. That is allowed, as long as the result your code sees is the same.

The code prices.reduce at the top. Arrows go to three engines: V8, SpiderMonkey, and JavaScriptCore. Each engine prints 10.prices.reduce(...)V810SpiderMonkey10JavaScriptCore10
Three different engines run the same code. Inside, each one works in its own way. All three must print 10.

Read each row from left to right: the engine, who builds it, where you meet it, and how it runs code.

The main engines, where they run, and their tier names.
EngineWho builds itWhere you meet itHow it runs code (tiers, first to fastest)Good to know
V8Google, as the open-source V8 project.Chrome, Edge, and other Chromium browsers, Node.js, and Deno.Ignition, Sparkplug, Maglev, TurboFan.The tier names change often, so check the V8 docs for the latest ones.
SpiderMonkeyMozilla.Firefox.Baseline Interpreter, Baseline Compiler, WarpMonkey.WarpMonkey is the fastest tier. It builds its machine code with parts from an older tier called Ion.
JavaScriptCoreApple, as part of WebKit.Safari, apps that show web pages with WebKit, and Bun.LLInt, Baseline JIT, DFG JIT, FTL JIT.WebKit's own posts use these four tier names.
HermesMeta, for React Native.React Native phone apps.Bytecode made before the app ships, run by an interpreter that starts quickly.When you build a React Native app for release, it turns your JavaScript into Hermes bytecode ahead of time.
QuickJS / QuickJS-ngFabrice Bellard and Charlie Gordon. QuickJS-ng is a copy kept up by the community.Programs that build in a small engine, command-line tools, tests, and small devices.One small interpreter that runs bytecode, with memory freed by reference counting.Great to build into other programs. It is not meant to replace a browser engine.

You don't need to remember the tiers. Keep this pattern instead. An engine first runs code in a tier that starts quickly. While the code runs, the engine takes notes about the values it sees. When some code runs many times, the engine spends extra time to make it faster. Later lessons explain each tier. They also explain why fast code must be able to fall back to a slower tier.

Hermes, QuickJS & embedded engines

The big three are not the only engines. Smaller engines make different choices. Some start up faster. Some use very little memory. Some fit inside a Java program. Some exist to test the language rules. They are useful when JavaScript runs inside something else: a phone app, a small device, a test tool, or a program written in another language.

Each row names an engine, where it usually runs, and what it is good at.

Smaller engines and what each one is for.
EngineWhere it usually runsWhat it is good at
HermesReact Native phone apps, where it is the default engine.Quick start-up and low memory. Release builds turn JavaScript into Hermes bytecode ahead of time.
QuickJS / QuickJS-ngOther programs, as a tiny engine written in C.A small interpreter that starts fast and supports most of the language. It frees memory by reference counting, plus a pass that clears loops of objects that point to each other.
BoaProjects written in Rust.A young engine built in Rust. Its team uses Test262 to check that it follows the language rules.
LibJSThe SerenityOS system and the Ladybird browser.A JavaScript engine for a browser, first built as part of SerenityOS.
JerryScriptSmall internet-connected devices.Runs on tiny chips (microcontrollers) that have only tens of kilobytes of memory.
Moddable XSApps for microcontrollers.Runs modern JavaScript for the Moddable tool kit, with very little memory and storage.
GraalJSJava programs, through GraalVM.Follows the language rules and works closely with Java code. It can also run on its own.
JSON works without a web pagePop out in the code editor (opens in a new tab)JavaScript
const status = { ready: true };console.log(JSON.stringify(status));

Line 1 makes a plain object. Line 2 uses JSON.stringify, which turns the object into text, and prints {"ready":true}. JSON is part of the language. So every engine provides it, even with no web page around. The same goes for objects, arrays, and promises. Picking a different engine changes speed, memory use, and tools. It must not change the language rules.

Small engines are real engines

An embedded engine is one that is built into another program or device. Many embedded engines have no web page, and many skip the fastest tiers. They still follow the language rules carefully. They also care about quick start-up, steady memory use, and safe links to the program around them. An engine for a tiny chip and an engine for a browser solve different real problems.

The steps every engine shares

STEP THROUGH

Engines differ inside, but they follow similar steps. Together the steps form a pipeline: the output of one step is the input of the next.

  1. The scanner reads the source text and splits it into tokens.
  2. The parser checks the grammar and builds a tree called an AST (abstract syntax tree). It may skip the inside of a function until that function is needed. This is called lazy parsing.
  3. The engine turns the tree into bytecode: simple instructions made for the engine, not for the computer's chip.
  4. An interpreter runs the bytecode, one instruction at a time.
  5. While the code runs, the engine keeps feedback: notes about the types and objects it sees.
  6. A JIT compiler ("just in time") turns code that runs often into fast machine code. It uses the feedback to guess what the code will see next.
  7. If a guess turns out wrong, the engine drops the fast code and goes back to a slower tier. This is called deoptimization, or "deopt" for short.

Beside all these steps, the garbage collector frees memory that your program can no longer reach.

A function that is never calledPop out in the code editor (opens in a new tab)JavaScript
function formatReceipt(total) {  return "Total: " + total;}console.log("shop ready");

Line 1 declares formatReceipt, but nothing calls it. Line 4 prints shop ready, and that is the only output. A function that never runs is called cold. The engine must still check the whole file for grammar mistakes. But it may wait to fully parse or compile a cold function until something calls it. Each engine picks its own way to do this, and your code can't tell the difference.

A syntax error stops the script before the first logPop out in the code editor (opens in a new tab)JavaScript
console.log("before");const price = ;console.log("after");

Line 2 has nothing after =. That breaks the grammar, so the parser throws a SyntaxError before any line runs. So neither before nor after is printed. A runtime error is different. It happens while the code runs, so the lines before it have already run.

The walkthrough below runs these steps on a small sum, 2 + 3 * 4.

Five cards in a row, joined by arrows: the source text 2 + 3 * 4, then 5 tokens, then an AST with plus at the top, then 5 bytecode steps, then the result 14.text2 + 3 * 4tokens5 tokensAST+ at the topbytecode5 steps14result
The walkthrough below follows these steps for 2 + 3 * 4. Each step turns the last one into a new form, until the result 14 comes out.
Step through the pipeline: source text to toy bytecode
Step 0 of 6Ready
Your turn: follow the blue line

Step through a tiny version of the engine's steps: source text, tokens, tree, bytecode, and the result.

Running in
  1. script
Next: line 1
const tokens = ["num:2","+/-:+","num:3","*:*","num:4"];const astRoot = "BinaryExpression";const bytecode = ["PUSH 2","PUSH 3","PUSH 4","MUL","ADD"];const result = 14;console.log(result);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Line 2 holds the tokens from the scanner. Line 3 holds the type of the node at the top of the tree, from the parser. Line 4 holds teaching bytecode. It is made up for this lesson. It is not the bytecode of V8 (called Ignition), SpiderMonkey, or JavaScriptCore. It is tiny on purpose, so you can see the idea before later lessons show real engine bytecode.

See real tokens, a real tree, and toy bytecode

LIVE

This playground runs in your browser. It uses Acorn, a JavaScript parser written in JavaScript. Acorn gives the real tokens and a real tree. The tree follows ESTree, a shared format for JavaScript trees that many tools use. Then a small compiler from this lesson turns the tree into bytecode. It only accepts arithmetic, such as 2 + 3 * 4. That bytecode is a teaching model you can step through. It is not copied from any real engine.

Live playground: Acorn tokens, a real tree, toy bytecode
The values the walkthrough usesPop out in the code editor (opens in a new tab)JavaScript
const sourceText = "2 + 3 * 4";const tokens = ["num:2","+/-:+","num:3","*:*","num:4"];const astRoot = "BinaryExpression";const bytecode = ["PUSH 2","PUSH 3","PUSH 4","MUL","ADD"];const result = 14;console.log(result);
What each step maderesult 14

Tokens

  1. num 2 0-1
  2. +/- + 2-3
  3. num 3 4-5
  4. * * 6-7
  5. num 4 8-9

Part of the tree (ESTree format)

{
  "type": "BinaryExpression",
  "start": 0,
  "end": 9,
  "operator": "+",
  "left": {
    "type": "Literal",
    "start": 0,
    "end": 1,
    "value": 2,
    "raw": "2"
  },
  "right": {
    "type": "BinaryExpression",
    "start": 4,
    "end": 9,
    "operator": "*",
    "left": {
      "type": "Literal",
      "start": 4,
      "end": 5,
      "value": 3,
      "raw": "3"
    },
    "right": {
      "type": "Literal",
      "start": 8,
      "end": 9,
      "value": 4,
      "raw": "4"
    }
  }
}

Toy bytecode and the stack after each step

  1. PUSH 2 stack [2]
  2. PUSH 3 stack [2, 3]
  3. PUSH 4 stack [2, 3, 4]
  4. MUL stack [2, 12]
  5. ADD stack [14]
Try it yourself

Acorn made 5 tokens. The top node of the tree is BinaryExpression. The teaching bytecode gives 14.

Acorn makes the tokens and the tree in your browser. The bytecode and the interpreter are a tiny teaching model, not the bytecode of V8, SpiderMonkey, or JavaScriptCore.

Try (7 - 1) / 3 and 5 * (2 + 6), and watch the tree change shape. Brackets and the order of operations (* before +) decide the shape of the tree before any bytecode is made. That is why the scanner and parser lessons come before the bytecode and JIT lessons in this stage.

Making code fast, and freeing memory

OPTIMIZE

An interpreter starts running code quickly, but it runs slowly. A JIT compiler needs time to build machine code, but that code runs fast. So engines only use the JIT for hot code: code that runs many times.

The JIT makes a guess from the feedback. For example: "this function has only seen numbers, so it will keep getting numbers." The fast code checks the guess each time it runs. This check is called a guard. If a later call breaks the guess, the guard fails. The engine then deoptimizes: it drops the fast code and goes back to a slower tier that handles every case correctly.

Two objects with the same shapePop out in the code editor (opens in a new tab)JavaScript
function userLabel(user) {  return user.name + ": " + user.score;}console.log(userLabel({ name: "Asha", score: 3 }));console.log(userLabel({ name: "Mina", score: 4 }));

Lines 4 and 5 call userLabel with two objects. Both objects have the same keys, name and score, made in the same order. An object's shape is its list of keys in that order. Line 4 prints Asha: 3, and line 5 prints Mina: 4. Seeing the same shape again and again gives the engine useful feedback, so it may make this function faster. That is not a promise. Don't make your data harder to read just to keep shapes the same.

The walkthrough below is a small model of feedback and deopt. A warm-up call teaches the engine to expect numbers. Then a later call either sends numbers again or sends a string.

After the warm-up call add(1, 2), the engine expects numbers. Top row: add(3, 4) passes the numbers check, runs in fast code, and gives 7. Bottom row: add with the string 3 fails the check, goes to a lower tier, and gives the string 34.after add(1, 2), the engine expects numbersadd(3, 4)numbers?yesfast code7add("3", 4)numbers?nolower tier"34"
The warm-up call add(1, 2) teaches the engine to expect numbers. A later call with numbers stays in the fast code. A call with a string fails the check and goes back to a lower tier.
Step through feedback and deopt (a teaching model)
Step 0 of 9Ready
Your turn: follow the blue line

Step through how feedback lets an engine build fast code from a guess, and why a later change of type can make it deopt.

Running in
  1. script
Next: line 1
  return a + b;} const feedback = [];feedback.push(typeof 1 + "+" + typeof 2);const first = add(1, 2);const optimizedFor = feedback[0];const later = add("3", 4);const outcome = typeof later === "number"  ? "stay in optimized code"  : "deopt to a lower tier";console.log(first);console.log(outcome);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
What the later call gets

Changing this choice starts the steps again. Real engines keep many more feedback notes than this model.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Garbage collection is not a last step after the code finishes. It runs beside the pipeline the whole time. Many things use memory: your values, objects, functions, and closures (functions that remember the variables around them). The engine's own bytecode, feedback, and fast code use memory too, and so do objects from the host. That is why memory lessons and engine lessons meet again when you read heap snapshots or look for leaks.

Performance rule

Learn these steps so you can find problems and measure better. Don't use them to rewrite small bits of code by guessing. Engines change often. A small rewrite can help one tier, hurt another, or make no difference next to the network, drawing the page, or a slow algorithm.

Engine vs host vs embedder

BOUNDARIES

Three parts work together when JavaScript runs:

  • The language. ECMA-262 defines the grammar, the values, the objects, how code runs, and built-in tools such as Promise and Array.prototype.map. Engines build all of this.
  • The host. It connects JavaScript to the outside world. In a browser, the HTML standard defines the event loop, timers, the page (called the DOM), and how modules load. Node defines process, file modules, how packages are found, and its own rules.
  • The embedder. This is the program that starts the engine, usually written in C++, Rust, or Java. It calls the engine's own functions to make an isolate (one copy of the engine with its own memory) and a context (one global world for code to run in). It also picks which outside objects JavaScript can use.

In a browser or in Node, one program is both the host and the embedder. The two words name two jobs: adding the extras, and setting up the engine.

Three columns. Language: Promise and JSON, in every engine. Host: document and process, added by the host. Embedder: isolate and context, which set up the engine.languagePromiseJSONin every enginehostdocumentprocessadded by the hostembedderisolatecontextsets up the engine
Every name comes from one of three places. The language gives Promise to every engine. A host adds names such as document. The embedder sets up the engine before your code runs.

Each row lists some names, who provides them, and how to think about them.

Where common names come from.
NamesWho provides themWhat this means
let, functions, objects, Array.prototype.map, Promise, JSON, globalThisThe language, ECMA-262.Every engine builds these, so they work everywhere.
The page (DOM), window, document, drawing the page, clicks and key presses, much of how modules loadBrowser standards such as HTML and DOM.The browser puts an engine inside and adds tools for the page.
Timers, the event loop, fetch, streams, modules, workersHost standards and each runtime's own choices.Browsers and server runtimes often have the same names, but different rules and limits.
process, node:fs, node:path, how packages are foundThe Node.js host.These are not part of the JavaScript language.
Isolates, contexts, links to C++ code, saved start-up states (snapshots), command-line flagsThe embedder, through the engine's own functions.The program that starts the engine decides how to set it up and which outside objects to hand in.
Who provides it?
  • Promise
  • Array.prototype.map
  • document.querySelector
  • requestAnimationFrame
  • node:fs/promises
  • process.versions.v8
  • make a V8 isolate
  • hand a C++ object to JS
Try it yourself
0 of 8 correct

Sort each card by who provides it. Then read the explanation on each card. Some cards are close calls on purpose.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

The short check below uses only names from the language. So it runs both in the browser editor and in Node. It uses nothing from the page and nothing that only Node has.

Check three built-in namesPop out in the code editor (opens in a new tab)JavaScript
console.log(typeof Array.prototype.map);console.log(typeof globalThis);console.log(typeof Promise);

typeof gives the kind of a value, as text. Each line asks for the kind of one built-in name: Array.prototype.map, globalThis (the global object), and Promise.

Check for the page before using itPop out in the code editor (opens in a new tab)JavaScript
const hasPageApis = typeof document !== "undefined";console.log(hasPageApis ? "page APIs available" : "no page APIs");

Line 1 uses typeof to check whether this host has a document. A plain read of a missing name throws an error, but typeof does not. In the lesson editor, line 2 prints page APIs available. In plain Node, it prints no page APIs. Checking for the feature itself is safer than checking the engine's name. V8 runs in both Chrome and Node, so the engine name can't tell you if there is a page.

Embedder code looks different, because it is not normal page code. It is the program around the engine. It makes a copy of the engine and a context, adds outside objects, and only then runs the user's code.

Embedder sketch, not browser JavaScriptJavaScript
// Pseudocode: embedders call engine APIs from C++/Rust/Java.const isolate = createIsolate();const context = isolate.createContext({ console });context.evaluate("console.log(1 + 2)");

Line 1 is a comment: real embedder code is written in C++, Rust, or Java. Line 2 makes an isolate. Line 3 makes a context and hands it console. Line 4 runs one line of JavaScript inside that context.

Exploring engines with d8, jsvu & eshost

TOOLS

Engine tools are useful, but each one depends on the version you have installed. Here is what each tool does:

  • d8 is V8's own shell: a small program that runs JavaScript on V8, with no browser around it.
  • jsvu downloads recent engine shells, so you don't have to build them yourself.
  • eshost-cli runs the same code in several engines, so you can compare the results.
  • node --v8-options lists the V8 settings, called flags, that your Node build lets you turn on.
  • Test262 is the official test suite for the language. Engine teams run it to check that they follow ECMA-262.
Ask Node for its version and its V8 versionBash
$ node --version$ node -p "process.versions.v8"$ node --v8-options | grep -- --print-bytecode

Line 1 prints the Node version. Line 2 prints the version of V8 inside this Node. Line 3 lists all V8 flags, and grep keeps only the line for --print-bytecode. That flag makes V8 print the bytecode it builds.

To find the V8 version in Chrome, open chrome://version in Chrome and read the JavaScript line. Chrome, Node, Deno, and a d8 shell can each have a different V8 version, so don't assume they match.

Example commands for engine tools, for your terminalBash
# V8's developer shell after building V8 or installing a binary with jsvuv8 --print-bytecode demo.js # Install current engine shells without compiling them yourselfnpx jsvu --engines=v8,spidermonkey,javascriptcore,quickjs,hermes,xs # Register shells and compare behavior across enginesnpx eshost-cli --configure-jsvueshost -e 'print(1 + 2)' # Run the official ECMAScript conformance suite when building an enginenpm test -- path/to/test262

You can't run these commands on this page. The editor here is not a terminal, and most engine shells are not installed. The lesson's tests do run the Node commands above. They check that Node 22 has V8 12.4 inside and offers --print-bytecode. The last part of a version number changes from one install to the next, so use the values your own computer prints.

Where engine knowledge helps

You rarely need to write code for one tier. But knowing the steps tells you where to look when something is slow or broken. Start with the simplest win: a good way to store your data.

Pick a good data structure firstPop out in the code editor (opens in a new tab)JavaScript
const pricesByItem = new Map([["tea", 3], ["cake", 5]]);console.log(pricesByItem.get("tea"));

Line 1 makes a Map: a list of keys, each with a value. Here each key is an item name and each value is a price. Line 2 asks for the price of tea directly and prints 3. As the list of items grows, a good data structure like this usually helps more than changing small bits of code to please one JIT. Measure the real program, including loading, parsing, network, drawing the page, and memory use.

Here is where engine knowledge helps in real work:

  • A page starts slowly. Ask how much code must be downloaded, scanned, parsed, compiled, and run before the user can click.
  • A profile shows one slow function. Measure first. Then look for a better algorithm, or for fewer new objects.
  • A heap snapshot shows objects that should be gone. Follow the links from closures and host objects back to the roots. The roots are the starting points the garbage collector always keeps, such as global variables.
  • Code moves between the browser, Node, Deno, Bun, or a small device. Separate the language rules from the host's extras.

Keep Runtime overview, Manuals & specs, and The event loop close. They explain the host side, which the engine does not own.

Common misconceptions

  • “V8 is the JavaScript standard.” V8 is one engine that follows the standard. The standard is ECMA-262.
  • “A JIT always makes code faster.” Building fast code takes time and memory. Code that runs only a few times may never leave the first tiers.
  • “Bytecode is the same in every engine.” Each engine has its own bytecode and its own tiers. This lesson's bytecode is only a teaching model.
  • “The engine owns timers and the page.” The host adds timers, page drawing, files, network, and most global objects around the engine.
  • “Garbage collection fixes leaks by itself.” The garbage collector only frees objects that nothing can reach. If your code or a host object still points to some data, that data stays.
  • “Engine flags are safe to use in real apps.” Flags are tools for studying engines. They can change, disappear, or act differently in the next version.

These four words are easy to mix up. Each row says what the word means and what it does not mean.

Four similar words for different parts.
WordWhat it meansWhat it does not mean
EngineThe program that follows the language rules, runs the code, and manages its memory.A full browser or a full server program.
HostThe program around the engine. It adds outside-world tools, such as the page or files.The parser or the JIT on its own.
RuntimeA complete program you run code in, such as Node, Deno, Bun, a browser tab, or an edge worker.Only the language rules.
EmbedderThe program code that starts the engine, makes isolates and contexts, and hands objects to JavaScript.Normal JavaScript app code.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upName the first token

Use the live playground. What kind of token comes first in 2 + 3 * 4?

Starter codePop out in the code editor (opens in a new tab)JavaScript
const tokenValues = ["num:2", "+", "num:3", "*", "num:4"];
console.log(tokenValues.join(" | "));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upFind the last bytecode instruction

    Look at the toy compiler's bytecode for 2 + 3 * 4. Type the last instruction.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const bytecode = ["PUSH 2", "PUSH 3", "PUSH 4", "MUL", "ADD"];
    console.log(bytecode.at(-1));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind who provides a page tool

      Who provides document.querySelector: the engine, the browser host, Node, or Test262?

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeRead Node's V8 version

        Which Node property does this lesson use to show the version of V8 inside Node?

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeExplain why fast code is dropped

          Fast code was built for adding numbers. Why might the engine drop it after a later call with "1"?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function add(a, b) {
            return a + b;
          }
          console.log(add(1, 2));
          console.log(add("1", 2));

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: engines, steps, and who provides what

            8 QUESTIONS

            Think about the pipeline steps and about who provides each feature. Code answers are real JavaScript output.

            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8Which sentence best describes a JavaScript engine?

              Choose an answer to see the explanation.

            2. Question 2 of 8Which engine and list of tiers matches Chrome and Node, as of this lesson's sources?

              Choose an answer to see the explanation.

            3. Question 3 of 8What result does the toy pipeline give for 2 + 3 * 4?

              Choose an answer to see the explanation.

            4. Question 4 of 8What does this code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function add(a, b) {
                return a + b;
              }
              console.log(add(1, 2));
              console.log(add("1", 2));

              Choose an answer to see the explanation.

            5. Question 5 of 8Which tool comes from the browser host, not from ECMA-262?

              Choose an answer to see the explanation.

            6. Question 6 of 8What does this code print, both in browsers and in Node?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(typeof Array.prototype.map);
              console.log(typeof globalThis);
              console.log(typeof Promise);

              Choose an answer to see the explanation.

            7. Question 7 of 8What is d8 useful for?

              Choose an answer to see the explanation.

            8. Question 8 of 8Why shouldn't you rewrite small bits of code just to please an engine?

              Choose an answer to see the explanation.

            Key takeaways and what comes next

            • V8, SpiderMonkey, and JavaScriptCore are the big browser engines. Hermes, QuickJS, Boa, LibJS, JerryScript, XS, and GraalJS serve other needs, such as phone apps and small devices.
            • The shared steps are: source text, tokens, tree (AST), bytecode, interpreter, feedback, JIT tiers, and sometimes deopt. The garbage collector runs beside all of them.
            • ECMA-262 defines the language. Hosts add the page, timers, files, modules, the event loop, and globals. Embedders start the engine and hand it outside objects.
            • d8, jsvu, eshost-cli, Node's V8 flags, and Test262 are tools for studying and testing engines. Don't depend on them in a real app.
            • Engine knowledge helps you find slow start-up, memory, and speed problems. Measuring still matters more than tips you heard somewhere.

            In one line: the engine runs the language, the host adds the world around it, and measuring beats guessing.

            The next lessons in this stage, and what each one explains:

            What the Inside the engine stage covers next.
            Next lessonWhat it explains
            Scanning source textHow characters become tokens, including /, which can mean two things, and names written with escapes.
            Parsing and ASTsGrammar rules, errors found before code runs, the ESTree format, and why a parser sometimes reads code twice.
            Lazy parsing and startupWhy engines wait before preparing functions that might never run.
            Scope analysis and bytecodeHow the engine finds each variable, handles closures, and builds bytecode before running it.
            Tiered compilation, feedback, inline caches, GCHow engines make hot code fast, drop it safely, and free memory.

            Further reading from the engine teams

            Up next: Scanning source text, where the first stream of characters becomes tokens.

            CompleteFrontend Clear concepts. Working examples.