Fix for bug 533637 (Speed up unwrapping a node in quickstubs that use nsINode (dromaeo)). Use flags on DOMCI to be able to cast instead of QI. r=jst.
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 12 Jan 2010 15:24:00 +0100
changeset 40491 88f469d18c97296654ba94caa303e702ae20672b
parent 40490 8e6cbbc07c71d3b003d33e326601e168a42c6c47
child 40492 b974b6dca6ce6c97bab6903ac827ff839295a7a2
push idunknown
push userunknown
push dateunknown
reviewersjst
bugs533637
milestone1.9.3a4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Fix for bug 533637 (Speed up unwrapping a node in quickstubs that use nsINode (dromaeo)). Use flags on DOMCI to be able to cast instead of QI. r=jst.
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMClassInfoID.h
js/src/xpconnect/idl/nsIXPCScriptable.idl
js/src/xpconnect/src/dom_quickstubs.qsconf
js/src/xpconnect/src/nsCSSPropertiesQS.h
js/src/xpconnect/src/nsDOMQS.h
js/src/xpconnect/src/xpcmaps.cpp
js/src/xpconnect/src/xpcmaps.h
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcquickstubs.h
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativejsops.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -556,16 +556,17 @@ DOMCI_DATA(Notation, void)
   { #_name,                                                                   \
     nsnull,                                                                   \
     { _helper::doCreate },                                                    \
     nsnull,                                                                   \
     nsnull,                                                                   \
     nsnull,                                                                   \
     _flags,                                                                   \
     PR_TRUE,                                                                  \
+    0,                                                                        \
     NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                    \
   },
 
 #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags)                     \
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, _flags)
 
 
 // This list of NS_DEFINE_CLASSINFO_DATA macros is what gives the DOM
@@ -1942,16 +1943,17 @@ nsDOMClassInfo::WrapNativeParent(JSConte
   return NS_OK;
 }
 
 #define _DOM_CLASSINFO_MAP_BEGIN(_class, _ifptr, _has_class_if)               \
   {                                                                           \
     nsDOMClassInfoData &d = sClassInfoData[eDOMClassInfo_##_class##_id];      \
     d.mProtoChainInterface = _ifptr;                                          \
     d.mHasClassInterface = _has_class_if;                                     \
+    d.mInterfacesBitmap = kDOMClassInfo_##_class##_interfaces;                \
     static const nsIID *interface_list[] = {
 
 #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface)                           \
   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), PR_TRUE)
 
 #define DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(_class, _interface)               \
   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), PR_FALSE)
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -75,16 +75,17 @@ struct nsDOMClassInfoData
   } u;
 
   nsIClassInfo *mCachedClassInfo; // low bit is set to 1 if external,
                                   // so be sure to mask if necessary!
   const nsIID *mProtoChainInterface;
   const nsIID **mInterfaces;
   PRUint32 mScriptableFlags : 31; // flags must not use more than 31 bits!
   PRUint32 mHasClassInterface : 1;
+  PRUint32 mInterfacesBitmap;
 #ifdef NS_DEBUG
   PRUint32 mDebugID;
 #endif
 };
 
 struct nsExternalDOMClassInfoData : public nsDOMClassInfoData
 {
   const nsCID *mConstructorCID;
@@ -207,16 +208,21 @@ protected:
   friend nsIClassInfo* NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID);
 
   const nsDOMClassInfoData* mData;
 
   virtual void PreserveWrapper(nsISupports *aNative)
   {
   }
 
+  virtual PRUint32 GetInterfacesBitmap()
+  {
+    return mData->mInterfacesBitmap;
+  }
+
   static nsresult Init();
   static nsresult RegisterClassName(PRInt32 aDOMClassInfoID);
   static nsresult RegisterClassProtos(PRInt32 aDOMClassInfoID);
   static nsresult RegisterExternalClasses();
   nsresult ResolveConstructor(JSContext *cx, JSObject *obj,
                               JSObject **objp);
 
   // Checks if id is a number and returns the number, if aIsNumber is
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -39,36 +39,94 @@
 /**
  * This file defines enum values for all of the DOM objects which have
  * an entry in nsDOMClassInfo.
  */
 
 #ifndef nsDOMClassInfoID_h__
 #define nsDOMClassInfoID_h__
 
