1 of 156

Ignition: Jump-starting an Interpreter for V8

Ross McIlroy

Google London

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

2 of 156

Agenda

  • Why we all love JavaScript
  • The V8 approach
  • How to retrofit an interpreter into a moving engine

3 of 156

Why we all love JavaScript...

4 of 156

JavaScript

  • The language of the Web

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

5 of 156

JavaScript

  • The language of the Web
  • Programs are distributed as source - parsing and compiling must be fast

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

6 of 156

JavaScript

  • The language of the Web
  • Programs are distributed as source - parsing and compiling must be fast
  • Untyped: variables and properties do not have types, values do

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

7 of 156

JavaScript

  • The language of the Web
  • Programs are distributed as source - parsing and compiling must be fast
  • Untyped: variables and properties do not have types, values do
  • Prototype-based object model

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

8 of 156

JavaScript

  • The language of the Web
  • Programs are distributed as source - parsing and compiling must be fast
  • Untyped: variables and properties do not have types, values do
  • Prototype-based object model
  • Functional features with closures

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

9 of 156

JavaScript

  • The language of the Web
  • Programs are distributed as source - parsing and compiling must be fast
  • Untyped: variables and properties do not have types, values do
  • Prototype-based object model
  • Functional features with closures
  • A smattering of interesting features
    • eval() allows dynamic execution of runtime generated statements within a function
    • weird scoping rules
    • default values and implicit type coercion
    • ...

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

10 of 156

Something Simple

