diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index 2cbd80b6dd6..3256cc4ae30 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -1152,7 +1152,7 @@ public: void SetHasRenderingObservers(bool aValue) { mNodeHasRenderingObservers = aValue; } - // Optimized way to get classinfo. May return null. + // Optimized way to get classinfo. virtual nsXPCClassInfo* GetClassInfo() = 0; protected: diff --git a/content/canvas/src/CustomQS_Canvas2D.h b/content/canvas/src/CustomQS_Canvas2D.h index 88fbe272e7a..b129beef493 100644 --- a/content/canvas/src/CustomQS_Canvas2D.h +++ b/content/canvas/src/CustomQS_Canvas2D.h @@ -110,21 +110,17 @@ Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, case nsIDOMCanvasRenderingContext2D::CMG_STYLE_PATTERN: { - nsWrapperCache* cache = xpc_qsGetWrapperCache(resultInterface); - qsObjectHelper helper(ToSupports(resultInterface)); - helper.SetNode(resultInterface); - helper.SetCanonical(ToCanonicalSupports(resultInterface)); - return xpc_qsXPCOMObjectToJsval(lccx, &helper, cache, + qsObjectHelper helper(resultInterface, + xpc_qsGetWrapperCache(resultInterface)); + return xpc_qsXPCOMObjectToJsval(lccx, helper, &NS_GET_IID(nsIDOMCanvasPattern), &interfaces[k_nsIDOMCanvasPattern], vp); } case nsIDOMCanvasRenderingContext2D::CMG_STYLE_GRADIENT: { - nsWrapperCache* cache = xpc_qsGetWrapperCache(resultInterface); - qsObjectHelper helper(ToSupports(resultInterface)); - helper.SetNode(resultInterface); - helper.SetCanonical(ToCanonicalSupports(resultInterface)); - return xpc_qsXPCOMObjectToJsval(lccx, &helper, cache, + qsObjectHelper helper(resultInterface, + xpc_qsGetWrapperCache(resultInterface)); + return xpc_qsXPCOMObjectToJsval(lccx, helper, &NS_GET_IID(nsIDOMCanvasGradient), &interfaces[k_nsIDOMCanvasGradient], vp); } diff --git a/content/xtf/src/nsXTFElementWrapper.cpp b/content/xtf/src/nsXTFElementWrapper.cpp index 2f622206e3f..4586efd2560 100644 --- a/content/xtf/src/nsXTFElementWrapper.cpp +++ b/content/xtf/src/nsXTFElementWrapper.cpp @@ -124,11 +124,17 @@ nsXTFElementWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_PRECONDITION(aInstancePtr, "null out param"); NS_IMPL_QUERY_CYCLE_COLLECTION(nsXTFElementWrapper) - if (aIID.Equals(NS_GET_IID(nsIClassInfo))) { + if (aIID.Equals(NS_GET_IID(nsIClassInfo)) || + aIID.Equals(NS_GET_IID(nsXPCClassInfo))) { *aInstancePtr = static_cast(this); NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIXPCScriptable))) { + *aInstancePtr = static_cast(this); + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(NS_GET_IID(nsIXTFElementWrapper))) { *aInstancePtr = static_cast(this); NS_ADDREF_THIS(); @@ -681,8 +687,7 @@ nsXTFElementWrapper::GetInterfaces(PRUint32* aCount, nsIID*** aArray) PRUint32 xtfCount = 0; nsIID** xtfArray = nsnull; - nsCOMPtr baseCi = - NS_GetDOMClassInfoInstance(eDOMClassInfo_Element_id); + nsCOMPtr baseCi = GetBaseXPCClassInfo(); if (baseCi) { baseCi->GetInterfaces(&baseCount, &baseArray); } @@ -740,8 +745,7 @@ nsXTFElementWrapper::GetHelperForLanguage(PRUint32 language, nsISupports** aHelper) { *aHelper = nsnull; - nsCOMPtr ci = - NS_GetDOMClassInfoInstance(eDOMClassInfo_Element_id); + nsCOMPtr ci = GetBaseXPCClassInfo(); return ci ? ci->GetHelperForLanguage(language, aHelper) : NS_ERROR_NOT_AVAILABLE; } diff --git a/content/xtf/src/nsXTFElementWrapper.h b/content/xtf/src/nsXTFElementWrapper.h index 828c42634b4..3274c23bb97 100644 --- a/content/xtf/src/nsXTFElementWrapper.h +++ b/content/xtf/src/nsXTFElementWrapper.h @@ -54,7 +54,7 @@ typedef nsXMLElement nsXTFElementWrapperBase; class nsXTFElementWrapper : public nsXTFElementWrapperBase, public nsIXTFElementWrapper, - public nsIClassInfo + public nsXPCClassInfo { public: nsXTFElementWrapper(already_AddRefed aNodeInfo, nsIXTFElement* aXTFElement); @@ -72,6 +72,11 @@ public: NS_DECL_NSIXTFELEMENTWRAPPER // nsIContent specializations: +#ifdef HAVE_CPP_AMBIGUITY_RESOLVING_USING + using nsINode::GetProperty; + using nsINode::SetProperty; +#endif + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, PRBool aCompileEventHandlers); @@ -122,7 +127,24 @@ public: // nsIClassInfo interface NS_DECL_NSICLASSINFO - + + // nsIXPCScriptable interface + NS_FORWARD_SAFE_NSIXPCSCRIPTABLE(GetBaseXPCClassInfo()) + + // nsXPCClassInfo + virtual void PreserveWrapper(nsISupports *aNative) + { + nsXPCClassInfo *ci = GetBaseXPCClassInfo(); + if (ci) { + ci->PreserveWrapper(aNative); + } + } + virtual PRUint32 GetInterfacesBitmap() + { + nsXPCClassInfo *ci = GetBaseXPCClassInfo(); + return ci ? ci->GetInterfacesBitmap() : 0; + } + virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); nsresult CloneState(nsIDOMElement *aElement) @@ -131,15 +153,20 @@ public: } nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; - // XTF elements have special classinfo, - // so this optimization needs to be disabled. - virtual nsXPCClassInfo* GetClassInfo() { return nsnull; } + virtual nsXPCClassInfo* GetClassInfo() { return this; } + protected: virtual nsIXTFElement* GetXTFElement() const { return mXTFElement; } - + + static nsXPCClassInfo* GetBaseXPCClassInfo() + { + return static_cast( + NS_GetDOMClassInfoInstance(eDOMClassInfo_Element_id)); + } + // implementation helpers: PRBool QueryInterfaceInner(REFNSIID aIID, void** result); diff --git a/js/src/xpconnect/src/nsDOMQS.h b/js/src/xpconnect/src/nsDOMQS.h index 319a298ade2..6625916f46b 100644 --- a/js/src/xpconnect/src/nsDOMQS.h +++ b/js/src/xpconnect/src/nsDOMQS.h @@ -76,6 +76,8 @@ xpc_qsUnwrapArg<_interface>(JSContext *cx, \ return rv; \ } +#undef DOMCI_CASTABLE_INTERFACE + #define DOMCI_CASTABLE_INTERFACE(_interface, _base, _bit, _extra) \ DEFINE_UNWRAP_CAST(_interface, _base, _bit) @@ -157,10 +159,4 @@ ToCanonicalSupports(nsContentList *p) return static_cast(p); } -inline already_AddRefed -ToCanonicalSupports(nsCOMPtr& p) -{ - return p.forget().get(); -} - #endif /* nsDOMQS_h__ */ diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index a48deb864c3..d6ffe247b1e 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -1149,11 +1149,13 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, if(NS_FAILED(InitClasses(aJSContext, tempGlobal))) return UnexpectedFailure(NS_ERROR_FAILURE); + nsresult rv; + xpcObjectHelper helper(aCOMObj); if(!XPCConvert::NativeInterface2JSObject(ccx, &v, getter_AddRefs(holder), - aCOMObj, &aIID, nsnull, - nsnull, tempGlobal, - PR_FALSE, OBJ_IS_GLOBAL, &rv)) + helper, &aIID, nsnull, + tempGlobal, PR_FALSE, + OBJ_IS_GLOBAL, &rv)) return UnexpectedFailure(rv); NS_ASSERTION(NS_SUCCEEDED(rv) && holder, "Didn't wrap properly"); @@ -1233,10 +1235,10 @@ NativeInterface2JSObject(XPCLazyCallContext & lccx, nsIXPConnectJSObjectHolder **aHolder) { nsresult rv; - if(!XPCConvert::NativeInterface2JSObject(lccx, aVal, aHolder, aCOMObj, aIID, - nsnull, aCache, aScope, - aAllowWrapping, OBJ_IS_NOT_GLOBAL, - &rv)) + xpcObjectHelper helper(aCOMObj, aCache); + if(!XPCConvert::NativeInterface2JSObject(lccx, aVal, aHolder, helper, aIID, + nsnull, aScope, aAllowWrapping, + OBJ_IS_NOT_GLOBAL, &rv)) return rv; #ifdef DEBUG diff --git a/js/src/xpconnect/src/qsgen.py b/js/src/xpconnect/src/qsgen.py index 566f031ad99..af29ca6633e 100644 --- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -708,12 +708,10 @@ def writeResultConv(f, type, jsvalPtr, jsvalRef): " return JS_TRUE;\n" " }\n" " }\n" - " qsObjectHelper helper(ToSupports(result));\n" - " helper.SetNode(result);\n" - " helper.SetCanonical(ToCanonicalSupports(result));\n" " // After this point do not use 'result'!\n" + " qsObjectHelper helper(result, cache);\n" " return xpc_qsXPCOMObjectToJsval(lccx, " - "&helper, cache, &NS_GET_IID(%s), &interfaces[k_%s], %s);\n" + "helper, &NS_GET_IID(%s), &interfaces[k_%s], %s);\n" % (jsvalPtr, type.name, type.name, jsvalPtr)) return @@ -1250,12 +1248,10 @@ def writeTraceableResultConv(f, type): " return wrapper;\n" " }\n" " }\n" - " qsObjectHelper helper(ToSupports(result));\n" - " helper.SetNode(result);\n" - " helper.SetCanonical(ToCanonicalSupports(result));\n" " // After this point do not use 'result'!\n" + " qsObjectHelper helper(result, cache);\n" " JSBool ok = xpc_qsXPCOMObjectToJsval(lccx, " - "&helper, cache, &NS_GET_IID(%s), &interfaces[k_%s], " + "helper, &NS_GET_IID(%s), &interfaces[k_%s], " "&vp.array[0]);\n" % (type.name, type.name)) f.write(" if (!ok) {\n"); diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 9099cf87945..2acc81ab77b 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -4196,7 +4196,8 @@ nsXPCComponents::AttachNewComponentsObject(XPCCallContext& ccx, return JS_FALSE; nsCOMPtr wrapper; - XPCWrappedNative::GetNewOrUsed(ccx, cholder, aScope, iface, nsnull, + xpcObjectHelper helper(cholder); + XPCWrappedNative::GetNewOrUsed(ccx, helper, aScope, iface, OBJ_IS_NOT_GLOBAL, getter_AddRefs(wrapper)); if(!wrapper) return JS_FALSE; diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index 6430700bd7c..72b42a4f818 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -469,8 +469,9 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s, // global object will not have been collected, and // therefore this NativeInterface2JSObject will not end up // creating a new XPCNativeScriptableShared. - if(!NativeInterface2JSObject(lccx, d, nsnull, iface, iid, - nsnull, nsnull, scope, PR_TRUE, + xpcObjectHelper helper(iface); + if(!NativeInterface2JSObject(lccx, d, nsnull, helper, iid, + nsnull, scope, PR_TRUE, OBJ_IS_NOT_GLOBAL, pErr)) return JS_FALSE; @@ -1084,15 +1085,13 @@ JSBool XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, jsval* d, nsIXPConnectJSObjectHolder** dest, - nsISupports* src, + xpcObjectHelper& aHelper, const nsID* iid, XPCNativeInterface** Interface, - nsWrapperCache *cache, JSObject* scope, PRBool allowNativeWrapper, PRBool isGlobal, - nsresult* pErr, - qsObjectHelper* aHelper) + nsresult* pErr) { NS_ASSERTION(scope, "bad param"); NS_ASSERTION(!Interface || iid, @@ -1101,6 +1100,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, *d = JSVAL_NULL; if(dest) *dest = nsnull; + nsISupports *src = aHelper.Object(); if(!src) return JS_TRUE; if(pErr) @@ -1149,8 +1149,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, if(!xpcscope) return JS_FALSE; - if(!cache) - CallQueryInterface(src, &cache); + nsWrapperCache *cache = aHelper.GetWrapperCache(); PRBool tryConstructSlimWrapper = PR_FALSE; JSObject *flat; @@ -1186,7 +1185,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, return JS_FALSE; jsval slim; - if(ConstructSlimWrapper(ccx, src, aHelper, cache, xpcscope, &slim)) + if(ConstructSlimWrapper(ccx, aHelper, xpcscope, &slim)) { *d = slim; return JS_TRUE; @@ -1234,8 +1233,8 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, if(!ccx.IsValid()) return JS_FALSE; - rv = XPCWrappedNative::GetNewOrUsed(ccx, src, xpcscope, iface, - cache, isGlobal, + rv = XPCWrappedNative::GetNewOrUsed(ccx, aHelper, xpcscope, iface, + isGlobal, getter_AddRefs(strongWrapper)); wrapper = strongWrapper; diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 8133f466f9d..96b7c182812 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -149,7 +149,7 @@ static FARPROC GetProcAddressA(HMODULE hMod, wchar_t *procName); #undef GetClassName #endif -class qsObjectHelper; +#include "nsINode.h" /***************************************************************************/ // Compile time switches for instrumentation and stuff.... @@ -211,13 +211,6 @@ void DEBUG_CheckWrapperThreadSafety(const XPCWrappedNative* wrapper); #define DEBUG_CheckWrapperThreadSafety(w) ((void)0) #endif -/***************************************************************************/ - -// Defeat possible Windows macro-mangling of the name -#ifdef GetClassInfo -#undef GetClassInfo -#endif - /***************************************************************************/ // default initial sizes for maps (hashtables) @@ -2287,11 +2280,9 @@ private: QITableEntry* mOffsets; }; - +class xpcObjectHelper; extern JSBool ConstructSlimWrapper(XPCCallContext &ccx, - nsISupports *p, - qsObjectHelper* aHelper, - nsWrapperCache* aCache, + xpcObjectHelper &aHelper, XPCWrappedNativeScope* xpcScope, jsval *rval); extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj); @@ -2514,16 +2505,11 @@ public: GetRuntime() const {XPCWrappedNativeScope* scope = GetScope(); return scope ? scope->GetRuntime() : nsnull;} - /** - * If Object has a nsWrapperCache it should be passed in. If a cache is - * passed in then cache->GetWrapper() must be null. - */ static nsresult GetNewOrUsed(XPCCallContext& ccx, - nsISupports* Object, + xpcObjectHelper& helper, XPCWrappedNativeScope* Scope, XPCNativeInterface* Interface, - nsWrapperCache* cache, JSBool isGlobal, XPCWrappedNative** wrapper); @@ -3065,6 +3051,105 @@ private: /***************************************************************************/ // data conversion +class xpcObjectHelper +{ +public: + xpcObjectHelper(nsISupports *aObject, nsWrapperCache *aCache = nsnull) + : mCanonical(nsnull), + mObject(aObject), + mCache(aCache), + mIsNode(PR_FALSE) + { + if(!mCache) + { + if(aObject) + CallQueryInterface(aObject, &mCache); + else + mCache = nsnull; + } + } + + nsISupports* Object() + { + return mObject; + } + + nsISupports* GetCanonical() + { + if (!mCanonical) { + mCanonicalStrong = do_QueryInterface(mObject); + mCanonical = mCanonicalStrong; + } + return mCanonical; + } + + already_AddRefed forgetCanonical() + { + NS_ASSERTION(mCanonical, "Huh, no canonical to forget?"); + + if (!mCanonicalStrong) + mCanonicalStrong = mCanonical; + mCanonical = nsnull; + return mCanonicalStrong.forget(); + } + + nsIClassInfo *GetClassInfo() + { + if(mXPCClassInfo) + return mXPCClassInfo; + if(!mClassInfo) + mClassInfo = do_QueryInterface(mObject); + return mClassInfo; + } + nsXPCClassInfo *GetXPCClassInfo() + { + if(!mXPCClassInfo) + { + if(mIsNode) + mXPCClassInfo = static_cast(GetCanonical())->GetClassInfo(); + else + CallQueryInterface(mObject, getter_AddRefs(mXPCClassInfo)); + } + return mXPCClassInfo; + } + + already_AddRefed forgetXPCClassInfo() + { + GetXPCClassInfo(); + + return mXPCClassInfo.forget(); + } + + nsWrapperCache *GetWrapperCache() + { + return mCache; + } + +protected: + xpcObjectHelper(nsISupports *aObject, nsISupports *aCanonical, + nsWrapperCache *aCache, PRBool aIsNode) + : mCanonical(aCanonical), + mObject(aObject), + mCache(aCache), + mIsNode(aIsNode) + { + if(!mCache && aObject) + CallQueryInterface(aObject, &mCache); + } + + nsCOMPtr mCanonicalStrong; + nsISupports* mCanonical; + +private: + xpcObjectHelper(xpcObjectHelper& aOther); + + nsISupports* mObject; + nsWrapperCache* mCache; + nsCOMPtr mClassInfo; + nsRefPtr mXPCClassInfo; + PRBool mIsNode; +}; + // class here just for static methods class XPCConvert { @@ -3121,33 +3206,29 @@ public: static JSBool NativeInterface2JSObject(XPCCallContext& ccx, jsval* d, nsIXPConnectJSObjectHolder** dest, - nsISupports* src, + xpcObjectHelper& aHelper, const nsID* iid, XPCNativeInterface** Interface, - nsWrapperCache *cache, JSObject* scope, PRBool allowNativeWrapper, PRBool isGlobal, - nsresult* pErr, - qsObjectHelper* aHelper = nsnull) + nsresult* pErr) { XPCLazyCallContext lccx(ccx); - return NativeInterface2JSObject(lccx, d, dest, src, iid, Interface, - cache, scope, allowNativeWrapper, - isGlobal, pErr, aHelper); + return NativeInterface2JSObject(lccx, d, dest, aHelper, iid, Interface, + scope, allowNativeWrapper, isGlobal, + pErr); } static JSBool NativeInterface2JSObject(XPCLazyCallContext& lccx, jsval* d, nsIXPConnectJSObjectHolder** dest, - nsISupports* src, + xpcObjectHelper& aHelper, const nsID* iid, XPCNativeInterface** Interface, - nsWrapperCache *cache, JSObject* scope, PRBool allowNativeWrapper, PRBool isGlobal, - nsresult* pErr, - qsObjectHelper* aHelper = nsnull); + nsresult* pErr); static JSBool GetNativeInterfaceFromJSObject(XPCCallContext& ccx, void** dest, JSObject* src, diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index b6a82acebe0..3478be65b37 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -1110,8 +1110,7 @@ xpc_qsStringToJsstring(JSContext *cx, nsString &str, JSString **rval) } JSBool -xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, qsObjectHelper* aHelper, - nsWrapperCache *cache, +xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, qsObjectHelper &aHelper, const nsIID *iid, XPCNativeInterface **iface, jsval *rval) { @@ -1130,12 +1129,9 @@ xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, qsObjectHelper* aHelper, nsresult rv; if(!XPCConvert::NativeInterface2JSObject(lccx, rval, nsnull, - aHelper->Object(), - iid, iface, - cache, + aHelper, iid, iface, lccx.GetCurrentJSObject(), PR_TRUE, - OBJ_IS_NOT_GLOBAL, &rv, - aHelper)) + OBJ_IS_NOT_GLOBAL, &rv)) { // I can't tell if NativeInterface2JSObject throws JS exceptions // or not. This is a sloppy stab at the right semantics; the diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index 6b335ea1130..9e35312ce3f 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -78,78 +78,87 @@ struct xpc_qsHashEntry { size_t chain; }; -class qsObjectHelper +inline nsISupports* +ToSupports(nsISupports *p) +{ + return p; +} + +inline nsISupports* +ToCanonicalSupports(nsISupports* p) +{ + return nsnull; +} + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) || \ + _MSC_FULL_VER >= 140050215 + +/* Use a compiler intrinsic if one is available. */ + +#define QS_CASTABLE_TO(_interface, _class) __is_base_of(_interface, _class) + +#else + +/* The generic version of this predicate relies on the overload resolution + * rules. If |_class| inherits from |_interface|, the |_interface*| + * overload of DOMCI_CastableTo<_interface>::p() will be chosen, otherwise + * the |void*| overload will be chosen. There is no definition of these + * functions; we determine which overload was selected by inspecting the + * size of the return type. + */ + +template struct QS_CastableTo { + struct false_type { int x[1]; }; + struct true_type { int x[2]; }; + static false_type p(void*); + static true_type p(Interface*); +}; + +#define QS_CASTABLE_TO(_interface, _class) \ + (sizeof(QS_CastableTo<_interface>::p(static_cast<_class*>(0))) == \ + sizeof(QS_CastableTo<_interface>::true_type)) + +#endif + +#define QS_IS_NODE(_class) \ + QS_CASTABLE_TO(nsINode, _class) || \ + QS_CASTABLE_TO(nsIDOMNode, _class) + +class qsObjectHelper : public xpcObjectHelper { public: - qsObjectHelper(nsISupports* aObject) - : mObject(aObject), - mCanonical(nsnull), - mCanonicalIsStrong(PR_FALSE), - mNode(nsnull) {} - - ~qsObjectHelper() + template + inline + qsObjectHelper(T *aObject, nsWrapperCache *aCache) + : xpcObjectHelper(ToSupports(aObject), ToCanonicalSupports(aObject), + aCache, QS_IS_NODE(T)) + {} + template + inline + qsObjectHelper(nsCOMPtr& aObject, nsWrapperCache *aCache) + : xpcObjectHelper(ToSupports(aObject.get()), + ToCanonicalSupports(aObject.get()), aCache, QS_IS_NODE(T)) { - if (mCanonicalIsStrong) { - NS_RELEASE(mCanonical); + if (mCanonical) + { + // Transfer the strong reference. + mCanonicalStrong = dont_AddRef(mCanonical); + aObject.forget(); } } - - void SetCanonical(already_AddRefed aCanonical) + template + inline + qsObjectHelper(nsRefPtr& aObject, nsWrapperCache *aCache) + : xpcObjectHelper(ToSupports(aObject.get()), + ToCanonicalSupports(aObject.get()), aCache, QS_IS_NODE(T)) { - mCanonical = aCanonical.get(); - if (mCanonical) { - mCanonicalIsStrong = PR_TRUE; + if (mCanonical) + { + // Transfer the strong reference. + mCanonicalStrong = dont_AddRef(mCanonical); + aObject.forget(); } } - - void SetCanonical(nsISupports* aCanonical) { mCanonical = aCanonical; } - - void SetNode(nsINode* aNode) { mNode = aNode; } - - void SetNode(void* /*aDummy*/) { } - - nsISupports* Object() { return mObject; } - - nsISupports* GetCanonical() - { - if (!mCanonical) { - CallQueryInterface(mObject, &mCanonical); - mCanonicalIsStrong = PR_TRUE; - } - return mCanonical; - } - - already_AddRefed TakeCanonical() - { - nsISupports* retval = mCanonical; - if (mCanonicalIsStrong) { - mCanonicalIsStrong = PR_FALSE; - } else { - NS_IF_ADDREF(mCanonical); - } - mCanonical = nsnull; - return retval; - } - - already_AddRefed GetXPCClassInfo() - { - nsRefPtr ci; - if (mNode) { - ci = mNode->GetClassInfo(); - } else { - CallQueryInterface(mObject, getter_AddRefs(ci)); - } - return ci.forget(); - } - -private: - qsObjectHelper(qsObjectHelper& aOther) {} - qsObjectHelper() {} - - nsISupports* mObject; - nsISupports* mCanonical; - PRBool mCanonicalIsStrong; - nsINode* mNode; }; JSBool @@ -630,8 +639,7 @@ xpc_qsGetWrapperCache(void *p) */ JSBool xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, - qsObjectHelper* aHelper, - nsWrapperCache *cache, + qsObjectHelper &aHelper, const nsIID *iid, XPCNativeInterface **iface, jsval *rval); @@ -644,18 +652,6 @@ xpc_qsVariantToJsval(XPCLazyCallContext &ccx, nsIVariant *p, jsval *rval); -inline nsISupports* -ToSupports(nsISupports *p) -{ - return p; -} - -inline nsISupports* -ToCanonicalSupports(nsISupports* p) -{ - return nsnull; -} - #ifdef DEBUG void xpc_qsAssertContextOK(JSContext *cx); diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index 9b3a24426ae..1e11fb8beb2 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -1430,10 +1430,11 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, if(newThis) { jsval v; + xpcObjectHelper helper(newThis); JSBool ok = XPCConvert::NativeInterface2JSObject(ccx, - &v, nsnull, newThis, newWrapperIID, - nsnull, nsnull, obj, PR_FALSE, PR_FALSE, + &v, nsnull, helper, newWrapperIID, + nsnull, obj, PR_FALSE, PR_FALSE, nsnull); if(newWrapperIID) nsMemory::Free(newWrapperIID); diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index f97bcf954e1..31ef18a97f8 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -296,30 +296,24 @@ FinishCreate(XPCCallContext& ccx, // static nsresult XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, - nsISupports* Object, + xpcObjectHelper& helper, XPCWrappedNativeScope* Scope, XPCNativeInterface* Interface, - nsWrapperCache *cache, JSBool isGlobal, XPCWrappedNative** resultWrapper) { + nsWrapperCache *cache = helper.GetWrapperCache(); + NS_ASSERTION(!cache || !cache->GetWrapper(), "We assume the caller already checked if it could get the " "wrapper from the cache."); nsresult rv; -#ifdef DEBUG NS_ASSERTION(!Scope->GetRuntime()->GetThreadRunningGC(), "XPCWrappedNative::GetNewOrUsed called during GC"); - { - nsWrapperCache *cache2 = nsnull; - CallQueryInterface(Object, &cache2); - NS_ASSERTION(!cache == !cache2, "Caller should pass in the cache!"); - } -#endif - nsCOMPtr identity; + nsISupports *identity; #ifdef XPC_IDISPATCH_SUPPORT // XXX This is done for the benefit of some warped COM implementations // where QI(IID_IUnknown, a.b) == QI(IID_IUnknown, a). If someone passes @@ -329,10 +323,10 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, PRBool isIDispatch = Interface && Interface->GetIID()->Equals(NSID_IDISPATCH); if(isIDispatch) - identity = Object; + identity = helper.Object(); else #endif - identity = do_QueryInterface(Object); + identity = helper.GetCanonical(); if(!identity) { @@ -396,18 +390,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, JSBool isClassInfo = Interface && Interface->GetIID()->Equals(NS_GET_IID(nsIClassInfo)); - nsCOMPtr info; - - if(!isClassInfo) - info = do_QueryInterface(identity); + nsIClassInfo *info = helper.GetClassInfo(); #ifdef XPC_IDISPATCH_SUPPORT // If this is an IDispatch wrapper and it didn't give us a class info // we'll provide a default one + nsCOMPtr dispatchInfo; if(isIDispatch && !info) { - info = dont_AddRef(static_cast + dispatchInfo = dont_AddRef(static_cast (XPCIDispatchClassInfo::GetSingleton())); + info = dispatchInfo; } #endif @@ -456,8 +449,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, XPCWrappedNativeScope* betterScope = XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent); if(betterScope != Scope) - return GetNewOrUsed(ccx, identity, betterScope, Interface, - cache, isGlobal, resultWrapper); + return GetNewOrUsed(ccx, helper, betterScope, Interface, + isGlobal, resultWrapper); newParentVal = OBJECT_TO_JSVAL(parent); } @@ -510,6 +503,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, } else { + nsISupports *Object = helper.Object(); if(nsXPCWrappedJSClass::IsWrappedJS(Object)) { nsCOMPtr wrappedjs(do_QueryInterface(Object)); @@ -542,8 +536,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, proto->CacheOffsets(identity); wrapper = needsXOW - ? new XPCWrappedNativeWithXOW(identity.get(), proto) - : new XPCWrappedNative(identity.get(), proto); + ? new XPCWrappedNativeWithXOW(identity, proto) + : new XPCWrappedNative(identity, proto); if(!wrapper) return NS_ERROR_FAILURE; } @@ -560,8 +554,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, return NS_ERROR_FAILURE; wrapper = needsXOW - ? new XPCWrappedNativeWithXOW(identity.get(), Scope, set) - : new XPCWrappedNative(identity.get(), Scope, set); + ? new XPCWrappedNativeWithXOW(identity, Scope, set) + : new XPCWrappedNative(identity, Scope, set); if(!wrapper) return NS_ERROR_FAILURE; @@ -570,8 +564,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, // The strong reference was taken over by the wrapper, so make the nsCOMPtr // forget about it. - // Note that identity is null from here on! - identity.forget(); + helper.forgetCanonical(); NS_ADDREF(wrapper); @@ -3853,25 +3846,11 @@ static PRUint32 sSlimWrappers; JSBool ConstructSlimWrapper(XPCCallContext &ccx, - nsISupports *p, - qsObjectHelper* aHelper, - nsWrapperCache* cache, + xpcObjectHelper &aHelper, XPCWrappedNativeScope* xpcScope, jsval *rval) { - nsCOMPtr strongIdentity; - nsISupports* identityObj = aHelper ? aHelper->GetCanonical() : nsnull; - if (!identityObj) { - strongIdentity = do_QueryInterface(p); - identityObj = strongIdentity.get(); - } - - nsRefPtr classInfoHelper; - if (aHelper) { - classInfoHelper = aHelper->GetXPCClassInfo(); - } - if (!classInfoHelper) { - CallQueryInterface(p, getter_AddRefs(classInfoHelper)); - } + nsISupports *identityObj = aHelper.GetCanonical(); + nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo(); JSUint32 flagsInt; nsresult rv = classInfoHelper->GetScriptableFlags(&flagsInt); @@ -3915,6 +3894,7 @@ ConstructSlimWrapper(XPCCallContext &ccx, // The PreCreate hook could have forced the creation of a wrapper, need // to check for that here and return early. + nsWrapperCache *cache = aHelper.GetWrapperCache(); JSObject* wrapper = cache->GetWrapper(); if(wrapper) { @@ -3923,16 +3903,15 @@ ConstructSlimWrapper(XPCCallContext &ccx, return JS_TRUE; } - nsIClassInfo* classInfo = classInfoHelper; PRUint32 interfacesBitmap = classInfoHelper->GetInterfacesBitmap(); XPCNativeScriptableCreateInfo - sciProto(classInfoHelper.forget().get(), flags, interfacesBitmap); + sciProto(aHelper.forgetXPCClassInfo(), flags, interfacesBitmap); AutoMarkingWrappedNativeProtoPtr xpcproto(ccx); JSBool isGlobal = JS_FALSE; - xpcproto = XPCWrappedNativeProto::GetNewOrUsed(ccx, xpcScope, classInfo, - &sciProto, JS_FALSE, - isGlobal); + xpcproto = XPCWrappedNativeProto::GetNewOrUsed(ccx, xpcScope, + classInfoHelper, &sciProto, + JS_FALSE, isGlobal); if(!xpcproto) return JS_FALSE; @@ -3952,11 +3931,7 @@ ConstructSlimWrapper(XPCCallContext &ccx, return JS_FALSE; // Transfer ownership to the wrapper's private. - if (strongIdentity) { - strongIdentity.forget(); - } else { - aHelper->TakeCanonical(); - } + aHelper.forgetCanonical(); cache->SetWrapper(wrapper);