Bug 1083285 - Fix noisy IndexedDB error, replace with better warning. r=khuey.
☠☠ backed out by ac74392f618b ☠ ☠
authorBen Turner <bent.mozilla@gmail.com>
Thu, 13 Nov 2014 18:20:38 -0800
changeset 216309 f5ed560d297fcba52f9783c3eb705e029e9578ad
parent 216308 df60c0297aa294388c5a26f652b23d98cc9b85d7
child 216310 ac74392f618b9fe5931283907fe941cdb42430cf
push id52012
push userbturner@mozilla.com
push dateTue, 18 Nov 2014 23:16:29 +0000
treeherdermozilla-inbound@f5ed560d297f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1083285
milestone36.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 1083285 - Fix noisy IndexedDB error, replace with better warning. r=khuey.
dom/indexedDB/ActorsChild.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBRequest.h
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBTransaction.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/locales/en-US/chrome/dom/dom.properties
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -1235,32 +1235,35 @@ BackgroundDatabaseChild::RecvPBackground
   MOZ_ASSERT(mOpenRequestActor);
 
   MaybeCollectGarbageOnIPCMessage();
 
   EnsureDOMObject();
 
   auto actor = static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
 
+  nsRefPtr<IDBOpenDBRequest> request = mOpenRequestActor->GetOpenDBRequest();
+  MOZ_ASSERT(request);
+
   nsRefPtr<IDBTransaction> transaction =
-    IDBTransaction::CreateVersionChange(mDatabase, actor, aNextObjectStoreId,
+    IDBTransaction::CreateVersionChange(mDatabase,
+                                        actor,
+                                        request,
+                                        aNextObjectStoreId,
                                         aNextIndexId);
   if (NS_WARN_IF(!transaction)) {
     return false;
   }
 
   transaction->AssertIsOnOwningThread();
 
   actor->SetDOMTransaction(transaction);
 
   mDatabase->EnterSetVersionTransaction(aRequestedVersion);
 
-  nsRefPtr<IDBOpenDBRequest> request = mOpenRequestActor->GetOpenDBRequest();
-  MOZ_ASSERT(request);
-
   request->SetTransaction(transaction);
 
   nsCOMPtr<nsIDOMEvent> upgradeNeededEvent =
     IDBVersionChangeEvent::Create(request,
                                   nsDependentString(kUpgradeNeededEventType),
                                   aCurrentVersion,
                                   aRequestedVersion);
   if (NS_WARN_IF(!upgradeNeededEvent)) {
@@ -1311,17 +1314,17 @@ BackgroundDatabaseChild::RecvVersionChan
         bfCacheEntry->RemoveFromBFCacheSync();
         shouldAbortAndClose = true;
       }
     }
 
     if (shouldAbortAndClose) {
       // Invalidate() doesn't close the database in the parent, so we have
       // to call Close() and AbortTransactions() manually.
-      mDatabase->AbortTransactions();
+      mDatabase->AbortTransactions(/* aShouldWarn */ false);
       mDatabase->Close();
       return true;
     }
   }
 
   // Otherwise fire a versionchange event.
   const nsDependentString type(kVersionChangeEventType);
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -34,19 +34,22 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/InputStreamParams.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "nsCOMPtr.h"
+#include "nsContentUtils.h"
+#include "nsIConsoleService.h"
 #include "nsIDocument.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
+#include "nsIScriptError.h"
 #include "nsISupportsPrimitives.h"
 #include "nsThreadUtils.h"
 #include "ProfilerHelpers.h"
 #include "ReportInternalError.h"
 
 // Include this last to avoid path problems on Windows.
 #include "ActorsChild.h"
 
