How JavaScript Objects Are Implemented

Preview:

DESCRIPTION

How JavaScript Objects are Implemented

Citation preview

How JavaScript Objects are Implemented

Eddy Jean-Paul Bruel

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Properties• An object is a collection of named properties.

• Each property has the following attributes:

• [[Enumerable]] Whether the property will be enumerated by for-in.

• [[Configurable]] Whether the property can be deleted, or its attributes (other than [[Value]]) modified.

• Each property is either a data property or an accessor property.

Data Properties

• A data property is a property that has the following attributes:

• [[Value]] The value of the property.

• [[Writable]] Whether the value of the property can be modified.

Accessor Properties• An accessor property is a property that has

the following attributes:

• [[Get]] A function to access the value of the property.

• [[Set]] A function to modify the value of the property.

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Shapes and Slots• In SpiderMonkey, an object

consists of:

• A linked list of shapes.

• A vector of slots.

• Each shape stores the name and attributes of a property (except [[Value]]).

• Each slot stores the [[Value]] attribute of a property.

• Each shape contains an index into the slot vector.

Shapes and Slots• In SpiderMonkey, an object

consists of:

• A linked list of shapes.

• A vector of slots.

• Each shape stores the name and attributes of a property (except [[Value]]).

• Each slot stores the [[Value]] attribute of a property.

• Each shape contains an index into the slot vector.

Shape Trees• Because the [[Value]] attribute

is stored separately, shapes can be (partially) shared for a set of properties IF:

• they have the same name,

• AND they have the same attributes (except [[Value]]),

• AND they are defined in the same order.

• This leads to the notion of shape trees.

Shape Trees• Because the [[Value]] attribute

is stored separately, shapes can be (partially) shared for a set of properties IF:

• they have the same name,

• AND they have the same attributes (except [[Value]]),

• AND they are defined in the same order.

• This leads to the notion of shape trees.

Empty Shapes• Every object starts out with

an empty shape.

• Objects start out with the same empty shape IF:

• they have the same compartment (i.e. global),

• AND they have the same class,

• AND they have the same prototype.

Empty Shapes• Every object starts out with

an empty shape.

• Objects start out with the same empty shape IF:

• they have the same compartment (i.e. global),

• AND they have the same class,

• AND they have the same prototype.

Empty Shapes• Every object starts out with

an empty shape.

• Objects start out with the same empty shape IF:

• they have the same compartment (i.e. global),

• AND they have the same class,

• AND they have the same prototype.

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Adding Properties

• To add a property P to an object O:

1. IF the current shape of O has a child C that stores P:

1. Let S be C.

2. ELSE:

1. Let S be a new shape that stores P.

2. Insert S as a child of the current shape of O.

3. Set the current shape of O to S.

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Shape Lookup

• To find the shape S that stores a property P on an object O.

1. Let S be the current shape of O.

2. If S stores P, return S.

3. If S is an empty shape, throw.

4. Let S be the parent of S.

5. Go back to 1.

Shape Lookup

• To find the shape S that stores a property P on an object O.

1. Let S be the current shape of O.

2. If S stores P, return S.

3. If S is an empty shape, throw.

4. Let S be the parent of S.

5. Go back to 1.

Shape Tables• Finding a shape using linear lookup has

O(n) worst case performance.

• Associate a shape table with each shape S.

• Finding a shape using shape tables has O(1) expected performance.

• Only store a shape table at S IF:

• the number of searches starting at S exceeds MAX_LINEAR_SEARCHES,

• AND the number of ancestors of S exceeds MAX_ENTRIES.

• Shape tables are shared between objects.

Shape Tables• Finding a shape using linear lookup has

O(n) worst case performance.

• Associate a shape table with each shape S.

• Finding a shape using shape tables has O(1) expected performance.

• Only store a shape table at S IF:

• the number of searches starting at S exceeds MAX_LINEAR_SEARCHES,

• AND the number of ancestors of S exceeds MAX_ENTRIES.

• Shape tables are shared between objects.

Inline Caching• For simple property access (i.e.

O[P]) we only need P.[[Value]].

• To get P.[[Value]], we need to know slotIndex(P).

• slotIndex(P) can only change if we remove properties (we will get to this in a bit).