function add(a, b) {

return a + b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

11 of 156

Something Simple

Integer addition

function add(a, b) {

return a + b;

}

add(1, 2); // 3

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

12 of 156

Something Simple

Integer addition

Floating point addition

function add(a, b) {

return a + b;

}

add(1, 2); // 3

add(1.2, 3.14); // 4.34

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

13 of 156

Something Simple

Integer addition

Floating point addition

String addition

function add(a, b) {

return a + b;

}

add(1, 2); // 3

add(1.2, 3.14); // 4.34

add(“hello”, “world”); // “helloworld”

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

14 of 156

Something Simple

Integer addition

Floating point addition

String addition

Type coercion

function add(a, b) {

return a + b;

}

add(1, 2); // 3

add(1.2, 3.14); // 4.34

add(“hello”, “world”); // “helloworld”

add(1, true); // 2

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

15 of 156

Something Simple

Integer addition

Floating point addition

String addition

Type coercion

function add(a, b) {

return a + b;

}

add(1, 2); // 3

add(1.2, 3.14); // 4.34

add(“hello”, “world”); // “helloworld”

add(1, true); // 2

add(“foo”, true); // “footrue”

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

16 of 156

Something Simple

function add(a, b) {

return a + b;

}

add(1, 2); // 3

add(1.2, 3.14); // 4.34

add(“hello”, “world”); // “helloworld”

add(1, true); // 2

add(“foo”, true); // “footrue”

var bar = {toString:() => “bar”};�add(“foo”, bar); // “foobar”

Integer addition

Floating point addition

String addition

Type coercion

toString() / valueOf()

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

17 of 156

A Glance at Semantics

operator +

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

18 of 156

A Glance at Semantics

operator +

ToPrimitive

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

19 of 156

A Glance at Semantics

operator +

ToString

ToPrimitive

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

20 of 156

A Glance at Semantics

ToPrimitive

ToString

ToNumber

operator +

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

21 of 156

A Glance at Semantics

operator +

ToNumber

ToString

ToPrimitive

GetMethod

GetV

ToObject

Call

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

22 of 156

A Glance at Semantics

operator +

ToNumber

ToString

ToPrimitive

GetMethod

GetV

ToObject

Call

Arbitrary Javascript

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

23 of 156

A Glance at Semantics

operator +

ToNumber

ToString

ToPrimitive

GetMethod

GetV

ToObject

Call

Arbitrary Javascript

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

24 of 156

Everything’s a Function

function Person(name) {

this.name = name;

}

An object’s constructor is just a function

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

25 of 156

Everything’s a Function

function Person(name) {

this.name = name;

}

Person.prototype.toString = function() { return this.name; }

Method’s are installed on the prototype of an object

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

26 of 156

Everything’s a Function

function Person(name) {

this.name = name;

}

Person.prototype.toString = function() { return this.name; }

var jill = new Person(“Jill”);

print(jill); // “Jill”

Objects are instantiated

by “new <Function>(...)

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

27 of 156

Everything’s a Function

function Person(name) {

this.name = name;

}

Person.prototype.toString = function() { return this.name; }

function Student(name, grade) {

Person.call(this, name);

this.grade = grade;

}

Student.prototype.__proto__ = Person.prototype;

var tom = new Student(“Tom”, 72);

print(tom); // “Tom”

Inheritance emulated by prototype chaining

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

28 of 156

Everything’s a Function

function Person(name) {

this.name = name;

}

Person.prototype.toString = function() { return this.name; }

function Student(name, grade) {

Person.call(this, name);

this.grade = grade;

}

Student.prototype.__proto__ = Person.prototype;

var tom = new Student(“Tom”, 72);

tom.__proto__ = Object.prototype;

print(tom); // “[object Object]”

Which is completely dynamic....

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

29 of 156

Except when it’s a Closure

function Counter(start) {

var count = 0;

return {

next: function() { return start + count++; }

}

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

30 of 156

Except when it’s a Closure

function Counter(start) {

var count = 0;

return {

next: function() { return start + count++; }

}

}

var counter = Counter(5);

print(counter.next() + “ -> ” + counter.next()); // 5 -> 6

Closures over parameters, and mutable local variables

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

31 of 156

Fun with eval()

function func(a, b) {

return eval(a) + (b == 0 ? 0 : func(a, --b));

}

func(“1”, 3); // 4

Executes string within the context of the calling function

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

32 of 156

Fun with eval()

function func(a, b) {

return eval(a) + (b == 0 ? 0 : func(a, --b));

}

func(“1”, 3); // 4

func(“b = 0”, 200); // 0

Executes string within the context of the calling function

Can modify locals or introduce new ones

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

33 of 156

Fun with eval()

function func(a, b) {

return eval(a) + (b == 0 ? 0 : func(a, --b));

}

func(“1”, 3); // 4

func(“b = 0”, 200); // 0

func("func = function() {

return 'bar'

}; 'foo'", 50); // “foobar”

Executes string within the context of the calling function

Can modify locals or introduce new ones

Or do crazy things...

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

34 of 156

The V8 Approach

35 of 156

V8 History

  • V8 was the first really fast JavaScript Virtual Machine
    • Launched with Chrome in 2008
    • 10x faster than competition at release
    • 10x faster today than in 2008
  • 2008 - Full-Codegen
    • Fast AST-walking JIT compiler with inline caching
  • 2010 - Crankshaft
    • Optimizing JIT compiler with type feedback and deoptimization
  • 2015 - TurboFan
    • Optimizing JIT compiler with type and range analysis, sea of nodes

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

36 of 156

Compiler Pipeline (2008)

Source

Parser

Full- codegen

Unoptimized Code

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

37 of 156

Full-Codegen in a nutshell

function Sum(point) = {

return point.x + point.y;

};

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

38 of 156

Full-Codegen in a nutshell

function Sum(point) = {

return point.x + point.y;

};

return

+

Load�Property

Load�Property

“x”

point

Parser

“y”

point

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

39 of 156

Full-Codegen in a nutshell

return

+

Load�Property

Load�Property

“x”

point

“y”

point

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

40 of 156

Full-Codegen in a nutshell

... ; prologue

mov eax, [ebp + 0x10] ; point

return

+

Load�Property

Load�Property

“x”

point

“y”

point

Full-Codegen

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

41 of 156

Full-Codegen in a nutshell

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

return

+

Load�Property

Load�Property

“x”

point

“y”

point

Full-Codegen

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

42 of 156

Full-Codegen in a nutshell

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

return

+

Load�Property

Load�Property

“x”

point

“y”

point

Full-Codegen

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

43 of 156

Full-Codegen in a nutshell

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

return

+

Load�Property

Load�Property

“x”

point

“y”

point

Full-Codegen

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

44 of 156

Full-Codegen in a nutshell

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

pop edx

call $BinaryOpAdd

...

return

+

Load�Property

Load�Property

“x”

point

“y”

point

Full-Codegen

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

45 of 156

Full-Codegen in a nutshell

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

pop edx

call $BinaryOpAdd

...

  • Call into runtime
  • Determine object layout
  • Load property with <name>

UNINITIALIZED_LOAD_IC

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

46 of 156

Hidden Classes

function Point(x, y) = {

this.x = x;

this.y = y;

};

Hidden classes was a technique from Self VM

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

47 of 156

Hidden Classes

function Point(x, y) {

this.x = x;

this.y = y;

};

var point = new Point(3, 5);

map[Point]

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

48 of 156

Hidden Classes

function Point(x, y) {

this.x = x;

this.y = y;

};

var point = new Point(3, 5);

3

map[Point]

map[Point1]

0x4: “x”

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

49 of 156

Hidden Classes

function Point(x, y) {

this.x = x;

this.y = y;

};

var point = new Point(3, 5);

3

map[Point]

map[Point1]

0x4: “x”

“x”

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

50 of 156

Hidden Classes

function Point(x, y) {

this.x = x;

this.y = y;

};

var point = new Point(3, 5);

3

5

map[Point]

map[Point1]

0x4: “x”

map[Point2]

0x4: “x”

0x8: “y”

“x”

“y”

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

51 of 156

Inline Caches (ICs)

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

pop edx

call $BinaryOpAdd

...

  • Call into runtime
  • Determine object layout
  • Load property with <name>

UNINITIALIZED_LOAD_IC

  • Generate specialized IC
  • Back-patch original call

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

52 of 156

Inline Caches (ICs)

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

pop edx

call $BinaryOpAdd

...

  • Call into runtime
  • Determine object layout
  • Load property with <name>

UNINITIALIZED_LOAD_IC

  • Generate specialized IC
  • Back-patch original call

… ; Check object’s map is

… ; Point type, or bailout

mov eax, [eax + 0x4]

ret

MONOMORPHIC_LOAD_IC_X

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

53 of 156

Inline Caches (ICs)

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

pop edx

call $BinaryOpAdd

...

… ; Check object’s map is

… ; Point type, or bailout

mov eax, [eax + 0x4]

ret

MONOMORPHIC_LOAD_IC_X

… ; Check object’s map is

… ; Point type, or bailout

mov eax, [eax + 0x8]

ret

MONOMORPHIC_LOAD_IC_Y

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

54 of 156

Inline Caches (ICs)

... ; prologue

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a79431 ; “x”

call $LoadNamedProperty

push eax

mov eax, [ebp + 0x10] ; point

mov ecx, 0x56a71251 ; “y”

call $LoadNamedProperty

pop edx

call $BinaryOpAdd

...

… ; Check object’s map is

… ; Point type, or bailout

mov eax, [eax + 0x4]

ret

MONOMORPHIC_LOAD_IC_X

… ; Check object’s map is

… ; Point type, or bailout

mov eax, [eax + 0x8]

ret

MONOMORPHIC_LOAD_IC_Y

BINARY_OP_ADD_IC

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

55 of 156

Compiler Pipeline (2010)

Source

Parser

Full- codegen

Crankshaft

Optimized Code

Unoptimized Code

Parser

Baseline

Optimized

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

56 of 156

A Little on Crankshaft

function Sum(point) {

return point.x + point.y;

};

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

57 of 156

A Little on Crankshaft

function Sum(point) {

return point.x + point.y;

};

Sum(new Point(1, 2));

Sum(new Point(100, 6));

Sum(new Point(0.5, 30));

Sum(new Point(0.5, 30));

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

58 of 156

A Little on Crankshaft

function Sum(point) {

return point.x + point.y;

};

Sum(new Point(1, 2));

Sum(new Point(100, 6));

Sum(new Point(0.5, 30));

Sum(new Point(0.5, 30));

Always a number

Always Point

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

59 of 156

A Little on Crankshaft

function Sum(point) {

return point.x + point.y;

};

Sum(new Point(1, 2));

Sum(new Point(100, 6));

Sum(new Point(0.5, 30));

Sum(new Point(0.5, 30));

Always a number

Always Point

Inline FP addition

Inline property load

Elide map checks

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

60 of 156

A Little on Crankshaft

function Sum(point) {

return point.x + point.y;

};

Sum(new Point(1, 2));

Sum(new Point(100, 6));

Sum(new Point(0.5, 30));

Sum(new Point(0.5, 30));

Always a number

Always Point

Inline FP addition

Inline property load

Elide map checks

GVN

Inlining

Escape analysis

Type analysis

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

61 of 156

A Little on Crankshaft

function Sum(point) {

return point.x + point.y;

};

Sum(new Point(1, 2));

Sum(new Point(100, 6));

Sum(new Point(0.5, 30));

Sum(new Point(0.5, 30));

Sum(new StringPair(“foo”, “bar”);

Always a number

Always Point

Inline FP addition

Inline property load

Elide map checks

GVN

Inlining

Escape analysis

Type analysis

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

62 of 156

Deoptimization - Always Have a Backup Plan

  • Deopt points inserted before speculative optimizations

  • Crankshaft needs to model Full-Codegen’s execution to rebuild a stack frame for the deopt point

Optimized Code

Baseline Code

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

63 of 156

Compiler Pipeline (2015)

Source

Parser

Full- codegen

Crankshaft

Optimized Code

Unoptimized Code

Parser

TurboFan

Baseline

Optimized

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

64 of 156

Another Optimizing Compiler?

Crankshaft served us well, but has various shortcomings:

  • Doesn’t scale to full modern JavaScript
    • try-catch, for-of, generators, async/await

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

65 of 156

Another Optimizing Compiler?

Crankshaft served us well, but has various shortcomings:

  • Doesn’t scale to full modern JavaScript
    • try-catch, for-of, generators, async/await
  • Relies heavily on deoptimization
    • Performance cliffs and deoptimization loops

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

66 of 156

Another Optimizing Compiler?

Crankshaft served us well, but has various shortcomings:

  • Doesn’t scale to full modern JavaScript
    • try-catch, for-of, generators, async/await
  • Relies heavily on deoptimization
    • Performance cliffs and deoptimization loops
  • Limited static type analysis / propagation
    • Not amenable to asm.js style optimization

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

67 of 156

Another Optimizing Compiler?

Crankshaft served us well, but has various shortcomings:

  • Doesn’t scale to full modern JavaScript
    • try-catch, for-of, generators, async/await
  • Relies heavily on deoptimization
    • Performance cliffs and deoptimization loops
  • Limited static type analysis / propagation
    • Not amenable to asm.js style optimization
  • Tight coupling Full-codegen

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

68 of 156

Another Optimizing Compiler?

Crankshaft served us well, but has various shortcomings:

  • Doesn’t scale to full modern JavaScript
    • try-catch, for-of, generators, async/await
  • Relies heavily on deoptimization
    • Performance cliffs and deoptimization loops
  • Limited static type analysis / propagation
    • Not amenable to asm.js style optimization
  • Tight coupling Full-codegen
  • High porting overhead

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

69 of 156

TurboFan

  • Sea of Nodes
    • Relax evaluation order for most operations (value edges)
    • Skeleton of a CFG remains (control edges) and stateful operations (effect edges)
    • Provides better redundant code elimination and more code motion

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

70 of 156

TurboFan

  • Sea of Nodes
    • Relax evaluation order for most operations (value edges)
    • Skeleton of a CFG remains (control edges) and stateful operations (effect edges)
    • Provides better redundant code elimination and more code motion
  • Three Level IR
    • JavaScript: JavaScript’s overloaded operators
    • Simplified: VM operations, e.g. allocation or number arithmetic
    • Machine: Machine-level operations, e.g. int32 addition

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

71 of 156

TurboFan

  • Sea of Nodes
    • Relax evaluation order for most operations (value edges)
    • Skeleton of a CFG remains (control edges) and stateful operations (effect edges)
    • Provides better redundant code elimination and more code motion
  • Three Level IR
    • JavaScript: JavaScript’s overloaded operators
    • Simplified: VM operations, e.g. allocation or number arithmetic
    • Machine: Machine-level operations, e.g. int32 addition
  • Lowering JS graph to simplified graph based on types
    • Take into account static type information and type feedback

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

72 of 156

Sea of Nodes

Start

End

Branch

IfTrue

IfFalse

Merge

phi

2

1

x

Control edge

Value edge

Effect edge

function (x) {

return x ? 1 : 2;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

73 of 156

Retrofitting an Interpreter into

a Moving Engine

74 of 156

Why Interpret?

  • Reduce memory usage

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

75 of 156

Why Interpret?

  • Reduce memory usage

  • Reduce startup time

33% of time spent parsing + compiling

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

76 of 156

Why Interpret?

  • Reduce memory usage

  • Reduce startup time

  • Reduce complexity

Full- codegen

Crankshaft

TurboFan

Unoptimized Code

Optimized Code

Optimized Code

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

77 of 156

Ignition - Goals

  • Reduce memory usage
    • Compile to bytecode which is 4x smaller than machine code
    • Reduce overall code memory by 2x
  • Reduce startup time

  • Reduce complexity

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

78 of 156

Ignition - Goals

  • Reduce memory usage
    • Compile to bytecode which is 4x smaller than machine code
    • Reduce overall code memory by 2x
  • Reduce startup time
    • Faster compiling to bytecode
    • Reduce re-parsing for lazy compile and optimize re-compile
  • Reduce complexity

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

79 of 156

Ignition - Goals

  • Reduce memory usage
    • Compile to bytecode which is 4x smaller than machine code
    • Reduce overall code memory by 2x
  • Reduce startup time
    • Faster compiling to bytecode
    • Reduce re-parsing for lazy compile and optimize re-compile
  • Reduce complexity
    • Bytecode as source of truth
    • Simplify compilation pipeline

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

80 of 156

Ignition - Challenges

  • Don’t regress performance

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

81 of 156

Ignition - Challenges

  • Don’t regress performance
  • Support 100% of the JavaScript language on 9 CPU architectures

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

82 of 156

Ignition - Challenges

  • Don’t regress performance
  • Support 100% of the JavaScript language on 9 CPU architectures
  • Integrate with V8’s runtime (type feedback, object model, GC, etc)

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

83 of 156

Ignition - Challenges

  • Don’t regress performance
  • Support 100% of the JavaScript language on 9 CPU architectures
  • Integrate with V8’s runtime (type feedback, object model, GC, etc)
  • Support the debugger / liveedit

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

84 of 156

Ignition - Challenges

  • Don’t regress performance
  • Support 100% of the JavaScript language on 9 CPU architectures
  • Integrate with V8’s runtime (type feedback, object model, GC, etc)
  • Support the debugger / liveedit
  • Support two pipelines (Crankshaft and TurboFan)

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

85 of 156

Compiler Pipeline (2015)

Crankshaft

Optimized Code

TurboFan

Optimized

Full- codegen

Unoptimized Code

Baseline

Optimize

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

86 of 156

Compiler Pipeline (2015)

Crankshaft

Optimized Code

TurboFan

Optimized

Full- codegen

Unoptimized Code

Baseline

Optimize

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

87 of 156

Compiler Pipeline (2016)

Crankshaft

Optimized Code

TurboFan

Optimized

Full- codegen

Unoptimized Code

Baseline

Optimize

Ignition

Bytecode

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

88 of 156

Compiler Pipeline (2016)

Crankshaft

Optimized Code

TurboFan

Optimized

Full- codegen

Unoptimized Code

Baseline

Optimize

Ignition

Bytecode

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

89 of 156

Compiler Pipeline (early 2017 ?)

Crankshaft

Optimized Code

TurboFan

Optimized

Full- codegen

Unoptimized Code

Baseline

Optimize

Ignition

Bytecode

Interpreted

Optimize

Baseline

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

90 of 156

Compiler Pipeline (early 2017 ?)

Crankshaft

Optimized Code

TurboFan

Optimized

Full- codegen

Unoptimized Code

Baseline

Optimize

Ignition

Bytecode

Interpreted

Optimize

Baseline

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

91 of 156

Compiler Pipeline (2017 ?)

Optimized Code

TurboFan

Optimized

Ignition

Bytecode

Interpreted

Optimize

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

92 of 156

Ignition Design Decisions

  • Focus on reducing code size
    • Indirect threaded bytecode dispatch
    • Accumulator as implicit input / output

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

93 of 156

Ignition Design Decisions

  • Focus on reducing code size
    • Indirect threaded bytecode dispatch
    • Accumulator as implicit input / output
  • But still as fast as possible
    • Hand coded using (architecture-independent) macro-assembly
    • Register machine

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

94 of 156

Ignition Design Decisions

  • Focus on reducing code size
    • Indirect threaded bytecode dispatch
    • Accumulator as implicit input / output
  • But still as fast as possible
    • Hand coded using (architecture-independent) macro-assembly
    • Register machine
  • Bytecode can be used to build TurboFan graphs directly
    • Bytecode is single source of truth
    • Simpler deoptimization execution modeling

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

95 of 156

Ignition Bytecode

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

96 of 156

Ignition Bytecode

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

97 of 156

Ignition Bytecode

r0 [local]

undefined

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

98 of 156

Ignition Bytecode

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

undefined

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

99 of 156

Ignition Bytecode

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

undefined

accumulator

undefined

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

100 of 156

Ignition Bytecode

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

undefined

accumulator

100

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

101 of 156

Ignition Bytecode

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

undefined

accumulator

50

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

102 of 156

Ignition Bytecode

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

50

accumulator

50

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

103 of 156

Ignition Bytecode

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

50

accumulator

2

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

104 of 156

Ignition Bytecode

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

50

accumulator

100

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

105 of 156

Ignition Bytecode

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

50

accumulator

105

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

106 of 156

Ignition Bytecode

a0 [a]

5

a1 [b]

2

a2 [c]

150

r0 [local]

50

accumulator

105

LdaSmi #100

Sub a2

Star r0

Ldar a1

Mul r0

Add a0

Return

function f(a, b, c) {

var local = c - 100;

return a + local * b;

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

107 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

108 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

void BytecodeGenerator::VisitAddExpression(

BinaryOperation* expr) {

Register lhs =

VisitForRegisterValue(expr->left());

VisitForAccumulatorValue(expr->right());

builder()->AddOperation(lhs);

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

109 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {

// Copy the literal boilerplate.

int fast_clone_properties_count = 0;

if (FastCloneShallowObjectStub::IsSupported(expr)) {

STATIC_ASSERT(

FastCloneShallowObjectStub::kMaximumClonedProperties <=

1 << CreateObjectLiteralFlags::FastClonePropertiesCountBits::kShift);

fast_clone_properties_count =

FastCloneShallowObjectStub::PropertiesCount(expr->properties_count());

}

uint8_t flags =

CreateObjectLiteralFlags::FlagsBits::encode(expr->ComputeFlags()) |

CreateObjectLiteralFlags::FastClonePropertiesCountBits::encode(

fast_clone_properties_count);

builder()->CreateObjectLiteral(expr->constant_properties(),

expr->literal_index(), flags);

// Allocate in the outer scope since this register is used to return the

// expression's results to the caller.

Register literal = register_allocator()->outer()->NewRegister();

builder()->StoreAccumulatorInRegister(literal);

// Store computed values into the literal.

int property_index = 0;

AccessorTable accessor_table(zone());

for (; property_index < expr->properties()->length(); property_index++) {

ObjectLiteral::Property* property = expr->properties()->at(property_index);

if (property->is_computed_name()) break;

if (property->IsCompileTimeValue()) continue;

RegisterAllocationScope inner_register_scope(this);

Literal* literal_key = property->key()->AsLiteral();

switch (property->kind()) {

case ObjectLiteral::Property::CONSTANT:

UNREACHABLE();

case ObjectLiteral::Property::MATERIALIZED_LITERAL:

DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));

// Fall through.

case ObjectLiteral::Property::COMPUTED: {

// It is safe to use [[Put]] here because the boilerplate already

// contains computed properties with an uninitialized value.

if (literal_key->value()->IsInternalizedString()) {

if (property->emit_store()) {

VisitForAccumulatorValue(property->value());

if (FunctionLiteral::NeedsHomeObject(property->value())) {

RegisterAllocationScope register_scope(this);

Register value = register_allocator()->NewRegister();

builder()->StoreAccumulatorInRegister(value);

builder()->StoreNamedProperty(

literal, literal_key->AsPropertyName(),

feedback_index(property->GetSlot(0)), language_mode());

VisitSetHomeObject(value, literal, property, 1);

} else {

builder()->StoreNamedProperty(

literal, literal_key->AsPropertyName(),

feedback_index(property->GetSlot(0)), language_mode());

}

} else {

VisitForEffect(property->value());

}

register_allocator()->PrepareForConsecutiveAllocations(4);

Register literal_argument =

register_allocator()->NextConsecutiveRegister();

Register key = register_allocator()->NextConsecutiveRegister();

Register value = register_allocator()->NextConsecutiveRegister();

Register language = register_allocator()->NextConsecutiveRegister();

builder()->MoveRegister(literal, literal_argument);

VisitForAccumulatorValue(property->key());

builder()->StoreAccumulatorInRegister(key);

VisitForAccumulatorValue(property->value());

builder()->StoreAccumulatorInRegister(value);

if (property->emit_store()) {

builder()

->LoadLiteral(Smi::FromInt(SLOPPY))

.StoreAccumulatorInRegister(language)

.CallRuntime(Runtime::kSetProperty, literal_argument, 4);

VisitSetHomeObject(value, literal, property);

}

}

break;

}

case ObjectLiteral::Property::PROTOTYPE: {

DCHECK(property->emit_store());

register_allocator()->PrepareForConsecutiveAllocations(2);

Register literal_argument =

register_allocator()->NextConsecutiveRegister();

Register value = register_allocator()->NextConsecutiveRegister();

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

110 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

builder()->MoveRegister(literal, literal_argument);

VisitForAccumulatorValue(property->value());

builder()->StoreAccumulatorInRegister(value).CallRuntime(

Runtime::kInternalSetPrototype, literal_argument, 2);

break;

}

case ObjectLiteral::Property::GETTER:

if (property->emit_store()) {

accessor_table.lookup(literal_key)->second->getter = property;

}

break;

case ObjectLiteral::Property::SETTER:

if (property->emit_store()) {

accessor_table.lookup(literal_key)->second->setter = property;

}

break;

}

}

// Define accessors, using only a single call to the runtime for each pair of

// corresponding getters and setters.

for (AccessorTable::Iterator it = accessor_table.begin();

it != accessor_table.end(); ++it) {

RegisterAllocationScope inner_register_scope(this);

register_allocator()->PrepareForConsecutiveAllocations(5);

Register literal_argument = register_allocator()->NextConsecutiveRegister();

Register name = register_allocator()->NextConsecutiveRegister();

Register getter = register_allocator()->NextConsecutiveRegister();

Register setter = register_allocator()->NextConsecutiveRegister();

Register attr = register_allocator()->NextConsecutiveRegister();

builder()->MoveRegister(literal, literal_argument);

VisitForAccumulatorValue(it->first);

builder()->StoreAccumulatorInRegister(name);

VisitObjectLiteralAccessor(literal, it->second->getter, getter);

VisitObjectLiteralAccessor(literal, it->second->setter, setter);

builder()

->LoadLiteral(Smi::FromInt(NONE))

.StoreAccumulatorInRegister(attr)

.CallRuntime(Runtime::kDefineAccessorPropertyUnchecked,

literal_argument, 5);

}

for (; property_index < expr->properties()->length(); property_index++) {

ObjectLiteral::Property* property = expr->properties()->at(property_index);

RegisterAllocationScope inner_register_scope(this);

if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {

DCHECK(property->emit_store());

register_allocator()->PrepareForConsecutiveAllocations(2);

Register literal_argument =

register_allocator()->NextConsecutiveRegister();

Register value = register_allocator()->NextConsecutiveRegister();

builder()->MoveRegister(literal, literal_argument);

VisitForAccumulatorValue(property->value());

builder()->StoreAccumulatorInRegister(value).CallRuntime(

Runtime::kInternalSetPrototype, literal_argument, 2);

continue;

}

register_allocator()->PrepareForConsecutiveAllocations(5);

Register literal_argument = register_allocator()->NextConsecutiveRegister();

Register key = register_allocator()->NextConsecutiveRegister();

Register value = register_allocator()->NextConsecutiveRegister();

Register attr = register_allocator()->NextConsecutiveRegister();

DCHECK(Register::AreContiguous(literal_argument, key, value, attr));

Register set_function_name =

register_allocator()->NextConsecutiveRegister();

builder()->MoveRegister(literal, literal_argument);

VisitForAccumulatorValue(property->key());

builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key);

VisitForAccumulatorValue(property->value());

builder()->StoreAccumulatorInRegister(value);

VisitSetHomeObject(value, literal, property);

builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr);

switch (property->kind()) {

case ObjectLiteral::Property::CONSTANT:

case ObjectLiteral::Property::COMPUTED:

case ObjectLiteral::Property::MATERIALIZED_LITERAL:

builder()

->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName()))

.StoreAccumulatorInRegister(set_function_name);

builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral,

literal_argument, 5);

break;

case ObjectLiteral::Property::PROTOTYPE:

UNREACHABLE(); // Handled specially above.

break;

case ObjectLiteral::Property::GETTER:

builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked,

literal_argument, 4);

break;

case ObjectLiteral::Property::SETTER:

builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked,

literal_argument, 4);

