Jeff Walden
unread,May 26, 2012, 5:08:34 PM5/26/12You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to
Because I haven't stirred up enough trouble this week asking to remove API... :-(
The JSClass flag JSCLASS_NEW_RESOLVE_GETS_START ("JNRGS") is incompatible with ECMAscript semantics. Those require property lookups be phrased in terms of calls to object [[GetOwnProperty]] hooks.
[[GetOwnProperty]] is only passed a single object -- the one whose hook is being called. It's not passed the starting object that's needed for new-style resolve hooks with JNRGS. If I implement property lookups that function as the spec wants them to, I don't have a starting object to pass to JNRGS-using resolve hooks.
I'd like to remove JNRGS. I'm implementing to-the-spec property semantics now, and this flag prevents a proper implementation. Who's using this flag, and how much, and how can I help people work around its removal?
Jeff
P.S. -- Gecko uses JNRGS in one location. I'll include a description of how we're eliminating that use after a break, to keep the important info short. It's possible the basic trick might work for other people.
Gecko uses JNRGS to lazily define properties on elements implemented with XBL. The prototype chain looks like this:
XBL element --> XBL binding proto --> rest of chain
Suppose I have an element |xe| whose XBL binding includes a field "foo". Getting |xe.foo| the first time will not find it in |xe|, then not find it in the binding proto and will call the binding proto's newresolve hook. The XBL proto has JNRGS set, so the proto's resolve hook is passed both proto and |xe|. The resolve hook uses the proto to dig up the text defining the field. It then evaluates the text as code and defines a property on |xe| to the result of that evaluation.
The workaround we'll use is this: the proto's hook will resolve an accessor property onto proto itself. The accessor's getter and setter, when accessed, *will* be passed a starting object for the get or set, because that's just how accessors work. So we can simply defer the work of defining the field to the getter/setter. They can define a property on |xe| that'll shadow the accessor on the XBL proto, then the getter can return that value, and the setter can modify it appropriately. There's a bunch of complexity to making sure the getter/setter properly vet the starting object they're passed, but it shouldn't be too bad.
(Another alternative would be to make every XBL element a proxy. This is likely a bunch more work for not much gain, if any, so we're not pursuing it.)
Thus everything will look basically the same if you're just getting and setting |xe.foo|. It'll look a little different if you're doing |Object.getOwnPropertyDescriptor(xe, "foo")|, or are defining a property using Object.getOwnPropertyDescriptor. But this sort of level of how-bindings-work nitpickery usually doesn't affect compatibility in our experience, so the accessor trick here should get the job done.