@@ -309,17 +312,17 @@ IDBDatabase::CloseInternal()
 }
 
 void
 IDBDatabase::InvalidateInternal()
 {
   AssertIsOnOwningThread();
 
   InvalidateMutableFiles();
-  AbortTransactions();
+  AbortTransactions(/* aShouldWarn */ true);
 
   CloseInternal();
 }
 
 void
 IDBDatabase::EnterSetVersionTransaction(uint64_t aNewVersion)
 {
   AssertIsOnOwningThread();
@@ -746,45 +749,49 @@ IDBDatabase::UnregisterTransaction(IDBTr
   MOZ_ASSERT(aTransaction);
   aTransaction->AssertIsOnOwningThread();
   MOZ_ASSERT(mTransactions.Contains(aTransaction));
 
   mTransactions.RemoveEntry(aTransaction);
 }
 
 void
-IDBDatabase::AbortTransactions()
+IDBDatabase::AbortTransactions(bool aShouldWarn)
 {
   AssertIsOnOwningThread();
 
   class MOZ_STACK_CLASS Helper MOZ_FINAL
   {
   public:
     static void
-    AbortTransactions(nsTHashtable<nsPtrHashKey<IDBTransaction>>& aTable)
+    AbortTransactions(nsTHashtable<nsPtrHashKey<IDBTransaction>>& aTable,
+                      nsTArray<nsRefPtr<IDBTransaction>>& aAbortedTransactions)
     {
       const uint32_t count = aTable.Count();
       if (!count) {
         return;
       }
 
-      nsTArray<nsRefPtr<IDBTransaction>> transactions;
+      nsAutoTArray<nsRefPtr<IDBTransaction>, 20> transactions;
       transactions.SetCapacity(count);
 
       aTable.EnumerateEntries(Collect, &transactions);
 
       MOZ_ASSERT(transactions.Length() == count);
 
-      IDB_REPORT_INTERNAL_ERR();
-
       for (uint32_t index = 0; index < count; index++) {
-        nsRefPtr<IDBTransaction> transaction = transactions[index].forget();
+        nsRefPtr<IDBTransaction> transaction = Move(transactions[index]);
         MOZ_ASSERT(transaction);
 
         transaction->Abort(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+        // We only care about warning for write transactions.
+        if (transaction->GetMode() != IDBTransaction::READ_ONLY) {
+          aAbortedTransactions.AppendElement(Move(transaction));
+        }
       }
     }
 
   private:
     static PLDHashOperator
     Collect(nsPtrHashKey<IDBTransaction>* aTransaction, void* aClosure)
     {
       MOZ_ASSERT(aTransaction);
@@ -793,17 +800,35 @@ IDBDatabase::AbortTransactions()
 
       auto* array = static_cast<nsTArray<nsRefPtr<IDBTransaction>>*>(aClosure);
       array->AppendElement(aTransaction->GetKey());
 
       return PL_DHASH_NEXT;
     }
   };
 
-  Helper::AbortTransactions(mTransactions);
+  nsAutoTArray<nsRefPtr<IDBTransaction>, 5> abortedTransactions;
+  Helper::AbortTransactions(mTransactions, abortedTransactions);
+
+  if (aShouldWarn && !abortedTransactions.IsEmpty()) {
+    static const char kWarningMessage[] = "IndexedDBTransactionAbortNavigation";
+
+    for (uint32_t count = abortedTransactions.Length(), index = 0;
+         index < count;
+         index++) {
+      nsRefPtr<IDBTransaction>& transaction = abortedTransactions[index];
+      MOZ_ASSERT(transaction);
+
+      nsString filename;
+      uint32_t lineNo;
+      transaction->GetCallerLocation(filename, &lineNo);
+
+      LogWarning(kWarningMessage, filename, lineNo);
+    }
+  }
 }
 
 PBackgroundIDBDatabaseFileChild*
 IDBDatabase::GetOrCreateFileActorForBlob(File* aBlob)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(mBackgroundActor);
@@ -1150,16 +1175,75 @@ IDBDatabase::Invalidate()
 
   if (!mInvalidated) {
     mInvalidated = true;
 
     InvalidateInternal();
   }
 }
 
+void
+IDBDatabase::LogWarning(const char* aMessageName,
+                        const nsAString& aFilename,
+                        uint32_t aLineNumber)
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(aMessageName);
+
+  // For now this is main-thread only.
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsXPIDLString localizedMessage;
+  if (NS_WARN_IF(NS_FAILED(
+    nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                       aMessageName,
+                                       localizedMessage)))) {
+    return;
+  }
+
+  nsAutoCString category;
+  if (mFactory->IsChrome()) {
+    category.AssignLiteral("chrome ");
+  } else {
+    category.AssignLiteral("content ");
+  }
+  category.AppendLiteral("javascript");
+
+  nsCOMPtr<nsIConsoleService> consoleService =
+    do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+  MOZ_ASSERT(consoleService);
+
+  nsCOMPtr<nsIScriptError> scriptError =
+    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
+  MOZ_ASSERT(consoleService);
+
+  if (mFactory->GetParentObject()) {
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+      scriptError->InitWithWindowID(localizedMessage,
+                                    aFilename,
+                                    /* aSourceLine */ EmptyString(),
+                                    aLineNumber,
+                                    /* aColumnNumber */ 0,
+                                    nsIScriptError::warningFlag,
+                                    category,
+                                    mFactory->InnerWindowID())));
+  } else {
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+      scriptError->Init(localizedMessage,
+                        aFilename,
+                        /* aSourceLine */ EmptyString(),
+                        aLineNumber,
+                        /* aColumnNumber */ 0,
+                        nsIScriptError::warningFlag,
+                        category.get())));
+  }
+
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
+}
+
 NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
 NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
 
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -166,17 +166,17 @@ public:
 
   void
   RegisterTransaction(IDBTransaction* aTransaction);
 
   void
   UnregisterTransaction(IDBTransaction* aTransaction);
 
   void
-  AbortTransactions();
+  AbortTransactions(bool aShouldWarn);
 
   PBackgroundIDBDatabaseFileChild*
   GetOrCreateFileActorForBlob(File* aBlob);
 
   void
   NoteFinishedFileActor(PBackgroundIDBDatabaseFileChild* aFileActor);
 
   void
@@ -294,15 +294,20 @@ private:
   void
   RefreshSpec(bool aMayDelete);
 
   void
   ExpireFileActors(bool aExpireAll);
 
   void
   InvalidateMutableFiles();
+
+  void
+  LogWarning(const char* aMessageName,
+             const nsAString& aFilename,
+             uint32_t aLineNumber);
 };
 
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_indexeddb_idbdatabase_h__
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -24,17 +24,17 @@
 #include "nsIWebNavigation.h"
 #include "ProfilerHelpers.h"
 #include "ReportInternalError.h"
 
 // Include this last to avoid path problems on Windows.
 #include "ActorsChild.h"
 
 #ifdef DEBUG
-#include "nsContentUtils.h" // For IsCallerChrome assertions.
+#include "nsContentUtils.h" // For assertions.
 #endif
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 using namespace mozilla::dom::quota;
 using namespace mozilla::ipc;
@@ -105,16 +105,17 @@ struct IDBFactory::PendingRequestInfo
     MOZ_ASSERT(aRequest);
     MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
   }
 };
 
 IDBFactory::IDBFactory()
   : mOwningObject(nullptr)
   , mBackgroundActor(nullptr)
+  , mInnerWindowID(0)
   , mBackgroundActorFailed(false)
   , mPrivateBrowsingMode(false)
 {
 #ifdef DEBUG
   mOwningThread = PR_GetCurrentThread();
 #endif
   AssertIsOnOwningThread();
 }
@@ -178,16 +179,17 @@ IDBFactory::CreateForWindow(nsPIDOMWindo
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
 
   bool privateBrowsingMode = loadContext && loadContext->UsePrivateBrowsing();
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
   factory->mPrincipalInfo = Move(principalInfo);
   factory->mWindow = aWindow;
   factory->mTabChild = TabChild::GetFrom(aWindow);
+  factory->mInnerWindowID = aWindow->WindowID();
   factory->mPrivateBrowsingMode = privateBrowsingMode;
 
   factory.forget(aFactory);
   return NS_OK;
 }
 
 // static
 nsresult
@@ -280,16 +282,25 @@ void
 IDBFactory::AssertIsOnOwningThread() const
 {
   MOZ_ASSERT(mOwningThread);
   MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
 }
 
 #endif // DEBUG
 
+bool
+IDBFactory::IsChrome() const
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(mPrincipalInfo);
+
+  return mPrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo;
+}
+
 void
 IDBFactory::SetBackgroundActor(BackgroundFactoryChild* aBackgroundActor)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aBackgroundActor);
   MOZ_ASSERT(!mBackgroundActor);
 
   mBackgroundActor = aBackgroundActor;
@@ -519,29 +530,30 @@ IDBFactory::OpenInternal(nsIPrincipal* a
       }
     }
   }
 
   AutoJSAPI autoJS;
   nsRefPtr<IDBOpenDBRequest> request;
 
   if (mWindow) {
-    if (NS_WARN_IF(!autoJS.Init(mWindow))) {
+    AutoJSContext cx;
+    if (NS_WARN_IF(!autoJS.Init(mWindow, cx))) {
       IDB_REPORT_INTERNAL_ERR();
       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
       return nullptr;
     }
 
-    JS::Rooted<JSObject*> scriptOwner(autoJS.cx(),
+    JS::Rooted<JSObject*> scriptOwner(cx,
       static_cast<nsGlobalWindow*>(mWindow.get())->FastGetGlobalJSObject());
     MOZ_ASSERT(scriptOwner);
 
     request = IDBOpenDBRequest::CreateForWindow(this, mWindow, scriptOwner);
   } else {
-    autoJS.Init();
+    autoJS.Init(mOwningObject.get());
     JS::Rooted<JSObject*> scriptOwner(autoJS.cx(), mOwningObject);
 
     request = IDBOpenDBRequest::CreateForJS(this, scriptOwner);
   }
 
   MOZ_ASSERT(request);
 
   // If we already have a background actor then we can start this request now.
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -68,16 +68,18 @@ class IDBFactory MOZ_FINAL
   nsTArray<nsAutoPtr<PendingRequestInfo>> mPendingRequests;
 
   BackgroundFactoryChild* mBackgroundActor;
 
 #ifdef DEBUG
   PRThread* mOwningThread;
 #endif
 
+  uint64_t mInnerWindowID;
+
   bool mBackgroundActorFailed;
   bool mPrivateBrowsingMode;
 
 public:
   static nsresult
   CreateForWindow(nsPIDOMWindow* aWindow,
                   IDBFactory** aFactory);
 
@@ -125,16 +127,27 @@ public:
   PrincipalInfo*
   GetPrincipalInfo() const
   {
     AssertIsOnOwningThread();
 
     return mPrincipalInfo;
   }
 
+  uint64_t
+  InnerWindowID() const
+  {
+    AssertIsOnOwningThread();
+
+    return mInnerWindowID;
+  }
+
+  bool
+  IsChrome() const;
+
   already_AddRefed<IDBOpenDBRequest>
   Open(const nsAString& aName,
        uint64_t aVersion,
        ErrorResult& aRv);
 
   already_AddRefed<IDBOpenDBRequest>
   Open(const nsAString& aName,
        const IDBOpenDBOptions& aOptions,
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -94,22 +94,21 @@ IDBRequest::InitMembers()
 already_AddRefed<IDBRequest>
 IDBRequest::Create(IDBDatabase* aDatabase,
                    IDBTransaction* aTransaction)
 {
   MOZ_ASSERT(aDatabase);
   aDatabase->AssertIsOnOwningThread();
 
   nsRefPtr<IDBRequest> request = new IDBRequest(aDatabase);
+  CaptureCaller(request->mFilename, &request->mLineNo);
 
   request->mTransaction = aTransaction;
   request->SetScriptOwner(aDatabase->GetScriptOwner());
 
-  request->CaptureCaller();
-
   return request.forget();
 }
 
 // static
 already_AddRefed<IDBRequest>
 IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore,
                    IDBDatabase* aDatabase,
                    IDBTransaction* aTransaction)
@@ -135,16 +134,36 @@ IDBRequest::Create(IDBIndex* aSourceAsIn
 
   nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
 
   request->mSourceAsIndex = aSourceAsIndex;
 
   return request.forget();
 }
 
+// static
+void
+IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
+{
+  MOZ_ASSERT(aFilename.IsEmpty());
+  MOZ_ASSERT(aLineNo);
+
+  ThreadsafeAutoJSContext cx;
+
+  const char* filename = nullptr;
+  uint32_t lineNo = 0;
+  if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
+    *aLineNo = 0;
+    return;
+  }
+
+  aFilename.Assign(NS_ConvertUTF8toUTF16(filename));
+  *aLineNo = lineNo;
+}
+
 void
 IDBRequest::GetSource(
              Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
 {
   AssertIsOnOwningThread();
 
   MOZ_ASSERT_IF(mSourceAsObjectStore, !mSourceAsIndex);
   MOZ_ASSERT_IF(mSourceAsIndex, !mSourceAsObjectStore);
@@ -222,35 +241,23 @@ IDBRequest::GetErrorCode() const
   MOZ_ASSERT(mHaveResultOrErrorCode);
 
   return mErrorCode;
 }
 
 #endif // DEBUG
 
 void
-IDBRequest::CaptureCaller()
+IDBRequest::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const
 {
-  AutoJSContext cx;
-
-  const char* filename = nullptr;
-  uint32_t lineNo = 0;
-  if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
-    return;
-  }
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(aLineNo);
 
-  mFilename.Assign(NS_ConvertUTF8toUTF16(filename));
-  mLineNo = lineNo;
-}
-
-void
-IDBRequest::FillScriptErrorEvent(ErrorEventInit& aEventInit) const
-{
-  aEventInit.mLineno = mLineNo;
-  aEventInit.mFilename = mFilename;
+  aFilename = mFilename;
+  *aLineNo = mLineNo;
 }
 
 IDBRequestReadyState
 IDBRequest::ReadyState() const
 {
   AssertIsOnOwningThread();
 
   return IsPending() ?
@@ -296,17 +303,16 @@ IDBRequest::SetResultCallback(ResultCall
   AssertIsOnOwningThread();
   MOZ_ASSERT(aCallback);
   MOZ_ASSERT(!mHaveResultOrErrorCode);
   MOZ_ASSERT(mResultVal.isUndefined());
   MOZ_ASSERT(!mError);
 
   // See if our window is still valid.
   if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) {
-    IDB_REPORT_INTERNAL_ERR();
     SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return;
   }
 
   AutoJSAPI autoJS;
   Maybe<JSAutoCompartment> ac;
 
   if (GetScriptOwner()) {
@@ -419,34 +425,34 @@ IDBOpenDBRequest::CreateForWindow(IDBFac
                                   JS::Handle<JSObject*> aScriptOwner)
 {
   MOZ_ASSERT(aFactory);
   aFactory->AssertIsOnOwningThread();
   MOZ_ASSERT(aOwner);
   MOZ_ASSERT(aScriptOwner);
 
   nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, aOwner);
-  request->CaptureCaller();
+  CaptureCaller(request->mFilename, &request->mLineNo);
 
   request->SetScriptOwner(aScriptOwner);
 
   return request.forget();
 }
 
 // static
 already_AddRefed<IDBOpenDBRequest>
 IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory,
                               JS::Handle<JSObject*> aScriptOwner)
 {
   MOZ_ASSERT(aFactory);
   aFactory->AssertIsOnOwningThread();
   MOZ_ASSERT(aScriptOwner);
 
   nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, nullptr);
-  request->CaptureCaller();
+  CaptureCaller(request->mFilename, &request->mLineNo);
 
   request->SetScriptOwner(aScriptOwner);
 
   return request.forget();
 }
 
 void
 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -109,17 +109,17 @@ public:
     return mErrorCode;
   }
 #endif
 
   DOMError*
   GetError(ErrorResult& aRv);
 
   void
-  FillScriptErrorEvent(ErrorEventInit& aEventInit) const;
+  GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
 
   bool
   IsPending() const
   {
     return !mHaveResultOrErrorCode;
   }
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
@@ -184,19 +184,16 @@ protected:
   explicit IDBRequest(nsPIDOMWindow* aOwner);
   ~IDBRequest();
 
   void
   InitMembers();
 
   void
   ConstructResult();
-
-  void
-  CaptureCaller();
 };
 
 class NS_NO_VTABLE IDBRequest::ResultCallback
 {
 public:
   virtual nsresult
   GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) = 0;
 
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -43,16 +43,17 @@ IDBTransaction::IDBTransaction(IDBDataba
                                Mode aMode)
   : IDBWrapperCache(aDatabase)
   , mDatabase(aDatabase)
   , mObjectStoreNames(aObjectStoreNames)
   , mNextObjectStoreId(0)
   , mNextIndexId(0)
   , mAbortCode(NS_OK)
   , mPendingRequestCount(0)
+  , mLineNo(0)
   , mReadyState(IDBTransaction::INITIAL)
   , mMode(aMode)
   , mCreating(false)
   , mAbortedByScript(false)
 #ifdef DEBUG
   , mSentCommitOrAbort(false)
   , mFiredCompleteOrAbort(false)
 #endif
@@ -122,29 +123,33 @@ IDBTransaction::~IDBTransaction()
   }
 }
 
 // static
 already_AddRefed<IDBTransaction>
 IDBTransaction::CreateVersionChange(
                                 IDBDatabase* aDatabase,
                                 BackgroundVersionChangeTransactionChild* aActor,
+                                IDBOpenDBRequest* aOpenRequest,
                                 int64_t aNextObjectStoreId,
                                 int64_t aNextIndexId)
 {
   MOZ_ASSERT(aDatabase);
   aDatabase->AssertIsOnOwningThread();
   MOZ_ASSERT(aActor);
+  MOZ_ASSERT(aOpenRequest);
   MOZ_ASSERT(aNextObjectStoreId > 0);
   MOZ_ASSERT(aNextIndexId > 0);
 
   nsTArray<nsString> emptyObjectStoreNames;
 
   nsRefPtr<IDBTransaction> transaction =
     new IDBTransaction(aDatabase, emptyObjectStoreNames, VERSION_CHANGE);
+  aOpenRequest->GetCallerLocation(transaction->mFilename,
+                                  &transaction->mLineNo);
 
   transaction->SetScriptOwner(aDatabase->GetScriptOwner());
   transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
   transaction->mNextObjectStoreId = aNextObjectStoreId;
   transaction->mNextIndexId = aNextIndexId;
 
   // XXX Fix!
   MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
@@ -170,16 +175,17 @@ IDBTransaction::Create(IDBDatabase* aDat
 {
   MOZ_ASSERT(aDatabase);
   aDatabase->AssertIsOnOwningThread();
   MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
   MOZ_ASSERT(aMode == READ_ONLY || aMode == READ_WRITE);
 
   nsRefPtr<IDBTransaction> transaction =
     new IDBTransaction(aDatabase, aObjectStoreNames, aMode);
+  IDBRequest::CaptureCaller(transaction->mFilename, &transaction->mLineNo);
 
   transaction->SetScriptOwner(aDatabase->GetScriptOwner());
 
   // XXX Fix!
   MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
 
   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
   if (NS_WARN_IF(!appShell) ||
@@ -386,16 +392,26 @@ IDBTransaction::IsOpen() const
   if (mReadyState == IDBTransaction::LOADING &&
       (mCreating || GetCurrent() == this)) {
     return true;
   }
 
   return false;
 }
 
+void
+IDBTransaction::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(aLineNo);
+
+  aFilename = mFilename;
+  *aLineNo = mLineNo;
+}
+
 already_AddRefed<IDBObjectStore>
 IDBTransaction::CreateObjectStore(const ObjectStoreSpec& aSpec)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aSpec.metadata().id());
   MOZ_ASSERT(VERSION_CHANGE == mMode);
   MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor);
   MOZ_ASSERT(IsOpen());
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -32,16 +32,17 @@ class PBlobChild;
 namespace indexedDB {
 
 class BackgroundCursorChild;
 class BackgroundRequestChild;
 class BackgroundTransactionChild;
 class BackgroundVersionChangeTransactionChild;
 class IDBDatabase;
 class IDBObjectStore;
+class IDBOpenDBRequest;
 class IDBRequest;
 class IndexMetadata;
 class ObjectStoreSpec;
 class OpenCursorParams;
 class PBackgroundIDBDatabaseFileChild;
 class RequestParams;
 
 class IDBTransaction MOZ_FINAL
@@ -89,31 +90,35 @@ private:
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
   uint64_t mSerialNumber;
 #endif
 
   nsresult mAbortCode;
   uint32_t mPendingRequestCount;
 
+  nsString mFilename;
+  uint32_t mLineNo;
+
   ReadyState mReadyState;
   Mode mMode;
 
   bool mCreating;
   bool mAbortedByScript;
 
 #ifdef DEBUG
   bool mSentCommitOrAbort;
   bool mFiredCompleteOrAbort;
 #endif
 
 public:
   static already_AddRefed<IDBTransaction>
   CreateVersionChange(IDBDatabase* aDatabase,
                       BackgroundVersionChangeTransactionChild* aActor,
+                      IDBOpenDBRequest* aOpenRequest,
                       int64_t aNextObjectStoreId,
                       int64_t aNextIndexId);
 
   static already_AddRefed<IDBTransaction>
   Create(IDBDatabase* aDatabase,
          const nsTArray<nsString>& aObjectStoreNames,
          Mode aMode);
 
@@ -179,16 +184,19 @@ public:
 
   bool
   IsAborted() const
   {
     AssertIsOnOwningThread();
     return NS_FAILED(mAbortCode);
   }
 
+  void
+  GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
+
   // 'Get' prefix is to avoid name collisions with the enum
   Mode
   GetMode() const
   {
     AssertIsOnOwningThread();
     return mMode;
   }
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -361,17 +361,17 @@ IndexedDatabaseManager::FireWindowOnErro
 
   nsString errorName;
   if (error) {
     error->GetName(errorName);
   }
 
   ThreadsafeAutoJSContext cx;
   RootedDictionary<ErrorEventInit> init(cx);
-  request->FillScriptErrorEvent(init);
+  request->GetCallerLocation(init.mFilename, &init.mLineno);
 
   init.mMessage = errorName;
   init.mCancelable = true;
   init.mBubbles = true;
 
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aOwner));
   NS_ASSERTION(sgo, "How can this happen?!");
 
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -204,8 +204,10 @@ KeyNameAppsWarning=KeyboardEvent.key val
 # LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "FastFwd" and "MediaFastForward".
 KeyNameFastFwdWarning=KeyboardEvent.key value "FastFwd" is obsolete and will be renamed to "MediaFastForward". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
 # LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Zoom" and "ZoomToggle".
 KeyNameZoomWarning=KeyboardEvent.key value "Zoom" is obsolete and will be renamed to "ZoomToggle". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
 # LOCALIZATION NOTE: Do not translate "KeyboardEvent.key" and "Dead".
 KeyNameDeadKeysWarning=KeyboardEvent.key values starting with "Dead" are obsolete and will be merged into just "Dead". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
 ImportXULIntoContentWarning=Importing XUL nodes into a content document is deprecated. This functionality may be removed soon.
 XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead.
+# LOCALIZATION NOTE: Do not translate "IndexedDB".
+IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation.
\ No newline at end of file