Search code examples
javascriptv8

How does V8 inline caching work with delete and computed property access?


As exampled in https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access, I (attempt to) understand that properties of an object are stored based in a hidden class, call it "C[N]", of its constructor. I may not have understood it correctly... For example:

// Let's suppose Object has these hidden classes already

/* Object[[HiddenClasses]] > C0, C1, C2
 *
 * C0 - for "x", goto C1
 * C1 - "x"; for "y", goto C2
 * C2 - "x", "y";
 */

var obj = {
    x: 0
};
// Currently based in C1 to get/put properties

obj.y = 0;
// Now based in C2

1. What happens if this new object adds a new property?

obj.z = 0

Will it still behave like the first instance of Object?

2. What happens if an object of the same constructor adds properties in opposite order of the hidden classes?

({ y: 5; }); // Will this be based in C2?

3. What happens if a property is deleted? Is its value only changed in memory for representing deleted?

4. Are lookups done inside hidden classes when the compiler can't see an object or name of its computed property access? I.e.:

({ [Math.random()]: 0 }),
randomlyReceivedObject.property;

Solution

    1. After obj.z = 0, C2 gets a new transition for "z", goto C3, and a new hidden class C3 - "x", "y", "z" is created for the object.

    2. That object will have a new hidden class C4 - "y". And C0 gets a new transition: for "y", goto C4. If that object later gets an "x" property, a new hidden class C5 - "y", "x" will be created, and a transition in C4: for "x", goto C5. C5 and C2 will forever remain distinct. This is actually mandated by the JavaScript spec, because e.g. a for..in loop Object.getOwnPropertyKeys must iterate properties in creation order, and V8 keeps track of property creation order via hidden classes. Since having more hidden classes naturally has a speed and memory cost, it is generally recommended to always create properties in the same order (e.g. by using a constructor function).

    3. When a property is deleted, the object is put into dictionary mode, and hidden classes are no longer used to keep track of its properties. Internally this is implemented via a special hidden class: C6 - all properties are in the properties dictionary. Every subsequent property access will then require a dictionary lookup. If you want to avoid this, you can manually overwrite properties instead of deleting them: obj.x = null or similar. (Fine print: as of very recent V8 versions, there is an exception to this, where if the last property is deleted, then the last hidden class transition is rolled back. This implementation detail may or may not stick around in the future, so don't rely on it.)

    4. Hidden classes are always used for lookups. Inline caches simply cache the results of these lookups; this always happens at execution time, not at compilation time. "The compiler" generally can't "see" objects, because at compilation time there are no objects yet.