Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Unified Diff: test/mjsunit/harmony/proxies-example-membrane.js

Issue 8392038: A more holistic test case for proxies. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/mjsunit/harmony/proxies-example-membrane.js
diff --git a/test/mjsunit/harmony/proxies-example-membrane.js b/test/mjsunit/harmony/proxies-example-membrane.js
new file mode 100644
index 0000000000000000000000000000000000000000..817b6359de03ecb16aa3979bc6d604dcacdf2349
--- /dev/null
+++ b/test/mjsunit/harmony/proxies-example-membrane.js
@@ -0,0 +1,510 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony
+
+
+// A simple no-op handler. Adapted from:
+// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#examplea_no-op_forwarding_proxy
Michael Starzinger 2011/10/28 12:08:34 I am not sure about the policy for long URLs in co
+
+function createHandler(obj) {
+ return {
+ getOwnPropertyDescriptor: function(name) {
+ var desc = Object.getOwnPropertyDescriptor(obj, name);
+ if (desc !== undefined) desc.configurable = true;
+ return desc;
+ },
+ getPropertyDescriptor: function(name) {
+ var desc = Object.getOwnPropertyDescriptor(obj, name);
+ //var desc = Object.getPropertyDescriptor(obj, name); // not in ES5
+ if (desc !== undefined) desc.configurable = true;
+ return desc;
+ },
+ getOwnPropertyNames: function() {
+ return Object.getOwnPropertyNames(obj);
+ },
+ getPropertyNames: function() {
+ return Object.getOwnPropertyNames(obj);
+ //return Object.getPropertyNames(obj); // not in ES5
+ },
+ defineProperty: function(name, desc) {
+ Object.defineProperty(obj, name, desc);
+ },
+ delete: function(name) {
+ return delete obj[name];
+ },
+ fix: function() {
+ if (Object.isFrozen(obj)) {
+ var result = {};
+ Object.getOwnPropertyNames(obj).forEach(function(name) {
+ result[name] = Object.getOwnPropertyDescriptor(obj, name);
+ });
+ return result;
+ }
+ // As long as obj is not frozen, the proxy won't allow itself to be fixed
+ return undefined; // will cause a TypeError to be thrown
+ },
+ has: function(name) { return name in obj; },
+ hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
+ get: function(receiver, name) { return obj[name]; },
+ set: function(receiver, name, val) {
+ obj[name] = val; // bad behavior when set fails in non-strict mode
+ return true;
+ },
+ enumerate: function() {
+ var result = [];
+ for (var name in obj) { result.push(name); };
+ return result;
+ },
+ keys: function() { return Object.keys(obj); }
+ };
+}
+
+
+
+// Auxiliary definitions enabling tracking of object identity in output.
+
+var objectMap = new WeakMap;
+var objectCounter = 0;
+
+function registerObject(x, s) {
+ if (x === Object(x) && !objectMap.has(x))
+ objectMap.set(x, ++objectCounter + (s == undefined ? "" : ":" + s));
+}
+
+registerObject(this, "global");
+registerObject(Object.prototype, "Object.prototype");
+
+function str(x) {
+ if (x === Object(x)) return "[" + typeof x + " " + objectMap.get(x) + "]";
+ if (typeof x == "string") return "\"" + x + "\"";
+ return "" + x;
+}
+
+
+
+// A simple membrane. Adapted from:
+// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#a_simple_membrane
+
+function createSimpleMembrane(target) {
+ var enabled = true;
+
+ function wrap(obj) {
+ registerObject(obj);
+ print("wrap enter", str(obj));
+ try {
+ var x = wrap2(obj);
+ registerObject(x, "wrapped");
+ print("wrap exit", str(obj), "as", str(x));
+ return x;
+ } catch(e) {
+ print("wrap exception", str(e));
+ throw e;
+ }
+ }
+
+ function wrap2(obj) {
+ if (obj !== Object(obj)) {
+ return obj;
+ }
+
+ function wrapCall(fun, that, args) {
+ registerObject(that);
+ print("wrapCall enter", fun, str(that));
+ try {
+ var x = wrapCall2(fun, that, args);
+ print("wrapCall exit", fun, str(that), "returning", str(x));
+ return x;
+ } catch(e) {
+ print("wrapCall exception", fun, str(that), str(e));
+ throw e;
+ }
+ }
+
+ function wrapCall2(fun, that, args) {
+ if (!enabled) { throw new Error("disabled"); }
+ try {
+ return wrap(fun.apply(that, Array.prototype.map.call(args, wrap)));
+ } catch (e) {
+ throw wrap(e);
+ }
+ }
+
+ var baseHandler = createHandler(obj);
+ var handler = Proxy.create(Object.freeze({
+ get: function(receiver, name) {
+ return function() {
+ var arg = (name === "get" || name == "set") ? arguments[1] : "";
+ print("handler enter", name, arg);
+ var x = wrapCall(baseHandler[name], baseHandler, arguments);
+ print("handler exit", name, arg, "returning", str(x));
+ return x;
+ }
+ }
+ }));
+ registerObject(baseHandler, "basehandler");
+ registerObject(handler, "handler");
+
+ if (typeof obj === "function") {
+ function callTrap() {
+ print("call trap enter", str(obj), str(this));
+ var x = wrapCall(obj, wrap(this), arguments);
+ print("call trap exit", str(obj), str(this), "returning", str(x));
+ return x;
+ }
+ function constructTrap() {
+ if (!enabled) { throw new Error("disabled"); }
+ try {
+ function forward(args) { return obj.apply(this, args) }
+ return wrap(new forward(Array.prototype.map.call(arguments, wrap)));
+ } catch (e) {
+ throw wrap(e);
+ }
+ }
+ return Proxy.createFunction(handler, callTrap, constructTrap);
+ } else {
+ var prototype = wrap(Object.getPrototypeOf(obj));
+ return Proxy.create(handler, prototype);
+ }
+ }
+
+ var gate = Object.freeze({
+ enable: function() { enabled = true; },
+ disable: function() { enabled = false; }
+ });
+
+ return Object.freeze({
+ wrapper: wrap(target),
+ gate: gate
+ });
+}
+
+
+var o = {
+ a: 6,
+ b: {bb: 8},
+ f: function(x) { return x },
+ g: function(x) { return x.a },
+ h: function(x) { this.q = x }
+};
+o[2] = {c: 7};
+var m = createSimpleMembrane(o);
+var w = m.wrapper;
+print("w =", str(w));
+
+var f = w.f;
+var x = f(66);
+var x = f({a: 1});
+var x = w.f({a: 1});
+var a = x.a;
+assertEquals(6, w.a);
+assertEquals(8, w.b.bb);
+assertEquals(7, w[2]["c"]);
+assertEquals(undefined, w.c);
+assertEquals(1, w.f(1));
+assertEquals(1, w.f({a: 1}).a);
+assertEquals(2, w.g({a: 2}));
+assertEquals(3, (w.r = {a: 3}).a);
+assertEquals(3, w.r.a);
+assertEquals(3, o.r.a);
+w.h(3);
+assertEquals(3, w.q);
+assertEquals(3, o.q);
+assertEquals(4, (new w.h(4)).q);
+
+var wb = w.b;
+var wr = w.r;
+var wf = w.f;
+var wf3 = w.f(3);
+var wfx = w.f({a: 6});
+var wgx = w.g({a: {aa: 7}});
+var wh4 = new w.h(4);
+m.gate.disable();
+assertEquals(3, wf3);
+assertThrows(function() { w.a }, Error);
+assertThrows(function() { w.r }, Error);
+assertThrows(function() { w.r = {a: 4} }, Error);
+assertThrows(function() { o.r.a }, Error);
+assertEquals("object", typeof o.r);
+assertEquals(5, (o.r = {a: 5}).a);
+assertEquals(5, o.r.a);
+assertThrows(function() { w[1] }, Error);
+assertThrows(function() { w.c }, Error);
+assertThrows(function() { wb.bb }, Error);
+assertThrows(function() { wr.a }, Error);
+assertThrows(function() { wf(4) }, Error);
+assertThrows(function() { wfx.a }, Error);
+assertThrows(function() { wgx.aa }, Error);
+assertThrows(function() { wh4.q }, Error);
+
+m.gate.enable();
+assertEquals(6, w.a);
+assertEquals(5, w.r.a);
+assertEquals(5, o.r.a);
+assertEquals(7, w.r = 7);
+assertEquals(7, w.r);
+assertEquals(7, o.r);
+assertEquals(8, w.b.bb);
+assertEquals(7, w[2]["c"]);
+assertEquals(undefined, w.c);
+assertEquals(8, wb.bb);
+assertEquals(3, wr.a);
+assertEquals(4, wf(4));
+assertEquals(3, wf3);
+assertEquals(6, wfx.a);
+assertEquals(7, wgx.aa);
+assertEquals(4, wh4.q);
+
+
+// An identity-preserving membrane. Adapted from:
+// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_identity-preserving_membrane
Michael Starzinger 2011/10/28 12:08:34 Likewise.
+
+function createMembrane(wetTarget) {
+ var wet2dry = WeakMap();
+ var dry2wet = WeakMap();
+
+ function asDry(obj) {
+ registerObject(obj)
+ print("asDry enter", str(obj))
+ try {
+ var x = asDry2(obj);
+ registerObject(x, "dry");
+ print("asDry exit", str(obj), "as", str(x));
+ return x;
+ } catch(e) {
+ print("asDry exception", str(e));
+ throw e;
+ }
+ }
+ function asDry2(wet) {
+ if (wet !== Object(wet)) {
+ // primitives provide only irrevocable knowledge, so don't
+ // bother wrapping it.
+ return wet;
+ }
+ var dryResult = wet2dry.get(wet);
+ if (dryResult) { return dryResult; }
+
+ var wetHandler = createHandler(wet);
+ var dryRevokeHandler = Proxy.create(Object.freeze({
+ get: function(receiver, name) {
+ return function() {
+ var arg = (name === "get" || name == "set") ? arguments[1] : "";
+ print("dry handler enter", name, arg);
+ var optWetHandler = dry2wet.get(dryRevokeHandler);
+ try {
+ var x = asDry(optWetHandler[name].apply(
+ optWetHandler, Array.prototype.map.call(arguments, asWet)));
+ print("dry handler exit", name, arg, "returning", str(x));
+ return x;
+ } catch (eWet) {
+ var x = asDry(eWet);
+ print("dry handler exception", name, arg, "throwing", str(x));
+ throw x;
+ }
+ };
+ }
+ }));
+ dry2wet.set(dryRevokeHandler, wetHandler);
+
+ if (typeof wet === "function") {
+ function callTrap() {
+ print("dry call trap enter", str(this));
+ var x = asDry(wet.apply(
+ asWet(this), Array.prototype.map.call(arguments, asWet)));
+ print("dry call trap exit", str(this), "returning", str(x));
+ return x;
+ }
+ function constructTrap() {
+ function forward(args) { return wet.apply(this, args) }
+ return asDry(new forward(Array.prototype.map.call(arguments, asWet)));
+ }
+ dryResult =
+ Proxy.createFunction(dryRevokeHandler, callTrap, constructTrap);
+ } else {
+ dryResult =
+ Proxy.create(dryRevokeHandler, asDry(Object.getPrototypeOf(wet)));
+ }
+ wet2dry.set(wet, dryResult);
+ dry2wet.set(dryResult, wet);
+ return dryResult;
+ }
+
+ function asWet(obj) {
+ registerObject(obj)
+ print("asWet enter", str(obj))
+ try {
+ var x = asWet2(obj)
+ registerObject(x, "wet")
+ print("asWet exit", str(obj), "as", str(x))
+ return x
+ } catch(e) {
+ print("asWet exception", str(e))
+ throw e
+ }
+ }
+ function asWet2(dry) {
+ if (dry !== Object(dry)) {
+ // primitives provide only irrevocable knowledge, so don't
+ // bother wrapping it.
+ return dry;
+ }
+ var wetResult = dry2wet.get(dry);
+ if (wetResult) { return wetResult; }
+
+ var dryHandler = createHandler(dry);
+ var wetRevokeHandler = Proxy.create(Object.freeze({
+ get: function(receiver, name) {
+ return function() {
+ var arg = (name === "get" || name == "set") ? arguments[1] : "";
+ print("wet handler enter", name, arg);
+ var optDryHandler = wet2dry.get(wetRevokeHandler);
+ try {
+ var x = asWet(optDryHandler[name].apply(
+ optDryHandler, Array.prototype.map.call(arguments, asDry)));
+ print("wet handler exit", name, arg, "returning", str(x));
+ return x;
+ } catch (eDry) {
+ var x = asWet(eDry);
+ print("wet handler exception", name, arg, "throwing", str(x));
+ throw x;
+ }
+ };
+ }
+ }));
+ wet2dry.set(wetRevokeHandler, dryHandler);
+
+ if (typeof dry === "function") {
+ function callTrap() {
+ print("wet call trap enter", str(this));
+ var x = asWet(dry.apply(
+ asDry(this), Array.prototype.map.call(arguments, asDry)));
+ print("wet call trap exit", str(this), "returning", str(x));
+ return x;
+ }
+ function constructTrap() {
+ function forward(args) { return dry.apply(this, args) }
+ return asWet(new forward(Array.prototype.map.call(arguments, asDry)));
+ }
+ wetResult =
+ Proxy.createFunction(wetRevokeHandler, callTrap, constructTrap);
+ } else {
+ wetResult =
+ Proxy.create(wetRevokeHandler, asWet(Object.getPrototypeOf(dry)));
+ }
+ dry2wet.set(dry, wetResult);
+ wet2dry.set(wetResult, dry);
+ return wetResult;
+ }
+
+ var gate = Object.freeze({
+ revoke: function() {
+ dry2wet = wet2dry = Object.freeze({
+ get: function(key) { throw new Error("revoked"); },
+ set: function(key, val) { throw new Error("revoked"); }
+ });
+ }
+ });
+
+ return Object.freeze({ wrapper: asDry(wetTarget), gate: gate });
+}
+
+
+var receiver
+var argument
+var o = {
+ a: 6,
+ b: {bb: 8},
+ f: function(x) { receiver = this; argument = x; return x },
+ g: function(x) { receiver = this; argument = x; return x.a },
+ h: function(x) { receiver = this; argument = x; this.q = x },
+ s: function(x) { receiver = this; argument = x; this.x = {y: x}; return this }
+}
+o[2] = {c: 7}
+var m = createMembrane(o)
+var w = m.wrapper
+print("dry w =", str(w))
+
+var f = w.f
+var x = f(66)
+var x = f({a: 1})
+var x = w.f({a: 1})
+var a = x.a
+assertEquals(6, w.a)
+assertEquals(8, w.b.bb)
+assertEquals(7, w[2]["c"])
+assertEquals(undefined, w.c)
+assertEquals(1, w.f(1))
+assertSame(o, receiver)
+assertEquals(1, w.f({a: 1}).a)
+assertSame(o, receiver)
+assertEquals(2, w.g({a: 2}))
+assertSame(o, receiver)
+assertEquals(w, w.f(w))
+assertSame(o, receiver)
+assertSame(o, argument)
+assertEquals(o, w.f(o))
+assertSame(o, receiver)
+assertSame(o, argument)
+assertEquals(3, (w.r = {a: 3}).a)
+assertEquals(3, w.r.a)
+assertEquals(3, o.r.a)
+w.h(3)
+assertEquals(3, w.q)
+assertEquals(3, o.q)
+assertEquals(4, (new w.h(4)).q)
+assertEquals(5, w.s(5).x.y)
+assertSame(o, receiver)
+
+var wb = w.b
+var wr = w.r
+var wf = w.f
+var wf3 = w.f(3)
+var wfx = w.f({a: 6})
+var wgx = w.g({a: {aa: 7}})
+var wh4 = new w.h(4)
+var ws5 = w.s(5)
+var ws5x = ws5.x
+m.gate.revoke()
+assertEquals(3, wf3)
+assertThrows(function() { w.a }, Error)
+assertThrows(function() { w.r }, Error)
+assertThrows(function() { w.r = {a: 4} }, Error)
+assertThrows(function() { o.r.a }, Error)
+assertEquals("object", typeof o.r)
+assertEquals(5, (o.r = {a: 5}).a)
+assertEquals(5, o.r.a)
+assertThrows(function() { w[1] }, Error)
+assertThrows(function() { w.c }, Error)
+assertThrows(function() { wb.bb }, Error)
+assertEquals(3, wr.a)
+assertThrows(function() { wf(4) }, Error)
+assertEquals(6, wfx.a)
+assertEquals(7, wgx.aa)
+assertThrows(function() { wh4.q }, Error)
+assertThrows(function() { ws5.x }, Error)
+assertThrows(function() { ws5x.y }, Error)
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698