Top Banner
Implementing a JavaScript Engine Krystal Mok (@rednaxelafx ) 2013-11-10
81

Implementing a JavaScript Engine

May 08, 2015

Download

Technology

Kris Mok

Presentation done at JingJS, Nov 10, 2013.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Implementing a JavaScript Engine

Implementing aJavaScript Engine

Krystal Mok (@rednaxelafx)2013-11-10

Page 2: Implementing a JavaScript Engine

Implementing a(Modern, High Performance?)

JavaScript Engine

Page 3: Implementing a JavaScript Engine

About Me

• Programming language and virtual machine enthusiast

• Worked on the HotSpot JVM at Taobao and Oracle

• Also worked on a JavaScript engine project• Twitter / Sina Weibo: @rednaxelafx• Blog: English / Chinese

Page 4: Implementing a JavaScript Engine

Agenda

• Know the Heritage• JavaScript Engine Overview• Implementation Strategies and Tradeoffs• A bit about Nashorn

Page 5: Implementing a JavaScript Engine

KNOW THE HERITAGEThe roots of JavaScript language and modern JavaScript engines

Page 6: Implementing a JavaScript Engine

Heritage of the Language

Self

Scheme

Java

JavaScript

function closure

prototype-based OO

C-like syntax,built-in objects

Page 7: Implementing a JavaScript Engine

Language Comparison

Self• Prototype-based OO• Multiple Prototype• Dynamically Typed• Dynamically Extend Objects• Mirror-based Reflection• Block (closure)• Support Non-local Return• (pass a error handler to

methods that might one)

JavaScript (ECMAScript 5)• Prototype-based OO• Single Prototype• Dynamically Typed• Dynamically Extend Objects• Reflection• First-class Function (closure)• (no non-local return)• Exception Handling

Page 8: Implementing a JavaScript Engine

Heritage of the Languagefunction MyPoint(x, y) { this.x = x; this.y = y;}

MyPoint.prototype.distance = function (p) { var xd = this.x - p.x, yd = this.y - p.y; return Math.sqrt(xd*xd + yd*yd);}

var p = new Point(2013, 11);

Page 9: Implementing a JavaScript Engine

Heritage of the Languagetraits myPoint = (| parent* = traits clonable. initX: newX Y: newY = (x: newX. y: newY) distance: p = (| xd. yd | xd: x - p x. yd: y - p y. (xd squared + yd squared) squareRooted ).|).

myPoint = (| parent* = traits myPoint. x <- 0. y <- 0|).

p: myPoint copy initX: 2013 Y: 11

Page 10: Implementing a JavaScript Engine

Heritage of the Language

on Self 4.4 / Mac OS X 10.7.5

Page 11: Implementing a JavaScript Engine

Heritage of the VM

Self VM(Self)

Strongtalk VM(Smalltalk)

HotSpot VM(Java)

V8(JavaScript)

CLDC-HI(Java)

Page 12: Implementing a JavaScript Engine

What’s in common?

• Lars Bak!

Page 13: Implementing a JavaScript Engine

VM Comparison

Self VM (3rd Generation)• Fast Object w/Hidden Class• Tiered Compilation

– OSR and deoptimization– support for full-speed debugging

• Type Feedback– Polymorphic Inline Caching

• Type Inference• Method/Block Inlining• Method Customization• Generational Scavenging

– Scavenging + Mark-Compact

V8 (with Crankshaft)• Fast Object w/Hidden Class• Tiered Compilation

– OSR and deoptimization– support for full-speed debugging

• Type Feedback– Polymorphic Inline Caching

• Type Inference• Function Inlining• Generational Scavenging

– Scavenging + Mark-Sweep/Mark-Compact

Page 14: Implementing a JavaScript Engine

To Implement a High Performance JavaScript Engine

• Learn from Self VM as a basis!

Page 15: Implementing a JavaScript Engine

Themes

• Pay-as-you-go / Lazy• Take advantage of runtime information– Type feedback

• Take advantage of actual code stability– Try to behave as static as possible

Page 16: Implementing a JavaScript Engine

JAVASCRIPT ENGINE OVERVIEWOutline of the main components

Page 17: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 18: Implementing a JavaScript Engine

Components of a JavaScript Engine

Memory (Runtime Data Areas)

Source Code

FFI

host / external library

GCJavaScriptObjects

CallStack

Parser ExecutionEngineAST

Page 19: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 20: Implementing a JavaScript Engine

Parser

• Parse source code into internal representation• Usually generates AST

var z = x + y

VarDecl: z

BinaryArith: +

x y

Page 21: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 22: Implementing a JavaScript Engine

Runtime

• Value Representation• Object Model• Built-in Objects• Misc.

__proto__

x 2013

y 11

Object

__proto__

prototype

__proto__ null

constructor

… …

Function

__proto__

prototype

__proto__

constructor

… …

Page 23: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 24: Implementing a JavaScript Engine

Execution Engine

• Execute JavaScript Code

