how javascript objects are implemented
DESCRIPTION
How JavaScript Objects are ImplementedTRANSCRIPT
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?