Bug 1269928 - Fold DirectProxyHandler into Wrapper, which is now its only (non-test) consumer. r=efaust
authorJeff Walden <jwalden@mit.edu>
Tue, 03 May 2016 17:29:10 -0700
changeset 363204 1d72d5a56b144d8ddfefa99ad299f63cb521f546
parent 363177 35b6bedcbb2ec68e387a87d14e8f5c7b98d2743e
child 363205 8a037cb33a3d93a6a2c7aeec3b725eb796713b43
push id17139
push userbmo:jbeich@FreeBSD.org
push dateWed, 04 May 2016 07:51:34 +0000
reviewersefaust
bugs1269928
milestone49.0a1
Bug 1269928 - Fold DirectProxyHandler into Wrapper, which is now its only (non-test) consumer. r=efaust
js/public/Proxy.h
js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
js/src/jswrapper.h
js/src/moz.build
js/src/proxy/DirectProxyHandler.cpp
js/src/proxy/Wrapper.cpp
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -96,20 +96,18 @@ class JS_FRIEND_API(Wrapper);
  * object. Not every proxy has the notion of a target, however.
  *
  * To minimize code duplication, a set of abstract proxy handler classes is
  * provided, from which other handlers may inherit. These abstract classes are
  * organized in the following hierarchy:
  *
  *     BaseProxyHandler
  *     |
- *     DirectProxyHandler        // has a target
- *     |
- *     Wrapper                   // can be unwrapped, revealing target
- *     |                         // (see js::CheckedUnwrap)
+ *     Wrapper                   // has a target, can be unwrapped to reveal
+ *     |                         // target (see js::CheckedUnwrap)
  *     |
  *     CrossCompartmentWrapper   // target is in another compartment;
  *                               // implements membrane between compartments
  *
  * Example: Some DOM objects (including all the arraylike DOM objects) are
  * implemented as proxies. Since these objects don't need to forward operations
  * to any underlying JS object, DOMJSProxyHandler directly subclasses
  * BaseProxyHandler.
@@ -344,91 +342,16 @@ class JS_FRIEND_API(BaseProxyHandler)
     virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
                              ElementAdder* adder) const;
 
     /* See comment for weakmapKeyDelegateOp in js/Class.h. */
     virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const;
     virtual bool isScripted() const { return false; }
 };
 
-/*
- * DirectProxyHandler includes a notion of a target object. All methods are
- * reimplemented such that they forward their behavior to the target. This
- * allows consumers of this class to forward to another object as transparently
- * and efficiently as possible.
- *
- * Important: If you add a method implementation here, you probably also need
- * to add an override in CrossCompartmentWrapper. If you don't, you risk
- * compartment mismatches. See bug 945826 comment 0.
- */
-class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
-{
-  public:
-    explicit MOZ_CONSTEXPR DirectProxyHandler(const void* aFamily, bool aHasPrototype = false,
-                                              bool aHasSecurityPolicy = false)
-      : BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy)
-    { }
-
-    /* Standard internal methods. */
-    virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
-                                          MutableHandle<PropertyDescriptor> desc) const override;
-    virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
-                                Handle<PropertyDescriptor> desc,
-                                ObjectOpResult& result) const override;
-    virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                                 AutoIdVector& props) const override;
-    virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
-                         ObjectOpResult& result) const override;
-    virtual bool enumerate(JSContext* cx, HandleObject proxy,
-                           MutableHandleObject objp) const override;
-    virtual bool getPrototype(JSContext* cx, HandleObject proxy,
-                              MutableHandleObject protop) const override;
-    virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
-                              ObjectOpResult& result) const override;
-    virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
-                                        MutableHandleObject protop) const override;
-    virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
-                                       bool* succeeded) const override;
-    virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
-                                   ObjectOpResult& result) const override;
-    virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
-    virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
-                     bool* bp) const override;
-    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
-                     HandleId id, MutableHandleValue vp) const override;
-    virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult& result) const override;
-    virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
-    virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
-
-    /* SpiderMonkey extensions. */
-    virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
-                                       MutableHandle<PropertyDescriptor> desc) const override;
-    virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
-                        bool* bp) const override;
-    virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                              AutoIdVector& props) const override;
-    virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
-                            const CallArgs& args) const override;
-    virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
-                             bool* bp) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                 ESClassValue* classValue) const override;
-    virtual bool isArray(JSContext* cx, HandleObject proxy,
-                         JS::IsArrayAnswer* answer) const override;
-    virtual const char* className(JSContext* cx, HandleObject proxy) const override;
-    virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
-                                   unsigned indent) const override;
-    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
-                                 RegExpGuard* g) const override;
-    virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
-    virtual bool isCallable(JSObject* obj) const override;
-    virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
-};
-
 extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr;
 
 inline bool IsProxy(const JSObject* obj)
 {
     return GetObjectClass(obj)->isProxy();
 }
 
 namespace detail {
--- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
+++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
@@ -6,19 +6,20 @@
 
 #include "js/Proxy.h"
 
 #include "jsapi-tests/tests.h"
 
 using namespace js;
 using namespace JS;
 
-class CustomProxyHandler : public DirectProxyHandler {
+class CustomProxyHandler : public Wrapper
+{
   public:
-    CustomProxyHandler() : DirectProxyHandler(nullptr) {}
+    CustomProxyHandler() : Wrapper(0) {}
 
     bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                MutableHandle<PropertyDescriptor> desc) const override
     {
         return impl(cx, proxy, id, desc, false);
     }
 
     bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
@@ -26,17 +27,17 @@ class CustomProxyHandler : public Direct
     {
         return impl(cx, proxy, id, desc, true);
     }
 
     bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
              ObjectOpResult& result) const override
     {
         Rooted<PropertyDescriptor> desc(cx);
-        if (!DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, &desc))
+        if (!Wrapper::getPropertyDescriptor(cx, proxy, id, &desc))
             return false;
         return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result);
     }
 
   private:
     bool impl(JSContext* cx, HandleObject proxy, HandleId id,
               MutableHandle<PropertyDescriptor> desc, bool ownOnly) const
     {
@@ -48,18 +49,18 @@ class CustomProxyHandler : public Direct
                 desc.object().set(proxy);
                 desc.attributesRef() = JSPROP_ENUMERATE;
                 desc.value().setInt32(42);
                 return true;
             }
         }
 
         if (ownOnly)
-            return DirectProxyHandler::getOwnPropertyDescriptor(cx, proxy, id, desc);
-        return DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, desc);
+            return Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
+        return Wrapper::getPropertyDescriptor(cx, proxy, id, desc);
     }
 
 };
 
 const CustomProxyHandler customProxyHandler;
 
 
 BEGIN_TEST(testSetPropertyIgnoringNamedGetter_direct)
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -39,29 +39,99 @@ class MOZ_STACK_CLASS WrapperOptions : p
     }
 
   private:
     mozilla::Maybe<JS::RootedObject> proto_;
 };
 
 /*
  * A wrapper is a proxy with a target object to which it generally forwards
- * operations, but may restrict access to certain operations or instrument the
- * methods in various ways. A wrapper is distinct from a Direct Proxy Handler
- * in the sense that it can be "unwrapped" in C++, exposing the underlying
- * object (Direct Proxy Handlers have an underlying target object, but don't
- * expect to expose this object via any kind of unwrapping operation). Callers
- * should be careful to avoid unwrapping security wrappers in the wrong
+ * operations, but may restrict access to certain operations or augment those
+ * operations in various ways.
+ *
+ * A wrapper can be "unwrapped" in C++, exposing the underlying object.
+ * Callers should be careful to avoid unwrapping security wrappers in the wrong
  * context.
+ *
+ * Important: If you add a method implementation here, you probably also need
+ * to add an override in CrossCompartmentWrapper. If you don't, you risk
+ * compartment mismatches. See bug 945826 comment 0.
  */
