Fix for bug 731227 (Fix script object ownership in IDBWrapperCache/IDBCursor). r=bent.
authorPeter Van der Beken <peterv@propagandism.org>
Mon, 27 Feb 2012 17:52:19 +0100
changeset 87943 a77570b9a808672c89b856560f36b21fa98aa5c7
parent 87942 8daec30c95414ea241d603c84ed35a7de7c9eaa0
child 87944 491ceed82be3404994c6f7d25a0c18b0b151344b
push id22164
push usermbrubeck@mozilla.com
push dateWed, 29 Feb 2012 18:48:10 +0000
treeherdermozilla-central@3812d0ce274e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs731227
milestone13.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
Fix for bug 731227 (Fix script object ownership in IDBWrapperCache/IDBCursor). r=bent.
dom/base/nsDOMClassInfo.cpp
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBWrapperCache.cpp
dom/indexedDB/IDBWrapperCache.h
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -679,21 +679,16 @@ protected:
 
   virtual ~IDBEventTargetSH()
   { }
 
 public:
   NS_IMETHOD PreCreate(nsISupports *aNativeObj, JSContext *aCx,
                        JSObject *aGlobalObj, JSObject **aParentObj);
 
-  NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *aWrapper, JSContext *aCx,
-                         JSObject *aObj, jsid aId, jsval *aVp, bool *aRetval);
-
-  virtual void PreserveWrapper(nsISupports *aNative);
-
   static nsIClassInfo *doCreate(nsDOMClassInfoData *aData)
   {
     return new IDBEventTargetSH(aData);
   }
 };
 
 } // anonymous namespace
 
