Running Code with the JIT All Major The basic JIT compiler on x = y + z : Browsers ‣ read the operation x = y + z from memory CPU does it for us! ‣ read the inputs y and z from memory ‣ check the types of y and z and choose the action ‣ unbox y and z ‣ execute the action ‣ box the output x ‣ write the output x to memory JIT code can keep things in registers Tuesday, November 8, 2011
Choosing the action in the JIT Tuesday, November 8, 2011
Choosing the action in the JIT • Many cases for operators like + Tuesday, November 8, 2011
Choosing the action in the JIT • Many cases for operators like + • Engines generate fast JIT code for “common cases” • number + number • string + string Tuesday, November 8, 2011
Choosing the action in the JIT • Many cases for operators like + • Engines generate fast JIT code for “common cases” • number + number • string + string • “Rare cases” run in the slow zone • number + undefined Tuesday, November 8, 2011
JITs for Regular Expressions All Major Browsers • There is a separate JIT for regular expressions • Regular expressions are generally faster than manual search • Still in the slow zone: • Some complex regexes (example: backreferences ) • Building result arrays ( test much faster than exec ) Tuesday, November 8, 2011
Object Properties function f(obj) { return obj.a + 1; } Tuesday, November 8, 2011
Object Properties function f(obj) { return obj.a + 1; } • Need to search obj for a property named a slow Tuesday, November 8, 2011
Object Properties function f(obj) { return obj.a + 1; } • Need to search obj for a property named a slow • May need to search prototype chain up several levels super-slow Tuesday, November 8, 2011
Object Properties function f(obj) { return obj.a + 1; } • Need to search obj for a property named a slow • May need to search prototype chain up several levels super-slow • Finally, once we’ve found it, get the property value fast! Tuesday, November 8, 2011
ICs: a mini-JIT for objects All Major Browsers Tuesday, November 8, 2011
ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) Tuesday, November 8, 2011
ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) • Basic plan: Tuesday, November 8, 2011
ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) • Basic plan: 1. First time around, search for the property in the Slow Zone Tuesday, November 8, 2011
ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) • Basic plan: 1. First time around, search for the property in the Slow Zone 2. But record the steps done to actually get the property Tuesday, November 8, 2011
ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) • Basic plan: 1. First time around, search for the property in the Slow Zone 2. But record the steps done to actually get the property 3. Then JIT a little piece of code that does just those steps Tuesday, November 8, 2011
ICs: Example Example Code var obj1 = { a: 1, b: 2, c: 3 }; var obj2 = { b: 2 }; function f(obj) { return obj.b + 1; } Tuesday, November 8, 2011
ICs: Example Example Code var obj1 = { a: 1, b: 2, c: 3 }; var obj2 = { b: 2 }; function f(obj) { return obj.b + 1; } Generated JIT Code ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code shape=12, in position 1 var obj1 = { a: 1, b: 2, c: 3 }; var obj2 = { b: 2 }; function f(obj) { return obj.b + 1; } Generated JIT Code ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] jump continue_1 function f(obj) { return obj.b + 1; } Generated JIT Code ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] jump continue_1 function f(obj) { return obj.b + 1; } Generated JIT Code ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] jump continue_1 function f(obj) { return obj.b + 1; } Generated JIT Code ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] shape=15, in position 0 jump continue_1 function f(obj) { return obj.b + 1; } Generated JIT Code ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] shape=15, in position 0 jump continue_1 function f(obj) { return obj.b + 1; icStub_2: } compare obj.shape, 15 jumpIfFalse slowPropAccess load obj.props[0] Generated JIT Code jump continue_1 ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] shape=15, in position 0 jump continue_1 function f(obj) { return obj.b + 1; icStub_2: } compare obj.shape, 15 jumpIfFalse slowPropAccess load obj.props[0] Generated JIT Code jump continue_1 ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
ICs: Example Example Code icStub_1: shape=12, in position 1 compare obj.shape, 12 var obj1 = { a: 1, b: 2, c: 3 }; jumpIfFalse slowPropAccess var obj2 = { b: 2 }; load obj.props[1] shape=15, in position 0 jump continue_1 function f(obj) { return obj.b + 1; icStub_2: } compare obj.shape, 15 jumpIfFalse slowPropAccess load obj.props[0] Generated JIT Code jump continue_1 ... jump slowPropAccess slowPropAccess: continue_1: ... set up call ... call ICGetProp ; C++ Slow Zone jump continue_1 Tuesday, November 8, 2011
These are fast because of ICs Global Variable Access var q = 4; var r; function f(obj) { r = q; } Tuesday, November 8, 2011
These are fast because of ICs Global Variable Access var q = 4; var r; function f(obj) { r = q; } Direct Property Access var obj1 = { a: 1, b: 2, c: 3 }; var obj2 = { b: 2 }; function f(obj) { obj2.b = obj1.c; } Tuesday, November 8, 2011
These are fast because of ICs Closure Variable Access Global Variable Access var f = function() { var q = 4; var x = 1; var r; var g = function() { var sum = 0; function f(obj) { for (var i = 0; i < N; ++i) { r = q; sum += x; } } return sum; Direct Property Access } return g(); var obj1 = { a: 1, b: 2, c: 3 }; } var obj2 = { b: 2 }; function f(obj) { obj2.b = obj1.c; } Tuesday, November 8, 2011
Prototype chains don’t hurt function A(x) { this.x = x; } function B(y) { this.y = y; } B.prototype = new A; function C(z) { this.z = z; } C.prototype = new B; Tuesday, November 8, 2011
Prototype chains don’t hurt new A function A(x) { this.x = x; } new B function B(y) { proto this.y = y; } new C(1) B.prototype = new A; function C(z) { this.z = z; } C.prototype = new B; Tuesday, November 8, 2011
Prototype chains don’t hurt new A function A(x) { this.x = x; } new B function B(y) { proto this.y = y; } new C(1) new C(2) B.prototype = new A; function C(z) { this.z = z; } C.prototype = new B; Tuesday, November 8, 2011
Prototype chains don’t hurt new A function A(x) { this.x = x; } new B function B(y) { proto this.y = y; } new C(1) new C(2) new C(3) B.prototype = new A; function C(z) { this.z = z; } C.prototype = new B; Tuesday, November 8, 2011
Prototype chains don’t hurt new A function A(x) { this.x = x; } new B function B(y) { proto this.y = y; } new C(1) new C(2) new C(3) B.prototype = new A; function C(z) { Shape of new C objects determines prototype this.z = z; } C.prototype = new B; Tuesday, November 8, 2011
Prototype chains don’t hurt new A function A(x) { this.x = x; } new B function B(y) { proto this.y = y; } new C(1) new C(2) new C(3) B.prototype = new A; function C(z) { Shape of new C objects determines prototype this.z = z; } C.prototype = new B; -> IC can generate code that checks shape, then reads directly from prototype without walking Tuesday, November 8, 2011
Many Shapes Slow Down ICs What happens if many shapes of obj are passed to f? function f(obj) { return obj.p; } ICs end up looking like this: Tuesday, November 8, 2011
Many Shapes Slow Down ICs What happens if many shapes of obj are passed to f? function f(obj) { return obj.p; } ICs end up looking like this: jumpIf shape != 12 read for shape 12 Tuesday, November 8, 2011
Many Shapes Slow Down ICs What happens if many shapes of obj are passed to f? function f(obj) { return obj.p; } ICs end up looking like this: jumpIf shape != 12 read for shape 12 jumpIf shape != 15 read for shape 15 Tuesday, November 8, 2011
Many Shapes Slow Down ICs What happens if many shapes of obj are passed to f? function f(obj) { return obj.p; } ICs end up looking like this: jumpIf shape != 12 read for shape 12 jumpIf shape != 15 read for shape 15 jumpIf shape != 6 read for shape 6 Tuesday, November 8, 2011
Many Shapes Slow Down ICs What happens if many shapes of obj are passed to f? function f(obj) { return obj.p; } ICs end up looking like this: ... jumpIf shape != 12 jumpIf shape != 16 read for shape 12 read for shape 16 jumpIf shape != 15 jumpIf shape != 22 read for shape 15 read for shape 22 jumpIf shape != 6 jumpIf shape != 3 read for shape 6 read for shape 3 Tuesday, November 8, 2011
Many shapes in practice 100 IE IE Slow Zone for 2+ shapes Opera Chrome 75 nanoseconds/iteration Opera # of shapes doesn’t matter! Firefox Safari Chrome more shapes -> slower 50 Firefox slower with more shapes, 25 but levels off in Slow Zone Safari 0 1 2 8 16 32 100 200 # of shapes at property read site Tuesday, November 8, 2011
Deeply Nested Closures are Slower var f = function() { var x; var g = function() { var h = function() { var y; var i = function () { var j = function() { z = x + y; Tuesday, November 8, 2011
Deeply Nested Closures are Slower f call object var f = function() { var x; var g = function() { var h = function() { h call object var y; var i = function () { var j = function() { j call object z = x + y; First call to f Tuesday, November 8, 2011
Deeply Nested Closures are Slower f call object f call object var f = function() { var x; var g = function() { var h = function() { h call object h call object var y; var i = function () { var j = function() { j call object j call object z = x + y; Second call to f First call to f Tuesday, November 8, 2011
Deeply Nested Closures are Slower f call object f call object var f = function() { var x; var g = function() { var h = function() { h call object h call object var y; var i = function () { var j = function() { j call object j call object z = x + y; Second call to f First call to f • Prototype chains don’t slow us down, but deep closure nesting does. Why? Tuesday, November 8, 2011
Deeply Nested Closures are Slower f call object f call object var f = function() { var x; var g = function() { var h = function() { h call object h call object var y; var i = function () { var j = function() { j call object j call object z = x + y; Second call to f First call to f • Prototype chains don’t slow us down, but deep closure nesting does. Why? • Every call to f generates a unique closure object to hold x . Tuesday, November 8, 2011
Deeply Nested Closures are Slower f call object f call object var f = function() { var x; var g = function() { var h = function() { h call object h call object var y; var i = function () { var j = function() { j call object j call object z = x + y; Second call to f First call to f • Prototype chains don’t slow us down, but deep closure nesting does. Why? • Every call to f generates a unique closure object to hold x . • The engine must walk to find the right x each time Tuesday, November 8, 2011
Properties in the Slow Zone Tuesday, November 8, 2011
Properties in the Slow Zone Undefined Property (Fast on Firefox, Chrome) var a = {}; a.x; Tuesday, November 8, 2011
Properties in the Slow Zone Undefined Property (Fast on Firefox, Chrome) var a = {}; a.x; DOM Access (I only tested .id, so take with a grain of salt-- other properties may differ) var a = document.getByElementId(“foo”); a.id; Tuesday, November 8, 2011
Properties in the Slow Zone Undefined Property Scripted Getter (Fast on Firefox, Chrome) (Fast on IE) var a = { x: get() { return 1; } }; var a = {}; a.x; a.x; DOM Access (I only tested .id, so take with a grain of salt-- other properties may differ) var a = document.getByElementId(“foo”); a.id; Tuesday, November 8, 2011
Properties in the Slow Zone Undefined Property Scripted Getter (Fast on Firefox, Chrome) (Fast on IE) var a = { x: get() { return 1; } }; var a = {}; a.x; a.x; DOM Access Scripted Setter (I only tested .id, so take with a grain of salt-- var a = { x: set(y) { this.x_ = y; } }; other properties may differ) a.x = 1; var a = document.getByElementId(“foo”); a.id; Tuesday, November 8, 2011
The Typed JIT Compiler Firefox 3.5+ (Tracemonkey, JM+TI) Chrome 11+ (Crankshaft) Tuesday, November 8, 2011
Types FTW! If only JavaScript had type declarations... Tuesday, November 8, 2011
Types FTW! If only JavaScript had type declarations... ➡ The JIT would know the type of every local variable Tuesday, November 8, 2011
Types FTW! If only JavaScript had type declarations... ➡ The JIT would know the type of every local variable ➡ Know exactly what action to use (no type checks) Tuesday, November 8, 2011
Types FTW! If only JavaScript had type declarations... ➡ The JIT would know the type of every local variable ➡ Know exactly what action to use (no type checks) ➡ Local variables don’t need to be boxed (or unboxed) Tuesday, November 8, 2011
Types FTW! If only JavaScript had type declarations... ➡ The JIT would know the type of every local variable ➡ Know exactly what action to use (no type checks) ➡ Local variables don’t need to be boxed (or unboxed) I call this kind of JIT a typed compiler Tuesday, November 8, 2011
But JS doesn’t have types Tuesday, November 8, 2011
But JS doesn’t have types • Problem: JS doesn’t have type declarations Tuesday, November 8, 2011
But JS doesn’t have types • Problem: JS doesn’t have type declarations • Solution: run the program for a bit, monitor types • Bonus points: use static analysis to infer more types Tuesday, November 8, 2011
But JS doesn’t have types • Problem: JS doesn’t have type declarations • Solution: run the program for a bit, monitor types • Bonus points: use static analysis to infer more types • Then recompile optimized for those types Tuesday, November 8, 2011
Recommend
More recommend