-class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
+class JS_FRIEND_API(Wrapper) : public BaseProxyHandler
 {
     unsigned mFlags;
 
   public:
+    explicit MOZ_CONSTEXPR Wrapper(unsigned aFlags, bool aHasPrototype = false,
+                                   bool aHasSecurityPolicy = false)
+      : BaseProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
+        mFlags(aFlags)
+    { }
+
+    virtual bool finalizeInBackground(Value priv) const override;
+
+    /* Standard internal methods. */
+    virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+                                          MutableHandle<PropertyDescriptor> desc) const override;
+    virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+                                Handle<PropertyDescriptor> desc,
+                                ObjectOpResult& result) const override;
+    virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
+                                 AutoIdVector& props) const override;
+    virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
+                         ObjectOpResult& result) const override;
+    virtual bool enumerate(JSContext* cx, HandleObject proxy,
+                           MutableHandleObject objp) const override;
+    virtual bool getPrototype(JSContext* cx, HandleObject proxy,
+                              MutableHandleObject protop) const override;
+    virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+                              ObjectOpResult& result) const override;
+    virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+                                        MutableHandleObject protop) const override;
+    virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
+                                       bool* succeeded) const override;
+    virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
+                                   ObjectOpResult& result) const override;
+    virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
+    virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
+                     bool* bp) const override;
+    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
+                     HandleId id, MutableHandleValue vp) const override;
+    virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+                     HandleValue receiver, ObjectOpResult& result) const override;
+    virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
+    virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
+
+    /* SpiderMonkey extensions. */
+    virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+                                       MutableHandle<PropertyDescriptor> desc) const override;
+    virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
+                        bool* bp) const override;
+    virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
+                                              AutoIdVector& props) const override;
+    virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+                            const CallArgs& args) const override;
+    virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+                             bool* bp) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
+                                 ESClassValue* classValue) const override;
+    virtual bool isArray(JSContext* cx, HandleObject proxy,
+                         JS::IsArrayAnswer* answer) const override;
+    virtual const char* className(JSContext* cx, HandleObject proxy) const override;
+    virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
+                                   unsigned indent) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 RegExpGuard* g) const override;
+    virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
+                                  MutableHandleValue vp) const override;
+    virtual bool isCallable(JSObject* obj) const override;
+    virtual bool isConstructor(JSObject* obj) const override;
+    virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
+
+  public:
     using BaseProxyHandler::Action;
 
     enum Flags {
         CROSS_COMPARTMENT = 1 << 0,
         LAST_USED_FLAG = CROSS_COMPARTMENT
     };
 
     static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
@@ -72,25 +142,16 @@ class JS_FRIEND_API(Wrapper) : public Di
     static const Wrapper* wrapperHandler(JSObject* wrapper);
 
     static JSObject* wrappedObject(JSObject* wrapper);
 
     unsigned flags() const {
         return mFlags;
     }
 
-    explicit MOZ_CONSTEXPR Wrapper(unsigned aFlags, bool aHasPrototype = false,
-                                   bool aHasSecurityPolicy = false)
-      : DirectProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
-        mFlags(aFlags)
-    { }
-
-    virtual bool finalizeInBackground(Value priv) const override;
-    virtual bool isConstructor(JSObject* obj) const override;
-
     static const char family;
     static const Wrapper singleton;
     static const Wrapper singletonWithPrototype;
 
     static JSObject* defaultProto;
 };
 
 inline JSObject*
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -298,17 +298,16 @@ UNIFIED_SOURCES += [
     'jsscript.cpp',
     'jsstr.cpp',
     'jswatchpoint.cpp',
     'jsweakmap.cpp',
     'perf/jsperf.cpp',
     'proxy/BaseProxyHandler.cpp',
     'proxy/CrossCompartmentWrapper.cpp',
     'proxy/DeadObjectProxy.cpp',
-    'proxy/DirectProxyHandler.cpp',
     'proxy/OpaqueCrossCompartmentWrapper.cpp',
     'proxy/Proxy.cpp',
     'proxy/ScriptedDirectProxyHandler.cpp',
     'proxy/SecurityWrapper.cpp',
     'proxy/Wrapper.cpp',
     'vm/ArgumentsObject.cpp',
     'vm/ArrayBufferObject.cpp',
     'vm/CallNonGenericMethod.cpp',
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -8,269 +8,9 @@
 
 #include "js/Proxy.h"
 #include "vm/ProxyObject.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
-bool
-DirectProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
-                                          MutableHandle<PropertyDescriptor> desc) const
-{
-    assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
-    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetPropertyDescriptor(cx, target, id, desc);
-}
 
-bool
-DirectProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
-                                             MutableHandle<PropertyDescriptor> desc) const
-{
-    assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetOwnPropertyDescriptor(cx, target, id, desc);
-}
-
-bool
-DirectProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
-                                   Handle<PropertyDescriptor> desc,
-                                   ObjectOpResult& result) const
-{
-    assertEnteredPolicy(cx, proxy, id, SET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return DefineProperty(cx, target, id, desc, result);
-}
-
-bool
-DirectProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
-                                    AutoIdVector& props) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetPropertyKeys(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
-}
-
-bool
-DirectProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
-                            ObjectOpResult& result) const
-{
-    assertEnteredPolicy(cx, proxy, id, SET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return DeleteProperty(cx, target, id, result);
-}
-
-bool
-DirectProxyHandler::enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
-    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetIterator(cx, target, 0, objp);
-}
-
-bool
-DirectProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
-    RootedValue target(cx, proxy->as<ProxyObject>().private_());
-
-    InvokeArgs iargs(cx);
-    if (!FillArgumentsFromArraylike(cx, iargs, args))
-        return false;
-
-    return js::Call(cx, target, args.thisv(), iargs, args.rval());
-}
-
-bool
-DirectProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
-
-    RootedValue target(cx, proxy->as<ProxyObject>().private_());
-    if (!IsConstructor(target)) {
-        ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, target, nullptr);
-        return false;
-    }
-
-    ConstructArgs cargs(cx);
-    if (!FillArgumentsFromArraylike(cx, cargs, args))
-        return false;
-
-    RootedObject obj(cx);
-    if (!Construct(cx, target, cargs, args.newTarget(), &obj))
-        return false;
-
-    args.rval().setObject(*obj);
-    return true;
-}
-
-bool
-DirectProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
-                               const CallArgs& args) const
-{
-    args.setThis(ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
-    if (!test(args.thisv())) {
-        ReportIncompatible(cx, args);
-        return false;
-    }
-
-    return CallNativeImpl(cx, impl, args);
-}
-
-bool
-DirectProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
-                                bool* bp) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return HasInstance(cx, target, v, bp);
-}
-
-bool
-DirectProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetPrototype(cx, target, protop);
-}
-
-bool
-DirectProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
-                                 ObjectOpResult& result) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return SetPrototype(cx, target, proto, result);
-}
-
-bool
-DirectProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
-                                           bool* isOrdinary, MutableHandleObject protop) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetPrototypeIfOrdinary(cx, target, isOrdinary, protop);
-}
-
-bool
-DirectProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return SetImmutablePrototype(cx, target, succeeded);
-}
-
-bool
-DirectProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return PreventExtensions(cx, target, result);
-}
-
-bool
-DirectProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return IsExtensible(cx, target, extensible);
-}
-
-bool
-DirectProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                    ESClassValue* classValue) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetBuiltinClass(cx, target, classValue);
-}
-
-bool
-DirectProxyHandler::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return IsArray(cx, target, answer);
-}
-
-const char*
-DirectProxyHandler::className(JSContext* cx, HandleObject proxy) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetObjectClassName(cx, target);
-}
-
-JSString*
-DirectProxyHandler::fun_toString(JSContext* cx, HandleObject proxy,
-                                 unsigned indent) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return fun_toStringHelper(cx, target, indent);
-}
-
-bool
-DirectProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
-                                    RegExpGuard* g) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return RegExpToShared(cx, target, g);
-}
-
-bool
-DirectProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
-{
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return Unbox(cx, target, vp);
-}
-
-JSObject*
-DirectProxyHandler::weakmapKeyDelegate(JSObject* proxy) const
-{
-    return UncheckedUnwrap(proxy);
-}
-
-bool
-DirectProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
-{
-    assertEnteredPolicy(cx, proxy, id, GET);
-    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return HasProperty(cx, target, id, bp);
-}
-
-bool
-DirectProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
-{
-    assertEnteredPolicy(cx, proxy, id, GET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return HasOwnProperty(cx, target, id, bp);
-}
-
-bool
-DirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
-                        HandleId id, MutableHandleValue vp) const
-{
-    assertEnteredPolicy(cx, proxy, id, GET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetProperty(cx, target, receiver, id, vp);
-}
-
-bool
-DirectProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
-                        HandleValue receiver, ObjectOpResult& result) const
-{
-    assertEnteredPolicy(cx, proxy, id, SET);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return SetProperty(cx, target, id, v, receiver, result);
-}
-
-bool
-DirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
-                                                 AutoIdVector& props) const
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
-    RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
-}
-
-bool
-DirectProxyHandler::isCallable(JSObject* obj) const
-{
-    JSObject * target = obj->as<ProxyObject>().target();
-    return target->isCallable();
-}
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -4,23 +4,308 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsexn.h"
 #include "jswrapper.h"
 
+#include "js/Proxy.h"
 #include "vm/ErrorObject.h"