VarDecl: z

BinaryArith: +

x y

addl %rcx, %rax

Page 25: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 26: Implementing a JavaScript Engine

Garbage Collector

• Collect memory from unused objects

Page 27: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 28: Implementing a JavaScript Engine

Foreign Function Interface

• Handle interaction between JavaScript and “the outside world”

• JavaScript call out to native function• Native function call into JavaScript function, or

access JavaScript object

Page 29: Implementing a JavaScript Engine

Components of a JavaScript Engine

• Parser• Runtime• Execution Engine• Garbage Collector (GC)• Foreign Function Interface (FFI)• Debugger and Diagnostics

Page 30: Implementing a JavaScript Engine

Debugger and Diagnostics

Page 31: Implementing a JavaScript Engine

IMPLEMENTATION STRATEGIES AND TRADEOFFS

Page 32: Implementing a JavaScript Engine

Parser

• LR• LL• Recursive Descent• Operator Precedence• Lazy Parsing / Deferred Parsing

Page 33: Implementing a JavaScript Engine

Value Representation

• Pointers, and all values allocated on heap• Discriminated Union• Tagged Value / Tagged Pointer

Page 34: Implementing a JavaScript Engine

Value Representation

• Pointers, and all values allocated on heap• Discriminated Union• Tagged Value / Tagged Pointer

Tag_Int

2013

typedef Object* JSValue;

Page 35: Implementing a JavaScript Engine

Value Representation

• Pointers, and all values allocated on heap• Discriminated Union• Tagged Value / Tagged Pointer

Tag_Int

2013