break;

}

}

execution_result()->SetResultInRegister(literal);

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

111 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

112 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

Register Optimizer

Peephole Optimizer

Dead-code Elimination

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

113 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

Register Optimizer

Peephole Optimizer

Dead-code Elimination

Bytecode Array Writer

Bytecode

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

114 of 156

Ignition Bytecode Pipeline

Parser

Bytecode Generator

Abstract Syntax Tree

Register Optimizer

Peephole Optimizer

Dead-code Elimination

Bytecode Array Writer

Bytecode

Interpreter

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

115 of 156

Building the Ignition Interpreter

  • Write in C++

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

116 of 156

Building the Ignition Interpreter

  • Write in C++
    • Need trampolines between Interpreted and JITed functions
    • Can’t interoperate with fast code-stubs

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

117 of 156

Building the Ignition Interpreter

  • Write in C++
    • Need trampolines between Interpreted and JITed functions
    • Can’t interoperate with fast code-stubs

  • Hand-crafted assembly code

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

118 of 156

Building the Ignition Interpreter

  • Write in C++
    • Need trampolines between Interpreted and JITed functions
    • Can’t interoperate with fast code-stubs

  • Hand-crafted assembly code
    • Would need to be ported to 9 architectures

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

119 of 156

Building the Ignition Interpreter

  • Write in C++
    • Need trampolines between Interpreted and JITed functions
    • Can’t interoperate with fast code-stubs

  • Hand-crafted assembly code
    • Would need to be ported to 9 architectures
  • Backend of the TurboFan Compiler

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

