Platform/Performance:IndexGetterSetter

IndexGetter/Setter

https://bugzilla.mozilla.org/show_bug.cgi?id=499201

Since writing that, I have come to think we might want a slightly different API. In particular, the ideal thing from the POV of content is if we have two things the JS engine asks us:

  1. Is this index in range? (possibly skipped for objects that map all integers; presumably needed for resolve to work right)
  2. What is the value at this index?

If the js engine can use a magic answer to #2 to skip the check in #1, so much the better.

We may want to draw a distinction between objects whose index range is immutable and those for which it can change. Not sure if that would be useful to optimize access to the former.


Semantics

I'll call an object's normal properties "real" and these new properties "virtual".

From the perspective of JS code, there should be almost no difference between virtual properties and real ones.

  • n in obj, obj.hasOwnProperty(n),Object.getOwnPropertyDescriptor(obj, n), and even Object.getOwnPropertyNames should treat virtual properties exactly the same as real ones.
  • obj[n], obj[n] = val, obj[n]++, and so on should behave exactly as you'd expect, given the property descriptor produced by Object.getOwnPropertyDescriptor.
  • So should JSAPI functions generally. For example, JS_GetElement must get virtual properties just as it would get real ones. (C/C++ code might end up needing JSAPI functions that distinguish the two, but the existing functions shouldn't.)

So what is the difference?

Unlike real properties, virtual properties can come and go without anything happening in the JS engine.

Also: a virtual property never has a stored value (that is, a slot).

Operations that create a property, such as assignment to a nonexisting property and Object.defineProperty, will continue to create real properties, at least for now. (It could change someday. If we ever want to use virtual properties for array elements, we would want a[a.length] = 1 to create a new virtual property, not a real one.)

An object's virtual properties should be shadowed by its real properties, so that if you set a real property obj[1] while obj has no virtual elements, and later it gains virtual elements numbered 0-5, obj[1] is the real property and the virtual one is completely undetectable.

Implementation notes

Currently, doing a lookupProperty on a native object always returns a real property that is in the object's JSScope. We must fix whatever is depending on this invariant; callers must be prepared for the possibility that the property is virtual, and thus isn't in the JSScope.

In particular, we must not cache virtual properties in the property cache, since they can come and go without modifying the object's shape. [YES! Not changing shape on nodelist [] access will help DOM tracing a lot in many cases.]

We must not allow Object.defineProperty(obj, n, desc), or anything else, to shadow or overwrite an existing non-configurable virtual own property obj[n]. This means either we decree that virtual properties can't be configurable; or we check for virtual properties before defining new properties.

If a virtual property is JSPROP_PERMANENT, then whoever writes the hooks is responsible for making sure it never goes away or gets shadowed.

Then: js_LookupProperty needs to return something when a virtual element is found. The new behavior will work a lot like the "new resolve hook" in that it participates in the lookup process. So we need to add a hook there, or just another variation on the existing resolve hook. Getting lookups working will be sufficient to get the in keyword, Object.getOwnPropertyDescriptor(), and many JSAPI functions working. In fact, that might be all we need to get all the desired functionality baseline working.

Then: We want an additional hook to