Bug 1091900 - Make GetIterator and others take an object as outparam. r=efaust
authorTom Schuster <evilpies@gmail.com>
Wed, 19 Nov 2014 01:44:03 +0100
changeset 240696 14a34e921e1b2ec5b962ecd6ffccc009f0684c44
parent 240695 22179ebb537b2e79f76b310ddbe4845801616615
child 240697 acf354e64226225a21e8e2542d0d75b52b541e1b
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1091900
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1091900 - Make GetIterator and others take an object as outparam. r=efaust
dom/base/nsGlobalWindow.cpp
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsproxy.h
js/src/jswrapper.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DirectProxyHandler.cpp
js/src/proxy/Proxy.cpp
js/src/proxy/Proxy.h
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/proxy/ScriptedDirectProxyHandler.h
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/FilteringWrapper.h
js/xpconnect/wrappers/WaiveXrayWrapper.cpp
js/xpconnect/wrappers/WaiveXrayWrapper.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -647,17 +647,17 @@ public:
   virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
                       JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
   virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
                                             JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
                                          JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
                        unsigned flags,
-                       JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                       JS::MutableHandle<JSObject*> objp) const MOZ_OVERRIDE;
   virtual const char *className(JSContext *cx,
                                 JS::Handle<JSObject*> wrapper) const MOZ_OVERRIDE;
 
   virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
 
   virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
     return false;
   }
@@ -938,24 +938,23 @@ nsOuterWindowProxy::getEnumerablePropert
 
   JS::AutoIdVector innerProps(cx);
   if (!js::Wrapper::getEnumerablePropertyKeys(cx, proxy, innerProps)) {
     return false;
   }
   return js::AppendUnique(cx, props, innerProps);
 }
 
-
 bool
 nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
-                            unsigned flags, JS::MutableHandle<JS::Value> vp) const
+                            unsigned flags, JS::MutableHandle<JSObject*> objp) const
 {
   // BaseProxyHandler::iterate seems to do what we want here: fall
   // back on the property names returned from keys() and enumerate().
-  return js::BaseProxyHandler::iterate(cx, proxy, flags, vp);
+  return js::BaseProxyHandler::iterate(cx, proxy, flags, objp);
 }
 
 bool
 nsOuterWindowProxy::GetSubframeWindow(JSContext *cx,
                                       JS::Handle<JSObject*> proxy,
                                       JS::Handle<jsid> id,
                                       JS::MutableHandle<JS::Value> vp,
                                       bool& found) const
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -402,51 +402,53 @@ js::GetPropertyKeys(JSContext *cx, Handl
     return Snapshot(cx, obj,
                     flags & (JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY),
                     props);
 }
 
 size_t sCustomIteratorCount = 0;
 
 static inline bool
-GetCustomIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp)
+GetCustomIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleObject objp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
+    RootedValue rval(cx);
     /* Check whether we have a valid __iterator__ method. */
     HandlePropertyName name = cx->names().iteratorIntrinsic;
-    if (!JSObject::getProperty(cx, obj, obj, name, vp))
+    if (!JSObject::getProperty(cx, obj, obj, name, &rval))
         return false;
 
     /* If there is no custom __iterator__ method, we are done here. */
-    if (!vp.isObject()) {
-        vp.setUndefined();
+    if (!rval.isObject()) {
+        objp.set(nullptr);
         return true;
     }
 
     if (!cx->runningWithTrustedPrincipals())
         ++sCustomIteratorCount;
 
     /* Otherwise call it and return that object. */
     Value arg = BooleanValue((flags & JSITER_FOREACH) == 0);
-    if (!Invoke(cx, ObjectValue(*obj), vp, 1, &arg, vp))
+    if (!Invoke(cx, ObjectValue(*obj), rval, 1, &arg, &rval))
         return false;
-    if (vp.isPrimitive()) {
+    if (rval.isPrimitive()) {
         /*
          * We are always coming from js::ValueToIterator, and we are no longer on
          * trace, so the object we are iterating over is on top of the stack (-1).
          */
         JSAutoByteString bytes;
         if (!AtomToPrintableString(cx, name, &bytes))
             return false;
         RootedValue val(cx, ObjectValue(*obj));
         js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
                              -1, val, js::NullPtr(), bytes.ptr());
         return false;
     }
+    objp.set(&rval.toObject());
     return true;
 }
 
 template <typename T>
 static inline bool
 Compare(T *a, T *b, size_t c)
 {
     size_t n = (c + size_t(7)) / size_t(8);
@@ -557,17 +559,17 @@ RegisterEnumerator(JSContext *cx, Proper
 
         MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
         ni->flags |= JSITER_ACTIVE;
     }
 }
 
 static inline bool
 VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &keys,
