Bug 718132 - IndexedDB: Intermittent Failing to get JS wrapper in IDBRequest::NotifyHelperCompleted. r=khuey.
☠☠ backed out by aa713a50f435 ☠ ☠
authorBen Turner <bent.mozilla@gmail.com>
Mon, 23 Jan 2012 06:03:41 -0800
changeset 87560 8886b027527ab9c4f0dff28c81321a65f5370e96
parent 87559 143f01714f2b68424d930a6619c61c62a61381a9
child 87561 551030e6e380b57a31be28b5ce62d4dea6e9a337
push id674
push userffxbld
push dateTue, 13 Mar 2012 21:17:50 +0000
treeherdermozilla-beta@e3c4c92dec31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs718132
milestone12.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 718132 - IndexedDB: Intermittent Failing to get JS wrapper in IDBRequest::NotifyHelperCompleted. r=khuey.
content/base/src/nsContentUtils.cpp
dom/base/nsDOMClassInfo.cpp
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBIndex.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBRequest.h
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBTransaction.h
dom/indexedDB/IDBWrapperCache.cpp
dom/indexedDB/IDBWrapperCache.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/Makefile.in
dom/indexedDB/OpenDatabaseHelper.cpp
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5449,18 +5449,19 @@ public:
   {
   }
   NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void* root,
                              nsCycleCollectionParticipant* helper)
   {
   }
   NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void* child)
   {
-    if (langID == nsIProgrammingLanguage::JAVASCRIPT) {
-      mFound = child == mWrapper;
+    if (langID == nsIProgrammingLanguage::JAVASCRIPT &&
+        child == mWrapper) {
+      mFound = true;
     }
   }
   NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child)
   {
   }
   NS_IMETHOD_(void) NoteNativeChild(void* child,
                                     nsCycleCollectionParticipant* helper)
   {
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -485,27 +485,30 @@
 #include "nsHTMLLegendElement.h"
 
 #include "DOMSVGLengthList.h"
 #include "DOMSVGNumberList.h"
 #include "DOMSVGPathSegList.h"
 #include "DOMSVGPointList.h"
 #include "DOMSVGTransformList.h"
 
+#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/indexedDB/IDBRequest.h"
 #include "mozilla/dom/indexedDB/IDBDatabase.h"
 #include "mozilla/dom/indexedDB/IDBEvents.h"
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
 #include "mozilla/dom/indexedDB/IDBTransaction.h"
 #include "mozilla/dom/indexedDB/IDBCursor.h"
 #include "mozilla/dom/indexedDB/IDBKeyRange.h"
 #include "mozilla/dom/indexedDB/IDBIndex.h"
 #include "nsIIDBDatabaseException.h"
 
+using mozilla::dom::indexedDB::IDBWrapperCache;
+
 #include "nsIDOMMediaQueryList.h"
 
 #include "nsDOMTouchEvent.h"
 #include "nsIDOMCustomEvent.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "dombindings.h"
 
@@ -590,16 +593,20 @@ static const char kDOMStringBundleURL[] 
    nsIXPCScriptable::WANT_DELPROPERTY |                                       \
    nsIXPCScriptable::WANT_SETPROPERTY |                                       \
    nsIXPCScriptable::WANT_GETPROPERTY)
 
 #define EVENTTARGET_SCRIPTABLE_FLAGS                                          \
   (DOM_DEFAULT_SCRIPTABLE_FLAGS       |                                       \
    nsIXPCScriptable::WANT_ADDPROPERTY)
 
+#define IDBEVENTTARGET_SCRIPTABLE_FLAGS                                       \
+  (EVENTTARGET_SCRIPTABLE_FLAGS |                                             \
+   nsIXPCScriptable::WANT_POSTCREATE)
+
 #define DOMCLASSINFO_STANDARD_FLAGS                                           \
   (nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::DOM_OBJECT)
 
 
 #ifdef NS_DEBUG
 #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class)                                \
     eDOMClassInfo_##_class##_id,
 #else
@@ -651,16 +658,47 @@ DOMCI_DATA(DOMConstructor, void)
 
 #define NS_DEFINE_CLASSINFO_DATA(_class, _helper, _flags)                     \
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, _flags)
 
 #define NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(_class, _helper, _flags)          \
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA_WITH_NAME(_class, _class, _helper, \
                                                  _flags)
 
