Bug 614347 - 'XPConnect-wrapped JSObjects must clear their gray bit when they are handed out'. r=peterv+gal, a=blocking.

This commit is contained in:
Ben Turner 2011-02-16 12:47:08 -08:00
Родитель c3973a7246
Коммит 348158b35c
26 изменённых файлов: 315 добавлений и 140 удалений

Просмотреть файл

@ -1280,7 +1280,8 @@ public:
void *aClosure) void *aClosure)
{ {
if (aCache->PreservingWrapper()) { if (aCache->PreservingWrapper()) {
aCallback(nsIProgrammingLanguage::JAVASCRIPT, aCache->GetWrapper(), aCallback(nsIProgrammingLanguage::JAVASCRIPT,
aCache->GetWrapperPreserveColor(),
aClosure); aClosure);
} }
} }

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIXPConnect.h" #include "nsIXPConnect.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "xpcpublic.h"
nsresult nsresult
NS_NewDOMDocumentType(nsIDOMDocumentType** aDocType, NS_NewDOMDocumentType(nsIDOMDocumentType** aDocType,

Просмотреть файл

@ -3802,7 +3802,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
if (!mWillReparent) { if (!mWillReparent) {
// We really shouldn't have a wrapper here but if we do we need to make sure // We really shouldn't have a wrapper here but if we do we need to make sure
// it has the correct parent. // it has the correct parent.
JSObject *obj = GetWrapper(); JSObject *obj = GetWrapperPreserveColor();
if (obj) { if (obj) {
JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject(); JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject();
nsIScriptContext *scx = aScriptGlobalObject->GetContext(); nsIScriptContext *scx = aScriptGlobalObject->GetContext();

Просмотреть файл

@ -71,6 +71,7 @@
#include "nsIRunnable.h" #include "nsIRunnable.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsDOMEventTargetWrapperCache.h" #include "nsDOMEventTargetWrapperCache.h"
#include "xpcpublic.h"
// General helper includes // General helper includes
#include "nsGlobalWindow.h" #include "nsGlobalWindow.h"
@ -4246,6 +4247,31 @@ nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsid id, PRBool *aIsNumber)
return i; 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 NS_IMETHODIMP
nsDOMClassInfo::GetInterfaces(PRUint32 *aCount, nsIID ***aArray) nsDOMClassInfo::GetInterfaces(PRUint32 *aCount, nsIID ***aArray)
{ {

Просмотреть файл

@ -48,7 +48,6 @@
#include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "xpcpublic.h"
class nsIDOMWindow; class nsIDOMWindow;
class nsIDOMNSHTMLOptionCollection; class nsIDOMNSHTMLOptionCollection;
@ -249,28 +248,11 @@ protected:
id == sName_id); id == sName_id);
} }
static nsresult WrapNative(JSContext *cx, JSObject *scope, inline static nsresult WrapNative(JSContext *cx, JSObject *scope,
nsISupports *native, nsWrapperCache *cache, nsISupports *native, nsWrapperCache *cache,
const nsIID* aIID, jsval *vp, const nsIID* aIID, jsval *vp,
nsIXPConnectJSObjectHolder** aHolder, nsIXPConnectJSObjectHolder** aHolder,
PRBool aAllowWrapping) 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);
}
static nsIXPConnect *sXPConnect; static nsIXPConnect *sXPConnect;
static nsIScriptSecurityManager *sSecMan; static nsIScriptSecurityManager *sSecMan;

Просмотреть файл

@ -85,6 +85,7 @@
#include "nsIXULRuntime.h" #include "nsIXULRuntime.h"
#include "nsDOMClassInfo.h" #include "nsDOMClassInfo.h"
#include "xpcpublic.h"
#include "jsdbgapi.h" // for JS_ClearWatchPointsForObject #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
#include "jsxdrapi.h" #include "jsxdrapi.h"

Просмотреть файл

@ -42,6 +42,7 @@
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
struct JSObject; struct JSObject;
class nsContentUtils;
typedef PRUptrdiff PtrBits; typedef PRUptrdiff PtrBits;
@ -58,6 +59,8 @@ typedef PRUptrdiff PtrBits;
*/ */
class nsWrapperCache class nsWrapperCache
{ {
friend class nsContentUtils;
public: public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID)
@ -70,7 +73,25 @@ public:
"Destroying cache with a preserved wrapper!"); "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<JSObject*>(mWrapperPtrBits & ~kWrapperBitMask); return reinterpret_cast<JSObject*>(mWrapperPtrBits & ~kWrapperBitMask);
} }
@ -88,6 +109,23 @@ public:
mWrapperPtrBits = 0; 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) void SetPreservingWrapper(PRBool aPreserve)
{ {
if(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_BIT_PRESERVED = 1 << 0 };
enum { WRAPPER_IS_PROXY = 1 << 1 }; enum { WRAPPER_IS_PROXY = 1 << 1 };
enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_PROXY) }; enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_PROXY) };

