
JavaScript engine basics: general forms and inline caching. Part 2
- Transfer
Hello! The course "Security of Information Systems" starts in 2 weeks, so today we want to publish the second part of the article, the publication of which is timed to coincide with its launch. You can read the first part here . So, let's begin.
Inline Caches (ICs)
The main idea behind the forms is the concept of inline caches or ICs. They are a key component of fast JavaScript! JavaScript engines use ICs to remember information about where to find the properties of objects in order to reduce the number of costly searches.

We have a function
If we run this function in JSC, we get the following bytecode:

The first instruction
JSC also embeds inline Cache in the instruction

And now let's assume that we call

The built-in

For subsequent IC starts, you only need to compare the form, and if it is the same as before, just load the value from the stored offset. In particular, if the JavaScript engine sees objects with a form that he wrote down earlier, he no longer needs to ask for information about these properties at all - instead, an expensive search for information about properties can be completely skipped. This is significantly faster than spending time looking for properties each time.
Efficient storage of arrays
For arrays, it is common practice to store array indices. The values of such properties are called array elements. It would be wasteful to store property attributes for each element of the array in a separate array. Instead, JavaScript engines rely on the fact that properties indexed in an array are writable, enumerable, and configurable by default, and they also store array elements separately from other named properties.
Consider the following array:
The engine stores an array of unit length and points to a shape that contains the offset and attributes for the property

This is similar to what we have seen before ... But where are the values of the array elements stored?

Each array has a separate element backing store containing all property values indexed by the array. The JavaScript engine does not need to store any property attributes for the elements of the array, since they are usually writable, enumerable, and configurable.
But what happens if they suddenly become unavailable for configuration? What if you change the attributes of a property of an array element?
The code snippet above defines a property that is called
In such extreme cases, the JavaScript engine presents the entire backup storage of elements as a dictionary that maps array indices to property attributes.

Even if only one element of the array has non-default attributes, the entire storage of backup copies of elements goes into a slow and inefficient mode of operation. Avoid
Conclusions
We learned how JavaScript engines store objects and arrays, how forms and inline caches help optimize various operations. Also in this article, we want to give some practical tips for JavaScript that can help increase the performance of your code:
Now the article can be considered complete. According to the established tradition, we are waiting for your comments and invite you to sign up for an open webinar on the course "Security of Information Systems", which will be held today by a well-known virus analyst and part-time our teacher - Alexander Kolesnikov .
Read the first part.
Inline Caches (ICs)
The main idea behind the forms is the concept of inline caches or ICs. They are a key component of fast JavaScript! JavaScript engines use ICs to remember information about where to find the properties of objects in order to reduce the number of costly searches.

We have a function
getX
that takes an object as an input and loads a property from it x
:function getX(o) {
return o.x;
}
If we run this function in JSC, we get the following bytecode:

The first instruction
get_by_id
loads the property ‘x’
from the first argument (arg1)
and stores the result in loc0
. The following statement returns what we stored in loc0
. JSC also embeds inline Cache in the instruction
get_by_id
, which consists of two uninitialized slots. 
And now let's assume that we call
getX
along with the object { x: 'a' }
. We already know that this object has a property ‘x’
, and its shape stores the offset and attributes of the property х
. When you execute the function for the first time, the instruction get_by_id
searches for the property ‘x’
and finds that its value is stored at offset 0.
The built-in
get_by_id
IC instruction remembers the shape and offset where the property was found. 
For subsequent IC starts, you only need to compare the form, and if it is the same as before, just load the value from the stored offset. In particular, if the JavaScript engine sees objects with a form that he wrote down earlier, he no longer needs to ask for information about these properties at all - instead, an expensive search for information about properties can be completely skipped. This is significantly faster than spending time looking for properties each time.
Efficient storage of arrays
For arrays, it is common practice to store array indices. The values of such properties are called array elements. It would be wasteful to store property attributes for each element of the array in a separate array. Instead, JavaScript engines rely on the fact that properties indexed in an array are writable, enumerable, and configurable by default, and they also store array elements separately from other named properties.
Consider the following array:
const array = [
'#jsconfeu',
];
The engine stores an array of unit length and points to a shape that contains the offset and attributes for the property
‘length’
. 
This is similar to what we have seen before ... But where are the values of the array elements stored?

Each array has a separate element backing store containing all property values indexed by the array. The JavaScript engine does not need to store any property attributes for the elements of the array, since they are usually writable, enumerable, and configurable.
But what happens if they suddenly become unavailable for configuration? What if you change the attributes of a property of an array element?
// Please don’t ever do this!
const array = Object.defineProperty(
[],
'0',
{
value: 'Oh noes!!1',
writable: false,
enumerable: false,
configurable: false,
}
);
The code snippet above defines a property that is called
‘0’
(it turns out to be an array index), it changes the attribute values to non-default ones. In such extreme cases, the JavaScript engine presents the entire backup storage of elements as a dictionary that maps array indices to property attributes.

Even if only one element of the array has non-default attributes, the entire storage of backup copies of elements goes into a slow and inefficient mode of operation. Avoid
Object.defineProperty
in array indices! (I don’t even know why you should use this in principle. It seems strange and irrational.) Conclusions
We learned how JavaScript engines store objects and arrays, how forms and inline caches help optimize various operations. Also in this article, we want to give some practical tips for JavaScript that can help increase the performance of your code:
- Always initialize your objects the same way so that they do not have different shapes;
- Do not mess with the attributes of the properties of the elements of the array, give them the opportunity to safely be stored and work efficiently.
Now the article can be considered complete. According to the established tradition, we are waiting for your comments and invite you to sign up for an open webinar on the course "Security of Information Systems", which will be held today by a well-known virus analyst and part-time our teacher - Alexander Kolesnikov .
Read the first part.