-                    uint32_t slength, uint32_t key, MutableHandleValue vp)
+                    uint32_t slength, uint32_t key, MutableHandleObject objp)
 {
     MOZ_ASSERT(!(flags & JSITER_FOREACH));
 
     if (obj->hasSingletonType() && !obj->setIteratedSingleton(cx))
         return false;
     types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
 
     Rooted<PropertyIteratorObject *> iterobj(cx, NewPropertyIteratorObject(cx, flags));
@@ -592,25 +594,25 @@ VectorToKeyIterator(JSContext *cx, Handl
         do {
             ni->shapes_array[ind++] = pobj->lastProperty();
             pobj = pobj->getProto();
         } while (pobj);
         MOZ_ASSERT(ind == slength);
     }
 
     iterobj->setNativeIterator(ni);
-    vp.setObject(*iterobj);
+    objp.set(iterobj);
 
     RegisterEnumerator(cx, iterobj, ni);
     return true;
 }
 
 static bool
 VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &keys,
-                      MutableHandleValue vp)
+                      MutableHandleObject objp)
 {
     MOZ_ASSERT(flags & JSITER_FOREACH);
 
     if (obj->hasSingletonType() && !obj->setIteratedSingleton(cx))
         return false;
     types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
 
     Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx, flags));
@@ -618,66 +620,66 @@ VectorToValueIterator(JSContext *cx, Han
         return false;
 
     NativeIterator *ni = NativeIterator::allocateIterator(cx, 0, keys);
     if (!ni)
         return false;
     ni->init(obj, iterobj, flags, 0, 0);
 
     iterobj->setNativeIterator(ni);
-    vp.setObject(*iterobj);
+    objp.set(iterobj);
 
     RegisterEnumerator(cx, iterobj, ni);
     return true;
 }
 
 bool
 js::EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags,
-                                 AutoIdVector &props, MutableHandleValue vp)
+                                 AutoIdVector &props, MutableHandleObject objp)
 {
     if (!(flags & JSITER_FOREACH))
-        return VectorToKeyIterator(cx, obj, flags, props, 0, 0, vp);
+        return VectorToKeyIterator(cx, obj, flags, props, 0, 0, objp);
 
-    return VectorToValueIterator(cx, obj, flags, props, vp);
+    return VectorToValueIterator(cx, obj, flags, props, objp);
 }
 
 // Mainly used for .. in over null/undefined
 bool
-js::NewEmptyPropertyIterator(JSContext *cx, unsigned flags, MutableHandleValue vp)
+js::NewEmptyPropertyIterator(JSContext *cx, unsigned flags, MutableHandleObject objp)
 {
     Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx, flags));
     if (!iterobj)
         return false;
 
     AutoIdVector keys(cx); // Empty
     NativeIterator *ni = NativeIterator::allocateIterator(cx, 0, keys);
     if (!ni)
         return false;
     ni->init(nullptr, iterobj, flags, 0, 0);
 
     iterobj->setNativeIterator(ni);
-    vp.setObject(*iterobj);
+    objp.set(iterobj);
 
     RegisterEnumerator(cx, iterobj, ni);
     return true;
 }
 
 static inline void
 UpdateNativeIterator(NativeIterator *ni, JSObject *obj)
 {
     // Update the object for which the native iterator is associated, so
     // SuppressDeletedPropertyHelper will recognize the iterator as a match.
     ni->obj = obj;
 }
 
 bool