+namespace {
+
+class IDBEventTargetSH : public nsEventTargetSH
+{
+protected:
+  IDBEventTargetSH(nsDOMClassInfoData* aData) : nsEventTargetSH(aData)
+  { }
+
+  virtual ~IDBEventTargetSH()
+  { }
+
+public:
+  NS_IMETHOD PreCreate(nsISupports *aNativeObj, JSContext *aCx,
+                       JSObject *aGlobalObj, JSObject **aParentObj);
+
+  NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *aQrapper, JSContext *aCx,
+                        JSObject *aObj);
+
+  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
+
 // This list of NS_DEFINE_CLASSINFO_DATA macros is what gives the DOM
 // classes their correct behavior when used through XPConnect. The
 // arguments that are passed to NS_DEFINE_CLASSINFO_DATA are
 //
 // 1. Class name as it should appear in JavaScript, this name is also
 //    used to find the id of the class in nsDOMClassInfo
 //    (i.e. e<classname>_id)
 // 2. Scriptable helper class
@@ -1534,36 +1572,36 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(WebSocket, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CloseEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(IDBFactory, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBRequest, nsEventTargetSH,
-                           EVENTTARGET_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBDatabase, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(IDBRequest, IDBEventTargetSH,
+                           IDBEVENTTARGET_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(IDBDatabase, IDBEventTargetSH,
+                           IDBEVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBObjectStore, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBTransaction, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(IDBTransaction, IDBEventTargetSH,
+                           IDBEVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBCursor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBCursorWithValue, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBKeyRange, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBIndex, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, IDBEventTargetSH,
+                           IDBEVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBDatabaseException, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(Touch, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMTouchListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TouchEvent, nsDOMGenericSH,
@@ -7616,16 +7654,56 @@ nsEventTargetSH::AddProperty(nsIXPConnec
 void
 nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
 {
   nsDOMEventTargetWrapperCache *target =
     nsDOMEventTargetWrapperCache::FromSupports(aNative);
   nsContentUtils::PreserveWrapper(aNative, target);
 }
 
+// IDBEventTarget helper
+
+NS_IMETHODIMP
+IDBEventTargetSH::PreCreate(nsISupports *aNativeObj, JSContext *aCx,
+                            JSObject *aGlobalObj, JSObject **aParentObj)
+{
+  IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNativeObj);
+  JSObject *parent = target->GetParentObject();
+  *aParentObj = parent ? parent : aGlobalObj;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IDBEventTargetSH::PostCreate(nsIXPConnectWrappedNative *aWrapper,
+                             JSContext *aCx, JSObject *aObj)
+{
+  IDBWrapperCache *target = IDBWrapperCache::FromSupports(aWrapper->Native());
+  target->OnWrapperCreated();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IDBEventTargetSH::AddProperty(nsIXPConnectWrappedNative *aWrapper,
+                              JSContext *aCx, JSObject *aObj, jsid aId,
+                              jsval *aVp, bool *aRetval)
+{
+  if (aId == sAddEventListener_id) {
+    return nsEventTargetSH::AddProperty(aWrapper, aCx, aObj, aId, aVp, aRetval);
+  }
+
+  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
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -141,28 +141,21 @@ HelperBase::WrapNative(JSContext* aCx,
                        nsISupports* aNative,
                        jsval* aResult)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aNative, "Null pointer!");
   NS_ASSERTION(aResult, "Null pointer!");
   NS_ASSERTION(mRequest, "Null request!");
 
-  JSObject* obj;
-  if (mRequest->ScriptContext()) {
-    obj = mRequest->ScriptContext()->GetNativeGlobal();
-  }
-  else {
-    obj = mRequest->GetWrapper();
-  }
-
-  NS_ENSURE_TRUE(obj, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  JSObject* global = mRequest->GetParentObject();
+  NS_ASSERTION(global, "This should never be null!");
 
   nsresult rv =
-    nsContentUtils::WrapNative(aCx, obj, aNative, aResult);
+    nsContentUtils::WrapNative(aCx, global, aNative, aResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 void
 HelperBase::ReleaseMainThreadObjects()
 {
@@ -283,17 +276,17 @@ AsyncConnectionHelper::Run()
     if (NS_SUCCEEDED(rv)) {
       setProgressHandler = true;
     }
   }
 
   if (NS_SUCCEEDED(rv)) {
     bool hasSavepoint = false;
     if (mDatabase) {
-      IndexedDatabaseManager::SetCurrentWindow(mDatabase->Owner());
+      IndexedDatabaseManager::SetCurrentWindow(mDatabase->GetOwner());
 
       // Make the first savepoint.
       if (mTransaction) {
         if (!(hasSavepoint = mTransaction->StartSavepoint())) {
           NS_WARNING("Failed to make savepoint!");
         }
       }
     }
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -59,18 +59,17 @@ USING_INDEXEDDB_NAMESPACE
 namespace {
 
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBCursor* aCursor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   IDBDatabase* database = aCursor->Transaction()->Database();
-  return IDBRequest::Create(aCursor, database->ScriptContext(),
-                            database->Owner(), aCursor->Transaction());
+  return IDBRequest::Create(aCursor, database, aCursor->Transaction());
 }
 
 } // anonymous namespace
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class ContinueHelper : public AsyncConnectionHelper
 {
@@ -257,31 +256,35 @@ IDBCursor::CreateCommon(IDBRequest* aReq
   NS_ASSERTION(aRequest, "Null pointer!");
   NS_ASSERTION(aTransaction, "Null pointer!");
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(!aContinueQuery.IsEmpty(), "Empty query!");
   NS_ASSERTION(!aContinueToQuery.IsEmpty(), "Empty query!");
 
   nsRefPtr<IDBCursor> cursor = new IDBCursor();
 
+  IDBDatabase* database = aTransaction->Database();
+  cursor->mScriptContext = database->GetScriptContext();
+  cursor->mOwner = database->GetOwner();
+  cursor->mScriptOwner = database->GetScriptOwner();
+
   cursor->mRequest = aRequest;
   cursor->mTransaction = aTransaction;
   cursor->mObjectStore = aObjectStore;
-  cursor->mScriptContext = aTransaction->Database()->ScriptContext();
-  cursor->mOwner = aTransaction->Database()->Owner();
   cursor->mDirection = aDirection;
   cursor->mContinueQuery = aContinueQuery;
   cursor->mContinueToQuery = aContinueToQuery;
   cursor->mRangeKey = aRangeKey;
 
   return cursor.forget();
 }
 
 IDBCursor::IDBCursor()
-: mType(OBJECTSTORE),
+: mScriptOwner(nsnull),
+  mType(OBJECTSTORE),
   mDirection(nsIIDBCursor::NEXT),
   mCachedKey(JSVAL_VOID),
   mCachedPrimaryKey(JSVAL_VOID),
   mCachedValue(JSVAL_VOID),
   mHaveCachedKey(false),
   mHaveCachedPrimaryKey(false),
   mHaveCachedValue(false),
   mRooted(false),
@@ -372,16 +375,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
   NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
                "Should have a cached key");
   NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
                JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
                "Should have a cached primary key");
   NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
                "Should have a cached value");
+  if (tmp->mScriptOwner) {
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mScriptOwner,
+                                               "mScriptOwner")
+  }
   if (JSVAL_IS_GCTHING(tmp->mCachedKey)) {
     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedKey);
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedKey")
   }
   if (JSVAL_IS_GCTHING(tmp->mCachedPrimaryKey)) {
     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedPrimaryKey);
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedPrimaryKey")
   }
@@ -390,16 +397,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDB
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "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 = nsnull;
     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;
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -149,16 +149,17 @@ protected:
 
   nsRefPtr<IDBRequest> mRequest;
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBIndex> mIndex;
 
   nsCOMPtr<nsIScriptContext> mScriptContext;
   nsCOMPtr<nsPIDOMWindow> mOwner;
+  JSObject* mScriptOwner;
 
   Type mType;
   PRUint16 mDirection;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
 
   // These are cycle-collected!
   jsval mCachedKey;
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -143,32 +143,32 @@ private:
   DatabaseInfo* mInfo;
   nsString mName;
 };
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBDatabase>
-IDBDatabase::Create(nsIScriptContext* aScriptContext,
-                    nsPIDOMWindow* aOwner,
+IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
                     already_AddRefed<DatabaseInfo> aDatabaseInfo,
                     const nsACString& aASCIIOrigin,
                     FileManager* aFileManager)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
 
   nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
   NS_ASSERTION(databaseInfo, "Null pointer!");
 
   nsRefPtr<IDBDatabase> db(new IDBDatabase());
 
-  db->mScriptContext = aScriptContext;
-  db->mOwner = aOwner;
+  db->mScriptContext = aOwnerCache->GetScriptContext();
+  db->mOwner = aOwnerCache->GetOwner();
+  db->mScriptOwner = aOwnerCache->GetScriptOwner();
 
   db->mDatabaseId = databaseInfo->id;
   db->mName = databaseInfo->name;
   db->mFilePath = databaseInfo->filePath;
   databaseInfo.swap(db->mDatabaseInfo);
   db->mASCIIOrigin = aASCIIOrigin;
   db->mFileManager = aFileManager;
 
@@ -200,30 +200,32 @@ 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!");
 
   // Make sure we're closed too.
   Close();
 
   // When the IndexedDatabaseManager needs to invalidate databases, all it has
   // is an origin, so we call back into the manager to cancel any prompts for
   // our owner.
-  IndexedDatabaseManager::CancelPromptsForWindow(Owner());
+  IndexedDatabaseManager::CancelPromptsForWindow(GetOwner());
 
   mInvalidated = true;
 }
 
 bool
 IDBDatabase::IsInvalidated()
 {
   return !!mInvalidated;
@@ -275,17 +277,18 @@ IDBDatabase::ExitSetVersionTransaction()
   NS_ASSERTION(mRunningVersionChange, "How did that happen?");
   mRunningVersionChange = false;
 }
 
 void
 IDBDatabase::OnUnlink()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(!mOwner, "Should have been cleared already!");
+  NS_ASSERTION(!GetOwner() && !GetScriptOwner(),
+               "Should have been cleared already!");
 
   // We've been unlinked, at the very least we should be able to prevent further
   // transactions from starting and unblock any other SetVersion callers.
   CloseInternal(true);
 
   // No reason for the IndexedDatabaseManager to track us any longer.
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   if (mgr) {
@@ -293,43 +296,45 @@ IDBDatabase::OnUnlink()
 
     // Don't try to unregister again in the destructor.
     mRegistered = false;
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase,
-                                                  nsDOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnAbortListener)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnVersionChangeListener)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(versionchange)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase,
-                                                nsDOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnAbortListener)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnVersionChangeListener)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(versionchange)
 
   // Do some cleanup.
   tmp->OnUnlink();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
   NS_INTERFACE_MAP_ENTRY(nsIIDBDatabase)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBDatabase)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
 
-NS_IMPL_ADDREF_INHERITED(IDBDatabase, nsDOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(IDBDatabase, nsDOMEventTargetHelper)
+NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
+NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
 
 DOMCI_DATA(IDBDatabase, IDBDatabase)
 
+NS_IMPL_EVENT_HANDLER(IDBDatabase, abort);
+NS_IMPL_EVENT_HANDLER(IDBDatabase, error);
+NS_IMPL_EVENT_HANDLER(IDBDatabase, versionchange);
+
 NS_IMETHODIMP
 IDBDatabase::GetName(nsAString& aName)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   aName.Assign(mName);
   return NS_OK;
 }
 
@@ -663,57 +668,16 @@ IDBDatabase::Close()
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   CloseInternal(false);
 
   NS_ASSERTION(mClosed, "Should have set the closed flag!");
   return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBDatabase::SetOnabort(nsIDOMEventListener* aAbortListener)
-{
-  return RemoveAddEventListener(NS_LITERAL_STRING(ABORT_EVT_STR),
-                                mOnAbortListener, aAbortListener);
-}
-
-NS_IMETHODIMP
-IDBDatabase::GetOnabort(nsIDOMEventListener** aAbortListener)
-{
-  return GetInnerEventListener(mOnAbortListener, aAbortListener);
-}
-
-NS_IMETHODIMP
-IDBDatabase::SetOnerror(nsIDOMEventListener* aErrorListener)
-{
-  return RemoveAddEventListener(NS_LITERAL_STRING(ERROR_EVT_STR),
-                                mOnErrorListener, aErrorListener);
-}
-
-NS_IMETHODIMP
-IDBDatabase::GetOnerror(nsIDOMEventListener** aErrorListener)
-{
-  return GetInnerEventListener(mOnErrorListener, aErrorListener);
-}
-
-NS_IMETHODIMP
-IDBDatabase::SetOnversionchange(nsIDOMEventListener* aVersionChangeListener)
-{
-  return RemoveAddEventListener(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR),
-                                mOnVersionChangeListener,
-                                aVersionChangeListener);
-}
-
-NS_IMETHODIMP
-IDBDatabase::GetOnversionchange(nsIDOMEventListener** aVersionChangeListener)
-{
-  return GetInnerEventListener(mOnVersionChangeListener,
-                               aVersionChangeListener);
-}
-
 nsresult
 IDBDatabase::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
 
   if (!mOwner) {
     return NS_OK;
   }
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -36,52 +36,49 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbdatabase_h__
 #define mozilla_dom_indexeddb_idbdatabase_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
-#include "mozilla/dom/indexedDB/FileManager.h"
 
+#include "nsIDocument.h"
 #include "nsIIDBDatabase.h"
 
-#include "nsCycleCollectionParticipant.h"
-#include "nsDOMEventTargetHelper.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
+#include "mozilla/dom/indexedDB/FileManager.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 struct DatabaseInfo;
 class IDBIndex;
 class IDBObjectStore;
 class IDBTransaction;
 class IndexedDatabaseManager;
 
-class IDBDatabase : public nsDOMEventTargetHelper,
+class IDBDatabase : public IDBWrapperCache,
                     public nsIIDBDatabase
 {
   friend class AsyncConnectionHelper;
   friend class IndexedDatabaseManager;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBDATABASE
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase,
-                                           nsDOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBDatabase, IDBWrapperCache)
 
   static already_AddRefed<IDBDatabase>
-  Create(nsIScriptContext* aScriptContext,
-         nsPIDOMWindow* aOwner,
+  Create(IDBWrapperCache* aOwnerCache,
          already_AddRefed<DatabaseInfo> aDatabaseInfo,
          const nsACString& aASCIIOrigin,
          FileManager* aFileManager);
 
   // nsIDOMEventTarget
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
 
   nsIAtom* Id() const
@@ -99,26 +96,16 @@ public:
     return mName;
   }
 
   const nsString& FilePath()
   {
     return mFilePath;
   }
 
-  nsIScriptContext* ScriptContext()
-  {
-    return mScriptContext;
-  }
-
-  nsPIDOMWindow* Owner()
-  {
-    return mOwner;
-  }
-
   already_AddRefed<nsIDocument> GetOwnerDocument()
   {
     if (!mOwner) {
       return nsnull;
     }
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOwner->GetExtantDocument());
     return doc.forget();
@@ -163,16 +150,16 @@ private:
   PRInt32 mInvalidated;
   bool mRegistered;
   bool mClosed;
   bool mRunningVersionChange;
 
   nsRefPtr<FileManager> mFileManager;
 
   // Only touched on the main thread.
-  nsRefPtr<nsDOMEventListenerWrapper> mOnAbortListener;
-  nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
-  nsRefPtr<nsDOMEventListenerWrapper> mOnVersionChangeListener;
+  NS_DECL_EVENT_HANDLER(abort);
+  NS_DECL_EVENT_HANDLER(error);
+  NS_DECL_EVENT_HANDLER(versionchange);
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbdatabase_h__
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -64,17 +64,16 @@
 #include "AsyncConnectionHelper.h"
 #include "CheckPermissionsHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IndexedDatabaseManager.h"
 #include "Key.h"
-#include "nsIScriptSecurityManager.h"
 
 using namespace mozilla;
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 GeckoProcessType gAllowedProcessType = GeckoProcessType_Invalid;
@@ -86,38 +85,59 @@ struct ObjectStoreInfoMap
 
   PRInt64 id;
   ObjectStoreInfo* info;
 };
 
 } // anonymous namespace
 
 IDBFactory::IDBFactory()
+: mOwningObject(nsnull)
 {
   IDBFactory::NoteUsedByProcessType(XRE_GetProcessType());
 }
 
+IDBFactory::~IDBFactory()
+{
+  if (mOwningObject) {
+    NS_DROP_JS_OBJECTS(this, IDBFactory);
+  }
+}
+
 // static
 already_AddRefed<nsIIDBFactory>
 IDBFactory::Create(nsPIDOMWindow* aWindow)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (aWindow && aWindow->IsOuterWindow()) {
+  NS_ENSURE_TRUE(aWindow, nsnull);
+
+  if (aWindow->IsOuterWindow()) {
     aWindow = aWindow->GetCurrentInnerWindow();
     NS_ENSURE_TRUE(aWindow, nsnull);
   }
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
+  factory->mWindow = aWindow;
+  return factory.forget();
+}
 
-  if (aWindow) {
-    factory->mWindow = do_GetWeakReference(aWindow);
-    NS_ENSURE_TRUE(factory->mWindow, nsnull);
-  }
+// static
+already_AddRefed<nsIIDBFactory>
+IDBFactory::Create(JSContext* aCx,
+                   JSObject* aOwningObject)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aCx, "Null context!");
+  NS_ASSERTION(aOwningObject, "Null object!");
+  NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
+               "Not a global object!");
 
+  nsRefPtr<IDBFactory> factory = new IDBFactory();
+  factory->mOwningObject = aOwningObject;
   return factory.forget();
 }
 
 // static
 already_AddRefed<mozIStorageConnection>
 IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
 {
   NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")),
@@ -395,65 +415,90 @@ IDBFactory::SetDatabaseMetadata(Database
       NS_WARNING("Out of memory!");
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   return NS_OK;
 }
 
-NS_IMPL_ADDREF(IDBFactory)
-NS_IMPL_RELEASE(IDBFactory)
+NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory)
 
-NS_INTERFACE_MAP_BEGIN(IDBFactory)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIIDBFactory)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBFactory)
 NS_INTERFACE_MAP_END
 
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
+  if (tmp->mOwningObject) {
+    tmp->mOwningObject = nsnull;
+  }
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
+  if (tmp->mOwningObject) {
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mOwningObject,
+                                               "mOwningObject")
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 DOMCI_DATA(IDBFactory, IDBFactory)
 
 nsresult
 IDBFactory::OpenCommon(const nsAString& aName,
                        PRInt64 aVersion,
                        bool aDeleting,
                        nsIIDBOpenDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(mWindow || mOwningObject, "Must have one of these!");
 
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     // Force ContentChild to cache the path from the parent, so that
     // we do not end up in a side thread that asks for the path (which
     // would make ContentChild try to send a message in a thread other
     // than the main one).
     ContentChild::GetSingleton()->GetIndexedDBPath();
   }
 
   nsCOMPtr<nsPIDOMWindow> window;
   nsCOMPtr<nsIScriptGlobalObject> sgo;
   nsIScriptContext* context = nsnull;
