Bug 592352 - 'Assertbotch on shutdown after IDB solo mochitest -- leaked contexts?'. r=bent.

This commit is contained in:
Peter Van der Beken 2010-09-13 15:32:56 -07:00
parent a279cbfbcc
commit 511524fbed
6 changed files with 129 additions and 71 deletions

View File

@ -255,7 +255,7 @@ IDBCursor::IDBCursor()
: mDirection(nsIIDBCursor::NEXT),
mCachedValue(JSVAL_VOID),
mHaveCachedValue(false),
mJSRuntime(nsnull),
mValueRooted(false),
mContinueCalled(false),
mDataIndex(0),
mType(OBJECTSTORE)
@ -267,8 +267,8 @@ IDBCursor::~IDBCursor()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mJSRuntime) {
js_RemoveRoot(mJSRuntime, &mCachedValue);
if (mValueRooted) {
NS_DROP_JS_OBJECTS(this, IDBCursor);
}
if (mListenerManager) {
@ -280,18 +280,38 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBCursor,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRequest,
nsPIDOMEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
nsPIDOMEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mObjectStore,
nsPIDOMEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mIndex,
nsPIDOMEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
nsPIDOMEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(IDBCursor)
if (tmp->mValueRooted) {
NS_DROP_JS_OBJECTS(tmp, IDBCursor);
tmp->mCachedValue = JSVAL_VOID;
tmp->mHaveCachedValue = false;
tmp->mValueRooted = false;
}
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
if (JSVAL_IS_GCTHING(tmp->mCachedValue)) {
void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedValue);
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing)
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBCursor,
nsDOMEventTargetHelper)
// Don't unlink mObjectStore, mIndex, or mTransaction!
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -377,19 +397,15 @@ IDBCursor::GetValue(JSContext* aCx,
if (!mHaveCachedValue) {
JSAutoRequest ar(aCx);
if (!mJSRuntime) {
JSRuntime* rt = JS_GetRuntime(aCx);
JSBool ok = js_AddRootRT(rt, &mCachedValue,
"IDBCursor::mCachedValue");
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
mJSRuntime = rt;
}
nsCOMPtr<nsIJSON> json(new nsJSON());
rv = json->DecodeToJSVal(mData[mDataIndex].value, aCx, &mCachedValue);
NS_ENSURE_SUCCESS(rv, rv);
if (!mValueRooted) {
NS_HOLD_JS_OBJECTS(this, IDBCursor);
mValueRooted = true;
}
mHaveCachedValue = true;
}

View File

@ -78,8 +78,8 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIIDBCURSOR
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBCursor,
nsDOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBCursor,
nsDOMEventTargetHelper)
static
already_AddRefed<IDBCursor>
@ -137,7 +137,7 @@ protected:
nsCOMPtr<nsIVariant> mCachedKey;
jsval mCachedValue;
bool mHaveCachedValue;
JSRuntime* mJSRuntime;
bool mValueRooted;
bool mContinueCalled;
PRUint32 mDataIndex;

View File

