Bug 861287 - 'Integrate IndexedDB into the gecko profiler'. r=khuey.
authorBen Turner <bent.mozilla@gmail.com>
Fri, 15 Mar 2013 23:58:50 -0700
changeset 140802 7b13433d8d0c4552dbd35d2cf4c085cf6d6d86ee
parent 140801 3dbdab219220d32e242a2e1f1fc123e5e8fc40df
child 140803 0e8b99f4d0b30a078e8aaf983481c36b91a1224f
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs861287
milestone23.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 861287 - 'Integrate IndexedDB into the gecko profiler'. r=khuey.
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBRequest.h
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBTransaction.h
dom/indexedDB/Key.h
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/ProfilerHelpers.h
dom/indexedDB/TransactionThreadPool.cpp
dom/quota/QuotaManager.cpp
xpcom/threads/LazyIdleThread.cpp
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -14,16 +14,17 @@
 #include "nsContentUtils.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCacheInlines.h"
 
 #include "IDBEvents.h"
 #include "IDBTransaction.h"
 #include "IndexedDatabaseManager.h"
+#include "ProfilerHelpers.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 USING_INDEXEDDB_NAMESPACE
 using mozilla::dom::quota::QuotaManager;
 
@@ -186,16 +187,18 @@ AsyncConnectionHelper::~AsyncConnectionH
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(AsyncConnectionHelper, nsIRunnable,
                                                      mozIStorageProgressHandler)
 
 NS_IMETHODIMP
 AsyncConnectionHelper::Run()
 {
   if (NS_IsMainThread()) {
+    PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::Run");
+
     if (mTransaction &&
         mTransaction->IsAborted()) {
       // Always fire a "error" event with ABORT_ERR if the transaction was
       // aborted, even if the request succeeded or failed with another error.
       mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
     }
 
     IDBTransaction* oldTransaction = gCurrentTransaction;
@@ -215,16 +218,21 @@ AsyncConnectionHelper::Run()
       }
 
       case Success_NotSent: {
         if (mRequest) {
           nsresult rv = mRequest->NotifyHelperCompleted(this);
           if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
             mResultCode = rv;
           }
+
+          IDB_PROFILER_MARK("IndexedDB Request %llu: Running main thread "
+                            "response (rv = %lu)",
+                            "IDBRequest[%llu] MT Done",
+                            mRequest->GetSerialNumber(), mResultCode);
         }
 
         // Call OnError if the database had an error or if the OnSuccess
         // handler has an error.
         if (NS_FAILED(mResultCode) ||
             NS_FAILED((mResultCode = OnSuccess()))) {
           OnError();
         }
@@ -261,16 +269,23 @@ AsyncConnectionHelper::Run()
     NS_ASSERTION(!(mDatabase || mTransaction || mRequest), "Subclass didn't "
                  "call AsyncConnectionHelper::ReleaseMainThreadObjects!");
 
     return NS_OK;
   }
 
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_LABEL("IndexedDB", "AsyncConnectionHelper::Run");
+
+  IDB_PROFILER_MARK_IF(mRequest,
+                       "IndexedDB Request %llu: Beginning database work",
+                       "IDBRequest[%llu] DT Start",
+                       mRequest->GetSerialNumber());
+
   nsresult rv = NS_OK;
   nsCOMPtr<mozIStorageConnection> connection;
 
   if (mTransaction) {
     rv = mTransaction->GetOrCreateConnection(getter_AddRefs(connection));
     if (NS_SUCCEEDED(rv)) {
       NS_ASSERTION(connection, "This should never be null!");
     }
@@ -336,16 +351,22 @@ AsyncConnectionHelper::Run()
 #ifdef DEBUG
     if (NS_SUCCEEDED(rv)) {
       NS_ASSERTION(SameCOMIdentity(handler, static_cast<nsIRunnable*>(this)),
                    "Mismatch!");
     }
 #endif
   }
 
+  IDB_PROFILER_MARK_IF(mRequest,
+                       "IndexedDB Request %llu: Finished database work "
+                       "(rv = %lu)",
+                       "IDBRequest[%llu] DT Done", mRequest->GetSerialNumber(),
+                       mResultCode);
+
   return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
 }
 
 NS_IMETHODIMP
 AsyncConnectionHelper::OnProgress(mozIStorageConnection* aConnection,
                                   bool* _retval)
 {
   if (mDatabase && mDatabase->IsInvalidated()) {
@@ -428,16 +449,18 @@ AsyncConnectionHelper::CreateSuccessEven
 }
 
 nsresult
 AsyncConnectionHelper::OnSuccess()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mRequest, "Null request!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnSuccess");
+
   nsRefPtr<nsIDOMEvent> event = CreateSuccessEvent(mRequest);
   if (!event) {
     NS_ERROR("Failed to create event!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   bool dummy;
   nsresult rv = mRequest->DispatchEvent(event, &dummy);
@@ -462,16 +485,18 @@ AsyncConnectionHelper::OnSuccess()
 }
 
 void
 AsyncConnectionHelper::OnError()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mRequest, "Null request!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnError");
+
   // Make an error event and fire it at the target.
   nsRefPtr<nsIDOMEvent> event =
     CreateGenericEvent(mRequest, NS_LITERAL_STRING(ERROR_EVT_STR), eDoesBubble,
                        eCancelable);
   if (!event) {
     NS_ERROR("Failed to create event!");
     return;
   }
@@ -551,16 +576,21 @@ AsyncConnectionHelper::MaybeSendResponse
     return Success_ActorDisconnected;
   }
 
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   if (!actor) {
     return Success_NotSent;
   }
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: Sending response to child "
+                    "process (rv = %lu)",
+                    "IDBRequest[%llu] MT Done",
+                    mRequest->GetSerialNumber(), aResultCode);
+
   return SendResponseToChildProcess(aResultCode);
 }
 
 nsresult
 AsyncConnectionHelper::OnParentProcessRequestComplete(
                                             const ResponseValue& aResponseValue)
 {
   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -16,16 +16,17 @@
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
+#include "ProfilerHelpers.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 USING_INDEXEDDB_NAMESPACE
@@ -618,17 +619,17 @@ IDBCursor::GetValue(JSContext* aCx,
     mHaveCachedValue = true;
   }
 
   *aValue = mCachedValue;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBCursor::Continue(const jsval &aKey,
+IDBCursor::Continue(const jsval& aKey,
                     JSContext* aCx)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   Key key;
   nsresult rv = key.SetFromJSVal(aCx, aKey);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -648,17 +649,50 @@ IDBCursor::Continue(const jsval &aKey,
         }
         break;
 
       default:
         NS_NOTREACHED("Unknown direction type!");
     }
   }
 
-  return ContinueInternal(key, 1);
+  rv = ContinueInternal(key, 1);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+#ifdef IDB_PROFILER_USE_MARKS
+  if (mType == OBJECTSTORE) {
+    IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                      "database(%s).transaction(%s).objectStore(%s).cursor(%s)."
+                      "continue(%s)",
+                      "IDBRequest[%llu] MT IDBCursor.continue()",
+                      Request()->GetSerialNumber(),
+                      IDB_PROFILER_STRING(Transaction()->Database()),
+                      IDB_PROFILER_STRING(Transaction()),
+                      IDB_PROFILER_STRING(mObjectStore),
+                      IDB_PROFILER_STRING(mDirection),
+                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
+  }
+  else {
+    IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                      "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                      "cursor(%s).continue(%s)",
+                      "IDBRequest[%llu] MT IDBCursor.continue()",
+                      Request()->GetSerialNumber(),
+                      IDB_PROFILER_STRING(Transaction()->Database()),
+                      IDB_PROFILER_STRING(Transaction()),
+                      IDB_PROFILER_STRING(mObjectStore),
+                      IDB_PROFILER_STRING(mIndex),
+                      IDB_PROFILER_STRING(mDirection),
+                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
+  }
+#endif
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBCursor::Update(const jsval& aValue,
                   JSContext* aCx,
                   nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -680,38 +714,83 @@ IDBCursor::Update(const jsval& aValue,
   NS_ASSERTION(mType != INDEXOBJECT || !mObjectKey.IsUnset(), "Bad key!");
 
   nsresult rv;
 
   JSAutoRequest ar(aCx);
 
   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
+  nsCOMPtr<nsIIDBRequest> request;
   if (mObjectStore->HasValidKeyPath()) {
     // Make sure the object given has the correct keyPath value set on it.
     const KeyPath& keyPath = mObjectStore->GetKeyPath();
     Key key;
 
     rv = keyPath.ExtractKey(aCx, aValue, key);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (key != objectKey) {
       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
 
-    return mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, _retval);
+    rv = mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, getter_AddRefs(request));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  else {
+    jsval keyVal;
+    rv = objectKey.ToJSVal(aCx, &keyVal);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = mObjectStore->Put(aValue, keyVal, aCx, 1, getter_AddRefs(request));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
   }
 
-  jsval keyVal;
-  rv = objectKey.ToJSVal(aCx, &keyVal);
-  NS_ENSURE_SUCCESS(rv, rv);
+#ifdef IDB_PROFILER_USE_MARKS
+  {
+    uint64_t requestSerial =
+      static_cast<IDBRequest*>(request.get())->GetSerialNumber();
+    if (mType == OBJECTSTORE) {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                        "database(%s).transaction(%s).objectStore(%s)."
+                        "cursor(%s).update(%s)",
+                        "IDBRequest[%llu] MT IDBCursor.update()",
+                        requestSerial,
+                        IDB_PROFILER_STRING(mTransaction->Database()),
+                        IDB_PROFILER_STRING(mTransaction),
+                        IDB_PROFILER_STRING(mObjectStore),
+                        IDB_PROFILER_STRING(mDirection),
+                        mObjectStore->HasValidKeyPath() ? "" :
+                          IDB_PROFILER_STRING(objectKey));
+    }
+    else {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                        "database(%s).transaction(%s).objectStore(%s)."
+                        "index(%s).cursor(%s).update(%s)",
+                        "IDBRequest[%llu] MT IDBCursor.update()",
+                        requestSerial,
+                        IDB_PROFILER_STRING(mTransaction->Database()),
+                        IDB_PROFILER_STRING(mTransaction),
+                        IDB_PROFILER_STRING(mObjectStore),
+                        IDB_PROFILER_STRING(mIndex),
+                        IDB_PROFILER_STRING(mDirection),
+                        mObjectStore->HasValidKeyPath() ? "" :
+                          IDB_PROFILER_STRING(objectKey));
+    }
+  }
+#endif
 
-  return mObjectStore->Put(aValue, keyVal, aCx, 1, _retval);
+  request.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBCursor::Delete(JSContext* aCx,
                   nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -731,42 +810,120 @@ IDBCursor::Delete(JSContext* aCx,
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
 
   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
   jsval key;
   nsresult rv = objectKey.ToJSVal(aCx, &key);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return mObjectStore->Delete(key, aCx, _retval);
+  nsCOMPtr<nsIIDBRequest> request;
+  rv = mObjectStore->Delete(key, aCx, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+#ifdef IDB_PROFILER_USE_MARKS
+  {
+    uint64_t requestSerial =
+      static_cast<IDBRequest*>(request.get())->GetSerialNumber();
+    if (mType == OBJECTSTORE) {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                        "database(%s).transaction(%s).objectStore(%s)."
+                        "cursor(%s).delete(%s)",
+                        "IDBRequest[%llu] MT IDBCursor.delete()",
+                        requestSerial,
+                        IDB_PROFILER_STRING(mTransaction->Database()),
+                        IDB_PROFILER_STRING(mTransaction),
+                        IDB_PROFILER_STRING(mObjectStore),
+                        IDB_PROFILER_STRING(mDirection),
+                        mObjectStore->HasValidKeyPath() ? "" :
+                          IDB_PROFILER_STRING(objectKey));
+    }
+    else {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                        "database(%s).transaction(%s).objectStore(%s)."
+                        "index(%s).cursor(%s).delete(%s)",
+                        "IDBRequest[%llu] MT IDBCursor.delete()",
+                        requestSerial,
+                        IDB_PROFILER_STRING(mTransaction->Database()),
+                        IDB_PROFILER_STRING(mTransaction),
+                        IDB_PROFILER_STRING(mObjectStore),
+                        IDB_PROFILER_STRING(mIndex),
+                        IDB_PROFILER_STRING(mDirection),
+                        mObjectStore->HasValidKeyPath() ? "" :
+                          IDB_PROFILER_STRING(objectKey));
+    }
+  }
+#endif
+
+  request.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBCursor::Advance(int64_t aCount)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (aCount < 1 || aCount > UINT32_MAX) {
     return NS_ERROR_TYPE_ERR;
   }
 
   Key key;
-  return ContinueInternal(key, int32_t(aCount));
+  nsresult rv = ContinueInternal(key, int32_t(aCount));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+#ifdef IDB_PROFILER_USE_MARKS
+  {
+    if (mType == OBJECTSTORE) {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                        "database(%s).transaction(%s).objectStore(%s)."
+                        "cursor(%s).advance(%ld)",
+                        "IDBRequest[%llu] MT IDBCursor.advance()",
+                        Request()->GetSerialNumber(),
+                        IDB_PROFILER_STRING(Transaction()->Database()),
+                        IDB_PROFILER_STRING(Transaction()),
+                        IDB_PROFILER_STRING(mObjectStore),
+                        IDB_PROFILER_STRING(mDirection), aCount);
+    }
+    else {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                        "database(%s).transaction(%s).objectStore(%s)."
+                        "index(%s).cursor(%s).advance(%ld)",
+                        "IDBRequest[%llu] MT IDBCursor.advance()",
+                        Request()->GetSerialNumber(),
+                        IDB_PROFILER_STRING(Transaction()->Database()),
+                        IDB_PROFILER_STRING(Transaction()),
+                        IDB_PROFILER_STRING(mObjectStore),
+                        IDB_PROFILER_STRING(mIndex),
+                        IDB_PROFILER_STRING(mDirection), aCount);
+    }
+  }
+#endif
+
+  return NS_OK;
 }
 
 void
 CursorHelper::ReleaseMainThreadObjects()
 {
   mCursor = nullptr;
   AsyncConnectionHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 CursorHelper::Dispatch(nsIEventTarget* aDatabaseThread)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "CursorHelper::Dispatch");
+
   if (IndexedDatabaseManager::IsMainProcess()) {
     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
   }
 
   // If we've been invalidated then there's no point sending anything to the
   // parent process.
   if (mCursor->Transaction()->Database()->IsInvalidated()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -787,16 +944,21 @@ CursorHelper::Dispatch(nsIEventTarget* a
   cursorActor->SendPIndexedDBRequestConstructor(mActor, params);
 
   return NS_OK;
 }
 
 nsresult
 ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "ContinueHelper::DoDatabaseWork");
+
   // We need to pick a query based on whether or not the cursor's mContinueToKey
   // is set. If it is unset then othing was passed to continue so we'll grab the
   // next item in the database that is greater than (less than, if we're running
   // a PREV cursor) the current key. If it is set then a key was passed to
   // continue so we'll grab the next item in the database that is greater than
   // (less than, if we're running a PREV cursor) or equal to the key that was
   // specified.
 
@@ -864,31 +1026,40 @@ ContinueHelper::ReleaseMainThreadObjects
 {
   IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   CursorHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 ContinueHelper::PackArgumentsForParentProcess(CursorRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "ContinueHelper::PackArgumentsForParentProcess");
+
   ContinueParams params;
 
   params.key() = mCursor->mContinueToKey;
   params.count() = uint32_t(mCount);
 
   aParams = params;
   return NS_OK;
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 ContinueHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "ContinueHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   InfallibleTArray<PBlobParent*> blobsParent;
 
   if (NS_SUCCEEDED(aResultCode)) {
     IDBDatabase* database = mTransaction->Database();
     NS_ASSERTION(database, "This should never be null!");
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -3,39 +3,40 @@
 /* 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 "base/basictypes.h"
 
 #include "IDBDatabase.h"
 
+#include "DictionaryHelpers.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/storage.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/quota/Client.h"
 #include "mozilla/dom/quota/QuotaManager.h"
+#include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMLists.h"
 #include "nsJSUtils.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBFileHandle.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "IDBFactory.h"
+#include "ProfilerHelpers.h"
 #include "TransactionThreadPool.h"
-#include "DictionaryHelpers.h"
-#include "nsContentUtils.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 USING_INDEXEDDB_NAMESPACE
 using mozilla::dom::ContentParent;
 using mozilla::dom::quota::Client;
 using mozilla::dom::quota::QuotaManager;
@@ -422,16 +423,24 @@ IDBDatabase::CreateObjectStoreInternal(I
     nsRefPtr<CreateObjectStoreHelper> helper =
       new CreateObjectStoreHelper(aTransaction, objectStore);
 
     nsresult rv = helper->DispatchToTransactionPool();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   autoRemove.forget();
+
+  IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
+                    "database(%s).transaction(%s).createObjectStore(%s)",
+                    "MT IDBDatabase.createObjectStore()",
+                    IDB_PROFILER_STRING(this),
+                    IDB_PROFILER_STRING(aTransaction),
+                    IDB_PROFILER_STRING(objectStore));
+
   objectStore.forget(_retval);
 
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -599,16 +608,23 @@ IDBDatabase::DeleteObjectStore(const nsA
     IndexedDBTransactionChild* actor = transaction->GetActorChild();
     NS_ASSERTION(actor, "Must have an actor here!");
 
     actor->SendDeleteObjectStore(nsString(aName));
   }
 
   transaction->RemoveObjectStore(aName);
 
+  IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
+                    "database(%s).transaction(%s).deleteObjectStore(\"%s\")",
+                    "MT IDBDatabase.deleteObjectStore()",
+                    IDB_PROFILER_STRING(this),
+                    IDB_PROFILER_STRING(transaction),
+                    NS_ConvertUTF16toUTF8(aName).get());
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::Transaction(const jsval& aStoreNames,
                          const nsAString& aMode,
                          JSContext* aCx,
                          uint8_t aOptionalArgCount,
@@ -736,16 +752,21 @@ IDBDatabase::Transaction(const jsval& aS
       return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
     }
   }
 
   nsRefPtr<IDBTransaction> transaction =
     IDBTransaction::Create(this, storesToOpen, transactionMode, false);
   NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Transaction %llu: database(%s).transaction(%s)",
+                    "IDBTransaction[%llu] MT Started",
+                    transaction->GetSerialNumber(), IDB_PROFILER_STRING(this),
+                    IDB_PROFILER_STRING(transaction));
+
   transaction.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::MozCreateFileHandle(const nsAString& aName,
                                  const nsAString& aType,
                                  JSContext* aCx,
@@ -874,16 +895,21 @@ NoRequestDatabaseHelper::OnError()
 {
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   mTransaction->Abort(GetResultCode());
 }
 
 nsresult
 CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "CreateObjectStoreHelper::DoDatabaseWork");
+
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     "INSERT INTO object_store (id, auto_increment, name, key_path) "
     "VALUES (:id, :auto_increment, :name, :key_path)"
   ));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
@@ -923,16 +949,21 @@ CreateObjectStoreHelper::ReleaseMainThre
 {
   mObjectStore = nullptr;
   NoRequestDatabaseHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 DeleteObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "DeleteObjectStoreHelper::DoDatabaseWork");
+
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     "DELETE FROM object_store "
     "WHERE id = :id "
   ));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
@@ -944,16 +975,21 @@ DeleteObjectStoreHelper::DoDatabaseWork(
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 CreateFileHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "CreateFileHelper::DoDatabaseWork");
+
   FileManager* fileManager = mDatabase->Manager();
 
   mFileInfo = fileManager->GetNewFileInfo();
   NS_ENSURE_TRUE(mFileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   const int64_t& fileId = mFileInfo->Id();
 
   nsCOMPtr<nsIFile> directory = fileManager->EnsureJournalDirectory();
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -2,22 +2,24 @@
 /* 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 "base/basictypes.h"
 
 #include "IDBFactory.h"
+
 #include "nsIFile.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 
+#include <algorithm>
 #include "jsdbgapi.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/IDBFactoryBinding.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/quota/OriginOrPatternString.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/TabChild.h"
@@ -37,19 +39,19 @@
 #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 "ProfilerHelpers.h"
 
 #include "ipc/IndexedDBChild.h"
-#include <algorithm>
 
 USING_INDEXEDDB_NAMESPACE
 USING_QUOTA_NAMESPACE
 
 using mozilla::dom::ContentChild;
 using mozilla::dom::ContentParent;
 using mozilla::dom::NonNull;
 using mozilla::dom::Optional;
@@ -588,16 +590,33 @@ IDBFactory::OpenInternal(const nsAString
     IndexedDBDatabaseChild* dbActor =
       static_cast<IndexedDBDatabaseChild*>(
         mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName),
                                                        aVersion));
 
     dbActor->SetRequest(request);
   }
 
+#ifdef IDB_PROFILER_USE_MARKS
+  {
+    NS_ConvertUTF16toUTF8 profilerName(aName);
+    if (aDeleting) {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: deleteDatabase(\"%s\")",
+                        "MT IDBFactory.deleteDatabase()",
+                        request->GetSerialNumber(), profilerName.get());
+    }
+    else {
+      IDB_PROFILER_MARK("IndexedDB Request %llu: open(\"%s\", %lld)",
+                        "MT IDBFactory.open()",
+                        request->GetSerialNumber(), profilerName.get(),
+                        aVersion);
+    }
+  }
+#endif
+
   request.forget(_retval);
   return NS_OK;
 }
 
 JSObject*
 IDBFactory::WrapObject(JSContext* aCx, JSObject* aScope)
 {
   return IDBFactoryBinding::Wrap(aCx, aScope, this);
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -8,30 +8,31 @@
 
 #include "IDBIndex.h"
 
 #include "nsIIDBKeyRange.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ipc/Blob.h"
+#include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsThreadUtils.h"
-#include "mozilla/storage.h"
 #include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
+#include "DatabaseInfo.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
-#include "DatabaseInfo.h"
+#include "ProfilerHelpers.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
@@ -440,16 +441,27 @@ IDBIndex::GetInternal(IDBKeyRange* aKeyR
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetHelper> helper =
     new GetHelper(transaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "get(%s)",
+                    "IDBRequest[%llu] MT IDBIndex.get()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::GetKeyInternal(IDBKeyRange* aKeyRange,
                          JSContext* aCx,
                          IDBRequest** _retval)
@@ -465,16 +477,27 @@ IDBIndex::GetKeyInternal(IDBKeyRange* aK
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetKeyHelper> helper =
     new GetKeyHelper(transaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "getKey(%s)",
+                    "IDBRequest[%llu] MT IDBIndex.getKey()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::GetAllInternal(IDBKeyRange* aKeyRange,
                          uint32_t aLimit,
                          JSContext* aCx,
@@ -491,16 +514,28 @@ IDBIndex::GetAllInternal(IDBKeyRange* aK
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetAllHelper> helper =
     new GetAllHelper(transaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "getAll(%s, %lu)",
+                    "IDBRequest[%llu] MT IDBIndex.getAll()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this),
+                    IDB_PROFILER_STRING(aKeyRange), aLimit);
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::GetAllKeysInternal(IDBKeyRange* aKeyRange,
                              uint32_t aLimit,
                              JSContext* aCx,
@@ -517,16 +552,28 @@ IDBIndex::GetAllKeysInternal(IDBKeyRange
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetAllKeysHelper> helper =
     new GetAllKeysHelper(transaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "getAllKeys(%s, %lu)",
+                    "IDBRequest[%llu] MT IDBIndex.getAllKeys()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
+                    aLimit);
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::CountInternal(IDBKeyRange* aKeyRange,
                         JSContext* aCx,
                         IDBRequest** _retval)
@@ -542,16 +589,27 @@ IDBIndex::CountInternal(IDBKeyRange* aKe
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<CountHelper> helper =
     new CountHelper(transaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "count(%s)",
+                    "IDBRequest[%llu] MT IDBIndex.count()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::OpenKeyCursorInternal(IDBKeyRange* aKeyRange,
                                 size_t aDirection,
                                 JSContext* aCx,
@@ -571,16 +629,28 @@ IDBIndex::OpenKeyCursorInternal(IDBKeyRa
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenKeyCursorHelper> helper =
     new OpenKeyCursorHelper(transaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "openKeyCursor(%s)",
+                    "IDBRequest[%llu] MT IDBIndex.openKeyCursor()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
+                    IDB_PROFILER_STRING(direction));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::OpenCursorInternal(IDBKeyRange* aKeyRange,
                              size_t aDirection,
                              JSContext* aCx,
@@ -600,16 +670,28 @@ IDBIndex::OpenCursorInternal(IDBKeyRange
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
     new OpenCursorHelper(transaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).index(%s)."
+                    "openCursor(%s)",
+                    "IDBRequest[%llu] MT IDBIndex.openCursor()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()->
+                                        Database()),
+                    IDB_PROFILER_STRING(ObjectStore()->Transaction()),
+                    IDB_PROFILER_STRING(ObjectStore()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
+                    IDB_PROFILER_STRING(direction));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBIndex::OpenCursorFromChildProcess(IDBRequest* aRequest,
                                      size_t aDirection,
                                      const Key& aKey,
@@ -1006,16 +1088,20 @@ IndexHelper::ReleaseMainThreadObjects()
 {
   mIndex = nullptr;
   AsyncConnectionHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 IndexHelper::Dispatch(nsIEventTarget* aDatabaseThread)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "IndexHelper::Dispatch");
+
   if (IndexedDatabaseManager::IsMainProcess()) {
     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
   }
 
   // If we've been invalidated then there's no point sending anything to the
   // parent process.
   if (mIndex->ObjectStore()->Transaction()->Database()->IsInvalidated()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -1036,18 +1122,22 @@ IndexHelper::Dispatch(nsIEventTarget* aD
   indexActor->SendPIndexedDBRequestConstructor(mActor, params);
 
   return NS_OK;
 }
 
 nsresult
 GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
+  PROFILER_LABEL("IndexedDB", "GetKeyHelper::DoDatabaseWork");
+
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
   }
   else {
     indexTable.AssignLiteral("index_data");
   }
 
@@ -1098,32 +1188,40 @@ GetKeyHelper::ReleaseMainThreadObjects()
 {
   mKeyRange = nullptr;
   IndexHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 GetKeyHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "This should never be null!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetKeyHelper::PackArgumentsForParentProcess");
+
   GetKeyParams params;
 
   mKeyRange->ToSerializedKeyRange(params.keyRange());
 
   aParams = params;
   return NS_OK;
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 GetKeyHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetKeyHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
@@ -1148,18 +1246,22 @@ GetKeyHelper::UnpackResponseFromParentPr
 
   mKey = aResponseValue.get_GetKeyResponse().key();
   return NS_OK;
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
+  PROFILER_LABEL("IndexedDB", "GetHelper::DoDatabaseWork [IDBIndex.cpp]");
+
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
   }
   else {
     indexTable.AssignLiteral("index_data");
   }
 
@@ -1218,32 +1320,42 @@ GetHelper::ReleaseMainThreadObjects()
 {
   IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   GetKeyHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 GetHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "This should never be null!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetHelper::PackArgumentsForParentProcess "
+                             "[IDBIndex.cpp]");
+
   FIXME_Bug_521898_index::GetParams params;
 
   mKeyRange->ToSerializedKeyRange(params.keyRange());
 
   aParams = params;
   return NS_OK;
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 GetHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetHelper::SendResponseToChildProcess "
+                             "[IDBIndex.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   InfallibleTArray<PBlobParent*> blobsParent;
 
   if (NS_SUCCEEDED(aResultCode)) {
     IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
     NS_ASSERTION(database, "This should never be null!");
@@ -1303,16 +1415,21 @@ GetHelper::UnpackResponseFromParentProce
   IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
                                        mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "GetAllKeysHelper::DoDatabaseWork");
+
   nsCString tableName;
   if (mIndex->IsUnique()) {
     tableName.AssignLiteral("unique_index_data");
   }
   else {
     tableName.AssignLiteral("index_data");
   }
 
@@ -1408,16 +1525,22 @@ GetAllKeysHelper::GetSuccessResult(JSCon
 
   *aVal = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetAllKeysHelper::PackArgumentsForParentProcess");
+
   GetAllKeysParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_index::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -1431,16 +1554,19 @@ GetAllKeysHelper::PackArgumentsForParent
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 GetAllKeysHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetAllKeysHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
@@ -1465,16 +1591,21 @@ GetAllKeysHelper::UnpackResponseFromPare
 
   mKeys.AppendElements(aResponseValue.get_GetAllKeysResponse().keys());
   return NS_OK;
 }
 
 nsresult
 GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "GetAllHelper::DoDatabaseWork [IDBIndex.cpp]");
+
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
   }
   else {
     indexTable.AssignLiteral("index_data");
   }
 
@@ -1552,16 +1683,23 @@ GetAllHelper::ReleaseMainThreadObjects()
     IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]);
   }
   GetKeyHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 GetAllHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetAllHelper::PackArgumentsForParentProcess "
+                             "[IDBIndex.cpp]");
+
   FIXME_Bug_521898_index::GetAllParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_index::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -1575,16 +1713,20 @@ GetAllHelper::PackArgumentsForParentProc
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 GetAllHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetAllHelper::SendResponseToChildProcess "
+                             "[IDBIndex.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   GetAllResponse getAllResponse;
 
   if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
     IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
     NS_ASSERTION(database, "This should never be null!");
@@ -1673,18 +1815,22 @@ GetAllHelper::UnpackResponseFromParentPr
   }
 
   return NS_OK;
 }
 
 nsresult
 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
+  PROFILER_LABEL("IndexedDB", "OpenKeyCursorHelper::DoDatabaseWork");
+
   nsCString table;
   if (mIndex->IsUnique()) {
     table.AssignLiteral("unique_index_data");
   }
   else {
     table.AssignLiteral("index_data");
   }
 
@@ -1879,16 +2025,23 @@ OpenKeyCursorHelper::ReleaseMainThreadOb
   mKeyRange = nullptr;
   mCursor = nullptr;
   IndexHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 OpenKeyCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenKeyCursorHelper::"
+                             "PackArgumentsForParentProcess");
+
   OpenKeyCursorParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_index::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -1903,16 +2056,19 @@ OpenKeyCursorHelper::PackArgumentsForPar
 
 AsyncConnectionHelper::ChildProcessSendResult
 OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenKeyCursorHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   if (NS_SUCCEEDED(aResultCode)) {
     nsresult rv = EnsureCursor();
     if (NS_FAILED(rv)) {
       NS_WARNING("EnsureCursor failed!");
       aResultCode = rv;
@@ -1994,18 +2150,23 @@ OpenKeyCursorHelper::UnpackResponseFromP
   }
 
   return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
+  PROFILER_LABEL("IndexedDB",
+                 "OpenCursorHelper::DoDatabaseWork [IDBIndex.cpp]");
+
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
   }
   else {
     indexTable.AssignLiteral("index_data");
   }
 
@@ -2208,16 +2369,23 @@ OpenCursorHelper::ReleaseMainThreadObjec
   mSerializedCloneReadInfo.dataLength = 0;
 
   OpenKeyCursorHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 OpenCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenCursorHelper::PackArgumentsForParentProcess "
+                             "[IDBIndex.cpp]");
+
   FIXME_Bug_521898_index::OpenCursorParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_index::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -2232,16 +2400,20 @@ OpenCursorHelper::PackArgumentsForParent
 
 AsyncConnectionHelper::ChildProcessSendResult
 OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenCursorHelper::SendResponseToChildProcess "
+                             "[IDBIndex.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   InfallibleTArray<PBlobParent*> blobsParent;
 
   if (NS_SUCCEEDED(aResultCode)) {
     IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
     NS_ASSERTION(database, "This should never be null!");
@@ -2312,16 +2484,21 @@ OpenCursorHelper::SendResponseToChildPro
   }
 
   return Success_Sent;
 }
 
 nsresult
 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "CountHelper::DoDatabaseWork [IDBIndex.cpp]");
+
   nsCString table;
   if (mIndex->IsUnique()) {
     table.AssignLiteral("unique_index_data");
   }
   else {
     table.AssignLiteral("index_data");
   }
 
@@ -2386,16 +2563,23 @@ CountHelper::ReleaseMainThreadObjects()
 {
   mKeyRange = nullptr;
   IndexHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 CountHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "CountHelper::PackArgumentsForParentProcess "
+                             "[IDBIndex.cpp]");
+
   FIXME_Bug_521898_index::CountParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_index::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -2407,16 +2591,20 @@ CountHelper::PackArgumentsForParentProce
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 CountHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "CountHelper::SendResponseToChildProcess "
+                             "[IDBIndex.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -33,16 +33,17 @@
 #include "IDBEvents.h"
 #include "IDBFileHandle.h"
 #include "IDBIndex.h"
 #include "IDBKeyRange.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 #include "DictionaryHelpers.h"
 #include "KeyPath.h"
+#include "ProfilerHelpers.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 
 #define FILE_COPY_BUFFER_SIZE 32768
 
@@ -972,16 +973,21 @@ IDBObjectStore::AppendIndexUpdateInfo(
 nsresult
 IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
                               int64_t aObjectStoreId,
                               const Key& aObjectStoreKey,
                               bool aOverwrite,
                               int64_t aObjectDataId,
                               const nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "IDBObjectStore::UpdateIndexes");
+
   nsresult rv;
 
   NS_ASSERTION(aObjectDataId != INT64_MIN, "Bad objectData id!");
 
   NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id");
 
   if (aOverwrite) {
     nsCOMPtr<mozIStorageStatement> deleteStmt =
@@ -1072,16 +1078,22 @@ IDBObjectStore::UpdateIndexes(IDBTransac
 nsresult
 IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
                                            mozIStorageStatement* aStatement,
                                            uint32_t aDataIndex,
                                            uint32_t aFileIdsIndex,
                                            IDBDatabase* aDatabase,
                                            StructuredCloneReadInfo& aInfo)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB",
+                 "IDBObjectStore::GetStructuredCloneReadInfoFromStatement");
+
 #ifdef DEBUG
   {
     int32_t type;
     NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(aDataIndex, &type)) &&
                  type == mozIStorageStatement::VALUE_TYPE_BLOB,
                  "Bad value type!");
   }
 #endif
@@ -1820,16 +1832,39 @@ IDBObjectStore::AddOrPut(const jsval& aV
 
   nsRefPtr<AddHelper> helper =
     new AddHelper(mTransaction, request, this, cloneWriteInfo, key,
                   aOverwrite, updateInfo);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+#ifdef IDB_PROFILER_USE_MARKS
+  if (aOverwrite) {
+    IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                      "database(%s).transaction(%s).objectStore(%s).%s(%s)",
+                      "IDBRequest[%llu] MT IDBObjectStore.put()",
+                      request->GetSerialNumber(),
+                      IDB_PROFILER_STRING(Transaction()->Database()),
+                      IDB_PROFILER_STRING(Transaction()),
+                      IDB_PROFILER_STRING(this),
+                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
+  }
+  else {
+    IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                      "database(%s).transaction(%s).objectStore(%s).add(%s)",
+                      "IDBRequest[%llu] MT IDBObjectStore.add()",
+                      request->GetSerialNumber(),
+                      IDB_PROFILER_STRING(Transaction()->Database()),
+                      IDB_PROFILER_STRING(Transaction()),
+                      IDB_PROFILER_STRING(this),
+                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
+  }
+#endif
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::AddOrPutInternal(
                       const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
                       const Key& aKey,
@@ -1906,16 +1941,39 @@ IDBObjectStore::AddOrPutInternal(
 
   nsRefPtr<AddHelper> helper =
     new AddHelper(mTransaction, request, this, cloneWriteInfo, key, aOverwrite,
                   updateInfo);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+#ifdef IDB_PROFILER_USE_MARKS
+  if (aOverwrite) {
+    IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                      "database(%s).transaction(%s).objectStore(%s).%s(%s)",
+                      "IDBRequest[%llu] MT IDBObjectStore.put()",
+                      request->GetSerialNumber(),
+                      IDB_PROFILER_STRING(Transaction()->Database()),
+                      IDB_PROFILER_STRING(Transaction()),
+                      IDB_PROFILER_STRING(this),
+                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
+  }
+  else {
+    IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                      "database(%s).transaction(%s).objectStore(%s).add(%s)",
+                      "IDBRequest[%llu] MT IDBObjectStore.add()",
+                      request->GetSerialNumber(),
+                      IDB_PROFILER_STRING(Transaction()->Database()),
+                      IDB_PROFILER_STRING(Transaction()),
+                      IDB_PROFILER_STRING(this),
+                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
+  }
+#endif
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::GetInternal(IDBKeyRange* aKeyRange,
                             JSContext* aCx,
                             IDBRequest** _retval)
@@ -1931,16 +1989,24 @@ IDBObjectStore::GetInternal(IDBKeyRange*
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetHelper> helper =
     new GetHelper(mTransaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).get(%s)",
+                    "IDBRequest[%llu] MT IDBObjectStore.get()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::GetAllInternal(IDBKeyRange* aKeyRange,
                                uint32_t aLimit,
                                JSContext* aCx,
@@ -1956,16 +2022,26 @@ IDBObjectStore::GetAllInternal(IDBKeyRan
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<GetAllHelper> helper =
     new GetAllHelper(mTransaction, request, this, aKeyRange, aLimit);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s)."
+                    "getAll(%s, %lu)",
+                    "IDBRequest[%llu] MT IDBObjectStore.getAll()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
+                    aLimit);
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::DeleteInternal(IDBKeyRange* aKeyRange,
                                JSContext* aCx,
                                IDBRequest** _retval)
@@ -1985,16 +2061,24 @@ IDBObjectStore::DeleteInternal(IDBKeyRan
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<DeleteHelper> helper =
     new DeleteHelper(mTransaction, request, this, aKeyRange);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).delete(%s)",
+                    "IDBRequest[%llu] MT IDBObjectStore.delete()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::ClearInternal(JSContext* aCx,
                               IDBRequest** _retval)
 {
@@ -2011,16 +2095,24 @@ IDBObjectStore::ClearInternal(JSContext*
   nsRefPtr<IDBRequest> request = GenerateRequest(this, aCx);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this));
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).clear()",
+                    "IDBRequest[%llu] MT IDBObjectStore.clear()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::CountInternal(IDBKeyRange* aKeyRange,
                               JSContext* aCx,
                               IDBRequest** _retval)
@@ -2034,16 +2126,24 @@ IDBObjectStore::CountInternal(IDBKeyRang
   nsRefPtr<IDBRequest> request = GenerateRequest(this, aCx);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<CountHelper> helper =
     new CountHelper(mTransaction, request, this, aKeyRange);
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s).count(%s)",
+                    "IDBRequest[%llu] MT IDBObjectStore.count()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::OpenCursorInternal(IDBKeyRange* aKeyRange,
                                    size_t aDirection,
                                    JSContext* aCx,
@@ -2062,16 +2162,26 @@ IDBObjectStore::OpenCursorInternal(IDBKe
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
     new OpenCursorHelper(mTransaction, request, this, aKeyRange, direction);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: "
+                    "database(%s).transaction(%s).objectStore(%s)."
+                    "openCursor(%s, %s)",
+                    "IDBRequest[%llu] MT IDBObjectStore.openCursor()",
+                    request->GetSerialNumber(),
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
+                    IDB_PROFILER_STRING(direction));
+
   request.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::OpenCursorFromChildProcess(
                             IDBRequest* aRequest,
                             size_t aDirection,
@@ -2143,16 +2253,24 @@ IDBObjectStore::CreateIndexInternal(cons
       new CreateIndexHelper(mTransaction, index);
 
     nsresult rv = helper->DispatchToTransactionPool();
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   autoRemove.forget();
 
+  IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
+                    "database(%s).transaction(%s).objectStore(%s)."
+                    "createIndex(%s)",
+                    "MT IDBObjectStore.createIndex()",
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index));
+
   index.forget(_retval);
   return NS_OK;
 }
 
 nsresult
 IDBObjectStore::IndexInternal(const nsAString& aName,
                               IDBIndex** _retval)
 {
@@ -2651,16 +2769,25 @@ IDBObjectStore::DeleteIndex(const nsAStr
 
   for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) {
     if (mCreatedIndexes[i]->Name() == aName) {
       mCreatedIndexes.RemoveElementAt(i);
       break;
     }
   }
 
+  IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
+                    "database(%s).transaction(%s).objectStore(%s)."
+                    "deleteIndex(\"%s\")",
+                    "MT IDBObjectStore.deleteIndex()",
+                    IDB_PROFILER_STRING(Transaction()->Database()),
+                    IDB_PROFILER_STRING(Transaction()),
+                    IDB_PROFILER_STRING(this),
+                    NS_ConvertUTF16toUTF8(aName).get());
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Count(const jsval& aKey,
                       JSContext* aCx,
                       uint8_t aOptionalArgCount,
                       nsIIDBRequest** _retval)
@@ -2685,16 +2812,21 @@ IDBObjectStore::Count(const jsval& aKey,
 
   request.forget(_retval);
   return NS_OK;
 }
 
 inline nsresult
 CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "CopyData");
+
   nsresult rv;
 
   do {
     char copyBuffer[FILE_COPY_BUFFER_SIZE];
 
     uint32_t numRead;
     rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -2724,16 +2856,20 @@ ObjectStoreHelper::ReleaseMainThreadObje
 {
   mObjectStore = nullptr;
   AsyncConnectionHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 ObjectStoreHelper::Dispatch(nsIEventTarget* aDatabaseThread)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "ObjectStoreHelper::Dispatch");
+
   if (IndexedDatabaseManager::IsMainProcess()) {
     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
   }
 
   // If we've been invalidated then there's no point sending anything to the
   // parent process.
   if (mObjectStore->Transaction()->Database()->IsInvalidated()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -2792,18 +2928,22 @@ NoRequestObjectStoreHelper::OnError()
 {
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   mTransaction->Abort(GetResultCode());
 }
 
 nsresult
 AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
+  PROFILER_LABEL("IndexedDB", "AddHelper::DoDatabaseWork");
+
   nsresult rv;
   bool keyUnset = mKey.IsUnset();
   int64_t osid = mObjectStore->Id();
   const KeyPath& keyPath = mObjectStore->GetKeyPath();
 
   // The "|| keyUnset" here is mostly a debugging tool. If a key isn't
   // specified we should never have a collision and so it shouldn't matter
   // if we allow overwrite or not. By not allowing overwrite we raise
@@ -2984,16 +3124,22 @@ AddHelper::ReleaseMainThreadObjects()
 {
   IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo);
   ObjectStoreHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "AddHelper::PackArgumentsForParentProcess");
+
   AddPutParams commonParams;
   commonParams.cloneInfo() = mCloneWriteInfo;
   commonParams.key() = mKey;
   commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo);
 
   const nsTArray<StructuredCloneFile>& files = mCloneWriteInfo.mFiles;
 
   if (!files.IsEmpty()) {
@@ -3035,16 +3181,19 @@ AddHelper::PackArgumentsForParentProcess
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 AddHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "AddHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response =  aResultCode;
   }
   else if (mOverwrite) {
@@ -3077,18 +3226,22 @@ AddHelper::UnpackResponseFromParentProce
          aResponseValue.get_AddResponse().key();
 
   return NS_OK;
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
+  PROFILER_LABEL("IndexedDB", "GetHelper::DoDatabaseWork [IDBObjectStore.cpp]");
+
   nsCString keyRangeClause;
   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1");
@@ -3136,32 +3289,42 @@ GetHelper::ReleaseMainThreadObjects()
   mKeyRange = nullptr;
   IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   ObjectStoreHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 GetHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "This should never be null!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetHelper::PackArgumentsForParentProcess "
+                             "[IDBObjectStore.cpp]");
+
   FIXME_Bug_521898_objectstore::GetParams params;
 
   mKeyRange->ToSerializedKeyRange(params.keyRange());
 
   aParams = params;
   return NS_OK;
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 GetHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetHelper::SendResponseToChildProcess "
+                             "[IDBObjectStore.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   InfallibleTArray<PBlobParent*> blobsParent;
 
   if (NS_SUCCEEDED(aResultCode)) {
     IDBDatabase* database = mObjectStore->Transaction()->Database();
     NS_ASSERTION(database, "This should never be null!");
@@ -3221,18 +3384,22 @@ GetHelper::UnpackResponseFromParentProce
   IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
                                        mCloneReadInfo.mFiles);
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
+  PROFILER_LABEL("IndexedDB", "DeleteHelper::DoDatabaseWork");
+
   nsCString keyRangeClause;
   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
   nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data "
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause;
@@ -3261,32 +3428,40 @@ DeleteHelper::GetSuccessResult(JSContext
 {
   *aVal = JSVAL_VOID;
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(mKeyRange, "This should never be null!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "DeleteHelper::PackArgumentsForParentProcess");
+
   DeleteParams params;
 
   mKeyRange->ToSerializedKeyRange(params.keyRange());
 
   aParams = params;
   return NS_OK;
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 DeleteHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "DeleteHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
@@ -3308,17 +3483,21 @@ DeleteHelper::UnpackResponseFromParentPr
                "Bad response type!");
 
   return NS_OK;
 }
 
 nsresult
 ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
-  NS_PRECONDITION(aConnection, "Passed a null connection!");
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  NS_ASSERTION(aConnection, "Passed a null connection!");
+
+  PROFILER_LABEL("IndexedDB", "ClearHelper::DoDatabaseWork");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       NS_LITERAL_CSTRING("DELETE FROM object_data "
                          "WHERE object_store_id = :osid"));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
@@ -3331,26 +3510,35 @@ ClearHelper::DoDatabaseWork(mozIStorageC
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "ClearHelper::PackArgumentsForParentProcess");
+
   aParams = ClearParams();
   return NS_OK;
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 ClearHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "ClearHelper::SendResponseToChildProcess");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
@@ -3372,16 +3560,22 @@ ClearHelper::UnpackResponseFromParentPro
                "Bad response type!");
 
   return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB",
+                 "OpenCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]");
+
   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
   }
 
   nsAutoCString directionClause;
@@ -3551,16 +3745,23 @@ OpenCursorHelper::ReleaseMainThreadObjec
 
   ObjectStoreHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 OpenCursorHelper::PackArgumentsForParentProcess(
                                               ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenCursorHelper::PackArgumentsForParentProcess "
+                             "[IDBObjectStore.cpp]");
+
   FIXME_Bug_521898_objectstore::OpenCursorParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_objectstore::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -3575,16 +3776,20 @@ OpenCursorHelper::PackArgumentsForParent
 
 AsyncConnectionHelper::ChildProcessSendResult
 OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenCursorHelper::SendResponseToChildProcess "
+                             "[IDBObjectStore.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   InfallibleTArray<PBlobParent*> blobsParent;
 
   if (NS_SUCCEEDED(aResultCode)) {
     IDBDatabase* database = mObjectStore->Transaction()->Database();
     NS_ASSERTION(database, "This should never be null!");
@@ -3693,16 +3898,21 @@ OpenCursorHelper::UnpackResponseFromPare
   }
 
   return NS_OK;
 }
 
 nsresult
 CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "CreateIndexHelper::DoDatabaseWork");
+
   // Insert the data into the database.
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
       "multientry, object_store_id) "
     "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)"
   );
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -3850,17 +4060,20 @@ void
 CreateIndexHelper::DestroyTLSEntry(void* aPtr)
 {
   delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
 }
 
 nsresult
 DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
-  NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "DeleteIndexHelper::DoDatabaseWork");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       "DELETE FROM object_store_index "
       "WHERE name = :name "
     );
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -3874,16 +4087,22 @@ DeleteIndexHelper::DoDatabaseWork(mozISt
   }
 
   return NS_OK;
 }
 
 nsresult
 GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB",
+                 "GetAllHelper::DoDatabaseWork [IDBObjectStore.cpp]");
+
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsAutoCString keyRangeClause;
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
       if (mKeyRange->IsLowerOpen()) {
@@ -3982,16 +4201,23 @@ GetAllHelper::ReleaseMainThreadObjects()
     IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]);
   }
   ObjectStoreHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 GetAllHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetAllHelper::PackArgumentsForParentProcess "
+                             "[IDBObjectStore.cpp]");
+
   FIXME_Bug_521898_objectstore::GetAllParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_objectstore::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -4005,16 +4231,20 @@ GetAllHelper::PackArgumentsForParentProc
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 GetAllHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "GetAllHelper::SendResponseToChildProcess "
+                             "[IDBObjectStore.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   GetAllResponse getAllResponse;
   if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
     IDBDatabase* database = mObjectStore->Transaction()->Database();
     NS_ASSERTION(database, "This should never be null!");
 
@@ -4099,16 +4329,22 @@ GetAllHelper::UnpackResponseFromParentPr
   }
 
   return NS_OK;
 }
 
 nsresult
 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB",
+                 "CountHelper::DoDatabaseWork [IDBObjectStore.cpp]");
+
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsAutoCString keyRangeClause;
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
       if (mKeyRange->IsLowerOpen()) {
@@ -4178,16 +4414,23 @@ CountHelper::ReleaseMainThreadObjects()
 {
   mKeyRange = nullptr;
   ObjectStoreHelper::ReleaseMainThreadObjects();
 }
 
 nsresult
 CountHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "CountHelper::PackArgumentsForParentProcess "
+                             "[IDBObjectStore.cpp]");
+
   FIXME_Bug_521898_objectstore::CountParams params;
 
   if (mKeyRange) {
     FIXME_Bug_521898_objectstore::KeyRange keyRange;
     mKeyRange->ToSerializedKeyRange(keyRange);
     params.optionalKeyRange() = keyRange;
   }
   else {
@@ -4199,16 +4442,20 @@ CountHelper::PackArgumentsForParentProce
 }
 
 AsyncConnectionHelper::ChildProcessSendResult
 CountHelper::SendResponseToChildProcess(nsresult aResultCode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "CountHelper::SendResponseToChildProcess "
+                             "[IDBObjectStore.cpp]");
+
   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
   NS_ASSERTION(actor, "How did we get this far without an actor?");
 
   ResponseValue response;
   if (NS_FAILED(aResultCode)) {
     response = aResultCode;
   }
   else {
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -20,24 +20,35 @@
 #include "nsWrapperCacheInlines.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBTransaction.h"
 #include "DOMError.h"
 
+namespace {
+
+#ifdef MOZ_ENABLE_PROFILER_SPS
+uint64_t gNextSerialNumber = 1;
+#endif
+
+} // anonymous namespace
+
 USING_INDEXEDDB_NAMESPACE
 
 IDBRequest::IDBRequest()
 : mResultVal(JSVAL_VOID),
   mActorParent(nullptr),
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  mSerialNumber(gNextSerialNumber++),
+#endif
   mErrorCode(NS_OK),
-  mHaveResultOrErrorCode(false),
-  mLineNo(0)
+  mLineNo(0),
+  mHaveResultOrErrorCode(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBRequest::~IDBRequest()
 {
   mResultVal = JSVAL_VOID;
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -79,39 +79,47 @@ public:
   {
     return mActorParent;
   }
 
   void CaptureCaller(JSContext* aCx);
 
   void FillScriptErrorEvent(nsScriptErrorEvent* aEvent) const;
 
-  bool IsPending() const
+  bool
+  IsPending() const
   {
     return !mHaveResultOrErrorCode;
   }
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  uint64_t
+  GetSerialNumber() const
+  {
+    return mSerialNumber;
+  }
+#endif
+
 protected:
   IDBRequest();
   ~IDBRequest();
 
   nsCOMPtr<nsISupports> mSource;
   nsRefPtr<IDBTransaction> mTransaction;
 
   jsval mResultVal;
-
   nsCOMPtr<nsIDOMDOMError> mError;
-
   IndexedDBRequestParentBase* mActorParent;
-
+  nsString mFilename;
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  uint64_t mSerialNumber;
+#endif
   nsresult mErrorCode;
+  uint32_t mLineNo;
   bool mHaveResultOrErrorCode;
-
-  nsString mFilename;
-  uint32_t mLineNo;
 };
 
 class IDBOpenDBRequest : public IDBRequest,
                          public nsIIDBOpenDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -25,29 +25,34 @@
 
 #include "AsyncConnectionHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBObjectStore.h"
 #include "IndexedDatabaseManager.h"
+#include "ProfilerHelpers.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 
 #define SAVEPOINT_NAME "savepoint"
 
 USING_INDEXEDDB_NAMESPACE
 using mozilla::dom::quota::QuotaManager;
 
 namespace {
 
 NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+uint64_t gNextSerialNumber = 1;
+#endif
+
 PLDHashOperator
 DoomCachedStatements(const nsACString& aQuery,
                      nsCOMPtr<mozIStorageStatement>& aStatement,
                      void* aUserArg)
 {
   CommitHelper* helper = static_cast<CommitHelper*>(aUserArg);
   helper->AddDoomedObject(aStatement);
   return PL_DHASH_REMOVE;
@@ -160,16 +165,19 @@ IDBTransaction::CreateInternal(IDBDataba
 IDBTransaction::IDBTransaction()
 : mReadyState(IDBTransaction::INITIAL),
   mMode(IDBTransaction::READ_ONLY),
   mPendingRequests(0),
   mSavepointCount(0),
   mActorChild(nullptr),
   mActorParent(nullptr),
   mAbortCode(NS_OK),
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  mSerialNumber(gNextSerialNumber++),
+#endif
   mCreating(false)
 #ifdef DEBUG
   , mFiredCompleteOrAbort(false)
 #endif
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
@@ -340,18 +348,20 @@ IDBTransaction::RollbackSavepoint()
 
   nsresult rv = stmt->Execute();
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
 nsresult
 IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_LABEL("IndexedDB", "IDBTransaction::GetOrCreateConnection");
 
   if (mDatabase->IsInvalidated()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mConnection) {
     nsCOMPtr<mozIStorageConnection> connection =
       IDBFactory::GetConnection(mDatabase->FilePath(),
@@ -811,16 +821,18 @@ CommitHelper::~CommitHelper()
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(CommitHelper, nsIRunnable)
 
 NS_IMETHODIMP
 CommitHelper::Run()
 {
   if (NS_IsMainThread()) {
+    PROFILER_MAIN_THREAD_LABEL("IndexedDB", "CommitHelper::Run");
+
     NS_ASSERTION(mDoomedObjects.IsEmpty(), "Didn't release doomed objects!");
 
     mTransaction->mReadyState = IDBTransaction::DONE;
 
     // Release file infos on the main thread, so they will eventually get
     // destroyed on correct thread.
     mTransaction->ClearCreatedFileInfos();
     if (mUpdateFileRefcountFunction) {
@@ -855,16 +867,20 @@ CommitHelper::Run()
                                  eDoesNotBubble, eNotCancelable);
     }
     NS_ENSURE_TRUE(event, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (mListener) {
       mListener->NotifyTransactionPreComplete(mTransaction);
     }
 
+    IDB_PROFILER_MARK("IndexedDB Transaction %llu: Complete (rv = %lu)",
+                      "IDBTransaction[%llu] MT Complete",
+                      mTransaction->GetSerialNumber(), mAbortCode);
+
     bool dummy;
     if (NS_FAILED(mTransaction->DispatchEvent(event, &dummy))) {
       NS_WARNING("Dispatch failed!");
     }
 
 #ifdef DEBUG
     mTransaction->mFiredCompleteOrAbort = true;
 #endif
@@ -873,16 +889,18 @@ CommitHelper::Run()
       mListener->NotifyTransactionPostComplete(mTransaction);
     }
 
     mTransaction = nullptr;
 
     return NS_OK;
   }
 
+  PROFILER_LABEL("IndexedDB", "CommitHelper::Run");
+
   IDBDatabase* database = mTransaction->Database();
   if (database->IsInvalidated()) {
     mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (mConnection) {
     QuotaManager::SetCurrentWindow(database->GetOwner());
 
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -207,16 +207,24 @@ public:
   Abort(nsresult aAbortCode);
 
   nsresult
   GetAbortCode() const
   {
     return mAbortCode;
   }
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  uint64_t
+  GetSerialNumber() const
+  {
+    return mSerialNumber;
+  }
+#endif
+
 private:
   nsresult
   AbortInternal(nsresult aAbortCode, already_AddRefed<nsIDOMDOMError> aError);
 
   // Should only be called directly through IndexedDBDatabaseChild.
   static already_AddRefed<IDBTransaction>
   CreateInternal(IDBDatabase* aDatabase,
                  nsTArray<nsString>& aObjectStoreNames,
@@ -253,16 +261,19 @@ private:
 
   nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
   nsRefPtrHashtable<nsISupportsHashKey, FileInfo> mCreatedFileInfos;
 
   IndexedDBTransactionChild* mActorChild;
   IndexedDBTransactionParent* mActorParent;
 
   nsresult mAbortCode;
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  uint64_t mSerialNumber;
+#endif
   bool mCreating;
 
 #ifdef DEBUG
   bool mFiredCompleteOrAbort;
 #endif
 };
 
 class CommitHelper MOZ_FINAL : public nsIRunnable
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -95,28 +95,60 @@ public:
 
   bool IsUnset() const
   {
     return mBuffer.IsVoid();
   }
 
   bool IsFloat() const
   {
-    return !mBuffer.IsVoid() && mBuffer.First() == eFloat;
+    return !IsUnset() && mBuffer.First() == eFloat;
+  }
+
+  bool IsDate() const
+  {
+    return !IsUnset() && mBuffer.First() == eDate;
+  }
+
+  bool IsString() const
+  {
+    return !IsUnset() && mBuffer.First() == eString;
+  }
+
+  bool IsArray() const
+  {
+    return !IsUnset() && mBuffer.First() >= eArray;
   }
 
   double ToFloat() const
   {
     NS_ASSERTION(IsFloat(), "Why'd you call this?");
     const unsigned char* pos = BufferStart();
     double res = DecodeNumber(pos, BufferEnd());
     NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer");
     return res;
   }
 
+  double ToDateMsec() const
+  {
+    NS_ASSERTION(IsDate(), "Why'd you call this?");
+    const unsigned char* pos = BufferStart();
+    double res = DecodeNumber(pos, BufferEnd());
+    NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer");
+    return res;
+  }
+
+  void ToString(nsString& aString) const
+  {
+    NS_ASSERTION(IsString(), "Why'd you call this?");
+    const unsigned char* pos = BufferStart();
+    DecodeString(pos, BufferEnd(), aString);
+    NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer");
+  }
+
   void SetFromString(const nsAString& aString)
   {
     mBuffer.Truncate();
     EncodeString(aString, 0);
     TrimBuffer();
   }
 
   void SetFromInteger(int64_t aInt)
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -1,33 +1,34 @@
 /* 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 "mozilla/DebugOnly.h"
 
 #include "OpenDatabaseHelper.h"
 
+#include "nsIBFCacheEntry.h"
 #include "nsIFile.h"
 
+#include <algorithm>
 #include "mozilla/dom/quota/AcquireListener.h"
 #include "mozilla/dom/quota/OriginOrPatternString.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/storage.h"
 #include "nsEscape.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "snappy/snappy.h"
 
 #include "Client.h"
-#include "nsIBFCacheEntry.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IndexedDatabaseManager.h"
-#include <algorithm>
+#include "ProfilerHelpers.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_INDEXEDDB_NAMESPACE
 USING_QUOTA_NAMESPACE
 
 namespace {
 
@@ -90,16 +91,21 @@ GetDatabaseFilename(const nsAString& aNa
   aDatabaseFilename.Append(NS_ConvertASCIItoUTF16(substring));
 
   return NS_OK;
 }
 
 nsresult
 CreateFileTables(mozIStorageConnection* aDBConn)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "CreateFileTables");
+
   // Table `file`
   nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE file ("
       "id INTEGER PRIMARY KEY, "
       "refcount INTEGER NOT NULL"
     ");"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -147,19 +153,21 @@ CreateFileTables(mozIStorageConnection* 
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 CreateTables(mozIStorageConnection* aDBConn)
 {
-  NS_PRECONDITION(!NS_IsMainThread(),
-                  "Creating tables on the main thread!");
-  NS_PRECONDITION(aDBConn, "Passing a null database connection!");
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  NS_ASSERTION(aDBConn, "Passing a null database connection!");
+
+  PROFILER_LABEL("IndexedDB", "CreateTables");
 
   // Table `database`
   nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE database ("
       "name TEXT NOT NULL, "
       "version INTEGER NOT NULL DEFAULT 0"
     ");"
   ));
@@ -262,16 +270,21 @@ CreateTables(mozIStorageConnection* aDBC
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom4To5");
+
   nsresult rv;
 
   // All we changed is the type of the version column, so lets try to
   // convert that to an integer, and if we fail, set it to 0.
   nsCOMPtr<mozIStorageStatement> stmt;
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT name, version, dataVersion "
     "FROM database"
@@ -346,16 +359,21 @@ UpgradeSchemaFrom4To5(mozIStorageConnect
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom5To6");
+
   // First, drop all the indexes we're no longer going to use.
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DROP INDEX key_index;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DROP INDEX ai_key_index;"
@@ -699,16 +717,21 @@ UpgradeSchemaFrom5To6(mozIStorageConnect
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom6To7");
+
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TEMPORARY TABLE temp_upgrade ("
       "id, "
       "name, "
       "key_path, "
       "auto_increment"
     ");"
   ));
@@ -753,16 +776,21 @@ UpgradeSchemaFrom6To7(mozIStorageConnect
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom7To8");
+
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TEMPORARY TABLE temp_upgrade ("
       "id, "
       "object_store_id, "
       "name, "
       "key_path, "
       "unique_index, "
       "object_store_autoincrement"
@@ -823,16 +851,18 @@ class CompressDataBlobsFunction MOZ_FINA
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult)
   {
+    PROFILER_LABEL("IndexedDB", "CompressDataBlobsFunction::OnFunctionCall");
+
     uint32_t argc;
     nsresult rv = aArguments->GetNumEntries(&argc);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (argc != 1) {
       NS_WARNING("Don't call me with the wrong number of arguments!");
       return NS_ERROR_UNEXPECTED;
     }
@@ -870,16 +900,21 @@ public:
   }
 };
 
 NS_IMPL_ISUPPORTS1(CompressDataBlobsFunction, mozIStorageFunction)
 
 nsresult
 UpgradeSchemaFrom8To9_0(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom8To9_0");
+
   // We no longer use the dataVersion column.
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "UPDATE database SET dataVersion = 0;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStorageFunction> compressor = new CompressDataBlobsFunction();
 
@@ -906,16 +941,21 @@ UpgradeSchemaFrom8To9_0(mozIStorageConne
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom9_0To10_0(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom9_0To10_0");
+
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"
   ));
@@ -928,16 +968,21 @@ UpgradeSchemaFrom9_0To10_0(mozIStorageCo
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom10_0To11_0");
+
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TEMPORARY TABLE temp_upgrade ("
       "id, "
       "object_store_id, "
       "name, "
       "key_path, "
       "unique_index, "
       "multientry"
@@ -1065,16 +1110,18 @@ class EncodeKeysFunction MOZ_FINAL : pub
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult)
   {
+    PROFILER_LABEL("IndexedDB", "EncodeKeysFunction::OnFunctionCall");
+
     uint32_t argc;
     nsresult rv = aArguments->GetNumEntries(&argc);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (argc != 1) {
       NS_WARNING("Don't call me with the wrong number of arguments!");
       return NS_ERROR_UNEXPECTED;
     }
@@ -1111,16 +1158,21 @@ public:
   }
 };
 
 NS_IMPL_ISUPPORTS1(EncodeKeysFunction, mozIStorageFunction)
 
 nsresult
 UpgradeSchemaFrom11_0To12_0(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom11_0To12_0");
+
   NS_NAMED_LITERAL_CSTRING(encoderName, "encode");
 
   nsCOMPtr<mozIStorageFunction> encoder = new EncodeKeysFunction();
 
   nsresult rv = aConnection->CreateFunction(encoderName, 1, encoder);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
@@ -1323,16 +1375,21 @@ UpgradeSchemaFrom11_0To12_0(mozIStorageC
 
   return NS_OK;
 }
 
 nsresult
 UpgradeSchemaFrom12_0To13_0(mozIStorageConnection* aConnection,
                             bool* aVacuumNeeded)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom12_0To13_0");
+
   nsresult rv;
 
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   int32_t defaultPageSize;
   rv = aConnection->GetDefaultPageSize(&defaultPageSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Enable auto_vacuum mode and update the page size to the platform default.
@@ -1538,16 +1595,18 @@ public:
 
     mWaitingDatabases.SwapElements(aWaitingDatabases);
   }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+    PROFILER_MAIN_THREAD_LABEL("IndexedDB", "VersionChangeEventsRunnable::Run");
+
     // Fire version change events at all of the databases that are not already
     // closed. Also kick bfcached documents out of bfcache.
     uint32_t count = mWaitingDatabases.Length();
     for (uint32_t index = 0; index < count; index++) {
       IDBDatabase* database =
         IDBDatabase::FromStorage(mWaitingDatabases[index]);
       NS_ASSERTION(database, "This shouldn't be null!");
 
@@ -1662,16 +1721,19 @@ OpenDatabaseHelper::DoDatabaseWork()
   {
     bool correctThread;
     NS_ASSERTION(NS_SUCCEEDED(QuotaManager::Get()->IOThread()->
                               IsOnCurrentThread(&correctThread)) &&
                  correctThread,
                  "Running on the wrong thread!");
   }
 #endif
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::DoDatabaseWork");
 
   mState = eFiringEvents; // In case we fail somewhere along the line.
 
   if (QuotaManager::IsShuttingDown()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   NS_ASSERTION(mOpenDBRequest, "This should never be null!");
@@ -1804,18 +1866,20 @@ OpenDatabaseHelper::DoDatabaseWork()
 nsresult
 OpenDatabaseHelper::CreateDatabaseConnection(
                                         nsIFile* aDBFile,
                                         nsIFile* aFMDirectory,
                                         const nsAString& aName,
                                         const nsACString& aOrigin,
                                         mozIStorageConnection** aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::CreateDatabaseConnection");
 
   nsCOMPtr<nsIFileURL> dbFileUrl =
     IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin);
   NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE);
 
   nsCOMPtr<mozIStorageService> ss =
     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
@@ -2050,16 +2114,18 @@ OpenDatabaseHelper::StartDelete()
 }
 
 NS_IMETHODIMP
 OpenDatabaseHelper::Run()
 {
   NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");
 
   if (NS_IsMainThread()) {
+    PROFILER_MAIN_THREAD_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
+
     // If we need to queue up a SetVersionHelper, do that here.
     if (mState == eSetVersionPending) {
       nsresult rv = StartSetVersion();
 
       if (NS_SUCCEEDED(rv)) {
         return rv;
       }
 
@@ -2118,16 +2184,21 @@ OpenDatabaseHelper::Run()
       }
 
       default:
         NS_NOTREACHED("Shouldn't get here!");
     }
 
     NS_ASSERTION(mState == eFiringEvents, "Why are we here?");
 
+    IDB_PROFILER_MARK("IndexedDB Request %llu: Running main thread "
+                      "response (rv = %lu)",
+                      "IDBRequest[%llu] MT Done",
+                      mRequest->GetSerialNumber(), mResultCode);
+
     if (NS_FAILED(mResultCode)) {
       DispatchErrorEvent();
     } else {
       DispatchSuccessEvent();
     }
 
     QuotaManager* quotaManager = QuotaManager::Get();
     NS_ASSERTION(quotaManager, "This should never be null!");
@@ -2136,29 +2207,43 @@ OpenDatabaseHelper::Run()
                                 OriginOrPatternString::FromOrigin(mASCIIOrigin),
                                 mDatabaseId);
 
     ReleaseMainThreadObjects();
 
     return NS_OK;
   }
 
+  PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
+
+  // We're on the DB thread.
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
-  // If we're on the DB thread, do that
+  IDB_PROFILER_MARK("IndexedDB Request %llu: Beginning database work",
+                    "IDBRequest[%llu] DT Start", mRequest->GetSerialNumber());
+
   NS_ASSERTION(mState == eDBWork, "Why are we here?");
   mResultCode = DoDatabaseWork();
   NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");
 
+  IDB_PROFILER_MARK("IndexedDB Request %llu: Finished database work (rv = %lu)",
+                    "IDBRequest[%llu] DT Done", mRequest->GetSerialNumber(),
+                    mResultCode);
+
   return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
 }
 
 nsresult
 OpenDatabaseHelper::EnsureSuccessResult()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "OpenDatabaseHelper::EnsureSuccessResult");
+
   nsRefPtr<DatabaseInfo> dbInfo;
   if (DatabaseInfo::Get(mDatabaseId, getter_AddRefs(dbInfo))) {
 
 #ifdef DEBUG
     {
       NS_ASSERTION(dbInfo->name == mName &&
                    dbInfo->version == mCurrentVersion &&
                    dbInfo->id == mDatabaseId &&
@@ -2286,31 +2371,41 @@ OpenDatabaseHelper::BlockDatabase()
   NS_ASSERTION(mDatabase, "This is going bad fast.");
 
   mDatabase->EnterSetVersionTransaction();
 }
 
 void
 OpenDatabaseHelper::DispatchSuccessEvent()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                              "OpenDatabaseHelper::DispatchSuccessEvent");
+
   nsRefPtr<nsIDOMEvent> event =
     CreateGenericEvent(mOpenDBRequest, NS_LITERAL_STRING(SUCCESS_EVT_STR),
                        eDoesNotBubble, eNotCancelable);
   if (!event) {
     NS_ERROR("Failed to create event!");
     return;
   }
 
   bool dummy;
   mOpenDBRequest->DispatchEvent(event, &dummy);
 }
 
 void
 OpenDatabaseHelper::DispatchErrorEvent()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                              "OpenDatabaseHelper::DispatchErrorEvent");
+
   nsRefPtr<nsIDOMEvent> event =
     CreateGenericEvent(mOpenDBRequest, NS_LITERAL_STRING(ERROR_EVT_STR),
                        eDoesBubble, eCancelable);
   if (!event) {
     NS_ERROR("Failed to create event!");
     return;
   }
 
@@ -2347,18 +2442,22 @@ SetVersionHelper::Init()
   mOpenHelper->BlockDatabase();
 
   return NS_OK;
 }
 
 nsresult
 SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(aConnection, "Passing a null connection!");
 
+  PROFILER_LABEL("IndexedDB", "SetVersionHelper::DoDatabaseWork");
+
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "UPDATE database "
     "SET version = :version"
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
@@ -2464,18 +2563,22 @@ SetVersionHelper::NotifyTransactionPostC
   return rv;
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(DeleteDatabaseHelper, AsyncConnectionHelper);
 
 nsresult
 DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!aConnection, "How did we get a connection here?");
 
+  PROFILER_LABEL("IndexedDB", "DeleteDatabaseHelper::DoDatabaseWork");
+
   const StoragePrivilege& privilege = mOpenHelper->Privilege();
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never fail!");
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = quotaManager->GetDirectoryForOrigin(mASCIIOrigin,
                                                     getter_AddRefs(directory));
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/ProfilerHelpers.h
@@ -0,0 +1,203 @@
+/* -*- 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_profilerhelpers_h__
+#define mozilla_dom_indexeddb_profilerhelpers_h__
+
+#include "GeckoProfiler.h"
+
+// Define this if you want IndexedDB operations to be marked in the profiler.
+#define IDB_PROFILER_USE_MARKS 0
+
+// Define this if you want extended details to appear in profiler marks.
+#define IDB_PROFILER_MARK_DETAILS 0
+
+// Sanity check the options above.
+#if IDB_PROFILER_USE_MARKS && !defined(MOZ_ENABLE_PROFILER_SPS)
+#error Cannot use IDB_PROFILER_USE_MARKS without MOZ_ENABLE_PROFILER_SPS!
+#endif
+
+#if IDB_PROFILER_MARK_DETAILS && !IDB_PROFILER_USE_MARKS
+#error Cannot use IDB_PROFILER_MARK_DETAILS without IDB_PROFILER_USE_MARKS!
+#endif
+
+#if IDB_PROFILER_USE_MARKS
+
+#if IDB_PROFILER_MARK_DETAILS
+
+#include "IDBCursor.h"
+#include "IDBDatabase.h"
+#include "IDBIndex.h"
+#include "IDBKeyRange.h"
+#include "IDBObjectStore.h"
+#include "IDBTransaction.h"
+#include "Key.h"
+
+BEGIN_INDEXEDDB_NAMESPACE
+
+class ProfilerString : public nsAutoCString
+{
+  static const char kQuote = '\"';
+  static const char kOpenBracket = '[';
+  static const char kCloseBracket = ']';
+  static const char kOpenParen = '(';
+  static const char kCloseParen = ')';
+
+public:
+  explicit
+  ProfilerString(IDBDatabase* aDatabase)
+  {
+    MOZ_ASSERT(aDatabase);
+
+    Append(kQuote);
+    AppendUTF16toUTF8(aDatabase->Name(), *this);
+    Append(kQuote);
+  }
+
+  explicit
+  ProfilerString(IDBTransaction* aTransaction)
+  {
+    MOZ_ASSERT(aTransaction);
+
+    switch (aTransaction->GetMode()) {
+      case IDBTransaction::READ_ONLY:
+        AppendLiteral("\"readonly\"");
+        break;
+      case IDBTransaction::READ_WRITE:
+        AppendLiteral("\"readwrite\"");
+        break;
+      case IDBTransaction::VERSION_CHANGE:
+        AppendLiteral("\"versionchange\"");
+        break;
+      default:
+        MOZ_NOT_REACHED("Unknown mode!");
+    };
+  }
+
+  explicit
+  ProfilerString(IDBObjectStore* aObjectStore)
+  {
+    MOZ_ASSERT(aObjectStore);
+
+    Append(kQuote);
+    AppendUTF16toUTF8(aObjectStore->Name(), *this);
+    Append(kQuote);
+  }
+
+  explicit
+  ProfilerString(IDBIndex* aIndex)
+  {
+    MOZ_ASSERT(aIndex);
+
+    Append(kQuote);
+    AppendUTF16toUTF8(aIndex->Name(), *this);
+    Append(kQuote);
+  }
+
+  explicit
+  ProfilerString(IDBKeyRange* aKeyRange)
+  {
+    if (aKeyRange) {
+      if (aKeyRange->IsOnly()) {
+        Append(ProfilerString(aKeyRange->Lower()));
+      }
+      else {
+        Append(aKeyRange->IsLowerOpen() ? kOpenParen : kOpenBracket);
+        Append(ProfilerString(aKeyRange->Lower()));
+        AppendLiteral(", ");
+        Append(ProfilerString(aKeyRange->Upper()));
+        Append(aKeyRange->IsUpperOpen() ? kCloseParen : kCloseBracket);
+      }
+    }
+  }
+
+  explicit
+  ProfilerString(const Key& aKey)
+  {
+    if (aKey.IsUnset()) {
+      Assign("null");
+    }
+    else if (aKey.IsFloat()) {
+      AppendPrintf("%g", aKey.ToFloat());
+    }
+    else if (aKey.IsDate()) {
+      AppendPrintf("<Date %g>", aKey.ToDateMsec());
+    }
+    else if (aKey.IsString()) {
+      nsAutoString str;
+      aKey.ToString(str);
+      AppendPrintf("\"%s\"", NS_ConvertUTF16toUTF8(str).get());
+    }
+    else {
+      MOZ_ASSERT(aKey.IsArray());
+      AppendLiteral("<Array>");
+    }
+  }
+
+  explicit
+  ProfilerString(const IDBCursor::Direction aDirection)
+  {
+    switch (aDirection) {
+      case IDBCursor::NEXT:
+        AppendLiteral("\"next\"");
+        break;
+      case IDBCursor::NEXT_UNIQUE:
+        AppendLiteral("\"nextunique\"");
+        break;
+      case IDBCursor::PREV:
+        AppendLiteral("\"prev\"");
+        break;
+      case IDBCursor::PREV_UNIQUE:
+        AppendLiteral("\"prevunique\"");
+        break;
+      default:
+        MOZ_NOT_REACHED("Unknown direction!");
+    };
+  }
+};
+
+END_INDEXEDDB_NAMESPACE
+
+#define IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, ...)                      \
+  do {                                                                         \
+    nsAutoCString _mark;                                                       \
+    _mark.AppendPrintf(_detailedFmt, ##__VA_ARGS__);                           \
+    PROFILER_MARKER(_mark.get());                                              \
+  } while (0)
+
+#define IDB_PROFILER_STRING(_arg)                                              \
+  mozilla::dom::indexedDB::ProfilerString((_arg)).get()
+
+#else // IDB_PROFILER_MARK_DETAILS
+
+#define IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, ...)                      \
+  do {                                                                         \
+    nsAutoCString _mark;                                                       \
+    _mark.AppendPrintf(_conciseFmt, ##__VA_ARGS__);                            \
+    PROFILER_MARKER(_mark.get());                                              \
+  } while (0)
+
+#define IDB_PROFILER_STRING(_arg) ""
+
+#endif // IDB_PROFILER_MARK_DETAILS
+
+#define IDB_PROFILER_MARK_IF(_cond, _detailedFmt, _conciseFmt, ...)            \
+  do {                                                                         \
+    if (_cond) {                                                               \
+      IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, __VA_ARGS__);               \
+    }                                                                          \
+  } while (0)
+
+#else // IDB_PROFILER_USE_MARKS
+
+#define IDB_PROFILER_MARK(...) do { } while(0)
+#define IDB_PROFILER_MARK_IF(_cond, ...) do { } while(0)
+#define IDB_PROFILER_MARK2(_detailedFmt, _notdetailedFmt, ...) do { } while(0)
+#define IDB_PROFILER_STRING(_arg) ""
+
+#endif // IDB_PROFILER_USE_MARKS
+
+#endif // mozilla_dom_indexeddb_profilerhelpers_h__
--- a/dom/indexedDB/TransactionThreadPool.cpp
+++ b/dom/indexedDB/TransactionThreadPool.cpp
@@ -9,29 +9,51 @@
 #include "nsIObserverService.h"
 #include "nsIThreadPool.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPCOMCIDInternal.h"
 
+#include "ProfilerHelpers.h"
+
 using mozilla::MonitorAutoLock;
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 const uint32_t kThreadLimit = 20;
 const uint32_t kIdleThreadLimit = 5;
 const uint32_t kIdleThreadTimeoutMs = 30000;
 
 TransactionThreadPool* gInstance = nullptr;
 bool gShutdown = false;
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+
+class ThreadPoolListener : public nsIThreadPoolListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITHREADPOOLLISTENER
+
+  ThreadPoolListener(TransactionThreadPool* aTransactionThreadPool)
+  : mTransactionThreadPool(aTransactionThreadPool)
+  {
+    MOZ_ASSERT(aTransactionThreadPool);
+  }
+
+private:
+  TransactionThreadPool* mTransactionThreadPool;
+};
+
+#endif // MOZ_ENABLE_PROFILER_SPS
+
 } // anonymous namespace
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class FinishTransactionRunnable MOZ_FINAL : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
@@ -118,24 +140,32 @@ TransactionThreadPool::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
   NS_ENSURE_SUCCESS(rv, rv);
 
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  nsRefPtr<ThreadPoolListener> listener = new ThreadPoolListener(this);
+  rv = mThreadPool->SetListener(listener);
+  NS_ENSURE_SUCCESS(rv, rv);
+#endif
+
   return NS_OK;
 }
 
 nsresult
 TransactionThreadPool::Cleanup()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "TransactionThreadPool::Cleanup");
+
   nsresult rv = mThreadPool->Shutdown();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Make sure the pool is still accessible while any callbacks generated from
   // the other threads are processed.
   rv = NS_ProcessPendingEvents(nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -176,16 +206,19 @@ TransactionThreadPool::MaybeUnblockTrans
 }
 
 void
 TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aTransaction, "Null pointer!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "TransactionThreadPool::FinishTransaction");
+
   // AddRef here because removing from the hash will call Release.
   nsRefPtr<IDBTransaction> transaction(aTransaction);
 
   nsIAtom* databaseId = aTransaction->mDatabase->Id();
 
   DatabaseTransactionInfo* dbTransactionInfo;
   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
     NS_ERROR("We don't know anyting about this database?!");
@@ -383,16 +416,20 @@ TransactionThreadPool::CollectTransactio
 }
 
 void
 TransactionThreadPool::AbortTransactionsForDatabase(IDBDatabase* aDatabase)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aDatabase, "Null pointer!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "TransactionThreadPool::"
+                             "AbortTransactionsForDatabase");
+
   // Get list of transactions for this database id
   DatabaseTransactionInfo* dbTransactionInfo;
   if (!mTransactionsInProgress.Get(aDatabase->Id(), &dbTransactionInfo)) {
     // If there are no transactions, we're done.
     return;
   }
 
   // Collect any running transactions
@@ -462,16 +499,19 @@ TransactionThreadPool::HasTransactionsFo
   return info.found;
 }
 
 bool
 TransactionThreadPool::MaybeFireCallback(DatabasesCompleteCallback aCallback)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
+                             "TransactionThreadPool::MaybeFireCallback");
+
   for (uint32_t index = 0; index < aCallback.mDatabases.Length(); index++) {
     IDBDatabase* database = aCallback.mDatabases[index];
     if (!database) {
       MOZ_CRASH();
     }
 
     if (mTransactionsInProgress.Get(database->Id(),
                                     nullptr)) {
@@ -484,16 +524,17 @@ TransactionThreadPool::MaybeFireCallback
 }
 
 TransactionThreadPool::
 TransactionQueue::TransactionQueue(IDBTransaction* aTransaction)
 : mMonitor("TransactionQueue::mMonitor"),
   mTransaction(aTransaction),
   mShouldFinish(false)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aTransaction, "Null pointer!");
 }
 
 void
 TransactionThreadPool::TransactionQueue::Unblock()
 {
   MonitorAutoLock lock(mMonitor);
 
@@ -529,16 +570,25 @@ TransactionThreadPool::TransactionQueue:
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(TransactionThreadPool::TransactionQueue,
                               nsIRunnable)
 
 NS_IMETHODIMP
 TransactionThreadPool::TransactionQueue::Run()
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  PROFILER_LABEL("IndexedDB", "TransactionQueue::Run");
+
+  IDB_PROFILER_MARK("IndexedDB Transaction %llu: Beginning database work",
+                    "IDBTransaction[%llu] DT Start",
+                    mTransaction->GetSerialNumber());
+
   nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue;
   nsCOMPtr<nsIRunnable> finishRunnable;
   bool shouldFinish = false;
 
   do {
     NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!");
 
     {
@@ -563,16 +613,20 @@ TransactionThreadPool::TransactionQueue:
       runnable = nullptr;
     }
 
     if (count) {
       queue.Clear();
     }
   } while (!shouldFinish);
 
+  IDB_PROFILER_MARK("IndexedDB Transaction %llu: Finished database work",
+                    "IDBTransaction[%llu] DT Done",
+                    mTransaction->GetSerialNumber());
+
   nsCOMPtr<nsIRunnable> finishTransactionRunnable =
     new FinishTransactionRunnable(mTransaction, finishRunnable);
   if (NS_FAILED(NS_DispatchToMainThread(finishTransactionRunnable,
                                         NS_DISPATCH_NORMAL))) {
     NS_WARNING("Failed to dispatch finishTransactionRunnable!");
   }
 
   return NS_OK;
@@ -589,22 +643,47 @@ FinishTransactionRunnable::FinishTransac
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(FinishTransactionRunnable, nsIRunnable)
 
 NS_IMETHODIMP
 FinishTransactionRunnable::Run()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "FinishTransactionRunnable::Run");
+
   if (!gInstance) {
     NS_ERROR("Running after shutdown!");
     return NS_ERROR_FAILURE;
   }
 
   gInstance->FinishTransaction(mTransaction);
 
   if (mFinishRunnable) {
     mFinishRunnable->Run();
     mFinishRunnable = nullptr;
   }
 
   return NS_OK;
 }
+
+#ifdef MOZ_ENABLE_PROFILER_SPS
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(ThreadPoolListener, nsIThreadPoolListener)
+
+NS_IMETHODIMP
+ThreadPoolListener::OnThreadCreated()
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  profiler_register_thread("IndexedDB Transaction");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ThreadPoolListener::OnThreadShuttingDown()
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  profiler_unregister_thread();
+  return NS_OK;
+}
+
+#endif // MOZ_ENABLE_PROFILER_SPS
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -17,16 +17,17 @@
 #include "nsISimpleEnumerator.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIUsageCallback.h"
 
 #include <algorithm>
+#include "GeckoProfiler.h"
 #include "mozilla/dom/file/FileService.h"
 #include "mozilla/dom/indexedDB/Client.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
@@ -1880,16 +1881,18 @@ OriginClearRunnable::DeleteFiles(QuotaMa
   aQuotaManager->UninitializeOriginsByPattern(mOriginOrPattern);
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(OriginClearRunnable, nsIRunnable)
 
 NS_IMETHODIMP
 OriginClearRunnable::Run()
 {
+  PROFILER_LABEL("Quota", "OriginClearRunnable::Run");
+
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "This should never fail!");
 
   switch (mCallbackState) {
     case Pending: {
       NS_NOTREACHED("Should never get here without being dispatched!");
       return NS_ERROR_UNEXPECTED;
     }
@@ -2122,16 +2125,18 @@ AsyncUsageRunnable::RunInternal()
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(AsyncUsageRunnable,
                               nsIRunnable,
                               nsIQuotaRequest)
 
 NS_IMETHODIMP
 AsyncUsageRunnable::Run()
 {
+  PROFILER_LABEL("Quota", "AsyncUsageRunnable::Run");
+
   nsresult rv = RunInternal();
 
   if (!NS_IsMainThread()) {
     if (NS_FAILED(rv)) {
       ResetUsage();
     }
 
     if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
--- a/xpcom/threads/LazyIdleThread.cpp
+++ b/xpcom/threads/LazyIdleThread.cpp
@@ -3,16 +3,17 @@
 /* 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 "LazyIdleThread.h"
 
 #include "nsIObserverService.h"
 
+#include "GeckoProfiler.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Services.h"
 
 #ifdef DEBUG
 #define ASSERT_OWNING_THREAD()                                                 \
   PR_BEGIN_MACRO                                                               \
@@ -163,17 +164,19 @@ LazyIdleThread::EnsureThread()
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void
 LazyIdleThread::InitThread()
 {
-  PR_SetCurrentThreadName(mName.BeginReading());
+  profiler_register_thread(mName.get());
+
+  PR_SetCurrentThreadName(mName.get());
 
   // Happens on mThread but mThread may not be set yet...
 
   nsCOMPtr<nsIThreadInternal> thread(do_QueryInterface(NS_GetCurrentThread()));
   MOZ_ASSERT(thread, "This should always succeed!");
 
   if (NS_FAILED(thread->SetObserver(this))) {
     NS_WARNING("Failed to set thread observer!");
@@ -185,20 +188,24 @@ LazyIdleThread::CleanupThread()
 {
   nsCOMPtr<nsIThreadInternal> thread(do_QueryInterface(NS_GetCurrentThread()));
   MOZ_ASSERT(thread, "This should always succeed!");
 
   if (NS_FAILED(thread->SetObserver(nullptr))) {
     NS_WARNING("Failed to set thread observer!");
   }
 
-  MutexAutoLock lock(mMutex);
+  {
+    MutexAutoLock lock(mMutex);
 
-  MOZ_ASSERT(!mThreadIsShuttingDown, "Shouldn't be true ever!");
-  mThreadIsShuttingDown = true;
+    MOZ_ASSERT(!mThreadIsShuttingDown, "Shouldn't be true ever!");
+    mThreadIsShuttingDown = true;
+  }
+
+  profiler_unregister_thread();
 }
 
 void
 LazyIdleThread::ScheduleTimer()
 {
   ASSERT_OWNING_THREAD();
 
   bool shouldSchedule;