-#define DOMCI_CLASS(_dom_class) \
+#define DOMCI_CLASS(_dom_class)                                               \
   eDOMClassInfo_##_dom_class##_id,
 
 enum nsDOMClassInfoID {
 
 #include "nsDOMClassInfoClasses.h"
 
   // This one better be the last one in this list
   eDOMClassInfoIDCount
 };
 
 #undef DOMCI_CLASS
 
 /**
  * nsIClassInfo helper macros
  */
 
+/**
+ * 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!
+ */
+#define DOMCI_CASTABLE_INTERFACES(_extra)                                     \
+DOMCI_CASTABLE_INTERFACE(nsINode, 0, _extra)                                  \
+DOMCI_CASTABLE_INTERFACE(nsIContent, 1, _extra)                               \
+DOMCI_CASTABLE_INTERFACE(nsIDocument, 2, _extra)                              \
+DOMCI_CASTABLE_INTERFACE(nsINodeList, 3, _extra)                              \
+DOMCI_CASTABLE_INTERFACE(nsICSSDeclaration, 4, _extra)
+
+
 #ifdef _IMPL_NS_LAYOUT
 
-#define DOMCI_DATA(_dom_class, _class)
+#define DOMCI_CLASS(_dom_class)                                               \
+  extern const PRUint32 kDOMClassInfo_##_dom_class##_interfaces;
+
+#include "nsDOMClassInfoClasses.h"
+
+#undef DOMCI_CLASS
+
+/**
+ * We define two functions for every interface in DOMCI_CASTABLE_INTERFACES.
+ * One takes a void* and one takes an nsIFoo*. These are used to compute the
+ * bitmap for a given class. If the class doesn't implement the interface then
+ * the void* variant will be called and we'll return 0, otherwise the nsIFoo*
+ * variant will be called and we'll return (1 << bit).
+ */
+#define DOMCI_CASTABLE_INTERFACE(_interface, _bit, _extra)                    \
+class _interface;                                                             \
+inline PRUint32 Implements_##_interface(_interface *foo)                      \
+  { return 1 << _bit; }                                                       \
+inline PRUint32 Implements_##_interface(void *foo)                            \
+  { return 0; }
+
+DOMCI_CASTABLE_INTERFACES()
+
+#undef DOMCI_CASTABLE_INTERFACE
+
+/**
+ * Here we calculate the bitmap for a given class. We'll call the functions
+ * defined above with (_class*)nsnull. If the class implements an interface,
+ * that function will return (1 << bit), if it doesn't the function returns 0.
+ * We just make the sum of all the values returned from the functions to
+ * generate the bitmap.
+ */
+#define DOMCI_CASTABLE_INTERFACE(_interface, _bit, _class)                    \
+  Implements_##_interface((_class*)nsnull) +
+
+#define DOMCI_DATA(_dom_class, _class)                                        \
+const PRUint32 kDOMClassInfo_##_dom_class##_interfaces =                      \
+  DOMCI_CASTABLE_INTERFACES(_class)                                           \
+  0;
 
 class nsIClassInfo;
 class nsXPCClassInfo;
 
 extern nsIClassInfo*
 NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID);
 
 #define NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class)                          \