-js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp)
+js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleObject objp)
 {
     if (obj->is<PropertyIteratorObject>() || obj->is<LegacyGeneratorObject>()) {
-        vp.setObject(*obj);
+        objp.set(obj);
         return true;
     }
 
     Vector<Shape *, 8> shapes(cx);
     uint32_t key = 0;
     if (flags == JSITER_ENUMERATE) {
         /*
          * Check to see if this is the same as the most recent object which
@@ -694,17 +696,17 @@ js::GetIterator(JSContext *cx, HandleObj
                 obj->lastProperty() == lastni->shapes_array[0])
             {
                 JSObject *proto = obj->getProto();
                 if (proto->isNative() &&
                     proto->as<NativeObject>().hasEmptyElements() &&
                     proto->lastProperty() == lastni->shapes_array[1] &&
                     !proto->getProto())
                 {
-                    vp.setObject(*last);
+                    objp.set(last);
                     UpdateNativeIterator(lastni, obj);
                     RegisterEnumerator(cx, last, lastni);
                     return true;
                 }
             }
         }
 
         /*
@@ -737,69 +739,69 @@ js::GetIterator(JSContext *cx, HandleObj
 
         PropertyIteratorObject *iterobj = cx->runtime()->nativeIterCache.get(key);
         if (iterobj) {
             NativeIterator *ni = iterobj->getNativeIterator();
             if (!(ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
                 ni->shapes_key == key &&
                 ni->shapes_length == shapes.length() &&
                 Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) {
-                vp.setObject(*iterobj);
+                objp.set(iterobj);
 
                 UpdateNativeIterator(ni, obj);
                 RegisterEnumerator(cx, iterobj, ni);
                 if (shapes.length() == 2)
                     cx->runtime()->nativeIterCache.last = iterobj;
                 return true;
             }
         }
     }
 
   miss:
     if (obj->is<ProxyObject>())
-        return Proxy::iterate(cx, obj, flags, vp);
+        return Proxy::iterate(cx, obj, flags, objp);
 
-    if (!GetCustomIterator(cx, obj, flags, vp))
+    if (!GetCustomIterator(cx, obj, flags, objp))
         return false;
-    if (!vp.isUndefined())
+    if (objp)
         return true;
 
     AutoIdVector keys(cx);
     if (flags & JSITER_FOREACH) {
         MOZ_ASSERT(shapes.empty());
 
         if (!Snapshot(cx, obj, flags, &keys))
             return false;
-        if (!VectorToValueIterator(cx, obj, flags, keys, vp))
+        if (!VectorToValueIterator(cx, obj, flags, keys, objp))
             return false;
     } else {
         if (!Snapshot(cx, obj, flags, &keys))
             return false;
-        if (!VectorToKeyIterator(cx, obj, flags, keys, shapes.length(), key, vp))
+        if (!VectorToKeyIterator(cx, obj, flags, keys, shapes.length(), key, objp))
             return false;
     }
 
-    PropertyIteratorObject *iterobj = &vp.toObject().as<PropertyIteratorObject>();
+    PropertyIteratorObject *iterobj = &objp->as<PropertyIteratorObject>();
 
     /* Cache the iterator object if possible. */
     if (shapes.length())
         cx->runtime()->nativeIterCache.set(key, iterobj);
 
     if (shapes.length() == 2)
         cx->runtime()->nativeIterCache.last = iterobj;
     return true;
 }
 
 JSObject *
 js::GetIteratorObject(JSContext *cx, HandleObject obj, uint32_t flags)
 {
-    RootedValue value(cx);
-    if (!GetIterator(cx, obj, flags, &value))
+    RootedObject iterator(cx);
+    if (!GetIterator(cx, obj, flags, &iterator))
         return nullptr;
-    return &value.toObject();
+    return iterator;
 }
 
 JSObject *
 js::CreateItrResultObject(JSContext *cx, HandleValue value, bool done)
 {
     // FIXME: We can cache the iterator result object shape somewhere.
     AssertHeapIsIdle(cx);
 
@@ -1010,24 +1012,32 @@ js::ValueToIterator(JSContext *cx, unsig
         /* Common case. */
         obj = &vp.toObject();
     } else if ((flags & JSITER_ENUMERATE) && vp.isNullOrUndefined()) {
         /*
          * Enumerating over null and undefined gives an empty enumerator, so
          * that |for (var p in <null or undefined>) <loop>;| never executes
          * <loop>, per ES5 12.6.4.
          */
-         return NewEmptyPropertyIterator(cx, flags, vp);
+        RootedObject iter(cx);
+        if (!NewEmptyPropertyIterator(cx, flags, &iter))
+            return false;
+        vp.setObject(*iter);
+        return true;
     } else {
         obj = ToObject(cx, vp);
         if (!obj)
             return false;
     }
 
-    return GetIterator(cx, obj, flags, vp);
+    RootedObject iter(cx);
+    if (!GetIterator(cx, obj, flags, &iter))
+        return false;
+    vp.setObject(*iter);
+    return true;
 }
 
 bool
 js::CloseIterator(JSContext *cx, HandleObject obj)
 {
     if (obj->is<PropertyIteratorObject>()) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator *ni = obj->as<PropertyIteratorObject>().getNativeIterator();
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -144,31 +144,31 @@ class StringIteratorObject : public JSOb
   public:
     static const Class class_;
 };
 
 bool
 VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap);
 
 bool
-GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp);
+GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleObject objp);
 
 JSObject *
 GetIteratorObject(JSContext *cx, HandleObject obj, unsigned flags);
 
 /*
  * Creates either a key or value iterator, depending on flags. For a value
  * iterator, performs value-lookup to convert the given list of jsids.
  */
 bool
 EnumeratedIdVectorToIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector &props,
-                             MutableHandleValue vp);
+                             MutableHandleObject objp);
 
 bool
-NewEmptyPropertyIterator(JSContext *cx, unsigned flags, MutableHandleValue vp);
+NewEmptyPropertyIterator(JSContext *cx, unsigned flags, MutableHandleObject objp);
 
 /*
  * Convert the value stored in *vp to its iteration object. The flags should
  * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating
  * for-in semantics are required, and when the caller can guarantee that the
  * iterator will never be exposed to scripts.
  */
 bool
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -303,17 +303,17 @@ class JS_FRIEND_API(BaseProxyHandler)
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const = 0;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const;
     virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                            AutoIdVector &props) const = 0;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                         MutableHandleValue vp) const;
+                         MutableHandleObject objp) const;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const;
     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const;
     virtual const char *className(JSContext *cx, HandleObject proxy) const;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const;
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const;
     virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const;
     virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) const;
@@ -390,17 +390,17 @@ class JS_PUBLIC_API(DirectProxyHandler) 
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
                         bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                            AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                         MutableHandleValue vp) const MOZ_OVERRIDE;
+                         MutableHandleObject objp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
                              bool *bp) const MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
                                JSContext *cx) const MOZ_OVERRIDE;
     virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy,
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -141,17 +141,17 @@ class JS_FRIEND_API(CrossCompartmentWrap
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
                                            AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
-                         MutableHandleValue vp) const MOZ_OVERRIDE;
+                         MutableHandleObject objp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
                              bool *bp) const MOZ_OVERRIDE;
     virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
                                    unsigned indent) const MOZ_OVERRIDE;
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -193,28 +193,28 @@ BaseProxyHandler::getOwnEnumerableProper
     MOZ_ASSERT(i <= props.length());
     props.resize(i);
 
     return true;
 }
 
 bool
 BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                          MutableHandleValue vp) const
+                          MutableHandleObject objp) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
 
     AutoIdVector props(cx);
     if ((flags & JSITER_OWNONLY)
         ? !getOwnEnumerablePropertyKeys(cx, proxy, props)
         : !getEnumerablePropertyKeys(cx, proxy, props)) {
         return false;
     }
 
-    return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
+    return EnumeratedIdVectorToIterator(cx, proxy, flags, props, objp);
 }
 
 bool
 BaseProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
 {
     MOZ_CRASH("callable proxies should implement call trap");
 }
 
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -198,21 +198,19 @@ CrossCompartmentWrapper::getEnumerablePr
            NOTHING);
 }
 
 /*
  * We can reify non-escaping iterator objects instead of having to wrap them. This
  * allows fast iteration over objects across a compartment boundary.
  */
 static bool
