JIT Compilation

Or how to go fast when needed.

Disclaimer!

This is a very high-level presentation. There will be a handful of links at the end.

Interpreter vs Compiler

Output

Source

Machine code

Interpret

Compile

Execute

Before the execution and only once

During execution and every time

JIT Interpreter

Output

Source

Machine code

Interpret

Compile

Execute

During execution and only sometimes

When to compile?

  1. As soon as it's needed:
  2. As soon as it's hot:

Executed enough number of times

These are only examples!

V8 Overview

Compilation

Deopt

Deopt(imization)?

V8’s interpreter, Ignition, collects profiling information about that function while interpreting it. Once the function becomes hot, this information is passed to V8’s compiler, TurboFan, which generates optimized machine code.

When the profiling information is no longer valid — for example because one of the profiled objects gets a different type during runtime — the optimized machine code might become invalid. In that case, V8 needs to deoptimize it.

If we don't pay attention, our code may be very JIT unfriendly.

Deoptimization

example

function f(o) {
  return o.x
}

// Monomorphic - great!
f({ x: 1 });
f({ x: 2 });

// Polymorphic - OK.
f({ x: 3, y: 1 });

// Megamorphic - bad!
f({ x: 5, a: 1 });
f({ x: 6, b: 1 });
f({ x: 7, c: 1 });

Deoptimization

example

Questions?

Links