Suggestion: Proxy.[[GetOwnProperty]] caching non-configurable, non-writable data descriptors?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Suggestion: Proxy.[[GetOwnProperty]] caching non-configurable, non-writable data descriptors?

Alex Vincent
Proxies are a little slow right now, and maybe the rules of ECMAScript can safely allow for caching a non-configurable, non-writable data descriptor.

Specifically, in ValidateAndApplyPropertyDescriptor from ES8 (section 9.1.6.3, step 7a-iii), we've already shown current and desc both have the following traits:
  1. isDataDescriptor(current) and isDataDescriptor(desc) return true
  2. [[Configurable]] is false
  3. [[Writable]] is false
  4. SameValue(Desc.[[Value]], current.[[Value]]) is true
  5. The [[GetOwnProperty]] or [[DefineOwnProperty]] internal method is executing, indirectly calling ValidateAndApplyPropertyDescriptor for this case.
  6. The [[Get]] or [[Set]] internal methods is probably executing, calling [[GetOwnProperty]] or [[DefineOwnProperty]] for this case.

That is a very specific set of traits.  As I understand it, it means the proxy target's property named P in Proxy.[[GetOwnProperty]] is permanently locked and can never change - and so neither can the proxy ever report a different value.  Therefore, calling on the proxy handler for that property a second time is, at least in my view, either redundant or unnecessarily expensive.

I would suggest that implementers in section 9.5 (Proxy internals) optionally have a private Map where values that are non-configurable and non-writable are stored.  Then [[GetOwnProperty]] could insert a couple of new steps into its algorithm.  Between steps 4 and 5 of the current algorithm, I would add:  "If the optional [[Map]] object exists and [[Map]].has(P) returns true, return [[Map]].get(P)."  In step 17 of the current algorithm, I would add a substep:  "If isDataDescriptor(resultDesc) and resultDesc.[[Writable]] is false and the optional [[Map]] object exists, call [[Map]].set(P, resultDesc).  (If the [[Map]] internal slot exists but does not contain a Map, the [[Map]] may be filled with a Map at this time.)"

I would also suggest similar changes for [[DefineOwnProperty]]. (Section 9.5.6)

Alternatively, if storing a specific descriptor in the Map is unpalatable, the specification could request storing resultDesc.[[Value]] in step 17, and create a new non-configurable, non-writable descriptor before the current step 5.

Also, if a Map is too expensive, the spec could allow for an equivalent native map<string, JSValue> or whatever other appropriate data structure fills the need.

Counter-point (1):  if the intent of the proxy is to treat all property look-ups equally, then caching the non-writable, non-configurable descriptors goes against that intent - because now the trap is invoked only once for properties returning this type of descriptor.  But there's a lot of steps, including invoking a custom proxy handler trap with an unknown number of steps, and a lot of complexity in that trap to ensure what it returns will pass all the assertions in the spec.

Counter-point (2):  I don't know how common it is to have a property descriptor that meets all six criteria at the beginning of this post, in particular that both [[Configurable]] and [[Writable]] are false.  So this does add another pointer, at least to null initially, for the [[Map]] slot.  This is why I am proposing the [[Map]] slot as optional for implementers.  Let the engines decide whether it's warranted or not as an optimization.

Thoughts?


Alex Vincent

Hayward, CA, USA

--
"The first step in confirming there is a bug in someone else's work is confirming there are no bugs in your own."
-- Alexander J. Vincent, June 30, 2001

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Suggestion: Proxy.[[GetOwnProperty]] caching non-configurable, non-writable data descriptors?

Oriol _
Instead of storing the properties in a map, I think you could first call [[GetOwnProperty]] on the target, and if it's not configurable nor writable, return the same descriptor without calling the proxy trap.

However, I disagree with this kind of things. Proxy traps are not only useful because of the value they return, they can also have desirable side-effects.

--Oriol


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Suggestion: Proxy.[[GetOwnProperty]] caching non-configurable, non-writable data descriptors?

Caridy Patino
In reply to this post by Alex Vincent
We had some preliminary discussions around proxies, and how to potentially fix some mistakes from the past, some details here:

But this is very tricky, specially because Proxies were designed with the idea that the handler could also be a Proxy, that’s why we do all the gymnastics in the spec.

V8 has started some effort to improve proxies:
https://v8project.blogspot.com/2017/10/optimizing-proxies.html

My suggestion is to wait and see how far they can go, and we can attempt to change the spec if there is anything that prevent them from achieving a great deal of improvements based on the current spec.

./caridy

On Oct 5, 2017, at 5:50 AM, Alex Vincent <[hidden email]> wrote:

Proxies are a little slow right now, and maybe the rules of ECMAScript can safely allow for caching a non-configurable, non-writable data descriptor.