@ -205,7 +205,17 @@ IDBEvent::CreateGenericEventRunnable(const nsAString& aType,
NS_IMPL_ADDREF_INHERITED(IDBEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(IDBEvent, nsDOMEvent)
NS_INTERFACE_MAP_BEGIN(IDBEvent)
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBEvent)
NS_INTERFACE_MAP_ENTRY(nsIIDBEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
@ -331,7 +341,19 @@ IDBSuccessEvent::CreateRunnable(IDBRequest* aRequest,
NS_IMPL_ADDREF_INHERITED(IDBSuccessEvent, IDBEvent)
NS_IMPL_RELEASE_INHERITED(IDBSuccessEvent, IDBEvent)
NS_INTERFACE_MAP_BEGIN(IDBSuccessEvent)
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBSuccessEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBSuccessEvent, IDBEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResult)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTransaction)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBSuccessEvent, IDBEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mResult)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBSuccessEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIDBTransactionEvent, mTransaction)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBTransactionEvent,
mTransaction)
@ -372,6 +394,13 @@ IDBSuccessEvent::GetTransaction(nsIIDBTransaction** aTransaction)
return NS_OK;
}
GetSuccessEvent::~GetSuccessEvent()
{
if (mValueRooted) {
NS_DROP_JS_OBJECTS(this, GetSuccessEvent);
}
}
nsresult
GetSuccessEvent::Init(IDBRequest* aRequest,
IDBTransaction* aTransaction)
@ -398,20 +427,14 @@ GetSuccessEvent::GetResult(JSContext* aCx,
return NS_OK;
}
if (!mJSRuntime) {
if (!mValueRooted) {
RootCachedValue();
nsString jsonValue = mValue;
mValue.Truncate();
JSAutoRequest ar(aCx);
JSRuntime* rt = JS_GetRuntime(aCx);
JSBool ok = js_AddRootRT(rt, &mCachedValue,
"GetSuccessEvent::mCachedValue");
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
mJSRuntime = rt;
nsCOMPtr<nsIJSON> json(new nsJSON());
nsresult rv = json->DecodeToJSVal(jsonValue, aCx, &mCachedValue);
if (NS_FAILED(rv)) {
@ -426,21 +449,56 @@ GetSuccessEvent::GetResult(JSContext* aCx,
return NS_OK;
}
void
GetSuccessEvent::RootCachedValue()
{
mValueRooted = PR_TRUE;
NS_HOLD_JS_OBJECTS(this, GetSuccessEvent);
}
NS_IMPL_ADDREF_INHERITED(GetSuccessEvent, IDBSuccessEvent)
NS_IMPL_RELEASE_INHERITED(GetSuccessEvent, IDBSuccessEvent)
NS_IMPL_CYCLE_COLLECTION_CLASS(GetSuccessEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GetSuccessEvent,
IDBSuccessEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(GetSuccessEvent)
if (tmp->mValueRooted) {
NS_DROP_JS_OBJECTS(tmp, GetSuccessEvent);
tmp->mCachedValue = JSVAL_VOID;
tmp->mValueRooted = PR_FALSE;
}
NS_IMPL_CYCLE_COLLECTION_ROOT_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GetSuccessEvent,
IDBSuccessEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mResult)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(GetSuccessEvent)
if (JSVAL_IS_GCTHING(tmp->mCachedValue)) {
void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedValue);
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing)
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GetSuccessEvent)
NS_INTERFACE_MAP_END_INHERITING(IDBSuccessEvent)
NS_IMETHODIMP
GetAllSuccessEvent::GetResult(JSContext* aCx,
jsval* aResult)
{
if (!mJSRuntime) {
if (!mValueRooted) {
RootCachedValue();
JSAutoRequest ar(aCx);
JSRuntime* rt = JS_GetRuntime(aCx);
JSBool ok = js_AddRootRT(rt, &mCachedValue,
"GetSuccessEvent::mCachedValue");
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
mJSRuntime = rt;
// Swap into a stack array so that we don't hang on to the strings if
// something fails.
nsTArray<nsString> values;
@ -497,17 +555,11 @@ NS_IMETHODIMP
GetAllKeySuccessEvent::GetResult(JSContext* aCx,
jsval* aResult)
{
if (!mJSRuntime) {
if (!mValueRooted) {
RootCachedValue();
JSAutoRequest ar(aCx);
JSRuntime* rt = JS_GetRuntime(aCx);
JSBool ok = js_AddRootRT(rt, &mCachedValue,
"GetSuccessEvent::mCachedValue");
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
mJSRuntime = rt;
// Swap into a stack array so that we don't hang on to the strings if
// something fails.
nsTArray<Key> keys;

View File

@ -73,6 +73,8 @@ public:
NS_DECL_NSIIDBEVENT
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBEvent, nsDOMEvent)
static already_AddRefed<nsIDOMEvent>
CreateGenericEvent(const nsAString& aType);
@ -121,6 +123,8 @@ public:
NS_FORWARD_NSIDOMEVENT(IDBEvent::)
NS_FORWARD_NSIIDBEVENT(IDBEvent::)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBSuccessEvent, IDBEvent)
static already_AddRefed<nsIDOMEvent>
Create(IDBRequest* aRequest,
nsIVariant* aResult,
@ -144,15 +148,14 @@ public:
GetSuccessEvent(const nsAString& aValue)
: mValue(aValue),
mCachedValue(JSVAL_VOID),
mJSRuntime(nsnull)
mValueRooted(PR_FALSE)
{ }
~GetSuccessEvent()
{
if (mJSRuntime) {
js_RemoveRoot(mJSRuntime, &mCachedValue);
}
}
~GetSuccessEvent();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(GetSuccessEvent,
IDBSuccessEvent)
NS_IMETHOD GetResult(JSContext* aCx,
jsval* aResult);
@ -164,8 +167,11 @@ private:
nsString mValue;
protected:
void RootCachedValue();
jsval mCachedValue;
JSRuntime* mJSRuntime;
PRBool mValueRooted;
};
class GetAllSuccessEvent : public GetSuccessEvent

View File

@ -113,12 +113,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnSuccessListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnSuccessListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)

View File

@ -1375,24 +1375,6 @@ static void
call_trace(JSTracer *trc, JSObject *obj)
{
JS_ASSERT(obj->isCall());
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) {
/*
* FIXME: Hide copies of stack values rooted by fp from the Cycle
* Collector, which currently lacks a non-stub Unlink implementation
* for JS objects (including Call objects), so is unable to collect
* cycles involving Call objects whose frames are active without this
* hiding hack.
*/
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
uintN count = fp->fun()->countArgsAndVars();
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
SetValueRangeToUndefined(&obj->fslots[first], fixed);
SetValueRangeToUndefined(obj->dslots, count - fixed);
}
MaybeMarkGenerator(trc, obj);
}