summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/proxy
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jit-test/tests/proxy
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/proxy')
-rw-r--r--js/src/jit-test/tests/proxy/bug-862848-1.js24
-rw-r--r--js/src/jit-test/tests/proxy/bug1072817.js5
-rw-r--r--js/src/jit-test/tests/proxy/bug1095973.js5
-rw-r--r--js/src/jit-test/tests/proxy/bug1685290.js13
-rw-r--r--js/src/jit-test/tests/proxy/bug897403.js3
-rw-r--r--js/src/jit-test/tests/proxy/bug901979-1.js16
-rw-r--r--js/src/jit-test/tests/proxy/bug901979-2.js37
-rw-r--r--js/src/jit-test/tests/proxy/bug911553.js10
-rw-r--r--js/src/jit-test/tests/proxy/defineProperty-fallback.js8
-rw-r--r--js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js10
-rw-r--r--js/src/jit-test/tests/proxy/freeze-proxy.js22
-rw-r--r--js/src/jit-test/tests/proxy/function-toString.js10
-rw-r--r--js/src/jit-test/tests/proxy/getElementIfPresent-not-present.js5
-rw-r--r--js/src/jit-test/tests/proxy/getPrototype-cycle-for-in.js12
-rw-r--r--js/src/jit-test/tests/proxy/getPrototype-cycle-hasInstance.js11
-rw-r--r--js/src/jit-test/tests/proxy/operations-on-revoked.js18
-rw-r--r--js/src/jit-test/tests/proxy/preserve-iscallable-isconstructor.js17
-rw-r--r--js/src/jit-test/tests/proxy/proxy-array-length.js4
-rw-r--r--js/src/jit-test/tests/proxy/seal-proxy.js16
-rw-r--r--js/src/jit-test/tests/proxy/surfaces.js14
-rw-r--r--js/src/jit-test/tests/proxy/target-becomes-nonextensible-during-preventExtensions.js8
-rw-r--r--js/src/jit-test/tests/proxy/testBug793160.js3
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyApply1.js6
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyApply2.js19
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyApply3.js10
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyApply4.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js21
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyConstruct3.js11
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyConstruct4.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js14
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyConstructor.js19
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty1.js23
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty2.js34
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty3.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty4.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty5.js13
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty6.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefineProperty7.js17
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyDefinePropertyFailure.js26
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js14
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGet1.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGet2.js22
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGet3.js50
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGet4.js14
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGet5.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGet6.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetInherited1.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetInherited2.js31
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetInherited3.js21
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetInherited4.js6
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor1.js27
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor10.js35
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor11.js14
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor2.js20
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor3.js13
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor4.js14
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor5.js15
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor6.js9
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor7.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor8.js13
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor9.js9
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames1.js30
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames2.js19
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames3.js6
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames4.js7
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames5.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames6.js11
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames7.js15
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames8.js42
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames9.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas1.js18
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas2.js21
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas3.js13
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas4.js15
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas5.js18
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas6.js13
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHas7.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyHasOwnProperty.js35
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js97
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyIsExtensible2.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys1.js27
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys10.js23
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys11.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys2.js20
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys3.js7
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys4.js7
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys5.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys6.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys7.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys8.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyKeys9.js35
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js23
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js33
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions1.js10
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions2.js25
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions3.js7
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions4.js6
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions5.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyRevoke.js45
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet1.js18
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet10.js60
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet2.js23
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet3.js14
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet4.js17
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet5.js13
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet6.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet7.js20
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet8.js21
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySet9.js20
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetArray1.js25
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetArray2.js12
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetArray3.js21
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetArray4.js24
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetFailure.js32
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetInherited.js23
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetNested.js15
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetNested2.js16
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxySetReceiverLookup.js57
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty1.js19
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty2.js39
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty3.js43
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty4.js24
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty5.js26
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty6.js28
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyValidateProperty7.js28
-rw-r--r--js/src/jit-test/tests/proxy/testSetImmutablePrototype.js11
-rw-r--r--js/src/jit-test/tests/proxy/testTestIntegrityLevel.js30
-rw-r--r--js/src/jit-test/tests/proxy/testWrapWithProtoIter.js1
-rw-r--r--js/src/jit-test/tests/proxy/testWrapWithProtoSet.js8
-rw-r--r--js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js19
-rw-r--r--js/src/jit-test/tests/proxy/testWrapWithProtoTypedArraySortFloat32.js3
-rw-r--r--js/src/jit-test/tests/proxy/testWrapperGetInherited.js18
133 files changed, 2455 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/proxy/bug-862848-1.js b/js/src/jit-test/tests/proxy/bug-862848-1.js
new file mode 100644
index 0000000000..870b5632c3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug-862848-1.js
@@ -0,0 +1,24 @@
+// obj.hasOwnProperty(id), Object.getOwnPropertyDescriptor(obj, id), and
+// Object.defineProperty(obj, id, desc) do not look at obj's prototype.
+
+var angryHandler = new Proxy({}, {
+ has: () => true,
+ get: (t, id) => {
+ throw new Error("angryHandler should not be queried (" + id + ")");
+ }
+});
+var angryProto = new Proxy({}, angryHandler);
+
+var obj = Object.create(angryProto, {
+ // Define hasOwnProperty directly on obj since we are poisoning its
+ // prototype chain.
+ hasOwnProperty: {
+ value: Object.prototype.hasOwnProperty
+ }
+});
+
+assertEq(Object.getOwnPropertyDescriptor(obj, "foo"), undefined);
+assertEq(obj.hasOwnProperty("foo"), false);
+Object.defineProperty(obj, "foo", {value: 5});
+assertEq(obj.hasOwnProperty("foo"), true);
+assertEq(obj.foo, 5);
diff --git a/js/src/jit-test/tests/proxy/bug1072817.js b/js/src/jit-test/tests/proxy/bug1072817.js
new file mode 100644
index 0000000000..d8656e0c70
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug1072817.js
@@ -0,0 +1,5 @@
+// |jit-test| error: TypeError
+var r = Proxy.revocable({}, {});
+var p = r.proxy;
+r.revoke();
+p instanceof Object;
diff --git a/js/src/jit-test/tests/proxy/bug1095973.js b/js/src/jit-test/tests/proxy/bug1095973.js
new file mode 100644
index 0000000000..6e917a16c8
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug1095973.js
@@ -0,0 +1,5 @@
+var C = {};
+var B = new Proxy(C, {});
+var A = Object.create(B);
+B.x = 1;
+assertEq(C.x, 1);
diff --git a/js/src/jit-test/tests/proxy/bug1685290.js b/js/src/jit-test/tests/proxy/bug1685290.js
new file mode 100644
index 0000000000..df1f2f6070
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug1685290.js
@@ -0,0 +1,13 @@
+with ({}) {}
+
+function test(s) {
+ "".replace(/x/, s);
+}
+
+for (var i = 0; i < 20; i++) {
+ test("");
+}
+
+try {
+ test(new Proxy({}, { get: invalidate }));
+} catch {}
diff --git a/js/src/jit-test/tests/proxy/bug897403.js b/js/src/jit-test/tests/proxy/bug897403.js
new file mode 100644
index 0000000000..45b743eac7
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug897403.js
@@ -0,0 +1,3 @@
+var f = (function () {}).bind({});
+var p = new Proxy(f, {});
+Object.defineProperty(p, "caller", {get: function(){}});
diff --git a/js/src/jit-test/tests/proxy/bug901979-1.js b/js/src/jit-test/tests/proxy/bug901979-1.js
new file mode 100644
index 0000000000..f6432a838c
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug901979-1.js
@@ -0,0 +1,16 @@
+// A proxy on the prototype chain of the global can't intercept lazy definition of globals.
+// Thanks to André Bargull for this one.
+load(libdir + "immutable-prototype.js");
+
+var global = this;
+var status = "pass";
+var handler = {
+ get: function get(t, pk, r) { status = "FAIL get"; },
+ has: function has(t, pk) { status = "FAIL has"; }
+};
+
+if (globalPrototypeChainIsMutable())
+ Object.prototype.__proto__ = new Proxy(Object.create(null), handler);
+
+Map;
+assertEq(status, "pass");
diff --git a/js/src/jit-test/tests/proxy/bug901979-2.js b/js/src/jit-test/tests/proxy/bug901979-2.js
new file mode 100644
index 0000000000..93f45dc891
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug901979-2.js
@@ -0,0 +1,37 @@
+// A proxy on the prototype chain of the global should not observe anything at
+// all about lazy resolution of globals.
+load(libdir + "immutable-prototype.js");
+
+var global = this;
+var status = "pass";
+
+// This is a little tricky. There are two proxies.
+// 1. handler is a proxy that fails the test if you try to call a method on it.
+var metaHandler = {
+ get: _ => { status = "SMASH"; },
+ has: _ => { status = "SMASH"; },
+ invoke: _ => { status = "SMASH"; }
+};
+var handler = new Proxy({}, metaHandler);
+
+// 2. Then we create a proxy using 'handler' as its handler. This means the test
+// will fail if *any* method of the handler is called, not just get/has/invoke.
+var angryProxy = new Proxy(Object.create(null), handler);
+if (globalPrototypeChainIsMutable()) {
+ this.__proto__ = angryProxy;
+ Object.prototype.__proto__ = angryProxy;
+}
+
+// Trip the alarm once, to make sure the proxies are working.
+this.nonExistingProperty;
+if (globalPrototypeChainIsMutable())
+ assertEq(status, "SMASH");
+else
+ assertEq(status, "pass");
+
+// OK. Reset the status and run the actual test.
+status = "pass";
+Map;
+ArrayBuffer;
+Date;
+assertEq(status, "pass");
diff --git a/js/src/jit-test/tests/proxy/bug911553.js b/js/src/jit-test/tests/proxy/bug911553.js
new file mode 100644
index 0000000000..5ccfbe21db
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug911553.js
@@ -0,0 +1,10 @@
+assertEq(
+ ""+new Proxy(
+ {toString:() => "inner toString"},
+ {get:(t, pk) => (pk === "toString" ? () => "proxy toString" : t[pk])}),
+ "proxy toString")
+assertEq(
+ ""+new Proxy(
+ {valueOf:() => "inner valueOf"},
+ {get:(t, pk) => (pk === "valueOf" ? () => "proxy valueOf" : t[pk])}),
+ "proxy valueOf")
diff --git a/js/src/jit-test/tests/proxy/defineProperty-fallback.js b/js/src/jit-test/tests/proxy/defineProperty-fallback.js
new file mode 100644
index 0000000000..e8f52dc382
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/defineProperty-fallback.js
@@ -0,0 +1,8 @@
+"use strict";
+var obj = {};
+Object.defineProperty(obj, "test", {configurable: false, writable: false, value: "hey"});
+Object.defineProperty(obj, "test", {configurable: false, writable: false});
+
+var wrapper = new Proxy(obj, {});
+Object.defineProperty(wrapper, "test", {configurable: false, writable: false});
+assertEq(wrapper.test, "hey");
diff --git a/js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js b/js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js
new file mode 100644
index 0000000000..1de2eaef04
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js
@@ -0,0 +1,10 @@
+// Create Proxy that throws for everything.
+var {proxy, revoke} = Proxy.revocable({}, {});
+
+var obj = {__proto__: proxy, a: 1};
+// This revokes the proxy, so every operation on it THROWS.
+revoke();
+
+assertEq(delete obj.a, true);
+assertEq(delete obj.b, true);
+// Should not have invoked anything on [[Prototype]]
diff --git a/js/src/jit-test/tests/proxy/freeze-proxy.js b/js/src/jit-test/tests/proxy/freeze-proxy.js
new file mode 100644
index 0000000000..ff82c50fd3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/freeze-proxy.js
@@ -0,0 +1,22 @@
+var called = [];
+var proxy = new Proxy({a: 1, get b() {}}, {
+ getOwnPropertyDescriptor(target, P) {
+ called.push("getOwnPropertyDescriptor");
+ return Object.getOwnPropertyDescriptor(target, P);
+ },
+ defineProperty(target, P, desc) {
+ called.push("defineProperty");
+ if (P == "a") {
+ assertEq(Object.getOwnPropertyNames(desc).length, 2);
+ assertEq(desc.configurable, false);
+ assertEq(desc.writable, false);
+ } else {
+ assertEq(Object.getOwnPropertyNames(desc).length, 1);
+ assertEq(desc.configurable, false);
+ }
+ return Object.defineProperty(target, P, desc);
+ }
+});
+
+Object.freeze(proxy);
+assertEq(called.toString(), "getOwnPropertyDescriptor,defineProperty,getOwnPropertyDescriptor,defineProperty");
diff --git a/js/src/jit-test/tests/proxy/function-toString.js b/js/src/jit-test/tests/proxy/function-toString.js
new file mode 100644
index 0000000000..4aca5c907e
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/function-toString.js
@@ -0,0 +1,10 @@
+load(libdir + 'asserts.js');
+
+var nativeCode = "function () {\n [native code]\n}";
+
+var proxy = new Proxy(function() {}, {});
+assertEq(Function.prototype.toString.call(proxy), nativeCode);
+var o = Proxy.revocable(function() {}, {});
+assertEq(Function.prototype.toString.call(o.proxy), nativeCode);
+o.revoke();
+assertEq(Function.prototype.toString.call(o.proxy), nativeCode);
diff --git a/js/src/jit-test/tests/proxy/getElementIfPresent-not-present.js b/js/src/jit-test/tests/proxy/getElementIfPresent-not-present.js
new file mode 100644
index 0000000000..ccfb92d8c4
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/getElementIfPresent-not-present.js
@@ -0,0 +1,5 @@
+x = (/x/).exec();
+y = wrapWithProto((new WeakMap), x);
+y.length = 7;
+Array.prototype.push.call(y, 1);
+Array.prototype.reverse.call(y);
diff --git a/js/src/jit-test/tests/proxy/getPrototype-cycle-for-in.js b/js/src/jit-test/tests/proxy/getPrototype-cycle-for-in.js
new file mode 100644
index 0000000000..6f109c6ac6
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/getPrototype-cycle-for-in.js
@@ -0,0 +1,12 @@
+// |jit-test| exitstatus: 6
+timeout(0.5);
+
+var proxy = new Proxy({}, {
+ getPrototypeOf() {
+ return proxy;
+ }
+});
+
+var obj = {a: 1, b: 2, __proto__: proxy};
+for (var x in obj) {}
+assertEq(0, 1); // Should timeout.
diff --git a/js/src/jit-test/tests/proxy/getPrototype-cycle-hasInstance.js b/js/src/jit-test/tests/proxy/getPrototype-cycle-hasInstance.js
new file mode 100644
index 0000000000..17b7422ba0
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/getPrototype-cycle-hasInstance.js
@@ -0,0 +1,11 @@
+// |jit-test| exitstatus: 6
+timeout(0.5)
+
+var proxy = new Proxy({}, {
+ getPrototypeOf() {
+ return proxy;
+ }
+});
+
+var x = proxy instanceof function() {};
+assertEq(0, 1); // Should timeout.
diff --git a/js/src/jit-test/tests/proxy/operations-on-revoked.js b/js/src/jit-test/tests/proxy/operations-on-revoked.js
new file mode 100644
index 0000000000..181f4c6fcf
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/operations-on-revoked.js
@@ -0,0 +1,18 @@
+load(libdir + 'asserts.js');
+
+var r = Proxy.revocable({}, {});
+var r2 = Proxy.revocable(function(){}, {});
+r.revoke();
+r2.revoke();
+
+var p = r.proxy;
+var p2 = r2.proxy;
+
+assertThrowsInstanceOf(() => ({} instanceof p), TypeError);
+assertThrowsInstanceOf(() => ({} instanceof p2), TypeError);
+
+assertThrowsInstanceOf(() => Object.prototype.toString.call(p), TypeError);
+assertThrowsInstanceOf(() => Object.prototype.toString.call(p2), TypeError);
+
+assertThrowsInstanceOf(() => RegExp.prototype.exec.call(p, ""), TypeError);
+assertThrowsInstanceOf(() => RegExp.prototype.exec.call(p2, ""), TypeError);
diff --git a/js/src/jit-test/tests/proxy/preserve-iscallable-isconstructor.js b/js/src/jit-test/tests/proxy/preserve-iscallable-isconstructor.js
new file mode 100644
index 0000000000..f1c84e2065
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/preserve-iscallable-isconstructor.js
@@ -0,0 +1,17 @@
+load(libdir + "asserts.js");
+
+var global = newGlobal({newCompartment: true})
+var fun = global.eval("(function() {})")
+var p = new Proxy(fun, {})
+
+// Nuking should preserve IsCallable and IsConstructor.
+assertEq(isConstructor(p), true);
+assertEq(typeof p, "function");
+nukeCCW(fun);
+assertEq(isConstructor(p), true);
+assertEq(typeof p, "function");
+
+// But actually calling and constructing should throw, because it's been
+// nuked.
+assertThrowsInstanceOf(() => { p(); }, TypeError);
+assertThrowsInstanceOf(() => { new p(); }, TypeError);
diff --git a/js/src/jit-test/tests/proxy/proxy-array-length.js b/js/src/jit-test/tests/proxy/proxy-array-length.js
new file mode 100644
index 0000000000..11045aac0f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/proxy-array-length.js
@@ -0,0 +1,4 @@
+var a = [1, 2, 3];
+var p = new Proxy(a, {});
+assertEq(p.length, 3);
+assertEq(JSON.stringify(p), "[1,2,3]");
diff --git a/js/src/jit-test/tests/proxy/seal-proxy.js b/js/src/jit-test/tests/proxy/seal-proxy.js
new file mode 100644
index 0000000000..74923cde01
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/seal-proxy.js
@@ -0,0 +1,16 @@
+var called = [];
+var proxy = new Proxy({a: 1}, {
+ getOwnPropertyDescriptor(target, P) {
+ called.push("getOwnPropertyDescriptor");
+ return Object.getOwnPropertyDescriptor(target, P);
+ },
+ defineProperty(target, P, desc) {
+ called.push("defineProperty");
+ assertEq(Object.getOwnPropertyNames(desc).length, 1);
+ assertEq(desc.configurable, false);
+ return Object.defineProperty(target, P, desc);
+ }
+});
+
+Object.seal(proxy);
+assertEq(called.toString(), "defineProperty");
diff --git a/js/src/jit-test/tests/proxy/surfaces.js b/js/src/jit-test/tests/proxy/surfaces.js
new file mode 100644
index 0000000000..087b53f94d
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/surfaces.js
@@ -0,0 +1,14 @@
+// Check superficial properties of the Proxy constructor.
+
+var desc = Object.getOwnPropertyDescriptor(this, "Proxy");
+assertEq(desc.configurable, true);
+assertEq(desc.enumerable, false);
+assertEq(desc.writable, true);
+assertEq(desc.value, Proxy);
+
+assertEq(typeof Proxy, "function");
+assertEq(Object.getPrototypeOf(Proxy), Function.prototype);
+assertEq(Proxy.length, 2);
+
+// Proxy is a constructor but has no .prototype property.
+assertEq(Proxy.hasOwnProperty("prototype"), false);
diff --git a/js/src/jit-test/tests/proxy/target-becomes-nonextensible-during-preventExtensions.js b/js/src/jit-test/tests/proxy/target-becomes-nonextensible-during-preventExtensions.js
new file mode 100644
index 0000000000..3ef475c728
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/target-becomes-nonextensible-during-preventExtensions.js
@@ -0,0 +1,8 @@
+// Don't assert
+var obj = {};
+var proxy = new Proxy(obj, {
+ get preventExtensions() {
+ Object.preventExtensions(obj);
+ }
+});
+Object.preventExtensions(proxy);
diff --git a/js/src/jit-test/tests/proxy/testBug793160.js b/js/src/jit-test/tests/proxy/testBug793160.js
new file mode 100644
index 0000000000..8e15baa269
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testBug793160.js
@@ -0,0 +1,3 @@
+var obj = new Proxy(Object.create(null), {});
+assertEq(typeof obj, 'object');
+assertEq(obj != null, true);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyApply1.js b/js/src/jit-test/tests/proxy/testDirectProxyApply1.js
new file mode 100644
index 0000000000..a198dd1449
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyApply1.js
@@ -0,0 +1,6 @@
+// Forward to the target if the trap is undefined
+var target = function (x, y) {
+ return x + y;
+}
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy])
+ assertEq(p(2, 3), 5);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyApply2.js b/js/src/jit-test/tests/proxy/testDirectProxyApply2.js
new file mode 100644
index 0000000000..cc2c5332e7
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyApply2.js
@@ -0,0 +1,19 @@
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, the original this value as the second argument, and the original
+ * arguments as the third argument.
+ */
+var target = function () {};
+var receiver = {};
+var handler = {
+ apply: function (target1, receiver1, args) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ assertEq(receiver1, receiver);
+ assertEq(args.length, 2);
+ assertEq(args[0], 2);
+ assertEq(args[1], 3);
+ }
+}
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ p.call(receiver, 2, 3);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyApply3.js b/js/src/jit-test/tests/proxy/testDirectProxyApply3.js
new file mode 100644
index 0000000000..2a5f927f65
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyApply3.js
@@ -0,0 +1,10 @@
+// Return the trap result
+// Man, wouldn't haskell's "uninfix" be cleaner? (+)
+function justAdd(x, y) {
+ return x + y;
+}
+
+var handler = { apply : function (target, receiver, args) { return args[0] * args[1]; } };
+
+for (let p of [new Proxy(justAdd, handler), Proxy.revocable(justAdd, handler).proxy])
+ assertEq(p(2,3), 6);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyApply4.js b/js/src/jit-test/tests/proxy/testDirectProxyApply4.js
new file mode 100644
index 0000000000..448f8c3b2c
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyApply4.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = function () { };
+var handler = { apply: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => holder.proxy(), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js b/js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js
new file mode 100644
index 0000000000..6117d8b6cb
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js
@@ -0,0 +1,12 @@
+// Forward to the target if the trap is undefined
+var p;
+var target = function (x, y) {
+ assertEq(new.target, p);
+ this.foo = x + y;
+}
+
+for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ var obj = new p(2, 3);
+ assertEq(obj.foo, 5);
+ assertEq(Object.getPrototypeOf(obj), target.prototype);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js b/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
new file mode 100644
index 0000000000..7f2421bd67
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
@@ -0,0 +1,21 @@
+load(libdir + "asserts.js");
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, and the original arguments as the third argument.
+ *
+ * Hooks that don't return an object must throw.
+ */
+var p;
+var target = function () {};
+var handler = {
+ construct: function (target1, args, newTarget) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ assertEq(args.length, 2);
+ assertEq(args[0], 2);
+ assertEq(args[1], 3);
+ assertEq(newTarget, p);
+ }
+}
+for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(function () {new p(2, 3)}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyConstruct3.js b/js/src/jit-test/tests/proxy/testDirectProxyConstruct3.js
new file mode 100644
index 0000000000..881523cdff
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct3.js
@@ -0,0 +1,11 @@
+// Return the trap result
+function setFoo(x,y) { this.foo = x + y; }
+var handler = { construct: function (target, args) { return { foo : args[0] * args[1]}; } }
+
+for (let proxy of [new Proxy(setFoo, handler), Proxy.revocable(setFoo, handler).proxy]) {
+ var obj1 = new proxy(2, 3);
+ assertEq(obj1.foo, 6);
+ obj1.bar = proxy;
+ var obj2 = new obj1.bar(2, 3);
+ assertEq(obj2.foo, 6);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyConstruct4.js b/js/src/jit-test/tests/proxy/testDirectProxyConstruct4.js
new file mode 100644
index 0000000000..35a44deac0
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct4.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = function () { };
+var handler = { construct: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => new holder.proxy(), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js b/js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js
new file mode 100644
index 0000000000..e86bc456fa
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js
@@ -0,0 +1,14 @@
+load(libdir + "asserts.js");
+
+// Make sure that a proxy only has a [[Construct]] if the target does
+
+var handler = {};
+var p = new Proxy(Math.sin, handler);
+var r = Proxy.revocable(Math.sin, handler).proxy;
+
+assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
+assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
+// Better throw regardless of whether we have a handler trap.
+handler.construct = (() => ({}));
+assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
+assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyConstructor.js b/js/src/jit-test/tests/proxy/testDirectProxyConstructor.js
new file mode 100644
index 0000000000..9ff2710bf0
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstructor.js
@@ -0,0 +1,19 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if Proxy is not called as a constructor
+assertThrowsInstanceOf(function () { Proxy({}, {}); }, TypeError);
+
+// Throw a TypeError if Proxy is called with less than two arguments
+assertThrowsInstanceOf(function () { new Proxy(); }, TypeError);
+assertThrowsInstanceOf(function () { new Proxy({}); }, TypeError);
+
+// Throw a TypeError if the first argument is not a non-null object
+assertThrowsInstanceOf(function () { new Proxy(0, {}); }, TypeError);
+assertThrowsInstanceOf(function () { new Proxy(null, {}); }, TypeError);
+
+// Throw a TypeError if the second argument is not a non-null object
+assertThrowsInstanceOf(function () { new Proxy({}, 0); }, TypeError);
+assertThrowsInstanceOf(function () { new Proxy({}, null); }, TypeError);
+
+// Result of the call should be an object
+assertEq(typeof new Proxy({}, {}), 'object');
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty1.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty1.js
new file mode 100644
index 0000000000..243ad55a13
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty1.js
@@ -0,0 +1,23 @@
+// Forward to the target if the trap is not defined
+
+var target;
+function testProxy(p, key) {
+ Object.defineProperty(p, key, {
+ value: 'bar',
+ writable: true,
+ enumerable: false,
+ configurable: true
+ });
+ var desc = Object.getOwnPropertyDescriptor(target, key);
+ assertEq(desc.value, 'bar');
+ assertEq(desc.writable, true);
+ assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+}
+
+for (var key of ['foo', Symbol("quux")]) {
+ target = {};
+ testProxy(new Proxy(target, {}), key);
+ target = {};
+ testProxy(Proxy.revocable(target, {}).proxy, key);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty2.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty2.js
new file mode 100644
index 0000000000..e07323efe5
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty2.js
@@ -0,0 +1,34 @@
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, the name of the property as the second argument, and the descriptor
+ * as the third argument.
+ */
+var target = {};
+var handler = {
+ defineProperty: function (target1, key, desc1) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ log.push(key);
+ assertEq(desc1 == desc, false);
+ assertEq(desc1.value, 'bar');
+ assertEq(desc1.writable, true);
+ assertEq(desc1.enumerable, false);
+ assertEq(desc1.configurable, true);
+ return true;
+ }
+};
+var desc = {
+ value: 'bar',
+ writable: true,
+ enumerable: false,
+ configurable: true
+};
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ var log = [];
+ Object.defineProperty(p, 'foo', desc);
+ Object.defineProperty(p, Symbol.for('quux'), desc);
+ assertEq(log.length, 2);
+ assertEq(log[0], 'foo');
+ assertEq(log[1], Symbol.for('quux'));
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty3.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty3.js
new file mode 100644
index 0000000000..8a466aded2
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty3.js
@@ -0,0 +1,16 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap defines a new property on a non-extensible
+ * object
+ */
+var target = {};
+Object.preventExtensions(target);
+
+var handler = { defineProperty: function (target, name, desc) { return true; } };
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ assertThrowsInstanceOf(function () {
+ Object.defineProperty(p, 'foo', { configurable: true });
+ }, TypeError);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty4.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty4.js
new file mode 100644
index 0000000000..30e8d63161
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty4.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap defines a non-configurable property that does
+ * not exist on the target
+ */
+var handler = { defineProperty: function (target, name, desc) { return true; } };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy]) {
+ assertThrowsInstanceOf(function () {
+ Object.defineProperty(p, 'foo', { configurable: false });
+ }, TypeError);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty5.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty5.js
new file mode 100644
index 0000000000..78d8847a97
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty5.js
@@ -0,0 +1,13 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { defineProperty: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+var p = holder.proxy;
+assertThrowsInstanceOf(() => Object.defineProperty(p, 'foo', {}), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty6.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty6.js
new file mode 100644
index 0000000000..9818257e0c
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty6.js
@@ -0,0 +1,16 @@
+// Bug 1133094 - Proxy.[[DefineOwnProperty]]() should not throw when asked to
+// define a configurable accessor property over an existing configurable data
+// property on the target, even if the trap leaves the target unchanged.
+
+var hits = 0;
+var p = new Proxy({x: 1}, {
+ defineProperty(t, k, desc) {
+ // don't bother redefining the existing property t.x
+ hits++;
+ return true;
+ }
+});
+
+assertEq(Object.defineProperty(p, "x", {get: function () {}}), p);
+assertEq(hits, 1);
+assertEq(p.x, 1);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty7.js b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty7.js
new file mode 100644
index 0000000000..8c05147c57
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty7.js
@@ -0,0 +1,17 @@
+// Bug 1133085 - Test that descriptors are properly reconstituted
+// when only .get or only .set is present.
+
+load(libdir + "asserts.js");
+
+var input, output;
+var p = new Proxy({x: 0}, {
+ defineProperty(t, k, desc) { output = desc; print("ok"); return true; }
+});
+
+input = {get: function () {}};
+Object.defineProperty(p, "x", input);
+assertDeepEq(output, input);
+
+input = {set: function () {}};
+Object.defineProperty(p, "x", input);
+assertDeepEq(output, input);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyDefinePropertyFailure.js b/js/src/jit-test/tests/proxy/testDirectProxyDefinePropertyFailure.js
new file mode 100644
index 0000000000..0de3000c3f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyDefinePropertyFailure.js
@@ -0,0 +1,26 @@
+// Test handling of false return from a handler.defineProperty() hook.
+
+load(libdir + "asserts.js");
+
+var obj = {x: 1, y: 2};
+var nope = false;
+var p = new Proxy(obj, {
+ defineProperty(target, key, desc) { return nope; }
+});
+
+// Object.defineProperty throws on failure.
+print(1);
+assertThrowsInstanceOf(() => Object.defineProperty(p, "z", {value: 3}), TypeError);
+assertEq("z" in obj, false);
+assertThrowsInstanceOf(() => Object.defineProperty(p, "x", {value: 0}), TypeError);
+
+// Setting a property ultimately causes [[DefineOwnProperty]] to be called.
+// In strict mode code only, this is a TypeError.
+print(2);
+assertEq(p.z = 3, 3);
+assertThrowsInstanceOf(() => { "use strict"; p.z = 3; }, TypeError);
+
+// Other falsy values also trigger failure.
+print(3);
+for (nope of [0, -0, NaN, ""])
+ assertThrowsInstanceOf(() => { "use strict"; p.z = 3; }, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js
new file mode 100644
index 0000000000..485e03182e
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js
@@ -0,0 +1,14 @@
+// for-in with revoked Proxy
+load(libdir + "asserts.js");
+
+let {proxy, revoke} = Proxy.revocable({a: 1}, {});
+
+for (let x in proxy)
+ assertEq(x, "a")
+
+revoke();
+
+assertThrowsInstanceOf(function() {
+ for (let x in proxy)
+ assertEq(true, false);
+}, TypeError)
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGet1.js b/js/src/jit-test/tests/proxy/testDirectProxyGet1.js
new file mode 100644
index 0000000000..43cb5385d0
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGet1.js
@@ -0,0 +1,12 @@
+// Forward to the target if the trap is not defined
+var target = { foo: 'bar' };
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ assertEq(p.foo, 'bar');
+ assertEq(p['foo'], 'bar');
+}
+
+var s = Symbol.for("moon");
+var obj = {};
+obj[s] = "dust";
+for (let p of [new Proxy(obj, {}), Proxy.revocable(obj, {}).proxy])
+ assertEq(p[s], "dust");
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGet2.js b/js/src/jit-test/tests/proxy/testDirectProxyGet2.js
new file mode 100644
index 0000000000..ab3efae322
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGet2.js
@@ -0,0 +1,22 @@
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, the name of the property as the second argument, and the receiver
+ * as the third argument
+ */
+var target = {};
+for (var key of ['foo', Symbol.iterator]) {
+ handler = {};
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ handler.get =
+ function (target1, name, receiver) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ assertEq(name, key);
+ assertEq(receiver, p);
+ called = true;
+ };
+ var called = false;
+ assertEq(p[key], undefined);
+ assertEq(called, true);
+ }
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGet3.js b/js/src/jit-test/tests/proxy/testDirectProxyGet3.js
new file mode 100644
index 0000000000..e0acc3b3bb
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGet3.js
@@ -0,0 +1,50 @@
+load(libdir + "asserts.js");
+
+function testProxy(handlerReturn, prop, shouldThrow) {
+ var handler = { get: function () { return handlerReturn; } };
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ if (shouldThrow)
+ assertThrowsInstanceOf(function () { return p[prop]; }, TypeError);
+ else
+ assertEq(p[prop], handlerReturn);
+ }
+}
+
+/*
+ * Throw a TypeError if the trap reports a different value for a non-writable,
+ * non-configurable property
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: 'bar',
+ writable: false,
+ configurable: false
+});
+testProxy('baz', 'foo', true);
+/*
+ * Don't throw a TypeError if the trap reports the same value for a non-writable,
+ * non-configurable property
+ */
+testProxy('bar', 'foo', false);
+
+/*
+ * Don't throw a TypeError if the trap reports a different value for a writable,
+ * non-configurable property
+ */
+Object.defineProperty(target, 'prop', {
+ value: 'bar',
+ writable: true,
+ configurable: false
+});
+testProxy('baz', 'prop', false);
+
+/*
+ * Don't throw a TypeError if the trap reports a different value for a non-writable,
+ * configurable property
+ */
+Object.defineProperty(target, 'prop2', {
+ value: 'bar',
+ writable: false,
+ configurable: true
+});
+testProxy('baz', 'prop2', false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGet4.js b/js/src/jit-test/tests/proxy/testDirectProxyGet4.js
new file mode 100644
index 0000000000..4fc7b2f9a3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGet4.js
@@ -0,0 +1,14 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap does not report undefined for a non-configurable
+ * accessor property that does not have a getter
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ set: function (value) {},
+ configurable: false
+});
+var handler = { get: function (target, name, receiver) { return 'baz'; } };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(function () { p['foo'] }, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGet5.js b/js/src/jit-test/tests/proxy/testDirectProxyGet5.js
new file mode 100644
index 0000000000..a71a36e80b
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGet5.js
@@ -0,0 +1,16 @@
+// Return the trap result
+var target = { foo: 'bar' };
+var s1 = Symbol("moon"), s2 = Symbol("sun");
+target[s1] = "wrong";
+
+var handler = { };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ handler.get = (() => 'baz');
+ assertEq(p.foo, 'baz');
+
+ handler.get = (() => undefined);
+ assertEq(p.foo, undefined);
+
+ handler.get = (() => s2);
+ assertEq(p[s1], s2);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGet6.js b/js/src/jit-test/tests/proxy/testDirectProxyGet6.js
new file mode 100644
index 0000000000..c86818122f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGet6.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { get: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => holder.proxy.foo, TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetInherited1.js b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited1.js
new file mode 100644
index 0000000000..fc2dc0388f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited1.js
@@ -0,0 +1,16 @@
+// Getting a property that exists on an ordinary object
+// does not touch a proxy on its proto chain.
+
+load(libdir + "asserts.js");
+
+var angryHandler = new Proxy({}, {
+ get(t, id) { throw new Error("angryHandler should not be queried (" + id + ")"); }
+});
+var angryProto = new Proxy({}, angryHandler);
+var obj = Object.create(angryProto, {
+ x: {value: 3},
+ y: {get: () => 4}
+});
+assertThrowsInstanceOf(() => obj.z, Error); // check that angryProto works
+assertEq(obj.x, 3);
+assertEq(obj.y, 4);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetInherited2.js b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited2.js
new file mode 100644
index 0000000000..3c58e314ea
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited2.js
@@ -0,0 +1,31 @@
+// Getting a property that's inherted from a proxy calls the proxy's get handler.
+
+var handler = {
+ get(t, id, r) {
+ assertEq(this, handler);
+ assertEq(t, target);
+ assertEq(id, "foo");
+ assertEq(r, obj);
+ return "bar";
+ },
+ getOwnPropertyDescriptor(t, id) {
+ throw "FAIL";
+ }
+};
+
+var target = {};
+var proto = new Proxy(target, handler);
+var obj = Object.create(proto);
+assertEq(obj.foo, "bar");
+
+// Longer proto chain: same result.
+var origObj = obj;
+for (var i = 0; i < 4; i++)
+ obj = Object.create(obj);
+assertEq(obj.foo, "bar");
+
+// Chain of transparent proxy wrappers: same result.
+obj = origObj;
+for (var i = 0; i < 4; i++)
+ obj = new Proxy(obj, {});
+assertEq(obj.foo, "bar");
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetInherited3.js b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited3.js
new file mode 100644
index 0000000000..d9f34e60e8
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited3.js
@@ -0,0 +1,21 @@
+// Recursion through the get hook works; runaway recursion is checked.
+
+load(libdir + "asserts.js");
+
+var hits = 0, limit = 10;
+var proto = new Proxy({}, {
+ get(t, id, r) {
+ assertEq(r, obj);
+ if (hits++ >= limit)
+ return "ding";
+ return obj[id];
+ }
+});
+
+var obj = Object.create(proto);
+assertEq(obj.prop, "ding");
+
+hits = 0;
+limit = Infinity;
+assertThrowsInstanceOf(() => obj.prop, InternalError);
+assertEq(hits > 10, true);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetInherited4.js b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited4.js
new file mode 100644
index 0000000000..b1cf4a9053
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited4.js
@@ -0,0 +1,6 @@
+// A proxy P whose target is an object X whose prototype is an array V inherits V.length.
+
+var V = [1, 2, 3];
+var X = Object.create(V);
+var P = new Proxy(X, {});
+assertEq(P.length, 3);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor1.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor1.js
new file mode 100644
index 0000000000..20163dfe04
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor1.js
@@ -0,0 +1,27 @@
+// Forward to the target if the trap is not defined
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: 'bar',
+ writable: true,
+ enumerable: false,
+ configurable: true
+});
+
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ var desc = Object.getOwnPropertyDescriptor(p, 'foo');
+ assertEq(desc.value, 'bar');
+ assertEq(desc.writable, true);
+ assertEq(desc.enumerable, false);
+ assertEq(desc.configurable, true);
+}
+
+var proto = {};
+Object.defineProperty(proto, 'foo', {
+ value: 'bar',
+ writable: true,
+ enumerable: false,
+ configurable: true
+});
+var target = Object.create(proto);
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy])
+ assertEq(Object.getOwnPropertyDescriptor(p, 'foo'), undefined);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor10.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor10.js
new file mode 100644
index 0000000000..79a46d59fd
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor10.js
@@ -0,0 +1,35 @@
+// Return a new descriptor object that agrees with that returned by the trap
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: 'bar',
+ writable: true,
+ enumerable: false,
+ configurable: true
+});
+
+var desc = {
+ value: 'baz',
+ writable: false,
+ enumerable: true,
+ configurable: true
+};
+var handler = { getOwnPropertyDescriptor: function () { return desc; } };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ var desc1 = Object.getOwnPropertyDescriptor(p, 'foo');
+ assertEq(desc1 == desc, false);
+ assertEq(desc1.value, 'baz');
+ assertEq(desc1.writable, false);
+ assertEq(desc1.enumerable, true);
+ assertEq(desc1.configurable, true);
+}
+
+// The returned descriptor must agree in configurability.
+desc = { configurable : true };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ var desc1 = Object.getOwnPropertyDescriptor(p, 'foo');
+ assertEq(desc1 == desc, false);
+ assertEq(desc1.value, undefined);
+ assertEq(desc1.writable, false);
+ assertEq(desc1.enumerable, false);
+ assertEq(desc1.configurable, true);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor11.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor11.js
new file mode 100644
index 0000000000..7af839477d
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor11.js
@@ -0,0 +1,14 @@
+// Bug 1133294 - Object.getOwnPropertyDescriptor should never return an incomplete descriptor.
+
+load(libdir + "asserts.js");
+
+var p = new Proxy({}, {
+ getOwnPropertyDescriptor() { return {configurable: true}; }
+});
+var desc = Object.getOwnPropertyDescriptor(p, "x");
+assertDeepEq(desc, {
+ value: undefined,
+ writable: false,
+ enumerable: false,
+ configurable: true
+});
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor2.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor2.js
new file mode 100644
index 0000000000..abf1f5d6d3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor2.js
@@ -0,0 +1,20 @@
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, and the name of the property as the second argument
+ */
+var target = {};
+var called;
+var handler = {
+ getOwnPropertyDescriptor: function (target1, name) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ assertEq(name, 'foo');
+ called = true;
+ }
+};
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ called = false;
+ Object.getOwnPropertyDescriptor(p, 'foo');
+ assertEq(called, true);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor3.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor3.js
new file mode 100644
index 0000000000..0bfdc7fb83
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor3.js
@@ -0,0 +1,13 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { getOwnPropertyDescriptor: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+var test = function () { Object.getOwnPropertyDescriptor(holder.proxy, 'foo'); }
+assertThrowsInstanceOf(test, TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor4.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor4.js
new file mode 100644
index 0000000000..9920121f20
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor4.js
@@ -0,0 +1,14 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports a non-configurable property as
+ * non-existent
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: false
+});
+
+var handler = { getOwnPropertyDescriptor: () => undefined };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor5.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor5.js
new file mode 100644
index 0000000000..0d3334680a
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor5.js
@@ -0,0 +1,15 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports an existing own property as
+ * non-existent on a non-extensible object
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: true
+});
+Object.preventExtensions(target);
+
+var handler = { getOwnPropertyDescriptor: () => undefined };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor6.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor6.js
new file mode 100644
index 0000000000..558aab8502
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor6.js
@@ -0,0 +1,9 @@
+// Return undefined if the trap returns undefined
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: true
+});
+
+var handler = { getOwnPropertyDescriptor: () => undefined };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertEq(Object.getOwnPropertyDescriptor(p, 'foo'), undefined);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor7.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor7.js
new file mode 100644
index 0000000000..4f11bb7330
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor7.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports a new own property on a non-extensible
+ * object
+ */
+var target = {};
+Object.preventExtensions(target);
+
+var handler = { getOwnPropertyDescriptor: () => ({}) };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor8.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor8.js
new file mode 100644
index 0000000000..6178d8a039
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor8.js
@@ -0,0 +1,13 @@
+load(libdir + "asserts.js");
+
+var target = {};
+var handler = {
+ getOwnPropertyDescriptor: function () { return { value: 2, configurable: true}; }
+};
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ Object.getOwnPropertyDescriptor(p, 'foo');
+
+Object.preventExtensions(target);
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor9.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor9.js
new file mode 100644
index 0000000000..7a07f74f6e
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyDescriptor9.js
@@ -0,0 +1,9 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap returns a non-configurable descriptor for a
+ * non-existent property
+ */
+var handler = { getOwnPropertyDescriptor: () => ({ configurable: false }) };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyDescriptor(p, 'foo'), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames1.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames1.js
new file mode 100644
index 0000000000..11618c876f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames1.js
@@ -0,0 +1,30 @@
+// Forward to the target if the trap is not defined
+var objAB = Object.create(null, {
+ a: {
+ enumerable: true,
+ configurable: true
+ },
+ b: {
+ enumerable: false,
+ configurable: true
+ }
+});
+
+var objCD = Object.create(objAB, {
+ c: {
+ enumerable: true,
+ configurable: true
+ },
+ d: {
+ enumerable: false,
+ configurable: true
+ }
+});
+
+objCD[Symbol("moon")] = "something";
+for (let p of [new Proxy(objCD, {}), Proxy.revocable(objCD, {}).proxy]) {
+ var names = Object.getOwnPropertyNames(p);
+ assertEq(names.length, 2);
+ assertEq(names[0], 'c');
+ assertEq(names[1], 'd');
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames2.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames2.js
new file mode 100644
index 0000000000..8d3696369d
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames2.js
@@ -0,0 +1,19 @@
+/*
+ * Call the trap with the handler as the this value, and the target as the first
+ * argument
+ */
+var target = {};
+var called = false;
+var handler = {
+ ownKeys: function (target1) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ called = true;
+ return [];
+ }
+};
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ assertEq(Object.getOwnPropertyNames(p).length, 0);
+ assertEq(called, true);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames3.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames3.js
new file mode 100644
index 0000000000..cd674a8ba9
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames3.js
@@ -0,0 +1,6 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the trap does not return an object
+var handler = { ownKeys: () => undefined };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames4.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames4.js
new file mode 100644
index 0000000000..d6ebb15b5e
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames4.js
@@ -0,0 +1,7 @@
+load(libdir + "asserts.js");
+
+// Throw TypeError if trap returns a property key multiple times.
+
+var handler = { ownKeys : () => [ 'foo', 'foo' ] };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames5.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames5.js
new file mode 100644
index 0000000000..9ff27518fd
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames5.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports a new own property on a non-extensible
+ * object
+ */
+var target = {};
+Object.preventExtensions(target);
+
+var handler = { ownKeys: () => [ 'foo' ] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames6.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames6.js
new file mode 100644
index 0000000000..355f88a92f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames6.js
@@ -0,0 +1,11 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the trap skips a non-configurable property
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: false
+});
+
+var handler = { ownKeys: () => [] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames7.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames7.js
new file mode 100644
index 0000000000..a062934144
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames7.js
@@ -0,0 +1,15 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap skips an existing own property on a
+ * non-extensible object
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: true
+});
+Object.preventExtensions(target);
+
+var handler = { ownKeys: () => [] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.getOwnPropertyNames(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames8.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames8.js
new file mode 100644
index 0000000000..bd4631ff84
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames8.js
@@ -0,0 +1,42 @@
+// Return the names returned by the trap
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: true
+});
+
+var handler = { ownKeys: () => [ 'bar' ] };
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ var names = Object.getOwnPropertyNames(p);
+ assertEq(names.length, 1);
+ assertEq(names[0], 'bar');
+}
+
+var protoWithAB = Object.create(null, {
+ a: {
+ enumerable: true,
+ configurable: true
+ },
+ b: {
+ enumerable: false,
+ configurable: true
+ }
+});
+var objWithCD = Object.create(protoWithAB, {
+ c: {
+ enumerable: true,
+ configurable: true
+ },
+ d: {
+ enumerable: true,
+ configurable: true
+ }
+});
+
+handler = { ownKeys: () => [ 'c', 'e' ] };
+for (let p of [new Proxy(objWithCD, handler), Proxy.revocable(objWithCD, handler).proxy]) {
+ var names = Object.getOwnPropertyNames(p);
+ assertEq(names.length, 2);
+ assertEq(names[0], 'c');
+ assertEq(names[1], 'e');
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames9.js b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames9.js
new file mode 100644
index 0000000000..18a2cc89d8
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetOwnPropertyNames9.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { ownKeys: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => Object.getOwnPropertyNames(holder.proxy), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas1.js b/js/src/jit-test/tests/proxy/testDirectProxyHas1.js
new file mode 100644
index 0000000000..0e46d03e88
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas1.js
@@ -0,0 +1,18 @@
+// Forward to the target if the trap is not defined
+var proto = Object.create(null, {
+ 'foo': {
+ configurable: true
+ }
+});
+var target = Object.create(proto, {
+ 'bar': {
+ configurable: true
+ }
+});
+
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ assertEq('foo' in p, true);
+ assertEq('bar' in p, true);
+ assertEq('baz' in p, false);
+ assertEq(Symbol() in p, false);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas2.js b/js/src/jit-test/tests/proxy/testDirectProxyHas2.js
new file mode 100644
index 0000000000..a1aba55dfb
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas2.js
@@ -0,0 +1,21 @@
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, and the name of the property as the second argument
+ */
+var target = {};
+for (var key of ['foo', Symbol('bar')]) {
+ var called;
+ var handler = {
+ has: function (target1, name) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ assertEq(name, key);
+ called = true;
+ }
+ };
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ called = false;
+ key in p;
+ assertEq(called, true);
+ }
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas3.js b/js/src/jit-test/tests/proxy/testDirectProxyHas3.js
new file mode 100644
index 0000000000..1840c85fdd
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas3.js
@@ -0,0 +1,13 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports a non-configurable own property as
+ * non-existent
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: false
+});
+var handler = { has: () => false };
+for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(function () { 'foo' in p; }, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas4.js b/js/src/jit-test/tests/proxy/testDirectProxyHas4.js
new file mode 100644
index 0000000000..e2f88a7ddc
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas4.js
@@ -0,0 +1,15 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports an existing own property as
+ * non-existent on a non-extensible object
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: true
+});
+Object.preventExtensions(target);
+
+var handler = { has: () => false };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(function () { 'foo' in p }, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas5.js b/js/src/jit-test/tests/proxy/testDirectProxyHas5.js
new file mode 100644
index 0000000000..c581ede8ed
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas5.js
@@ -0,0 +1,18 @@
+// Return the trap result
+var proto = Object.create(null, {
+ 'foo': {
+ configurable: true
+ }
+});
+var target = Object.create(proto, {
+ 'bar': {
+ configurable: true
+ }
+});
+
+var handler = { has: () => false };
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ assertEq('foo' in p, false);
+ assertEq('bar' in p, false);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas6.js b/js/src/jit-test/tests/proxy/testDirectProxyHas6.js
new file mode 100644
index 0000000000..179e40f86f
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas6.js
@@ -0,0 +1,13 @@
+/*
+ * Don't throw a type error if the trap reports an undefined property as
+ * non-present, regardless of extensibility.
+ */
+var target = {};
+Object.preventExtensions(target);
+
+var handler = { has: () => false };
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ assertEq('foo' in p, false);
+ assertEq(Symbol.iterator in p, false);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHas7.js b/js/src/jit-test/tests/proxy/testDirectProxyHas7.js
new file mode 100644
index 0000000000..096688204a
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHas7.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { has: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => 'foo' in holder.proxy, TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyHasOwnProperty.js b/js/src/jit-test/tests/proxy/testDirectProxyHasOwnProperty.js
new file mode 100644
index 0000000000..5b7a97bba9
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyHasOwnProperty.js
@@ -0,0 +1,35 @@
+// Forward to the target if the trap is not defined
+var proto = Object.create(null, {
+ 'foo': {
+ configurable: true
+ }
+});
+var descs = {
+ 'bar': {
+ configurable: true
+ }
+};
+descs[Symbol.for("quux")] = {configurable: true};
+var target = Object.create(proto, descs);
+
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ assertEq(({}).hasOwnProperty.call(p, 'foo'), false);
+ assertEq(({}).hasOwnProperty.call(p, 'bar'), true);
+ assertEq(({}).hasOwnProperty.call(p, 'quux'), false);
+ assertEq(({}).hasOwnProperty.call(p, Symbol('quux')), false);
+ assertEq(({}).hasOwnProperty.call(p, 'Symbol(quux)'), false);
+ assertEq(({}).hasOwnProperty.call(p, Symbol.for('quux')), true);
+}
+
+// Make sure only the getOwnPropertyDescriptor trap is called, and not the has
+// trap.
+var called;
+var handler = { getOwnPropertyDescriptor: function () { called = true; },
+ has: function () { assertEq(false, true, "has trap must not be called"); }
+ }
+
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy]) {
+ called = false;
+ assertEq(({}).hasOwnProperty.call(p, 'foo'), false);
+ assertEq(called, true);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js b/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js
new file mode 100644
index 0000000000..6d0bdc6298
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js
@@ -0,0 +1,97 @@
+load(libdir + "asserts.js");
+// Test ES6 Proxy trap compliance for Object.isExtensible() on exotic proxy
+// objects.
+var unsealed = {};
+var sealed = Object.seal({});
+var handler = {};
+
+assertEq(Object.isExtensible(unsealed), true);
+assertEq(Object.isExtensible(sealed), false);
+
+var targetSealed = new Proxy(sealed, handler);
+var targetUnsealed = new Proxy(unsealed, handler);
+
+var handlerCalled = false;
+
+function testExtensible(target, expectedResult, shouldIgnoreHandler = false)
+{
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ handlerCalled = false;
+ if (typeof expectedResult === "boolean")
+ assertEq(Object.isExtensible(p), expectedResult, "Must return the correct value.");
+ else
+ assertThrowsInstanceOf(() => Object.isExtensible(p), expectedResult);
+ assertEq(handlerCalled, !shouldIgnoreHandler, "Must call handler appropriately");
+ }
+}
+
+// without traps, forward to the target
+// First, make sure we get the obvious answer on a non-exotic target.
+testExtensible(sealed, false, /* shouldIgnoreHandler = */true);
+testExtensible(unsealed, true, /* shouldIgnoreHandler = */true);
+
+// Now, keep everyone honest. What if the target itself is a proxy?
+// Note that we cheat a little. |handlerCalled| is true in a sense, just not
+// for the toplevel handler.
+// While we're here, test that the argument is passed correctly.
+var targetsTarget = {};
+function ensureCalled(target) { assertEq(target, targetsTarget); handlerCalled = true; return true; }
+var proxyTarget = new Proxy(targetsTarget, { isExtensible : ensureCalled });
+testExtensible(proxyTarget, true);
+
+// What if the trap says it's necessarily sealed?
+function fakeSealed() { handlerCalled = true; return false; }
+handler.isExtensible = fakeSealed;
+testExtensible(targetSealed, false);
+testExtensible(targetUnsealed, TypeError);
+
+// What if the trap says it's never sealed?
+function fakeUnsealed() { handlerCalled = true; return true; }
+handler.isExtensible = fakeUnsealed;
+testExtensible(targetSealed, TypeError);
+testExtensible(targetUnsealed, true);
+
+// make sure we are able to prevent further extensions mid-flight and throw if the
+// hook tries to lie.
+function makeSealedTruth(target) { handlerCalled = true; Object.preventExtensions(target); return false; }
+function makeSealedLie(target) { handlerCalled = true; Object.preventExtensions(target); return true; }
+handler.isExtensible = makeSealedTruth;
+testExtensible({}, false);
+handler.isExtensible = makeSealedLie;
+testExtensible({}, TypeError);
+
+// What if the trap doesn't directly return a boolean?
+function falseyNonBool() { handlerCalled = true; return undefined; }
+handler.isExtensible = falseyNonBool;
+testExtensible(sealed, false);
+testExtensible(unsealed, TypeError);
+
+function truthyNonBool() { handlerCalled = true; return {}; }
+handler.isExtensible = truthyNonBool;
+testExtensible(sealed, TypeError);
+testExtensible(unsealed, true);
+
+// What if the trap throws?
+function ExtensibleError() { }
+ExtensibleError.prototype = new Error();
+ExtensibleError.prototype.constructor = ExtensibleError;
+function throwFromTrap() { throw new ExtensibleError(); }
+handler.isExtensible = throwFromTrap;
+
+// exercise some other code paths and make sure that they invoke the trap and
+// can handle the ensuing error.
+for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) {
+ assertThrowsInstanceOf(function () { Object.isExtensible(p); },
+ ExtensibleError, "Must throw if the trap does.");
+ assertThrowsInstanceOf(function () { Object.isFrozen(p); },
+ ExtensibleError, "Must throw if the trap does.");
+ assertThrowsInstanceOf(function () { Object.isSealed(p); },
+ ExtensibleError, "Must throw if the trap does.");
+}
+
+// What if the trap likes to re-ask old questions?
+for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) {
+ handler.isExtensible = (() => Object.isExtensible(p));
+ assertThrowsInstanceOf(() => Object.isExtensible(p),
+ InternalError, "Should allow and detect infinite recurison.");
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible2.js b/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible2.js
new file mode 100644
index 0000000000..09662541d0
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible2.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { isExtensible: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => Object.isExtensible(holder.proxy), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys1.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys1.js
new file mode 100644
index 0000000000..2176850500
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys1.js
@@ -0,0 +1,27 @@
+// Forward to the target if the trap is not defined
+var proto = Object.create(null, {
+ a: {
+ enumerable: true,
+ configurable: true
+ },
+ b: {
+ enumerable: false,
+ configurable: true
+ }
+});
+var target = Object.create(proto, {
+ c: {
+ enumerable: true,
+ configurable: true
+ },
+ d: {
+ enumerable: false,
+ configurable: true
+ }
+});
+
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ var names = Object.keys(p);
+ assertEq(names.length, 1);
+ assertEq(names[0], 'c');
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys10.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys10.js
new file mode 100644
index 0000000000..47a4360aac
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys10.js
@@ -0,0 +1,23 @@
+load(libdir + "asserts.js");
+
+// Allow [[GetOwnPropertyDescriptor]] to spoof enumerability of target object's
+// properties. Note that this also tests that the getOwnPropertyDescriptor is
+// called by Object.keys(), as expected.
+
+var target = {};
+var handler = {
+ getOwnPropertyDescriptor : function (target, P) {
+ var targetDesc = Object.getOwnPropertyDescriptor(target, P);
+ // Lie about enumerability
+ targetDesc.enumerable = !targetDesc.enumerable;
+ return targetDesc;
+ }
+};
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ Object.defineProperty(target, "foo", { configurable: true, enumerable: false });
+ assertDeepEq(Object.keys(p), ["foo"]);
+
+ Object.defineProperty(target, "foo", {configurable: true, enumerable: true});
+ assertDeepEq(Object.keys(p), []);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys11.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys11.js
new file mode 100644
index 0000000000..2cd54d3b06
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys11.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { ownKeys: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => Object.keys(holder.proxy), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys2.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys2.js
new file mode 100644
index 0000000000..db03be48f8
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys2.js
@@ -0,0 +1,20 @@
+/*
+ * Call the trap with the handler as the this value, and the target as the first
+ * argument
+ */
+var target = {};
+var called;
+var handler = {
+ ownKeys: function (target1) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ called = true;
+ return [];
+ }
+};
+
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ called = false;
+ Object.keys(new Proxy(target, handler));
+ assertEq(called, true);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys3.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys3.js
new file mode 100644
index 0000000000..1ffc2edd63
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys3.js
@@ -0,0 +1,7 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the trap does not return an object
+
+var handler = { ownKeys: () => undefined };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.keys(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys4.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys4.js
new file mode 100644
index 0000000000..16ce41a029
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys4.js
@@ -0,0 +1,7 @@
+load(libdir + "asserts.js");
+
+// Throw TypeError if trap returns a property key multiple times.
+
+var handler = { ownKeys: () => [ 'foo', 'foo' ] };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.keys(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys5.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys5.js
new file mode 100644
index 0000000000..2ccfc5cd31
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys5.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap reports a new own property on a non-extensible
+ * object
+ */
+var target = {};
+Object.preventExtensions(target);
+
+var handler = { ownKeys: () => [ 'foo' ] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.keys(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys6.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys6.js
new file mode 100644
index 0000000000..00d97cbbca
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys6.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the trap skips a non-configurable enumerable property
+var target = {};
+Object.defineProperty(target, 'foo', {
+ enumerable: true,
+ configurable: false
+});
+
+var handler = { ownKeys: () => [] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.keys(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys7.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys7.js
new file mode 100644
index 0000000000..4486919300
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys7.js
@@ -0,0 +1,16 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap skips an existing own enumerable property on a
+ * non-extensible object
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ enumerable: true,
+ configurable: true
+});
+Object.preventExtensions(target);
+
+var handler = { ownKeys: () => [] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.keys(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys8.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys8.js
new file mode 100644
index 0000000000..4486919300
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys8.js
@@ -0,0 +1,16 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap skips an existing own enumerable property on a
+ * non-extensible object
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ enumerable: true,
+ configurable: true
+});
+Object.preventExtensions(target);
+
+var handler = { ownKeys: () => [] };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => Object.keys(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyKeys9.js b/js/src/jit-test/tests/proxy/testDirectProxyKeys9.js
new file mode 100644
index 0000000000..92695cdcd1
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyKeys9.js
@@ -0,0 +1,35 @@
+// Cull non-existent names returned by the trap.
+var nullProtoAB = Object.create(null, {
+ a: {
+ enumerable: true,
+ configurable: true
+ },
+ b: {
+ enumerable: false,
+ configurable: true
+ }
+});
+var protoABWithCD = Object.create(nullProtoAB, {
+ c: {
+ enumerable: true,
+ configurable: true
+ },
+ d: {
+ enumerable: false,
+ configurable: true
+ }
+});
+
+var returnedNames;
+var handler = { ownKeys: () => returnedNames };
+
+for (let p of [new Proxy(protoABWithCD, handler), Proxy.revocable(protoABWithCD, handler).proxy]) {
+ returnedNames = [ 'e' ];
+ var names = Object.keys(p);
+ assertEq(names.length, 0);
+
+ returnedNames = [ 'c' ];
+ names = Object.keys(p);
+ assertEq(names.length, 1);
+ assertEq(names[0], 'c');
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js b/js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js
new file mode 100644
index 0000000000..984e913c0e
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js
@@ -0,0 +1,23 @@
+let proxy = new Proxy({
+ a: 1,
+ b: 2,
+ c: 3
+}, {
+ enumerate() {
+ // Should not be invoked.
+ assertEq(false, true);
+ },
+
+ ownKeys() {
+ return ['a', 'b'];
+ }
+});
+
+let object = Object.create(proxy);
+object.d = 4;
+
+let a = [];
+for (let x in object) {
+ a.push(x);
+}
+assertEq(a.toString(), "d,a,b");
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js b/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js
new file mode 100644
index 0000000000..ad6e1845e1
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js
@@ -0,0 +1,33 @@
+// Make sure that we can find own, enumerable symbols.
+var symbol = Symbol("bad");
+var symbol2 = Symbol("good");
+var proxy = new Proxy({}, {
+ ownKeys() {
+ return [symbol, symbol2];
+ },
+ getOwnPropertyDescriptor(target, name) {
+ if (name == symbol)
+ return {configurable: true, enumerable: false, value: {}};
+ // Only this enumerable symbol should be defined.
+ if (name == symbol2)
+ return {configurable: true, enumerable: true, value: {}};
+ assertEq(true, false);
+ },
+ get(target, name) {
+ // Slightly confusing, but these are the descriptors that defineProperties
+ // is going to define on the object.
+ if (name == symbol)
+ return {configurable: true, value: "bad"};
+ if (name == symbol2)
+ return {configurable: true, value: "good"};
+ assertEq(true, false);
+ }
+});
+assertEq(Object.getOwnPropertySymbols(proxy).length, 2);
+
+var obj = {};
+Object.defineProperties(obj, proxy);
+assertEq(Object.getOwnPropertySymbols(obj).length, 1);
+assertEq(symbol in obj, false);
+assertEq(symbol2 in obj, true);
+assertEq(obj[symbol2], "good");
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions1.js b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions1.js
new file mode 100644
index 0000000000..384be1cf57
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions1.js
@@ -0,0 +1,10 @@
+// Forward to the target if the trap is not defined
+var target = {};
+var proxy = new Proxy(target, {});
+Object.preventExtensions(proxy);
+assertEq(Object.isExtensible(target), false);
+
+target = {};
+proxy = Proxy.revocable(target, {}).proxy;
+Object.preventExtensions(proxy);
+assertEq(Object.isExtensible(target), false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions2.js b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions2.js
new file mode 100644
index 0000000000..42591e22c3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions2.js
@@ -0,0 +1,25 @@
+/*
+ * Call the trap with the handler as the this value and the target as the first
+ * argument.
+ */
+var target = {};
+var handler = {
+ preventExtensions: function (target1) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ Object.preventExtensions(target1);
+ called = true;
+ return true;
+ }
+};
+
+var proxy = new Proxy(target, handler);
+var called = false;
+Object.preventExtensions(proxy);
+assertEq(called, true);
+
+target = {};
+proxy = Proxy.revocable(target, handler).proxy;
+called = false;
+Object.preventExtensions(proxy);
+assertEq(called, true);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions3.js b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions3.js
new file mode 100644
index 0000000000..7cb4046185
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions3.js
@@ -0,0 +1,7 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the trap reports an extensible object as non-extensible
+
+var handler = { preventExtensions: () => true };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.preventExtensions(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions4.js b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions4.js
new file mode 100644
index 0000000000..01395624e3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions4.js
@@ -0,0 +1,6 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the object refuses to be made non-extensible
+var handler = { preventExtensions: () => false };
+for (let p of [new Proxy({}, handler), Proxy.revocable({}, handler).proxy])
+ assertThrowsInstanceOf(() => Object.preventExtensions(p), TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions5.js b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions5.js
new file mode 100644
index 0000000000..e839ffa7b2
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions5.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { preventExtensions: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => Object.preventExtensions(holder.proxy), TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyRevoke.js b/js/src/jit-test/tests/proxy/testDirectProxyRevoke.js
new file mode 100644
index 0000000000..420fe3eaf9
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyRevoke.js
@@ -0,0 +1,45 @@
+load(libdir + "asserts.js");
+
+// Test for various properties demanded of Proxy.revocable
+var holder = Proxy.revocable({}, {});
+
+// The returned object must inherit from Object.prototype
+assertEq(Object.getPrototypeOf(holder), Object.prototype);
+
+assertDeepEq(Object.getOwnPropertyNames(holder), [ 'proxy', 'revoke' ]);
+
+// The revocation function must inherit from Function.prototype
+assertEq(Object.getPrototypeOf(holder.revoke), Function.prototype);
+
+// Proxy.revoke should return unique objects from the same opcode call.
+var proxyLog = []
+var revokerLog = []
+var holderLog = []
+
+function addUnique(l, v)
+{
+ assertEq(l.indexOf(v), -1);
+ l.push(v);
+}
+
+for (let i = 0; i < 5; i++) {
+ holder = Proxy.revocable({}, {});
+ addUnique(holderLog, holder);
+ addUnique(revokerLog, holder.revoke);
+ addUnique(proxyLog, holder.proxy);
+}
+
+// The provided revoke function should revoke only the 1 proxy
+var p = proxyLog.pop();
+var r = revokerLog.pop();
+
+// Works before, but not after. This is mostly a token. There are
+// testDirectProxy* tests to check each trap revokes properly.
+p.foo;
+assertEq(r(), undefined, "Revoke trap must return undefined");
+assertThrowsInstanceOf(() => p.foo, TypeError);
+assertEq(r(), undefined, "Revoke trap must return undefined");
+
+// None of this should throw, since these proxies are unrevoked.
+for (let i = 0; i < proxyLog.length; i++)
+ proxyLog[i].foo;
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet1.js b/js/src/jit-test/tests/proxy/testDirectProxySet1.js
new file mode 100644
index 0000000000..ddc1bc5ddc
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet1.js
@@ -0,0 +1,18 @@
+// Forward to the target if the trap is not defined
+var target = {
+ foo: 'bar'
+};
+for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+ // The sets from the first iteration will affect target, but it doesn't
+ // matter, since the effectiveness of the foo sets is still observable.
+ p.foo = 'baz';
+ assertEq(target.foo, 'baz');
+ p['foo'] = 'buz';
+ assertEq(target.foo, 'buz');
+
+ var sym = Symbol.for('quux');
+ p[sym] = sym;
+ assertEq(target[sym], sym);
+ // Reset for second iteration
+ target[sym] = undefined;
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet10.js b/js/src/jit-test/tests/proxy/testDirectProxySet10.js
new file mode 100644
index 0000000000..287cced8f3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet10.js
@@ -0,0 +1,60 @@
+// Assigning to a non-existing property of a plain object defines that
+// property on that object, even if a proxy is on the proto chain.
+
+// Create an object that behaves just like obj except it throws (instead of
+// returning undefined) if you try to get a property that doesn't exist.
+function throwIfNoSuchProperty(obj) {
+ return new Proxy(obj, {
+ get(t, id) {
+ if (id in t)
+ return t[id];
+ throw new Error("no such handler method: " + id);
+ }
+ });
+}
+
+// Use a touchy object as our proxy handler in this test.
+var hits = 0, savedDesc = undefined;
+var touchyHandler = throwIfNoSuchProperty({
+ set: undefined
+});
+var target = {};
+var proto = new Proxy(target, touchyHandler);
+var receiver = Object.create(proto);
+
+// This assignment `receiver.x = 2` results in a series of [[Set]] calls,
+// starting with:
+//
+// - receiver.[[Set]]()
+// - receiver is an ordinary object.
+// - This looks for an own property "x" on receiver. There is none.
+// - So it walks the prototype chain, doing a tail-call to:
+// - proto.[[Set]]()
+// - proto is a proxy.
+// - This does handler.[[Get]]("set") to look for a set trap
+// (that's why we need `set: undefined` on the handler, above)
+// - Since there's no "set" handler, it tail-calls:
+// - target.[[Set]]()
+// - ordinary
+// - no own property "x"
+// - tail call to:
+// - Object.prototype.[[Set]]()
+// - ordinary
+// - no own property "x"
+// - We're at the end of the line: there's nothing left on the proto chain.
+// - So at last we call:
+// - receiver.[[DefineOwnProperty]]()
+// - ordinary
+// - creates the property
+//
+// Got all that? Let's try it.
+//
+receiver.x = 2;
+assertEq(receiver.x, 2);
+
+var desc = Object.getOwnPropertyDescriptor(receiver, "x");
+assertEq(desc.enumerable, true);
+assertEq(desc.configurable, true);
+assertEq(desc.writable, true);
+assertEq(desc.value, 2);
+
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet2.js b/js/src/jit-test/tests/proxy/testDirectProxySet2.js
new file mode 100644
index 0000000000..af940f6bc3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet2.js
@@ -0,0 +1,23 @@
+/*
+ * Call the trap with the handler as the this value, the target as the first
+ * argument, the name of the property as the second argument, the value as the
+ * third argument, and the receiver as the fourth argument
+ */
+var target = {};
+for (var key of ['foo', Symbol.for('quux')]) {
+ var handler = { };
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ handler.set = function (target1, name, val, receiver) {
+ assertEq(this, handler);
+ assertEq(target1, target);
+ assertEq(name, key);
+ assertEq(val, 'baz');
+ assertEq(receiver, p);
+ called = true;
+ }
+
+ var called = false;
+ p[key] = 'baz';
+ assertEq(called, true);
+ }
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet3.js b/js/src/jit-test/tests/proxy/testDirectProxySet3.js
new file mode 100644
index 0000000000..94674aed61
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet3.js
@@ -0,0 +1,14 @@
+load(libdir + "asserts.js");
+
+// Throw a TypeError if the trap sets a non-writable, non-configurable property
+for (var key of ['foo', Symbol.for('quux')]) {
+ var target = {};
+ Object.defineProperty(target, key, {
+ value: 'bar',
+ writable: false,
+ configurable: false
+ });
+ var handler = { set: () => true };
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => p[key] = 'baz', TypeError);
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet4.js b/js/src/jit-test/tests/proxy/testDirectProxySet4.js
new file mode 100644
index 0000000000..760d1099df
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet4.js
@@ -0,0 +1,17 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the trap sets a non-configurable accessor property that
+ * doest not have a setter
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ get: function () {
+ return 'bar'
+ },
+ configurable: false
+});
+
+var handler = { set: () => true };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+ assertThrowsInstanceOf(() => p['foo'] = 'baz', TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet5.js b/js/src/jit-test/tests/proxy/testDirectProxySet5.js
new file mode 100644
index 0000000000..d4adcda0fe
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet5.js
@@ -0,0 +1,13 @@
+// Reflect side-effects from the trap
+var target = {
+ foo: 'bar'
+};
+
+var handler = { set: (target, name) => target[name] = 'qux' };
+for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ p['foo'] = 'baz';
+ assertEq(target['foo'], 'qux');
+
+ // reset for second iteration
+ target['foo'] = 'bar';
+}
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet6.js b/js/src/jit-test/tests/proxy/testDirectProxySet6.js
new file mode 100644
index 0000000000..3b5f66c2a9
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet6.js
@@ -0,0 +1,12 @@
+load(libdir + "asserts.js");
+// Revoked proxies should throw before calling the handler
+
+var called = false;
+var target = {};
+var handler = { set: () => called = true };
+var holder = Proxy.revocable(target, handler);
+
+holder.revoke();
+
+assertThrowsInstanceOf(() => holder.proxy.foo = 'bar', TypeError);
+assertEq(called, false);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet7.js b/js/src/jit-test/tests/proxy/testDirectProxySet7.js
new file mode 100644
index 0000000000..9376670e4a
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet7.js
@@ -0,0 +1,20 @@
+// Assigning to a proxy with no set handler calls the defineProperty handler
+// when no such property already exists.
+
+var hits = 0;
+var t = {};
+var p = new Proxy(t, {
+ defineProperty(t, id, desc) { hits++; return true; }
+});
+p.x = 1;
+assertEq(hits, 1);
+assertEq("x" in t, false);
+
+// Same thing, but the receiver is a plain object inheriting from p:
+var receiver = Object.create(p);
+hits = 0;
+receiver.x = 2;
+assertEq(hits, 0);
+assertEq("x" in t, false);
+assertEq(receiver.hasOwnProperty("x"), true);
+assertEq(receiver.x, 2);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet8.js b/js/src/jit-test/tests/proxy/testDirectProxySet8.js
new file mode 100644
index 0000000000..905769bbde
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet8.js
@@ -0,0 +1,21 @@
+// Assigning to a proxy with no set handler calls the defineProperty handler
+// when an existing inherited data property already exists.
+
+var hits = 0;
+var proto = {x: 1};
+var t = Object.create(proto);
+var p = new Proxy(t, {
+ defineProperty(t, id, desc) { hits++; return true; }
+});
+p.x = 2;
+assertEq(hits, 1);
+assertEq(proto.x, 1);
+assertEq(t.hasOwnProperty("x"), false);
+
+// Same thing, but the receiver is a plain object inheriting from p:
+var receiver = Object.create(p);
+receiver.x = 2;
+assertEq(hits, 1);
+assertEq(t.hasOwnProperty("x"), false);
+assertEq(receiver.hasOwnProperty("x"), true);
+assertEq(receiver.x, 2);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySet9.js b/js/src/jit-test/tests/proxy/testDirectProxySet9.js
new file mode 100644
index 0000000000..7a08b3c0cd
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySet9.js
@@ -0,0 +1,20 @@
+// Assigning to a proxy with no set handler calls the defineProperty handler
+// when an existing own data property already exists on the target.
+
+var t = {x: 1};
+var p = new Proxy(t, {
+ defineProperty(t, id, desc) {
+ hits++;
+
+ // ES6 draft rev 28 (2014 Oct 14) 9.1.9 step 5.e.i.
+ // Since the property already exists, the system only changes
+ // the value. desc is otherwise empty.
+ assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
+ assertEq(desc.value, 42);
+ return true;
+ }
+});
+var hits = 0;
+p.x = 42;
+assertEq(hits, 1);
+assertEq(t.x, 1);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetArray1.js b/js/src/jit-test/tests/proxy/testDirectProxySetArray1.js
new file mode 100644
index 0000000000..27d8489c4d
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetArray1.js
@@ -0,0 +1,25 @@
+// Assigning to a missing array element (a hole) via a proxy with no set handler
+// calls the defineProperty handler.
+
+function test(id) {
+ var arr = [, 1, 2, 3];
+ var p = new Proxy(arr, {
+ defineProperty(t, id, desc) {
+ hits++;
+ assertEq(desc.value, "ponies");
+ assertEq(desc.enumerable, true);
+ assertEq(desc.configurable, true);
+ assertEq(desc.writable, true);
+ return true;
+ }
+ });
+ var hits = 0;
+ p[id] = "ponies";
+ assertEq(hits, 1);
+ assertEq(id in arr, false);
+ assertEq(arr.length, 4);
+}
+
+test(0);
+test(4);
+test("str");
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetArray2.js b/js/src/jit-test/tests/proxy/testDirectProxySetArray2.js
new file mode 100644
index 0000000000..1025aa04f9
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetArray2.js
@@ -0,0 +1,12 @@
+// Direct proxies pass through the receiver argument to [[Set]] to their targets.
+// This also tests that an ordinary object's [[Set]] method can change the length
+// of an array passed as the receiver.
+
+load(libdir + "asserts.js");
+
+var a = [0, 1, 2, 3];
+var p = new Proxy({}, {});
+Reflect.set(p, "length", 2, a);
+assertEq("length" in p, false);
+assertEq(a.length, 2);
+assertDeepEq(a, [0, 1]);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetArray3.js b/js/src/jit-test/tests/proxy/testDirectProxySetArray3.js
new file mode 100644
index 0000000000..44bbcd99b4
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetArray3.js
@@ -0,0 +1,21 @@
+// Assigning to the length property of a proxy to an array
+// calls the proxy's defineProperty handler.
+
+var a = [0, 1, 2, 3];
+var p = new Proxy(a, {
+ defineProperty(t, id, desc) {
+ hits++;
+
+ // ES6 draft rev 28 (2014 Oct 14) 9.1.9 step 5.e.i.
+ // Since the property already exists, the system only changes
+ // the value. desc is otherwise empty.
+ assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
+ assertEq(desc.value, 2);
+ return true;
+ }
+});
+var hits = 0;
+p.length = 2;
+assertEq(hits, 1);
+assertEq(a.length, 4);
+assertEq(a[2], 2);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetArray4.js b/js/src/jit-test/tests/proxy/testDirectProxySetArray4.js
new file mode 100644
index 0000000000..524ddca456
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetArray4.js
@@ -0,0 +1,24 @@
+// Assigning to an existing array element via a proxy with no set handler
+// calls the defineProperty handler.
+
+function test(arr) {
+ var p = new Proxy(arr, {
+ defineProperty(t, id, desc) {
+ hits++;
+
+ // ES6 draft rev 28 (2014 Oct 14) 9.1.9 step 5.e.i.
+ // Since the property already exists, the system only changes
+ // the value. desc is otherwise empty.
+ assertEq(Object.getOwnPropertyNames(desc).join(","), "value");
+ assertEq(desc.value, "ponies");
+ return true;
+ }
+ });
+ var hits = 0;
+ p[0] = "ponies";
+ assertEq(hits, 1);
+ assertEq(arr[0], 123);
+}
+
+test([123]);
+test(new Int32Array([123]));
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetFailure.js b/js/src/jit-test/tests/proxy/testDirectProxySetFailure.js
new file mode 100644
index 0000000000..3646fc69b3
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetFailure.js
@@ -0,0 +1,32 @@
+// Test handling of false return from a handler.set() hook.
+
+load(libdir + "asserts.js");
+
+var obj = {x: 1};
+var p = new Proxy(obj, {
+ set(target, key, value, receiver) { return false; }
+});
+
+// Failing to set a property is a no-op in non-strict code.
+assertEq(p.x = 2, 2);
+assertEq(obj.x, 1);
+
+// It's a TypeError in strict mode code.
+assertThrowsInstanceOf(() => { "use strict"; p.x = 2; }, TypeError);
+assertEq(obj.x, 1);
+
+// Even if the value doesn't change.
+assertThrowsInstanceOf(() => { "use strict"; p.x = 1; }, TypeError);
+assertEq(obj.x, 1);
+
+// Even if the target property doesn't already exist.
+assertThrowsInstanceOf(() => { "use strict"; p.z = 1; }, TypeError);
+assertEq("z" in obj, false);
+
+// [].sort() mutates its operand only by doing strict [[Set]] calls.
+var arr = ["not", "already", "in", "order"];
+var p2 = new Proxy(arr, {
+ set(target, key, value, receiver) { return false; }
+});
+assertThrowsInstanceOf(() => p2.sort(), TypeError);
+assertDeepEq(arr, ["not", "already", "in", "order"]);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetInherited.js b/js/src/jit-test/tests/proxy/testDirectProxySetInherited.js
new file mode 100644
index 0000000000..9c8c880938
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetInherited.js
@@ -0,0 +1,23 @@
+// When assigning to an object with a proxy is on the prototype chain,
+// the proxy's set handler is called.
+
+var C = {};
+var B = new Proxy(C, {
+ get() { throw "FAIL"; },
+ getOwnPropertyDescriptor() { throw "FAIL"; },
+ has() { throw "FAIL"; },
+ defineProperty() { throw "FAIL"; },
+ set(target, id, value, receiver) {
+ hits++;
+ assertEq(target, C);
+ assertEq(id, "x");
+ assertEq(value, 3);
+ assertEq(receiver, A);
+ return true;
+ }
+});
+var A = Object.create(B);
+
+var hits = 0;
+A.x = 3;
+assertEq(hits, 1);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetNested.js b/js/src/jit-test/tests/proxy/testDirectProxySetNested.js
new file mode 100644
index 0000000000..20df6bbec8
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetNested.js
@@ -0,0 +1,15 @@
+// The receiver argument is passed through proxies with no "set" handler.
+
+var hits;
+var a = new Proxy({}, {
+ set(t, id, value, receiver) {
+ assertEq(id, "prop");
+ assertEq(value, 3);
+ assertEq(receiver, b);
+ hits++;
+ }
+});
+var b = new Proxy(a, {});
+hits = 0;
+b.prop = 3;
+assertEq(hits, 1);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetNested2.js b/js/src/jit-test/tests/proxy/testDirectProxySetNested2.js
new file mode 100644
index 0000000000..1825ec259c
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetNested2.js
@@ -0,0 +1,16 @@
+// The receiver argument is passed through prototype chains and proxies with no "set" handler.
+
+var hits;
+var a = new Proxy({}, {
+ set(t, id, value, receiver) {
+ assertEq(id, "prop");
+ assertEq(value, 3);
+ assertEq(receiver, b);
+ hits++;
+ }
+});
+var b = Object.create(Object.create(new Proxy(Object.create(new Proxy(a, {})), {})));
+hits = 0;
+b.prop = 3;
+assertEq(hits, 1);
+assertEq(b.prop, undefined);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxySetReceiverLookup.js b/js/src/jit-test/tests/proxy/testDirectProxySetReceiverLookup.js
new file mode 100644
index 0000000000..3cf687ed54
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxySetReceiverLookup.js
@@ -0,0 +1,57 @@
+// Assigning to a proxy with no set handler causes the proxy's
+// getOwnPropertyDescriptor handler to be called just before defineProperty
+// in some cases. (ES6 draft rev 28, 2014 Oct 14, 9.1.9 step 5.c.)
+
+var attrs = ["configurable", "enumerable", "writable", "value", "get", "set"];
+
+function test(target, id, existingDesc, expectedDesc) {
+ var log = "";
+ var p = new Proxy(target, {
+ getOwnPropertyDescriptor(t, idarg) {
+ assertEq(idarg, id);
+ log += "g";
+ return existingDesc;
+ },
+ defineProperty(t, idarg, desc) {
+ assertEq(idarg, id);
+ for (var attr of attrs) {
+ var args = JSON.stringify([target, id, existingDesc]).slice(1, -1);
+ assertEq(attr in desc, attr in expectedDesc,
+ `test(${args}), checking existence of desc.${attr}`);
+ assertEq(desc[attr], expectedDesc[attr],
+ `test(${args}), checking value of desc.${attr}`);
+ }
+ log += "d";
+ return true;
+ }
+ });
+ p[id] = "pizza";
+ assertEq(log, "gd");
+}
+
+var fullDesc = {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value: "pizza"
+};
+var valueOnlyDesc = {
+ value: "pizza"
+};
+var sealedDesc = {
+ configurable: false,
+ enumerable: true,
+ writable: true,
+ value: "pizza"
+};
+
+test({}, "x", undefined, fullDesc);
+test({}, "x", fullDesc, valueOnlyDesc);
+test({x: 1}, "x", undefined, fullDesc);
+test({x: 1}, "x", fullDesc, valueOnlyDesc);
+test(Object.seal({x: 1}), "x", sealedDesc, valueOnlyDesc);
+test(Object.create({x: 1}), "x", undefined, fullDesc);
+test([0, 1, 2], "2", undefined, fullDesc);
+test([0, 1, 2], "2", fullDesc, valueOnlyDesc);
+test([0, 1, 2], "3", undefined, fullDesc);
+test([0, 1, 2], "3", fullDesc, valueOnlyDesc);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty1.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty1.js
new file mode 100644
index 0000000000..d2c9c18c9d
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty1.js
@@ -0,0 +1,19 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the current descriptor is non-configurable and the trap
+ * returns a configurable descriptor
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: false
+});
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ configurable: true
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty2.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty2.js
new file mode 100644
index 0000000000..b027c68804
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty2.js
@@ -0,0 +1,39 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the enumerable fields of the current descriptor and the
+ * descriptor returned by the trap are the boolean negation of each other
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: false,
+ enumerable: true
+});
+var caught = false;
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ configurable: false,
+ enumerable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
+
+var target = {};
+Object.defineProperty(target, 'foo', {
+ configurable: false,
+ enumerable: false
+});
+var caught = false;
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ configurable: false,
+ enumerable: true
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty3.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty3.js
new file mode 100644
index 0000000000..34654d3ce9
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty3.js
@@ -0,0 +1,43 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if the current descriptor is a data descriptor and the
+ * descriptor returned by the trap is not, or vice versa, and the current
+ * descriptor is non-configurable
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: 'bar',
+ configurable: false
+});
+var caught = false;
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ get: function () {
+ return 'bar';
+ },
+ configurable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
+
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: function () {
+ return 'bar';
+ },
+ configurable: false
+});
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ value: 'bar',
+ configurable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty4.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty4.js
new file mode 100644
index 0000000000..966bd364e2
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty4.js
@@ -0,0 +1,24 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if both the current descriptor and the descriptor returned
+ * by the trap are data descriptors, the current descriptor is non-configurable
+ * and non-writable, and the descriptor returned by the trap is writable.
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: 'bar',
+ writable: false,
+ configurable: false
+});
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ value: 'bar',
+ writable: true,
+ configurable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty5.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty5.js
new file mode 100644
index 0000000000..0cc3cb8e0c
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty5.js
@@ -0,0 +1,26 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if both the current descriptor and the descriptor returned
+ * by the trap are data descriptors, the current descriptor is non-configurable
+ * and non-writable, and the descriptor returned by the trap does not have the
+ * same value.
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ value: 'bar',
+ writable: false,
+ configurable: false
+});
+var caught = false;
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ value: 'baz',
+ writable: false,
+ configurable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty6.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty6.js
new file mode 100644
index 0000000000..40cf389167
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty6.js
@@ -0,0 +1,28 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if both the current descriptor and the descriptor returned
+ * by the trap are accessor descriptors, the current descriptor is
+ * non-configurable, and the descriptor returned by the trap has a different
+ * setter.
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ set: function (value) {
+ target.foo = 'bar';
+ },
+ configurable: false
+});
+var caught = false;
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ set: function (value) {
+ target.foo = 'baz';
+ },
+ configurable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty7.js b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty7.js
new file mode 100644
index 0000000000..3c945c1315
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyValidateProperty7.js
@@ -0,0 +1,28 @@
+load(libdir + "asserts.js");
+
+/*
+ * Throw a TypeError if both the current descriptor and the descriptor returned
+ * by the trap are accessor descriptors, the current descriptor is
+ * non-configurable, and the descriptor returned by the trap has a different
+ * getter.
+ */
+var target = {};
+Object.defineProperty(target, 'foo', {
+ get: function () {
+ return 'bar';
+ },
+ configurable: false
+});
+var caught = false;
+assertThrowsInstanceOf(function () {
+ Object.getOwnPropertyDescriptor(new Proxy(target, {
+ getOwnPropertyDescriptor: function (target, name) {
+ return {
+ get: function () {
+ return 'baz';
+ },
+ configurable: false
+ };
+ }
+ }), 'foo');
+}, TypeError);
diff --git a/js/src/jit-test/tests/proxy/testSetImmutablePrototype.js b/js/src/jit-test/tests/proxy/testSetImmutablePrototype.js
new file mode 100644
index 0000000000..bc61dbbfcf
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testSetImmutablePrototype.js
@@ -0,0 +1,11 @@
+load(libdir + "asserts.js");
+
+let p = {};
+let x = new Proxy({__proto__: p}, {});
+assertEq(Reflect.getPrototypeOf(x), p);
+setImmutablePrototype(x);
+assertEq(Reflect.getPrototypeOf(x), p);
+assertEq(Reflect.setPrototypeOf(x, Date.prototype), false);
+assertEq(Reflect.setPrototypeOf(x, p), true);
+assertThrowsInstanceOf(() => Object.setPrototypeOf(x, Date.prototype), TypeError);
+assertEq(Reflect.getPrototypeOf(x), p);
diff --git a/js/src/jit-test/tests/proxy/testTestIntegrityLevel.js b/js/src/jit-test/tests/proxy/testTestIntegrityLevel.js
new file mode 100644
index 0000000000..4defb5f607
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testTestIntegrityLevel.js
@@ -0,0 +1,30 @@
+// isSealed/isFrozen should short-circuit.
+
+var count = 0;
+var target = Object.preventExtensions({a: 1, b: 2, c: 3});
+var p = new Proxy(target, {
+ getOwnPropertyDescriptor(t, id) {
+ count++;
+ return Object.getOwnPropertyDescriptor(t, id);
+ }
+});
+assertEq(Object.isSealed(p), false);
+assertEq(count, 1);
+
+count = 0;
+assertEq(Object.isFrozen(p), false);
+assertEq(count, 1);
+
+Object.seal(target);
+count = 0;
+assertEq(Object.isSealed(p), true);
+assertEq(count, 3);
+
+count = 0;
+assertEq(Object.isFrozen(p), false);
+assertEq(count, 1);
+
+Object.freeze(target);
+count = 0;
+assertEq(Object.isFrozen(p), true);
+assertEq(count, 3);
diff --git a/js/src/jit-test/tests/proxy/testWrapWithProtoIter.js b/js/src/jit-test/tests/proxy/testWrapWithProtoIter.js
new file mode 100644
index 0000000000..c6854b2067
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoIter.js
@@ -0,0 +1 @@
+[...wrapWithProto(new Int8Array(), new Int8Array())]
diff --git a/js/src/jit-test/tests/proxy/testWrapWithProtoSet.js b/js/src/jit-test/tests/proxy/testWrapWithProtoSet.js
new file mode 100644
index 0000000000..9139186571
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoSet.js
@@ -0,0 +1,8 @@
+// A scripted proxy can delegate a [[Set]] along to a target
+// that's a different kind of proxy.
+
+var target = {};
+var wrapper = wrapWithProto(target, null);
+var p = new Proxy(wrapper, {});
+p.prop = 3;
+assertEq(target.prop, 3);
diff --git a/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js
new file mode 100644
index 0000000000..1b805d30a1
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArray.js
@@ -0,0 +1,19 @@
+let a = wrapWithProto(new Int8Array([1, 3, 5, 6, 9]), new Int8Array());
+
+assertEq([...a].toString(), "1,3,5,6,9");
+assertEq(a.every(e => e < 100), true);
+assertEq(a.filter(e => e % 2 == 1).toString(), "1,3,5,9");
+assertEq(a.find(e => e > 3), 5);
+assertEq(a.findIndex(e => e % 2 == 0), 3);
+assertEq(a.map(e => e * 10).toString(), "10,30,50,60,90");
+assertEq(a.reduce((a, b) => a + b, ""), "13569");
+assertEq(a.reduceRight((acc, e) => "(" + e + acc + ")", ""), "(1(3(5(6(9)))))");
+assertEq(a.some(e => e % 2 == 0), true);
+
+let s = "";
+assertEq(a.forEach(e => s += e), undefined);
+assertEq(s, "13569");
+
+a.sort((a, b) => b - a);
+assertEq(a.toString(), "9,6,5,3,1");
+
diff --git a/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArraySortFloat32.js b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArraySortFloat32.js
new file mode 100644
index 0000000000..b36fa34f34
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArraySortFloat32.js
@@ -0,0 +1,3 @@
+let a = wrapWithProto(new Float32Array(1024), new Float32Array());
+
+a.sort();
diff --git a/js/src/jit-test/tests/proxy/testWrapperGetInherited.js b/js/src/jit-test/tests/proxy/testWrapperGetInherited.js
new file mode 100644
index 0000000000..1ff767e920
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapperGetInherited.js
@@ -0,0 +1,18 @@
+// Getting a property O.X, inherited from a transparent cross-compartment wrapper W
+// that wraps a Proxy P.
+
+var g = newGlobal();
+var target = {}
+var P = new Proxy(target, {
+ get(t, id, r) {
+ assertEq(t, target);
+ assertEq(id, "X");
+ assertEq(r, wO);
+ return "vega";
+ }
+});
+
+g.W = P;
+g.eval("var O = Object.create(W);");
+var wO = g.O;
+assertEq(g.eval("O.X"), "vega");