Javascript:SpiderMonkey:PropertyElementStorage
Objective
Summary: Store and represent properties of objects differently, depending whether the property is a string containing an unsigned 32-bit number (indexed: an element) or is not such a string (non-indexed: a "property").
Currently we represent all properties of an object through a single mechanism. Every property is represented either through the shape_
field of the object, or through class/objectops hooks that are passed a jsid
. There's no API separation between properties that are indexed by a uint32_t
("0", "17", "4294967295") and properties that are named ("baz", "-1", "-0", "4294967296"). And for objects which represent properties using shape_
, all properties of any kind (excepting low-valued indexes, in certain circumstances -- but not uniformly) are intermingled.
But the distinction between indexed and non-indexed properties exists in various APIs implemented in JavaScript. It's present in WebIDL, implicitly in Array
itself (if one excludes UINT32_MAX
), implicitly in typed arrays, and elsewhere. (Not to mention that most people write code that respects this distinction -- object literals use non-indexed properties, dotted property access is inherently non-indexed, most objects get used non-indexed-ly unless they're array-likes [in which case accesses are pretty much always obviously indexed or obviously non-indexed], and so on.)
One result of this lack of separation is increased overhead for accessing all properties. Any object whose properties split this way, that uses class/objectops hooks, incurs extra overhead to differentiate the two cases. A jsid
might be either an index or not, and that distinction must be checked before indexed or non-indexed behavior can occur. (Unless certain hacks are done, but those are pretty tricky to do, and they're one-off each time.)
Another result is that for objects where we've manually worked around this extra overhead -- for example, typed arrays -- we usually have to give up on representing all properties. (This is currently the case for typed arrays, which cannot have extra properties added to them. It was historically the case for dense arrays, too, before recent changes to make an initial sequence of indexed properties be stored more compactly, in some cases.)
A last nicety is that this all makes implementing a non-writable length
property on arrays much easier.
People
Accountable: Naveed
Responsible: Waldo
Consulted:
Informed: Product Marketing
Steps
Remove resolve flags
Resolve flags stand in the way of making our property-access APIs close enough to the ECMAScript internal operations to cleanly implement the split. The only remaining flag -- many have been removed since mid-2012 -- is JSRESOLVE_ASSIGNING
.
Time: M weeks
- Remove all tests of
flags & JSRESOLVE_ASSIGNING
in all files - ???dom/base/nsDOMClassInfo.cpp
- Fix the test in resolving readonly-replaceable properties
- Fix the test to optimize fast expandos on
window
- bz, 1 day- This will be fixed (or close enough) by bug 823227.
- Fix the test in
nsNamedArraySH::NewResolve
- a day?- Suss out exactly how this code gets called, write a test for new behavior if there's a change, done. Likely simple.
- Fix the test in
nsHTMLDocumentSH::NewResolve
- Waldo, 1 day?- This might just be totally removable -- unclear.
- Fix the test in
nsHTMLFormElementSH::NewResolve
- Waldo, 1 day?- This might just be totally removable. Unclear.
dom/bindings/Codegen.py
- This probably requires work from DOM bindings people, to implement
set
hooks rather than relying ongetPropertyDescriptor
to implement assignish behavior. Not sure how much time it'll take.
- This probably requires work from DOM bindings people, to implement
js/src/shell/js.cpp
- Waldo, ~no timejs/src/jswrapper.cpp
- Waldo, ???- bholley thinks this might be removable easily. Unclear.
js/xpconnect/wrappers/XrayWrapper.cpp
- bholley, ???- Tangled mess of complexity, unclear how long to resolve the underlying issue.
- Remove
JSRESOLVE_ASSIGNING
completely - Waldo, ~no time
When all flags have been removed, we can either just pass 0 everywhere, or remove all flags
arguments. We should do the latter, but it's irrelevant to forward progress on property/element work.
Implement the property key stuff in ES6
ES6 property names aren't strings, they're property keys made by ToPropertyKey
spec op -- either strings or ES6 symbols. It'll be a very clean split to implement property keys but have indexes as a third kind of property key. This provides nice typing at the underlying API boundary level, and it enables a high-level type for undistinguished property accesses, that straightforwardly decomposes into the more specific types.
ES6 symbols aren't specified yet. We can carve out the API space for them underneath property keys, as currently-dead code -- maybe add a super-stupid symbol-like creator function to the shell if we want to exercise them.
Fully implementing property keys requires removing E4X SpecialId
s. Thus ultimate landing of this work depends on E4X removal.
Time: M weeks
- Implement
PropertyKey
as a class containing a Value, withis*
andas*
methods, with index/name/symbol subclasses - 2 days- This is simple to do in terms of
Value
's existing interface.
- This is simple to do in terms of
- step 1 - N weeks,
- step 2
Copy/Paste Step (don't edit!)
Description of step N.
- step 1 - N weeks, (started or not)
- consideration 1
- consideration 2
- subsubpart 2 - M weeks (person)
- consideration 1
- step 2 - Q weeks, not started
- substep 1 - X weeks?
- consideration 1
- substep 2 - Y weeks (person, person)
- consideration 1
- substep 1 - X weeks?
Issues
- thing to consider
- other thing to consider
Risks
- risk 1
- mitigating idea 1
- mitigating idea 2
- risk 2
- mitigating idea 1