know your engines
play

Know Your Engines How to Make Your JavaScript Fast Dave Mandelin 8 - PowerPoint PPT Presentation

Know Your Engines How to Make Your JavaScript Fast Dave Mandelin 8 November 2011 OReilly Velocity Europe Tuesday, November 8, 2011 JavaScript is getting really fast and programs are getting crazy Bullet physics engine (ammo.js) H.264


  1. 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

  2. Choosing the action in the JIT Tuesday, November 8, 2011

  3. Choosing the action in the JIT • Many cases for operators like + Tuesday, November 8, 2011

  4. 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

  5. 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

  6. 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

  7. Object Properties function f(obj) { return obj.a + 1; } Tuesday, November 8, 2011

  8. Object Properties function f(obj) { return obj.a + 1; } • Need to search obj for a property named a slow Tuesday, November 8, 2011

  9. 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

  10. 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

  11. ICs: a mini-JIT for objects All Major Browsers Tuesday, November 8, 2011

  12. ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) Tuesday, November 8, 2011

  13. ICs: a mini-JIT for objects All Major Browsers • Properties become fast with inline caching (we prefer IC ) • Basic plan: Tuesday, November 8, 2011

  14. 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

  15. 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

  16. 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

  17. 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

  18. 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

  19. 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

  20. 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

  21. 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

  22. 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

  23. 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

  24. 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

  25. 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

  26. 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

  27. These are fast because of ICs Global Variable Access var q = 4; var r; function f(obj) { r = q; } Tuesday, November 8, 2011

  28. 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

  29. 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

  30. 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

  31. 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

  32. 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

  33. 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

  34. 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

  35. 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

  36. 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

  37. 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

  38. 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

  39. 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

  40. 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

  41. 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

  42. 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

  43. 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

  44. 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

  45. 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

  46. 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

  47. 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

  48. Properties in the Slow Zone Tuesday, November 8, 2011

  49. Properties in the Slow Zone Undefined Property (Fast on Firefox, Chrome) var a = {}; a.x; Tuesday, November 8, 2011

  50. 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

  51. 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

  52. 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

  53. The Typed JIT Compiler Firefox 3.5+ (Tracemonkey, JM+TI) Chrome 11+ (Crankshaft) Tuesday, November 8, 2011

  54. Types FTW! If only JavaScript had type declarations... Tuesday, November 8, 2011

  55. Types FTW! If only JavaScript had type declarations... ➡ The JIT would know the type of every local variable Tuesday, November 8, 2011

  56. 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

  57. 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

  58. 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

  59. But JS doesn’t have types Tuesday, November 8, 2011

  60. But JS doesn’t have types • Problem: JS doesn’t have type declarations Tuesday, November 8, 2011

  61. 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

  62. 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