+#include "vm/ProxyObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
+bool
+Wrapper::finalizeInBackground(Value priv) const
+{
+    if (!priv.isObject())
+        return true;
+
+    /*
+     * Make the 'background-finalized-ness' of the wrapper the same as the
+     * wrapped object, to allow transplanting between them.
+     *
+     * If the wrapped object is in the nursery then we know it doesn't have a
+     * finalizer, and so background finalization is ok.
+     */
+    if (IsInsideNursery(&priv.toObject()))
+        return true;
+    return IsBackgroundFinalized(priv.toObject().asTenured().getAllocKind());
+}
+
+bool
+Wrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+                                  MutableHandle<PropertyDescriptor> desc) const
+{
+    assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetOwnPropertyDescriptor(cx, target, id, desc);
+}
+
+bool
+Wrapper::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+                        Handle<PropertyDescriptor> desc, ObjectOpResult& result) const
+{
+    assertEnteredPolicy(cx, proxy, id, SET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return DefineProperty(cx, target, id, desc, result);
+}
+
+bool
+Wrapper::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetPropertyKeys(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
+}
+
+bool
+Wrapper::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) const
+{
+    assertEnteredPolicy(cx, proxy, id, SET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return DeleteProperty(cx, target, id, result);
+}
+
+bool
+Wrapper::enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetIterator(cx, target, 0, objp);
+}
+
+bool
+Wrapper::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetPrototype(cx, target, protop);
+}
+
+bool
+Wrapper::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+                                 ObjectOpResult& result) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return SetPrototype(cx, target, proto, result);
+}
+
+bool
+Wrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
+                                           bool* isOrdinary, MutableHandleObject protop) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetPrototypeIfOrdinary(cx, target, isOrdinary, protop);
+}
+
+bool
+Wrapper::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return SetImmutablePrototype(cx, target, succeeded);
+}
+
+bool
+Wrapper::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return PreventExtensions(cx, target, result);
+}
+
+bool
+Wrapper::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return IsExtensible(cx, target, extensible);
+}
+
+bool
+Wrapper::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
+{
+    assertEnteredPolicy(cx, proxy, id, GET);
+    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return HasProperty(cx, target, id, bp);
+}
+
+bool
+Wrapper::get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
+             MutableHandleValue vp) const
+{
+    assertEnteredPolicy(cx, proxy, id, GET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetProperty(cx, target, receiver, id, vp);
+}
+
+bool
+Wrapper::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
+             ObjectOpResult& result) const
+{
+    assertEnteredPolicy(cx, proxy, id, SET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return SetProperty(cx, target, id, v, receiver, result);
+}
+
+bool
+Wrapper::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
+    RootedValue target(cx, proxy->as<ProxyObject>().private_());
+
+    InvokeArgs iargs(cx);
+    if (!FillArgumentsFromArraylike(cx, iargs, args))
+        return false;
+
+    return js::Call(cx, target, args.thisv(), iargs, args.rval());
+}
+
+bool
+Wrapper::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
+
+    RootedValue target(cx, proxy->as<ProxyObject>().private_());
+    if (!IsConstructor(target)) {
+        ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, target, nullptr);
+        return false;
+    }
+
+    ConstructArgs cargs(cx);
+    if (!FillArgumentsFromArraylike(cx, cargs, args))
+        return false;
+
+    RootedObject obj(cx);
+    if (!Construct(cx, target, cargs, args.newTarget(), &obj))
+        return false;
+
+    args.rval().setObject(*obj);
+    return true;
+}
+
+bool
+Wrapper::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+                               MutableHandle<PropertyDescriptor> desc) const
+{
+    assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
+    MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetPropertyDescriptor(cx, target, id, desc);
+}
+
+bool
+Wrapper::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
+{
+    assertEnteredPolicy(cx, proxy, id, GET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return HasOwnProperty(cx, target, id, bp);
+}
+
+bool
+Wrapper::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
+                                                 AutoIdVector& props) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
+}
+
+bool
+Wrapper::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+                               const CallArgs& args) const
+{
+    args.setThis(ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
+    if (!test(args.thisv())) {
+        ReportIncompatible(cx, args);
+        return false;
+    }
+
+    return CallNativeImpl(cx, impl, args);
+}
+
+bool
+Wrapper::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+                                bool* bp) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return HasInstance(cx, target, v, bp);
+}
+
+bool
+Wrapper::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClassValue* classValue) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetBuiltinClass(cx, target, classValue);
+}
+
+bool
+Wrapper::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return IsArray(cx, target, answer);
+}
+
+const char*
+Wrapper::className(JSContext* cx, HandleObject proxy) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return GetObjectClassName(cx, target);
+}
+
+JSString*
+Wrapper::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
+{
+    assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return fun_toStringHelper(cx, target, indent);
+}
+
+bool
+Wrapper::regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return RegExpToShared(cx, target, g);
+}
+
+bool
+Wrapper::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
+{
+    RootedObject target(cx, proxy->as<ProxyObject>().target());
+    return Unbox(cx, target, vp);
+}
+
+bool
+Wrapper::isCallable(JSObject* obj) const
+{
+    JSObject * target = obj->as<ProxyObject>().target();
+    return target->isCallable();
+}
+
+bool
+Wrapper::isConstructor(JSObject* obj) const
+{
+    // For now, all wrappers are constructable if they are callable. We will want to eventually
+    // decouple this behavior, but none of the Wrapper infrastructure is currently prepared for
+    // that.
+    return isCallable(obj);
+}
+
+JSObject*
+Wrapper::weakmapKeyDelegate(JSObject* proxy) const
+{
+    return UncheckedUnwrap(proxy);
+}
+
 JSObject*
 Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler,
              const WrapperOptions& options)
 {
     RootedValue priv(cx, ObjectValue(*obj));
     return NewProxyObject(cx, handler, priv, options.proto(), options);
 }
 