+  JSObject* scriptOwner = nsnull;
 
   if (mWindow) {
-    window = do_QueryReferent(mWindow);
-    NS_ENSURE_TRUE(window, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-    
-    sgo = do_QueryInterface(window);
+    sgo = do_QueryInterface(mWindow);
     NS_ENSURE_TRUE(sgo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-    
+
     context = sgo->GetContext();
     NS_ENSURE_TRUE(context, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    window = mWindow;
+  }
+  else {
+    scriptOwner = mOwningObject;
   }
 
   nsCString origin;
   nsresult rv =
     IndexedDatabaseManager::GetASCIIOriginFromWindow(window, origin);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<IDBOpenDBRequest> request =
-    IDBOpenDBRequest::Create(context, window);
+    IDBOpenDBRequest::Create(context, window, scriptOwner);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenDatabaseHelper> openHelper =
     new OpenDatabaseHelper(request, aName, origin, aVersion, aDeleting);
 
   rv = openHelper->Init();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -40,37 +40,42 @@
 #ifndef mozilla_dom_indexeddb_idbfactory_h__
 #define mozilla_dom_indexeddb_idbfactory_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "mozIStorageConnection.h"
 #include "nsIIDBFactory.h"
 
-#include "nsIWeakReferenceUtils.h"
+#include "nsCycleCollectionParticipant.h"
 #include "nsXULAppAPI.h"
 
+class nsIAtom;
 class nsPIDOMWindow;
-class nsIAtom;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo;
 class IDBDatabase;
 struct ObjectStoreInfo;
 
 class IDBFactory : public nsIIDBFactory
 {
   typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
+
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBFactory)
   NS_DECL_NSIIDBFACTORY
 
   static already_AddRefed<nsIIDBFactory> Create(nsPIDOMWindow* aWindow);
 
+  static already_AddRefed<nsIIDBFactory> Create(JSContext* aCx,
+                                                JSObject* aOwningObject);
+
   static already_AddRefed<mozIStorageConnection>
   GetConnection(const nsAString& aDatabaseFilePath);
 
   // Called when a process uses an IndexedDB factory. We only allow
   // a single process type to use IndexedDB - the chrome/single process
   // in Firefox, and the child process in Fennec - so access by more
   // than one process type is a very serious error.
   static void
@@ -91,22 +96,25 @@ public:
 
   static nsresult
   SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
                       PRUint64 aVersion,
                       ObjectStoreInfoArray& aObjectStores);
 
 private:
   IDBFactory();
-  ~IDBFactory() { }
+  ~IDBFactory();
 
   nsresult
   OpenCommon(const nsAString& aName,
              PRInt64 aVersion,
              bool aDeleting,
              nsIIDBOpenDBRequest** _retval);
 
-  nsCOMPtr<nsIWeakReference> mWindow;
+  // If this factory lives on a window then mWindow must be non-null. Otherwise
+  // mOwningObject must be non-null.
+  nsCOMPtr<nsPIDOMWindow> mWindow;
+  JSObject* mOwningObject;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbfactory_h__
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -289,18 +289,17 @@ private:
 
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBIndex* aIndex)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   IDBTransaction* transaction = aIndex->ObjectStore()->Transaction();
   IDBDatabase* database = transaction->Database();
-  return IDBRequest::Create(aIndex, database->ScriptContext(),
-                            database->Owner(), transaction);
+  return IDBRequest::Create(aIndex, database, transaction);
 }
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBIndex>
 IDBIndex::Create(IDBObjectStore* aObjectStore,
                  const IndexInfo* aIndexInfo)
@@ -308,19 +307,16 @@ IDBIndex::Create(IDBObjectStore* aObject
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(aIndexInfo, "Null pointer!");
 
   IDBDatabase* database = aObjectStore->Transaction()->Database();
 
   nsRefPtr<IDBIndex> index = new IDBIndex();
 
-  index->mScriptContext = database->ScriptContext();
-  index->mOwner = database->Owner();
-
   index->mObjectStore = aObjectStore;
   index->mId = aIndexInfo->id;
   index->mName = aIndexInfo->name;
   index->mKeyPath = aIndexInfo->keyPath;
   index->mKeyPathArray = aIndexInfo->keyPathArray;
   index->mUnique = aIndexInfo->unique;
   index->mMultiEntry = aIndexInfo->multiEntry;
 
@@ -338,24 +334,20 @@ IDBIndex::~IDBIndex()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObjectStore)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex)
   // Don't unlink mObjectStore!
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex)
   NS_INTERFACE_MAP_ENTRY(nsIIDBIndex)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBIndex)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -108,19 +108,16 @@ public:
   }
 
 private:
   IDBIndex();
   ~IDBIndex();
 
   nsRefPtr<IDBObjectStore> mObjectStore;
 
-  nsCOMPtr<nsIScriptContext> mScriptContext;
-  nsCOMPtr<nsPIDOMWindow> mOwner;
-
   PRInt64 mId;
   nsString mName;
   nsString mKeyPath;
   nsTArray<nsString> mKeyPathArray;
   bool mUnique;
   bool mMultiEntry;
 };
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -502,18 +502,18 @@ GetKeyFromValue(JSContext* aCx,
 
 
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBObjectStore* aObjectStore)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   IDBDatabase* database = aObjectStore->Transaction()->Database();
-  return IDBRequest::Create(aObjectStore, database->ScriptContext(),
-                            database->Owner(), aObjectStore->Transaction());
+  return IDBRequest::Create(aObjectStore, database,
+                            aObjectStore->Transaction());
 }
 
 JSClass gDummyPropClass = {
   "dummy", 0,
   JS_PropertyStub,  JS_PropertyStub,
   JS_PropertyStub,  JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub,
   JS_ConvertStub, JS_FinalizeStub,
@@ -527,19 +527,16 @@ already_AddRefed<IDBObjectStore>
 IDBObjectStore::Create(IDBTransaction* aTransaction,
                        ObjectStoreInfo* aStoreInfo,
                        nsIAtom* aDatabaseId)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore();
 
-  objectStore->mScriptContext = aTransaction->Database()->ScriptContext();
-  objectStore->mOwner = aTransaction->Database()->Owner();
-
   objectStore->mTransaction = aTransaction;
   objectStore->mName = aStoreInfo->name;
   objectStore->mId = aStoreInfo->id;
   objectStore->mKeyPath = aStoreInfo->keyPath;
   objectStore->mKeyPathArray = aStoreInfo->keyPathArray;
   objectStore->mAutoIncrement = !!aStoreInfo->nextAutoIncrementId;
   objectStore->mDatabaseId = aDatabaseId;
   objectStore->mInfo = aStoreInfo;
@@ -1371,29 +1368,25 @@ IDBObjectStore::AddOrPut(const jsval& aV
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
                                                        nsIDOMEventTarget)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
 
   for (PRUint32 i = 0; i < tmp->mCreatedIndexes.Length(); i++) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedIndexes[i]");
     cb.NoteXPCOMChild(static_cast<nsIIDBIndex*>(tmp->mCreatedIndexes[i].get()));
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
   // Don't unlink mTransaction!
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
 
   tmp->mCreatedIndexes.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore)
   NS_INTERFACE_MAP_ENTRY(nsIIDBObjectStore)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBObjectStore)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -36,23 +36,24 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbobjectstore_h__
 #define mozilla_dom_indexeddb_idbobjectstore_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
-#include "mozilla/dom/indexedDB/IDBTransaction.h"
 
 #include "nsIIDBObjectStore.h"
 #include "nsIIDBTransaction.h"
 
 #include "nsCycleCollectionParticipant.h"
 
+#include "mozilla/dom/indexedDB/IDBTransaction.h"
+
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 class Key;
 
@@ -199,19 +200,16 @@ protected:
                     JSContext* aCx,
                     PRUint8 aOptionalArgCount,
                     nsIIDBRequest** _retval,
                     bool aOverwrite);
 
 private:
   nsRefPtr<IDBTransaction> mTransaction;
 
-  nsCOMPtr<nsIScriptContext> mScriptContext;
-  nsCOMPtr<nsPIDOMWindow> mOwner;
-
   PRInt64 mId;
   nsString mName;
   nsString mKeyPath;
   nsTArray<nsString> mKeyPathArray;
   bool mAutoIncrement;
   nsCOMPtr<nsIAtom> mDatabaseId;
   nsRefPtr<ObjectStoreInfo> mInfo;
   PRUint32 mStructuredCloneVersion;
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -57,70 +57,63 @@
 #include "IDBEvents.h"
 #include "IDBTransaction.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 IDBRequest::IDBRequest()
 : mResultVal(JSVAL_VOID),
   mErrorCode(0),
-  mResultValRooted(false),
-  mHaveResultOrErrorCode(false)
+  mHaveResultOrErrorCode(false),
+  mManuallyRooted(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBRequest::~IDBRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (mResultValRooted) {
-    // Calling a virtual from the destructor is bad... But we know that we won't
-    // call a subclass' implementation because mResultValRooted will be set to
-    // false.
-    UnrootResultVal();
-  }
+  UnrootResultVal();
 }
 
 // static
 already_AddRefed<IDBRequest>
 IDBRequest::Create(nsISupports* aSource,
-                   nsIScriptContext* aScriptContext,
-                   nsPIDOMWindow* aOwner,
+                   IDBWrapperCache* aOwnerCache,
                    IDBTransaction* aTransaction)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBRequest> request(new IDBRequest());
 
   request->mSource = aSource;
   request->mTransaction = aTransaction;
-  request->mScriptContext = aScriptContext;
-  request->mOwner = aOwner;
+  request->mScriptContext = aOwnerCache->GetScriptContext();
+  request->mOwner = aOwnerCache->GetOwner();
+  request->mScriptOwner = aOwnerCache->GetScriptOwner();
 
   return request.forget();
 }
 
 void
 IDBRequest::Reset()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   mResultVal = JSVAL_VOID;
   mHaveResultOrErrorCode = false;
   mErrorCode = 0;
-  if (mResultValRooted) {
-    UnrootResultVal();
-  }
+  UnrootResultVal();
 }
 
 nsresult
 IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
-  NS_ASSERTION(!mResultValRooted, "Already rooted?!");
+  NS_ASSERTION(!PreservingWrapper(), "Already rooted?!");
   NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
 
   // See if our window is still valid. If not then we're going to pretend that
   // we never completed.
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return NS_OK;
   }
 
@@ -130,81 +123,106 @@ 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 = nsnull;
-  JSObject* obj = nsnull;
-  if (mScriptContext) {   
-    cx = mScriptContext->GetNativeContext();
-    NS_ASSERTION(cx, "Failed to get a context!");
-
-    obj = mScriptContext->GetNativeGlobal();
-    NS_ASSERTION(obj, "Failed to get global object!");
-  } 
-  else {
+  JSContext* cx;
+  if (mScriptOwner) {
     nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
     NS_ASSERTION(cxStack, "Failed to get thread context stack!");
 
-    NS_ENSURE_SUCCESS(cxStack->GetSafeJSContext(&cx),
-                      NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    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;
+    }
+  }
+  else {
+    cx = mScriptContext->GetNativeContext();
+    NS_ASSERTION(cx, "Failed to get a context!");
+  } 
 
-    obj = GetWrapper();
-    NS_ENSURE_TRUE(obj, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  }
+  JSObject* global = GetParentObject();
+  NS_ASSERTION(global, "This should never be null!");
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, obj)) {
-    rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-  else {
+  if (ac.enter(cx, global)) {
     RootResultVal();
 
     rv = aHelper->GetSuccessResult(cx, &mResultVal);
-    if (NS_SUCCEEDED(rv)) {
-      // Unroot if we don't really need to be rooted.
-      if (!JSVAL_IS_GCTHING(mResultVal)) {
-        UnrootResultVal();
-      }
-    }
-    else {
+    if (NS_FAILED(rv)) {
       NS_WARNING("GetSuccessResult failed!");
     }
   }
+  else {
+    NS_WARNING("Failed to enter correct compartment!");
+    rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
 
   if (NS_SUCCEEDED(rv)) {
     mErrorCode = 0;
   }
   else {
     mErrorCode = NS_ERROR_GET_CODE(rv);
     mResultVal = JSVAL_VOID;
   }
 
   return rv;
 }
 
 void
 IDBRequest::RootResultVal()
 {
-  NS_ASSERTION(!mResultValRooted, "This should be false!");
-  NS_HOLD_JS_OBJECTS(this, IDBRequest);
-  mResultValRooted = true;
+  // We want to use the preserved wrapper to keep our result alive, but we don't
+  // always get a wrapper right away. Manually root if we don't have a wrapper.
+  if (!PreservingWrapper() && GetWrapperPreserveColor()) {
+    NS_ASSERTION(!mManuallyRooted, "Should not be manually rooted here!");
+    nsContentUtils::PreserveWrapper(static_cast<nsIDOMEventTarget*>(this),
+                                    this);
+  }
+  else if (!mManuallyRooted) {
+    NS_HOLD_JS_OBJECTS(this, IDBRequest);
+    mManuallyRooted = true;
+  }
 }
 
 void
 IDBRequest::UnrootResultVal()
 {
-  NS_ASSERTION(mResultValRooted, "This should be true!");
-  NS_DROP_JS_OBJECTS(this, IDBRequest);
-  mResultValRooted = false;
+  if (mManuallyRooted) {
+    NS_ASSERTION(!PreservingWrapper(), "Shouldn't have a wrapper here!");
+    NS_DROP_JS_OBJECTS(this, IDBRequest);
+    mManuallyRooted = false;
+  }
+  else if (PreservingWrapper()) {
+    nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this);
+  }
+}
+
+void
+IDBRequest::OnWrapperCreated()
+{
+  NS_ASSERTION(!PreservingWrapper(),
+               "Shouldn't have had a wrapper before now!");
+
+  // Update our rooting strategy to accommodate new wrapper if needed. We have
+  // to unroot the old way first. This is annoying because XPConnect uses a hash
+  // table to store these so we could be just fine adding an entry for a second
+  // time... However nsContentUtils keeps a counter that will get out of sync if
+  // we do. Safest to just remove the old holder and then add a new one.
+  if (mManuallyRooted) {
+    UnrootResultVal();
+    RootResultVal();
+  }
 }
 
 NS_IMETHODIMP
 IDBRequest::GetReadyState(PRUint16* aReadyState)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   *aReadyState = mHaveResultOrErrorCode ?
@@ -257,165 +275,118 @@ IDBRequest::GetErrorCode(PRUint16* aErro
     // XXX Need a real error code here.
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   *aErrorCode = mErrorCode;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBRequest::SetOnsuccess(nsIDOMEventListener* aSuccessListener)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return RemoveAddEventListener(NS_LITERAL_STRING(SUCCESS_EVT_STR),
-                                mOnSuccessListener, aSuccessListener);
-}
-
-NS_IMETHODIMP
-IDBRequest::GetOnsuccess(nsIDOMEventListener** aSuccessListener)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return GetInnerEventListener(mOnSuccessListener, aSuccessListener);
-}
-
-NS_IMETHODIMP
-IDBRequest::SetOnerror(nsIDOMEventListener* aErrorListener)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return RemoveAddEventListener(NS_LITERAL_STRING(ERROR_EVT_STR),
-                                mOnErrorListener, aErrorListener);
-}
-
-NS_IMETHODIMP
-IDBRequest::GetOnerror(nsIDOMEventListener** aErrorListener)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return GetInnerEventListener(mOnErrorListener, aErrorListener);
-}
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
-                                                  nsDOMEventTargetWrapperCache)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnSuccessListener)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
+  // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
+  // nsDOMEventTargetHelper does it for us.
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
                                                        nsPIDOMEventTarget)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
-                                                nsDOMEventTargetWrapperCache)
-  if (tmp->mResultValRooted) {
-    tmp->mResultVal = JSVAL_VOID;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
+  tmp->mResultVal = JSVAL_VOID;
+  if (tmp->mManuallyRooted) {
     tmp->UnrootResultVal();
   }
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnSuccessListener)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest,
-                                               nsDOMEventTargetWrapperCache)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
+  // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
+  // nsDOMEventTargetHelper does it for us.
   if (JSVAL_IS_GCTHING(tmp->mResultVal)) {
     void *gcThing = JSVAL_TO_GCTHING(tmp->mResultVal);
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResultVal")
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
   NS_INTERFACE_MAP_ENTRY(nsIIDBRequest)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBRequest)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
 
-NS_IMPL_ADDREF_INHERITED(IDBRequest, nsDOMEventTargetWrapperCache)
-NS_IMPL_RELEASE_INHERITED(IDBRequest, nsDOMEventTargetWrapperCache)
+NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
+NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
 
 DOMCI_DATA(IDBRequest, IDBRequest)
 
+NS_IMPL_EVENT_HANDLER(IDBRequest, success);
+NS_IMPL_EVENT_HANDLER(IDBRequest, error);
+
 nsresult
 IDBRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   aVisitor.mCanHandle = true;
   aVisitor.mParentTarget = mTransaction;
   return NS_OK;
 }
 
 IDBOpenDBRequest::~IDBOpenDBRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (mResultValRooted) {
-    UnrootResultVal();
-  }
+  UnrootResultVal();
 }
 
 // static
 already_AddRefed<IDBOpenDBRequest>
 IDBOpenDBRequest::Create(nsIScriptContext* aScriptContext,
-                         nsPIDOMWindow* aOwner)
+                         nsPIDOMWindow* aOwner,
+                         JSObject* aScriptOwner)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBOpenDBRequest> request(new IDBOpenDBRequest());
 
   request->mScriptContext = aScriptContext;
   request->mOwner = aOwner;
+  request->mScriptOwner = aScriptOwner;
 
   return request.forget();
 }
 
 void
 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
 {
   mTransaction = aTransaction;
 }
 
-void
-IDBOpenDBRequest::RootResultVal()
-{
-  NS_ASSERTION(!mResultValRooted, "This should be false!");
-  NS_HOLD_JS_OBJECTS(this, IDBOpenDBRequest);
-  mResultValRooted = true;
-}
-
-void
-IDBOpenDBRequest::UnrootResultVal()
-{
-  NS_ASSERTION(mResultValRooted, "This should be true!");
-  NS_DROP_JS_OBJECTS(this, IDBOpenDBRequest);
-  mResultValRooted = false;
-}
-
-NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked)
-NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded)
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
                                                   IDBRequest)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnupgradeneededListener)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnblockedListener)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(upgradeneeded)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(blocked)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
                                                 IDBRequest)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnupgradeneededListener)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnblockedListener)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(upgradeneeded)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(blocked)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
   NS_INTERFACE_MAP_ENTRY(nsIIDBOpenDBRequest)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBOpenDBRequest)
 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
 
 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
 
 DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest)
+
+NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked);
+NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded);
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -41,40 +41,38 @@
 #ifndef mozilla_dom_indexeddb_idbrequest_h__
 #define mozilla_dom_indexeddb_idbrequest_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "nsIIDBRequest.h"
 #include "nsIIDBOpenDBRequest.h"
 
-#include "nsDOMEventTargetWrapperCache.h"
-#include "nsCycleCollectionParticipant.h"
+#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class HelperBase;
 class IDBTransaction;
 
-class IDBRequest : public nsDOMEventTargetWrapperCache,
+class IDBRequest : public IDBWrapperCache,
                    public nsIIDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBREQUEST
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest,
-                                                         nsDOMEventTargetWrapperCache)
+                                                         IDBWrapperCache)
 
   static
   already_AddRefed<IDBRequest> Create(nsISupports* aSource,
-                                      nsIScriptContext* aScriptContext,
-                                      nsPIDOMWindow* aOwner,
+                                      IDBWrapperCache* aOwnerCache,
                                       IDBTransaction* aTransaction);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   nsISupports* Source()
   {
     return mSource;
@@ -87,68 +85,66 @@ public:
   void SetError(nsresult rv)
   {
     NS_ASSERTION(NS_FAILED(rv), "Er, what?");
     NS_ASSERTION(mErrorCode == NS_OK, "Already have an error?");
 
     mErrorCode = rv;
   }
 
-  nsIScriptContext* ScriptContext()
-  {
-    return mScriptContext;
-  }
+  void RootResultVal();
+  void UnrootResultVal();
 
-  nsPIDOMWindow* Owner()
-  {
-    return mOwner;
-  }
-
-  virtual void RootResultVal();
-  virtual void UnrootResultVal();
+  virtual void OnWrapperCreated();
 
 protected:
   IDBRequest();
   ~IDBRequest();
 
   nsCOMPtr<nsISupports> mSource;
   nsRefPtr<IDBTransaction> mTransaction;
 
-  nsRefPtr<nsDOMEventListenerWrapper> mOnSuccessListener;
-  nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
+  NS_DECL_EVENT_HANDLER(success);
+  NS_DECL_EVENT_HANDLER(error);
 
   jsval mResultVal;
 
   PRUint16 mErrorCode;
-  bool mResultValRooted;
   bool mHaveResultOrErrorCode;
+  bool mManuallyRooted;
 };
 
 class IDBOpenDBRequest : public IDBRequest,
                          public nsIIDBOpenDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
   NS_DECL_NSIIDBOPENDBREQUEST
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest,
-                                           IDBRequest)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest, IDBRequest)
 
   static
   already_AddRefed<IDBOpenDBRequest>
   Create(nsIScriptContext* aScriptContext,
-         nsPIDOMWindow* aOwner);
+         nsPIDOMWindow* aOwner,
+         JSObject* aScriptOwner);
+
+  static
+  already_AddRefed<IDBOpenDBRequest>
+  Create(IDBWrapperCache* aOwnerCache)
+  {
+    return Create(aOwnerCache->GetScriptContext(), aOwnerCache->GetOwner(),
+                  aOwnerCache->GetScriptOwner());
+  }
 
   void SetTransaction(IDBTransaction* aTransaction);
 
-  virtual void RootResultVal();
-  virtual void UnrootResultVal();
-
 protected:
   ~IDBOpenDBRequest();
 
-  nsRefPtr<nsDOMEventListenerWrapper> mOnblockedListener;
-  nsRefPtr<nsDOMEventListenerWrapper> mOnupgradeneededListener;
+  // Only touched on the main thread.
+  NS_DECL_EVENT_HANDLER(blocked);
+  NS_DECL_EVENT_HANDLER(upgradeneeded);
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbrequest_h__
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -37,16 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBTransaction.h"
 
 #include "nsIScriptContext.h"
 
 #include "mozilla/storage.h"
+#include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMLists.h"
 #include "nsEventDispatcher.h"
 #include "nsPIDOMWindow.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
@@ -111,18 +112,19 @@ IDBTransaction::Create(IDBDatabase* aDat
                        nsTArray<nsString>& aObjectStoreNames,
                        PRUint16 aMode,
                        bool aDispatchDelayed)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<IDBTransaction> transaction = new IDBTransaction();
 
-  transaction->mScriptContext = aDatabase->ScriptContext();
-  transaction->mOwner = aDatabase->Owner();
+  transaction->mScriptContext = aDatabase->GetScriptContext();
+  transaction->mOwner = aDatabase->GetOwner();
+  transaction->mScriptOwner = aDatabase->GetScriptOwner();
 
   transaction->mDatabase = aDatabase;
   transaction->mMode = aMode;
   
   transaction->mDatabaseInfo = aDatabase->Info();
 
   if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) {
     NS_ERROR("Out of memory!");
@@ -179,16 +181,18 @@ IDBTransaction::IDBTransaction()
 IDBTransaction::~IDBTransaction()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mPendingRequests, "Should have no pending requests here!");
   NS_ASSERTION(!mSavepointCount, "Should have released them all!");
   NS_ASSERTION(!mConnection, "Should have called CommitOrRollback!");
   NS_ASSERTION(!mCreating, "Should have been cleared already!");
   NS_ASSERTION(mFiredCompleteOrAbort, "Should have fired event!");
+
+  nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this);
 }
 
 void
 IDBTransaction::OnNewRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   if (!mPendingRequests) {
     NS_ASSERTION(mReadyState == nsIIDBTransaction::INITIAL,
@@ -469,53 +473,55 @@ void
 IDBTransaction::ClearCreatedFileInfos()
 {
   mCreatedFileInfos.Clear();
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBTransaction)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBTransaction,
-                                                  nsDOMEventTargetHelper)
+                                                  IDBWrapperCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mDatabase,
                                                        nsIDOMEventTarget)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnCompleteListener)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnAbortListener)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(complete)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort)
 
   for (PRUint32 i = 0; i < tmp->mCreatedObjectStores.Length(); i++) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedObjectStores[i]");
     cb.NoteXPCOMChild(static_cast<nsIIDBObjectStore*>(
                       tmp->mCreatedObjectStores[i].get()));
   }
-
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBTransaction,
-                                                nsDOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBTransaction, IDBWrapperCache)
   // Don't unlink mDatabase!
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnCompleteListener)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnAbortListener)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(complete)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort)
 
   tmp->mCreatedObjectStores.Clear();
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBTransaction)
   NS_INTERFACE_MAP_ENTRY(nsIIDBTransaction)
   NS_INTERFACE_MAP_ENTRY(nsIThreadObserver)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBTransaction)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
 
-NS_IMPL_ADDREF_INHERITED(IDBTransaction, nsDOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(IDBTransaction, nsDOMEventTargetHelper)
+NS_IMPL_ADDREF_INHERITED(IDBTransaction, IDBWrapperCache)
+NS_IMPL_RELEASE_INHERITED(IDBTransaction, IDBWrapperCache)
 
 DOMCI_DATA(IDBTransaction, IDBTransaction)
 
+NS_IMPL_EVENT_HANDLER(IDBTransaction, error);
+NS_IMPL_EVENT_HANDLER(IDBTransaction, complete);
+NS_IMPL_EVENT_HANDLER(IDBTransaction, abort);
+
 NS_IMETHODIMP
 IDBTransaction::GetDb(nsIIDBDatabase** aDB)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ADDREF(*aDB = mDatabase);
   return NS_OK;
 }
@@ -621,63 +627,16 @@ IDBTransaction::Abort()
   // abort event will be fired when all outstanding requests finish.
   if (needToCommitOrRollback) {
     return CommitOrRollback();
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBTransaction::SetOnerror(nsIDOMEventListener* aErrorListener)
-{
-  return RemoveAddEventListener(NS_LITERAL_STRING(ERROR_EVT_STR),
-                                mOnErrorListener, aErrorListener);
-}
-
-NS_IMETHODIMP
-IDBTransaction::GetOnerror(nsIDOMEventListener** aErrorListener)
-{
-  return GetInnerEventListener(mOnErrorListener, aErrorListener);
-}
-
-NS_IMETHODIMP
-IDBTransaction::GetOncomplete(nsIDOMEventListener** aOncomplete)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return GetInnerEventListener(mOnCompleteListener, aOncomplete);
-}
-
-NS_IMETHODIMP
-IDBTransaction::SetOncomplete(nsIDOMEventListener* aOncomplete)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return RemoveAddEventListener(NS_LITERAL_STRING(COMPLETE_EVT_STR),
-                                mOnCompleteListener, aOncomplete);
-}
-
-NS_IMETHODIMP
-IDBTransaction::GetOnabort(nsIDOMEventListener** aOnabort)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return GetInnerEventListener(mOnAbortListener, aOnabort);
-}
-
-NS_IMETHODIMP
-IDBTransaction::SetOnabort(nsIDOMEventListener* aOnabort)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  return RemoveAddEventListener(NS_LITERAL_STRING(ABORT_EVT_STR),
-                                mOnAbortListener, aOnabort);
-}
-
 nsresult
 IDBTransaction::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   aVisitor.mParentTarget = mDatabase;
   return NS_OK;
 }
 
