Bug 1053271 - Remove XrayTraits' HasPrototype. r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Mon, 04 Jun 2018 14:26:37 +0200
changeset 805266 3cd7e51e9913010024d318fa6b726f335e21c48f
parent 805265 c0c9e69ee274daf9d6c6eb017a92b856b88c368e
child 805267 00275042e5174f27f4a7697326dfd4a2a1c6c854
push id112610
push userbmo:gl@mozilla.com
push dateThu, 07 Jun 2018 15:48:24 +0000
reviewersbz
bugs1053271
milestone62.0a1
Bug 1053271 - Remove XrayTraits' HasPrototype. r=bz. XPCWN Xrays were the only Xrays that set HasPrototype to 0.
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1781,19 +1781,17 @@ XrayWrapper<Base, Traits>::isExtensible(
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
                                                  JS::MutableHandle<PropertyDescriptor> desc)
                                                  const
 {
-    // We can't assert !Traits::HasPrototypes here, because
-    // CrossOriginXrayWrapper::getOwnPropertyDescriptor calls us, but it uses
-    // DOMXrayTraits, which have HasPrototype.
+    // CrossOriginXrayWrapper::getOwnPropertyDescriptor calls this.
 
     assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET |
                                          BaseProxyHandler::GET_PROPERTY_DESCRIPTOR);
     RootedObject target(cx, Traits::getTargetObject(wrapper));
     RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
 
     if (!holder)
         return false;
@@ -2053,23 +2051,16 @@ XrayWrapper<Base, Traits>::delete_(JSCon
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::get(JSContext* cx, HandleObject wrapper,
                                HandleValue receiver, HandleId id,
                                MutableHandleValue vp) const
 {
     // Skip our Base if it isn't already ProxyHandler.
-    // NB: None of the functions we call are prepared for the receiver not
-    // being the wrapper, so ignore the receiver here.
-    RootedValue thisv(cx);
-    if (Traits::HasPrototype)
-      thisv = receiver;
-    else
-      thisv.setObject(*wrapper);
 
     // This uses getPropertyDescriptor for backward compatibility with
     // the old BaseProxyHandler::get implementation.
     Rooted<PropertyDescriptor> desc(cx);
     if (!getPropertyDescriptor(cx, wrapper, id, &desc))
         return false;
     desc.assertCompleteIfFound();
 
@@ -2087,30 +2078,26 @@ XrayWrapper<Base, Traits>::get(JSContext
     MOZ_ASSERT(desc.isAccessorDescriptor());
     RootedObject getter(cx, desc.getterObject());
 
     if (!getter) {
         vp.setUndefined();
         return true;
     }
 
-    return Call(cx, thisv, getter, HandleValueArray::empty(), vp);
+    return Call(cx, receiver, getter, HandleValueArray::empty(), vp);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
                                HandleValue receiver, ObjectOpResult& result) const
 {
-    MOZ_ASSERT(!Traits::HasPrototype);
-    // Skip our Base if it isn't already BaseProxyHandler.
-    // NB: None of the functions we call are prepared for the receiver not
-    // being the wrapper, so ignore the receiver here.
-    RootedValue wrapperValue(cx, ObjectValue(*wrapper));
-    return js::BaseProxyHandler::set(cx, wrapper, id, v, wrapperValue, result);
+    MOZ_CRASH("Shouldn't be called");
+    return false;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::has(JSContext* cx, HandleObject wrapper,
                                HandleId id, bool* bp) const
 {
     // This uses getPropertyDescriptor for backward compatibility with
@@ -2141,19 +2128,18 @@ XrayWrapper<Base, Traits>::getOwnEnumera
     // Skip our Base if it isn't already ProxyHandler.
     return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props);
 }
 
 template <typename Base, typename Traits>
 JSObject*
 XrayWrapper<Base, Traits>::enumerate(JSContext* cx, HandleObject wrapper) const
 {
-    MOZ_ASSERT(!Traits::HasPrototype, "Why did we get called?");
-    // Skip our Base if it isn't already ProxyHandler.
-    return js::BaseProxyHandler::enumerate(cx, wrapper);
+    MOZ_CRASH("Shouldn't be called");
+    return nullptr;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::call(JSContext* cx, HandleObject wrapper, const JS::CallArgs& args) const
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::CALL);
     // Hard cast the singleton since SecurityWrapper doesn't have one.
@@ -2219,17 +2205,17 @@ XrayWrapper<Base, Traits>::getPrototype(
     // Check our holder, and cache there if we don't have it cached already.
     RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
     if (!holder)
         return false;
 
     Value cached = js::GetReservedSlot(holder,
                                        Traits::HOLDER_SLOT_CACHED_PROTO);
     if (cached.isUndefined()) {
-        if (!getPrototypeHelper(cx, wrapper, target, protop))
+        if (!Traits::singleton.getPrototype(cx, wrapper, target, protop))
             return false;
 
         js::SetReservedSlot(holder, Traits::HOLDER_SLOT_CACHED_PROTO,
                             ObjectOrNullValue(protop));
     } else {
         protop.set(cached.toObjectOrNull());
     }
     return true;
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -141,20 +141,16 @@ private:
     const XrayTraits& operator=(XrayTraits&) = delete;
 };
 
 class DOMXrayTraits : public XrayTraits
 {
 public:
     constexpr DOMXrayTraits() = default;
 
-    enum {
-        HasPrototype = 1
-    };
-
     static const XrayType Type = XrayForDOMObject;
 
     virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
                                        JS::HandleObject holder, JS::HandleId id,
                                        JS::MutableHandle<JS::PropertyDescriptor> desc) override
     {
         // Xrays for DOM binding objects have a prototype chain that consists of
         // Xrays for the prototypes of the DOM binding object (ignoring changes
@@ -197,19 +193,16 @@ public:
 protected:
     virtual const JSClass* getExpandoClass(JSContext* cx,
                                            JS::HandleObject target) const override;
 };
 
 class JSXrayTraits : public XrayTraits
 {
 public:
-    enum {
-        HasPrototype = 1
-    };
     static const XrayType Type = XrayForJSObject;
 
     virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
                                        JS::HandleObject holder, JS::HandleId id,
                                        JS::MutableHandle<JS::PropertyDescriptor> desc) override
     {
         MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
     }
@@ -314,19 +307,16 @@ public:
 };
 
 // These traits are used when the target is not Xrayable and we therefore want
 // to make it opaque modulo the usual Xray machinery (like expandos and
 // .wrappedJSObject).
 class OpaqueXrayTraits : public XrayTraits
 {
 public:
-    enum {
-        HasPrototype = 1
-    };
     static const XrayType Type = XrayForOpaqueObject;
 
     virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
                                        JS::HandleObject holder, JS::HandleId id,
                                        JS::MutableHandle<JS::PropertyDescriptor> desc) override
     {
         MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
     }
@@ -399,22 +389,23 @@ public:
     }
 
     static OpaqueXrayTraits singleton;
 };
 
 XrayType GetXrayType(JSObject* obj);
 XrayTraits* GetXrayTraits(JSObject* obj);
 