--- a/js/src/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl
@@ -190,29 +190,31 @@ interface nsIXPCScriptable : nsISupports
     void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto);
 };
 
 %{ C++
 
 #include "nsAutoPtr.h"
 
 #define NS_XPCCLASSINFO_IID \
-{ 0xc39aa8db, 0x619d, 0x4ee6, \
- { 0xb1, 0x72, 0x5a, 0x83, 0x5d, 0x68, 0xfb, 0xb2 } }
+{ 0x9a5b0342, 0x0f70, 0x4d31, \
+ { 0xb7, 0xd7, 0x29, 0x68, 0xa5, 0x70, 0x4b, 0xd8 } }
 
 class NS_NO_VTABLE nsXPCClassInfo : public nsIClassInfo,
                                     public nsIXPCScriptable
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCCLASSINFO_IID)
 
   NS_IMETHOD_(nsrefcnt) AddRef() = 0;
   NS_IMETHOD_(nsrefcnt) Release() = 0;
 
   virtual void PreserveWrapper(nsISupports *aNative) = 0;
+
+  virtual PRUint32 GetInterfacesBitmap() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCClassInfo, NS_XPCCLASSINFO_IID)
 
 inline
 nsresult
 CallQueryInterface(nsISupports* aSourcePtr,
                    nsRefPtrGetterAddRefs<nsXPCClassInfo> aDestPtr)
--- a/js/src/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/src/xpconnect/src/dom_quickstubs.qsconf
@@ -488,16 +488,17 @@ irregularFilenames = {
     }
 
 customIncludes = [
     'nsINode.h',
     'nsIContent.h',
     'nsIDocument.h',
     'nsINodeList.h',
     'nsCSSPropertiesQS.h',
+    'nsDOMQS.h',
     ]
 
 customQuickStubs = [
     'CustomQS_WebGL.h',
     'CustomQS_Canvas2D.h'
     ]
 
 customReturnInterfaces = [
--- a/js/src/xpconnect/src/nsCSSPropertiesQS.h
+++ b/js/src/xpconnect/src/nsCSSPropertiesQS.h
@@ -1,8 +1,44 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is XPConnect code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
 #ifndef nsCSSPropertiesQS_h__
 #define nsCSSPropertiesQS_h__
 
 #include "nsICSSDeclaration.h"
 
 #define CSS_PROP(name_, id_, method_, flags_, datastruct_, member_, type_,     \
                  kwtable_, stylestruct_, stylestructoffset_, animtype_)        \
 static const nsCSSProperty QS_CSS_PROP_##method_ = eCSSProperty_##id_;
new file mode 100644
--- /dev/null
+++ b/js/src/xpconnect/src/nsDOMQS.h
@@ -0,0 +1,86 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is XPConnect code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsDOMQS_h__
+#define nsDOMQS_h__
+
+#include "nsDOMClassInfoID.h"
+
+#define DEFINE_UNWRAP_CAST(_interface, _bit)                                  \
+NS_SPECIALIZE_TEMPLATE                                                        \
+inline JSBool                                                                 \
+xpc_qsUnwrapThis<_interface>(JSContext *cx,                                   \
+                             JSObject *obj,                                   \
+                             JSObject *callee,                                \
+                             _interface **ppThis,                             \
+                             nsISupports **pThisRef,                          \
+                             jsval *pThisVal,                                 \
+                             XPCLazyCallContext *lccx)                        \
+{                                                                             \
+    nsresult rv;                                                              \
+    nsISupports *native = castNativeFromWrapper(cx, obj, callee, _bit,        \
+                                                pThisRef, pThisVal, lccx,     \
+                                                &rv);                         \
+    if(!native)                                                               \
+        return JS_FALSE;                                                      \
+    *ppThis = static_cast<_interface*>(native);                               \
+    return JS_TRUE;                                                           \
+}                                                                             \
+                                                                              \
+NS_SPECIALIZE_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);                      \
+    if(NS_SUCCEEDED(rv))                                                      \
+        *ppArg = static_cast<_interface*>(native);                            \
+    return rv;                                                                \
+}
+
+#define DOMCI_CASTABLE_INTERFACE(_interface, _bit, _extra)                    \
+  DEFINE_UNWRAP_CAST(_interface, _bit)
+
+DOMCI_CASTABLE_INTERFACES()
+
+#undef DOMCI_CASTABLE_INTERFACE
+
+#endif /* nsDOMQS_h__ */
--- a/js/src/xpconnect/src/xpcmaps.cpp
+++ b/js/src/xpconnect/src/xpcmaps.cpp
@@ -540,34 +540,35 @@ XPCNativeScriptableSharedMap::~XPCNative
     if(mTable)
         JS_DHashTableDestroy(mTable);
 }
 
 JSBool
 XPCNativeScriptableSharedMap::GetNewOrUsed(JSUint32 flags,
                                            char* name,
                                            JSBool isGlobal,
+                                           PRUint32 interfacesBitmap,
                                            XPCNativeScriptableInfo* si)
 {
     NS_PRECONDITION(name,"bad param");
     NS_PRECONDITION(si,"bad param");
 
-    XPCNativeScriptableShared key(flags, name);
-
+    XPCNativeScriptableShared key(flags, name, interfacesBitmap);
     Entry* entry = (Entry*)
         JS_DHashTableOperate(mTable, &key, JS_DHASH_ADD);
     if(!entry)
         return JS_FALSE;
 
     XPCNativeScriptableShared* shared = entry->key;
 
     if(!shared)
     {
         entry->key = shared =
-            new XPCNativeScriptableShared(flags, key.TransferNameOwnership());
+            new XPCNativeScriptableShared(flags, key.TransferNameOwnership(),
+                                          interfacesBitmap);
         if(!shared)
             return JS_FALSE;
         shared->PopulateJSClass(isGlobal);
     }
     si->SetScriptableShared(shared);
     return JS_TRUE;
 }
 
