Fix for bug 807330 (Make xpc_qsUnwrapThis/xpc_qsUnwrapArg deal with new DOM bindings). r=jst.
authorPeter Van der Beken <peterv@propagandism.org>
Wed, 26 Sep 2012 16:17:46 +0200
changeset 121516 5fd176fb2acaec963539d0a9ce513aec76b22169
parent 121515 843a3db9c0457acbdf91e257a927ac97ea4a7dc5
child 121517 ee3ee9e659bdb255b3db24633b64d6e54b58be4f
push id273
push userlsblakk@mozilla.com
push dateThu, 14 Feb 2013 23:19:38 +0000
treeherdermozilla-release@c5e807a3f8b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs807330
milestone19.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
Fix for bug 807330 (Make xpc_qsUnwrapThis/xpc_qsUnwrapArg deal with new DOM bindings). r=jst.
dom/base/nsDOMClassInfoID.h
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/nsDOMQS.h
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -26,56 +26,47 @@ enum nsDOMClassInfoID {
 
 #undef DOMCI_CLASS
 
 /**
  * nsIClassInfo helper macros
  */
 
 /**
+ * !! THIS MECHANISM IS DEPRECATED, DO NOT ADD MORE INTERFACE TO THESE LISTS !!
+ *
  * DOMCI_CASTABLE_INTERFACES contains the list of interfaces that we have a bit
  * for in nsDOMClassInfo's mInterfacesBitmap. To use it you need to define
  * DOMCI_CASTABLE_INTERFACE(interface, bit, extra) and then call
  * DOMCI_CASTABLE_INTERFACES(extra). For every interface there will be one
  * call to DOMCI_CASTABLE_INTERFACE with the bit that it corresponds to and
  * the extra argument that was passed in to DOMCI_CASTABLE_INTERFACES.
  *
  * WARNING: Be very careful when adding interfaces to this list. Every object
  *          that implements one of these interfaces must be directly castable
  *          to that interface from the *canonical* nsISupports! Also, none of
  *          the objects that implement these interfaces may use the new DOM
  *          bindings.
  */
 #undef DOMCI_CASTABLE_INTERFACE
 #define DOMCI_CASTABLE_INTERFACES(_extra)                                     \
 DOMCI_CASTABLE_INTERFACE(nsINode, nsINode, 0, _extra)                         \
-DOMCI_CASTABLE_INTERFACE(nsIContent, nsIContent, 1, _extra)                   \
-DOMCI_CASTABLE_INTERFACE(nsIDocument, nsIDocument, 2, _extra)                 \
-DOMCI_CASTABLE_INTERFACE(nsICSSDeclaration, nsICSSDeclaration, 4, _extra)     \
+DOMCI_CASTABLE_INTERFACE(nsGenericElement, nsGenericElement, 1, _extra)       \
 DOMCI_CASTABLE_INTERFACE(nsDocument, nsIDocument, 5, _extra)                  \
 DOMCI_CASTABLE_INTERFACE(nsGenericHTMLElement, nsGenericHTMLElement, 6,       \
                          _extra)                                              \
 DOMCI_CASTABLE_INTERFACE(nsHTMLDocument, nsIDocument, 7, _extra)              \
 DOMCI_CASTABLE_INTERFACE(nsStyledElement, nsStyledElement, 8, _extra)         \
 DOMCI_CASTABLE_INTERFACE(nsSVGStylableElement, nsIContent, 9, _extra)
  
 // Make sure all classes mentioned in DOMCI_CASTABLE_INTERFACES
 // have been declared.
-#undef DOMCI_CASTABLE_NAMESPACED_INTERFACE
 #define DOMCI_CASTABLE_INTERFACE(_interface, _u1, _u2, _u3) class _interface;
-#define DOMCI_CASTABLE_NAMESPACED_INTERFACE(ns, className, interface, bit, _extra) \
-  namespace ns {                                                        \
-  class className;                                                      \
-  }
 DOMCI_CASTABLE_INTERFACES(unused)
 #undef DOMCI_CASTABLE_INTERFACE
-#undef DOMCI_CASTABLE_NAMESPACED_INTERFACE
-
-#define DOMCI_CASTABLE_NAMESPACED_INTERFACE(ns, className, interface, bit, _extra) \
-  DOMCI_CASTABLE_INTERFACE(ns::className, interface, bit, _extra)
 
 #ifdef _IMPL_NS_LAYOUT
 
 #define DOMCI_CLASS(_dom_class)                                               \
   extern const uint32_t kDOMClassInfo_##_dom_class##_interfaces;
 
 #include "nsDOMClassInfoClasses.h"
 
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1057,17 +1057,17 @@ XPCConvert::JSObject2NativeInterface(JSC
 
         // XXX E4X breaks the world. Don't try wrapping E4X objects!
         // This hack can be removed (or changed accordingly) when the
         // DOM <-> E4X bindings are complete, see bug 270553
         if (JS_TypeOfValue(cx, OBJECT_TO_JSVAL(src)) == JSTYPE_XML)
             return false;
 
         // Deal with slim wrappers here.
-        if (GetISupportsFromJSObject(src, &iface)) {
+        if (GetISupportsFromJSObject(inner ? inner : src, &iface)) {
             if (iface)
                 return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
 
             return false;
         }
     }
 
     // else...
--- a/js/xpconnect/src/XPCQuickStubs.h
+++ b/js/xpconnect/src/XPCQuickStubs.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef xpcquickstubs_h___
 #define xpcquickstubs_h___
 
 #include "xpcpublic.h"
 #include "xpcprivate.h"
 #include "qsObjectHelper.h"
+#include "mozilla/dom/BindingUtils.h"
 
 /* XPCQuickStubs.h - Support functions used only by quick stubs. */
 
 class XPCCallContext;
 
 #define XPC_QS_NULL_INDEX  ((uint16_t) -1)
 
 struct xpc_qsPropertySpec {
@@ -391,20 +392,32 @@ xpc_qsUnwrapThis(JSContext *cx,
     if (failureFatal)
         return NS_SUCCEEDED(rv) || xpc_qsThrow(cx, rv);
 
     if (NS_FAILED(rv))
         *ppThis = nullptr;
     return true;
 }
 
+MOZ_ALWAYS_INLINE bool
+HasBitInInterfacesBitmap(JSObject *obj, uint32_t interfaceBit)
+{
+    NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)), "Not a wrapper?");
+
+    XPCWrappedNativeJSClass *clasp =
+      (XPCWrappedNativeJSClass*)js::GetObjectClass(obj);
+    return (clasp->interfacesBitmap & (1 << interfaceBit)) != 0;
+}
+
 MOZ_ALWAYS_INLINE nsISupports*
 castNativeFromWrapper(JSContext *cx,
                       JSObject *obj,
                       uint32_t interfaceBit,
+                      uint32_t protoID,
+                      int32_t protoDepth,
                       nsISupports **pRef,
                       jsval *pVal,
                       XPCLazyCallContext *lccx,
                       nsresult *rv)
 {
     XPCWrappedNative *wrapper;
     XPCWrappedNativeTearOff *tearoff;
     JSObject *cur;
@@ -416,45 +429,54 @@ castNativeFromWrapper(JSContext *cx,
                   nullptr;
         tearoff = nullptr;
     } else {
         *rv = getWrapper(cx, obj, &wrapper, &cur, &tearoff);
         if (NS_FAILED(*rv))
             return nullptr;
     }
 
+    *rv = NS_ERROR_XPC_BAD_CONVERT_JS;
+
     nsISupports *native;
     if (wrapper) {
         native = wrapper->GetIdentityObject();
         cur = wrapper->GetFlatJSObject();
-    } else if (cur && IS_SLIM_WRAPPER(cur)) {
-        native = static_cast<nsISupports*>(xpc_GetJSPrivate(cur));
+        if (!native || !HasBitInInterfacesBitmap(cur, interfaceBit)) {
+            return nullptr;
+        }
+    } else if (cur) {
+        if (IS_SLIM_WRAPPER(cur)) {
+            native = static_cast<nsISupports*>(xpc_GetJSPrivate(cur));
+            if (!native || !HasBitInInterfacesBitmap(cur, interfaceBit)) {
+                return nullptr;
+            }
+        } else if (protoDepth >= 0) {
+            const mozilla::dom::DOMClass* domClass;
+            mozilla::dom::DOMObjectSlot slot =
+                mozilla::dom::GetDOMClass(cur, domClass);
+            native = mozilla::dom::UnwrapDOMObject<nsISupports>(cur, slot);
+            if (!native ||
+                (uint32_t)domClass->mInterfaceChain[protoDepth] != protoID) {
+                return nullptr;
+            }
+        } else {
+            return nullptr;
+        }
     } else {
-        native = nullptr;
+        return nullptr;
     }
 
-    *rv = NS_ERROR_XPC_BAD_CONVERT_JS;
-
-    if (!native)
-        return nullptr;
-
-    NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(cur)), "Not a wrapper?");
-
-    XPCWrappedNativeJSClass *clasp =
-      (XPCWrappedNativeJSClass*)js::GetObjectClass(cur);
-    if (!(clasp->interfacesBitmap & (1 << interfaceBit)))
-        return nullptr;
-
     *pRef = nullptr;
     *pVal = OBJECT_TO_JSVAL(cur);
 
     if (lccx) {
         if (wrapper)
             lccx->SetWrapper(wrapper, tearoff);
-        else
+        else if (IS_SLIM_WRAPPER(cur))
             lccx->SetWrapper(cur);
     }
 
     *rv = NS_OK;
 
     return native;
 }
 
