1

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;
  • 1
    Regarding question 1, the same rules for adding a property apply that did when the transition from C1 to C2 happened because of the `y` property. – Bergi Jun 05 '17 at 12:39

1 Answers1

2
  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.

jmrk
  • 34,271
  • 7
  • 59
  • 74
  • 1
    Thanks, this helped me. I know in compile time there are no objects, but the compiler could attempt to detect and follow them anyways. Hum, but in ther own page they say hidden classes avoid lookup: *"To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties."*. Edit: I think I misunderstood your answer at 4. In-line caching means that at least one lookup must be done for own property of an object, correct? –  Jun 05 '17 at 12:02
  • Regarding "*mandated by the JavaScript spec: a for..in loop must iterate properties in creation order*" - [actually it doesn't](https://stackoverflow.com/a/30919039/1048572), only the `OwnPropertyKeys` algorithm needs to do that. – Bergi Jun 05 '17 at 12:36
  • @Bergi This is nearly like what would be in ES4 with for in and for each. –  Jun 05 '17 at 12:52
  • @Bergi Hey, do you think V8 would create and generate access of bound/function-scoped variables by memory addresses or will these variables be lookuped everytime when used? They're specified as properties of the current variable object, but it's not accessible anyways –  Jun 05 '17 at 14:36
  • 2
    @Matheus There are no variable objects (I mean JS objects), all variable lookups are statically optimisable (unless `with`, `eval` or global). But really jmrk is the right addressee for such questions :-) – Bergi Jun 05 '17 at 16:36
  • 3
    @Bergi: thanks, fixed. (I've always assumed that since `EnumerateObjectProperties` must call `[[OwnPropertyKeys]]`, it must also maintain order of the result, but as the discussion you linked to points out, that was not the intent of the spec text. How confusing!) --- @Matheus: function-local variables are not represented as object properties, and accessing them is very fast ("optimized away", essentially). – jmrk Jun 06 '17 at 12:51
  • @jmrk Thanks, these points have really clarified my questions –  Jun 07 '17 at 21:25
  • Sorry :/, but I'm still a bit confused in point 4. The GitHub page says _"There are two advantages to using hidden classes: property access does not require a dictionary lookup"_, but your answer says _"Hidden classes are always used for lookups."_ (what is negativating what was said on the GitHub page), so there's really no extra compile time optimization in lookups that it can detect like `{ let o = { x: 0, y: 0, z: 0 }; o.x, o.y, o.z }`? –  Jun 09 '17 at 18:35
  • 3
    In a JavaScript engine without hidden classes, *every* property access would require a dictionary lookup. In V8, inline caches remember what object types (=hidden classes) they have seen before, so they don't need to do a lookup when they encounter an object with the same hidden class again -- but they do need to do a lookup the first time they see a given hidden class. --- Compile-time optimizations are a different mechanism (they do exist; but they don't "optimize lookups"). – jmrk Jun 10 '17 at 00:40
  • Thanks for the time. By lookup you refer to the property access lookup (i.e., `o.prop`), right? Will `'prop'` always require lookup independently of the object's hidden class? –  Jun 10 '17 at 10:11
  • 2
    The first time an `o.prop` statement is executed, the engine needs to figure out what to do ("does this `o` even have a `prop` property? where in the object is it stored?"). This is called "lookup". The result (e.g. "it exists, it's the fifth property") is then cached, so when *the same* `o.prop` is executed again later, then if the new `o` has the same hidden class as before, it can simply load the fifth property from it -- no lookup required. – jmrk Jun 11 '17 at 11:16