--- a/js/src/xpconnect/src/xpcmaps.h
+++ b/js/src/xpconnect/src/xpcmaps.h
@@ -544,17 +544,17 @@ public:
               const void *key);
 
         static struct JSDHashTableOps sOps;
     };
 
     static XPCNativeScriptableSharedMap* newMap(int size);
 
     JSBool GetNewOrUsed(JSUint32 flags, char* name, PRBool isGlobal,
-                        XPCNativeScriptableInfo* si);
+                        PRUint32 interfacesBitmap, XPCNativeScriptableInfo* si);
 
     inline uint32 Count() {return mTable->entryCount;}
     inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
         {return JS_DHashTableEnumerate(mTable, f, arg);}
 
     ~XPCNativeScriptableSharedMap();
 private:
     XPCNativeScriptableSharedMap();    // no implementation
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1928,29 +1928,38 @@ public:
 // XPCNativeScriptableShared is used to hold the JSClass and the
 // associated scriptable flags for XPCWrappedNatives. These are shared across
 // the runtime and are garbage collected by xpconnect. We *used* to just store
 // this inside the XPCNativeScriptableInfo (usually owned by instances of
 // XPCWrappedNativeProto. This had two problems... It was wasteful, and it
 // was a big problem when wrappers are reparented to different scopes (and
 // thus different protos (the DOM does this).
 
+struct XPCNativeScriptableSharedJSClass : public JSExtendedClass
+{
+    PRUint32 interfacesBitmap;
+};
+
 class XPCNativeScriptableShared
 {
 public:
     const XPCNativeScriptableFlags& GetFlags() const {return mFlags;}
+    PRUint32                        GetInterfacesBitmap() const
+        {return mJSClass.interfacesBitmap;}
     JSClass*                        GetJSClass() {return &mJSClass.base;}
     JSClass*                        GetSlimJSClass()
         {if(mCanBeSlim) return GetJSClass(); return nsnull;}
 
-    XPCNativeScriptableShared(JSUint32 aFlags = 0, char* aName = nsnull)
+    XPCNativeScriptableShared(JSUint32 aFlags, char* aName,
+                              PRUint32 interfacesBitmap)
         : mFlags(aFlags),
           mCanBeSlim(JS_FALSE)
         {memset(&mJSClass, 0, sizeof(mJSClass));
          mJSClass.base.name = aName;  // take ownership
+         mJSClass.interfacesBitmap = interfacesBitmap;
          MOZ_COUNT_CTOR(XPCNativeScriptableShared);}
 
     ~XPCNativeScriptableShared()
         {if(mJSClass.base.name)nsMemory::Free((void*)mJSClass.base.name);
          MOZ_COUNT_DTOR(XPCNativeScriptableShared);}
 
     char* TransferNameOwnership()
         {char* name=(char*)mJSClass.base.name; mJSClass.base.name = nsnull;
@@ -1959,17 +1968,17 @@ public:
     void PopulateJSClass(JSBool isGlobal);
 
     void Mark()       {mFlags.Mark();}
     void Unmark()     {mFlags.Unmark();}
     JSBool IsMarked() const {return mFlags.IsMarked();}
 
 private:
     XPCNativeScriptableFlags mFlags;
-    JSExtendedClass          mJSClass;
+    XPCNativeScriptableSharedJSClass mJSClass;
     JSBool                   mCanBeSlim;
 };
 
 /***************************************************************************/
 // XPCNativeScriptableInfo is used to hold the nsIXPCScriptable state for a
 // given class or instance.
 
 class XPCNativeScriptableInfo
@@ -1980,16 +1989,19 @@ public:
               const XPCNativeScriptableCreateInfo* sci);
 
     nsIXPCScriptable*
     GetCallback() const {return mCallback;}
 
     const XPCNativeScriptableFlags&
     GetFlags() const      {return mShared->GetFlags();}
 
+    PRUint32
+    GetInterfacesBitmap() const {return mShared->GetInterfacesBitmap();}
+
     JSClass*
     GetJSClass()          {return mShared->GetJSClass();}
 
     JSClass*
     GetSlimJSClass()      {return mShared->GetSlimJSClass();}
 
     XPCNativeScriptableShared*
     GetScriptableShared() {return mShared;}
@@ -2027,42 +2039,53 @@ private:
 // it abstracts out the scriptable interface pointer and the flags. After
 // creation these are factored differently using XPCNativeScriptableInfo.
 
 class NS_STACK_CLASS XPCNativeScriptableCreateInfo
 {
 public:
 
     XPCNativeScriptableCreateInfo(const XPCNativeScriptableInfo& si)
-        : mCallback(si.GetCallback()), mFlags(si.GetFlags()) {}
+        : mCallback(si.GetCallback()), mFlags(si.GetFlags()),
+          mInterfacesBitmap(si.GetInterfacesBitmap()) {}
 
     XPCNativeScriptableCreateInfo(already_AddRefed<nsIXPCScriptable> callback,
-                                  XPCNativeScriptableFlags flags)
-        : mCallback(callback), mFlags(flags) {}
+                                  XPCNativeScriptableFlags flags,
+                                  PRUint32 interfacesBitmap)
+        : mCallback(callback), mFlags(flags),
+          mInterfacesBitmap(interfacesBitmap) {}
 
     XPCNativeScriptableCreateInfo()
-        : mFlags(0) {}
+        : mFlags(0), mInterfacesBitmap(0) {}
 
 
     nsIXPCScriptable*
     GetCallback() const {return mCallback;}
 
     const XPCNativeScriptableFlags&
     GetFlags() const      {return mFlags;}
 
+    PRUint32
+    GetInterfacesBitmap() const     {return mInterfacesBitmap;}
+
     void
     SetCallback(already_AddRefed<nsIXPCScriptable> callback)
-      {mCallback = callback;}
+        {mCallback = callback;}
 
     void
     SetFlags(const XPCNativeScriptableFlags& flags)  {mFlags = flags;}
 
+    void
+    SetInterfacesBitmap(PRUint32 interfacesBitmap)
+        {mInterfacesBitmap = interfacesBitmap;}
+
 private:
     nsCOMPtr<nsIXPCScriptable>  mCallback;
     XPCNativeScriptableFlags    mFlags;