-CanReify(HandleValue vp)
+CanReify(HandleObject obj)
 {
-    JSObject *obj;
-    return vp.isObject() &&
-           (obj = &vp.toObject())->is<PropertyIteratorObject>() &&
+    return obj->is<PropertyIteratorObject>() &&
            (obj->as<PropertyIteratorObject>().getNativeIterator()->flags & JSITER_ENUMERATE);
 }
 
 struct AutoCloseIterator
 {
     AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(cx, obj) {}
 
     ~AutoCloseIterator() { if (obj) CloseIterator(cx, obj); }
@@ -220,19 +218,19 @@ struct AutoCloseIterator
     void clear() { obj = nullptr; }
 
   private:
     JSContext *cx;
     RootedObject obj;
 };
 
 static bool
-Reify(JSContext *cx, JSCompartment *origin, MutableHandleValue vp)
+Reify(JSContext *cx, JSCompartment *origin, MutableHandleObject objp)
 {
-    Rooted<PropertyIteratorObject*> iterObj(cx, &vp.toObject().as<PropertyIteratorObject>());
+    Rooted<PropertyIteratorObject*> iterObj(cx, &objp->as<PropertyIteratorObject>());
     NativeIterator *ni = iterObj->getNativeIterator();
 
     AutoCloseIterator close(cx, iterObj);
 
     /* Wrap the iteratee. */
     RootedObject obj(cx, ni->obj);
     if (!origin->wrap(cx, &obj))
         return false;
@@ -255,32 +253,32 @@ Reify(JSContext *cx, JSCompartment *orig
             keys.infallibleAppend(id);
         }
     }
 
     close.clear();
     if (!CloseIterator(cx, iterObj))
         return false;
 
-    return EnumeratedIdVectorToIterator(cx, obj, ni->flags, keys, vp);
+    return EnumeratedIdVectorToIterator(cx, obj, ni->flags, keys, objp);
 }
 
 bool
 CrossCompartmentWrapper::iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
-                                 MutableHandleValue vp) const
+                                 MutableHandleObject objp) const
 {
     {
         AutoCompartment call(cx, wrappedObject(wrapper));
-        if (!Wrapper::iterate(cx, wrapper, flags, vp))
+        if (!Wrapper::iterate(cx, wrapper, flags, objp))
             return false;
     }
 
-    if (CanReify(vp))
-        return Reify(cx, cx->compartment(), vp);
-    return cx->compartment()->wrap(cx, vp);
+    if (CanReify(objp))
+        return Reify(cx, cx->compartment(), objp);
+    return cx->compartment()->wrap(cx, objp);
 }
 
 bool
 CrossCompartmentWrapper::call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const
 {
     RootedObject wrapped(cx, wrappedObject(wrapper));
 
     {
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -249,22 +249,22 @@ DirectProxyHandler::getEnumerablePropert
     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 GetPropertyKeys(cx, target, 0, &props);
 }
 
 bool
 DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                            MutableHandleValue vp) const
+                            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, flags, vp);
+    return GetIterator(cx, target, flags, objp);
 }
 
 bool
 DirectProxyHandler::isCallable(JSObject *obj) const
 {
     JSObject * target = obj->as<ProxyObject>().target();
     return target->isCallable();
 }
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -380,40 +380,40 @@ Proxy::getEnumerablePropertyKeys(JSConte
         return false;
     AutoIdVector protoProps(cx);
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
                         GetPropertyKeys(cx, proto, 0, &protoProps) &&
                         AppendUnique(cx, props, protoProps));
 }
 
 bool
-Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
+Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleObject objp)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
-    vp.setUndefined(); // default result if we refuse to perform this action
+    objp.set(nullptr); // default result if we refuse to perform this action
     if (!handler->hasPrototype()) {
         AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                                BaseProxyHandler::ENUMERATE, true);
         // If the policy denies access but wants us to return true, we need
         // to hand a valid (empty) iterator object to the caller.
         if (!policy.allowed()) {
             return policy.returnValue() &&
-                   NewEmptyPropertyIterator(cx, flags, vp);
+                   NewEmptyPropertyIterator(cx, flags, objp);
         }
-        return handler->iterate(cx, proxy, flags, vp);
+        return handler->iterate(cx, proxy, flags, objp);
     }
     AutoIdVector props(cx);
     // The other Proxy::foo methods do the prototype-aware work for us here.
     if ((flags & JSITER_OWNONLY)
         ? !Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props)
         : !Proxy::getEnumerablePropertyKeys(cx, proxy, props)) {
         return false;
     }
