Upgrade to Pro — share decks privately, control downloads, hide ads and more …

When Bits Hit the TurboFan

Yarden Laifenfeld
June 23, 2024
130

When Bits Hit the TurboFan

Yarden Laifenfeld

June 23, 2024
Tweet

Transcript

  1. • Software Engineer & Dev Advocate at Dynatrace • Interested

    in compilers • And everything else software internals • Also debuggers Who Am I
  2. v8’s Parts (Pre-2021) • Parser - creates AST • Ignition

    - JavaScript interpreter • TurboFan - JavaScript bytecode compiler
  3. v8’s Parts - Parser function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } esprima.org
  4. v8’s Parts - Parser function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } esprima.org add
  5. v8’s Parts - Parser function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } esprima.org add params
  6. v8’s Parts - Parser function add(a, b) { return a

    + b; } "params": [ { "type": "Identifier", "name": "a" }, { "type": "Identifier", "name": "b" } ], esprima.org add a b params
  7. v8’s Parts - Parser function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } esprima.org add a b params body
  8. v8’s Parts - Parser function add(a, b) { return a

    + b; } "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Identifier", "name": "a" }, "right": { "type": "Identifier", "name": "b" esprima.org add a b params body
  9. v8’s Parts - Parser function add(a, b) { return a

    + b; } "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Identifier", "name": "a" }, "right": { "type": "Identifier", "name": "b" esprima.org add a b params body return
  10. v8’s Parts - Parser function add(a, b) { return a

    + b; } "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Identifier", "name": "a" }, "right": { "type": "Identifier", "name": "b" esprima.org add a b params body return +
  11. v8’s Parts - Parser function add(a, b) { return a

    + b; } "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Identifier", "name": "a" }, "right": { "type": "Identifier", "name": "b" esprima.org add a b params body return + a
  12. v8’s Parts - Parser function add(a, b) { return a

    + b; } "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Identifier", "name": "a" }, "right": { "type": "Identifier", "name": "b" esprima.org add a b params body return + a b
  13. v8’s Parts (Pre-2021) • Parser - creates AST • Ignition

    - JavaScript interpreter • TurboFan - JavaScript bytecode compiler
  14. v8’s Parts - Ignition function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } Ldar a1 Add a0, [0] Return node --print-bytecode
  15. v8’s Parts - Ignition function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } Ldar a1 Add a0, [0] Return b node --print-bytecode
  16. v8’s Parts - Ignition function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } Ldar a1 Add a0, [0] Return b a, b node --print-bytecode
  17. Intermediate Representation (IR) • Data structure or code • Used

    by a compiler • Represents source code accurately • Better for optimization or translation
  18. v8’s Parts - Ignition function add(a, b) { return a

    + b; } { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [...], "body": {...}, "generator": false, "expression": false, "async": false } ], "sourceType": "script" } Ldar a1 Add a0, [0] Return b a, b node --print-bytecode
  19. v8’s Parts - Ignition • JavaScript “interpreter” • Maybe a

    compiler? • Also a virtual machine • A fast way to execute code slowly
  20. A Slow Way to Execute Code Fastly • CrankShaft ->

    TurboFan • Input: JavaScript bytecode Output: machine code • Optimize the code! ◦ Not all code
  21. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; }
  22. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2)
  23. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2) add(1, 2)
  24. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2) add(1, 2) add(1, 2)
  25. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2) add(1, 2) add(1, 2) add(1, 2) optimization - a, b are Numbers
  26. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2) add(1, 2) add(1, 2) add(1, 2) add(1, 2) optimization - a, b are Numbers
  27. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2) add(1, 2) add(1, 2) add(1, 2) add(1, 2) add(1, 2) optimization - a, b are Numbers
  28. TurboFan • Optimistic assumptions ◦ Type feedback from Ignition •

    Wrong assumptions lead to deoptimization function add(a, b) { return a + b; } add(1, 2) add(1, 2) add(1, 2) add(1, 2) add(1, 2) add(1, 2) add(“abc”, “def”) optimization - a, b are Numbers deoptimization
  29. TurboFan - Sea of Nodes A sea of nodes is

    a graph representation of single-static assignment (SSA) representation of a program that combines data flow and control flow, and relaxes the control flow from a total order to a partial order, keeping only the orderings required by data flow.
  30. 01| let a = 1; 02| console.log(a); 03| a =

    2; 04| console.log(a); Single-Static Assignment (SSA)
  31. 01| let a0 = 1; 02| console.log(a0); 03| a1 =

    2; 04| console.log(a1); Single-Static Assignment (SSA)
  32. 01| let a = 1; 02| let b = a

    + 1; ... 04| let c = a + 1; Single-Static Assignment (SSA)
  33. 01| let a = 1; 02| let b = a

    + 1; 03| // Do nothing 04| let c = a + 1; Single-Static Assignment (SSA) 01| let a = 1; 02| let b = a + 1; 03| a = 2; 04| let c = a + 1;
  34. 01| let a0 = 1; 02| let b0 = a0

    + 1; 03| // Do nothing 04| let c0 = a0 + 1; Single-Static Assignment (SSA) 01| let a = 1; 02| let b = a + 1; 03| a = 2; 04| let c = a + 1;
  35. 01| let a0 = 1; 02| let b0 = a0

    + 1; 03| // Do nothing 04| let c0 = a0 + 1; Single-Static Assignment (SSA) 01| let a = 1; 02| let b = a + 1; 03| a = 2; 04| let c = a + 1; ✔ c0 = b0
  36. 01| let a0 = 1; 02| let b0 = a0

    + 1; 03| // Do nothing 04| let c0 = a0 + 1; Single-Static Assignment (SSA) 01| let a0 = 1; 02| let b0 = a0 + 1; 03| a1 = 2; 04| let c0 = a1 + 1; ✔ c0 = b0
  37. 01| let a0 = 1; 02| let b0 = a0

    + 1; 03| // Do nothing 04| let c0 = a0 + 1; Single-Static Assignment (SSA) 01| let a0 = 1; 02| let b0 = a0 + 1; 03| a1 = 2; 04| let c0 = a1 + 1; ✔ c0 = b0 ✘ c0 ≠ b0
  38. 01| if (a > 3) { 02| a = 2;

    03| } else { 04| a = 4; 05| } 06| console.log(a); Single-Static Assignment (SSA)
  39. 01| if (a0 > 3) { 02| a = 2;

    03| } else { 04| a = 4; 05| } 06| console.log(a); Single-Static Assignment (SSA)
  40. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a = 4; 05| } 06| console.log(a); Single-Static Assignment (SSA)
  41. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a); Single-Static Assignment (SSA)
  42. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA)
  43. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA)
  44. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA)
  45. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA) a0 > 3
  46. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA) a0 > 3 a1 = 2 true
  47. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA) a2 = 4 a0 > 3 a1 = 2 true false
  48. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA) a2 = 4 a0 > 3 a1 = 2 true false
  49. • Used when different values can be assigned depending on

    which node we came from • Creates a new variable • Specify what the value options are Phi a2 = 4 a0 > 3 a1 = 2 true false a3 = ɸ(a1, a2)
  50. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a?); Single-Static Assignment (SSA) a2 = 4 a0 > 3 a1 = 2 true false a3 = ɸ(a1, a2)
  51. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a3); Single-Static Assignment (SSA) a2 = 4 a0 > 3 a1 = 2 true false a3 = ɸ(a1, a2) console.log(a3)
  52. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a3); Single-Static Assignment (SSA) a2 = 4 a0 > 3 a1 = 2 true false a3 = ɸ(a1, a2) console.log(a3)
  53. 01| if (a0 > 3) { 02| a1 = 2;

    03| } else { 04| a2 = 4; 05| } 06| console.log(a3); Control Flow Graph true false
  54. let a = 5; let b = 3; while (a

    < b) { b -= 1; a += 1; } Control Flow Graph • Basic Blocks ◦ Consecutive instructions • Control dependencies ◦ if, while, for, function, call, return • Doesn’t care about data
  55. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph
  56. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start
  57. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start let sum = 0 let i = 0
  58. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start i < arr.length let sum = 0 let i = 0 true false
  59. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start i < arr.length sum += arr[i] i += 1 let sum = 0 let i = 0 true false
  60. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start i < arr.length sum += arr[i] i += 1 return sum let sum = 0 let i = 0 true false
  61. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start i < arr.length sum += arr[i] i += 1 return sum End let sum = 0 let i = 0 true false
  62. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Control Flow Graph Start End
  63. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Start i < arr.length sum += arr[i] i += 1 return sum End var sum = 0 var i = 0 true false
  64. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i < arr.length sum = sum + arr[i] i = i + 1 return sum End var sum = 0 var i = 0 true false
  65. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i < arr.length sum = sum + arr[i] i = i + 1 return sum End var sum = 0 var i = 0 true false
  66. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i < arr.length sum = sum + arr[i] i = i + 1 return sum End var sum = 0 var i0 = 0 true false
  67. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i < arr.length sum = sum + arr[i] i1 = i + 1 return sum End var sum = 0 var i0 = 0 true false
  68. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i < arr.length return sum End var sum = 0 var i0 = 0 true sum = sum + arr[i] i1 = i + 1 false
  69. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i0 < arr.length return sum End var sum = 0 var i0 = 0 true sum = sum + arr[i] i1 = i1 + 1 false
  70. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i1 < arr.length return sum End var sum = 0 var i0 = 0 true sum = sum + arr[i] i1 = i + 1 false
  71. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i < arr.length return sum End var sum = 0 var i0 = 0 true sum = sum + arr[i] i1 = i + 1 false
  72. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length return sum End var sum = 0 var i0 = 0 true sum = sum + arr[i] i1 = i + 1 false
  73. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum = sum + arr[i] i1 = i + 1 return sum End var sum = 0 var i0 = 0 true false
  74. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum = sum + arr[i] i1 = i + 1 return sum End var sum = 0 var i0 = 0 true false
  75. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum = sum + arr[i2] i1 = i2 + 1 return sum End var sum = 0 var i0 = 0 true false
  76. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  77. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  78. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  79. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  80. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  81. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  82. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  83. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum2 + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  84. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum2 + arr[i2] i1 = i2 + 1 return sum End var sum0 = 0 var i0 = 0 true false
  85. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum2 + arr[i2] i1 = i2 + 1 return sum2 End var sum0 = 0 var i0 = 0 true false
  86. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr.length sum1 = sum2 + arr[i2] i1 = i2 + 1 return sum2 End var sum0 = 0 var i0 = 0 true false
  87. SSA & CFG func calcSum(arr) { let sum = 0;

    let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; } Start sum2 = ɸ(sum0, sum1) i2 =ɸ(i0, i1) i2 < arr0.length sum1 = sum2 + arr0[i2] i1 = i2 + 1 return sum2 End var sum0 = 0 var i0 = 0 true false
  88. 01| let a = 3; 02| let b = a

    * 2; 03| let c = b + a; Data Flow Graph
  89. 01| let a = 3; 02| let b = a

    * 2; 03| let c = b + a; Data Flow Graph * a 2 b
  90. 01| let a = 3; 02| let b = a

    * 2; 03| let c = b + a; Data Flow Graph * + a 2 b a c
  91. func calcSum(arr) { let sum = 0; let i =

    0; while (i < arr.length) { sum += arr[i]; i += 1; } return sum; } Data Flow Graph
  92. while (i < arr.length) { sum += arr[i]; i +=

    1; } Data Flow Graph length arr
  93. while (i < arr.length) { sum += arr[i]; i +=

    1; } Data Flow Graph length arr < i
  94. while (i < arr.length) { sum += arr[i]; i +=

    1; } Data Flow Graph load arr i
  95. while (i < arr.length) { sum += arr[i]; i +=

    1; } Data Flow Graph load arr + sum i sum
  96. while (i < arr.length) { sum += arr[i]; i +=

    1; } + i 1 i Data Flow Graph
  97. while (i < arr.length) { sum += arr[i]; i +=

    1; } Data Flow Graph length arr < i + i 1 i load arr + sum i sum
  98. Sea of Nodes • SSA • CFG • DFG let

    a = 5; let b = 3; while (a < b) { b -= 1; a += 1; }
  99. • SSA • CFG • DFG Sea of Nodes let

    a = 5; let b = 3; while (a < b) { b -= 1; a += 1; }
  100. Sea of Nodes Source: https://darksi.de/d.sea-of-nodes/ arr.length: func calcSum(arr) { let

    sum = 0; let i = 0; while (i < arr.length) { sum = sum + arr[i]; i = i + 1; } return sum; }
  101. Sea of Nodes Source: https://darksi.de/d.sea-of-nodes/ arr.length: func calcSum(arr) { let

    sum = 0; let i = 0; let arrLen = arr.length; while (i < arrLen) { sum = sum + arr[i]; i = i + 1; } return sum;
  102. Sea of Nodes Source: https://darksi.de/d.sea-of-nodes/ • Allows less compiler passes

    • Removes unnecessary dependencies • Not cache-friendly • Slow
  103. • Be consistent with the types you pass to functions

    ◦ Avoids deoptimization • Declare properties in the constructor ◦ Avoids deoptimization • Declare classes in the global scope • Avoid arrays with holes ◦ const arr = [0]; arr[5] = 3; ◦ [ 0, <4 empty items>, 3 ] • Don’t be afraid to use builtins ◦ Array.prototype.forEach() How Can We Help TurboFan?
  104. v8’s Parts (Pre-2021) • Parser - creates AST • Ignition

    - JavaScript interpreter • TurboFan - JavaScript bytecode compiler
  105. v8’s Parts (Pre-2023) • Parser - creates AST • Ignition

    - JavaScript interpreter • Sparkplug - non-optimizing JavaScript bytecode compiler (no IR!) • TurboFan - JavaScript bytecode compiler
  106. v8’s Parts (Now) • Parser - creates AST • Ignition

    - JavaScript interpreter • Sparkplug - non-optimizing JavaScript bytecode compiler (no IR!) • Maglev - simple SSA compiler • TurboFan - JavaScript bytecode compiler
  107. Resources • https://v8.dev/docs - Official documentation, a lot of good

    stuff • https://www.youtube.com/watch?v=cvybnv79Sek - Talk by Benedikt Meurer about TurboFan • https://darksi.de/d.sea-of-nodes/ - Good explanation of Sea of Nodes • https://github.com/pranayga/expl0ring_V8/blob/master/docs/ Turbofan.md - Interesting doc about TurboFan • https://github.com/SeaOfNodes/Simple - Showcase of Sea of Nodes • https://www.youtube.com/watch?v=98lt45Aj8mo&t=1591s - Talk by Cliff Click (creator of Sea of Nodes) on Sea of Nodes