зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
9c768ea955
Коммит
ec808d0089
|
@ -1280,7 +1280,8 @@ public:
|
|||
void *aClosure)
|
||||
{
|
||||
if (aCache->PreservingWrapper()) {
|
||||
aCallback(nsIProgrammingLanguage::JAVASCRIPT, aCache->GetWrapper(),
|
||||
aCallback(nsIProgrammingLanguage::JAVASCRIPT,
|
||||
aCache->GetWrapperPreserveColor(),
|
||||
aClosure);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
nsresult
|
||||
NS_NewDOMDocumentType(nsIDOMDocumentType** aDocType,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#include "nsIXULRuntime.h"
|
||||
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
|
||||
#include "jsxdrapi.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<JSObject*>(mWrapperPtrBits & ~kWrapperBitMask);
|
||||
}
|
||||
|
@ -88,16 +109,6 @@ public:
|
|||
mWrapperPtrBits = 0;
|
||||
}
|
||||
|
||||
void SetPreservingWrapper(PRBool aPreserve)
|
||||
{
|
||||
if(aPreserve) {
|
||||
mWrapperPtrBits |= WRAPPER_BIT_PRESERVED;
|
||||
}
|
||||
else {
|
||||
mWrapperPtrBits &= ~WRAPPER_BIT_PRESERVED;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool PreservingWrapper()
|
||||
{
|
||||
return (mWrapperPtrBits & WRAPPER_BIT_PRESERVED) != 0;
|
||||
|
@ -114,6 +125,17 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Only meant to be called by nsContentUtils.
|
||||
void SetPreservingWrapper(PRBool aPreserve)
|
||||
{
|
||||
if(aPreserve) {
|
||||
mWrapperPtrBits |= WRAPPER_BIT_PRESERVED;
|
||||
}
|
||||
else {
|
||||
mWrapperPtrBits &= ~WRAPPER_BIT_PRESERVED;
|
||||
}
|
||||
}
|
||||
|
||||
enum { WRAPPER_BIT_PRESERVED = 1 << 0 };
|
||||
enum { WRAPPER_IS_PROXY = 1 << 1 };
|
||||
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 markIfUnmarked(uint32 color) const;
|
||||
JS_ALWAYS_INLINE void unmark(uint32 color) const;
|
||||
|
||||
inline JSCompartment *compartment() const;
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -55,7 +55,8 @@
|
|||
#include "jspubtd.h"
|
||||
#include "xptinfo.h"
|
||||
#include "nsAXPCNativeCallContext.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsWrapperCache;
|
||||
%}
|
||||
|
||||
/***************************************************************************/
|
||||
|
|
|
@ -569,9 +569,12 @@ struct TraversalTracer : public JSTracer
|
|||
static void
|
||||
NoteJSChild(JSTracer *trc, void *thing, uint32 kind)
|
||||
{
|
||||
TraversalTracer *tracer = static_cast<TraversalTracer*>(trc);
|
||||
if(!nsXPConnect::IsGray(thing) && !tracer->cb.WantAllTraces())
|
||||
return;
|
||||
|
||||
if(ADD_TO_CC(kind))
|
||||
{
|
||||
TraversalTracer *tracer = static_cast<TraversalTracer*>(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()) {
|
||||
|
@ -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");
|
||||
|
|
|
@ -196,7 +196,7 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage,
|
|||
{
|
||||
DEBUG_CheckWrapperThreadSafety(mWrapper);
|
||||
|
||||
mFlattenedJSObject = mWrapper->GetFlatJSObjectAndMark();
|
||||
mFlattenedJSObject = mWrapper->GetFlatJSObject();
|
||||
|
||||
if(mTearOff)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<nsXPCWrappedJS*>(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;
|
||||
}
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -581,7 +581,7 @@ castNativeFromWrapper(JSContext *cx,
|
|||
if(wrapper)
|
||||
{
|
||||
native = wrapper->GetIdentityObject();
|
||||
cur = wrapper->GetFlatJSObjectAndMark();
|
||||
cur = wrapper->GetFlatJSObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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<XPCTraceableVariant*>(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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "nsIDOMElement.h"
|
||||
#include "prmem.h"
|
||||
#include "nsIContent.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
using namespace mozilla::plugins::parent;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче