author | Ehsan Akhgari <ehsan@mozilla.com> |
Wed, 28 Nov 2012 09:43:30 -0500 | |
changeset 114364 | 33b2ec1bc7f37e943d33d251512c28756da1ef86 |
parent 114363 | eb4eff0fc3d75dd237617aa76040d485421aaa5e (current diff) |
parent 114257 | 6c23f41b074768a4970c493edeafedee43450a1e (diff) |
child 114365 | 67e95e421678221c8d8532860ef990af49d73249 |
push id | 23917 |
push user | emorley@mozilla.com |
push date | Thu, 29 Nov 2012 14:20:29 +0000 |
treeherder | mozilla-central@c72d38e7a212 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 20.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -2234,18 +2234,16 @@ private: static nsIStringBundle* sStringBundles[PropertiesFile_COUNT]; static nsIContentPolicy* sContentPolicyService; static bool sTriedToGetContentPolicy; static nsILineBreaker* sLineBreaker; static nsIWordBreaker* sWordBreaker; - static uint32_t sJSGCThingRootCount; - #ifdef IBMBIDI static nsIBidiKeyboard* sBidiKeyboard; #endif static bool sInitialized; static uint32_t sScriptBlockerCount; #ifdef DEBUG static uint32_t sDOMNodeRemovedSuppressCount;
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -203,17 +203,16 @@ nsDataHashtable<nsISupportsHashKey, Even nsDataHashtable<nsStringHashKey, EventNameMapping>* nsContentUtils::sStringEventTable = nullptr; nsCOMArray<nsIAtom>* nsContentUtils::sUserDefinedEvents = nullptr; nsIStringBundleService *nsContentUtils::sStringBundleService; nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT]; nsIContentPolicy *nsContentUtils::sContentPolicyService; bool nsContentUtils::sTriedToGetContentPolicy = false; nsILineBreaker *nsContentUtils::sLineBreaker; nsIWordBreaker *nsContentUtils::sWordBreaker; -uint32_t nsContentUtils::sJSGCThingRootCount; #ifdef IBMBIDI nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr; #endif uint32_t nsContentUtils::sScriptBlockerCount = 0; #ifdef DEBUG uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0; #endif uint32_t nsContentUtils::sMicroTaskLevel = 0; @@ -4514,38 +4513,28 @@ nsContentUtils::DestroyAnonymousContent( /* static */ nsresult nsContentUtils::HoldJSObjects(void* aScriptObjectHolder, nsScriptObjectTracer* aTracer) { NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED); - nsresult rv = sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer); - NS_ENSURE_SUCCESS(rv, rv); - - if (sJSGCThingRootCount++ == 0) { - nsLayoutStatics::AddRef(); - } - NS_LOG_ADDREF(sXPConnect, sJSGCThingRootCount, "HoldJSObjects", - sizeof(void*)); - - return NS_OK; + return sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer); } /* static */ nsresult nsContentUtils::DropJSObjects(void* aScriptObjectHolder) { - NS_LOG_RELEASE(sXPConnect, sJSGCThingRootCount - 1, "HoldJSObjects"); - nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder); - if (--sJSGCThingRootCount == 0) { - nsLayoutStatics::Release(); - } - return rv; + if (!sXPConnect) { + return NS_OK; + } + + return sXPConnect->RemoveJSHolder(aScriptObjectHolder); } #ifdef DEBUG /* static */ bool nsContentUtils::AreJSObjectsHeld(void* aScriptHolder) { bool isHeld = false; @@ -6872,19 +6861,18 @@ nsContentUtils::ReleaseWrapper(void* aSc if (aCache->PreservingWrapper()) { // PreserveWrapper puts new DOM bindings in the JS holders hash, but they // can also be in the DOM expando hash, so we need to try to remove them // from both here. JSObject* obj = aCache->GetWrapperPreserveColor(); if (aCache->IsDOMBinding() && obj) { xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj); } + aCache->SetPreservingWrapper(false); DropJSObjects(aScriptObjectHolder); - - aCache->SetPreservingWrapper(false); } } // static void nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback, void *aClosure) {
--- a/content/canvas/src/ImageData.cpp +++ b/content/canvas/src/ImageData.cpp @@ -41,18 +41,18 @@ ImageData::HoldData() { NS_HOLD_JS_OBJECTS(this, ImageData); } void ImageData::DropData() { if (mData) { + mData = NULL; NS_DROP_JS_OBJECTS(this, ImageData); - mData = NULL; } } JSObject* ImageData::WrapObject(JSContext* cx, JSObject* scope) { return ImageDataBinding::Wrap(cx, scope, this); }
--- a/content/events/src/nsDOMMessageEvent.cpp +++ b/content/events/src/nsDOMMessageEvent.cpp @@ -57,19 +57,19 @@ nsDOMMessageEvent::RootData() NS_HOLD_JS_OBJECTS(this, nsDOMMessageEvent); mDataRooted = true; } void nsDOMMessageEvent::UnrootData() { NS_ASSERTION(mDataRooted, "..."); - NS_DROP_JS_OBJECTS(this, nsDOMMessageEvent); mDataRooted = false; mData = JSVAL_VOID; + NS_DROP_JS_OBJECTS(this, nsDOMMessageEvent); } NS_IMETHODIMP nsDOMMessageEvent::GetData(JSContext* aCx, jsval* aData) { *aData = mData; if (!JS_WrapValue(aCx, aData)) return NS_ERROR_FAILURE;
--- a/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp +++ b/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp @@ -33,18 +33,18 @@ DOMCI_DATA(NotifyAudioAvailableEvent, ns NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMNotifyAudioAvailableEvent) NS_IMPL_ADDREF_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent) NS_IMPL_RELEASE_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent) if (tmp->mCachedArray) { + tmp->mCachedArray = nullptr; NS_DROP_JS_OBJECTS(tmp, nsDOMNotifyAudioAvailableEvent); - tmp->mCachedArray = nullptr; } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMNotifyAudioAvailableEvent) @@ -55,18 +55,18 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_ NS_INTERFACE_MAP_ENTRY(nsIDOMNotifyAudioAvailableEvent) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NotifyAudioAvailableEvent) NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) nsDOMNotifyAudioAvailableEvent::~nsDOMNotifyAudioAvailableEvent() { MOZ_COUNT_DTOR(nsDOMNotifyAudioAvailableEvent); if (mCachedArray) { + mCachedArray = nullptr; NS_DROP_JS_OBJECTS(this, nsDOMNotifyAudioAvailableEvent); - mCachedArray = nullptr; } } NS_IMETHODIMP nsDOMNotifyAudioAvailableEvent::GetFrameBuffer(JSContext* aCx, jsval* aResult) { if (!mAllowAudioData) { // Media is not same-origin, don't allow the data out.
--- a/content/media/webaudio/AudioBuffer.cpp +++ b/content/media/webaudio/AudioBuffer.cpp @@ -49,16 +49,17 @@ AudioBuffer::AudioBuffer(AudioContext* a { SetIsDOMBinding(); NS_HOLD_JS_OBJECTS(this, AudioBuffer); } AudioBuffer::~AudioBuffer() { + mChannels.Clear(); NS_DROP_JS_OBJECTS(this, AudioBuffer); } bool AudioBuffer::InitializeBuffers(uint32_t aNumberOfChannels, JSContext* aJSContext) { if (!mChannels.SetCapacity(aNumberOfChannels)) { return false;
--- a/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/content/xbl/src/nsXBLDocumentInfo.cpp @@ -517,18 +517,19 @@ nsXBLDocumentInfo::~nsXBLDocumentInfo() { /* destructor code */ if (mGlobalObject) { // remove circular reference mGlobalObject->ClearScriptContext(); mGlobalObject->ClearGlobalObjectOwner(); // just in case } if (mBindingTable) { + delete mBindingTable; + mBindingTable = nullptr; NS_DROP_JS_OBJECTS(this, nsXBLDocumentInfo); - delete mBindingTable; } } nsXBLPrototypeBinding* nsXBLDocumentInfo::GetPrototypeBinding(const nsACString& aRef) { if (!mBindingTable) return NULL;
--- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -2486,18 +2486,18 @@ nsXULPrototypeScript::Compile(const PRUn Set(newScriptObject); return rv; } void nsXULPrototypeScript::UnlinkJSObjects() { if (mScriptObject.mObject) { + mScriptObject.mObject = nullptr; nsContentUtils::DropJSObjects(this); - mScriptObject.mObject = nullptr; } } void nsXULPrototypeScript::Set(JSScript* aObject) { NS_ASSERTION(!mScriptObject.mObject, "Leaking script object."); if (!aObject) {
--- a/dom/base/DOMRequest.cpp +++ b/dom/base/DOMRequest.cpp @@ -49,17 +49,16 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(DOMReques NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest, nsDOMEventTargetHelper) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest, nsDOMEventTargetHelper) if (tmp->mRooted) { - tmp->mResult = JSVAL_VOID; tmp->UnrootResultVal(); } NS_IMPL_CYCLE_COLLECTION_UNLINK(mError) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest, nsDOMEventTargetHelper) // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because @@ -182,16 +181,17 @@ DOMRequest::RootResultVal() participant); mRooted = true; } void DOMRequest::UnrootResultVal() { NS_ASSERTION(mRooted, "Don't call me if not rooted!"); + mResult = JSVAL_VOID; NS_DROP_JS_OBJECTS(this, DOMRequest); mRooted = false; } NS_IMPL_ISUPPORTS1(DOMRequestService, nsIDOMRequestService) NS_IMETHODIMP DOMRequestService::CreateRequest(nsIDOMWindow* aWindow,
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -4139,22 +4139,23 @@ nsJSArgArray::nsJSArgArray(JSContext *aC nsJSArgArray::~nsJSArgArray() { ReleaseJSObjects(); } void nsJSArgArray::ReleaseJSObjects() { - if (mArgc > 0) - NS_DROP_JS_OBJECTS(this, nsJSArgArray); if (mArgv) { PR_DELETE(mArgv); } - mArgc = 0; + if (mArgc > 0) { + mArgc = 0; + NS_DROP_JS_OBJECTS(this, nsJSArgArray); + } } // QueryInterface implementation for nsJSArgArray NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray) tmp->ReleaseJSObjects(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray)
--- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -136,27 +136,22 @@ nsJSScriptTimeoutHandler::nsJSScriptTime nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler() { ReleaseJSObjects(); } void nsJSScriptTimeoutHandler::ReleaseJSObjects() { - if (mExpr || mFunObj) { - if (mExpr) { - NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler); - mExpr = nullptr; - } else if (mFunObj) { - NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler); - mFunObj = nullptr; - } else { - NS_WARNING("No func and no expr - roots may not have been removed"); - } + if (mExpr) { + mExpr = nullptr; + } else { + mFunObj = nullptr; } + NS_DROP_JS_OBJECTS(this, nsJSScriptTimeoutHandler); } nsresult nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval, int32_t *aInterval) { mContext = aWindow->GetContextInternal(); if (!mContext) {
--- a/dom/bindings/CallbackFunction.h +++ b/dom/bindings/CallbackFunction.h @@ -86,18 +86,18 @@ public: // Play it safe in case this gets called after unlink. return mCallable && xpc_IsGrayGCThing(mCallable); } protected: void DropCallback() { if (mCallable) { + mCallable = nullptr; NS_DROP_JS_OBJECTS(this, CallbackFunction); - mCallable = nullptr; nsLayoutStatics::Release(); } } JSObject* mCallable; class NS_STACK_CLASS CallSetup {
--- a/dom/bluetooth/BluetoothAdapter.cpp +++ b/dom/bluetooth/BluetoothAdapter.cpp @@ -158,16 +158,18 @@ BluetoothAdapter::~BluetoothAdapter() } void BluetoothAdapter::Unroot() { if (!mIsRooted) { return; } + mJsUuids = nullptr; + mJsDeviceAddresses = nullptr; NS_DROP_JS_OBJECTS(this, BluetoothAdapter); mIsRooted = false; } void BluetoothAdapter::Root() { if (mIsRooted) {
--- a/dom/bluetooth/BluetoothDevice.cpp +++ b/dom/bluetooth/BluetoothDevice.cpp @@ -82,16 +82,18 @@ BluetoothDevice::Root() mIsRooted = true; } } void BluetoothDevice::Unroot() { if (mIsRooted) { + mJsUuids = nullptr; + mJsServices = nullptr; NS_DROP_JS_OBJECTS(this, BluetoothDevice); mIsRooted = false; } } void BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue) {
--- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -1136,18 +1136,18 @@ nsDOMDeviceStorageCursor::Continue() { if (!mOkToCallContinue) { return NS_ERROR_UNEXPECTED; } if (mRooted) { // We call onsuccess multiple times. clear the last // rooted result. + mResult = JSVAL_VOID; NS_DROP_JS_OBJECTS(this, nsDOMDeviceStorageCursor); - mResult = JSVAL_VOID; mDone = false; mRooted = false; } nsCOMPtr<ContinueCursorEvent> event = new ContinueCursorEvent(this); NS_DispatchToMainThread(event); mOkToCallContinue = false;
--- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -364,20 +364,36 @@ IDBCursor::~IDBCursor() NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); if (mActorChild) { NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); mActorChild->Send__delete__(mActorChild); NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); } - if (mRooted) { - NS_DROP_JS_OBJECTS(this, IDBCursor); + DropJSObjects(); + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); +} + +void +IDBCursor::DropJSObjects() +{ + if (!mRooted) { + return; } - IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); + mScriptOwner = nullptr; + mCachedKey = JSVAL_VOID; + mCachedPrimaryKey = JSVAL_VOID; + mCachedValue = JSVAL_VOID; + mHaveCachedKey = false; + mHaveCachedPrimaryKey = false; + mHaveCachedValue = false; + mRooted = false; + mHaveValue = false; + NS_DROP_JS_OBJECTS(this, IDBCursor); } nsresult IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aCount > 0, "Must have a count!"); @@ -450,28 +466,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDB NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner) NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey) NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey) NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor) // Don't unlink mObjectStore, mIndex, or mTransaction! - if (tmp->mRooted) { - NS_DROP_JS_OBJECTS(tmp, IDBCursor); - tmp->mScriptOwner = nullptr; - tmp->mCachedKey = JSVAL_VOID; - tmp->mCachedPrimaryKey = JSVAL_VOID; - tmp->mCachedValue = JSVAL_VOID; - tmp->mHaveCachedKey = false; - tmp->mHaveCachedPrimaryKey = false; - tmp->mHaveCachedValue = false; - tmp->mRooted = false; - tmp->mHaveValue = false; - } + tmp->DropJSObjects(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor) NS_INTERFACE_MAP_ENTRY(nsIIDBCursor) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIDBCursorWithValue, mType != INDEXKEY) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursorWithValue, mType != INDEXKEY)
--- a/dom/indexedDB/IDBCursor.h +++ b/dom/indexedDB/IDBCursor.h @@ -146,16 +146,18 @@ public: nsresult ContinueInternal(const Key& aKey, int32_t aCount); protected: IDBCursor(); ~IDBCursor(); + void DropJSObjects(); + static already_AddRefed<IDBCursor> CreateCommon(IDBRequest* aRequest, IDBTransaction* aTransaction, IDBObjectStore* aObjectStore, Direction aDirection, const Key& aRangeKey, const nsACString& aContinueQuery,
--- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -239,18 +239,16 @@ IDBDatabase::~IDBDatabase() if (mRegistered) { CloseInternal(true); IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); if (mgr) { mgr->UnregisterDatabase(this); } } - - nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this); } void IDBDatabase::Invalidate() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (IsInvalidated()) {
--- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -72,16 +72,17 @@ IDBFactory::~IDBFactory() { NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); if (mActorChild) { NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); mActorChild->Send__delete__(mActorChild); NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); } if (mRootedOwningObject) { + mOwningObject = nullptr; NS_DROP_JS_OBJECTS(this, IDBFactory); } } // static nsresult IDBFactory::Create(nsPIDOMWindow* aWindow, const nsACString& aASCIIOrigin,
--- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -409,16 +409,17 @@ IDBIndex::IDBIndex() } IDBIndex::~IDBIndex() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); if (mRooted) { + mCachedKeyPath = JSVAL_VOID; NS_DROP_JS_OBJECTS(this, IDBIndex); } if (mActorChild) { NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); mActorChild->Send__delete__(mActorChild); NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); }
--- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -313,42 +313,47 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN( NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange) NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal) NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange) - if (tmp->mRooted) { - NS_DROP_JS_OBJECTS(tmp, IDBKeyRange); - tmp->mCachedLowerVal = JSVAL_VOID; - tmp->mCachedUpperVal = JSVAL_VOID; - tmp->mHaveCachedLowerVal = false; - tmp->mHaveCachedUpperVal = false; - tmp->mRooted = false; - } + tmp->DropJSObjects(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsIIDBKeyRange) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBKeyRange) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange) NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange) DOMCI_DATA(IDBKeyRange, IDBKeyRange) +void +IDBKeyRange::DropJSObjects() +{ + if (!mRooted) { + return; + } + mCachedLowerVal = JSVAL_VOID; + mCachedUpperVal = JSVAL_VOID; + mHaveCachedLowerVal = false; + mHaveCachedUpperVal = false; + mRooted = false; + NS_DROP_JS_OBJECTS(this, IDBKeyRange); +} + IDBKeyRange::~IDBKeyRange() { - if (mRooted) { - NS_DROP_JS_OBJECTS(this, IDBKeyRange); - } + DropJSObjects(); } NS_IMETHODIMP IDBKeyRange::GetLower(JSContext* aCx, jsval* aLower) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
--- a/dom/indexedDB/IDBKeyRange.h +++ b/dom/indexedDB/IDBKeyRange.h @@ -145,16 +145,18 @@ public: } return NS_OK; } template <class T> void ToSerializedKeyRange(T& aKeyRange); + void DropJSObjects(); + private: ~IDBKeyRange(); Key mLower; Key mUpper; jsval mCachedLowerVal; jsval mCachedUpperVal; bool mLowerOpen;
--- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1538,16 +1538,17 @@ IDBObjectStore::~IDBObjectStore() NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); if (mActorChild) { NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); mActorChild->Send__delete__(mActorChild); NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); } if (mRooted) { + mCachedKeyPath = JSVAL_VOID; NS_DROP_JS_OBJECTS(this, IDBObjectStore); } } nsresult IDBObjectStore::GetAddInfo(JSContext* aCx, jsval aValue, jsval aKeyVal,
--- a/dom/indexedDB/IDBRequest.cpp +++ b/dom/indexedDB/IDBRequest.cpp @@ -35,16 +35,17 @@ IDBRequest::IDBRequest() mHaveResultOrErrorCode(false), mLineNo(0) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); } IDBRequest::~IDBRequest() { + mResultVal = JSVAL_VOID; NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); } // static already_AddRefed<IDBRequest> IDBRequest::Create(nsISupports* aSource, IDBWrapperCache* aOwnerCache, IDBTransaction* aTransaction,
--- a/dom/indexedDB/IDBTransaction.cpp +++ b/dom/indexedDB/IDBTransaction.cpp @@ -184,18 +184,16 @@ IDBTransaction::~IDBTransaction() NS_ASSERTION(mFiredCompleteOrAbort, "Should have fired event!"); NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); if (mActorChild) { NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); mActorChild->Send__delete__(mActorChild); NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); } - - nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this); } void IDBTransaction::OnNewRequest() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (!mPendingRequests) { NS_ASSERTION(mReadyState == IDBTransaction::INITIAL,
--- a/dom/indexedDB/IDBWrapperCache.cpp +++ b/dom/indexedDB/IDBWrapperCache.cpp @@ -15,18 +15,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ nsDOMEventTargetHelper) // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because // nsDOMEventTargetHelper does it for us. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBWrapperCache, nsDOMEventTargetHelper) if (tmp->mScriptOwner) { + tmp->mScriptOwner = nullptr; NS_DROP_JS_OBJECTS(tmp, IDBWrapperCache); - tmp->mScriptOwner = nullptr; } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBWrapperCache, nsDOMEventTargetHelper) // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because // nsDOMEventTargetHelper does it for us. NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner) @@ -35,19 +35,19 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBWrapperCache) NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(IDBWrapperCache, nsDOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(IDBWrapperCache, nsDOMEventTargetHelper) IDBWrapperCache::~IDBWrapperCache() { - if (mScriptOwner) { - NS_DROP_JS_OBJECTS(this, IDBWrapperCache); - } + mScriptOwner = nullptr; + nsContentUtils::ReleaseWrapper(this, this); + NS_DROP_JS_OBJECTS(this, IDBWrapperCache); } bool IDBWrapperCache::SetScriptOwner(JSObject* aScriptOwner) { NS_ASSERTION(aScriptOwner, "This should never be null!"); mScriptOwner = aScriptOwner;
--- a/dom/sms/src/SmsRequest.cpp +++ b/dom/sms/src/SmsRequest.cpp @@ -38,17 +38,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCursor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SmsRequest, nsDOMEventTargetHelper) if (tmp->mResultRooted) { - tmp->mResult = JSVAL_VOID; tmp->UnrootResult(); } NS_IMPL_CYCLE_COLLECTION_UNLINK(mCursor) NS_IMPL_CYCLE_COLLECTION_UNLINK(mError) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(SmsRequest, nsDOMEventTargetHelper) @@ -132,16 +131,17 @@ SmsRequest::RootResult() NS_HOLD_JS_OBJECTS(this, SmsRequest); mResultRooted = true; } void SmsRequest::UnrootResult() { NS_ASSERTION(mResultRooted, "Don't call UnrotResult() if not rooted!"); + mResult = JSVAL_VOID; NS_DROP_JS_OBJECTS(this, SmsRequest); mResultRooted = false; } void SmsRequest::SetSuccess(nsIDOMMozSmsMessage* aMessage) { SetSuccessInternal(aMessage); @@ -201,17 +201,16 @@ SmsRequest::SetSuccessInternal(nsISuppor JSAutoRequest ar(cx); JSAutoCompartment ac(cx, global); RootResult(); if (NS_FAILED(nsContentUtils::WrapNative(cx, global, aObject, &mResult))) { UnrootResult(); - mResult = JSVAL_VOID; SetError(nsISmsRequest::INTERNAL_ERROR); return false; } mDone = true; return true; }
--- a/dom/src/events/nsJSEventListener.cpp +++ b/dom/src/events/nsJSEventListener.cpp @@ -56,37 +56,39 @@ nsJSEventListener::nsJSEventListener(nsI if (mScopeObject) { NS_HOLD_JS_OBJECTS(this, nsJSEventListener); } } nsJSEventListener::~nsJSEventListener() { if (mScopeObject) { + mScopeObject = nullptr; NS_DROP_JS_OBJECTS(this, nsJSEventListener); } } /* virtual */ void nsJSEventListener::UpdateScopeObject(JSObject* aScopeObject) { if (mScopeObject && !aScopeObject) { + mScopeObject = nullptr; NS_DROP_JS_OBJECTS(this, nsJSEventListener); } else if (aScopeObject && !mScopeObject) { NS_HOLD_JS_OBJECTS(this, nsJSEventListener); } mScopeObject = aScopeObject; } NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener) if (tmp->mScopeObject) { + tmp->mScopeObject = nullptr; NS_DROP_JS_OBJECTS(tmp, nsJSEventListener); - tmp->mScopeObject = nullptr; NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext) } tmp->mHandler.ForgetHandler(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSEventListener) if (MOZ_UNLIKELY(cb.WantDebugInfo()) && tmp->mEventName) { nsAutoCString name; name.AppendLiteral("nsJSEventListener handlerName=");
--- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -48,16 +48,17 @@ Telephony::Telephony() Telephony::~Telephony() { if (mRIL && mRILTelephonyCallback) { mRIL->UnregisterTelephonyCallback(mRILTelephonyCallback); } if (mRooted) { + mCallsArray = nullptr; NS_DROP_JS_OBJECTS(this, Telephony); } NS_ASSERTION(gTelephonyList, "This should never be null!"); NS_ASSERTION(gTelephonyList->Contains(this), "Should be in the list!"); if (gTelephonyList->Length() == 1) { delete gTelephonyList;
--- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -245,25 +245,59 @@ CompartmentDestroyedCallback(JSFreeOp *f nsAutoPtr<CompartmentPrivate> priv(GetCompartmentPrivate(compartment)); JS_SetCompartmentPrivate(compartment, nullptr); } nsresult XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer) { MOZ_ASSERT(aTracer->Trace, "AddJSHolder needs a non-null Trace function"); + bool wasEmpty = mJSHolders.Count() == 0; mJSHolders.Put(aHolder, aTracer); + if (wasEmpty && mJSHolders.Count() == 1) { + nsLayoutStatics::AddRef(); + } return NS_OK; } +#ifdef DEBUG +static void +AssertNoGcThing(void* aGCThing, const char* aName, void* aClosure) +{ + MOZ_ASSERT(!aGCThing); +} + +void +XPCJSRuntime::AssertNoObjectsToTrace(void* aPossibleJSHolder) +{ + nsScriptObjectTracer* tracer = mJSHolders.Get(aPossibleJSHolder); + if (tracer && tracer->Trace) { + tracer->Trace(aPossibleJSHolder, AssertNoGcThing, nullptr); + } +} +#endif + nsresult XPCJSRuntime::RemoveJSHolder(void* aHolder) { +#ifdef DEBUG + // Assert that the holder doesn't try to keep any GC things alive. + // In case of unlinking cycle collector calls AssertNoObjectsToTrace + // manually because we don't want to check the holder before we are + // finished unlinking it + if (aHolder != mObjectToUnlink) { + AssertNoObjectsToTrace(aHolder); + } +#endif + bool hadOne = mJSHolders.Count() == 1; mJSHolders.Remove(aHolder); + if (hadOne && mJSHolders.Count() == 0) { + nsLayoutStatics::Release(); + } return NS_OK; } nsresult XPCJSRuntime::TestJSHolder(void* aHolder, bool* aRetval) { *aRetval = mJSHolders.Get(aHolder, nullptr); @@ -2398,16 +2432,19 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* mWrappedJSRoots(nullptr), mObjectHolderRoots(nullptr), mWatchdogLock(nullptr), mWatchdogWakeup(nullptr), mWatchdogThread(nullptr), mWatchdogHibernating(false), mLastActiveTime(-1), mExceptionManagerNotAvailable(false) +#ifdef DEBUG + , mObjectToUnlink(nullptr) +#endif { #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN DEBUG_WrappedNativeHashtable = JS_NewDHashTable(JS_DHashGetStubOps(), nullptr, sizeof(JSDHashEntryStub), 128); #endif DOM_InitInterfaces();
--- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -2708,16 +2708,32 @@ nsXPConnect::WriteFunction(nsIObjectOutp } NS_IMETHODIMP nsXPConnect::ReadFunction(nsIObjectInputStream *stream, JSContext *cx, JSObject **functionObjp) { return ReadScriptOrFunction(stream, cx, nullptr, functionObjp); } +#ifdef DEBUG +void +nsXPConnect::SetObjectToUnlink(void* aObject) +{ + if (mRuntime) + mRuntime->SetObjectToUnlink(aObject); +} + +void +nsXPConnect::AssertNoObjectsToTrace(void* aPossibleJSHolder) +{ + if (mRuntime) + mRuntime->AssertNoObjectsToTrace(aPossibleJSHolder); +} +#endif + /* These are here to be callable from a debugger */ JS_BEGIN_EXTERN_C JS_EXPORT_API(void) DumpJSStack() { nsresult rv; nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); if (NS_SUCCEEDED(rv) && xpc) xpc->DebugDumpJSStack(true, true, false);
--- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -480,16 +480,21 @@ public: // non-interface implementation public: // These get non-addref'd pointers static nsXPConnect* GetXPConnect(); static nsXPConnect* FastGetXPConnect() { return gSelf ? gSelf : GetXPConnect(); } static XPCJSRuntime* GetRuntimeInstance(); XPCJSRuntime* GetRuntime() {return mRuntime;} +#ifdef DEBUG + void SetObjectToUnlink(void* aObject); + void AssertNoObjectsToTrace(void* aPossibleJSHolder); +#endif + // Gets addref'd pointer static nsresult GetInterfaceInfoManager(nsIInterfaceInfoSuperManager** iim, nsXPConnect* xpc = nullptr); static JSBool IsISupportsDescendant(nsIInterfaceInfo* info); nsIXPCSecurityManager* GetDefaultSecurityManager() const { @@ -820,16 +825,20 @@ public: inline void AddVariantRoot(XPCTraceableVariant* variant); inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS); inline void AddObjectHolderRoot(XPCJSObjectHolder* holder); nsresult AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer); nsresult RemoveJSHolder(void* aHolder); nsresult TestJSHolder(void* aHolder, bool* aRetval); +#ifdef DEBUG + void SetObjectToUnlink(void* aObject) { mObjectToUnlink = aObject; } + void AssertNoObjectsToTrace(void* aPossibleJSHolder); +#endif static void SuspectWrappedNative(XPCWrappedNative *wrapper, nsCycleCollectionTraversalCallback &cb); void DebugDump(int16_t depth); void SystemIsBeingShutDown(); @@ -985,16 +994,20 @@ private: mozilla::AlignedStorage2<XPCReadableJSStringWrapper> mString; bool mInUse; }; StringWrapperEntry mScratchStrings[XPCCCX_STRING_CACHE_SIZE]; friend class AutoLockWatchdog; friend class XPCIncrementalReleaseRunnable; + +#ifdef DEBUG + void* mObjectToUnlink; +#endif }; /***************************************************************************/ /***************************************************************************/ // XPCContext is mostly a dumb class to hold JSContext specific data and // maps that let us find wrappers created for the given JSContext. // no virtuals
--- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2376,17 +2376,28 @@ nsCycleCollector::CollectWhite(nsICycleC PtrInfo *pinfo = mWhiteNodes->ElementAt(i); aListener->DescribeGarbage((uint64_t)pinfo->mPointer); } aListener->End(); } for (uint32_t i = 0; i < count; ++i) { PtrInfo *pinfo = mWhiteNodes->ElementAt(i); +#ifdef DEBUG + if (mJSRuntime) { + mJSRuntime->SetObjectToUnlink(pinfo->mPointer); + } +#endif rv = pinfo->mParticipant->Unlink(pinfo->mPointer); +#ifdef DEBUG + if (mJSRuntime) { + mJSRuntime->SetObjectToUnlink(nullptr); + mJSRuntime->AssertNoObjectsToTrace(pinfo->mPointer); + } +#endif if (NS_FAILED(rv)) { Fault("Failed unlink call while unlinking", pinfo); #ifdef DEBUG_CC mStats.mFailedUnlink++; #endif } else { #ifdef DEBUG_CC
--- a/xpcom/base/nsCycleCollector.h +++ b/xpcom/base/nsCycleCollector.h @@ -76,16 +76,21 @@ struct nsCycleCollectionJSRuntime * Runs the JavaScript GC. |reason| is a gcreason::Reason from jsfriendapi.h. */ virtual void Collect(uint32_t reason) = 0; /** * Get the JS cycle collection participant. */ virtual nsCycleCollectionParticipant *GetParticipant() = 0; + +#ifdef DEBUG + virtual void SetObjectToUnlink(void* aObject) = 0; + virtual void AssertNoObjectsToTrace(void* aPossibleJSHolder) = 0; +#endif }; // Helpers for interacting with JS void nsCycleCollector_registerJSRuntime(nsCycleCollectionJSRuntime *rt); void nsCycleCollector_forgetJSRuntime(); #ifdef DEBUG void nsCycleCollector_DEBUG_shouldBeFreed(nsISupports *n);