class JSValue { ObjectType ot; union { double n; bool b; Object* o; // … } u;}

Page 36: Implementing a JavaScript Engine

Tagged

• Tagged Pointer– Non-zero tag on pointer– Favor small integer arithmetics

• Tagged Value– Non-zero tag on non-pointer– Favor pointer access

• NaN-boxing– use special NaN value as box

small integer 00

pointer 01

Page 37: Implementing a JavaScript Engine

Tagged

• Tagged Pointer– Non-zero tag on pointer– Favor small integer arithmetics

• Tagged Value– Non-zero tag on non-pointer– Favor pointer access

• NaN-boxing– use special NaN value as box

small integer 01

pointer 00

Page 38: Implementing a JavaScript Engine

Tagged

• Tagged Pointer– Non-zero tag on pointer– Favor small integer arithmetics

• Tagged Value– Non-zero tag on non-pointer– Favor pointer access

• NaN-boxing– use special QNaN value as box

00000000 pointer

xxxxxxxx double

11111111 00000000 integer

Page 39: Implementing a JavaScript Engine

Value Representation in Self

Page 40: Implementing a JavaScript Engine

Numeric Tower

• Internal Numeric Tower• Smi -> HeapDouble• int -> long -> double• unboxed number

Page 41: Implementing a JavaScript Engine

Object Model

• Hash based– “Dictionary Mode”

• Hidden Class based– “Fast Object”

Page 42: Implementing a JavaScript Engine

Groovy code: Equivalent Java code:

Object ModelExample: behind Groovy’s “object literal”-ish syntax

obj = [ x: 2013, y: 42];

i = obj.x;

obj = new LinkedHashMap(2);obj.put("x", 2013);obj.put("y", 42);

i = obj.get("x");

Page 43: Implementing a JavaScript Engine

keySet null

values null

table

size 2

threshold 1

loadFactor 0.75

modCount 2

entrySet null

header

accessOrder false

2013

42

0

1

key “y”

value

next null

hash 126

before x

after header

key null

value null

next null

hash -1

before

after

key “x”

value

next null

hash 127

before header

after y

Page 44: Implementing a JavaScript Engine

map

__proto__

context …

flags 0

spill null

arrayData

L0 x

L1 y

L2 (unused)

L3 (unused)

Key Getter Setter“x” x getter x setter“y” y getter y setter

map

__proto__

2013

42

EMPTY_ARRAY

Nashorn Object Model

Page 45: Implementing a JavaScript Engine

map

__proto__

context …

flags 0

spill null

arrayData

L0 x

L1 y

L2 (unused)

L3 (unused)

Key Getter Setter“x” x getter x setter“y” y getter y setter

map

__proto__

2013

42

EMPTY_ARRAY

Let’s ignore some fields

for now

Page 46: Implementing a JavaScript Engine

map

L0 x

L1 y

Key Getter Setter“x” x getter x setter“y” y getter y setter

2013

42

… and we’ll get this

Page 47: Implementing a JavaScript Engine

metadata

x

y

Key Offset“x” +12“y” +16

2013

42

looks just like a Java

object

class Point { Object x; Object y;}

… with boxed fields

Page 48: Implementing a JavaScript Engine

metadata

x 2013

y 42

Key Offset“x” +12“y” +16

would be even better

if …

class Point { int x; int y;}

but Nashorn doesn’t go this far yet

Page 49: Implementing a JavaScript Engine

map

__proto__

context …

flags 0

spill

arrayData

L0 x

L1 y

L2 z

L3 a

Key Getter Setter“x” x getter x setter“y” y getter y setter“z” z getter z setter“a” a getter a setter“b” b getter b setter

map

__proto__

1

2

0 6

1 7

b

5

3

4

Page 50: Implementing a JavaScript Engine

Inline Cache

• Facilitated by use of hidden class• Improve property access efficiency• Collect type information for type feedback– later fed to JIT compilers for better optimization

• Works with both interpreted and compiled code

Page 51: Implementing a JavaScript Engine

String

• Flat string• Rope / ConsString / ConcatString• Substring / Span• Symbol / Atom• External String

Page 52: Implementing a JavaScript Engine

RegExp

• NFA• Optimize to DFA where profitable• Interpreted• JIT Compiled

Page 53: Implementing a JavaScript Engine

Call Stack

• Native or separate?• Native– fast– easier transition between execution modes– harder to implement

• Separate (aka “stack-less”)– easy to implement– slow– overhead when transitioning between exec modes

Page 54: Implementing a JavaScript Engine

Execution Engine

• Interpreter• Compiler– Ahead-of-Time Compiler– Just-in-Time Compiler– Dynamic / Adaptive Compiler

• Mixed-mode• Tiered

Page 55: Implementing a JavaScript Engine

Execution Engine in Self

Page 56: Implementing a JavaScript Engine

Interpreter

• Line Interpreter• AST Interpreter• Stack-based Bytecode Interpreter• Register-based Bytecode Interpreter

Page 57: Implementing a JavaScript Engine

Interpreter

• Written in– C/C++– Assembler– others?

Page 58: Implementing a JavaScript Engine

Compiler Concurrency

• Foreground/Blocking Compilation• Background Compilation• Parallel Compilation

Page 59: Implementing a JavaScript Engine

Baseline Compiler

• Fast compilation, little optimization• Should generate type-stable code

Page 60: Implementing a JavaScript Engine

Optimizing Compiler

• Type Feedback• Type Inference• Function Inlining

Page 61: Implementing a JavaScript Engine

On-stack Replacement

Page 62: Implementing a JavaScript Engine

Garbage Collection

• Reference Counting?– not really used by any mainstream impl

• Tracing GC– mark-sweep– mark-compact– copying

Page 63: Implementing a JavaScript Engine

GC Advances

• Generational GC• Incremental GC• Concurrent GC• Parallel GC

Page 64: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCmark sweep

Mark-Sweep

Page 65: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCmark compact

Mark-Compact

Page 66: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCscavenge

Scavenging

Page 67: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCincremental mark sweep

Incremental Mark

Page 68: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCmark lazy sweep

Lazy Sweep

Page 69: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCincremental mark lazy sweep

Incremental Mark + Lazy Sweep

Page 70: Implementing a JavaScript Engine

GC Concurrency

Application Thread

JavaScript

GCincremental markand scavenge

lazy sweep

Generational:Scavenging + (Incremental Mark + Lazy Sweep)

Page 71: Implementing a JavaScript Engine

GC Concurrency

GC Thread

Application Thread

JavaScript

GC

initial markconcurrent sweepconcurrent mark

remark reset

(Mostly) Concurrent Mark-Sweep

Page 72: Implementing a JavaScript Engine

A BIT ABOUT NASHORNA new high performance JavaScript on top of the JVM

Page 73: Implementing a JavaScript Engine

What is Nashorn?

• Oracle’s ECMAScript 5.1 implementation, on the JVM

• Clean code base, 100% Java– started from scratch; no code from Rhino

• An OpenJDK project• GPLv2 licensed

Overview

Page 74: Implementing a JavaScript Engine

What is Nashorn?Origins of the “Nashorn” name: the Rhino book

Page 75: Implementing a JavaScript Engine

What is Nashorn?Origins of the “Nashorn” name: Mozilla Rhino

Page 76: Implementing a JavaScript Engine

What is Nashorn?Origins of the “Nashorn” name: the unofficial Nashorn logo

Page 77: Implementing a JavaScript Engine

What is Nashorn?Origins of the “Nashorn” name: my impression

Page 78: Implementing a JavaScript Engine

Dynamic Languages on the JVMCan easily get to a sports-car-ish level

Page 79: Implementing a JavaScript Engine

Dynamic Languages on the JVMTakes some effort to get to a decent sports car level

Page 80: Implementing a JavaScript Engine

Dynamic Languages on the JVMHard to achieve extremely good performance

Page 81: Implementing a JavaScript Engine

Nashorn Execution Model

Lexical Analysis

Syntax Analysis

Constant Folding

Control-flow Lowering

Type Annotating

Range Analysis (*)

Code Splitting

Type Hardening

Bytecode Generation

JavaScript Source Code

AST

Java Bytecode

Parser (Compiler Frontend)

Compiler Backend

* Not complete yet