# **Quá trình compile Javascript của V8** ![image](https://hackmd.io/_uploads/rkdZzmfg0.png) - **Parsing** : Phân tích cú pháp mã nguồn để chuyển đổi thành *Abstract Syntax Tree (AST)* - **Ignition** : V8 sử dụng *Ignition* tạo bytecode từ AST - **Optimising Compiler** : V8 sử dụng trình biên dịch ***TurboFan*** để biên dịch sang mã máy, **TurboFan** sử dụng nhiều kỹ thuật để tạo ra mã máy tối ưu nhất có thể - Cuối cùng là giai đoạn thực thi > V8 sử dụng ***Just-in-Time compilation (JIT)*** để biên dịch mã nguồn hoặc mã bytecode thành mã máy trực tiếp trong quá trình chạy của một chương trình, để cải thiện hiệu xuất và giảm thời gian thực thi # **Build bản debug của V8** - Ở task 1 ta đã build phiên bản ```release```, để debug với V8 ta sẽ build V8 với phiên bản ```debug``` sẽ hỗ trợ trong quá trình debug - Để build phiên bản ```debug``` ta cài đặt cấu hình GN và build ``` tools/dev/v8gen.py x64.debug ninja -C out.gn/x64.debug ``` - Tạo mục ```~/.gdbinit``` để thêm extension ```gdbinit``` và ```gdb-v8-support.py``` từ mục tools vào ``` source ~/v8/tools/gdbinit source ~/v8/tools/gdb-v8-support.py ``` > Hoặc có thể trong ```gdb``` mình dùng trực tiếp 2 câu lệnh trên để thêm extension # **Memory structure** ### **Small Integer** - số nguyên nhỏ trong Javascript được ghi rõ nên không cần cấp phát bộ nhớ nên khi debug không có thông tin về memory của biến ```javascript d8> let a = 10 undefined d8> %DebugPrint(a) DebugPrint: Smi: 0xa (10) 10 ``` - Thử lấy một số nguyên lớn ```java d8> %DebugPrint(2**31) DebugPrint: 0x37ee0029a245: [HeapNumber] in OldSpace - map: 0x37ee00000809 <Map[12](HEAP_NUMBER_TYPE)> - value: 2147483648.0 0x37ee00000809: [Map] in ReadOnlySpace - map: 0x37ee000004cd <MetaMap (0x37ee00000085 <null>)> - type: HEAP_NUMBER_TYPE - instance size: 12 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x37ee00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x37ee00000759 <DescriptorArray[0]> - prototype: 0x37ee00000085 <null> - constructor: 0x37ee00000085 <null> - dependent code: 0x37ee00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 2147483648 ``` - Số nguyên lớn thuộc kiểu ```HeapNumber``` vì số lớn hơn số biểu diễn của 31 bit nên sẽ được biểu diễn dạng số thực ### **Double value**: - giá trị số thực được cấp phát bộ nhớ và nằm ở ```0x2c3a00299b15```, thuộc kiểu ```HeapNumber``` nằm ở ```Oldspace``` > - ```Oldspace``` là vùng bộ nhớ ở heap để lưu trữ các dữ liệu đã tồn tại lâu và không được giải phóng > - ```HeapNumber``` là đối tượng để biểu diễn số thực ```java d8> a = 3.14 3.14 d8> %DebugPrint(a) DebugPrint: 0xcbb00299d09: [HeapNumber] in OldSpace - map: 0x0cbb00000809 <Map[12](HEAP_NUMBER_TYPE)> - value: 3.14 0xcbb00000809: [Map] in ReadOnlySpace - map: 0x0cbb000004cd <MetaMap (0x0cbb00000085 <null>)> - type: HEAP_NUMBER_TYPE - instance size: 12 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb00000085 <null> - constructor: 0x0cbb00000085 <null> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 3.14 ``` ```bash pwndbg> x/10gx 0xcbb00299d09-5 0xcbb00299d04: 0x0000080900000010 0x40091eb851eb851f 0xcbb00299d14: 0x004018000000117d 0x0000000000000000 0xcbb00299d24: 0x00000002000008d1 0x0000000100000000 0xcbb00299d34: 0x0000072500281e91 0x0020a60100000725 0xcbb00299d44: 0x0028172900299cb9 0x0000074100299d55 ``` - Vì là số thực nên khi biểu diễn trên máy tính sẽ chuyển đổi theo chuẩn ```IEEE 754```, ```3.14``` sẽ được biểu diễn là ```0x40091eb851eb851f``` ### **String** : - địa chỉ của string là ```0xcbb00298d99``` và cũng được lưu trữ ở ```Oldspace``` và có kích thước không xác định vì chuỗi có thể thay đổi ```java d8> a = "Hello World" "Hello World" d8> %DebugPrint(a) DebugPrint: 0xcbb00298d99: [String] in OldSpace: #Hello World 0xcbb000003dd: [Map] in ReadOnlySpace - map: 0x0cbb000004cd <MetaMap (0x0cbb00000085 <null>)> - type: INTERNALIZED_ONE_BYTE_STRING_TYPE - instance size: variable - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - non-extensible - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb00000085 <null> - constructor: 0x0cbb00000085 <null> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 "Hello World" ``` - Ta dùng gdb để xem chuỗi đang lưu trữ trong bộ nhớ ```bash pwndbg> x/10gx 0xcbb00298d99 0xcbb00298d99: 0x0be901b432000003 0x6f6c6c6548000000 0xcbb00298da9: 0xe500646c726f5720 0xbf00000002000005 0xcbb00298db9: 0x0000000d3900298d 0xedfffffffe004000 0xcbb00298dc9: 0x5100298e1d00298d 0x000001000000298d 0xcbb00298dd9: 0x0008001000000200 0x000000032a000000 pwndbg> x/s 0xcbb00298d99+0xb 0xcbb00298da4: "Hello World" ``` ### **Array** : - Địa chỉ của array là ```0x37ee0004a8d9```, ```lenght``` cho biết độ dài array là 3, phần ```elements``` cho biết các phần tử được lưu trữ ở đâu, phần tử 0 và 1 là một smi nên được lưu trữ trực tiếp còn phần tử thứ 2 là một chuỗi nên cần một bộ nhớ để lưu trữ ```java d8> a = [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] d8> %DebugPrint(a) DebugPrint: 0xcbb0004a8f1: [JSArray] - map: 0x0cbb0028c629 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties] - prototype: 0x0cbb0028c89d <JSArray[0]> - elements: 0x0cbb00299e8d <FixedArray[5]> [PACKED_SMI_ELEMENTS (COW)] - length: 5 - properties: 0x0cbb00000725 <FixedArray[0]> - All own properties (excluding elements): { 0xcbb00000d99: [String] in ReadOnlySpace: #length: 0x0cbb00270811 <AccessorInfo name= 0x0cbb00000d99 <String[6]: #length>, data= 0x0cbb00000069 <undefined>> (const accessor descriptor), location: descriptor } - elements: 0x0cbb00299e8d <FixedArray[5]> { 0: 1 1: 2 2: 3 3: 4 4: 5 } 0xcbb0028c629: [Map] in OldSpace - map: 0x0cbb002816d9 <MetaMap (0x0cbb00281729 <NativeContext[291]>)> - type: JS_ARRAY_TYPE - instance size: 16 - inobject properties: 0 - unused property fields: 0 - elements kind: PACKED_SMI_ELEMENTS - enum length: invalid - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0x0cbb00000a89 <Cell value= 1> - instance descriptors #1: 0x0cbb0028ceb5 <DescriptorArray[1]> - transitions #1: 0x0cbb0028ced1 <TransitionArray[4]>Transition array #1: 0x0cbb00000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_SMI_ELEMENTS) -> 0x0cbb0028cee9 <Map[16](HOLEY_SMI_ELEMENTS)> - prototype: 0x0cbb0028c89d <JSArray[0]> - constructor: 0x0cbb0028c595 <JSFunction Array (sfi = 0xcbb00275b81)> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 [1, 2, 3, 4, 5] ``` ```bash pwndbg> x/20gx 0x0cbb00299e8d-5 0xcbb00299e88: 0x0000065d00000026 0x000000020000000a 0xcbb00299e98: 0x0000000600000004 0x0000000a00000008 0xcbb00299ea8: 0x00000000000010b5 0x0000117d00299e8d 0xcbb00299eb8: 0x0000000000401a00 0x000008d100000000 0xcbb00299ec8: 0x0000000000000003 0x00281e9100000033 0xcbb00299ed8: 0x0000072500000725 0x00299e3d0020a601 0xcbb00299ee8: 0x00299ef500281729 0x00000b3100000741 0xcbb00299ef8: 0x00000062000020cd 0x0000072500281e91 0xcbb00299f08: 0x0020a60100000725 0x00281729002999e1 0xcbb00299f18: 0x0000074100299f21 0x000020cd00000b31 ``` - V8 sử dụng kĩ thuật ```pointer tagging``` nghĩa là sẽ lấy bit có trọng số nhỏ nhất của Smi để đánh dấu còn 31bit còn lại để biểu diễn giá trị, còn con trỏ heap sẽ lấy bit có trọng số thứ 2 để đánh dấu con trỏ mạnh hay yếu - Trong array này chứa Smi nên các giá trị của nó sẽ bị dịch sang trái 1 bit có nghĩa là giá trị sẽ nhân 2, ### **Arraybuffer**: ```java d8> a = new ArrayBuffer(16) [object ArrayBuffer] d8> %DebugPrint(a) DebugPrint: 0xcbb0004b8d1: [JSArrayBuffer] - map: 0x0cbb00289f39 <Map[68](HOLEY_ELEMENTS)> [FastProperties] - prototype: 0x0cbb0028a00d <Object map = 0xcbb00297809> - elements: 0x0cbb00000725 <FixedArray[0]> [HOLEY_ELEMENTS] - embedder fields: 2 - cpp_heap_wrappable: 0 - backing_store: 0xcbc00000000 - byte_length: 16 - max_byte_length: 16 - detach key: 0x0cbb00000069 <undefined> - detachable - properties: 0x0cbb00000725 <FixedArray[0]> - All own properties (excluding elements): {} - embedder fields = { 0, aligned pointer: (nil) 0, aligned pointer: (nil) } 0xcbb00289f39: [Map] in OldSpace - map: 0x0cbb002816d9 <MetaMap (0x0cbb00281729 <NativeContext[291]>)> - type: JS_ARRAY_BUFFER_TYPE - instance size: 68 - inobject properties: 0 - unused property fields: 0 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0x0cbb00000a89 <Cell value= 1> - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb0028a00d <Object map = 0xcbb00297809> - constructor: 0x0cbb00289ee9 <JSFunction ArrayBuffer (sfi = 0xcbb0027a081)> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 [object ArrayBuffer] ``` - ```backing_store: 0xcbc00000000``` là địa chỉ thực để lưu dữ liệu đầu tiên ```bash pwndbg> x/20gx 0xcbc00000000 0xcbc00000000: 0x0000000000000000 0x0000000000000000 0xcbc00000010: 0x0000000000000000 0x0000000000000000 0xcbc00000020: 0x0000000000000000 0x0000000000000000 0xcbc00000030: 0x0000000000000000 0x0000000000000000 0xcbc00000040: 0x0000000000000000 0x0000000000000000 0xcbc00000050: 0x0000000000000000 0x0000000000000000 0xcbc00000060: 0x0000000000000000 0x0000000000000000 0xcbc00000070: 0x0000000000000000 0x0000000000000000 0xcbc00000080: 0x0000000000000000 0x0000000000000000 0xcbc00000090: 0x0000000000000000 0x0000000000000000 ``` ### **Pointer**: - V8 sử dụng ```Pointer Compression``` để đưa con trỏ về 32 bit với bit có trọng số nhỏ nhất là 1, nên khi cần địa chỉ thực ta cần trừ đi 1 và cộng với địa chỉ base ### **Special value**: #### undefined: ```javascript d8> var e undefined d8> %DebugPrint(e) DebugPrint: 0xcbb00000069: [Oddball] in ReadOnlySpace: #undefined 0xcbb000004f5: [Map] in ReadOnlySpace - map: 0x0cbb000004cd <MetaMap (0x0cbb00000085 <null>)> - type: ODDBALL_TYPE - instance size: 28 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - undetectable - non-extensible - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb00000085 <null> - constructor: 0x0cbb00000085 <null> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 undefined ``` ```bash pwndbg> x/gx 0xcbb00000069 0xcbb00000069: 0x0000000000000004 ``` #### Null ```javascript d8> a = null null d8> %DebugPrint(a) DebugPrint: 0xcbb00000085: [Oddball] in ReadOnlySpace: #null 0xcbb0000051d: [Map] in ReadOnlySpace - map: 0x0cbb000004cd <MetaMap (0x0cbb00000085 <null>)> - type: ODDBALL_TYPE - instance size: 28 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - undetectable - non-extensible - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb00000085 <null> - constructor: 0x0cbb00000085 <null> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 null ``` ```bash pwndbg> x/gx 0xcbb00000085 0xcbb00000085: 0x0000000000000005 ``` #### True ```javascript d8> a = true true d8> %DebugPrint(a) DebugPrint: 0xcbb000000c9: [Oddball] in ReadOnlySpace: #true 0xcbb00000545: [Map] in ReadOnlySpace - map: 0x0cbb000004cd <MetaMap (0x0cbb00000085 <null>)> - type: ODDBALL_TYPE - instance size: 28 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - non-extensible - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb00000085 <null> - constructor: 0x0cbb00000085 <null> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 true ``` ``` pwndbg> x/gx 0xcbb000000c9 0xcbb000000c9: 0x0000000000000005 ``` #### False ```javascript d8> a = false false d8> %DebugPrint(a) DebugPrint: 0xcbb000000ad: [Oddball] in ReadOnlySpace: #false 0xcbb00000545: [Map] in ReadOnlySpace - map: 0x0cbb000004cd <MetaMap (0x0cbb00000085 <null>)> - type: ODDBALL_TYPE - instance size: 28 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - non-extensible - back pointer: 0x0cbb00000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x0cbb00000759 <DescriptorArray[0]> - prototype: 0x0cbb00000085 <null> - constructor: 0x0cbb00000085 <null> - dependent code: 0x0cbb00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 false ``` ``` pwndbg> x/gx 0xcbb000000ad 0xcbb000000ad: 0x0000000000000005 ``` ~~Không hiểu tại sao các special value lại có các giá trị này và không hiểu tại sao các địa chỉ thực của data với địa chỉ được in ra ở DebugPrint lại có offset như vậy~~ # **UPDATE** ## Hidden Class - Khi một object được tạo trong Javascript đều có một ***Hidden Class*** riêng để theo dõi cấu trúc các thuộc tính (property) hiện có và vị trí bộ nhớ của chúng. Khi thêm, xóa hay thay đổi thuộc tính thì một ***Hidden Class*** mới được tạo. ***Hidden Class*** giúp tối ưu hóa thời gian truy cập đến một thuộc tính của object ```javascript= d8> let object = {a:"hello", b:"world", c:10, d:true} undefined d8> %DebugPrint(object) DebugPrint: 0x290e0004ae6d: [JS_OBJECT_TYPE] - map: 0x290e0029a0b5 <Map[28](HOLEY_ELEMENTS)> [FastProperties] - prototype: 0x290e002825d9 <Object map = 0x290e00281c15> - elements: 0x290e00000725 <FixedArray[0]> [HOLEY_ELEMENTS] - properties: 0x290e00000725 <FixedArray[0]> - All own properties (excluding elements): { 0x290e00002b19: [String] in ReadOnlySpace: #a: 0x290e00298db1 <String[5]: #hello> (const data field 0), location: in-object 0x290e00002b29: [String] in ReadOnlySpace: #b: 0x290e00299cd1 <String[5]: #world> (const data field 1), location: in-object 0x290e00002b39: [String] in ReadOnlySpace: #c: 10 (const data field 2), location: in-object 0x290e00002b49: [String] in ReadOnlySpace: #d: 0x290e000000c9 <true> (const data field 3), location: in-object } 0x290e0029a0b5: [Map] in OldSpace - map: 0x290e002816d9 <MetaMap (0x290e00281729 <NativeContext[291]>)> - type: JS_OBJECT_TYPE - instance size: 28 - inobject properties: 4 - unused property fields: 0 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x290e0029a08d <Map[28](HOLEY_ELEMENTS)> - prototype_validity cell: 0x290e00000a89 <Cell value= 1> - instance descriptors (own) #4: 0x290e0004af01 <DescriptorArray[4]> - prototype: 0x290e002825d9 <Object map = 0x290e00281c15> - constructor: 0x290e0028211d <JSFunction Object (sfi = 0x290e00275161)> - dependent code: 0x290e00000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 {a: "hello", b: "world", c: 10, d: true} ``` - Khi một object được tạo ta thấy các trường *map*, *prototype*, *elements*, *properties* ### Prototype - Là một tham chiếu đến object khác cho phép object đó có tính kế thừa object hiện tại, có nghĩa là mang thuộc tính và phương thức của object hiện tại. ### Elements - *Elements* là một object, nếu key của thuộc tính thuộc kiểu *Integer* thì sẽ được lưu trữ trong *Elements*, ví dụ trên *Element* không chứa gì vì trong object hiện tại các key không thuộc kiểu *Integer* - ##### Elements kind ```java= d8> var a = [1, 2, 3, 4, 5] undefined d8> %DebugPrint(a) DebugPrint: 0x3201000487bd: [JSArray] - map: 0x32010028c629 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties] - prototype: 0x32010028c89d <JSArray[0]> - elements: 0x320100298e01 <FixedArray[5]> [PACKED_SMI_ELEMENTS (COW)] - length: 5 - properties: 0x320100000725 <FixedArray[0]> - All own properties (excluding elements): { 0x320100000d99: [String] in ReadOnlySpace: #length: 0x320100270811 <AccessorInfo name= 0x320100000d99 <String[6]: #length>, data= 0x320100000069 <undefined>> (const accessor descriptor), location: descriptor } - elements: 0x320100298e01 <FixedArray[5]> { 0: 1 1: 2 2: 3 3: 4 4: 5 } 0x32010028c629: [Map] in OldSpace - map: 0x3201002816d9 <MetaMap (0x320100281729 <NativeContext[291]>)> - type: JS_ARRAY_TYPE - instance size: 16 - inobject properties: 0 - unused property fields: 0 - elements kind: PACKED_SMI_ELEMENTS - enum length: invalid - back pointer: 0x320100000069 <undefined> - prototype_validity cell: 0x320100000a89 <Cell value= 1> - instance descriptors #1: 0x32010028ceb5 <DescriptorArray[1]> - transitions #1: 0x32010028ced1 <TransitionArray[4]>Transition array #1: 0x320100000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_SMI_ELEMENTS) -> 0x32010028cee9 <Map[16](HOLEY_SMI_ELEMENTS)> - prototype: 0x32010028c89d <JSArray[0]> - constructor: 0x32010028c595 <JSFunction Array (sfi = 0x320100275b81)> - dependent code: 0x320100000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 [1, 2, 3, 4, 5] ``` - Vì trong mảng a toàn các smi nên *Elements kind* là ```PACKED_SMI_ELEMENTS``` (ở hàng 26) - Khi ta thêm vào mảng một giá trị *double* ```java= d8> a.push(3.4) 6 d8> %DebugPrint(a) DebugPrint: 0x3201000487bd: [JSArray] - map: 0x32010028cf29 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties] - prototype: 0x32010028c89d <JSArray[0]> - elements: 0x32010004a6cd <FixedDoubleArray[25]> [PACKED_DOUBLE_ELEMENTS] - length: 6 - properties: 0x320100000725 <FixedArray[0]> - All own properties (excluding elements): { 0x320100000d99: [String] in ReadOnlySpace: #length: 0x320100270811 <AccessorInfo name= 0x320100000d99 <String[6]: #length>, data= 0x320100000069 <undefined>> (const accessor descriptor), location: descriptor } - elements: 0x32010004a6cd <FixedDoubleArray[25]> { 0: 1 1: 2 2: 3 3: 4 4: 5 5: 3.4 6-24: <the_hole> } 0x32010028cf29: [Map] in OldSpace - map: 0x3201002816d9 <MetaMap (0x320100281729 <NativeContext[291]>)> - type: JS_ARRAY_TYPE - instance size: 16 - inobject properties: 0 - unused property fields: 0 - elements kind: PACKED_DOUBLE_ELEMENTS - enum length: invalid - back pointer: 0x32010028cee9 <Map[16](HOLEY_SMI_ELEMENTS)> - prototype_validity cell: 0x320100000a89 <Cell value= 1> - instance descriptors #1: 0x32010028ceb5 <DescriptorArray[1]> - transitions #1: 0x32010028cf51 <TransitionArray[4]>Transition array #1: 0x320100000e5d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x32010028cf69 <Map[16](HOLEY_DOUBLE_ELEMENTS)> - prototype: 0x32010028c89d <JSArray[0]> - constructor: 0x32010028c595 <JSFunction Array (sfi = 0x320100275b81)> - dependent code: 0x320100000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 [1, 2, 3, 4, 5, 3.4] ``` - Ta thấy ngay lập tức *Elements kind* của mảng a đổi thành ```PACKED_DOUBLE_ELEMENTS``` - Khi ta thêm vào 1 kí tự thì *Elements kind* đổi thành ```PACKED_ELEMENTS```, ta thấy khi thêm một phần tử khác data type thì *Elements kind* sẽ đổi sang loạt tổng quát hơn để có thể mô tả dữ liệu trong mảng - Khi dữ liệu trong mảng không nối tiếp nhau thì *Elements kind* sẽ đổi sang ```HOLY_ELEMENTS```, ví dụ như mảng trên đang có 6 phần từ từ index 0 đến 5 ta thêm vào mảng a ở index 8 thì trong mảng sẽ chứa các khoảng trống giữa các phần tử - ##### Fast elements và Slow elements - *Fast elements* là biểu diễn dữ liệu trong mảng liền kề nhau không có phần tử trống, phần tử không xác định, truy cập chậm hơn *Slow elements* nhưng tiết kiệm bộ nhớ hơn - *Slow elements* thì ngược lại biểu diễn phần tử các nhau và có khoảng trống giữa các phần tử, truy cập nhanh hơn *Fast elements* nhưng tốn nhiều bộ nhớ hơn ### Properties - Khi số lượng các thuộc tính trong object quá nhiều không thể lưu trữ trong cấu trúc bộ nhớ object sẽ được lưu trữ ở *properties*, vì ví dụ trên số lượng thuộc tính ít nên không có gì lưu trữ ở *properties*. Ở trường **All own properties (excluding elements)** ta thấy được các thuộc tính và *location : in-object* có nghĩa là được lưu trực tiếp trong cấu trúc bộ nhớ của object ### All own properties (excluding elements) - Thông tin các thuộc tính như địa chỉ thuộc tính, địa chỉ các value, giá trị value và nơi lưu trữ thuộc tính đó ### Map - **Map** đại diện cho ***Hidden Class***, **Map** mô tả cấu trúc của object và các thuộc tính của object đó được tổ chức trong bộ nhớ - Đây là một cấu trúc của một **Map** ```javascript 0x36c900298f51: [Map] in OldSpace - map: 0x36c9002816d9 <MetaMap (0x36c900281729 <NativeContext[291]>)> - type: JS_OBJECT_TYPE - instance size: 28 - inobject properties: 4 - unused property fields: 0 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x36c900298f29 <Map[28](HOLEY_ELEMENTS)> - prototype_validity cell: 0x36c900000a89 <Cell value= 1> - instance descriptors (own) #4: 0x36c900048879 <DescriptorArray[4]> - prototype: 0x36c9002825d9 <Object map = 0x36c900281c15> - constructor: 0x36c90028211d <JSFunction Object (sfi = 0x36c900275161)> - dependent code: 0x36c900000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 ``` - Gồm các thông tin như: type, instance size, inobject properties, elements kind, back pointer ... - Mô tả cách hoạt động của **Hidden Class** ở ví dụ trên ![image](https://hackmd.io/_uploads/rksUA3BgC.png) - *Hidden Class* sẽ xây dựng một cấu trúc object từ lúc rỗng đến khi thêm đủ các thuộc tính - Mỗi class trong cấu trúc được gọi là 1 Map - Ta tạo một object sau đó thêm một thuộc tính vào để xem cấu trúc của *Hidden class* - Trong *Hidden Class* có ```DescriptorArray``` và ```TransitionArray``` - ```DescriptorArray``` là danh sách đầy đủ các thuộc tính của các class có cùng thông tin - ```TransitionArray```là một danh sách phản ánh sự thay đổi của đối tượng trong object như thêm, xóa, ... ```javascript= d8> let object = {a:"hello", b:10} undefined d8> %DebugPrint(object) DebugPrint: 0x10a4000487d1: [JS_OBJECT_TYPE] - map: 0x10a400298edd <Map[20](HOLEY_ELEMENTS)> [FastProperties] - prototype: 0x10a4002825d9 <Object map = 0x10a400281c15> - elements: 0x10a400000725 <FixedArray[0]> [HOLEY_ELEMENTS] - properties: 0x10a400000725 <FixedArray[0]> - All own properties (excluding elements): { 0x10a400002b19: [String] in ReadOnlySpace: #a: 0x10a400298d99 <String[5]: #hello> (const data field 0), location: in-object 0x10a400002b29: [String] in ReadOnlySpace: #b: 10 (const data field 1), location: in-object } 0x10a400298edd: [Map] in OldSpace - map: 0x10a4002816d9 <MetaMap (0x10a400281729 <NativeContext[291]>)> - type: JS_OBJECT_TYPE - instance size: 20 - inobject properties: 2 - unused property fields: 0 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x10a400298e95 <Map[20](HOLEY_ELEMENTS)> - prototype_validity cell: 0x10a400000a89 <Cell value= 1> - instance descriptors (own) #2: 0x10a400048801 <DescriptorArray[2]> - prototype: 0x10a4002825d9 <Object map = 0x10a400281c15> - constructor: 0x10a40028211d <JSFunction Object (sfi = 0x10a400275161)> - dependent code: 0x10a400000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 {a: "hello", b: 10} ``` - Khi ta tạo object chứa 2 thuộc tính ```a```, ```b```, ta thấy địa chỉ map là ```0x10a400298edd``` ,các thuộc tính được lưu ở ```in-object``` ```javascript= d8> object.c = "haha" "haha" d8> %DebugPrint(object) DebugPrint: 0x10a4000487d1: [JS_OBJECT_TYPE] - map: 0x10a400299c51 <Map[20](HOLEY_ELEMENTS)> [FastProperties] - prototype: 0x10a4002825d9 <Object map = 0x10a400281c15> - elements: 0x10a400000725 <FixedArray[0]> [HOLEY_ELEMENTS] - properties: 0x10a40004a7a1 <PropertyArray[3]> - All own properties (excluding elements): { 0x10a400002b19: [String] in ReadOnlySpace: #a: 0x10a400298d99 <String[5]: #hello> (const data field 0), location: in-object 0x10a400002b29: [String] in ReadOnlySpace: #b: 10 (const data field 1), location: in-object 0x10a400002b39: [String] in ReadOnlySpace: #c: 0x10a400299b99 <String[4]: #haha> (const data field 2), location: properties[0] } 0x10a400299c51: [Map] in OldSpace - map: 0x10a4002816d9 <MetaMap (0x10a400281729 <NativeContext[291]>)> - type: JS_OBJECT_TYPE - instance size: 20 - inobject properties: 2 - unused property fields: 2 - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x10a400298edd <Map[20](HOLEY_ELEMENTS)> - prototype_validity cell: 0x10a400299c79 <Cell value= 0> - instance descriptors (own) #3: 0x10a40004a76d <DescriptorArray[3]> - prototype: 0x10a4002825d9 <Object map = 0x10a400281c15> - constructor: 0x10a40028211d <JSFunction Object (sfi = 0x10a400275161)> - dependent code: 0x10a400000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 {a: "hello", b: 10, c: "haha"} ``` - Khi ta thêm một thuộc tính thì ta thấy map thay đổi thành ```0x10a400299c51``` và ```back pointer``` trỏ đến class phía trước trùng với pointer trước khi thêm ```0x10a400298edd``` - Ta thấy ```location``` ở ```properties[0]```, và thông tin ở ```properties: 0x10a40004a7a1 <PropertyArray[3]>``` cho ta biết ```properties``` đang lưu trữ thuộc tính. Nhưng vì sao kích thước array là 3, có thể là cơ chế cấp phát bộ nhớ của V8 để có thể tối ưu truy cập??. Ta dùng ```%DebugPrintPtr``` để xem chi tiết thông tin tại pointer đó ```javascript d8> %DebugPrintPtr(0x10a40004a7a1) DebugPrint: 0x10a40004a7a1: [PropertyArray] - map: 0x10a400000999 <Map(PROPERTY_ARRAY_TYPE)> - length: 3 - hash: 0 0: 0x10a400299b99 <String[4]: #haha> 1-2: 0x10a400000069 <undefined> 0x10a400000999: [Map] in ReadOnlySpace - map: 0x10a4000004cd <MetaMap (0x10a400000085 <null>)> - type: PROPERTY_ARRAY_TYPE - instance size: variable - elements kind: HOLEY_ELEMENTS - enum length: invalid - stable_map - back pointer: 0x10a400000069 <undefined> - prototype_validity cell: 0 - instance descriptors (own) #0: 0x10a400000759 <DescriptorArray[0]> - prototype: 0x10a400000085 <null> - constructor: 0x10a400000085 <null> - dependent code: 0x10a400000735 <Other heap object (WEAK_ARRAY_LIST_TYPE)> - construction counter: 0 ``` - Ta thấy thuộc tính ```c``` được lưu trữ trong ```PropertyArray```