Просмотреть файл

@ -71,6 +71,7 @@ struct Cell {
JS_ALWAYS_INLINE bool isMarked(uint32 color) const; JS_ALWAYS_INLINE bool isMarked(uint32 color) const;
JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color) const; JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color) const;
JS_ALWAYS_INLINE void unmark(uint32 color) const;
inline JSCompartment *compartment() const; inline JSCompartment *compartment() const;

Просмотреть файл

@ -505,7 +505,7 @@ IsAboutToBeFinalized(JSContext *cx, void *thing)
} }
JS_FRIEND_API(bool) JS_FRIEND_API(bool)
js_GCThingIsMarked(void *thing, uint32 color = BLACK) js_GCThingIsMarked(void *thing, uintN color = BLACK)
{ {
JS_ASSERT(thing); JS_ASSERT(thing);
AssertValidColor(thing, color); AssertValidColor(thing, color);

Просмотреть файл

@ -213,6 +213,13 @@ struct ArenaBitmap {
return true; 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 #ifdef DEBUG
bool noBitsSet() { bool noBitsSet() {
for (unsigned i = 0; i < BitWords; i++) { for (unsigned i = 0; i < BitWords; i++) {
@ -461,6 +468,14 @@ Cell::markIfUnmarked(uint32 color = BLACK) const
return bitmap()->markIfUnmarked(cellIndex(), color); return bitmap()->markIfUnmarked(cellIndex(), color);
} }
void
Cell::unmark(uint32 color) const
{
JS_ASSERT(color != BLACK);
AssertValidColor(this, color);
bitmap()->unmark(cellIndex(), color);
}
JSCompartment * JSCompartment *
Cell::compartment() const Cell::compartment() const
{ {
@ -800,7 +815,7 @@ extern JS_FRIEND_API(bool)
IsAboutToBeFinalized(JSContext *cx, void *thing); IsAboutToBeFinalized(JSContext *cx, void *thing);
extern JS_FRIEND_API(bool) extern JS_FRIEND_API(bool)
js_GCThingIsMarked(void *thing, uint32 color); js_GCThingIsMarked(void *thing, uintN color);
extern void extern void
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp); js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp);

Просмотреть файл

@ -55,7 +55,8 @@
#include "jspubtd.h" #include "jspubtd.h"
#include "xptinfo.h" #include "xptinfo.h"
#include "nsAXPCNativeCallContext.h" #include "nsAXPCNativeCallContext.h"
#include "nsWrapperCache.h"
class nsWrapperCache;
%} %}
/***************************************************************************/ /***************************************************************************/

Просмотреть файл

@ -49,6 +49,7 @@
#include "jsatom.h" #include "jsatom.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsfun.h" #include "jsfun.h"
#include "jsgc.h"
#include "jsscript.h" #include "jsscript.h"
#include "nsThreadUtilsInternal.h" #include "nsThreadUtilsInternal.h"
#include "dom_quickstubs.h" #include "dom_quickstubs.h"
@ -558,6 +559,43 @@ nsXPConnect::Unroot(void *p)
return NS_OK; return NS_OK;
} }
static void
UnmarkGrayChildren(JSTracer *trc, void *thing, uint32 kind)
{
// If this thing is not a CC-kind or already non-gray then we're done.
if(!ADD_TO_CC(kind) || !xpc_IsGrayGCThing(thing))
return;
// Unmark.
static_cast<js::gc::Cell *>(thing)->unmark(XPC_GC_COLOR_GRAY);
// Trace children.
JS_TraceChildren(trc, thing, kind);
}
void
xpc_UnmarkGrayObjectRecursive(JSObject *obj)
{
NS_ASSERTION(obj, "Don't pass me null!");
// Unmark.
obj->unmark(XPC_GC_COLOR_GRAY);
// Tracing requires a JSContext...
JSContext *cx;
nsXPConnect* xpc = nsXPConnect::GetXPConnect();
if(!xpc || NS_FAILED(xpc->GetSafeJSContext(&cx)) || !cx)
{
NS_ERROR("Failed to get safe JSContext!");
return;
}
// Trace children.
JSTracer trc;
JS_TRACER_INIT(&trc, cx, UnmarkGrayChildren);
JS_TraceChildren(&trc, obj, JSTRACE_OBJECT);
}
struct TraversalTracer : public JSTracer struct TraversalTracer : public JSTracer
{ {
TraversalTracer(nsCycleCollectionTraversalCallback &aCb) : cb(aCb) TraversalTracer(nsCycleCollectionTraversalCallback &aCb) : cb(aCb)
@ -572,6 +610,12 @@ NoteJSChild(JSTracer *trc, void *thing, uint32 kind)
if(ADD_TO_CC(kind)) if(ADD_TO_CC(kind))
{ {
TraversalTracer *tracer = static_cast<TraversalTracer*>(trc); TraversalTracer *tracer = static_cast<TraversalTracer*>(trc);
// There's no point in further traversing a non-gray object here unless
// we explicitly want to see all traces.
if(!xpc_IsGrayGCThing(thing) && !tracer->cb.WantAllTraces())
return;
#if defined(DEBUG) #if defined(DEBUG)
if (NS_UNLIKELY(tracer->cb.WantDebugInfo())) { if (NS_UNLIKELY(tracer->cb.WantDebugInfo())) {
// based on DumpNotify in jsapi.c // based on DumpNotify in jsapi.c
@ -613,12 +657,6 @@ WrapperIsNotMainThreadOnly(XPCWrappedNative *wrapper)
return NS_FAILED(CallQueryInterface(wrapper->Native(), &participant)); return NS_FAILED(CallQueryInterface(wrapper->Native(), &participant));
} }
JSBool
nsXPConnect::IsGray(void *thing)
{
return js_GCThingIsMarked(thing, XPC_GC_COLOR_GRAY);
}
NS_IMETHODIMP NS_IMETHODIMP
nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
{ {
@ -680,7 +718,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
#endif #endif
{ {
// Normal codepath (matches non-DEBUG_CC codepath). // Normal codepath (matches non-DEBUG_CC codepath).
type = !markJSObject && IsGray(p) ? GCUnmarked : GCMarked; type = !markJSObject && xpc_IsGrayGCThing(p) ? GCUnmarked : GCMarked;
} }
if (cb.WantDebugInfo()) { if (cb.WantDebugInfo()) {
@ -775,7 +813,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
if(traceKind != JSTRACE_OBJECT || dontTraverse) if(traceKind != JSTRACE_OBJECT || dontTraverse)
return NS_OK; return NS_OK;
if(clazz == &XPC_WN_Tearoff_JSClass) if(clazz == &XPC_WN_Tearoff_JSClass)
{ {
// A tearoff holds a strong reference to its native object // A tearoff holds a strong reference to its native object
@ -1594,7 +1632,7 @@ MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
newParent = parentWrapper->GetFlatJSObjectNoMark(); newParent = parentWrapper->GetFlatJSObject();
} }
else else
NS_ASSERTION(betterScope == newScope, "Weird scope returned"); NS_ASSERTION(betterScope == newScope, "Weird scope returned");

Просмотреть файл

@ -198,7 +198,7 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage,
{ {
DEBUG_CheckWrapperThreadSafety(mWrapper); DEBUG_CheckWrapperThreadSafety(mWrapper);
mFlattenedJSObject = mWrapper->GetFlatJSObjectAndMark(); mFlattenedJSObject = mWrapper->GetFlatJSObject();
if(mTearOff) if(mTearOff)
mScriptableInfo = nsnull; mScriptableInfo = nsnull;

Просмотреть файл

@ -1310,7 +1310,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
// If we're not creating security wrappers, we can return the // If we're not creating security wrappers, we can return the
// XPCWrappedNative as-is here. // XPCWrappedNative as-is here.
flat = wrapper->GetFlatJSObjectAndMark(); flat = wrapper->GetFlatJSObject();
jsval v = OBJECT_TO_JSVAL(flat); jsval v = OBJECT_TO_JSVAL(flat);
if(!XPCPerThreadData::IsMainThread(lccx.GetJSContext()) || if(!XPCPerThreadData::IsMainThread(lccx.GetJSContext()) ||
!allowNativeWrapper) !allowNativeWrapper)

Просмотреть файл

@ -791,7 +791,7 @@ XPCLazyCallContext::SetWrapper(XPCWrappedNative* wrapper,
if(mTearOff) if(mTearOff)
mFlattenedJSObject = mTearOff->GetJSObject(); mFlattenedJSObject = mTearOff->GetJSObject();
else else
mFlattenedJSObject = mWrapper->GetFlatJSObjectAndMark(); mFlattenedJSObject = mWrapper->GetFlatJSObject();
} }
inline void inline void
XPCLazyCallContext::SetWrapper(JSObject* flattenedJSObject) XPCLazyCallContext::SetWrapper(JSObject* flattenedJSObject)

Просмотреть файл

@ -94,8 +94,10 @@ WrappedJSDyingJSObjectFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
{ {
if(wrapper->IsSubjectToFinalization()) if(wrapper->IsSubjectToFinalization())
{ {
js::SwitchToCompartment sc(data->cx, wrapper->GetJSObject()); js::SwitchToCompartment sc(data->cx,
if(JS_IsAboutToBeFinalized(data->cx, wrapper->GetJSObject())) wrapper->GetJSObjectPreserveColor());
if(JS_IsAboutToBeFinalized(data->cx,
wrapper->GetJSObjectPreserveColor()))
data->array->AppendElement(wrapper); data->array->AppendElement(wrapper);
} }
wrapper = wrapper->GetNextWrapper(); wrapper = wrapper->GetNextWrapper();
@ -503,16 +505,13 @@ XPCJSRuntime::SuspectWrappedNative(JSContext *cx, XPCWrappedNative *wrapper,
// Only suspect wrappedJSObjects that are in a compartment that // Only suspect wrappedJSObjects that are in a compartment that
// participates in cycle collection. // participates in cycle collection.
JSObject* obj = wrapper->GetFlatJSObjectAndMark(); JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
if(!xpc::ParticipatesInCycleCollection(cx, obj)) if(!xpc::ParticipatesInCycleCollection(cx, obj))
return; 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 // Only record objects that might be part of a cycle as roots, unless
// the callback wants all traces (a debug feature). // the callback wants all traces (a debug feature).
if(nsXPConnect::IsGray(obj) || cb.WantAllTraces()) if(xpc_IsGrayGCThing(obj) || cb.WantAllTraces())
cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, obj, cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, obj,
nsXPConnect::GetXPConnect()); nsXPConnect::GetXPConnect());
} }
@ -572,7 +571,7 @@ XPCJSRuntime::AddXPConnectRoots(JSContext* cx,
for(XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) for(XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
{ {
nsXPCWrappedJS *wrappedJS = static_cast<nsXPCWrappedJS*>(e); nsXPCWrappedJS *wrappedJS = static_cast<nsXPCWrappedJS*>(e);
JSObject *obj = wrappedJS->GetJSObject(); JSObject *obj = wrappedJS->GetJSObjectPreserveColor();
// Only suspect wrappedJSObjects that are in a compartment that // Only suspect wrappedJSObjects that are in a compartment that
// participates in cycle collection. // participates in cycle collection.
@ -640,7 +639,7 @@ static PLDHashOperator
SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg) SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg)
{ {
JSContext *cx = (JSContext *)arg; JSContext *cx = (JSContext *)arg;
return IsAboutToBeFinalized(cx, wn->GetFlatJSObjectNoMark()) return IsAboutToBeFinalized(cx, wn->GetFlatJSObjectPreserveColor())
? PL_DHASH_REMOVE ? PL_DHASH_REMOVE
: PL_DHASH_NEXT; : PL_DHASH_NEXT;
} }

Просмотреть файл

@ -79,7 +79,7 @@ public:
inline nsXPCWrappedJS* Add(nsXPCWrappedJS* wrapper) inline nsXPCWrappedJS* Add(nsXPCWrappedJS* wrapper)
{ {
NS_PRECONDITION(wrapper,"bad param"); NS_PRECONDITION(wrapper,"bad param");
JSObject* obj = wrapper->GetJSObject(); JSObject* obj = wrapper->GetJSObjectPreserveColor();
Entry* entry = (Entry*) Entry* entry = (Entry*)
JS_DHashTableOperate(mTable, obj, JS_DHASH_ADD); JS_DHashTableOperate(mTable, obj, JS_DHASH_ADD);
if(!entry) if(!entry)
@ -94,7 +94,8 @@ public:
inline void Remove(nsXPCWrappedJS* wrapper) inline void Remove(nsXPCWrappedJS* wrapper)
{ {
NS_PRECONDITION(wrapper,"bad param"); 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;} inline uint32 Count() {return mTable->entryCount;}

Просмотреть файл

@ -60,7 +60,6 @@
#include "jsdbgapi.h" #include "jsdbgapi.h"
#include "jsgc.h" #include "jsgc.h"
#include "jscompartment.h" #include "jscompartment.h"
#include "xpcpublic.h"
#include "nscore.h" #include "nscore.h"
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
@ -489,9 +488,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 // 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 // pointer generally do so using an 'out' parm. When interface pointers are
// returned as function call result values they are not addref'd. Exceptions // returned as function call result values they are not addref'd. Exceptions
@ -557,11 +553,6 @@ public:
JSBool IsShuttingDown() const {return mShuttingDown;} JSBool IsShuttingDown() const {return mShuttingDown;}
// The JS GC marks objects gray that are held alive directly or indirectly
// by an XPConnect root. The cycle collector explores only this subset
// of the JS heap.
static JSBool IsGray(void *thing);
nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info); nsresult GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info);
nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info); nsresult GetInfoForName(const char * name, nsIInterfaceInfo** info);
@ -2550,14 +2541,26 @@ public:
nsISupports* nsISupports*
GetIdentityObject() const {return mIdentity;} 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* JSObject*
GetFlatJSObjectAndMark() const GetFlatJSObject() const
{if(mFlatJSObject && mFlatJSObject != INVALID_OBJECT) {if(mFlatJSObject != INVALID_OBJECT)
mFlatJSObject->markIfUnmarked(); xpc_UnmarkGrayObject(mFlatJSObject);
return mFlatJSObject;} 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* JSObject*
GetFlatJSObjectNoMark() const {return mFlatJSObject;} GetFlatJSObjectPreserveColor() const {return mFlatJSObject;}
XPCLock* XPCLock*
GetLock() const {return IsValid() && HasProto() ? GetLock() const {return IsValid() && HasProto() ?
@ -2695,7 +2698,7 @@ public:
if(mScriptableInfo && JS_IsGCMarkingTracer(trc)) if(mScriptableInfo && JS_IsGCMarkingTracer(trc))
mScriptableInfo->Mark(); mScriptableInfo->Mark();
if(HasProto()) GetProto()->TraceJS(trc); if(HasProto()) GetProto()->TraceJS(trc);
JSObject* wrapper = GetWrapper(); JSObject* wrapper = GetWrapperPreserveColor();
if(wrapper) if(wrapper)
JS_CALL_OBJECT_TRACER(trc, wrapper, "XPCWrappedNative::mWrapper"); JS_CALL_OBJECT_TRACER(trc, wrapper, "XPCWrappedNative::mWrapper");
} }
@ -2741,9 +2744,19 @@ public:
JSBool NeedsCOW() { return !!(mWrapperWord & NEEDS_COW); } JSBool NeedsCOW() { return !!(mWrapperWord & NEEDS_COW); }
void SetNeedsCOW() { mWrapperWord |= NEEDS_COW; } void SetNeedsCOW() { mWrapperWord |= NEEDS_COW; }
JSObject* GetWrapperPreserveColor() const
{return (JSObject*)(mWrapperWord & (size_t)~(size_t)FLAG_MASK);}
JSObject* GetWrapper() JSObject* GetWrapper()
{ {
return (JSObject *) (mWrapperWord & (size_t)~(size_t)FLAG_MASK); JSObject* wrapper = GetWrapperPreserveColor();
if(wrapper)
{
xpc_UnmarkGrayObject(wrapper);
// Call this to unmark mFlatJSObject.
GetFlatJSObject();
}
return wrapper;
} }
void SetWrapper(JSObject *obj) void SetWrapper(JSObject *obj)
{ {
@ -3005,7 +3018,24 @@ public:
nsXPCWrappedJS** wrapper); nsXPCWrappedJS** wrapper);
nsISomeInterface* GetXPTCStub() { return mXPTCStub; } 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 {xpc_UnmarkGrayObject(mJSObj);
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;} nsXPCWrappedJSClass* GetClass() const {return mClass;}
REFNSIID GetIID() const {return GetClass()->GetIID();} REFNSIID GetIID() const {return GetClass()->GetIID();}
nsXPCWrappedJS* GetRootWrapper() const {return mRoot;} nsXPCWrappedJS* GetRootWrapper() const {return mRoot;}
@ -4321,10 +4351,25 @@ public:
static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal); static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal);
/** /**
* nsIVariant exposes a GetAsJSVal() method, which also returns mJSVal. * This getter clears the gray bit before handing out the jsval if the jsval
* But if you can, you should call this one, since it can be inlined. * 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_PRIMITIVE(mJSVal))
xpc_UnmarkGrayObject(JSVAL_TO_OBJECT(mJSVal));
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); XPCVariant(XPCCallContext& ccx, jsval aJSVal);
@ -4515,7 +4560,9 @@ struct CompartmentPrivate
JSObject *LookupExpandoObject(XPCWrappedNative *wn) { JSObject *LookupExpandoObject(XPCWrappedNative *wn) {
if (!expandoMap) if (!expandoMap)
return nsnull; return nsnull;
return expandoMap->Get(wn); JSObject *obj = expandoMap->Get(wn);
xpc_UnmarkGrayObject(obj);
return obj;
} }
}; };

Просмотреть файл

@ -50,6 +50,9 @@
class nsIPrincipal; class nsIPrincipal;
static const uint32 XPC_GC_COLOR_BLACK = 0;
static const uint32 XPC_GC_COLOR_GRAY = 1;
nsresult nsresult
xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp, xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
nsIPrincipal *principal, nsISupports *ptr, nsIPrincipal *principal, nsISupports *ptr,
@ -136,4 +139,34 @@ xpc_GetCachedSlimWrapper(nsWrapperCache *cache, JSObject *scope)
return xpc_GetCachedSlimWrapper(cache, scope, &dummy); return xpc_GetCachedSlimWrapper(cache, scope, &dummy);
} }
// The JS GC marks objects gray that are held alive directly or indirectly
// by an XPConnect root. The cycle collector explores only this subset
// of the JS heap.
inline JSBool
xpc_IsGrayGCThing(void *thing)
{
return js_GCThingIsMarked(thing, XPC_GC_COLOR_GRAY);
}
// Implemented in nsXPConnect.cpp.
extern void
xpc_UnmarkGrayObjectRecursive(JSObject* obj);
// Remove the gray color from the given JSObject and any other objects that can
// be reached through it.
inline void
xpc_UnmarkGrayObject(JSObject *obj)
{
if(obj && xpc_IsGrayGCThing(obj))
xpc_UnmarkGrayObjectRecursive(obj);
}
inline JSObject*
nsWrapperCache::GetWrapper() const
{
JSObject* obj = GetWrapperPreserveColor();
xpc_UnmarkGrayObject(obj);
return obj;
}
#endif #endif

Просмотреть файл

@ -816,8 +816,7 @@ getNativeFromWrapper(JSContext *cx,
jsval *vp) jsval *vp)
{ {
return getNative(wrapper->GetIdentityObject(), wrapper->GetOffsets(), return getNative(wrapper->GetIdentityObject(), wrapper->GetOffsets(),
wrapper->GetFlatJSObjectAndMark(), iid, ppThis, pThisRef, wrapper->GetFlatJSObject(), iid, ppThis, pThisRef, vp);
vp);
} }

Просмотреть файл

@ -581,7 +581,7 @@ castNativeFromWrapper(JSContext *cx,
if(wrapper) if(wrapper)
{ {
native = wrapper->GetIdentityObject(); native = wrapper->GetIdentityObject();
cur = wrapper->GetFlatJSObjectAndMark(); cur = wrapper->GetFlatJSObject();
} }
else else
{ {

Просмотреть файл

@ -81,22 +81,26 @@ XPCVariant::XPCVariant(XPCCallContext& ccx, jsval aJSVal)
XPCTraceableVariant::~XPCTraceableVariant() 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; NS_ASSERTION(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked");
// simply removing the string from the root set is good.
if(!JSVAL_IS_STRING(mJSVal)) // 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); nsVariant::Cleanup(&mData);
if (!JSVAL_IS_NULL(mJSVal)) if (!JSVAL_IS_NULL(val))
RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock()); RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
} }
void XPCTraceableVariant::TraceJS(JSTracer* trc) 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_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 #ifdef DEBUG
@ -109,21 +113,24 @@ XPCTraceableVariant::PrintTraceName(JSTracer* trc, char *buf, size_t bufsize)
#endif #endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant) 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, cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
JSVAL_TO_OBJECT(tmp->mJSVal)); JSVAL_TO_OBJECT(val));
nsVariant::Traverse(tmp->mData, cb); nsVariant::Traverse(tmp->mData, cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
// We're sharing mJSVal's buffer, clear the pointer to it jsval val = tmp->GetJSValPreserveColor();
// so Cleanup() won't try to delete it
if(JSVAL_IS_STRING(tmp->mJSVal)) // 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; tmp->mData.u.wstr.mWStringValue = nsnull;
nsVariant::Cleanup(&tmp->mData); nsVariant::Cleanup(&tmp->mData);
if(JSVAL_IS_TRACEABLE(tmp->mJSVal)) if(JSVAL_IS_TRACEABLE(val))
{ {
XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp); XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp);
v->RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock()); v->RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetMapLock());
@ -300,24 +307,25 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
{ {
JS_CHECK_RECURSION(ccx.GetJSContext(), return JS_FALSE); JS_CHECK_RECURSION(ccx.GetJSContext(), return JS_FALSE);
if(JSVAL_IS_INT(mJSVal)) jsval val = GetJSVal();
return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData,
JSVAL_TO_INT(mJSVal))); if(JSVAL_IS_INT(val))
if(JSVAL_IS_DOUBLE(mJSVal)) return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, JSVAL_TO_INT(val)));
if(JSVAL_IS_DOUBLE(val))
return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData,
JSVAL_TO_DOUBLE(mJSVal))); JSVAL_TO_DOUBLE(val)));
if(JSVAL_IS_BOOLEAN(mJSVal)) if(JSVAL_IS_BOOLEAN(val))
return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, return NS_SUCCEEDED(nsVariant::SetFromBool(&mData,
JSVAL_TO_BOOLEAN(mJSVal))); JSVAL_TO_BOOLEAN(val)));
if(JSVAL_IS_VOID(mJSVal)) if(JSVAL_IS_VOID(val))
return NS_SUCCEEDED(nsVariant::SetToVoid(&mData)); return NS_SUCCEEDED(nsVariant::SetToVoid(&mData));
if(JSVAL_IS_NULL(mJSVal)) if(JSVAL_IS_NULL(val))
return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData)); 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, // Make our string immutable. This will also ensure null-termination,
// which nsVariant assumes for its PRUnichar* stuff. // which nsVariant assumes for its PRUnichar* stuff.
JSString* str = JSVAL_TO_STRING(mJSVal); JSString* str = JSVAL_TO_STRING(val);
if(!JS_MakeStringImmutable(ccx, str)) if(!JS_MakeStringImmutable(ccx, str))
return JS_FALSE; return JS_FALSE;
@ -344,9 +352,9 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
} }
// leaving only JSObject... // 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. // Let's see if it is a xpcJSID.
@ -374,7 +382,7 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
return JS_FALSE; return JS_FALSE;
if(!XPCConvert::JSArray2Native(ccx, &mData.u.array.mArrayValue, if(!XPCConvert::JSArray2Native(ccx, &mData.u.array.mArrayValue,
mJSVal, len, len, val, len, len,
type, type.IsPointer(), type, type.IsPointer(),
&id, nsnull)) &id, nsnull))
return JS_FALSE; return JS_FALSE;

Просмотреть файл

@ -81,7 +81,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
// nsXPCWrappedJS roots its mJSObj when its refcount is > 1, see // nsXPCWrappedJS roots its mJSObj when its refcount is > 1, see
// the comment above nsXPCWrappedJS::AddRef. // the comment above nsXPCWrappedJS::AddRef.
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
tmp->GetJSObject()); tmp->GetJSObjectPreserveColor());
nsXPCWrappedJS* root = tmp->GetRootWrapper(); nsXPCWrappedJS* root = tmp->GetRootWrapper();
if(root == tmp) if(root == tmp)
@ -262,7 +262,7 @@ nsXPCWrappedJS::TraceJS(JSTracer* trc)
{ {
NS_ASSERTION(mRefCnt >= 2 && IsValid(), "must be strongly referenced"); NS_ASSERTION(mRefCnt >= 2 && IsValid(), "must be strongly referenced");
JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0); JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0);
JS_CallTracer(trc, mJSObj, JSTRACE_OBJECT); JS_CallTracer(trc, GetJSObjectPreserveColor(), JSTRACE_OBJECT);
} }
#ifdef DEBUG #ifdef DEBUG
@ -290,9 +290,9 @@ NS_IMETHODIMP
nsXPCWrappedJS::GetJSObject(JSObject** aJSObj) nsXPCWrappedJS::GetJSObject(JSObject** aJSObj)
{ {
NS_PRECONDITION(aJSObj, "bad param"); 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_ERROR_OUT_OF_MEMORY;
return NS_OK; return NS_OK;
} }
@ -627,7 +627,8 @@ nsXPCWrappedJS::GetEnumerator(nsISimpleEnumerator * *aEnumerate)
if(!ccx.IsValid()) if(!ccx.IsValid())
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
return nsXPCWrappedJSClass::BuildPropertyEnumerator(ccx, mJSObj, aEnumerate); return nsXPCWrappedJSClass::BuildPropertyEnumerator(ccx, GetJSObject(),
aEnumerate);
} }
/* nsIVariant getProperty (in AString name); */ /* nsIVariant getProperty (in AString name); */
@ -646,7 +647,7 @@ nsXPCWrappedJS::GetProperty(const nsAString & name, nsIVariant **_retval)
buf->AddRef(); buf->AddRef();
return nsXPCWrappedJSClass:: return nsXPCWrappedJSClass::
GetNamedPropertyAsVariant(ccx, mJSObj, jsstr, _retval); GetNamedPropertyAsVariant(ccx, GetJSObject(), jsstr, _retval);
} }
/***************************************************************************/ /***************************************************************************/

Просмотреть файл

@ -122,10 +122,8 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
// for XPCWrappedNatives, described in a larger comment below and also // for XPCWrappedNatives, described in a larger comment below and also
// on our wiki at http://wiki.mozilla.org/XPConnect_object_wrapping // on our wiki at http://wiki.mozilla.org/XPConnect_object_wrapping
JSObject *obj = nsnull; JSObject *obj = tmp->GetFlatJSObjectPreserveColor();
nsresult rv = tmp->GetJSObject(&obj); cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, obj);
if(NS_SUCCEEDED(rv))
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, obj);
} }
XPCJSRuntime *rt = tmp->GetRuntime(); XPCJSRuntime *rt = tmp->GetRuntime();
@ -334,7 +332,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
{ {
nsWrapperCache *cache = helper.GetWrapperCache(); 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 " "We assume the caller already checked if it could get the "
"wrapper from the cache."); "wrapper from the cache.");
@ -397,7 +395,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
} }
} }
#ifdef DEBUG #ifdef DEBUG
else if(!cache->GetWrapper()) else if(!cache->GetWrapperPreserveColor())
{ // scoped lock { // scoped lock
XPCAutoLock lock(mapLock); XPCAutoLock lock(mapLock);
NS_ASSERTION(!map->Find(identity), NS_ASSERTION(!map->Find(identity),
@ -675,13 +673,13 @@ FinishCreate(XPCCallContext& ccx,
} }
else if(wrapper) else if(wrapper)
{ {
JSObject *flat = wrapper->GetFlatJSObjectAndMark(); JSObject *flat = wrapper->GetFlatJSObject();
NS_ASSERTION(!cache || !cache->GetWrapper() || NS_ASSERTION(!cache || !cache->GetWrapperPreserveColor() ||
flat == cache->GetWrapper(), flat == cache->GetWrapperPreserveColor(),
"This object has a cached wrapper that's different from " "This object has a cached wrapper that's different from "
"the JSObject held by its native wrapper?"); "the JSObject held by its native wrapper?");
if(cache && !cache->GetWrapper()) if(cache && !cache->GetWrapperPreserveColor())
cache->SetWrapper(flat); cache->SetWrapper(flat);
// Our newly created wrapper is the one that we just added to the table. // Our newly created wrapper is the one that we just added to the table.
@ -1511,7 +1509,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
if(NS_FAILED(rv)) if(NS_FAILED(rv))
return rv; return rv;
flat = wrapper->GetFlatJSObjectAndMark(); flat = wrapper->GetFlatJSObject();
} }
if(!flat) if(!flat)
@ -3106,7 +3104,7 @@ CallMethodHelper::Invoke()
/* readonly attribute JSObjectPtr JSObject; */ /* readonly attribute JSObjectPtr JSObject; */
NS_IMETHODIMP XPCWrappedNative::GetJSObject(JSObject * *aJSObject) NS_IMETHODIMP XPCWrappedNative::GetJSObject(JSObject * *aJSObject)
{ {
*aJSObject = GetFlatJSObjectAndMark(); *aJSObject = GetFlatJSObject();
return NS_OK; return NS_OK;
} }
@ -3124,7 +3122,7 @@ NS_IMETHODIMP XPCWrappedNative::GetNative(nsISupports * *aNative)
NS_IMETHODIMP XPCWrappedNative::GetJSObjectPrototype(JSObject * *aJSObjectPrototype) NS_IMETHODIMP XPCWrappedNative::GetJSObjectPrototype(JSObject * *aJSObjectPrototype)
{ {
*aJSObjectPrototype = HasProto() ? *aJSObjectPrototype = HasProto() ?
GetProto()->GetJSProtoObject() : GetFlatJSObjectAndMark(); GetProto()->GetJSProtoObject() : GetFlatJSObject();
return NS_OK; return NS_OK;
} }
@ -3208,7 +3206,7 @@ NS_IMETHODIMP XPCWrappedNative::RefreshPrototype()
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);
JSAutoEnterCompartment ac; JSAutoEnterCompartment ac;
if(!ac.enter(ccx, GetFlatJSObjectAndMark())) if(!ac.enter(ccx, GetFlatJSObject()))
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);
AutoMarkingWrappedNativeProtoPtr oldProto(ccx); AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
@ -3232,7 +3230,7 @@ NS_IMETHODIMP XPCWrappedNative::RefreshPrototype()
if(newProto.get() == oldProto.get()) if(newProto.get() == oldProto.get())
return NS_OK; return NS_OK;
if(!JS_SetPrototype(ccx, GetFlatJSObjectAndMark(), if(!JS_SetPrototype(ccx, GetFlatJSObject(),
newProto->GetJSProtoObject())) newProto->GetJSProtoObject()))
return UnexpectedFailure(NS_ERROR_FAILURE); return UnexpectedFailure(NS_ERROR_FAILURE);

Просмотреть файл

@ -363,7 +363,7 @@ WrappedNativeJSGCThingTracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
if(wrapper->HasExternalReference() && !wrapper->IsWrapperExpired()) if(wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
{ {
JSTracer* trc = (JSTracer *)arg; JSTracer* trc = (JSTracer *)arg;
JS_CALL_OBJECT_TRACER(trc, wrapper->GetFlatJSObjectNoMark(), JS_CALL_OBJECT_TRACER(trc, wrapper->GetFlatJSObjectPreserveColor(),
"XPCWrappedNative::mFlatJSObject"); "XPCWrappedNative::mFlatJSObject");
} }

Просмотреть файл

@ -56,6 +56,7 @@
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "prmem.h" #include "prmem.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "xpcpublic.h"
using namespace mozilla::plugins::parent; using namespace mozilla::plugins::parent;