Bug 811206, Fix JSHolder drop handling, part 3 (fixes), r=mccr8,khuey
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 28 Nov 2012 03:37:57 +0200
changeset 124114 6c23f41b074768a4970c493edeafedee43450a1e
parent 124113 aaf77faa6886e2bdc344e94d5a9d25eb86098dde
child 124216 17c267a881cf107fab1455d1b252f30bbfe9d2b7
child 124221 33b2ec1bc7f37e943d33d251512c28756da1ef86
push id297
push userlsblakk@mozilla.com
push dateTue, 26 Mar 2013 17:28:00 +0000
treeherdermozilla-release@64d7b45c34e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, khuey
bugs811206
milestone20.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
Bug 811206, Fix JSHolder drop handling, part 3 (fixes), r=mccr8,khuey
accessible/src/msaa/nsAccessNodeWrap.cpp
accessible/src/msaa/nsAccessNodeWrap.h
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/canvas/src/ImageData.cpp
content/events/src/nsDOMMessageEvent.cpp
content/events/src/nsDOMNotifyAudioAvailableEvent.cpp
content/media/webaudio/AudioBuffer.cpp
content/xbl/src/nsXBLDocumentInfo.cpp
content/xul/content/src/nsXULElement.cpp
dom/base/DOMRequest.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsJSTimeoutHandler.cpp
dom/bindings/CallbackFunction.h
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothDevice.cpp
dom/devicestorage/nsDeviceStorage.cpp
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBKeyRange.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBWrapperCache.cpp
dom/sms/src/SmsRequest.cpp
dom/src/events/nsJSEventListener.cpp
dom/telephony/Telephony.cpp
--- 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;
@@ -4521,16 +4520,20 @@ nsContentUtils::HoldJSObjects(void* aScr
 
   return sXPConnect->AddJSHolder(aScriptObjectHolder, aTracer);
 }
 
 /* static */
 nsresult
 nsContentUtils::DropJSObjects(void* aScriptObjectHolder)
 {
+  if (!sXPConnect) {
+    return NS_OK;
+  }
+
   return sXPConnect->RemoveJSHolder(aScriptObjectHolder);
 }
 
 #ifdef DEBUG
 /* static */
 bool
 nsContentUtils::AreJSObjectsHeld(void* aScriptHolder)
 {
@@ -6858,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;