WhoBuilt

Hermes Hacking: Demystifying JavaScript Engines

Sep 25, 2023· 27 min· 5.5K views·Watch on YouTube

Speaker

Radek Pietruszewski, CTO of Nozbe and author of open-source React Native libraries, explains JavaScript engines and Hermes at React Native EU 2023.

From source code to an abstract syntax tree

Lexing turns JavaScript source into tokens, removing whitespace and comments and converting string and number syntax into values. Parsing organizes those tokens into an abstract syntax tree, with nodes for functions, calls, identifiers, and literals. Pietruszewski notes that JavaScript syntax can be ambiguous, so parsing uses context to distinguish cases such as division and regular expressions.

How a simple interpreter runs code

An AST interpreter evaluates each node, working through expressions such as `1 + 2 * 3` and looking up variables in an execution context. A practical interpreter also needs to handle function declarations, hoisting, nested scopes, and the call stack. Pietruszewski uses `const a = 1` followed by `console.log(a + 2)` to show how declarations and calls are evaluated.

Why engines use bytecode

A bytecode interpreter first compiles the AST into a flat sequence of simple instructions, then executes them on a virtual machine with registers and locals. Pietruszewski says this layout can improve performance because execution follows a compact instruction buffer instead of jumping among AST objects in memory. Hermes also uses an intermediate representation, applies optimization passes, and generates bytecode ahead of execution.

How garbage collection reclaims memory

Pietruszewski describes mark-and-sweep collection: the engine follows references from roots such as globals, event handlers, and stack locals, then frees objects it cannot reach. Collection may pause execution, so the hard engineering problem is reducing pauses and doing more work concurrently. He points to Hermes documentation and a WebKit post by Filip Pizło for deeper reading.

Takeaways

  • A basic understanding of engines does not require a compiler background; tracing tokens, AST nodes, and execution makes the stages approachable.
  • AST interpretation is intuitive, while bytecode turns execution into a flat sequence of instructions that can be optimized.
  • JavaScript parsing needs grammar context to resolve ambiguous syntax such as division versus regular expressions.
  • Garbage collection keeps reachable objects alive and reclaims unreachable ones; pause time and concurrency are the main performance challenges.

Mentioned in this talk

Search inside this talk

What was claimed 10

Show all 10 facts

Related talks