-// NB: Base *must* derive from JSProxyHandler
 template <typename Base, typename Traits>
 class XrayWrapper : public Base {
+    static_assert(mozilla::IsBaseOf<js::BaseProxyHandler, Base>::value,
+                  "Base *must* derive from js::BaseProxyHandler");
   public:
     constexpr explicit XrayWrapper(unsigned flags)
-      : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG, Traits::HasPrototype)
+      : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG, /* aHasPrototype = */ true)
     { };
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                           JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                 JS::Handle<JS::PropertyDescriptor> desc,
                                 JS::ObjectOpResult& result) const override;
@@ -454,38 +445,16 @@ class XrayWrapper : public Base {
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
                                               JS::AutoIdVector& props) const override;
 
     virtual bool getBuiltinClass(JSContext* cx, JS::HandleObject wapper, js::ESClass* cls) const override;
     virtual const char* className(JSContext* cx, JS::HandleObject proxy) const override;
 
     static const XrayWrapper singleton;
 
-  private:
-    template <bool HasPrototype>
-    typename mozilla::EnableIf<HasPrototype, bool>::Type
-        getPrototypeHelper(JSContext* cx, JS::HandleObject wrapper,
-                           JS::HandleObject target, JS::MutableHandleObject protop) const
-    {
-        return Traits::singleton.getPrototype(cx, wrapper, target, protop);
-    }
-    template <bool HasPrototype>
-    typename mozilla::EnableIf<!HasPrototype, bool>::Type
-        getPrototypeHelper(JSContext* cx, JS::HandleObject wrapper,
-                           JS::HandleObject target, JS::MutableHandleObject protop) const
-    {
-        return Base::getPrototype(cx, wrapper, protop);
-    }
-    bool getPrototypeHelper(JSContext* cx, JS::HandleObject wrapper,
-                            JS::HandleObject target, JS::MutableHandleObject protop) const
-    {
-        return getPrototypeHelper<Traits::HasPrototype>(cx, wrapper, target,
-                                                        protop);
-    }
-
   protected:
     bool getPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper, unsigned flags,
                          JS::AutoIdVector& props) const;
 };
 
 #define PermissiveXrayDOM xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
 #define SecurityXrayDOM xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::DOMXrayTraits>
 #define PermissiveXrayJS xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::JSXrayTraits>