[Proxies] Refactoring prototype climbing in the spec
allen at wirfs-brock.com
Tue Nov 8 10:37:10 PST 2011
On Nov 8, 2011, at 7:33 AM, Andreas Rossberg wrote:
> On 7 November 2011 16:54, Tom Van Cutsem <tomvc.be at gmail.com> wrote:
>> I wrote up an initial (but fairly complete) draft of a proposed refactoring
>> of the ES5 [[Get]], [[Put]] and [[HasProperty]] algorithms to change the way
>> in which these algorithms climb the prototype
>> chain: <http://wiki.ecmascript.org/doku.php?id=strawman:refactoring_put>
> Looks good, and as far as I can see from a first read, solves the
> issues we were discussing so far.
> But I have a follow-up request. :) Regarding redundant trap calls with
> proxies there is another, more pervasive problem with the current
> spec: in lots of places it first calls [[HasProperty]] and then
> [[Get]]. With proxies, this always implies two trap calls, which seems
> wasteful. Would it be possible to refactor that, too?
> Seems more difficult, because we would need to enable [[Get]] (and
> hence the get trap) to signal lookup failure. (Too bad that we cannot
> reuse `undefined' for it.) But I think the current situation isn't
I agree, the current specification style is fine when we are dealing with side-effectly free internal operations but as soon as they are reified they become problematic and a performance issue.
I believe that the [[HasProperty]] [[Get]] combination is always used in situations where a "conditional [[Get]]" is desired. I suggest that we redefine [[Get]] to take a second optional argument which is used as a signal value to indicated that the property does not exist. Internally (within the specification) any unique object value can be used as the signal value as the spec. will never allow that value to escape such that it could be stored as a property value.
A similar approach could be taken with the trap and Object.getProperty APIs but there is the hazard that handler code might capture and misuse (store into a property) the signal value. It isn't clear to me whether this would constitute an exploitable hazard or whether it would just be an annoying bug. This capture problem could be avoid if the trap always passed a new object to the handler when the [[Get]] call uses its second argument. I'm reluctant to impose an (even trivial) object allocation on [[Get]] traps but it probably is still less overhead then making two traps. Also, it would not be needed in situations where the [[Get]] only had a single argument.
Using this approach, the get handler signature could be something like: function(receiver, name, target, proxy, missingMarker=undefined)
and the signature for Object.getProperty could be: function(receiver, name, missingMarker=undefined, parent=receiver)
(for the optional argument ordering, I'm assuming that use of a missingMarker is more common then using an explicit parent)
Given the limitations of ES function protocol the moral equivalent of either reference parameters or multiple value returns also require an object allocation. It isn't clear that we can do much better than this style of API. If we do this we should be able to eliminate both the [[HasProperty]] internal method and the has trap.
More information about the es-discuss