• If we remove properties, currentShape(O) changes as well.

• Avoid unnecessary shape lookups by caching slotIndex(P) for currentShape(O).

Inline Caching1. IF currentShape(O) is NOT equal to cachedShape(O)

(cache miss):

1. Find the shape S that stores P.

2. Set cachedSlot(P) to S.slotIndex

3. Set cachedShape(O) to currentShape(O).

2. ELSE (cache hit):

1. Load the value of P from cachedSlot(P) in the slot vector of O.

Inline Caching• The JIT generates code in which cachedShape(O) and cachedSlot(P)

are hardcoded.

• On a cache miss, the cached values are updated in place (by recompiling the function).

• This is known as inline caching:

Inline Caching• The JIT generates code in which cachedShape(O) and cachedSlot(P)

are hardcoded.

• On a cache miss, the cached values are updated in place (by recompiling the function).

• This is known as inline caching:

cmp [aex + CURRENT_SHAPE], CACHED_SHAPE jne cache_miss mov aex, [aex + CACHED_SLOT]

Inline Caching• Modern JITs are actually even smarter than this, and

can cache slotIndex(P) for multiple O’s with different shapes.

• This is known as polymorphic inline caching.

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Removing Properties• To remove a property P from

an object O:

1. Find the shape S that stores P.

2. IF S == currentShape(O):

1. Set currentShape(O) to its parent.

3. ELSE:

1. Lazily fork the shape tree at the parent of S.

Removing Properties• To remove a property P from

an object O:

1. Find the shape S that stores P.

2. IF S == currentShape(O):

1. Set currentShape(O) to its parent.

3. ELSE:

1. Lazily fork the shape tree at the parent of S.

Removing Properties• To remove a property P from

an object O:

1. Find the shape S that stores P.

2. IF S == currentShape(O):

1. Set currentShape(O) to its parent.

3. ELSE:

1. Lazily fork the shape tree at the parent of S.

Removing Properties• To remove a property P from

an object O:

1. Find the shape S that stores P.

2. IF S == currentShape(O):

1. Set currentShape(O) to its parent.

3. ELSE:

1. Lazily fork the shape tree at the parent of S.

Dictionary Mode• Lazily forking the

property tree has O(n2) worst case performance.

• Instead, copy the entire shape tree, eliminating sharing altogether.

• This is known as dictionary mode.

Dictionary Mode• Lazily forking the

property tree has O(n2) worst case performance.

• Instead, copy the entire shape tree, eliminating sharing altogether.

• This is known as dictionary mode.

Dictionary Mode• Dictionary mode eliminates sharing, and is thus best

avoided.

• What you shouldn’t do:

• Deleting a non-last property.

• Changing the attributes of a non-last property.

• However:

• Setting a non-last property to undefined is ok.

• If the property is the last property, you’re also ok.

Overview• How objects are specified

• How objects are represented

• Object operations:

• Adding properties

• Finding properties

• Removing properties

• Arrays and elements

Elements

• A property name P is an array index IF:

• ToString(ToUint32(P)) == P,

• and ToUInt32(P) != 232 - 1.

• A property is an element IF its name is an array index.

Arrays• Arrays store elements

in a separate slot vector, using the array index as the slot index.

• This is why properties are enumerated in insertion order, but elements are not.

Arrays• Arrays store elements

in a separate slot vector, using the array index as the slot index.

• This is why properties are enumerated in insertion order, but elements are not.

Array Holes

• Removing a non-last element replaces its value with an array hole.

• A sparse array is an array with one or more holes in it.

Array Holes

• Removing a non-last element replaces its value with an array hole.

• A sparse array is an array with one or more holes in it.

Sparse Elements• Attributes are stored on

shapes. Because elements don’t have shapes, they can’t have non-default attributes.

• Changing the attributes of an element replaces it with a property.

• Such properties are known as sparse elements.

• In an object, all elements are sparse.

Sparse Elements• Attributes are stored on

shapes. Because elements don’t have shapes, they can’t have non-default attributes.

• Changing the attributes of an element replaces it with a property.

• Such properties are known as sparse elements.

• In an object, all elements are sparse.

Thanks for Listening!Any questions?

Recommended