How does JavaScript VM implements Object property access? Is it Hashtable?

Viewed 12020

Objects in JavaScript can be used as Hashtable (the key must be String) Is it perform well as Hashtable the data structure?

I mean , does it implemented as Hashtable behind the scene?

Update: (1) I changed HashMap to hashtable (2) I guess most of the browser implement it the same, if not why not? is there any requirement how to implement it in the ECMAScript specs?

Update 2 : I understand, I just wonder how V8 and the Firefox JS VM implements the Object.properties getters/setters?

4 Answers

Most modern JS engines use pretty similar technique to speed up the object property access. The technique is based on so called hidden classes, or shapes. It's important to understand how this optimization works to write efficient JS code.

JS object looks like a dictionary, so why not use one to store the properties? Hash table has O(1) access complexity, it looks like a good solution. Actually, first JS engines have implemented objects this way. But in static typed languages, like C++ or Java a class instance property access is lightning fast. In such languages a class instance is just a segment of memory, end every property has its own constant offset, so to get the property value we just need to take the instance pointer and add the offset to it. In other words, in compile time an expression like this point.x is just replaced by its address in memory.

May be we can implement some similar technique in JS? But how? Let's look at a simple JS function:

function getX(point) {
  return point.x;
}

How to get the point.x value? The first problem here is that we don't have a class (or shape) which describes the point. But we can calculate one, that is what modern JS engines do. Most of JS objects at runtime have a shape which is bound to the object. The shape describes properties of the object and where these properties values are stored. It's very similar to how a class definition describes the class in C++ or Java. It's a pretty big question, how the Shape of an object is calculated, I won't describe it here. I recommend this article which contains a great explanation of the shapes in general, and this post which explains how the things are implemented in V8. The most important thing you should know about the shapes is that all objects with the same properties which are added in the same order will have the same shape. There are few exceptions, for example if an object has a lot of properties which are frequently changed, or if you delete some of the object properties using delete operator, the object will be switched into dictionary mode and won't have a shape.

Now, let's imagine that the point object has an array of property values, and we have a shape attached to it, which describes where the x value in this property array is stored. But there is another problem - we can pass any object to the function, it's not even necessary that the object has the x property. This problem is solved by the technique called Inline caching. It's pretty simple, when getX() is executed the first time, it remembers the shape of the point and the result of the x lookup. When the function is called second time, it compares the shape of the point with the previous one. If the shape matches no lookup is required, we can take the previous lookup result.

The primary takeaway is that all objects which describe the same thing should have the same shape, i.e. they should have the same set of properties which are added in the same order. It also explains why it's better to always initialize object properties, even if they are undefined by default, here is a great explanation of the problem.

Relative resources:

this article explains how they are implemented in V8, the engine used by Node.js and most versions of Google Chrome

https://v8.dev/blog/fast-properties

apparently the "tactic" can change over time, depending on the number of properties, going from an array of named values to a dictionary.

v8 also takes the type into account, a number or string will not be treated in the same way as an object (or function, a type of object)

if i understand this correctly a property access frequently, for example in a loop, will be cached.

v8 optimises code on the fly by observing what its actually doing, and how often

v8 will identify the objects with the same set of named properties, added in the same order (like a class constructor would do, or a repetitive bit of JSON, and handle them in the same way.

see the article for more details, then apply at google for a job :)

Related