Specifically, in ValidateAndApplyPropertyDescriptor from ES8 (section 9.1.6.3, step 7a-iii), we've already shown current and desc both have the following traits:
  1. isDataDescriptor(current) and isDataDescriptor(desc) return true
  2. [[Configurable]] is false
  3. [[Writable]] is false
  4. SameValue(Desc.[[Value]], current.[[Value]]) is true
  5. The [[GetOwnProperty]] or [[DefineOwnProperty]] internal method is executing, indirectly calling ValidateAndApplyPropertyDescriptor for this case.
  6. The [[Get]] or [[Set]] internal methods is probably executing, calling [[GetOwnProperty]] or [[DefineOwnProperty]] for this case.

That is a very specific set of traits.  As I understand it, it means the proxy target's property named P in Proxy.[[GetOwnProperty]] is permanently locked and can never change - and so neither can the proxy ever report a different value.  Therefore, calling on the proxy handler for that property a second time is, at least in my view, either redundant or unnecessarily expensive.

I would suggest that implementers in section 9.5 (Proxy internals) optionally have a private Map where values that are non-configurable and non-writable are stored.  Then [[GetOwnProperty]] could insert a couple of new steps into its algorithm.  Between steps 4 and 5 of the current algorithm, I would add:  "If the optional [[Map]] object exists and [[Map]].has(P) returns true, return [[Map]].get(P)."  In step 17 of the current algorithm, I would add a substep:  "If isDataDescriptor(resultDesc) and resultDesc.[[Writable]] is false and the optional [[Map]] object exists, call [[Map]].set(P, resultDesc).  (If the [[Map]] internal slot exists but does not contain a Map, the [[Map]] may be filled with a Map at this time.)"

I would also suggest similar changes for [[DefineOwnProperty]]. (Section 9.5.6)

Alternatively, if storing a specific descriptor in the Map is unpalatable, the specification could request storing resultDesc.[[Value]] in step 17, and create a new non-configurable, non-writable descriptor before the current step 5.

Also, if a Map is too expensive, the spec could allow for an equivalent native map<string, JSValue> or whatever other appropriate data structure fills the need.

Counter-point (1):  if the intent of the proxy is to treat all property look-ups equally, then caching the non-writable, non-configurable descriptors goes against that intent - because now the trap is invoked only once for properties returning this type of descriptor.  But there's a lot of steps, including invoking a custom proxy handler trap with an unknown number of steps, and a lot of complexity in that trap to ensure what it returns will pass all the assertions in the spec.

Counter-point (2):  I don't know how common it is to have a property descriptor that meets all six criteria at the beginning of this post, in particular that both [[Configurable]] and [[Writable]] are false.  So this does add another pointer, at least to null initially, for the [[Map]] slot.  This is why I am proposing the [[Map]] slot as optional for implementers.  Let the engines decide whether it's warranted or not as an optimization.

Thoughts?


Alex Vincent

Hayward, CA, USA

--
"The first step in confirming there is a bug in someone else's work is confirming there are no bugs in your own."
-- Alexander J. Vincent, June 30, 2001
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Suggestion: Proxy.[[GetOwnProperty]] caching non-configurable, non-writable data descriptors?

Alex Vincent
In reply to this post by Alex Vincent

---------- Forwarded message ----------
From: Oriol _ <[hidden email]>
Instead of storing the properties in a map, I think you could first call [[GetOwnProperty]] on the target, and if it's not configurable nor writable, return the same descriptor without calling the proxy trap.

I believe that's what my original suggestion was.

However, I disagree with this kind of things. Proxy traps are not only useful because of the value they return, they can also have desirable side-effects.

--Oriol
 
You make an annoyingly good point here... :-) I made a similar point a few months ago to someone who wanted to create a "hybrid" object which hid the proxy as the prototype of a regular object, for speed.  *shudder*

That said, I still believe the algorithm I pointed out goes through a lot of steps that can be unnecessary in the scenario I laid out... except that the creator of the proxy has no way of telling the implementing engine that.  There's no "proxy configuration options" that I can modify to pass these optimizing hints to the engine.  Maybe that's something we might need.

I know, this is quite a stretch, suggesting more API for proxies.  (I still want Reflect.parse to happen, after all, and unlike kai zhu, I think operator overloading is a good thing...)  I "blame" (actually, credit) Tom van Cutsem for that, as he made a suggestion about optional properties being an object in my own Membrane API recently.  It was a good idea there, and for other algorithmic shortcuts in proxy traps, it might be a good idea here.

I also take Caridy's point about Google Chrome 62's optimizations that are coming.  I didn't know that was actually happening until Caridy posted about it here. 

Thanks for your response, though:  it's nice to know someone cares about this.

Alex

--
"The first step in confirming there is a bug in someone else's work is confirming there are no bugs in your own."
-- Alexander J. Vincent, June 30, 2001

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss