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. V8 internals
    for JavaScript developers
    @mathias

    View full-size slide

  2. Elements kinds
    in V8

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  8. 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 full-size slide

  9. Smi
    Doubles
    Regular elements
    Elements kinds

    View full-size slide

  10. 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 full-size slide

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

    View full-size slide

  12. 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 full-size slide

  13. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  16. 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 full-size 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 full-size slide

  18. 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 full-size slide

  19. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  22. 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 full-size 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 full-size slide

  24. 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 full-size slide

  25. 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. PACKED > HOLEY

    View full-size slide

  35. PACKED > HOLEY

    View full-size slide

  36. Smi
    Doubles
    Regular elements
    Elements kinds

    View full-size slide

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

    View full-size slide

  38. PACKED_SMI_ELEMENTS
    HOLEY_SMI_ELEMENTS
    PACKED_DOUBLE_ELEMENTS
    HOLEY_DOUBLE_ELEMENTS
    PACKED_ELEMENTS
    HOLEY_ELEMENTS

    View full-size slide

  39. const array = new Array(3);

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  45. 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 full-size slide

  46. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  49. Avoid holes!
    #ProTip
    Avoid holes

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  58. Avoid holes!
    #ProTip
    Avoid elements kind transitions

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  61. 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 full-size slide

  62. 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 full-size slide

  63. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  69. $ 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 full-size slide

  70. $ 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 full-size 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]; %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 full-size slide

  72. Avoid holes.
    — J.K. Rowling

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  76. 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 full-size slide

  77. Thank you!
    @mathias

    View full-size slide