[Harmony Proxies] LazyReadCopy experiment and invariant checking for [[Extensible]]=false

David Bruant david.bruant at labri.fr
Wed Jul 13 10:29:40 PDT 2011


Recently, I've been thinking about the structured clone algorithm used
in postMessage
The browser has to do a copy of an object and pass it to the message
receiving context. In some cases, if the object has a lot of properties,
it could be costly to do this copy. So I thought "hey, what about
wrapping it with a proxy and just hand the proxy?".
For the rest of this use case, I will consider myself in the role of the
browser (implementing postMessage and tryiing to do so in JavaScript)
and I may use the "become" primitive if needed since I'm in "privileged

Basically, the proxy has to forward "reads" to the target object, keep
the "writes" internally and make sure future "reads" are consistent if
some "writes" occured.
You can see my implementation of "LazyReadCopy" at:
(I discuss limitations below)

So now we can send an object in the message Receiving Context (RC). This
object is a copy of the one in the message Sending Context (SC). The RC
can manipulate the object and this will have no noticeable effect in the SC.
However, the opposite is not true. If a property is added in the SC, the
RC can read this new property. So, for my implementation to work, I
would need 2 lazy read copies. One for the SC, one for the RC. The one
in the SC can replace the object thanks to the "become" privileged

So far, so good, we have an object, two lazy read copies of it (one in
each context), basic expectations are respected.

Now, consider the following snippet:
var o = {};
Object.isExtensible(o); // false
// The browser replaces o with a lazy read copy of o. That's now a proxy.
Object.isExtensible(o); // true, because it's a proxy :-s
Of course, that's my fault, I shouldn't play too much with the "become"
However I feel that I should be allowed to create non-extensible proxies
to cover this use case.

And well, you probably see my proposal coming: what about doing
invariant-enforcing with [[Extensible]]=false instead of the fix+become?
There would only be a need for a preventExtension fundamental trap
(freeze and seal would be derived or even not trap at all, calling the
preventExtension trap anyway)

I haven't taken the time to try to implement it, but starting from Tom's
FixedHandler implementation [1], it looks like it would be just adding a
this.extensible boolean (and the set of properties can be retrieved from
One-property traps would need a lookup to a property set (hopefully, JS
engines have efficient implementations for that for the "in" operator)
to avoid lies on whether the property is part of the object already or
not. The rest of the one-property traps invariants are already taken
care of by FixedHandler.
Several-property traps (get{Own}PropertyNames, enumerate, keys) could
call the trap, throw away the result and return the set of properties.
The inconvenient of this would be that the user-returned order wouldn't
be respected. The costly alternative is to check that the returned array
isn't adding properties that shouldn't be there.

Another idea is to provide the choice between the invariant-checking
flavor and the "turn me into a normal object" flavor with the return
value of the fix/preventExtension trap.

Any thoughts?

Limitations of my implementation regarding the structured clone algorithm.
* Non-enumerable and inherited properties are not filtered out
* Doing a lazy copy read is not performed recursively
* The object in the receiving context should only have data property, so
if there are accessors, their getters should be called once at copy time
and the result stored in the copy.
(this last point cannot be implemented efficiently in JavaScript, I think)


More information about the es-discuss mailing list