120 of 156

Building the Ignition Interpreter

  • Write in C++
    • Need trampolines between Interpreted and JITed functions
    • Can’t interoperate with fast code-stubs

  • Hand-crafted assembly code
    • Would need to be ported to 9 architectures
  • Backend of the TurboFan Compiler
    • Write-once in macro-assembly
    • Architecture specific instruction selection optimizations for free
    • Relatively painless interoperability with existing code-stubs

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

121 of 156

TurboFan Pipeline

JavaScript

Simple

Machine

Scheduler

CodeGen

JavaScript Source

Machine Code

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

122 of 156

TurboFan Pipeline

JavaScript

Simple

Machine

Scheduler

CodeGen

Machine Code

Interpreter Assembler

JavaScript Source

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

123 of 156

TurboFan Pipeline

JavaScript

Simple

Machine

Scheduler

CodeGen

JavaScript Source

Machine Code

WebAssembly

Interpreter Assembler

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

124 of 156

Building an Interpreter using TurboFan

void Interpreter::DoAdd(InterpreterAssembler* assembler) {

Node* reg_index = assembler->BytecodeOperandReg(0);

Node* lhs = assembler->LoadRegister(reg_index);

Node* rhs = assembler->GetAccumulator();

Node* result = AddStub::Generate(assembler, lhs, rhs);

assembler->SetAccumulator(result);

assembler->Dispatch();

}

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