@@ -812,17 +771,17 @@ CommitHelper::Run()
   }
 
   IDBDatabase* database = mTransaction->Database();
   if (database->IsInvalidated()) {
     mAborted = true;
   }
 
   if (mConnection) {
-    IndexedDatabaseManager::SetCurrentWindow(database->Owner());
+    IndexedDatabaseManager::SetCurrentWindow(database->GetOwner());
 
     if (!mAborted && mUpdateFileRefcountFunction &&
         NS_FAILED(mUpdateFileRefcountFunction->UpdateDatabase(mConnection))) {
       mAborted = true;
     }
 
     if (!mAborted && NS_FAILED(WriteAutoIncrementCounts())) {
       mAborted = true;
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -36,34 +36,33 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbtransaction_h__
 #define mozilla_dom_indexeddb_idbtransaction_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
-#include "mozilla/dom/indexedDB/IDBDatabase.h"
-#include "mozilla/dom/indexedDB/FileInfo.h"
 
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageFunction.h"
 #include "nsIIDBTransaction.h"
 #include "nsIRunnable.h"
 #include "nsIThreadInternal.h"
 
-#include "nsDOMEventTargetHelper.h"
-#include "nsCycleCollectionParticipant.h"
-
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsInterfaceHashtable.h"
 
+#include "mozilla/dom/indexedDB/IDBDatabase.h"
+#include "mozilla/dom/indexedDB/IDBWrapperCache.h"
+#include "mozilla/dom/indexedDB/FileInfo.h"
+
 class nsIThread;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 class CommitHelper;
 struct ObjectStoreInfo;
 class TransactionThreadPool;
@@ -73,32 +72,31 @@ class IDBTransactionListener
 {
 public:
   NS_IMETHOD_(nsrefcnt) AddRef() = 0;
   NS_IMETHOD_(nsrefcnt) Release() = 0;
 
   virtual nsresult NotifyTransactionComplete(IDBTransaction* aTransaction) = 0;
 };
 
-class IDBTransaction : public nsDOMEventTargetHelper,
+class IDBTransaction : public IDBWrapperCache,
                        public nsIIDBTransaction,
                        public nsIThreadObserver
 {
   friend class AsyncConnectionHelper;
   friend class CommitHelper;
   friend class ThreadObserver;
   friend class TransactionThreadPool;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBTRANSACTION
   NS_DECL_NSITHREADOBSERVER
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction,
-                                           nsDOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, IDBWrapperCache)
 
   static already_AddRefed<IDBTransaction>
   Create(IDBDatabase* aDatabase,
          nsTArray<nsString>& aObjectStoreNames,
          PRUint16 aMode,
          bool aDispatchDelayed);
 
   // nsIDOMEventTarget
@@ -175,19 +173,19 @@ private:
   nsRefPtr<DatabaseInfo> mDatabaseInfo;
   nsTArray<nsString> mObjectStoreNames;
   PRUint16 mReadyState;
   PRUint16 mMode;
   PRUint32 mPendingRequests;
   PRUint32 mCreatedRecursionDepth;
 
   // Only touched on the main thread.
-  nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
-  nsRefPtr<nsDOMEventListenerWrapper> mOnCompleteListener;
-  nsRefPtr<nsDOMEventListenerWrapper> mOnAbortListener;
+  NS_DECL_EVENT_HANDLER(error);
+  NS_DECL_EVENT_HANDLER(complete);
+  NS_DECL_EVENT_HANDLER(abort);
 
   nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
     mCachedStatements;
 
   nsRefPtr<IDBTransactionListener> mListener;
 
   // Only touched on the database thread.
   nsCOMPtr<mozIStorageConnection> mConnection;
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IDBWrapperCache.cpp
@@ -0,0 +1,38 @@
+/* -*- 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"
+
+USING_INDEXEDDB_NAMESPACE
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(IDBWrapperCache)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBWrapperCache,
+                                                  nsDOMEventTargetWrapperCache)
+  // 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,
+                                                nsDOMEventTargetWrapperCache)
+  tmp->mScriptOwner = nsnull;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBWrapperCache,
+                                               nsDOMEventTargetWrapperCache)
+  // 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,
+                                               "mScriptOwner")
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBWrapperCache)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+
+NS_IMPL_ADDREF_INHERITED(IDBWrapperCache, nsDOMEventTargetWrapperCache)
+NS_IMPL_RELEASE_INHERITED(IDBWrapperCache, nsDOMEventTargetWrapperCache)
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IDBWrapperCache.h
@@ -0,0 +1,74 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_indexeddb_idbwrappercache_h__
+#define mozilla_dom_indexeddb_idbwrappercache_h__
+
+#include "mozilla/dom/indexedDB/IndexedDatabase.h"
+
+#include "nsDOMEventTargetWrapperCache.h"
+
+BEGIN_INDEXEDDB_NAMESPACE
+
+class IDBWrapperCache : public nsDOMEventTargetWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
+                                                   IDBWrapperCache,
+                                                   nsDOMEventTargetWrapperCache)
+
+  JSObject* GetScriptOwner() const
+  {
+    return mScriptOwner;
+  }
+
+  nsIScriptContext* GetScriptContext() const
+  {
+    return mScriptContext;
+  }
+
+  nsPIDOMWindow* GetOwner() const
+  {
+    return mOwner;
+  }
+
+  JSObject* GetParentObject()
+  {
+    if (mScriptOwner) {
+      return mScriptOwner;
+    }
+
+    // Do what nsEventTargetSH::PreCreate does.
+    nsCOMPtr<nsIScriptGlobalObject> parent;
+    nsDOMEventTargetWrapperCache::GetParentObject(getter_AddRefs(parent));
+
+    return parent ? parent->GetGlobalJSObject() : nsnull;
+  }
+
+  virtual void OnWrapperCreated()
+  { }
+
+  static IDBWrapperCache* FromSupports(nsISupports* aSupports)
+  {
+    return static_cast<IDBWrapperCache*>(
+      nsDOMEventTargetWrapperCache::FromSupports(aSupports));
+  }
+
+protected:
+  IDBWrapperCache()
+  : mScriptOwner(nsnull)
+  { }
+
+  virtual ~IDBWrapperCache()
+  { }
+
+  JSObject* mScriptOwner;
+};
+
+END_INDEXEDDB_NAMESPACE
+
+#endif // mozilla_dom_indexeddb_idbwrappercache_h__
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -500,17 +500,17 @@ IndexedDatabaseManager::AbortCloseDataba
 
   nsAutoTArray<IDBDatabase*, 50> liveDatabases;
   mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
 
   TransactionThreadPool* pool = TransactionThreadPool::Get();
 
   for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
     IDBDatabase*& database = liveDatabases[index];
-    if (database->Owner() == aWindow) {
+    if (database->GetOwner() == aWindow) {
       if (NS_FAILED(database->Close())) {
         NS_WARNING("Failed to close database for dying window!");
       }
 
       if (pool) {
         pool->AbortTransactionsForDatabase(database);
       }
     }
@@ -528,17 +528,17 @@ IndexedDatabaseManager::HasOpenTransacti
 
   TransactionThreadPool* pool = TransactionThreadPool::Get();
   if (!pool) {
     return false;
   }
 
   for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
     IDBDatabase*& database = liveDatabases[index];
-    if (database->Owner() == aWindow &&
+    if (database->GetOwner() == aWindow &&
         pool->HasTransactionsForDatabase(database)) {
       return true;
     }
   }
   
   return false;
 }
 
@@ -1586,42 +1586,42 @@ IndexedDatabaseManager::SynchronizedOp::
 
   mDelayedRunnables.Clear();
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::InitWindowless(const jsval& aObj, JSContext* aCx)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
-  
+  NS_ENSURE_ARG(!JSVAL_IS_PRIMITIVE(aObj));
+
   // Instantiating this class will register exception providers so even 
-  // in xpcshell we will get typed (dom) exceptions, instead of general exceptions.
+  // in xpcshell we will get typed (dom) exceptions, instead of general
+  // exceptions.
   nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID));
 
-  // Defining IDBKeyrange static functions on the global.
-  if (JSVAL_IS_PRIMITIVE(aObj)) {
-    return NS_ERROR_INVALID_ARG;
-  }
+  JSObject* obj = JSVAL_TO_OBJECT(aObj);
+
+  JSObject* global = JS_GetGlobalForObject(aCx, obj);
 
-  nsCOMPtr<nsIIDBFactory> factory = IDBFactory::Create(nsnull);
-  NS_ASSERTION(factory, "IDBFactory should not be null.");
+  nsCOMPtr<nsIIDBFactory> factory = IDBFactory::Create(aCx, global);
+  NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
 
-  JSObject* obj = JSVAL_TO_OBJECT(aObj);
   jsval mozIndexedDBVal;
   nsresult rv = nsContentUtils::WrapNative(aCx, obj, factory, &mozIndexedDBVal);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!JS_DefineProperty(aCx, obj, "mozIndexedDB", mozIndexedDBVal, 
-      nsnull, nsnull, JSPROP_ENUMERATE)) {
+  if (!JS_DefineProperty(aCx, obj, "mozIndexedDB", mozIndexedDBVal, nsnull,
+                         nsnull, JSPROP_ENUMERATE)) {
     return NS_ERROR_FAILURE;
   }
 
   JSObject* keyrangeObj = JS_NewObject(aCx, nsnull, nsnull, nsnull);
   NS_ENSURE_TRUE(keyrangeObj, NS_ERROR_OUT_OF_MEMORY);
-    
+
   if (!IDBKeyRange::DefineConstructors(aCx, keyrangeObj)) {
     return NS_ERROR_FAILURE;
   }
 
   if (!JS_DefineProperty(aCx, obj, "IDBKeyRange", OBJECT_TO_JSVAL(keyrangeObj),
                          nsnull, nsnull, JSPROP_ENUMERATE)) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -56,37 +56,39 @@ CPPSRCS = \
   CheckPermissionsHelper.cpp \
   CheckQuotaHelper.cpp \
   DatabaseInfo.cpp \
   FileInfo.cpp \
   FileManager.cpp \
   IDBCursor.cpp \
   IDBDatabase.cpp \
   IDBEvents.cpp \
+  IDBFactory.cpp \
   IDBIndex.cpp \
   IDBKeyRange.cpp \
   IDBObjectStore.cpp \
   IDBRequest.cpp \
   IDBTransaction.cpp \
-  IDBFactory.cpp \
+  IDBWrapperCache.cpp \
   IndexedDatabaseManager.cpp \
+  Key.cpp \
   OpenDatabaseHelper.cpp \
   TransactionThreadPool.cpp \
-  Key.cpp \
   $(NULL)
 
 EXPORTS_mozilla/dom/indexedDB = \
   IDBCursor.h \
   IDBDatabase.h \
   IDBEvents.h \
   IDBIndex.h \
   IDBKeyRange.h \
   IDBObjectStore.h \
   IDBRequest.h \
   IDBTransaction.h \
+  IDBWrapperCache.h \
   IndexedDatabase.h \
   IndexedDatabaseManager.h \
   IDBFactory.h \
   Key.h \
   FileManager.h \
   FileInfo.h \
   $(NULL)
 
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -1606,17 +1606,19 @@ OpenDatabaseHelper::DoDatabaseWork()
   mState = eFiringEvents; // In case we fail somewhere along the line.
 
   if (IndexedDatabaseManager::IsShuttingDown()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   NS_ASSERTION(mOpenDBRequest, "This should never be null!");
 
-  nsPIDOMWindow* window = mOpenDBRequest->Owner();
+  // This will be null for non-window contexts.
+  nsPIDOMWindow* window = mOpenDBRequest->GetOwner();
+
   AutoEnterWindow autoWindow(window);
 
   nsCOMPtr<nsIFile> dbDirectory;
 
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   NS_ASSERTION(mgr, "This should never be null!");
 
   nsresult rv = mgr->EnsureOriginIsInitialized(mASCIIOrigin,
@@ -2106,18 +2108,17 @@ OpenDatabaseHelper::EnsureSuccessResult(
 
     NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
   }
 
   dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
   dbInfo->nextIndexId = mLastIndexId + 1;
 
   nsRefPtr<IDBDatabase> database =
-    IDBDatabase::Create(mOpenDBRequest->ScriptContext(),
-                        mOpenDBRequest->Owner(),
+    IDBDatabase::Create(mOpenDBRequest,
                         dbInfo.forget(),
                         mASCIIOrigin,
                         mFileManager);
   if (!database) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!");