diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index ebcc250951c0..f650a2f53f76 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1280,7 +1280,8 @@ public: void *aClosure) { if (aCache->PreservingWrapper()) { - aCallback(nsIProgrammingLanguage::JAVASCRIPT, aCache->GetWrapper(), + aCallback(nsIProgrammingLanguage::JAVASCRIPT, + aCache->GetWrapperPreserveColor(), aClosure); } } diff --git a/content/base/src/nsDOMDocumentType.cpp b/content/base/src/nsDOMDocumentType.cpp index ab02ef9aad5f..20fb07ef806f 100644 --- a/content/base/src/nsDOMDocumentType.cpp +++ b/content/base/src/nsDOMDocumentType.cpp @@ -51,6 +51,7 @@ #include "nsIDocument.h" #include "nsIXPConnect.h" #include "nsIDOMDocument.h" +#include "xpcpublic.h" nsresult NS_NewDOMDocumentType(nsIDOMDocumentType** aDocType, diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index dcf323e78933..f5eafbd533a7 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -3790,7 +3790,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) if (!mWillReparent) { // We really shouldn't have a wrapper here but if we do we need to make sure // it has the correct parent. - JSObject *obj = GetWrapper(); + JSObject *obj = GetWrapperPreserveColor(); if (obj) { JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject(); nsIScriptContext *scx = aScriptGlobalObject->GetContext(); diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 08b1719980d3..aafc3c3f81dc 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -71,6 +71,7 @@ #include "nsIRunnable.h" #include "nsThreadUtils.h" #include "nsDOMEventTargetWrapperCache.h" +#include "xpcpublic.h" // General helper includes #include "nsGlobalWindow.h" @@ -4239,6 +4240,31 @@ nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsid id, PRBool *aIsNumber) return i; } +// static +nsresult +nsDOMClassInfo::WrapNative(JSContext *cx, JSObject *scope, + nsISupports *native, nsWrapperCache *cache, + const nsIID* aIID, jsval *vp, + nsIXPConnectJSObjectHolder** aHolder, + PRBool aAllowWrapping) +{ + if (!native) { + NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!"); + + *vp = JSVAL_NULL; + + return NS_OK; + } + + JSObject *wrapper = xpc_GetCachedSlimWrapper(cache, scope, vp); + if (wrapper) { + return NS_OK; + } + + return sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID, + aAllowWrapping, vp, aHolder); +} + NS_IMETHODIMP nsDOMClassInfo::GetInterfaces(PRUint32 *aCount, nsIID ***aArray) { diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index b97b3aae7dfa..0b95bdc84e24 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -48,7 +48,6 @@ #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext #include "nsIScriptGlobalObject.h" #include "nsContentUtils.h" -#include "xpcpublic.h" class nsIDOMWindow; class nsIDOMNSHTMLOptionCollection; @@ -253,24 +252,7 @@ protected: nsISupports *native, nsWrapperCache *cache, const nsIID* aIID, jsval *vp, nsIXPConnectJSObjectHolder** aHolder, - PRBool aAllowWrapping) - { - if (!native) { - NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!"); - - *vp = JSVAL_NULL; - - return NS_OK; - } - - JSObject *wrapper = xpc_GetCachedSlimWrapper(cache, scope, vp); - if (wrapper) { - return NS_OK; - } - - return sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID, - aAllowWrapping, vp, aHolder); - } + PRBool aAllowWrapping); static nsIXPConnect *sXPConnect; static nsIScriptSecurityManager *sSecMan; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index a1838ed73c04..0c2c48f22671 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -85,6 +85,7 @@ #include "nsIXULRuntime.h" #include "nsDOMClassInfo.h" +#include "xpcpublic.h" #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject #include "jsxdrapi.h" diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index 555955fec311..a7ac2f058e66 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -42,6 +42,7 @@ #include "nsCycleCollectionParticipant.h" struct JSObject; +class nsContentUtils; typedef PRUptrdiff PtrBits; @@ -58,6 +59,8 @@ typedef PRUptrdiff PtrBits; */ class nsWrapperCache { + friend class nsContentUtils; + public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID) @@ -70,7 +73,25 @@ public: "Destroying cache with a preserved wrapper!"); } - JSObject* GetWrapper() const + /** + * This getter clears the gray bit before handing out the JSObject which means + * that the object is guaranteed to be kept alive past the next CC. + * + * Implemented in xpcpublic.h because we have to include some JS headers that + * don't play nicely with the rest of the codebase. Include xpcpublic.h if you + * need to call this method. + */ + inline JSObject* GetWrapper() const; + + /** + * This getter does not change the color of the JSObject meaning that the + * object returned is not guaranteed to be kept alive past the next CC. + * + * This should only be called if you are certain that the return value won't + * be passed into a JS API function and that it won't be stored without being + * rooted (or otherwise signaling the stored value to the CC). + */ + JSObject* GetWrapperPreserveColor() const { return reinterpret_cast(mWrapperPtrBits & ~kWrapperBitMask); } @@ -88,6 +109,23 @@ public: mWrapperPtrBits = 0; } + PRBool PreservingWrapper() + { + return (mWrapperPtrBits & WRAPPER_BIT_PRESERVED) != 0; + } + + void SetIsProxy() + { + mWrapperPtrBits |= WRAPPER_IS_PROXY; + } + + PRBool IsProxy() + { + return (mWrapperPtrBits & WRAPPER_IS_PROXY) != 0; + } + +private: + // Only meant to be called by nsContentUtils. void SetPreservingWrapper(PRBool aPreserve) { if(aPreserve) { @@ -98,22 +136,6 @@ public: } } - PRBool PreservingWrapper() - { - return (mWrapperPtrBits & WRAPPER_BIT_PRESERVED) != 0; - } - - void SetIsProxy() - { - mWrapperPtrBits |= WRAPPER_IS_PROXY; - } - - PRBool IsProxy() - { - return (mWrapperPtrBits & WRAPPER_IS_PROXY) != 0; - } - -private: enum { WRAPPER_BIT_PRESERVED = 1 << 0 }; enum { WRAPPER_IS_PROXY = 1 << 1 }; enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_PROXY) }; diff --git a/js/src/jscell.h b/js/src/jscell.h index 173a3dbd49ff..aadfe8d9bfe0 100644 --- a/js/src/jscell.h +++ b/js/src/jscell.h @@ -71,6 +71,7 @@ struct Cell { JS_ALWAYS_INLINE bool isMarked(uint32 color) const; JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color) const; + JS_ALWAYS_INLINE void unmark(uint32 color) const; inline JSCompartment *compartment() const; diff --git a/js/src/jsgc.h b/js/src/jsgc.h index da8108dc6922..5f990b49bc43 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -213,6 +213,13 @@ struct ArenaBitmap { return true; } + JS_ALWAYS_INLINE void unmark(size_t bit, uint32 color) { + bit += color; + JS_ASSERT(bit < BitCount); + uintptr_t *word = &bitmap[bit / JS_BITS_PER_WORD]; + *word &= ~(uintptr_t(1) << (bit % JS_BITS_PER_WORD)); + } + #ifdef DEBUG bool noBitsSet() { for (unsigned i = 0; i < BitWords; i++) { @@ -461,6 +468,14 @@ Cell::markIfUnmarked(uint32 color = BLACK) const return bitmap()->markIfUnmarked(cellIndex(), color); } +void +Cell::unmark(uint32 color) const +{ + JS_ASSERT(color != BLACK); + AssertValidColor(this, color); + bitmap()->unmark(cellIndex(), color); +} + JSCompartment * Cell::compartment() const { diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index 012b5e7c2d8b..d043f6af220f 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -55,7 +55,8 @@ #include "jspubtd.h" #include "xptinfo.h" #include "nsAXPCNativeCallContext.h" -#include "nsWrapperCache.h" + +class nsWrapperCache; %} /***************************************************************************/ diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 0f2ddb2394aa..ddd979e6549c 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -569,9 +569,12 @@ struct TraversalTracer : public JSTracer static void NoteJSChild(JSTracer *trc, void *thing, uint32 kind) { + TraversalTracer *tracer = static_cast(trc); + if(!nsXPConnect::IsGray(thing) && !tracer->cb.WantAllTraces()) + return; + if(ADD_TO_CC(kind)) { - TraversalTracer *tracer = static_cast(trc); #if defined(DEBUG) if (NS_UNLIKELY(tracer->cb.WantDebugInfo())) { // based on DumpNotify in jsapi.c @@ -680,7 +683,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) #endif { // Normal codepath (matches non-DEBUG_CC codepath). - type = !markJSObject && IsGray(p) ? GCUnmarked : GCMarked; + type = !markJSObject ? GCUnmarked : GCMarked; } if (cb.WantDebugInfo()) { @@ -775,7 +778,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) if(traceKind != JSTRACE_OBJECT || dontTraverse) return NS_OK; - + if(clazz == &XPC_WN_Tearoff_JSClass) { // A tearoff holds a strong reference to its native object @@ -1588,7 +1591,7 @@ MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper, NS_ENSURE_SUCCESS(rv, rv); - newParent = parentWrapper->GetFlatJSObjectNoMark(); + newParent = parentWrapper->GetFlatJSObject(); } else NS_ASSERTION(betterScope == newScope, "Weird scope returned"); diff --git a/js/src/xpconnect/src/xpccallcontext.cpp b/js/src/xpconnect/src/xpccallcontext.cpp index 1c6d7f2d4212..dd3f29ab3f52 100644 --- a/js/src/xpconnect/src/xpccallcontext.cpp +++ b/js/src/xpconnect/src/xpccallcontext.cpp @@ -196,7 +196,7 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage, { DEBUG_CheckWrapperThreadSafety(mWrapper); - mFlattenedJSObject = mWrapper->GetFlatJSObjectAndMark(); + mFlattenedJSObject = mWrapper->GetFlatJSObject(); if(mTearOff) { diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index af1d27511e7e..c5c750c59ee3 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1353,7 +1353,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, // If we're not creating security wrappers, we can return the // XPCWrappedNative as-is here. - flat = wrapper->GetFlatJSObjectAndMark(); + flat = wrapper->GetFlatJSObject(); jsval v = OBJECT_TO_JSVAL(flat); if(!XPCPerThreadData::IsMainThread(lccx.GetJSContext()) || !allowNativeWrapper) diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index ff269f3f7dbe..3a0976af168e 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -94,8 +94,10 @@ WrappedJSDyingJSObjectFinder(JSDHashTable *table, JSDHashEntryHdr *hdr, { if(wrapper->IsSubjectToFinalization()) { - js::SwitchToCompartment sc(data->cx, wrapper->GetJSObject()); - if(JS_IsAboutToBeFinalized(data->cx, wrapper->GetJSObject())) + js::SwitchToCompartment sc(data->cx, + wrapper->GetJSObjectPreserveColor()); + if(JS_IsAboutToBeFinalized(data->cx, + wrapper->GetJSObjectPreserveColor())) data->array->AppendElement(wrapper); } wrapper = wrapper->GetNextWrapper(); @@ -503,13 +505,10 @@ XPCJSRuntime::SuspectWrappedNative(JSContext *cx, XPCWrappedNative *wrapper, // Only suspect wrappedJSObjects that are in a compartment that // participates in cycle collection. - JSObject* obj = wrapper->GetFlatJSObjectAndMark(); + JSObject* obj = wrapper->GetFlatJSObjectPreserveColor(); if(!xpc::ParticipatesInCycleCollection(cx, obj)) return; - NS_ASSERTION(!JS_IsAboutToBeFinalized(cx, obj), - "SuspectWrappedNative attempting to touch dead object"); - // Only record objects that might be part of a cycle as roots, unless // the callback wants all traces (a debug feature). if(nsXPConnect::IsGray(obj) || cb.WantAllTraces()) @@ -572,7 +571,7 @@ XPCJSRuntime::AddXPConnectRoots(JSContext* cx, for(XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) { nsXPCWrappedJS *wrappedJS = static_cast(e); - JSObject *obj = wrappedJS->GetJSObject(); + JSObject *obj = wrappedJS->GetJSObjectPreserveColor(); // Only suspect wrappedJSObjects that are in a compartment that // participates in cycle collection. @@ -640,7 +639,7 @@ static PLDHashOperator SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg) { JSContext *cx = (JSContext *)arg; - return IsAboutToBeFinalized(cx, wn->GetFlatJSObjectNoMark()) + return IsAboutToBeFinalized(cx, wn->GetFlatJSObjectPreserveColor()) ? PL_DHASH_REMOVE : PL_DHASH_NEXT; } diff --git a/js/src/xpconnect/src/xpcmaps.h b/js/src/xpconnect/src/xpcmaps.h index fe5453bae61d..037754386f56 100644 --- a/js/src/xpconnect/src/xpcmaps.h +++ b/js/src/xpconnect/src/xpcmaps.h @@ -79,7 +79,7 @@ public: inline nsXPCWrappedJS* Add(nsXPCWrappedJS* wrapper) { NS_PRECONDITION(wrapper,"bad param"); - JSObject* obj = wrapper->GetJSObject(); + JSObject* obj = wrapper->GetJSObjectPreserveColor(); Entry* entry = (Entry*) JS_DHashTableOperate(mTable, obj, JS_DHASH_ADD); if(!entry) @@ -94,7 +94,8 @@ public: inline void Remove(nsXPCWrappedJS* wrapper) { NS_PRECONDITION(wrapper,"bad param"); - JS_DHashTableOperate(mTable, wrapper->GetJSObject(), JS_DHASH_REMOVE); + JS_DHashTableOperate(mTable, wrapper->GetJSObjectPreserveColor(), + JS_DHASH_REMOVE); } inline uint32 Count() {return mTable->entryCount;} diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index b26ce88e009a..2d957a3a793b 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -60,7 +60,6 @@ #include "jsdbgapi.h" #include "jsgc.h" #include "jscompartment.h" -#include "xpcpublic.h" #include "nscore.h" #include "nsXPCOM.h" #include "nsAutoPtr.h" @@ -488,9 +487,6 @@ private: **************************************************************************** ***************************************************************************/ -static const uint32 XPC_GC_COLOR_BLACK = 0; -static const uint32 XPC_GC_COLOR_GRAY = 1; - // We have a general rule internally that getters that return addref'd interface // pointer generally do so using an 'out' parm. When interface pointers are // returned as function call result values they are not addref'd. Exceptions @@ -2529,14 +2525,26 @@ public: nsISupports* GetIdentityObject() const {return mIdentity;} + /** + * This getter clears the gray bit before handing out the JSObject which + * means that the object is guaranteed to be kept alive past the next CC. + */ JSObject* - GetFlatJSObjectAndMark() const + GetFlatJSObject() const {if(mFlatJSObject && mFlatJSObject != INVALID_OBJECT) - mFlatJSObject->markIfUnmarked(); + mFlatJSObject->unmark(XPC_GC_COLOR_GRAY); return mFlatJSObject;} + /** + * This getter does not change the color of the JSObject meaning that the + * object returned is not guaranteed to be kept alive past the next CC. + * + * This should only be called if you are certain that the return value won't + * be passed into a JS API function and that it won't be stored without + * being rooted (or otherwise signaling the stored value to the CC). + */ JSObject* - GetFlatJSObjectNoMark() const {return mFlatJSObject;} + GetFlatJSObjectPreserveColor() const {return mFlatJSObject;} XPCLock* GetLock() const {return IsValid() && HasProto() ? @@ -2984,7 +2992,24 @@ public: nsXPCWrappedJS** wrapper); nsISomeInterface* GetXPTCStub() { return mXPTCStub; } - JSObject* GetJSObject() const {return mJSObj;} + + /** + * This getter clears the gray bit before handing out the JSObject which + * means that the object is guaranteed to be kept alive past the next CC. + */ + JSObject* GetJSObject() const {if(mJSObj) mJSObj->unmark(XPC_GC_COLOR_GRAY); + return mJSObj;} + + /** + * This getter does not change the color of the JSObject meaning that the + * object returned is not guaranteed to be kept alive past the next CC. + * + * This should only be called if you are certain that the return value won't + * be passed into a JS API function and that it won't be stored without + * being rooted (or otherwise signaling the stored value to the CC). + */ + JSObject* GetJSObjectPreserveColor() const {return mJSObj;} + nsXPCWrappedJSClass* GetClass() const {return mClass;} REFNSIID GetIID() const {return GetClass()->GetIID();} nsXPCWrappedJS* GetRootWrapper() const {return mRoot;} @@ -4306,10 +4331,25 @@ public: static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal); /** - * nsIVariant exposes a GetAsJSVal() method, which also returns mJSVal. - * But if you can, you should call this one, since it can be inlined. + * This getter clears the gray bit before handing out the jsval if the jsval + * represents a JSObject. That means that the object is guaranteed to be + * kept alive past the next CC. */ - jsval GetJSVal() const {return mJSVal;} + jsval GetJSVal() const + {if(JSVAL_IS_OBJECT(mJSVal)) + JSVAL_TO_OBJECT(mJSVal)->unmark(XPC_GC_COLOR_GRAY); + return mJSVal;} + + /** + * This getter does not change the color of the jsval (if it represents a + * JSObject) meaning that the value returned is not guaranteed to be kept + * alive past the next CC. + * + * This should only be called if you are certain that the return value won't + * be passed into a JS API function and that it won't be stored without + * being rooted (or otherwise signaling the stored value to the CC). + */ + jsval GetJSValPreserveColor() const {return mJSVal;} XPCVariant(XPCCallContext& ccx, jsval aJSVal); diff --git a/js/src/xpconnect/src/xpcpublic.h b/js/src/xpconnect/src/xpcpublic.h index 4f7c8c490600..d96b5984f885 100644 --- a/js/src/xpconnect/src/xpcpublic.h +++ b/js/src/xpconnect/src/xpcpublic.h @@ -48,6 +48,9 @@ #include "nsIPrincipal.h" #include "nsWrapperCache.h" +static const uint32 XPC_GC_COLOR_BLACK = 0; +static const uint32 XPC_GC_COLOR_GRAY = 1; + class nsIPrincipal; nsresult @@ -110,6 +113,16 @@ xpc_GetGlobalForObject(JSObject *obj) return obj; } +inline JSObject* +nsWrapperCache::GetWrapper() const +{ + JSObject* object = GetWrapperPreserveColor(); + if (object) { + object->unmark(XPC_GC_COLOR_GRAY); + } + return object; +} + inline JSObject* xpc_GetCachedSlimWrapper(nsWrapperCache *cache, JSObject *scope, jsval *vp) { diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index 29ad6d80869b..b463946985ed 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -796,8 +796,7 @@ getNativeFromWrapper(JSContext *cx, jsval *vp) { return getNative(wrapper->GetIdentityObject(), wrapper->GetOffsets(), - wrapper->GetFlatJSObjectAndMark(), iid, ppThis, pThisRef, - vp); + wrapper->GetFlatJSObject(), iid, ppThis, pThisRef, vp); } diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index 69b7beb7dff7..c2f89f225c72 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -581,7 +581,7 @@ castNativeFromWrapper(JSContext *cx, if(wrapper) { native = wrapper->GetIdentityObject(); - cur = wrapper->GetFlatJSObjectAndMark(); + cur = wrapper->GetFlatJSObject(); } else { diff --git a/js/src/xpconnect/src/xpcvariant.cpp b/js/src/xpconnect/src/xpcvariant.cpp index 890ddf26d15a..438b55f46093 100644 --- a/js/src/xpconnect/src/xpcvariant.cpp +++ b/js/src/xpconnect/src/xpcvariant.cpp @@ -81,22 +81,26 @@ XPCVariant::XPCVariant(XPCCallContext& ccx, jsval aJSVal) XPCTraceableVariant::~XPCTraceableVariant() { - NS_ASSERTION(JSVAL_IS_GCTHING(mJSVal), "Must be traceable or unlinked"); + jsval val = GetJSValPreserveColor(); - // If mJSVal is JSVAL_STRING, we don't need to clean anything up; - // simply removing the string from the root set is good. - if(!JSVAL_IS_STRING(mJSVal)) + NS_ASSERTION(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked"); + + // If val is JSVAL_STRING, we don't need to clean anything up; simply + // removing the string from the root set is good. + if(!JSVAL_IS_STRING(val)) nsVariant::Cleanup(&mData); - if (!JSVAL_IS_NULL(mJSVal)) + if (!JSVAL_IS_NULL(val)) RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock()); } void XPCTraceableVariant::TraceJS(JSTracer* trc) { - NS_ASSERTION(JSVAL_IS_TRACEABLE(mJSVal), "Must be traceable"); + jsval val = GetJSValPreserveColor(); + + NS_ASSERTION(JSVAL_IS_TRACEABLE(val), "Must be traceable"); JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0); - JS_CallTracer(trc, JSVAL_TO_TRACEABLE(mJSVal), JSVAL_TRACE_KIND(mJSVal)); + JS_CallTracer(trc, JSVAL_TO_TRACEABLE(val), JSVAL_TRACE_KIND(val)); } #ifdef DEBUG @@ -109,21 +113,24 @@ XPCTraceableVariant::PrintTraceName(JSTracer* trc, char *buf, size_t bufsize) #endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant) - if(JSVAL_IS_OBJECT(tmp->mJSVal)) + jsval val = tmp->GetJSValPreserveColor(); + if(JSVAL_IS_OBJECT(val)) cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, - JSVAL_TO_OBJECT(tmp->mJSVal)); + JSVAL_TO_OBJECT(val)); nsVariant::Traverse(tmp->mData, cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) - // We're sharing mJSVal's buffer, clear the pointer to it - // so Cleanup() won't try to delete it - if(JSVAL_IS_STRING(tmp->mJSVal)) + jsval val = tmp->GetJSValPreserveColor(); + + // We're sharing val's buffer, clear the pointer to it so Cleanup() won't + // try to delete it + if(JSVAL_IS_STRING(val)) tmp->mData.u.wstr.mWStringValue = nsnull; nsVariant::Cleanup(&tmp->mData); - if(JSVAL_IS_TRACEABLE(tmp->mJSVal)) + if(JSVAL_IS_TRACEABLE(val)) { XPCTraceableVariant *v = static_cast(tmp); v->RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock()); @@ -300,24 +307,25 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx) { JS_CHECK_RECURSION(ccx.GetJSContext(), return JS_FALSE); - if(JSVAL_IS_INT(mJSVal)) - return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, - JSVAL_TO_INT(mJSVal))); - if(JSVAL_IS_DOUBLE(mJSVal)) + jsval val = GetJSVal(); + + if(JSVAL_IS_INT(val)) + return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, JSVAL_TO_INT(val))); + if(JSVAL_IS_DOUBLE(val)) return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, - JSVAL_TO_DOUBLE(mJSVal))); - if(JSVAL_IS_BOOLEAN(mJSVal)) + JSVAL_TO_DOUBLE(val))); + if(JSVAL_IS_BOOLEAN(val)) return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, - JSVAL_TO_BOOLEAN(mJSVal))); - if(JSVAL_IS_VOID(mJSVal)) + JSVAL_TO_BOOLEAN(val))); + if(JSVAL_IS_VOID(val)) return NS_SUCCEEDED(nsVariant::SetToVoid(&mData)); - if(JSVAL_IS_NULL(mJSVal)) + if(JSVAL_IS_NULL(val)) return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData)); - if(JSVAL_IS_STRING(mJSVal)) + if(JSVAL_IS_STRING(val)) { // Make our string immutable. This will also ensure null-termination, // which nsVariant assumes for its PRUnichar* stuff. - JSString* str = JSVAL_TO_STRING(mJSVal); + JSString* str = JSVAL_TO_STRING(val); if(!JS_MakeStringImmutable(ccx, str)) return JS_FALSE; @@ -344,9 +352,9 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx) } // leaving only JSObject... - NS_ASSERTION(JSVAL_IS_OBJECT(mJSVal), "invalid type of jsval!"); + NS_ASSERTION(JSVAL_IS_OBJECT(val), "invalid type of jsval!"); - JSObject* jsobj = JSVAL_TO_OBJECT(mJSVal); + JSObject* jsobj = JSVAL_TO_OBJECT(val); // Let's see if it is a xpcJSID. @@ -374,7 +382,7 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx) return JS_FALSE; if(!XPCConvert::JSArray2Native(ccx, &mData.u.array.mArrayValue, - mJSVal, len, len, + val, len, len, type, type.IsPointer(), &id, nsnull)) return JS_FALSE; diff --git a/js/src/xpconnect/src/xpcwrappedjs.cpp b/js/src/xpconnect/src/xpcwrappedjs.cpp index 7b127ed9d8d8..d0a8d2d80f66 100644 --- a/js/src/xpconnect/src/xpcwrappedjs.cpp +++ b/js/src/xpconnect/src/xpcwrappedjs.cpp @@ -81,7 +81,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse // nsXPCWrappedJS roots its mJSObj when its refcount is > 1, see // the comment above nsXPCWrappedJS::AddRef. cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, - tmp->GetJSObject()); + tmp->GetJSObjectPreserveColor()); nsXPCWrappedJS* root = tmp->GetRootWrapper(); if(root == tmp) @@ -262,7 +262,7 @@ nsXPCWrappedJS::TraceJS(JSTracer* trc) { NS_ASSERTION(mRefCnt >= 2 && IsValid(), "must be strongly referenced"); JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0); - JS_CallTracer(trc, mJSObj, JSTRACE_OBJECT); + JS_CallTracer(trc, GetJSObjectPreserveColor(), JSTRACE_OBJECT); } #ifdef DEBUG @@ -290,9 +290,9 @@ NS_IMETHODIMP nsXPCWrappedJS::GetJSObject(JSObject** aJSObj) { NS_PRECONDITION(aJSObj, "bad param"); - NS_PRECONDITION(mJSObj, "bad wrapper"); + NS_PRECONDITION(IsValid(), "bad wrapper"); - if(!(*aJSObj = mJSObj)) + if(!(*aJSObj = GetJSObject())) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } @@ -627,7 +627,8 @@ nsXPCWrappedJS::GetEnumerator(nsISimpleEnumerator * *aEnumerate) if(!ccx.IsValid()) return NS_ERROR_UNEXPECTED; - return nsXPCWrappedJSClass::BuildPropertyEnumerator(ccx, mJSObj, aEnumerate); + return nsXPCWrappedJSClass::BuildPropertyEnumerator(ccx, GetJSObject(), + aEnumerate); } /* nsIVariant getProperty (in AString name); */ @@ -646,7 +647,7 @@ nsXPCWrappedJS::GetProperty(const nsAString & name, nsIVariant **_retval) buf->AddRef(); return nsXPCWrappedJSClass:: - GetNamedPropertyAsVariant(ccx, mJSObj, jsstr, _retval); + GetNamedPropertyAsVariant(ccx, GetJSObject(), jsstr, _retval); } /***************************************************************************/ diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index de7859ae93c2..3023622f3143 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -122,9 +122,8 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p, // for XPCWrappedNatives, described in a larger comment below and also // on our wiki at http://wiki.mozilla.org/XPConnect_object_wrapping - JSObject *obj = nsnull; - nsresult rv = tmp->GetJSObject(&obj); - if(NS_SUCCEEDED(rv)) + JSObject *obj = tmp->GetFlatJSObjectPreserveColor(); + if(obj) cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, obj); } @@ -334,7 +333,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, { nsWrapperCache *cache = helper.GetWrapperCache(); - NS_ASSERTION(!cache || !cache->GetWrapper(), + NS_ASSERTION(!cache || !cache->GetWrapperPreserveColor(), "We assume the caller already checked if it could get the " "wrapper from the cache."); @@ -397,7 +396,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx, } } #ifdef DEBUG - else if(!cache->GetWrapper()) + else if(!cache->GetWrapperPreserveColor()) { // scoped lock XPCAutoLock lock(mapLock); NS_ASSERTION(!map->Find(identity), @@ -675,13 +674,13 @@ FinishCreate(XPCCallContext& ccx, } else if(wrapper) { - JSObject *flat = wrapper->GetFlatJSObjectAndMark(); - NS_ASSERTION(!cache || !cache->GetWrapper() || - flat == cache->GetWrapper(), + JSObject *flat = wrapper->GetFlatJSObject(); + NS_ASSERTION(!cache || !cache->GetWrapperPreserveColor() || + flat == cache->GetWrapperPreserveColor(), "This object has a cached wrapper that's different from " "the JSObject held by its native wrapper?"); - if(cache && !cache->GetWrapper()) + if(cache && !cache->GetWrapperPreserveColor()) cache->SetWrapper(flat); // Our newly created wrapper is the one that we just added to the table. @@ -1511,7 +1510,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, if(NS_FAILED(rv)) return rv; - flat = wrapper->GetFlatJSObjectAndMark(); + flat = wrapper->GetFlatJSObject(); } if(!flat) @@ -3108,7 +3107,7 @@ CallMethodHelper::Invoke() /* readonly attribute JSObjectPtr JSObject; */ NS_IMETHODIMP XPCWrappedNative::GetJSObject(JSObject * *aJSObject) { - *aJSObject = GetFlatJSObjectAndMark(); + *aJSObject = GetFlatJSObject(); return NS_OK; } @@ -3126,7 +3125,7 @@ NS_IMETHODIMP XPCWrappedNative::GetNative(nsISupports * *aNative) NS_IMETHODIMP XPCWrappedNative::GetJSObjectPrototype(JSObject * *aJSObjectPrototype) { *aJSObjectPrototype = HasProto() ? - GetProto()->GetJSProtoObject() : GetFlatJSObjectAndMark(); + GetProto()->GetJSProtoObject() : GetFlatJSObject(); return NS_OK; } @@ -3210,7 +3209,7 @@ NS_IMETHODIMP XPCWrappedNative::RefreshPrototype() return UnexpectedFailure(NS_ERROR_FAILURE); JSAutoEnterCompartment ac; - if(!ac.enter(ccx, GetFlatJSObjectAndMark())) + if(!ac.enter(ccx, GetFlatJSObject())) return UnexpectedFailure(NS_ERROR_FAILURE); AutoMarkingWrappedNativeProtoPtr oldProto(ccx); @@ -3234,7 +3233,7 @@ NS_IMETHODIMP XPCWrappedNative::RefreshPrototype() if(newProto.get() == oldProto.get()) return NS_OK; - if(!JS_SetPrototype(ccx, GetFlatJSObjectAndMark(), + if(!JS_SetPrototype(ccx, GetFlatJSObject(), newProto->GetJSProtoObject())) return UnexpectedFailure(NS_ERROR_FAILURE); diff --git a/js/src/xpconnect/src/xpcwrappednativescope.cpp b/js/src/xpconnect/src/xpcwrappednativescope.cpp index 1c0c635d7cd9..1097ec9d9dfd 100644 --- a/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -363,7 +363,7 @@ WrappedNativeJSGCThingTracer(JSDHashTable *table, JSDHashEntryHdr *hdr, if(wrapper->HasExternalReference() && !wrapper->IsWrapperExpired()) { JSTracer* trc = (JSTracer *)arg; - JS_CALL_OBJECT_TRACER(trc, wrapper->GetFlatJSObjectNoMark(), + JS_CALL_OBJECT_TRACER(trc, wrapper->GetFlatJSObjectPreserveColor(), "XPCWrappedNative::mFlatJSObject"); } diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index 0eff426cfc46..d8000a058b06 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -56,6 +56,7 @@ #include "nsIDOMElement.h" #include "prmem.h" #include "nsIContent.h" +#include "xpcpublic.h" using namespace mozilla::plugins::parent;