+    PRUint32                    mInterfacesBitmap;
 };
 
 /***********************************************/
 // XPCWrappedNativeProto hold the additional (potentially shared) wrapper data
 // for XPCWrappedNative whose native objects expose nsIClassInfo.
 
 #define UNKNOWN_OFFSETS ((QITableEntry*)1)
 
--- a/js/src/xpconnect/src/xpcquickstubs.h
+++ b/js/src/xpconnect/src/xpcquickstubs.h
@@ -399,16 +399,88 @@ xpc_qsUnwrapThis(JSContext *cx,
     if(NS_SUCCEEDED(rv))
         rv = castNative(cx, wrapper, obj, tearoff, NS_GET_TEMPLATE_IID(T),
                         reinterpret_cast<void **>(ppThis), pThisRef, pThisVal,
                         lccx);
 
     return NS_SUCCEEDED(rv) || xpc_qsThrow(cx, rv);
 }
 
+inline nsISupports*
+castNativeFromWrapper(JSContext *cx,
+                      JSObject *obj,
+                      JSObject *callee,
+                      PRUint32 interfaceBit,
+                      nsISupports **pThisRef,
+                      jsval *pThisVal,
+                      XPCLazyCallContext *lccx,
+                      nsresult *rv NS_OUTPARAM)
+{
+    XPCWrappedNative *wrapper;
+    XPCWrappedNativeTearOff *tearoff;
+    JSObject *cur;
+
+    if(!callee && IS_WRAPPER_CLASS(obj->getClass()))
+    {
+        cur = obj;
+        wrapper = IS_WN_WRAPPER_OBJECT(cur) ?
+                  (XPCWrappedNative*)xpc_GetJSPrivate(obj) :
+                  nsnull;
+        tearoff = nsnull;
+    }
+    else
+    {
+        *rv = getWrapper(cx, obj, callee, &wrapper, &cur, &tearoff);
+        if (NS_FAILED(*rv))
+            return nsnull;
+    }
+
+    nsISupports *native;
+    JSObject *thisObj;
+    if(wrapper)
+    {
+        native = wrapper->GetIdentityObject();
+        thisObj = wrapper->GetFlatJSObject();
+    }
+    else
+    {
+        native = cur ?
+                 static_cast<nsISupports*>(xpc_GetJSPrivate(cur)) :
+                 nsnull;
+        thisObj = cur;
+    }
+
+    *rv = NS_ERROR_XPC_BAD_CONVERT_JS;
+
+    if(!native)
+        return nsnull;
+
+    NS_ASSERTION(IS_WRAPPER_CLASS(thisObj->getClass()), "Not a wrapper?");
+
+    XPCNativeScriptableSharedJSClass *clasp =
+      (XPCNativeScriptableSharedJSClass*)thisObj->getClass();
+    if(!(clasp->interfacesBitmap & (1 << interfaceBit)))
+        return nsnull;
+
+    *pThisRef = nsnull;
+    *pThisVal = OBJECT_TO_JSVAL(thisObj);
+
+    if(lccx)
+    {
+        if(wrapper)
+            lccx->SetWrapper(wrapper, tearoff);
+        else
+            lccx->SetWrapper(obj);
+    }
+
+    *rv = NS_OK;
+
+    return native;
+}
+
 JSBool
 xpc_qsUnwrapThisFromCcxImpl(XPCCallContext &ccx,
                             const nsIID &iid,
                             void **ppThis,
                             nsISupports **pThisRef,
                             jsval *vp);
 
 /**
@@ -424,30 +496,48 @@ xpc_qsUnwrapThisFromCcx(XPCCallContext &
 {
     return xpc_qsUnwrapThisFromCcxImpl(ccx,
                                        NS_GET_TEMPLATE_IID(T),
                                        reinterpret_cast<void **>(ppThis),
                                        pThisRef,
                                        pThisVal);
 }
 
+JSObject*
+xpc_qsUnwrapObj(jsval v, nsISupports **ppArgRef, nsresult *rv);
+
 nsresult
 xpc_qsUnwrapArgImpl(JSContext *cx, jsval v, const nsIID &iid, void **ppArg,
                     nsISupports **ppArgRef, jsval *vp);
 
 /** Convert a jsval to an XPCOM pointer. */
 template <class T>
 inline nsresult
 xpc_qsUnwrapArg(JSContext *cx, jsval v, T **ppArg, nsISupports **ppArgRef,
                 jsval *vp)
 {
     return xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(T),
                                reinterpret_cast<void **>(ppArg), ppArgRef, vp);
 }
 
