Bug 1105045 - Outerize the receiver passed to proxy hooks. r=efaust, a=sylvestre.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 24 Aug 2015 15:20:49 -0500
changeset 288871 226332faa0052f8182d45fe7f1f72be933243a07
parent 288870 1a373581e42c1903922c5198d899f9f4ad58d753
child 288872 c0b4ef91febc6515ae17078efc841d039b5ad401
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust, sylvestre
bugs1105045
milestone42.0a2
Bug 1105045 - Outerize the receiver passed to proxy hooks. r=efaust, a=sylvestre.
js/src/proxy/Proxy.cpp
js/src/tests/ecma_6/Proxy/global-receiver.js
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -260,26 +260,41 @@ Proxy::hasOwn(JSContext* cx, HandleObjec
     const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
     *bp = false; // default result if we refuse to perform this action
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
     return handler->hasOwn(cx, proxy, id, bp);
 }
 
+static Value
+OuterizeValue(JSContext* cx, HandleValue v)
+{
+    if (v.isObject()) {
+        RootedObject obj(cx, &v.toObject());
+        return ObjectValue(*GetOuterObject(cx, obj));
+    }
+    return v;
+}
+
 bool
-Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
+Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver_, HandleId id,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
     vp.setUndefined(); // default result if we refuse to perform this action
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
+
+    // Outerize the receiver. Proxy handlers shouldn't have to know about
+    // the Window/WindowProxy distinction.
+    RootedObject receiver(cx, GetOuterObject(cx, receiver_));
+
     bool own;
     if (!handler->hasPrototype()) {
         own = true;
     } else {
         if (!handler->hasOwn(cx, proxy, id, &own))
             return false;
     }
     if (own)
@@ -302,28 +317,32 @@ Proxy::callProp(JSContext* cx, HandleObj
             return false;
     }
 #endif
 
     return true;
 }
 
 bool
-Proxy::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
+Proxy::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver_,
            ObjectOpResult& result)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
     if (!policy.allowed()) {
         if (!policy.returnValue())
             return false;
         return result.succeed();
     }
 
+    // Outerize the receiver. Proxy handlers shouldn't have to know about
+    // the Window/WindowProxy distinction.
+    RootedValue receiver(cx, OuterizeValue(cx, receiver_));
+
     // Special case. See the comment on BaseProxyHandler::mHasPrototype.
     if (handler->hasPrototype())
         return handler->BaseProxyHandler::set(cx, proxy, id, v, receiver, result);
 
     return handler->set(cx, proxy, id, v, receiver, result);
 }
 
 bool
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Proxy/global-receiver.js
@@ -0,0 +1,29 @@
+// The global object can be the receiver passed to the get and set traps of a Proxy.
+
+var global = this;
+var proto = Object.getPrototypeOf(global);
+var gets = 0, sets = 0;
+Object.setPrototypeOf(global, new Proxy(proto, {
+    has(t, id) {
+        return id === "bareword" || Reflect.has(t, id);
+    },
+    get(t, id, r) {
+        gets++;
+        assertEq(r, global);
+        return Reflect.get(t, id, r);
+    },
+    set(t, id, v, r) {
+        sets++;
+        assertEq(r, global);
+        return Reflect.set(t, id, v, r);
+    }
+}));
+
+assertEq(bareword, undefined);
+assertEq(gets, 1);
+
+bareword = 12;
+assertEq(sets, 1);
+assertEq(global.bareword, 12);
+
+reportCompare(0, 0);