125 of 156

Building an Interpreter using TurboFan

void Interpreter::DoAdd(InterpreterAssembler* assembler) {

Node* reg_index = assembler->BytecodeOperandReg(0);

Node* lhs = assembler->LoadRegister(reg_index);

Node* rhs = assembler->GetAccumulator();

Node* result = AddStub::Generate(assembler, lhs, rhs);

assembler->SetAccumulator(result);

assembler->Dispatch();

}

~375 LOC for number addition

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

126 of 156

Building an Interpreter using TurboFan

void Interpreter::DoAdd(InterpreterAssembler* assembler) {

Node* reg_index = assembler->BytecodeOperandReg(0);

Node* lhs = assembler->LoadRegister(reg_index);

Node* rhs = assembler->GetAccumulator();

Node* result = AddStub::Generate(assembler, lhs, rhs);

assembler->SetAccumulator(result);

assembler->Dispatch();

}

~375 LOC for number addition

~250 LOC for string addition

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

127 of 156

Building an Interpreter using TurboFan

void Interpreter::DoAdd(InterpreterAssembler* assembler) {

Node* reg_index = assembler->BytecodeOperandReg(0);

Node* lhs = assembler->LoadRegister(reg_index);

Node* rhs = assembler->GetAccumulator();

Node* result = AddStub::Generate(assembler, lhs, rhs);

assembler->SetAccumulator(result);

assembler->Dispatch();

}