@@ -503,25 +525,28 @@ xpc_qsUnwrapArg(JSContext *cx, jsval v, 
     *ppArgRef = static_cast<StrongRefType*>(argRef);
     return rv;
 }
 
 inline nsISupports*
 castNativeArgFromWrapper(JSContext *cx,
                          jsval v,
                          uint32_t bit,
+                         uint32_t protoID,
+                         int32_t protoDepth,
                          nsISupports **pArgRef,
                          jsval *vp,
                          nsresult *rv)
 {
     JSObject *src = xpc_qsUnwrapObj(v, pArgRef, rv);
     if (!src)
         return nullptr;
 
-    return castNativeFromWrapper(cx, src, bit, pArgRef, vp, nullptr, rv);
+    return castNativeFromWrapper(cx, src, bit, protoID, protoDepth, pArgRef, vp,
+                                 nullptr, rv);
 }
 
 inline nsWrapperCache*
 xpc_qsGetWrapperCache(nsWrapperCache *cache)
 {
     return cache;
 }
 
--- a/js/xpconnect/src/nsDOMQS.h
+++ b/js/xpconnect/src/nsDOMQS.h
@@ -11,137 +11,114 @@
 #include "nsHTMLImageElement.h"
 #include "nsHTMLOptionElement.h"
 #include "nsHTMLOptGroupElement.h"
 #include "nsHTMLVideoElement.h"
 #include "nsHTMLDocument.h"
 #include "nsICSSDeclaration.h"
 #include "nsSVGStylableElement.h"
 
