0
JavaScript Engines<br />Pop the hood<br />
z = x + y<br />
Executing  z = x + y<br />Read operation from memory<br />Get location of x and y<br />Read values for x and y <br />Unbox...
1. Read operation from memory…<br />String “z = x + y” is passed into tokenizer.<br />Webkit uses Flex (LEX)<br />Accommod...
2. Get locations of x and y<br />X & Y could be number, string, object, null, undefined, array, etc. <br />Offsets directl...
2.  Get values of x – Array<br />If x is a actually array - obj[x]<br />Dense array have offsets<br />Created using 0..N o...
2.  Get values of x – Object<br />If X is an object property (obj.x)<br />Looks up current object or up the prototype chai...
3. Read boxed input …<br />JavaScript variable assignments are un-typed. <br />Assignments stored as boxed inputs<br />x c...
4.  Unbox x and y<br /><ul><li>From box, infer type and value, represent it in native type
Int32 x = 100;
From NunBoxed Values
0x400c 0000 | 0x0000 0000 = not a nan, so double (3.5)
0xFFFF0001 | 0x0000 0040 = Nan space, so Int32 (0x0000 0040)
From NanBoxed Values (0xFFFF80 00000040)
Mask to get pointer, shift to get double
X64 portability, fits in register, but harder to decode</li></li></ul><li>5.  Perform “+” : Interpreter<br /><ul><li>If (t...
result = x <operator> y
If (result overflows), result = float
If (result Nan), result = NaN.
If (typeof x == int32 && typeof y === float)
result = CoarceToFloat(x) + y
Upcoming SlideShare
Loading in...5
×

Understanding Javascript Engines

5,351

Published on

A quick introduction to how Javascript engi

Published in: Technology

Transcript of "Understanding Javascript Engines "

  1. 1. JavaScript Engines<br />Pop the hood<br />
  2. 2. z = x + y<br />
  3. 3. Executing z = x + y<br />Read operation from memory<br />Get location of x and y<br />Read values for x and y <br />Unbox x and y.<br />Choose meaning of “+”, perform “+”<br />Save z to memory<br />Do garbage. <br />
  4. 4. 1. Read operation from memory…<br />String “z = x + y” is passed into tokenizer.<br />Webkit uses Flex (LEX)<br />Accommodate semi colon insertion, etc.<br />Tokenizer output fed to parser <br />Webkit uses Bison, bottom up shift reduce parser<br />Gecko has top down parser<br />Statement now available as Abstract Syntax Tree (AST)<br />
  5. 5. 2. Get locations of x and y<br />X & Y could be number, string, object, null, undefined, array, etc. <br />Offsets directly available for primitives<br />Values also depend on context of execution<br />Closures (activation contexts)<br />Local Variables<br />Object properties<br />Scope modifiers – eval, with, etc.<br />
  6. 6. 2. Get values of x – Array<br />If x is a actually array - obj[x]<br />Dense array have offsets<br />Created using 0..N or push<br />Gecko creates sparse array on N..0<br />Adding obj[“name”] fails optimization<br />
  7. 7. 2. Get values of x – Object<br />If X is an object property (obj.x)<br />Looks up current object or up the prototype chain<br />Inline Cache (IC) the value<br />Objects have shape – {x:1} is different from {x:1,y:2}<br />Webkit stores memory offsets in hidden classes<br />New shape created for every new property.<br />IC can read from prototype without walking tree<br />Closures only save path, still have to walk every time. <br />OpCodes generated for each shape<br />Obj.x ==> read shape1[member1]<br />
  8. 8. 3. Read boxed input …<br />JavaScript variable assignments are un-typed. <br />Assignments stored as boxed inputs<br />x could be (int32 | 100) – indicating type and value<br />Javascript numbers are IEEE-754 floating point.<br />Who cares, just use 32 bit to optimize. <br />Overflow to doubles. <br />Ways to Box values (ref)<br />Tagging the LSBs (ref)<br />Nan Boxing (ref) – 51 bit of NaN space for non-doubles (Webkit)<br />Nun Boxing (favor doubles in NAN – Mozilla pun)<br />
  9. 9. 4. Unbox x and y<br /><ul><li>From box, infer type and value, represent it in native type
  10. 10. Int32 x = 100;
  11. 11. From NunBoxed Values
  12. 12. 0x400c 0000 | 0x0000 0000 = not a nan, so double (3.5)
  13. 13. 0xFFFF0001 | 0x0000 0040 = Nan space, so Int32 (0x0000 0040)
  14. 14. From NanBoxed Values (0xFFFF80 00000040)
  15. 15. Mask to get pointer, shift to get double
  16. 16. X64 portability, fits in register, but harder to decode</li></li></ul><li>5. Perform “+” : Interpreter<br /><ul><li>If (typeof x == int32 && typeof y == int32)
  17. 17. result = x <operator> y
  18. 18. If (result overflows), result = float
  19. 19. If (result Nan), result = NaN.
  20. 20. If (typeof x == int32 && typeof y === float)
  21. 21. result = CoarceToFloat(x) + y
  22. 22. // Same sanity checks
  23. 23. …..
  24. 24. If (typeof x === Object)
  25. 25. …. </li></li></ul><li>5. Perform “+” : Basic JIT<br /><ul><li>If type of x and y are known,
  26. 26. generate opcodes
  27. 27. Fall to opcode when routine is hit.
  28. 28. Save cost of boxing, unboxing.
  29. 29. Determined opcode Paths for each shape
  30. 30. Multiple shapes mean multiple if-else branches
  31. 31. Still have to check for validity/dirtiness of opcpdes
  32. 32. Typical JagerMonkeyJITing</li></li></ul><li>5. Perform “+” : Typed JIT<br /><ul><li>Observe and identify hot code
  33. 33. 70 iterations
  34. 34. Crankshaft – according to profiler
  35. 35. Other heuristics
  36. 36. Execute opcode routine for specific type
  37. 37. Initial compilation cost
  38. 38. OpCodes may be thrown away if types change
  39. 39. Fallback to non-optimized version (Performance fault)
  40. 40. Classic Tracemonkey</li></li></ul><li>5. Perform “+” : Next Gen JIT<br /><ul><li>Static analysis of code to “prove” types
  41. 41. Reduce checks, ensure only one path taken at all times.
  42. 42. Type stable Javascript
  43. 43. IonMonkey Internals.
  44. 44. Use multicore processors
  45. 45. To box/unbox values
  46. 46. To generate compiled opcodes (Chakra)</li></li></ul><li>5. Perform “+” : GPU Enabled<br /><ul><li>Used by WebGL and Canvas render computation routines
  47. 47. Shaders and alpha channel (no direct JS code)
  48. 48. Super fast floating point math
  49. 49. Note that variables is strongly typed as Blobs</li></li></ul><li>5. Perform “+” : Datatypes<br /><ul><li>Strings
  50. 50. Substring is O(1), Concat also optimized
  51. 51. Concat fault on Opera, Chrome
  52. 52. Array
  53. 53. Denser the better
  54. 54. Named property is sparse in FF, IE
  55. 55. Iterate using index, not for:in or functional
  56. 56. Functions
  57. 57. F() faster than f.call(), f.apply().
  58. 58. Using arguments slows down execution</li></li></ul><li>5. Perform “+” : Datatypes<br /><ul><li>Objects
  59. 59. Prototypes are better than closures
  60. 60. Exceptions
  61. 61. Try is mostly free, catch is expensive
  62. 62. May cause optimizer to stop
  63. 63. Eval and With
  64. 64. Cause scope sudden change, prevent JIT</li></li></ul><li>6. Save Z<br /><ul><li>Box “z” and put it on heap if required.
  65. 65. Leave “z” in register if used subsequently
  66. 66. Create shape for “z” if object</li></li></ul><li>7. Garbage Collection<br /><ul><li>Mark and Sweep
  67. 67. Causes GC to pause main routine
  68. 68. Jittery animation, unresponsive UI thread
  69. 69. Incremental GC
  70. 70. Mark and sweep only parts
  71. 71. Generational GC
  72. 72. Separate objects in nursery and tenured areas
  73. 73. Promoting young to old is expensive
  74. 74. Combine Generational and Incremental
  75. 75. Frequent young cleanup, occasional old cleanup</li></li></ul><li>Changes due to ECMA.next<br /><ul><li>Block Scope reduces variable lookups (let, var)
  76. 76. “Yeild” may need to save current context
  77. 77. Blob Data type – boxing/unboxing issues
  78. 78. Classes === Concrete Shapes ?
  79. 79. Syntactic sugar, no impact
  80. 80. Assignment de-structuring
  81. 81. Promises, modules, etc.</li></li></ul><li>Conclusions<br /><ul><li>Don’t write any code
  82. 82. Practice type safety
  83. 83. Leave hot loops alone – don’t create shapes in them
  84. 84. Make arrays dense
  85. 85. Avoid operations that require different type coercion every time.</li></li></ul><li>@nparashuramhttp://nparashuram.com<br />
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×