Bug 899804 - Make CPOWs handle instanceof with WebIDL interfaces (r=bz,dvander)
authorBill McCloskey <wmccloskey@mozilla.com>
Thu, 01 Aug 2013 16:45:17 -0700
changeset 141277 123ae8924326f087bc3046ee794954c2b839dcd1
parent 141276 b1a2caba50bfa3dc22c46714c497225401c21b29
child 141278 e35b3cf5c8ddb3d5cf502e2c58a3d70969eeaa5c
push idunknown
push userunknown
push dateunknown
reviewersbz, dvander
bugs899804
milestone25.0a1
Bug 899804 - Make CPOWs handle instanceof with WebIDL interfaces (r=bz,dvander)
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Makefile.in
js/ipc/JavaScriptChild.cpp
js/ipc/JavaScriptChild.h
js/ipc/JavaScriptParent.cpp
js/ipc/JavaScriptParent.h
js/ipc/PJavaScript.ipdl
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2,16 +2,18 @@
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 <algorithm>
 #include <stdarg.h>
 
+#include "JavaScriptParent.h"
+
 #include "prprf.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Assertions.h"
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
@@ -1741,16 +1743,27 @@ InterfaceHasInstance(JSContext* cx, JS::
              "ID?");
 
   if (domClass &&
       domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
     *bp = true;
     return true;
   }
 
+  JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(instance, true));
+  if (unwrapped && jsipc::JavaScriptParent::IsCPOW(unwrapped)) {
+    bool boolp = false;
+    if (!jsipc::JavaScriptParent::DOMInstanceOf(unwrapped, clasp->mPrototypeID,
+                                                clasp->mDepth, &boolp)) {
+      return false;
+    }
+    *bp = boolp;
+    return true;
+  }
+
   JS::Rooted<JS::Value> protov(cx);
   DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov);
   MOZ_ASSERT(ok, "Someone messed with our prototype property?");
 
   JS::Rooted<JSObject*> interfacePrototype(cx, &protov.toObject());
   MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),
              "Someone messed with our prototype property?");
 
@@ -1782,16 +1795,31 @@ InterfaceHasInstance(JSContext* cx, JS::
     *bp = false;
     return true;
   }
 
   JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
   return InterfaceHasInstance(cx, obj, instanceObject, bp);
 }
 
+JSBool
+InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
+                     JS::Handle<JSObject*> instance,
+                     JSBool* bp)
+{
+  const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
+
+  MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count,
+             "Why do we have a hasInstance hook if we don't have a prototype "
+             "ID?");
+
+  *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID);
+  return true;
+}
+
 bool
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj)
 {
   GlobalObject global(cx, obj);
   if (global.Failed()) {
     return false;
   }
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2069,16 +2069,20 @@ ReparentWrapper(JSContext* aCx, JS::Hand
  */
 JSBool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
                      JS::Handle<JSObject*> instance,
                      JSBool* bp);
 JSBool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
                      JSBool* bp);
+JSBool
+InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
+                     JS::Handle<JSObject*> instance,
+                     JSBool* bp);
 
 // Helper for lenient getters/setters to report to console.  If this
 // returns false, we couldn't even get a global.
 bool
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj);
 
 inline JSObject*
 GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -69,16 +69,17 @@ CPPSRCS = \
   CallbackInterface.cpp \
   CallbackObject.cpp \
   DOMJSProxyHandler.cpp \
   $(NULL)
 endif
 
 LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \
   -I$(topsrcdir)/js/xpconnect/wrappers \
+  -I$(topsrcdir)/js/ipc \
   -I$(topsrcdir)/content/canvas/src \
   -I$(topsrcdir)/content/html/content/src \
   -I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/battery \
   -I$(topsrcdir)/dom/indexedDB \
   -I$(topsrcdir)/content/xslt/src/base \
   -I$(topsrcdir)/content/xslt/src/xpath \
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=4 sw=4 et tw=80:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "JavaScriptChild.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/BindingUtils.h"
 #include "nsContentUtils.h"
 #include "xpcprivate.h"
 #include "jsfriendapi.h"
 #include "nsCxPusher.h"
 
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
@@ -620,8 +621,32 @@ JavaScriptChild::AnswerInstanceOf(const 
     ConvertID(iid, &nsiid);
 
     nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
     if (rv != NS_OK)
         return fail(cx, rs);
 
     return ok(rs);
 }