~375 LOC for number addition

~250 LOC for string addition

… for type conversions

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

128 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

129 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

movsxbq rax,[r14+r12*1+0x1]

movq rax,[rbp+rax*8]

leaq r12,[r12+0x2]

movzxbl rbx,[r12+r14*1]

movq rbx,[r15+rbx*8]

jmp rbx

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Ldar

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

130 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

movsxbq rax,[r14+r12*1+0x1]

movq rax,[rbp+rax*8]

leaq r12,[r12+0x2]

movzxbl rbx,[r12+r14*1]

movq rbx,[r15+rbx*8]

jmp rbx

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Load operand #0

Ldar

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

131 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

movsxbq rax,[r14+r12*1+0x1]

movq rax,[rbp+rax*8]

leaq r12,[r12+0x2]

movzxbl rbx,[r12+r14*1]

movq rbx,[r15+rbx*8]

jmp rbx

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Load operand #0

Ldar

Load register to accumulator

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

132 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

movsxbq rax,[r14+r12*1+0x1]

movq rax,[rbp+rax*8]

leaq r12,[r12+0x2]

movzxbl rbx,[r12+r14*1]

movq rbx,[r15+rbx*8]

jmp rbx

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Load operand #0

Ldar

Load register to accumulator

Advance to next bytecode

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