-    return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
+    return EnumeratedIdVectorToIterator(cx, proxy, flags, props, objp);
 }
 
 bool
 Proxy::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
 
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -51,17 +51,17 @@ class Proxy
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                       MutableHandle<JSPropertyDescriptor> desc);
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                       MutableHandleValue vp);
     static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                              AutoIdVector &props);
     static bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
-    static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
+    static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleObject objp);
     static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
     static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
     static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
     static const char *className(JSContext *cx, HandleObject proxy);
     static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
     static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
     static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp);
     static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1015,20 +1015,20 @@ ScriptedDirectProxyHandler::set(JSContex
 
     // step 11, 15
     vp.set(BooleanValue(success));
     return true;
 }
 
 bool
 ScriptedDirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                                    MutableHandleValue vp) const
+                                    MutableHandleObject objp) const
 {
     // FIXME: Provide a proper implementation for this trap, see bug 787004
-    return DirectProxyHandler::iterate(cx, proxy, flags, vp);
+    return DirectProxyHandler::iterate(cx, proxy, flags, objp);
 }
 
 // ES6 (22 May, 2014) 9.5.13 Proxy.[[Call]]
 bool
 ScriptedDirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
 {
     // step 1
     RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -60,17 +60,17 @@ class ScriptedDirectProxyHandler : publi
     // the target's properties.
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE {
         return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
     }
     virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                            AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                         MutableHandleValue vp) const MOZ_OVERRIDE;
+                         MutableHandleObject objp) const MOZ_OVERRIDE;
 
     virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
     virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
         // For now we maintain the broken behavior that a scripted proxy is constructable if it's
         // callable. See bug 929467.
         return isCallable(obj);
     }
     virtual bool isScripted() const MOZ_OVERRIDE { return true; }
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -313,26 +313,32 @@ ScriptedIndirectProxyHandler::getEnumera
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().enumerate, &fval) &&
            Trap(cx, handler, fval, 0, nullptr, &value) &&
            ArrayToIdVector(cx, value, props);
 }
 
 bool
 ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                                      MutableHandleValue vp) const
+                                      MutableHandleObject objp) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue value(cx);
     if (!GetDerivedTrap(cx, handler, cx->names().iterate, &value))
         return false;
     if (!IsCallable(value))
-        return BaseProxyHandler::iterate(cx, proxy, flags, vp);
-    return Trap(cx, handler, value, 0, nullptr, vp) &&
-           ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, vp);
+        return BaseProxyHandler::iterate(cx, proxy, flags, objp);
+
+    RootedValue rval(cx);
+    if (!Trap(cx, handler, value, 0, nullptr, &rval))
+        return false;
+    if (!ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, rval))
+        return false;
+    objp.set(&rval.toObject());
+    return true;
 }
 
 bool
 ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                                          CallArgs args) const
 {
     return BaseProxyHandler::nativeCall(cx, test, impl, args);
 }
--- a/js/src/proxy/ScriptedIndirectProxyHandler.h
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.h
@@ -39,17 +39,17 @@ class ScriptedIndirectProxyHandler : pub
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                            AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                         MutableHandleValue vp) const MOZ_OVERRIDE;
+                         MutableHandleObject objp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
     virtual bool isScripted() const MOZ_OVERRIDE { return true; }
 
     static const char family;
     static const ScriptedIndirectProxyHandler singleton;
 };
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -733,19 +733,19 @@ xpc::SandboxProxyHandler::getOwnEnumerab
                                                        JS::Handle<JSObject*> proxy,
                                                        AutoIdVector &props) const
 {
     return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
 }
 
 bool
 xpc::SandboxProxyHandler::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
