| OLD | NEW | 
|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 //     * Redistributions of source code must retain the above copyright | 6 //     * Redistributions of source code must retain the above copyright | 
| 7 //       notice, this list of conditions and the following disclaimer. | 7 //       notice, this list of conditions and the following disclaimer. | 
| 8 //     * Redistributions in binary form must reproduce the above | 8 //     * Redistributions in binary form must reproduce the above | 
| 9 //       copyright notice, this list of conditions and the following | 9 //       copyright notice, this list of conditions and the following | 
| 10 //       disclaimer in the documentation and/or other materials provided | 10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 27 | 27 | 
| 28 // Flags: --harmony --harmony-proxies | 28 // Flags: --harmony --harmony-proxies | 
| 29 | 29 | 
| 30 | 30 | 
| 31 // A simple no-op handler. Adapted from: |  | 
| 32 // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#examplea_no-op_forward
     ing_proxy |  | 
| 33 |  | 
| 34 function createHandler(obj) { |  | 
| 35   return { |  | 
| 36     getOwnPropertyDescriptor: function(name) { |  | 
| 37       var desc = Object.getOwnPropertyDescriptor(obj, name); |  | 
| 38       if (desc !== undefined) desc.configurable = true; |  | 
| 39       return desc; |  | 
| 40     }, |  | 
| 41     getPropertyDescriptor: function(name) { |  | 
| 42       var desc = Object.getOwnPropertyDescriptor(obj, name); |  | 
| 43       //var desc = Object.getPropertyDescriptor(obj, name);  // not in ES5 |  | 
| 44       if (desc !== undefined) desc.configurable = true; |  | 
| 45       return desc; |  | 
| 46     }, |  | 
| 47     getOwnPropertyNames: function() { |  | 
| 48       return Object.getOwnPropertyNames(obj); |  | 
| 49     }, |  | 
| 50     getPropertyNames: function() { |  | 
| 51       return Object.getOwnPropertyNames(obj); |  | 
| 52       //return Object.getPropertyNames(obj);  // not in ES5 |  | 
| 53     }, |  | 
| 54     defineProperty: function(name, desc) { |  | 
| 55       Object.defineProperty(obj, name, desc); |  | 
| 56     }, |  | 
| 57     delete: function(name) { |  | 
| 58       return delete obj[name]; |  | 
| 59     }, |  | 
| 60     fix: function() { |  | 
| 61       if (Object.isFrozen(obj)) { |  | 
| 62         var result = {}; |  | 
| 63         Object.getOwnPropertyNames(obj).forEach(function(name) { |  | 
| 64           result[name] = Object.getOwnPropertyDescriptor(obj, name); |  | 
| 65         }); |  | 
| 66         return result; |  | 
| 67       } |  | 
| 68       // As long as obj is not frozen, the proxy won't allow itself to be fixed |  | 
| 69       return undefined; // will cause a TypeError to be thrown |  | 
| 70     }, |  | 
| 71     has: function(name) { return name in obj; }, |  | 
| 72     hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); }, |  | 
| 73     get: function(receiver, name) { return obj[name]; }, |  | 
| 74     set: function(receiver, name, val) { |  | 
| 75       obj[name] = val;  // bad behavior when set fails in sloppy mode |  | 
| 76       return true; |  | 
| 77     }, |  | 
| 78     keys: function() { return Object.keys(obj); } |  | 
| 79   }; |  | 
| 80 } |  | 
| 81 |  | 
| 82 |  | 
| 83 |  | 
| 84 // Auxiliary definitions enabling tracking of object identity in output. |  | 
| 85 |  | 
| 86 var objectMap = new WeakMap; |  | 
| 87 var objectCounter = 0; |  | 
| 88 |  | 
| 89 function registerObject(x, s) { |  | 
| 90   if (x === Object(x) && !objectMap.has(x)) |  | 
| 91     objectMap.set(x, ++objectCounter + (s == undefined ? "" : ":" + s)); |  | 
| 92 } |  | 
| 93 |  | 
| 94 registerObject(this, "global"); |  | 
| 95 registerObject(Object.prototype, "Object.prototype"); |  | 
| 96 |  | 
| 97 function str(x) { |  | 
| 98   if (x === Object(x)) return "[" + typeof x + " " + objectMap.get(x) + "]"; |  | 
| 99   if (typeof x == "string") return "\"" + x + "\""; |  | 
| 100   return "" + x; |  | 
| 101 } |  | 
| 102 |  | 
| 103 |  | 
| 104 | 31 | 
| 105 // A simple membrane. Adapted from: | 32 // A simple membrane. Adapted from: | 
| 106 // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#a_simple_membrane | 33 // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#a_simple_membrane | 
| 107 | 34 | 
| 108 function createSimpleMembrane(target) { | 35 function createSimpleMembrane(target) { | 
| 109   var enabled = true; | 36   let enabled = true; | 
| 110 | 37 | 
| 111   function wrap(obj) { | 38   function wrap(obj) { | 
| 112     registerObject(obj); | 39     if (obj !== Object(obj)) return obj; | 
| 113     print("wrap enter", str(obj)); | 40 | 
| 114     try { | 41     let handler = new Proxy({}, {get: function(_, key) { | 
| 115       var x = wrap2(obj); | 42       if (!enabled) throw new Error("disabled"); | 
| 116       registerObject(x, "wrapped"); | 43       switch (key) { | 
| 117       print("wrap exit", str(obj), "as", str(x)); | 44       case "apply": | 
| 118       return x; | 45         return (_, that, args) => { | 
| 119     } catch(e) { | 46           try { | 
| 120       print("wrap exception", str(e)); | 47             return wrap(Reflect.apply( | 
| 121       throw e; | 48                 obj, wrap(that), args.map((x) => wrap(x)))); | 
| 122     } | 49           } catch(e) { | 
|  | 50             throw wrap(e); | 
|  | 51           } | 
|  | 52         } | 
|  | 53       case "construct": | 
|  | 54         return (_, args, newt) => { | 
|  | 55           try { | 
|  | 56             return wrap(Reflect.construct( | 
|  | 57                 obj, args.map((x) => wrap(x)), wrap(newt))); | 
|  | 58           } catch(e) { | 
|  | 59             throw wrap(e); | 
|  | 60           } | 
|  | 61         } | 
|  | 62       default: | 
|  | 63         return (_, ...args) => { | 
|  | 64           try { | 
|  | 65             return wrap(Reflect[key](obj, ...(args.map(wrap)))); | 
|  | 66           } catch(e) { | 
|  | 67             throw wrap(e); | 
|  | 68           } | 
|  | 69         } | 
|  | 70       } | 
|  | 71     }}); | 
|  | 72 | 
|  | 73     return new Proxy(obj, handler); | 
| 123   } | 74   } | 
| 124 | 75 | 
| 125   function wrap2(obj) { | 76   const gate = Object.freeze({ | 
| 126     if (obj !== Object(obj)) { | 77     enable: () => enabled = true, | 
| 127       return obj; | 78     disable: () => enabled = false | 
| 128     } |  | 
| 129 |  | 
| 130     function wrapCall(fun, that, args) { |  | 
| 131       registerObject(that); |  | 
| 132       print("wrapCall enter", fun, str(that)); |  | 
| 133       try { |  | 
| 134         var x = wrapCall2(fun, that, args); |  | 
| 135         print("wrapCall exit", fun, str(that), "returning", str(x)); |  | 
| 136         return x; |  | 
| 137       } catch(e) { |  | 
| 138         print("wrapCall exception", fun, str(that), str(e)); |  | 
| 139         throw e; |  | 
| 140       } |  | 
| 141     } |  | 
| 142 |  | 
| 143     function wrapCall2(fun, that, args) { |  | 
| 144       if (!enabled) { throw new Error("disabled"); } |  | 
| 145       try { |  | 
| 146         return wrap(fun.apply(that, Array.prototype.map.call(args, wrap))); |  | 
| 147       } catch (e) { |  | 
| 148         throw wrap(e); |  | 
| 149       } |  | 
| 150     } |  | 
| 151 |  | 
| 152     var baseHandler = createHandler(obj); |  | 
| 153     var handler = new Proxy({}, Object.freeze({ |  | 
| 154       get: function(receiver, name) { |  | 
| 155         return function() { |  | 
| 156           var arg = (name === "get" || name == "set") ? arguments[1] : ""; |  | 
| 157           print("handler enter", name, arg); |  | 
| 158           var x = wrapCall(baseHandler[name], baseHandler, arguments); |  | 
| 159           print("handler exit", name, arg, "returning", str(x)); |  | 
| 160           return x; |  | 
| 161         } |  | 
| 162       } |  | 
| 163     })); |  | 
| 164     registerObject(baseHandler, "basehandler"); |  | 
| 165     registerObject(handler, "handler"); |  | 
| 166 |  | 
| 167     if (typeof obj === "function") { |  | 
| 168       function callTrap() { |  | 
| 169         print("call trap enter", str(obj), str(this)); |  | 
| 170         var x = wrapCall(obj, wrap(this), arguments); |  | 
| 171         print("call trap exit", str(obj), str(this), "returning", str(x)); |  | 
| 172         return x; |  | 
| 173       } |  | 
| 174       function constructTrap() { |  | 
| 175         if (!enabled) { throw new Error("disabled"); } |  | 
| 176         try { |  | 
| 177           function forward(args) { return obj.apply(this, args) } |  | 
| 178           return wrap(new forward(Array.prototype.map.call(arguments, wrap))); |  | 
| 179         } catch (e) { |  | 
| 180           throw wrap(e); |  | 
| 181         } |  | 
| 182       } |  | 
| 183       return Proxy.createFunction(handler, callTrap, constructTrap); |  | 
| 184     } else { |  | 
| 185       var prototype = wrap(Object.getPrototypeOf(obj)); |  | 
| 186       return new Proxy(prototype, handler); |  | 
| 187     } |  | 
| 188   } |  | 
| 189 |  | 
| 190   var gate = Object.freeze({ |  | 
| 191     enable: function() { enabled = true; }, |  | 
| 192     disable: function() { enabled = false; } |  | 
| 193   }); | 79   }); | 
| 194 | 80 | 
| 195   return Object.freeze({ | 81   return Object.freeze({ | 
| 196     wrapper: wrap(target), | 82     wrapper: wrap(target), | 
| 197     gate: gate | 83     gate: gate | 
| 198   }); | 84   }); | 
| 199 } | 85 } | 
| 200 | 86 | 
| 201 | 87 | 
| 202 var o = { | 88 // Test the simple membrane. | 
| 203   a: 6, | 89 { | 
| 204   b: {bb: 8}, | 90   var o = { | 
| 205   f: function(x) { return x }, | 91     a: 6, | 
| 206   g: function(x) { return x.a }, | 92     b: {bb: 8}, | 
| 207   h: function(x) { this.q = x } | 93     f: function(x) { return x }, | 
| 208 }; | 94     g: function(x) { return x.a }, | 
| 209 o[2] = {c: 7}; | 95     h: function(x) { this.q = x } | 
| 210 var m = createSimpleMembrane(o); | 96   }; | 
| 211 var w = m.wrapper; | 97   o[2] = {c: 7}; | 
| 212 print("o =", str(o)) | 98   var m = createSimpleMembrane(o); | 
| 213 print("w =", str(w)); | 99   var w = m.wrapper; | 
| 214 | 100   var f = w.f; | 
| 215 var f = w.f; | 101   var x = f(66); | 
| 216 var x = f(66); | 102   var x = f({a: 1}); | 
| 217 var x = f({a: 1}); | 103   var x = w.f({a: 1}); | 
| 218 var x = w.f({a: 1}); | 104   var a = x.a; | 
| 219 var a = x.a; | 105   assertEquals(6, w.a); | 
| 220 assertEquals(6, w.a); | 106   assertEquals(8, w.b.bb); | 
| 221 assertEquals(8, w.b.bb); | 107   assertEquals(7, w[2]["c"]); | 
| 222 assertEquals(7, w[2]["c"]); | 108   assertEquals(undefined, w.c); | 
| 223 assertEquals(undefined, w.c); | 109   assertEquals(1, w.f(1)); | 
| 224 assertEquals(1, w.f(1)); | 110   assertEquals(1, w.f({a: 1}).a); | 
| 225 assertEquals(1, w.f({a: 1}).a); | 111   assertEquals(2, w.g({a: 2})); | 
| 226 assertEquals(2, w.g({a: 2})); | 112   assertEquals(3, (w.r = {a: 3}).a); | 
| 227 assertEquals(3, (w.r = {a: 3}).a); | 113   assertEquals(3, w.r.a); | 
| 228 assertEquals(3, w.r.a); | 114   assertEquals(3, o.r.a); | 
| 229 assertEquals(3, o.r.a); | 115   w.h(3); | 
| 230 w.h(3); | 116   assertEquals(3, w.q); | 
| 231 assertEquals(3, w.q); | 117   assertEquals(3, o.q); | 
| 232 assertEquals(3, o.q); | 118   assertEquals(4, (new w.h(4)).q); | 
| 233 assertEquals(4, (new w.h(4)).q); | 119 | 
| 234 | 120   var wb = w.b; | 
| 235 var wb = w.b; | 121   var wr = w.r; | 
| 236 var wr = w.r; | 122   var wf = w.f; | 
| 237 var wf = w.f; | 123   var wf3 = w.f(3); | 
| 238 var wf3 = w.f(3); | 124   var wfx = w.f({a: 6}); | 
| 239 var wfx = w.f({a: 6}); | 125   var wgx = w.g({a: {aa: 7}}); | 
| 240 var wgx = w.g({a: {aa: 7}}); | 126   var wh4 = new w.h(4); | 
| 241 var wh4 = new w.h(4); | 127   m.gate.disable(); | 
| 242 m.gate.disable(); | 128   assertEquals(3, wf3); | 
| 243 assertEquals(3, wf3); | 129   assertThrows(function() { w.a }, Error); | 
| 244 assertThrows(function() { w.a }, Error); | 130   assertThrows(function() { w.r }, Error); | 
| 245 assertThrows(function() { w.r }, Error); | 131   assertThrows(function() { w.r = {a: 4} }, Error); | 
| 246 assertThrows(function() { w.r = {a: 4} }, Error); | 132   assertThrows(function() { o.r.a }, Error); | 
| 247 assertThrows(function() { o.r.a }, Error); | 133   assertEquals("object", typeof o.r); | 
| 248 assertEquals("object", typeof o.r); | 134   assertEquals(5, (o.r = {a: 5}).a); | 
| 249 assertEquals(5, (o.r = {a: 5}).a); | 135   assertEquals(5, o.r.a); | 
| 250 assertEquals(5, o.r.a); | 136   assertThrows(function() { w[1] }, Error); | 
| 251 assertThrows(function() { w[1] }, Error); | 137   assertThrows(function() { w.c }, Error); | 
| 252 assertThrows(function() { w.c }, Error); | 138   assertThrows(function() { wb.bb }, Error); | 
| 253 assertThrows(function() { wb.bb }, Error); | 139   assertThrows(function() { wr.a }, Error); | 
| 254 assertThrows(function() { wr.a }, Error); | 140   assertThrows(function() { wf(4) }, Error); | 
| 255 assertThrows(function() { wf(4) }, Error); | 141   assertThrows(function() { wfx.a }, Error); | 
| 256 assertThrows(function() { wfx.a }, Error); | 142   assertThrows(function() { wgx.aa }, Error); | 
| 257 assertThrows(function() { wgx.aa }, Error); | 143   assertThrows(function() { wh4.q }, Error); | 
| 258 assertThrows(function() { wh4.q }, Error); | 144 | 
| 259 | 145   m.gate.enable(); | 
| 260 m.gate.enable(); | 146   assertEquals(6, w.a); | 
| 261 assertEquals(6, w.a); | 147   assertEquals(5, w.r.a); | 
| 262 assertEquals(5, w.r.a); | 148   assertEquals(5, o.r.a); | 
| 263 assertEquals(5, o.r.a); | 149   assertEquals(7, w.r = 7); | 
| 264 assertEquals(7, w.r = 7); | 150   assertEquals(7, w.r); | 
| 265 assertEquals(7, w.r); | 151   assertEquals(7, o.r); | 
| 266 assertEquals(7, o.r); | 152   assertEquals(8, w.b.bb); | 
| 267 assertEquals(8, w.b.bb); | 153   assertEquals(7, w[2]["c"]); | 
| 268 assertEquals(7, w[2]["c"]); | 154   assertEquals(undefined, w.c); | 
| 269 assertEquals(undefined, w.c); | 155   assertEquals(8, wb.bb); | 
| 270 assertEquals(8, wb.bb); | 156   assertEquals(3, wr.a); | 
| 271 assertEquals(3, wr.a); | 157   assertEquals(4, wf(4)); | 
| 272 assertEquals(4, wf(4)); | 158   assertEquals(3, wf3); | 
| 273 assertEquals(3, wf3); | 159   assertEquals(6, wfx.a); | 
| 274 assertEquals(6, wfx.a); | 160   assertEquals(7, wgx.aa); | 
| 275 assertEquals(7, wgx.aa); | 161   assertEquals(4, wh4.q); | 
| 276 assertEquals(4, wh4.q); | 162 } | 
|  | 163 | 
| 277 | 164 | 
| 278 | 165 | 
| 279 // An identity-preserving membrane. Adapted from: | 166 // An identity-preserving membrane. Adapted from: | 
| 280 // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_identity-preserving
     _membrane | 167 // http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_identity-preserving
     _membrane | 
