Javascript:SpiderMonkey:PropertyElementStorage

From MozillaWiki
Jump to navigation Jump to search

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

Property/element splitting

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

  1. 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 on getPropertyDescriptor to implement assignish behavior. Not sure how much time it'll take.
    • js/src/shell/js.cpp - Waldo, ~no time
    • js/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.
  2. 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 SpecialIds. Thus ultimate landing of this work depends on E4X removal.

Time: M weeks

  • Implement PropertyKey as a class containing a Value, with is* and as* methods, with index/name/symbol subclasses - 2 days
    • This is simple to do in terms of Value's existing interface.
  • 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)
  • step 2 - Q weeks, not started
    • substep 1 - X weeks?
      • consideration 1
    • substep 2 - Y weeks (person, person)
      • consideration 1

Issues

  • thing to consider
  • other thing to consider

Risks

  • risk 1
    • mitigating idea 1
    • mitigating idea 2
  • risk 2
    • mitigating idea 1