diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 3a8d1defbaa0..12f8ab7328e1 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -561,6 +561,7 @@ DOMCI_DATA(Notation, void) nsnull, \ _flags, \ PR_TRUE, \ + 0, \ NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \ }, @@ -1947,6 +1948,7 @@ nsDOMClassInfo::WrapNativeParent(JSContext *cx, JSObject *scope, 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) \ diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index e6da74e5fccb..b54b2c1c7d62 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -80,6 +80,7 @@ struct nsDOMClassInfoData 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 @@ -212,6 +213,11 @@ protected: { } + virtual PRUint32 GetInterfacesBitmap() + { + return mData->mInterfacesBitmap; + } + static nsresult Init(); static nsresult RegisterClassName(PRInt32 aDOMClassInfoID); static nsresult RegisterClassProtos(PRInt32 aDOMClassInfoID); diff --git a/dom/base/nsDOMClassInfoID.h b/dom/base/nsDOMClassInfoID.h index 6bfadff980eb..42467f544f52 100644 --- a/dom/base/nsDOMClassInfoID.h +++ b/dom/base/nsDOMClassInfoID.h @@ -44,7 +44,7 @@ #ifndef nsDOMClassInfoID_h__ #define nsDOMClassInfoID_h__ -#define DOMCI_CLASS(_dom_class) \ +#define DOMCI_CLASS(_dom_class) \ eDOMClassInfo_##_dom_class##_id, enum nsDOMClassInfoID { @@ -61,9 +61,67 @@ enum nsDOMClassInfoID { * 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; diff --git a/js/src/xpconnect/idl/nsIXPCScriptable.idl b/js/src/xpconnect/idl/nsIXPCScriptable.idl index 995f0bb4b6c3..1005b55fb2b4 100644 --- a/js/src/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl @@ -195,8 +195,8 @@ interface nsIXPCScriptable : nsISupports #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 @@ -208,6 +208,8 @@ public: NS_IMETHOD_(nsrefcnt) Release() = 0; virtual void PreserveWrapper(nsISupports *aNative) = 0; + + virtual PRUint32 GetInterfacesBitmap() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCClassInfo, NS_XPCCLASSINFO_IID) diff --git a/js/src/xpconnect/src/dom_quickstubs.qsconf b/js/src/xpconnect/src/dom_quickstubs.qsconf index 16e4d99e5eee..e2ef6a6e27eb 100644 --- a/js/src/xpconnect/src/dom_quickstubs.qsconf +++ b/js/src/xpconnect/src/dom_quickstubs.qsconf @@ -493,6 +493,7 @@ customIncludes = [ 'nsIDocument.h', 'nsINodeList.h', 'nsCSSPropertiesQS.h', + 'nsDOMQS.h', ] customQuickStubs = [ diff --git a/js/src/xpconnect/src/nsCSSPropertiesQS.h b/js/src/xpconnect/src/nsCSSPropertiesQS.h index 0c94f7210ed9..4de04f43bbe5 100644 --- a/js/src/xpconnect/src/nsCSSPropertiesQS.h +++ b/js/src/xpconnect/src/nsCSSPropertiesQS.h @@ -1,3 +1,39 @@ +/* ***** 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__ diff --git a/js/src/xpconnect/src/nsDOMQS.h b/js/src/xpconnect/src/nsDOMQS.h new file mode 100644 index 000000000000..dedbd5f75bfd --- /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__ */ diff --git a/js/src/xpconnect/src/xpcmaps.cpp b/js/src/xpconnect/src/xpcmaps.cpp index 2006252ca4ab..c1140e8c9f06 100644 --- a/js/src/xpconnect/src/xpcmaps.cpp +++ b/js/src/xpconnect/src/xpcmaps.cpp @@ -545,13 +545,13 @@ 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) @@ -562,7 +562,8 @@ XPCNativeScriptableSharedMap::GetNewOrUsed(JSUint32 flags, if(!shared) { entry->key = shared = - new XPCNativeScriptableShared(flags, key.TransferNameOwnership()); + new XPCNativeScriptableShared(flags, key.TransferNameOwnership(), + interfacesBitmap); if(!shared) return JS_FALSE; shared->PopulateJSClass(isGlobal); diff --git a/js/src/xpconnect/src/xpcmaps.h b/js/src/xpconnect/src/xpcmaps.h index acdee5733b95..940bdf1a20a6 100644 --- a/js/src/xpconnect/src/xpcmaps.h +++ b/js/src/xpconnect/src/xpcmaps.h @@ -549,7 +549,7 @@ public: 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) diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 6222363338cf..718284ededfc 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -1933,19 +1933,28 @@ public: // 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() @@ -1964,7 +1973,7 @@ public: private: XPCNativeScriptableFlags mFlags; - JSExtendedClass mJSClass; + XPCNativeScriptableSharedJSClass mJSClass; JSBool mCanBeSlim; }; @@ -1985,6 +1994,9 @@ public: const XPCNativeScriptableFlags& GetFlags() const {return mShared->GetFlags();} + PRUint32 + GetInterfacesBitmap() const {return mShared->GetInterfacesBitmap();} + JSClass* GetJSClass() {return mShared->GetJSClass();} @@ -2032,14 +2044,17 @@ 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 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* @@ -2048,16 +2063,24 @@ public: const XPCNativeScriptableFlags& GetFlags() const {return mFlags;} + PRUint32 + GetInterfacesBitmap() const {return mInterfacesBitmap;} + void SetCallback(already_AddRefed callback) - {mCallback = callback;} + {mCallback = callback;} void SetFlags(const XPCNativeScriptableFlags& flags) {mFlags = flags;} + void + SetInterfacesBitmap(PRUint32 interfacesBitmap) + {mInterfacesBitmap = interfacesBitmap;} + private: nsCOMPtr mCallback; XPCNativeScriptableFlags mFlags; + PRUint32 mInterfacesBitmap; }; /***********************************************/ diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index 57aa37273435..d37e5a91c7b9 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -404,6 +404,78 @@ xpc_qsUnwrapThis(JSContext *cx, 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(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, @@ -429,6 +501,9 @@ xpc_qsUnwrapThisFromCcx(XPCCallContext &ccx, 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); @@ -443,6 +518,21 @@ xpc_qsUnwrapArg(JSContext *cx, jsval v, T **ppArg, nsISupports **ppArgRef, reinterpret_cast(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) { diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 5b05be78f6da..e9f0fdb7ebaf 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -944,6 +944,7 @@ XPCWrappedNative::GatherProtoScriptableCreateInfo( sciProto.SetCallback(helper.forget()); sciProto.SetFlags(flags); + sciProto.SetInterfacesBitmap(classInfoHelper->GetInterfacesBitmap()); return; } @@ -3873,8 +3874,9 @@ ConstructSlimWrapper(XPCCallContext &ccx, nsISupports *p, nsWrapperCache *cache, } nsIClassInfo* classInfo = classInfoHelper; - XPCNativeScriptableCreateInfo sciProto(classInfoHelper.forget().get(), - flags); + XPCNativeScriptableCreateInfo + sciProto(classInfoHelper.forget().get(), flags, + classInfoHelper->GetInterfacesBitmap()); AutoMarkingWrappedNativeProtoPtr xpcproto(ccx); JSBool isGlobal = JS_FALSE; diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 551ede0a388d..c628cded40b5 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -1607,7 +1607,8 @@ XPCNativeScriptableInfo::Construct(XPCCallContext& ccx, 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)