@@ -7695,35 +7690,16 @@ IDBEventTargetSH::PreCreate(nsISupports 
                             JSObject *aGlobalObj, JSObject **aParentObj)
 {
   IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNativeObj);
   JSObject *parent = target->GetParentObject();
   *aParentObj = parent ? parent : aGlobalObj;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBEventTargetSH::AddProperty(nsIXPConnectWrappedNative *aWrapper,
-                              JSContext *aCx, JSObject *aObj, jsid aId,
-                              jsval *aVp, bool *aRetval)
-{
-  if (aId != sAddEventListener_id) {
-    IDBEventTargetSH::PreserveWrapper(GetNative(aWrapper, aObj));
-  }
-
-  return NS_OK;
-}
-
-void
-IDBEventTargetSH::PreserveWrapper(nsISupports *aNative)
-{
-  IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNative);
-  nsContentUtils::PreserveWrapper(aNative, target);
-}
-
 // Element helper
 
 static bool
 GetBindingURL(Element *aElement, nsIDocument *aDocument,
               nsCSSValue::URL **aResult)
 {
   // If we have a frame the frame has already loaded the binding.  And
   // otherwise, don't do anything else here unless we're dealing with
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -261,16 +261,24 @@ IDBCursor::CreateCommon(IDBRequest* aReq
 
   nsRefPtr<IDBCursor> cursor = new IDBCursor();
 
   IDBDatabase* database = aTransaction->Database();
   cursor->mScriptContext = database->GetScriptContext();
   cursor->mOwner = database->GetOwner();
   cursor->mScriptOwner = database->GetScriptOwner();
 
+  if (cursor->mScriptOwner) {
+    if (NS_FAILED(NS_HOLD_JS_OBJECTS(cursor, IDBCursor))) {
+      return nsnull;
+    }
+
+    cursor->mRooted = true;
+  }
+
   cursor->mRequest = aRequest;
   cursor->mTransaction = aTransaction;
   cursor->mObjectStore = aObjectStore;
   cursor->mDirection = aDirection;
   cursor->mContinueQuery = aContinueQuery;
   cursor->mContinueToQuery = aContinueToQuery;
   cursor->mRangeKey = aRangeKey;
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -159,17 +159,19 @@ IDBDatabase::Create(IDBWrapperCache* aOw
 
   nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
   NS_ASSERTION(databaseInfo, "Null pointer!");
 
   nsRefPtr<IDBDatabase> db(new IDBDatabase());
 
   db->mScriptContext = aOwnerCache->GetScriptContext();
   db->mOwner = aOwnerCache->GetOwner();
-  db->mScriptOwner = aOwnerCache->GetScriptOwner();
+  if (!db->SetScriptOwner(aOwnerCache->GetScriptOwner())) {
+    return nsnull;
+  }
 
   db->mDatabaseId = databaseInfo->id;
   db->mName = databaseInfo->name;
   db->mFilePath = databaseInfo->filePath;
   databaseInfo.swap(db->mDatabaseInfo);
   db->mASCIIOrigin = aASCIIOrigin;
   db->mFileManager = aFileManager;
 
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -83,17 +83,19 @@ IDBRequest::Create(nsISupports* aSource,
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBRequest> request(new IDBRequest());
 
   request->mSource = aSource;
   request->mTransaction = aTransaction;
   request->mScriptContext = aOwnerCache->GetScriptContext();
   request->mOwner = aOwnerCache->GetOwner();
-  request->mScriptOwner = aOwnerCache->GetScriptOwner();
+  if (!request->SetScriptOwner(aOwnerCache->GetScriptOwner())) {
+    return nsnull;
+  }
 
   return request.forget();
 }
 
 void
 IDBRequest::Reset()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -124,17 +126,17 @@ IDBRequest::NotifyHelperCompleted(Helper
   // If the request failed then set the error code and return.
   if (NS_FAILED(rv)) {
     mErrorCode = NS_ERROR_GET_CODE(rv);
     return NS_OK;
   }
 
   // Otherwise we need to get the result from the helper.
   JSContext* cx;
-  if (mScriptOwner) {
+  if (GetScriptOwner()) {
     nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
     NS_ASSERTION(cxStack, "Failed to get thread context stack!");
 
     if (NS_FAILED(cxStack->GetSafeJSContext(&cx))) {
       NS_WARNING("Failed to get safe JSContext!");
       rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       mErrorCode = NS_ERROR_GET_CODE(rv);
       return rv;
@@ -312,17 +314,19 @@ IDBOpenDBRequest::Create(nsIScriptContex
                          nsPIDOMWindow* aOwner,
                          JSObject* aScriptOwner)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBOpenDBRequest> request(new IDBOpenDBRequest());
 
   request->mScriptContext = aScriptContext;
   request->mOwner = aOwner;
-  request->mScriptOwner = aScriptOwner;
+  if (!request->SetScriptOwner(aScriptOwner)) {
+    return nsnull;
+  }
 
   return request.forget();
 }
 
 void
 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
 {
   mTransaction = aTransaction;
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -114,17 +114,19 @@ IDBTransaction::Create(IDBDatabase* aDat
                        bool aDispatchDelayed)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<IDBTransaction> transaction = new IDBTransaction();
 
   transaction->mScriptContext = aDatabase->GetScriptContext();
   transaction->mOwner = aDatabase->GetOwner();
-  transaction->mScriptOwner = aDatabase->GetScriptOwner();
+  if (!transaction->SetScriptOwner(aDatabase->GetScriptOwner())) {
+    return nsnull;
+  }
 
   transaction->mDatabase = aDatabase;
   transaction->mMode = aMode;
   
   transaction->mDatabaseInfo = aDatabase->Info();
 
   if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) {
     NS_ERROR("Out of memory!");
--- a/dom/indexedDB/IDBWrapperCache.cpp
+++ b/dom/indexedDB/IDBWrapperCache.cpp
@@ -1,29 +1,33 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IDBWrapperCache.h"
+#include "nsContentUtils.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBWrapperCache)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBWrapperCache,
                                                   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)
-  tmp->mScriptOwner = nsnull;
+  if (tmp->mScriptOwner) {
+    NS_DROP_JS_OBJECTS(tmp, IDBWrapperCache);
+    tmp->mScriptOwner = nsnull;
+  }
 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.
   if (tmp->mScriptOwner) {
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mScriptOwner,
@@ -31,8 +35,41 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INH
   }
 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);
+  }
+}
+
+bool
+IDBWrapperCache::SetScriptOwner(JSObject* aScriptOwner)
+{
+  if (!aScriptOwner) {
+    NS_ASSERTION(!mScriptOwner,
+                 "Don't null out existing owner, we need to call "
+                 "DropJSObjects!");
+
+    return true;
+  }
+
+  mScriptOwner = aScriptOwner;
+
+  nsISupports* thisSupports = NS_CYCLE_COLLECTION_UPCAST(this, IDBWrapperCache);
+  nsXPCOMCycleCollectionParticipant* participant;
+  CallQueryInterface(this, &participant);
+  nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("nsContentUtils::HoldJSObjects failed.");
+    mScriptOwner = nsnull;
+    return false;
+  }
+
+  return true;
+}
--- a/dom/indexedDB/IDBWrapperCache.h
+++ b/dom/indexedDB/IDBWrapperCache.h
@@ -20,16 +20,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
                                                    IDBWrapperCache,
                                                    nsDOMEventTargetHelper)
 
   JSObject* GetScriptOwner() const
   {
     return mScriptOwner;
   }
+  bool SetScriptOwner(JSObject* aScriptOwner);
 
   nsIScriptContext* GetScriptContext() const
   {
     return mScriptContext;
   }
 
   nsPIDOMWindow* GetOwner() const
   {
@@ -55,17 +56,17 @@ public:
       nsDOMEventTargetHelper::FromSupports(aSupports));
   }
 
 protected:
   IDBWrapperCache()
   : mScriptOwner(nsnull)
   { }
 
-  virtual ~IDBWrapperCache()
-  { }
+  virtual ~IDBWrapperCache();
 
+private:
   JSObject* mScriptOwner;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbwrappercache_h__