Note: JSObject objects in V8 with the same build structure have the same memory (space) layout.

JavaScript objects are allocated a constant amount of space on the heap (as required) :

  • Pre-allocate (not more than) a certain size * for inobject_properties.
  • When the pre-allocated space is insufficient (no free slot is available), the new properties are stored in the Properties.
  • The digital attributes are stored in Elements.
  • Properties/Elements A larger FixedArray is created (copied) when space is insufficient.

*


V8 defines the maximum JSObject instance size as kMaxInstanceSize = 2040 byte,


Among them:


KPointerSize = sizeof (void *) = 8 byte,


KHeaderSize = kPointerSize * 3,


Max (inobject_properties) = 252

To illustrate, let’s look at an example:

1. Create an object

var obj = {};
Copy the code

An attribute – free object created from an object literal is allocated four inobject_properties Spaces.

2. Add three attributes

obj.x = 1;
obj.y = 2;
obj.z = 3;
Copy the code

Attributes (“x”, “y”, “z”) are stored preferentially in the in-object property store.

3. Add two digital attributes

obj[0] = "a";
obj[1] = "b";
Copy the code

The digital attributes (“0”, “1”) are stored in Elements.

4. Add three more attributes

obj.a = "a";
obj.b = "b";
obj.c = "c";
Copy the code

In-object property storage (” A “) is preferred, and properties (“b”, “C”) are stored in properties when pre-allocated space is insufficient.

How does V8 know the state of space allocation and space structure?

This brings us to

, where each instance created in the heap has a

describing its structure.

Let’s take JSObject<Map> for example:

  • Type: indicates that the in-heap instance is a JSObject object
  • Inobject Properties: In-object storage space (including unused slots)
  • Unused Property fields: Unused property storage space
  • Instance size: Size of the instance (in the heap)
  • Constructor: Object constructor
  • Prototype: Object prototype
  • Stable [Dictionary] : current state of the object
    • Stable_map: Fast mode
    • Dictionary_map: dictionary mode
  • … …

When the object is in dictionary mode, the Jenkins Hash can be used directly to get the location of the property value to be accessed. When the object is in fast mode, V8 uses instance_descriptors in JSObject

to mark the location of the property name of the object instance and its value to be accessed (as shown below) :

In addition, object V8 in fast mode also works with RAW_Transitions in JSObject<Map> to improve the access performance of object instances.

To understand Transitions, here’s an example:

When instantiating the constructor, create a new empty object according to the ECMA-262 standard:

When adding attribute x = 1:

  1. Generate a new
    (#1) and change the reference to JSObject

    to the newly created

    (#1).
  2. Write a transition #x to Map(#1) to transitions from the previous
    (#0) reference.
  3. Write #x in offset 0 at the current instance_descriptors(own).
  4. Writes the number 1 (Smi) to bit 0 of the property store in the JSObject object (as identified in instance_descriptors).

The structure is as follows:

When continuing to add attribute y = 2, the execution process is similar to adding attribute X, and the final generated object P1 is as follows:

Typically, TransitionsList or even TransitionsTree is formed as a result of the object’s build process.

But does it seem that Transitions from individual <Map> Transitions in object P1 instantiation are useless? And so it is! Meow meow meow? ! But if you instantiate the object again, you can see why it’s useful.

We instantiate the constructor again, but this time we pass in two strings (“a”, “b”) :

When adding attribute x = “a” :

  1. Look for transition records based on key=x in JSObject
    (#0) transitions, and follow the path of changing the JSObject

    reference to the found

    (#1) (no new

    is created here).
  2. Read the current instance_descriptors to find #x at offset 0.
  3. Writes the string “a” (Pointer) to bit 0 of the property store in the JSObject object (as identified in instance_descriptors).

Note that: Here the instance_descriptors instance (that is, instance_descriptors) is owned by <Map>(#2), not <Map>(#1)(#0), so instance_descriptors can only be read, not written.

The structure is as follows:

When adding attribute y = “b”, the execution process is similar to adding attribute x, and the resulting object P2 has the following structure:

Here we find that although the actual data (type) stored by P1 and P2 is different, through the Transitions feature they share the same

(#2), which results in them also sharing instance_descriptors. So their spatial structure (layout) is the same (as shown below).

To summarize, objects built in the same order with the same attribute name (same constructor) share the same <Map>.

JSObject<Map> is also known as Hidden ClassThis is due to the original V8 in
Design ElementsIt was called Hidden Class and is still used today.

That is, JSObject objects with the same build structure in V8 have the same memory (space) layout in the heap.

The same memory (space) layout is the basis for V8 optimized object access.

How is V8 optimized for access based on this? Welcome to the next episode:

  • V8 iii, polymorphic inline cache PICs