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.

--HG--
extra : rebase_source : b33953705ace2b6c2171f32fcf7c0157a1f76173
This commit is contained in:
Peter Van der Beken 2010-01-12 15:24:00 +01:00
parent 85c9e641b0
commit 021da6d7ce
13 changed files with 326 additions and 18 deletions

View File

@ -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) \

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -493,6 +493,7 @@ customIncludes = [
'nsIDocument.h',
'nsINodeList.h',
'nsCSSPropertiesQS.h',
'nsDOMQS.h',
]
customQuickStubs = [

View File

@ -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__

View File

@ -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__ */

View File

@ -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);

View File

@ -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)

View File

@ -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<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*
@ -2048,6 +2063,9 @@ public:
const XPCNativeScriptableFlags&
GetFlags() const {return mFlags;}
PRUint32
GetInterfacesBitmap() const {return mInterfacesBitmap;}
void
SetCallback(already_AddRefed<nsIXPCScriptable> callback)
{mCallback = callback;}
@ -2055,9 +2073,14 @@ public:
void
SetFlags(const XPCNativeScriptableFlags& flags) {mFlags = flags;}
void
SetInterfacesBitmap(PRUint32 interfacesBitmap)
{mInterfacesBitmap = interfacesBitmap;}
private:
nsCOMPtr<nsIXPCScriptable> mCallback;
XPCNativeScriptableFlags mFlags;
PRUint32 mInterfacesBitmap;
};
/***********************************************/

View File

@ -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<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,
@ -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<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)
{

View File

@ -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;

View File

@ -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)