-                                  unsigned flags, JS::MutableHandle<Value> vp) const
+                                  unsigned flags, JS::MutableHandle<JSObject*> objp) const
 {
-    return BaseProxyHandler::iterate(cx, proxy, flags, vp);
+    return BaseProxyHandler::iterate(cx, proxy, flags, objp);
 }
 
 bool
 xpc::GlobalProperties::Parse(JSContext *cx, JS::HandleObject obj)
 {
     MOZ_ASSERT(JS_IsArrayObject(cx, obj));
 
     uint32_t length;
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -120,24 +120,24 @@ FilteringWrapper<Base, Policy>::getEnume
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
     return Base::getEnumerablePropertyKeys(cx, wrapper, props) &&
            Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::iterate(JSContext *cx, HandleObject wrapper,
-                                        unsigned flags, MutableHandleValue vp) const
+                                        unsigned flags, MutableHandleObject objp) const
 {
     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
     // We refuse to trigger the iterator hook across chrome wrappers because
     // we don't know how to censor custom iterator objects. Instead we trigger
     // the default proxy iterate trap, which will ask enumerate() for the list
     // of (censored) ids.
-    return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
+    return js::BaseProxyHandler::iterate(cx, wrapper, flags, objp);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                     const JS::CallArgs &args) const
 {
     if (!Policy::checkCall(cx, wrapper, args))
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -37,17 +37,17 @@ class FilteringWrapper : public Base {
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                            JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
-                         JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                         JS::MutableHandle<JSObject*> objp) const MOZ_OVERRIDE;
 
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const MOZ_OVERRIDE;
 
     virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl,
                             JS::CallArgs args) const MOZ_OVERRIDE;
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
@@ -55,20 +55,20 @@ WaiveXrayWrapper::get(JSContext *cx, Han
                       MutableHandleValue vp) const
 {
     return CrossCompartmentWrapper::get(cx, wrapper, receiver, id, vp) &&
            WrapperFactory::WaiveXrayAndWrap(cx, vp);
 }
 
 bool
 WaiveXrayWrapper::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                         MutableHandleValue vp) const
+                          MutableHandleObject objp) const
 {
-    return CrossCompartmentWrapper::iterate(cx, proxy, flags, vp) &&
-           WrapperFactory::WaiveXrayAndWrap(cx, vp);
+    return CrossCompartmentWrapper::iterate(cx, proxy, flags, objp) &&
+           (!objp || WrapperFactory::WaiveXrayAndWrap(cx, objp));
 }
 
 bool
 WaiveXrayWrapper::call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) const
 {
     return CrossCompartmentWrapper::call(cx, wrapper, args) &&
            WrapperFactory::WaiveXrayAndWrap(cx, args.rval());
 }
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.h
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h
@@ -25,17 +25,17 @@ class WaiveXrayWrapper : public js::Cros
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const MOZ_OVERRIDE;
 
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy, unsigned flags,
-                         JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                         JS::MutableHandle<JSObject*> objp) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test,
                             JS::NativeImpl impl, JS::CallArgs args) const MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
 
     static const WaiveXrayWrapper singleton;
 };
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -2122,20 +2122,20 @@ XrayWrapper<Base, Traits>::getEnumerable
                                                      AutoIdVector &props) const
 {
     return getPropertyKeys(cx, wrapper, 0, props);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::iterate(JSContext *cx, HandleObject wrapper,
-                                   unsigned flags, MutableHandleValue vp) const
+                                   unsigned flags, MutableHandleObject objp) const
 {
     // Skip our Base if it isn't already ProxyHandler.
-    return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
+    return js::BaseProxyHandler::iterate(cx, wrapper, flags, objp);
 }
 
 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.
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -437,17 +437,17 @@ class XrayWrapper : public Base {
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                         bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                            JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
-                         JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                         JS::MutableHandle<JSObject*> objp) const MOZ_OVERRIDE;
 
     virtual const char *className(JSContext *cx, JS::HandleObject proxy) const MOZ_OVERRIDE;
     virtual bool defaultValue(JSContext *cx, JS::HandleObject wrapper,
                               JSType hint, JS::MutableHandleValue vp)
                               const MOZ_OVERRIDE;
 
     static const XrayWrapper singleton;
 
@@ -508,17 +508,17 @@ public:
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> proxy,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                         bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
                                               JS::AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy, unsigned flags,
-                         JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                         JS::MutableHandle<JSObject*> objp) const MOZ_OVERRIDE;
 };
 
 extern const SandboxProxyHandler sandboxProxyHandler;
 
 // A proxy handler that lets us wrap callables and invoke them with
 // the correct this object, while forwarding all other operations down
 // to them directly.
 class SandboxCallableProxyHandler : public js::Wrapper {