On revoking access to the target of a proxy

David Bruant bruant.d at gmail.com
Fri Aug 3 14:03:43 PDT 2012


Hi,

I spent a couple of hours presenting proxies to a couple of folks at the 
IDRC (Inclusive Design Research Center) in Toronto and Colin Clark (IDRC 
Tech Lead) made me realize that we have lost something between the 
previous proxy design and the current one. This is related to the 
caretaker and membrane patterns and garbage collection.

     // With the previous proxy design:
     var handler = {
         get: function(){
             something(target)
         },
         set: function(){
             somethingElse(target)
         },
         target : {};
     }
     function revoke(){
         handler.target = null;
     }

On calling the revoke method, access to the target will cause error to 
be thrown when the proxy is touched. Additionally, if this was the only 
reference to the target, the target can be garbage collected. This 
scales also for a membrane where revoke can lead to the garbage 
collection of an arbitrary number of objects.

With the current design, there is no way to cut the access to the target 
and enable its garbage collection because the target is an internal 
property of the proxy. It means that malicious or buggy code keeping a 
reference to the proxy keeps a reference to the target.

As a matter of fact, I've recently had this problem of a library keeping 
references to a large files and ending up crashing the (node.js) process 
because of memory overflow. Having the ability to cut the reference 
would likely allow to garbage collect the content and solve the problem.
I should mention also the "Huey fix" [1][2] which is a real-world use of 
the caretaker pattern used for the sake of memory consumption.

Proposals (first shot at least):
* A Proxy.revokeTarget(proxy) & corresponding revokeTarget trap (returns 
a boolean to decide whether to procede or not). After the access to the 
target has been revoked, any attempt to touch the proxy throws an 
exception without trapping (very much like transferable objects when 
they've been transfered IIRC).
If no revokeTarget trap is provided, the target is not revoked (return 
false by default).
Called on a non-proxy object, Proxy.revokeTarget does nothing.
Of course, if someone else holds a reference to the target, it is not 
garbage-collected no matter how many proxies have been revoked access to it.
* Alternatively, the proxy constructor returns a pair so that only the 
proxy creator has access to the revoke method (removes the need for the 
trap). But it induces boilerplate when you don't care about revokability.
* Alternatively, having 2 constructors, Proxy and RevokableProxy. The 
former is the one for current direct proxies, the latter returns a pair 
as described in the second proposal.

David

[1] http://blog.kylehuey.com/post/21892343371/fixing-the-memory-leak
[2] 
https://blog.mozilla.org/nnethercote/2012/05/15/additional-update-on-leaky-add-ons/


More information about the es-discuss mailing list