| 281 | 168 | 
| 282 function createMembrane(wetTarget) { | 169 function createMembrane(target) { | 
| 283   var wet2dry = new WeakMap(); | 170   const wet2dry = 0; | 
| 284   var dry2wet = new WeakMap(); | 171   const dry2wet = 1; | 
| 285 | 172 | 
| 286   function asDry(obj) { | 173   function flip(dir) { return (dir + 1) % 2 } | 
| 287     registerObject(obj) | 174 | 
| 288     print("asDry enter", str(obj)) | 175   let maps = [new WeakMap(), new WeakMap()]; | 
| 289     try { | 176 | 
| 290       var x = asDry2(obj); | 177   let revoked = false; | 
| 291       registerObject(x, "dry"); | 178 | 
| 292       print("asDry exit", str(obj), "as", str(x)); | 179   function wrap(dir, obj) { | 
| 293       return x; | 180     if (obj !== Object(obj)) return obj; | 
| 294     } catch(e) { | 181 | 
| 295       print("asDry exception", str(e)); | 182     let wrapper = maps[dir].get(obj); | 
| 296       throw e; | 183     if (wrapper) return wrapper; | 
| 297     } | 184 | 
|  | 185     let handler = new Proxy({}, {get: function(_, key) { | 
|  | 186       if (revoked) throw new Error("revoked"); | 
|  | 187       switch (key) { | 
|  | 188       case "apply": | 
|  | 189         return (_, that, args) => { | 
|  | 190           try { | 
|  | 191             return wrap(dir, Reflect.apply( | 
|  | 192                 obj, wrap(flip(dir), that), | 
|  | 193                 args.map((x) => wrap(flip(dir), x)))); | 
|  | 194           } catch(e) { | 
|  | 195             throw wrap(dir, e); | 
|  | 196           } | 
|  | 197         } | 
|  | 198       case "construct": | 
|  | 199         return (_, args, newt) => { | 
|  | 200           try { | 
|  | 201             return wrap(dir, Reflect.construct( | 
|  | 202                 obj, args.map((x) => wrap(flip(dir), x)), | 
|  | 203                 wrap(flip(dir), newt))); | 
|  | 204           } catch(e) { | 
|  | 205             throw wrap(dir, e); | 
|  | 206           } | 
|  | 207         } | 
|  | 208       default: | 
|  | 209         return (_, ...args) => { | 
|  | 210           try { | 
|  | 211             return wrap(dir, Reflect[key]( | 
|  | 212                 obj, ...(args.map((x) => wrap(flip(dir), x))))) | 
|  | 213           } catch(e) { | 
|  | 214             throw wrap(dir, e); | 
|  | 215           } | 
|  | 216         } | 
|  | 217       } | 
|  | 218     }}); | 
|  | 219 | 
|  | 220     wrapper = new Proxy(obj, handler); | 
|  | 221     maps[dir].set(obj, wrapper); | 
|  | 222     maps[flip(dir)].set(wrapper, obj); | 
|  | 223     return wrapper; | 
| 298   } | 224   } | 
| 299   function asDry2(wet) { | 225 | 
| 300     if (wet !== Object(wet)) { | 226   const gate = Object.freeze({ | 
| 301       // primitives provide only irrevocable knowledge, so don't | 227     revoke: () => revoked = true | 
| 302       // bother wrapping it. | 228   }); | 
| 303       return wet; | 229 | 
| 304     } | 230   return Object.freeze({ | 
| 305     var dryResult = wet2dry.get(wet); | 231     wrapper: wrap(wet2dry, target), | 
| 306     if (dryResult) { return dryResult; } | 232     gate: gate | 
| 307 | 233   }); | 
| 308     var wetHandler = createHandler(wet); | 234 } | 
| 309     var dryRevokeHandler = new Proxy({}, Object.freeze({ | 235 | 
| 310       get: function(receiver, name) { | 236 | 
| 311         return function() { | 237 // Test the identity-preserving membrane. | 
| 312           var arg = (name === "get" || name == "set") ? arguments[1] : ""; | 238 { | 
| 313           print("dry handler enter", name, arg); | 239   var receiver | 
| 314           var optWetHandler = dry2wet.get(dryRevokeHandler); | 240   var argument | 
| 315           try { | 241   var o = { | 
| 316             var x = asDry(optWetHandler[name].apply( | 242     a: 6, | 
| 317               optWetHandler, Array.prototype.map.call(arguments, asWet))); | 243     b: {bb: 8}, | 
| 318             print("dry handler exit", name, arg, "returning", str(x)); | 244     f: function(x) {receiver = this; argument = x; return x}, | 
| 319             return x; | 245     g: function(x) {receiver = this; argument = x; return x.a}, | 
| 320           } catch (eWet) { | 246     h: function(x) {receiver = this; argument = x; this.q = x}, | 
| 321             var x = asDry(eWet); | 247     s: function(x) {receiver = this; argument = x; this.x = {y: x}; return this} | 
| 322             print("dry handler exception", name, arg, "throwing", str(x)); |  | 
| 323             throw x; |  | 
| 324           } |  | 
| 325         }; |  | 
| 326       } |  | 
| 327     })); |  | 
| 328     dry2wet.set(dryRevokeHandler, wetHandler); |  | 
| 329 |  | 
| 330     if (typeof wet === "function") { |  | 
| 331       function callTrap() { |  | 
| 332         print("dry call trap enter", str(this)); |  | 
| 333         var x = asDry(wet.apply( |  | 
| 334           asWet(this), Array.prototype.map.call(arguments, asWet))); |  | 
| 335         print("dry call trap exit", str(this), "returning", str(x)); |  | 
| 336         return x; |  | 
| 337       } |  | 
| 338       function constructTrap() { |  | 
| 339         function forward(args) { return wet.apply(this, args) } |  | 
| 340         return asDry(new forward(Array.prototype.map.call(arguments, asWet))); |  | 
| 341       } |  | 
| 342       dryResult = |  | 
| 343         Proxy.createFunction(dryRevokeHandler, callTrap, constructTrap); |  | 
| 344     } else { |  | 
| 345       dryResult = |  | 
| 346         new Proxy(asDry(Object.getPrototypeOf(wet)), dryRevokeHandler); |  | 
| 347     } |  | 
| 348     wet2dry.set(wet, dryResult); |  | 
| 349     dry2wet.set(dryResult, wet); |  | 
| 350     return dryResult; |  | 
| 351   } | 248   } | 
| 352 | 249   o[2] = {c: 7} | 
| 353   function asWet(obj) { | 250   var m = createMembrane(o) | 
| 354     registerObject(obj) | 251   var w = m.wrapper | 
| 355     print("asWet enter", str(obj)) | 252   var f = w.f | 
| 356     try { | 253   var x = f(66) | 
| 357       var x = asWet2(obj) | 254   var x = f({a: 1}) | 
| 358       registerObject(x, "wet") | 255   var x = w.f({a: 1}) | 
| 359       print("asWet exit", str(obj), "as", str(x)) | 256   var a = x.a | 
| 360       return x | 257   assertEquals(6, w.a) | 
| 361     } catch(e) { | 258   assertEquals(8, w.b.bb) | 
| 362       print("asWet exception", str(e)) | 259   assertEquals(7, w[2]["c"]) | 
| 363       throw e | 260   assertEquals(undefined, w.c) | 
| 364     } | 261   assertEquals(1, w.f(1)) | 
| 365   } | 262   assertSame(o, receiver) | 
| 366   function asWet2(dry) { | 263   assertEquals(1, w.f({a: 1}).a) | 
| 367     if (dry !== Object(dry)) { | 264   assertSame(o, receiver) | 
| 368       // primitives provide only irrevocable knowledge, so don't | 265   assertEquals(2, w.g({a: 2})) | 
| 369       // bother wrapping it. | 266   assertSame(o, receiver) | 
| 370       return dry; | 267   assertSame(w, w.f(w)) | 
| 371     } | 268   assertSame(o, receiver) | 
| 372     var wetResult = dry2wet.get(dry); | 269   assertSame(o, argument) | 
| 373     if (wetResult) { return wetResult; } | 270   assertSame(o, w.f(o)) | 
| 374 | 271   assertSame(o, receiver) | 
| 375     var dryHandler = createHandler(dry); | 272   // Note that argument !== o, since o isn't dry, so gets wrapped wet again. | 
| 376     var wetRevokeHandler = new Proxy({}, Object.freeze({ | 273   assertEquals(3, (w.r = {a: 3}).a) | 
| 377       get: function(receiver, name) { | 274   assertEquals(3, w.r.a) | 
| 378         return function() { | 275   assertEquals(3, o.r.a) | 
| 379           var arg = (name === "get" || name == "set") ? arguments[1] : ""; | 276   w.h(3) | 
| 380           print("wet handler enter", name, arg); | 277   assertEquals(3, w.q) | 
| 381           var optDryHandler = wet2dry.get(wetRevokeHandler); | 278   assertEquals(3, o.q) | 
| 382           try { | 279   assertEquals(4, (new w.h(4)).q) | 
| 383             var x = asWet(optDryHandler[name].apply( | 280   assertEquals(5, w.s(5).x.y) | 
| 384               optDryHandler, Array.prototype.map.call(arguments, asDry))); | 281   assertSame(o, receiver) | 
| 385             print("wet handler exit", name, arg, "returning", str(x)); | 282 | 
| 386             return x; | 283   var wb = w.b | 
| 387           } catch (eDry) { | 284   var wr = w.r | 
| 388             var x = asWet(eDry); | 285   var wf = w.f | 
| 389             print("wet handler exception", name, arg, "throwing", str(x)); | 286   var wf3 = w.f(3) | 
| 390             throw x; | 287   var wfx = w.f({a: 6}) | 
| 391           } | 288   var wgx = w.g({a: {aa: 7}}) | 
| 392         }; | 289   var wh4 = new w.h(4) | 
| 393       } | 290   var ws5 = w.s(5) | 
| 394     })); | 291   var ws5x = ws5.x | 
| 395     wet2dry.set(wetRevokeHandler, dryHandler); | 292   m.gate.revoke() | 
| 396 | 293   assertEquals(3, wf3) | 
| 397     if (typeof dry === "function") { | 294   assertThrows(function() { w.a }, Error) | 
| 398       function callTrap() { | 295   assertThrows(function() { w.r }, Error) | 
| 399         print("wet call trap enter", str(this)); | 296   assertThrows(function() { w.r = {a: 4} }, Error) | 
| 400         var x = asWet(dry.apply( | 297   assertThrows(function() { o.r.a }, Error) | 
| 401           asDry(this), Array.prototype.map.call(arguments, asDry))); | 298   assertEquals("object", typeof o.r) | 
| 402         print("wet call trap exit", str(this), "returning", str(x)); | 299   assertEquals(5, (o.r = {a: 5}).a) | 
| 403         return x; | 300   assertEquals(5, o.r.a) | 
| 404       } | 301   assertThrows(function() { w[1] }, Error) | 
| 405       function constructTrap() { | 302   assertThrows(function() { w.c }, Error) | 
| 406         function forward(args) { return dry.apply(this, args) } | 303   assertThrows(function() { wb.bb }, Error) | 
| 407         return asWet(new forward(Array.prototype.map.call(arguments, asDry))); | 304   assertEquals(3, wr.a) | 
| 408       } | 305   assertThrows(function() { wf(4) }, Error) | 
| 409       wetResult = | 306   assertEquals(6, wfx.a) | 
| 410         Proxy.createFunction(wetRevokeHandler, callTrap, constructTrap); | 307   assertEquals(7, wgx.aa) | 
| 411     } else { | 308   assertThrows(function() { wh4.q }, Error) | 
| 412       wetResult = | 309   assertThrows(function() { ws5.x }, Error) | 
| 413         new Proxy(asWet(Object.getPrototypeOf(dry)), wetRevokeHandler); | 310   assertThrows(function() { ws5x.y }, Error) | 
| 414     } | 311 } | 
| 415     dry2wet.set(dry, wetResult); |  | 
| 416     wet2dry.set(wetResult, dry); |  | 
| 417     return wetResult; |  | 
| 418   } |  | 
| 419 |  | 
| 420   var gate = Object.freeze({ |  | 
| 421     revoke: function() { |  | 
| 422       dry2wet = wet2dry = Object.freeze({ |  | 
| 423         get: function(key) { throw new Error("revoked"); }, |  | 
| 424         set: function(key, val) { throw new Error("revoked"); } |  | 
| 425       }); |  | 
| 426     } |  | 
| 427   }); |  | 
| 428 |  | 
| 429   return Object.freeze({ wrapper: asDry(wetTarget), gate: gate }); |  | 
| 430 } |  | 
| 431 |  | 
| 432 |  | 
| 433 var receiver |  | 
| 434 var argument |  | 
| 435 var o = { |  | 
| 436   a: 6, |  | 
| 437   b: {bb: 8}, |  | 
| 438   f: function(x) { receiver = this; argument = x; return x }, |  | 
| 439   g: function(x) { receiver = this; argument = x; return x.a }, |  | 
| 440   h: function(x) { receiver = this; argument = x; this.q = x }, |  | 
| 441   s: function(x) { receiver = this; argument = x; this.x = {y: x}; return this } |  | 
| 442 } |  | 
| 443 o[2] = {c: 7} |  | 
| 444 var m = createMembrane(o) |  | 
| 445 var w = m.wrapper |  | 
| 446 print("o =", str(o)) |  | 
| 447 print("w =", str(w)) |  | 
| 448 |  | 
| 449 var f = w.f |  | 
| 450 var x = f(66) |  | 
| 451 var x = f({a: 1}) |  | 
| 452 var x = w.f({a: 1}) |  | 
| 453 var a = x.a |  | 
| 454 assertEquals(6, w.a) |  | 
| 455 assertEquals(8, w.b.bb) |  | 
| 456 assertEquals(7, w[2]["c"]) |  | 
| 457 assertEquals(undefined, w.c) |  | 
| 458 assertEquals(1, w.f(1)) |  | 
| 459 assertSame(o, receiver) |  | 
| 460 assertEquals(1, w.f({a: 1}).a) |  | 
| 461 assertSame(o, receiver) |  | 
| 462 assertEquals(2, w.g({a: 2})) |  | 
| 463 assertSame(o, receiver) |  | 
| 464 assertSame(w, w.f(w)) |  | 
| 465 assertSame(o, receiver) |  | 
| 466 assertSame(o, argument) |  | 
| 467 assertSame(o, w.f(o)) |  | 
| 468 assertSame(o, receiver) |  | 
| 469 // Note that argument !== o, since o isn't dry, so gets wrapped wet again. |  | 
| 470 assertEquals(3, (w.r = {a: 3}).a) |  | 
| 471 assertEquals(3, w.r.a) |  | 
| 472 assertEquals(3, o.r.a) |  | 
| 473 w.h(3) |  | 
| 474 assertEquals(3, w.q) |  | 
| 475 assertEquals(3, o.q) |  | 
| 476 assertEquals(4, (new w.h(4)).q) |  | 
| 477 assertEquals(5, w.s(5).x.y) |  | 
| 478 assertSame(o, receiver) |  | 
| 479 |  | 
| 480 var wb = w.b |  | 
| 481 var wr = w.r |  | 
| 482 var wf = w.f |  | 
| 483 var wf3 = w.f(3) |  | 
| 484 var wfx = w.f({a: 6}) |  | 
| 485 var wgx = w.g({a: {aa: 7}}) |  | 
| 486 var wh4 = new w.h(4) |  | 
| 487 var ws5 = w.s(5) |  | 
| 488 var ws5x = ws5.x |  | 
| 489 m.gate.revoke() |  | 
| 490 assertEquals(3, wf3) |  | 
| 491 assertThrows(function() { w.a }, Error) |  | 
| 492 assertThrows(function() { w.r }, Error) |  | 
| 493 assertThrows(function() { w.r = {a: 4} }, Error) |  | 
| 494 assertThrows(function() { o.r.a }, Error) |  | 
| 495 assertEquals("object", typeof o.r) |  | 
| 496 assertEquals(5, (o.r = {a: 5}).a) |  | 
| 497 assertEquals(5, o.r.a) |  | 
| 498 assertThrows(function() { w[1] }, Error) |  | 
| 499 assertThrows(function() { w.c }, Error) |  | 
| 500 assertThrows(function() { wb.bb }, Error) |  | 
| 501 assertEquals(3, wr.a) |  | 
| 502 assertThrows(function() { wf(4) }, Error) |  | 
| 503 assertEquals(6, wfx.a) |  | 
| 504 assertEquals(7, wgx.aa) |  | 
| 505 assertThrows(function() { wh4.q }, Error) |  | 
| 506 assertThrows(function() { ws5.x }, Error) |  | 
| 507 assertThrows(function() { ws5x.y }, Error) |  | 
| OLD | NEW | 
|---|