@@ -40,40 +325,31 @@ Wrapper::wrapperHandler(JSObject* wrappe
 
 JSObject*
 Wrapper::wrappedObject(JSObject* wrapper)
 {
     MOZ_ASSERT(wrapper->is<WrapperObject>());
     return wrapper->as<ProxyObject>().target();
 }
 
-bool
-Wrapper::isConstructor(JSObject* obj) const
-{
-    // For now, all wrappers are constructable if they are callable. We will want to eventually
-    // decouple this behavior, but none of the Wrapper infrastructure is currently prepared for
-    // that.
-    return isCallable(obj);
-}
-
 JS_FRIEND_API(JSObject*)
 js::UncheckedUnwrap(JSObject* wrapped, bool stopAtWindowProxy, unsigned* flagsp)
 {
     unsigned flags = 0;
     while (true) {
         if (!wrapped->is<WrapperObject>() ||
             MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(wrapped)))
         {
             break;
         }
         flags |= Wrapper::wrapperHandler(wrapped)->flags();
         wrapped = wrapped->as<ProxyObject>().private_().toObjectOrNull();
 
-        // This can be called from DirectProxyHandler::weakmapKeyDelegate() on a
-        // wrapper whose referent has been moved while it is still unmarked.
+        // This can be called from Wrapper::weakmapKeyDelegate() on a wrapper
+        // whose referent has been moved while it is still unmarked.
         if (wrapped)
             wrapped = MaybeForwarded(wrapped);
     }
     if (flagsp)
         *flagsp = flags;
     return wrapped;
 }
 
@@ -103,17 +379,17 @@ js::UnwrapOneChecked(JSObject* obj, bool
 
 const char Wrapper::family = 0;
 const Wrapper Wrapper::singleton((unsigned)0);
 const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
 JSObject* Wrapper::defaultProto = TaggedProto::LazyProto;
 
 /* Compartments. */
 
-extern JSObject*
+JSObject*
 js::TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj)
 {
     // Allow wrapping outer window proxies.
     MOZ_ASSERT(!obj->is<WrapperObject>() || IsWindowProxy(obj));
     return Wrapper::New(cx, obj, &CrossCompartmentWrapper::singleton);
 }
 
 ErrorCopier::~ErrorCopier()
@@ -132,25 +408,8 @@ ErrorCopier::~ErrorCopier()
             ac.reset();
             Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
             JSObject* copyobj = CopyErrorObject(cx, errObj);
             if (copyobj)
                 cx->setPendingException(ObjectValue(*copyobj));
         }
     }
 }
-
-bool Wrapper::finalizeInBackground(Value priv) const
-{
-    if (!priv.isObject())
-        return true;
-
-    /*
-     * Make the 'background-finalized-ness' of the wrapper the same as the
-     * wrapped object, to allow transplanting between them.
-     *
-     * If the wrapped object is in the nursery then we know it doesn't have a
-     * finalizer, and so background finalization is ok.
-     */
-    if (IsInsideNursery(&priv.toObject()))
-        return true;
-    return IsBackgroundFinalized(priv.toObject().asTenured().getAllocKind());
-}