+
+bool
+JavaScriptChild::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
+                                     const int &depth,
+                                     ReturnStatus *rs, bool *instanceof)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    *instanceof = false;
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    JSBool tmp;
+    if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
+        return fail(cx, rs);
+    *instanceof = tmp;
+
+    return ok(rs);
+}
--- a/js/ipc/JavaScriptChild.h
+++ b/js/ipc/JavaScriptChild.h
@@ -61,16 +61,18 @@ class JavaScriptChild
     bool AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
                              bool *result);
     bool AnswerClassName(const ObjectId &objId, nsString *result);
 
     bool AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
                                 ReturnStatus *rs, nsTArray<nsString> *names);
     bool AnswerInstanceOf(const ObjectId &objId, const JSIID &iid,
                           ReturnStatus *rs, bool *instanceof);
+    bool AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+                             ReturnStatus *rs, bool *instanceof);
 
   protected:
     JSObject *unwrap(JSContext *cx, ObjectId id);
 
   private:
     bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
     bool fail(JSContext *cx, ReturnStatus *rs);
     bool ok(ReturnStatus *rs);
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -509,17 +509,18 @@ JavaScriptParent::init()
         return false;
 
     return true;
 }
 
 bool
 JavaScriptParent::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
 {
-    if (!IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
+    obj = js::CheckedUnwrap(obj, false);
+    if (!obj || !IsProxy(obj) || GetProxyHandler(obj) != &CPOWProxyHandler::singleton) {
         JS_ReportError(cx, "cannot ipc non-cpow object");
         return false;
     }
 
     *idp = idOf(obj);
     return true;
 }
 
@@ -651,8 +652,29 @@ JavaScriptParent::instanceOf(JSObject *o
     if (!CallInstanceOf(objId, iid, &status, bp))
         return NS_ERROR_UNEXPECTED;
 
     if (!status.ok())
         return NS_ERROR_UNEXPECTED;
 
     return NS_OK;
 }
+
+/* static */ bool
+JavaScriptParent::DOMInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp)
+{
+    return ParentOf(obj)->domInstanceOf(obj, prototypeID, depth, bp);
+}
+
+bool
+JavaScriptParent::domInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp)
+{
+    ObjectId objId = idOf(obj);
+
+    ReturnStatus status;
+    if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
+        return false;
+
+    if (!status.ok())
+        return false;
+
+    return true;
+}
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -61,19 +61,26 @@ class JavaScriptParent
 
     void decref();
     void incref();
     void destroyFromContent();
 
     void drop(JSObject *obj);
 
     static bool IsCPOW(JSObject *obj);
+
     static nsresult InstanceOf(JSObject *obj, const nsID *id, bool *bp);
+    nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
 
-    nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
+    /*
+     * Check that |obj| is a DOM wrapper whose prototype chain contains
+     * |prototypeID| at depth |depth|.
+     */
+    static bool DOMInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp);
+    bool domInstanceOf(JSObject *obj, int prototypeID, int depth, bool *bp);
 
   protected:
     JSObject *unwrap(JSContext *cx, ObjectId objId);
 
   private:
     bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
     bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags, js::AutoIdVector &props);
     ObjectId idOf(JSObject *obj);
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -36,15 +36,16 @@ child:
 
     urgent IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
     urgent Call(uint64_t objId, JSParam[] argv) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
     urgent ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
     urgent ClassName(uint64_t objId) returns (nsString name);
 
     urgent GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
     urgent InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
+    urgent DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
 
 parent:
     async __delete__();
 };
 
 }
 }