133 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

movsxbq rax,[r14+r12*1+0x1]

movq rax,[rbp+rax*8]

leaq r12,[r12+0x2]

movzxbl rbx,[r12+r14*1]

movq rbx,[r15+rbx*8]

jmp rbx

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Load operand #0

Ldar

Load register to accumulator

Advance to next bytecode

Load next bytecode

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

134 of 156

Indirect Threaded Bytecode Dispatch

...

Ldar:

Star:

Add:

Sub:

movsxbq rax,[r14+r12*1+0x1]

movq rax,[rbp+rax*8]

leaq r12,[r12+0x2]

movzxbl rbx,[r12+r14*1]

movq rbx,[r15+rbx*8]

jmp rbx

0x32e3e920

0x32e3e9a0

0x32e400e0

0x32e401e0

Load operand #0

Ldar

Load register to accumulator

Advance to next bytecode

Load next bytecode

Dispatch

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

135 of 156

Inline Caches with Code Patching

Machine Code

IC Stubs

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

136 of 156

Inline Caches with Code Patching

Machine Code

IC Stubs

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

137 of 156

Inline Caches with Type Feedback Vector

Machine Code

IC Stubs

Feedback Vector

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

138 of 156

Inline Caches with Type Feedback Vector

Bytecode

IC Stubs