+template<class T>
+struct ProtoIDAndDepth
+{
+    enum {
+        PrototypeID = mozilla::dom::prototypes::id::_ID_Count,
+        Depth = -1
+    };
+};
+
+#define NEW_BINDING(_native)                                                  \
+template<>                                                                    \
+struct ProtoIDAndDepth<_native>                                               \
+{                                                                             \
+    enum {                                                                    \
+        PrototypeID = mozilla::dom::PrototypeIDMap<_native>::PrototypeID,     \
+        Depth = mozilla::dom::PrototypeTraits<                                \
+            static_cast<mozilla::dom::prototypes::ID>(PrototypeID)>::Depth    \
+    };                                                                        \
+}
+
 #define DEFINE_UNWRAP_CAST(_interface, _base, _bit)                           \
 template <>                                                                   \
 MOZ_ALWAYS_INLINE JSBool                                                      \
 xpc_qsUnwrapThis<_interface>(JSContext *cx,                                   \
                              JSObject *obj,                                   \
                              _interface **ppThis,                             \
                              nsISupports **pThisRef,                          \
                              jsval *pThisVal,                                 \
                              XPCLazyCallContext *lccx,                        \
                              bool failureFatal)                               \
 {                                                                             \
     nsresult rv;                                                              \
-    nsISupports *native = castNativeFromWrapper(cx, obj, _bit,                \
-                                                pThisRef, pThisVal, lccx,     \
-                                                &rv);                         \
+    nsISupports *native =                                                     \
+        castNativeFromWrapper(cx, obj, _bit,                                  \
+                              ProtoIDAndDepth<_interface>::PrototypeID,       \
+                              ProtoIDAndDepth<_interface>::Depth,             \
+                              pThisRef, pThisVal, lccx, &rv);                 \
     *ppThis = NULL;  /* avoids uninitialized warnings in callers */           \
     if (failureFatal && !native)                                              \
         return xpc_qsThrow(cx, rv);                                           \
     *ppThis = static_cast<_interface*>(static_cast<_base*>(native));          \
     return true;                                                              \
 }                                                                             \
                                                                               \
 template <>                                                                   \
 inline nsresult                                                               \
 xpc_qsUnwrapArg<_interface>(JSContext *cx,                                    \
                             jsval v,                                          \
                             _interface **ppArg,                               \
                             nsISupports **ppArgRef,                           \
                             jsval *vp)                                        \
 {                                                                             \
     nsresult rv;                                                              \
-    nsISupports *native = castNativeArgFromWrapper(cx, v, _bit, ppArgRef, vp, \
-                                                   &rv);                      \
+    nsISupports *native =                                                     \
+        castNativeArgFromWrapper(cx, v, _bit,                                 \
+                                 ProtoIDAndDepth<_interface>::PrototypeID,    \
+                                 ProtoIDAndDepth<_interface>::Depth,          \
+                                 ppArgRef, vp, &rv);                          \
     if (NS_SUCCEEDED(rv))                                                     \
         *ppArg = static_cast<_interface*>(static_cast<_base*>(native));       \
     return rv;                                                                \
+}                                                                             \
+template <>                                                                   \
+inline nsresult                                                               \
+xpc_qsUnwrapArg<_interface>(JSContext *cx,                                    \
+                            jsval v,                                          \
+                            _interface **ppArg,                               \
+                            _interface **ppArgRef,                            \
+                            jsval *vp)                                        \
+{                                                                             \
+    nsISupports* argRef = static_cast<_base*>(*ppArgRef);                     \
+    nsresult rv = xpc_qsUnwrapArg<_interface>(cx, v, ppArg, &argRef, vp);     \
+    *ppArgRef = static_cast<_interface*>(static_cast<_base*>(argRef));        \
+    return rv;                                                                \
 }
 
 #undef DOMCI_CASTABLE_INTERFACE
 
 #undef DOMCI_CASTABLE_INTERFACE
 #define DOMCI_CASTABLE_INTERFACE(_interface, _base, _bit, _extra)             \
   DEFINE_UNWRAP_CAST(_interface, _base, _bit)
 
 DOMCI_CASTABLE_INTERFACES(unused)
 
 #undef DOMCI_CASTABLE_INTERFACE
 
