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

V8 internals for JavaScript developers

V8 internals for JavaScript developers

Google Experts Summit 2017

Mathias Bynens

September 04, 2017
Tweet

More Decks by Mathias Bynens

Other Decks in Technology

Transcript

  1. View Slide

  2. V8 internals
    for JavaScript developers
    @mathias

    View Slide

  3. Elements kinds
    in V8

    View Slide

  4. const array = [1, 2, 3];

    View Slide

  5. const array = [1, 2, 3];
    // elements kind: PACKED_SMI_ELEMENTS

    View Slide

  6. const array = [1, 2, 3];
    // elements kind: PACKED_SMI_ELEMENTS
    array.push(4.56);

    View Slide

  7. const array = [1, 2, 3];
    // elements kind: PACKED_SMI_ELEMENTS
    array.push(4.56);
    // elements kind: PACKED_DOUBLE_ELEMENTS

    View Slide

  8. const array = [1, 2, 3];
    // elements kind: PACKED_SMI_ELEMENTS
    array.push(4.56);
    // elements kind: PACKED_DOUBLE_ELEMENTS
    array.push('x');

    View Slide

  9. const array = [1, 2, 3];
    // elements kind: PACKED_SMI_ELEMENTS
    array.push(4.56);
    // elements kind: PACKED_DOUBLE_ELEMENTS
    array.push('x');
    // elements kind: PACKED_ELEMENTS

    View Slide

  10. Smi
    Doubles
    Regular elements
    Elements kinds

    View Slide

  11. const array = [1, 2, 3];
    // elements kind: PACKED_SMI_ELEMENTS
    array.push(4.56);
    // elements kind: PACKED_DOUBLE_ELEMENTS
    array.push('x');
    // elements kind: PACKED_ELEMENTS

    View Slide

  12. array.length; // 5
    index 0 1 2 3 4
    value 1 2 3 4.56 'x'

    View Slide

  13. array.length; // 5
    array[9] = 1;
    // array[5] until array[8] are now holes
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  14. array.length; // 5
    array[9] = 1;
    // array[5] until array[8] are now holes
    // elements kind: HOLEY_ELEMENTS
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  15. array[8];
    // → ???
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  16. array[8];
    // → ??? ❌
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  17. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  18. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  19. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '8');
    // → false
    index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1

    View Slide

  20. index 0 1 2 3 4 5 6 7 8 9
    value 1 2 3 4.56 'x' 1
    array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '8');
    // → false ❌

    View Slide

  21. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '8');
    // → false ❌
    hasOwnProperty(Array.prototype, '8');
    // → false

    View Slide

  22. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '8');
    // → false ❌
    hasOwnProperty(Array.prototype, '8');
    // → false ❌

    View Slide

  23. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '8');
    // → false ❌
    hasOwnProperty(Array.prototype, '8');
    // → false ❌
    hasOwnProperty(Object.prototype, '8');
    // → false

    View Slide

  24. array[8];
    // → ??? ❌
    8 >= 0 && 8 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '8');
    // → false ❌
    hasOwnProperty(Array.prototype, '8');
    // → false ❌
    hasOwnProperty(Object.prototype, '8');
    // → false ✅

    View Slide

  25. array[8];
    // → undefined ✅
    8 >= 0 && 8 < array.length; // bounds check
    // → true
    hasOwnProperty(array, '8');
    // → false
    hasOwnProperty(Array.prototype, '8');
    // → false
    hasOwnProperty(Object.prototype, '8');
    // → false ✅

    View Slide

  26. packedArray[8];
    // → undefined ✅
    8 >= 0 && 8 < packedArray.length; // bounds check
    // → true ✅
    hasOwnProperty(packedArray, '8');
    // → true ✅
    hasOwnProperty(Array.prototype, '8');
    // → false ✅
    hasOwnProperty(Object.prototype, '8');
    // → false ✅

    View Slide

  27. packedArray[8];
    // → undefined ✅
    8 >= 0 && 8 < packedArray.length; // bounds check
    // → true ✅
    hasOwnProperty(packedArray, '8');
    // → true ✅
    hasOwnProperty(Array.prototype, '8');
    // → false ✅
    hasOwnProperty(Object.prototype, '8');
    // → false ✅

    View Slide

  28. array[0];
    // → ???

    View Slide

  29. array[0];
    // → ??? ❌

    View Slide

  30. array[0];
    // → ??? ❌
    0 >= 0 && 0 < array.length; // bounds check
    // → true

    View Slide

  31. array[0];
    // → ??? ❌
    0 >= 0 && 0 < array.length; // bounds check
    // → true ❌

    View Slide

  32. array[0];
    // → ??? ❌
    0 >= 0 && 0 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '0');
    // → true

    View Slide

  33. array[0];
    // → ??? ❌
    0 >= 0 && 0 < array.length; // bounds check
    // → true ❌
    hasOwnProperty(array, '0');
    // → true ✅

    View Slide

  34. array[0];
    // → 1 ✅
    0 >= 0 && 0 < array.length; // bounds check
    // → true
    hasOwnProperty(array, '0');
    // → true ✅

    View Slide

  35. PACKED > HOLEY

    View Slide

  36. PACKED > HOLEY

    View Slide

  37. Smi
    Doubles
    Regular elements
    Elements kinds

    View Slide

  38. Smi,
    packed
    Doubles, packed
    Regular elements, packed
    Smi,
    holey
    Doubles, holey
    Regular elements, holey

    View Slide

  39. lattice

    View Slide

  40. PACKED_SMI_ELEMENTS
    HOLEY_SMI_ELEMENTS
    PACKED_DOUBLE_ELEMENTS
    HOLEY_DOUBLE_ELEMENTS
    PACKED_ELEMENTS
    HOLEY_ELEMENTS

    View Slide

  41. const array = new Array(3);

    View Slide

  42. const array = new Array(3); index 0 1 2
    value

    View Slide

  43. const array = new Array(3);
    // HOLEY_SMI_ELEMENTS
    index 0 1 2
    value

    View Slide

  44. const array = new Array(3);
    // HOLEY_SMI_ELEMENTS
    array[0] = 'a';
    index 0 1 2
    value 'a'

    View Slide

  45. const array = new Array(3);
    // HOLEY_SMI_ELEMENTS
    array[0] = 'a';
    // HOLEY_ELEMENTS
    index 0 1 2
    value 'a'

    View Slide

  46. const array = new Array(3);
    // HOLEY_SMI_ELEMENTS
    array[0] = 'a';
    // HOLEY_ELEMENTS
    array[1] = 'b';
    index 0 1 2
    value 'a' 'b'

    View Slide

  47. const array = new Array(3);
    // HOLEY_SMI_ELEMENTS
    array[0] = 'a';
    // HOLEY_ELEMENTS
    array[1] = 'b';
    array[2] = 'c';
    index 0 1 2
    value 'a' 'b' 'c'
    now packed!

    View Slide

  48. const array = new Array(3);
    // HOLEY_SMI_ELEMENTS
    array[0] = 'a';
    // HOLEY_ELEMENTS
    array[1] = 'b';
    array[2] = 'c';
    // HOLEY_ELEMENTS (still!)
    now packed!
    but it’s too late
    index 0 1 2
    value 'a' 'b' 'c'

    View Slide

  49. const array = ['a', 'b', 'c'];
    // elements kind: PACKED_ELEMENTS

    View Slide

  50. const array = ['a', 'b', 'c'];
    // elements kind: PACKED_ELEMENTS
    // …
    array.push(someValue);
    array.push(someOtherValue);

    View Slide

  51. Avoid holes!
    #ProTip
    Avoid holes

    View Slide

  52. for (let i = 0, item; (item = items[i]) != null; i++) {
    doSomething(item);
    }

    View Slide

  53. for (let i = 0, item; (item = items[i]) != null; i++) {
    doSomething(item);
    }

    View Slide

  54. for (let i = 0, item; (item = items[i]) != null; i++) {
    doSomething(item);
    }
    for (let index = 0; index < items.length; index++) {
    doSomething(item);
    }

    View Slide

  55. for (const item of items) {
    doSomething(item);
    }

    View Slide

  56. Avoid holes!
    #ProTip
    Avoid out-of-bounds reads

    View Slide

  57. [3, 2, 1, +0];
    // PACKED_SMI_ELEMENTS

    View Slide

  58. [3, 2, 1, +0];
    // PACKED_SMI_ELEMENTS
    [3, 2, 1, -0];
    // PACKED_DOUBLE_ELEMENTS

    View Slide

  59. [3, 2, 1, +0];
    // PACKED_SMI_ELEMENTS
    [3, 2, 1, -0];
    // PACKED_DOUBLE_ELEMENTS
    [3, 2, 1, NaN, Infinity];
    // PACKED_DOUBLE_ELEMENTS

    View Slide

  60. Avoid holes!
    #ProTip
    Avoid elements kind transitions

    View Slide

  61. const arrayLike = {};
    arrayLike[0] = 'a';
    arrayLike[1] = 'b';
    arrayLike[2] = 'c';
    arrayLike.length = 3;

    View Slide

  62. Array.prototype.forEach.call(arrayLike, (value, index) => {
    console.log(`${ index }: ${ value }`);
    });
    // This logs '0: a', then '1: b', and finally '2: c'.

    View Slide

  63. const actualArray = Array.prototype.slice.call(arrayLike, 0);
    actualArray.forEach((value, index) => {
    console.log(`${ index }: ${ value }`);
    });
    // This logs '0: a', then '1: b', and finally '2: c'.

    View Slide

  64. const logArgs = function() {
    Array.prototype.forEach.call(arguments, (value, index) => {
    console.log(`${ index }: ${ value }`);
    });
    };
    logArgs('a', 'b', 'c');
    // This logs '0: a', then '1: b', and finally '2: c'.

    View Slide

  65. const logArgs = (...args) => {
    args.forEach((value, index) => {
    console.log(`${ index }: ${ value }`);
    });
    };
    logArgs('a', 'b', 'c');
    // This logs '0: a', then '1: b', and finally '2: c'.

    View Slide

  66. Avoid holes!
    #ProTip
    Prefer arrays over array-like objects

    View Slide

  67. $

    View Slide

  68. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8

    View Slide

  69. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax

    View Slide

  70. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax
    V8 version 6.2.0 (candidate)
    d8>

    View Slide

  71. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax
    V8 version 6.2.0 (candidate)
    d8> const array = [1, 2, 3];

    View Slide

  72. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax
    V8 version 6.2.0 (candidate)
    d8> const array = [1, 2, 3]; %DebugPrint(array);

    View Slide

  73. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax
    V8 version 6.2.0 (candidate)
    d8> const array = [1, 2, 3]; %DebugPrint(array);
    DebugPrint: 0x313389e0e551: [JSArray]
    - map = 0x3133e0582889 [FastProperties]
    - prototype = 0x313360387f81
    - elements = 0x313389e0e4c9 [PACKED_SMI_ELEMENTS (COW)]
    - length = 3
    - properties = 0x3133dae02241 {
    #length: 0x31336c242839 (const accessor descriptor)
    }

    View Slide

  74. $ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax
    V8 version 6.2.0 (candidate)
    d8> const array = [1, 2, 3]; %DebugPrint(array);
    DebugPrint: 0x313389e0e551: [JSArray]
    - map = 0x3133e0582889 [FastProperties]
    - prototype = 0x313360387f81
    - elements = 0x313389e0e4c9 [PACKED_SMI_ELEMENTS (COW)]
    - length = 3
    - properties = 0x3133dae02241 {
    #length: 0x31336c242839 (const accessor descriptor)
    }

    View Slide

  75. View Slide

  76. Avoid holes.
    — J.K. Rowling

    View Slide

  77. Avoid holes. Avoid out-of-bounds reads.
    — ancient Chinese proverb

    View Slide

  78. Avoid holes. Avoid out-of-bounds reads.
    Avoid elements kind transitions.
    — Justin Bieber

    View Slide

  79. Avoid holes. Avoid out-of-bounds reads.
    Avoid elements kind transitions. Prefer
    arrays over array-like objects.
    — Albert Einstein

    View Slide

  80. Avoid holes. Avoid out-of-bounds reads.
    Avoid elements kind transitions. Prefer
    arrays over array-like objects. Eat your
    vegetables.
    — this slide, just now

    View Slide

  81. Thank you!
    @mathias

    View Slide