+inline nsISupports*
+castNativeArgFromWrapper(JSContext *cx,
+                         jsval v,
+                         PRUint32 bit,
+                         nsISupports **pArgRef,
+                         jsval *vp,
+                         nsresult *rv NS_OUTPARAM)
+{
+    JSObject *src = xpc_qsUnwrapObj(v, pArgRef, rv);
+    if(!src)
+        return nsnull;
+
+    return castNativeFromWrapper(cx, src, nsnull, bit, pArgRef, vp, nsnull, rv);
+}
+
 inline nsWrapperCache*
 xpc_qsGetWrapperCache(nsWrapperCache *cache)
 {
     return cache;
 }
 
 inline nsWrapperCache*
 xpc_qsGetWrapperCache(void *p)
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -939,16 +939,17 @@ XPCWrappedNative::GatherProtoScriptableC
           dont_AddRef(static_cast<nsIXPCScriptable*>(classInfoHelper));
         JSUint32 flags;
         nsresult rv = classInfoHelper->GetScriptableFlags(&flags);
         if(NS_FAILED(rv))
             flags = 0;
 
         sciProto.SetCallback(helper.forget());
         sciProto.SetFlags(flags);
+        sciProto.SetInterfacesBitmap(classInfoHelper->GetInterfacesBitmap());
 
         return;
     }
 
     nsCOMPtr<nsISupports> possibleHelper;
     nsresult rv = classInfo->GetHelperForLanguage(
                                     nsIProgrammingLanguage::JAVASCRIPT,
                                     getter_AddRefs(possibleHelper));
@@ -3868,18 +3869,19 @@ ConstructSlimWrapper(XPCCallContext &ccx
     if(wrapper)
     {
         *rval = OBJECT_TO_JSVAL(wrapper);
 
         return JS_TRUE;
     }
 
     nsIClassInfo* classInfo = classInfoHelper;
-    XPCNativeScriptableCreateInfo sciProto(classInfoHelper.forget().get(),
-                                           flags);
+    XPCNativeScriptableCreateInfo
+        sciProto(classInfoHelper.forget().get(), flags,
+                 classInfoHelper->GetInterfacesBitmap());
 
     AutoMarkingWrappedNativeProtoPtr xpcproto(ccx);
     JSBool isGlobal = JS_FALSE;
     xpcproto = XPCWrappedNativeProto::GetNewOrUsed(ccx, xpcScope, classInfo,
                                                    &sciProto, JS_FALSE,
                                                    isGlobal);
     if(!xpcproto)
         return JS_FALSE;
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -1602,17 +1602,18 @@ XPCNativeScriptableInfo::Construct(XPCCa
     }
 
     JSBool success;
 
     XPCJSRuntime* rt = ccx.GetRuntime();
     XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap();
     {   // scoped lock
         XPCAutoLock lock(rt->GetMapLock());
-        success = map->GetNewOrUsed(sci->GetFlags(), name, isGlobal, newObj);
+        success = map->GetNewOrUsed(sci->GetFlags(), name, isGlobal,
+                                    sci->GetInterfacesBitmap(), newObj);
     }
 
     if(!success)
     {
         delete newObj;
         return nsnull;
     }