-// Ideally we'd just add nsGenericElement to the castable interfaces, but for
-// now nsDocumentFragment inherits from nsGenericElement (even though it's not
-// an Element) so we have to special-case nsGenericElement and use
-// nsIContent::IsElement().
-// FIXME: bug 563659.
-inline JSBool
-castToElement(nsIContent *content, jsval val, nsGenericElement **ppInterface,
-              jsval *pVal)
-{
-    if (!content->IsElement())
-        return false;
-    *ppInterface = static_cast<nsGenericElement*>(content->AsElement());
-    *pVal = val;
-    return true;
-}
-
-template <>
-inline JSBool
-xpc_qsUnwrapThis<nsGenericElement>(JSContext *cx,
-                                   JSObject *obj,
-                                   nsGenericElement **ppThis,
-                                   nsISupports **pThisRef,
-                                   jsval *pThisVal,
-                                   XPCLazyCallContext *lccx,
-                                   bool failureFatal)
-{
-    nsIContent *content;
-    jsval val;
-    JSBool ok = xpc_qsUnwrapThis<nsIContent>(cx, obj, &content,
-                                             pThisRef, &val, lccx,
-                                             failureFatal);
-    if (ok) {
-        if (failureFatal || content)
-          ok = castToElement(content, val, ppThis, pThisVal);
-        if (failureFatal && !ok)
-            xpc_qsThrow(cx, NS_ERROR_XPC_BAD_OP_ON_WN_PROTO);
-    }
-
-    if (!failureFatal && (!ok || !content)) {
-      ok = true;
-      *ppThis = nullptr;
-    }
-
-    return ok;
-}
-
-template <>
-inline nsresult
-xpc_qsUnwrapArg<nsGenericElement>(JSContext *cx,
-                                  jsval v,
-                                  nsGenericElement **ppArg,
-                                  nsISupports **ppArgRef,
-                                  jsval *vp)
-{
-    nsIContent *content;
-    jsval val;
-    nsresult rv = xpc_qsUnwrapArg<nsIContent>(cx, v, &content, ppArgRef, &val);
-    if (NS_SUCCEEDED(rv) && !castToElement(content, val, ppArg, vp))
-        rv = NS_ERROR_XPC_BAD_CONVERT_JS;
-    return rv;
-}
-
 inline nsresult
 xpc_qsUnwrapArg_HTMLElement(JSContext *cx,
                             jsval v,
                             nsIAtom *aTag,
                             nsIContent **ppArg,
                             nsISupports **ppArgRef,
                             jsval *vp)
 {
-    nsIContent *elem;
+    nsGenericHTMLElement *elem;
     jsval val;
-    nsresult rv = xpc_qsUnwrapArg<nsIContent>(cx, v, &elem, ppArgRef, &val);
+    nsresult rv =
+        xpc_qsUnwrapArg<nsGenericHTMLElement>(cx, v, &elem, ppArgRef, &val);
     if (NS_SUCCEEDED(rv)) {
         if (elem->IsHTML(aTag)) {
             *ppArg = elem;
             *vp = val;
         } else {
             rv = NS_ERROR_XPC_BAD_CONVERT_JS;
         }
     }