Feedback Vector

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

139 of 156

Inline Caches with Type Feedback Vector

Bytecode

IC Stubs

Feedback Vector

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

140 of 156

Ignition vs Full-Codegen

Octane (Nexus 5)Crankshaft and TurboFan disabled

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

141 of 156

Ignition vs Full-Codegen

Octane (Nexus 5)Crankshaft and TurboFan disabled

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

142 of 156

Ignition vs Default

Octane Score (x64)

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

143 of 156

Ignition vs Default

Octane Score (x64)

40% slower

5% slower

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

144 of 156

Ignition vs Default

Octane Score (x64)

40% slower

5% slower

Tune Tiering up

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

145 of 156

Ignition vs Default

Octane Score (x64)

40% slower

5% slower

Tune Tiering up

OSR

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

146 of 156

Ignition vs Default

Octane Score (x64)

40% slower

5% slower

Tune Tiering up

OSR

BinaryOp Feedback

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

147 of 156

Ignition vs Default

Octane Score (x64)

40% slower

5% slower

Tune Tiering up

OSR

BinaryOp Feedback

CS / TF adaption

Score

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

148 of 156

Real Websites

Google Maps

LinkedIn

Facebook

Default

Default

Default

Ignition

Ignition

Ignition

Page Load (ms)

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

149 of 156

Real Websites

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

150 of 156

Real Websites

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

151 of 156

Summary

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

152 of 156

Summary

  • JavaScript is hard

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

153 of 156

Summary

  • JavaScript is hard
  • V8 is complex

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

154 of 156

Summary

  • JavaScript is hard
  • V8 is complex
  • An interpreter can (sometimes) beat a JIT...

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

155 of 156

Summary

  • JavaScript is hard
  • V8 is complex
  • An interpreter can (sometimes) beat a JIT... but it takes a lot of work!

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem

156 of 156

Ignition Bytecodes

Loading the accumulator

LdaZero

LdaSmi8

LdaUndefined

LdrUndefined

LdaNull

LdaTheHole

LdaTrue

LdaFalse

LdaConstant

Binary Operators

Add

Sub

Mul

Div

Mod

BitwiseOr

BitwiseXor

BitwiseAnd

ShiftLeft

ShiftRight

ShiftRightLogical

Closure Allocation

CreateClosure

Globals

LdaGlobal

LdrGlobal

LdaGlobalInsideTypeof

StaGlobalSloppy

StaGlobalStrict

Unary Operators

Inc

Dec

LogicalNot

TypeOf

DeletePropertyStrict

DeletePropertySloppy

Call Operations

Call

TailCall

CallRuntime

CallRuntimeForPair

CallJsRuntime

InvokeIntrinsic

New Operator

New

Test Operators

TestEqual

TestNotEqual

TestEqualStrict

TestLessThan

TestGreaterThan

TestLessThanOrEqual

TestGreaterThanOrEqual

TestInstanceOf

TestIn

Context Operations

PushContext

PopContext

LdaContextSlot

LdrContextSlot

StaContextSlot

Cast Operators

ToName

ToNumber

ToObject

Arguments Allocation

CreateMappedArguments

CreateUnmappedArguments

CreateRestParameter

Register Transfers

Ldar

Star

Mov

Control Flow

Jump

JumpConstant

JumpIfTrue

JumpIfTrueConstant

JumpIfFalse

JumpIfFalseConstant

JumpIfToBooleanTrue

JumpIfToBooleanTrueConstant

JumpIfToBooleanFalse

JumpIfToBooleanFalseConstant

JumpIfNull

JumpIfNullConstant

JumpIfUndefined

JumpIfUndefinedConstant

JumpIfNotHole

JumpIfNotHoleConstant

Non-Local Flow Control

Throw

ReThrow

Return

Literals

CreateRegExpLiteral

CreateArrayLiteral

CreateObjectLiteral

Load Property Operations

LdaNamedProperty

LdaKeyedProperty

KeyedLoadICStrict

Store Property Operations

StoreICSloppy

StoreICStrict

KeyedStoreICSloppy

KeyedStoreICStrict

Complex Flow Control

ForInPrepare

ForInNext

ForInDone

ForInStep

Generators

SuspendGenerator

ResumeGenerator

Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem