Bug 666693 - 'Remote IndexedDB for multiple IndexedDB-using processes'. r=cjones+sicking.
authorBen Turner <bent.mozilla@gmail.com>
Fri, 01 Jun 2012 10:21:12 -0700
changeset 99597 d7d612dd7255424653af7c75637537c038dcdd92
parent 99596 284763d56e9672f35d62af79584488c785771861
child 99598 49344db27069b5a5bfa8b76a5aabe3bfaca59bb7
push id1116
push userlsblakk@mozilla.com
push dateMon, 16 Jul 2012 19:38:18 +0000
treeherdermozilla-beta@95f959a8b4dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs666693
milestone15.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 666693 - 'Remote IndexedDB for multiple IndexedDB-using processes'. r=cjones+sicking.
dom/base/nsGlobalWindow.cpp
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/AsyncConnectionHelper.h
dom/indexedDB/DatabaseInfo.cpp
dom/indexedDB/DatabaseInfo.h
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBCursor.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IDBEvents.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBIndex.h
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBKeyRange.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IDBRequest.cpp
dom/indexedDB/IDBRequest.h
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBTransaction.h
dom/indexedDB/IndexedDatabase.h
dom/indexedDB/IndexedDatabaseInlines.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/IndexedDatabaseManager.h
dom/indexedDB/Key.cpp
dom/indexedDB/Key.h
dom/indexedDB/Makefile.in
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/OpenDatabaseHelper.h
dom/indexedDB/ipc/IndexedDBChild.cpp
dom/indexedDB/ipc/IndexedDBChild.h
dom/indexedDB/ipc/IndexedDBParent.cpp
dom/indexedDB/ipc/IndexedDBParent.h
dom/indexedDB/ipc/Makefile.in
dom/indexedDB/ipc/PIndexedDB.ipdl
dom/indexedDB/ipc/PIndexedDBCursor.ipdl
dom/indexedDB/ipc/PIndexedDBDatabase.ipdl
dom/indexedDB/ipc/PIndexedDBDeleteDatabaseRequest.ipdl
dom/indexedDB/ipc/PIndexedDBIndex.ipdl
dom/indexedDB/ipc/PIndexedDBObjectStore.ipdl
dom/indexedDB/ipc/PIndexedDBRequest.ipdl
dom/indexedDB/ipc/PIndexedDBTransaction.ipdl
dom/indexedDB/ipc/SerializationHelpers.h
dom/indexedDB/ipc/ipdl.mk
dom/indexedDB/ipc/test_ipc.html
dom/indexedDB/nsIIDBVersionChangeEvent.idl
dom/indexedDB/test/error_events_abort_transactions_iframe.html
dom/indexedDB/test/event_propagation_iframe.html
dom/indexedDB/test/exceptions_in_success_events_iframe.html
dom/indexedDB/test/file.js
dom/indexedDB/test/helpers.js
dom/indexedDB/test/test_bfcache.html
dom/indexedDB/test/test_leaving_page.html
dom/indexedDB/test/test_third_party.html
dom/indexedDB/test/unit/head_idb.js
dom/indexedDB/test/unit/test_setVersion_abort.js
dom/indexedDB/test/unit/test_setVersion_events.js
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
gfx/layers/d3d10/ThebesLayerD3D10.cpp
ipc/ipdl/Makefile.in
layout/build/Makefile.in
testing/mochitest/specialpowers/components/SpecialPowersObserver.js
testing/mochitest/tests/SimpleTest/SpecialPowersObserverAPI.js
testing/mochitest/tests/SimpleTest/TestRunner.js
testing/mochitest/tests/SimpleTest/specialpowersAPI.js
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8195,35 +8195,37 @@ nsGlobalWindow::GetLocalStorage(nsIDOMSt
 //*****************************************************************************
 // nsGlobalWindow::nsIDOMStorageIndexedDB
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
 {
   if (!mIndexedDB) {
+    nsresult rv;
+
     if (!IsChromeWindow()) {
       nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
         do_GetService(THIRDPARTYUTIL_CONTRACTID);
       NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       bool isThirdParty;
-      nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
-                                                       &isThirdParty);
+      rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull, &isThirdParty);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       if (isThirdParty) {
         NS_WARNING("IndexedDB is not permitted in a third-party window.");
         *_retval = nsnull;
         return NS_OK;
       }
     }
 
-    mIndexedDB = indexedDB::IDBFactory::Create(this);
-    NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    // This may be null if being created from a file.
+    rv = indexedDB::IDBFactory::Create(this, getter_AddRefs(mIndexedDB));
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
   request.forget(_retval);
   return NS_OK;
 }
 
 //*****************************************************************************
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -1,41 +1,43 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "AsyncConnectionHelper.h"
 
 #include "mozilla/storage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCacheInlines.h"
 
 #include "IDBEvents.h"
 #include "IDBTransaction.h"
 #include "IndexedDatabaseManager.h"
 #include "TransactionThreadPool.h"
 
+#include "ipc/IndexedDBChild.h"
+
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 IDBTransaction* gCurrentTransaction = nsnull;
 
 const PRUint32 kProgressHandlerGranularity = 1000;
 
-NS_STACK_CLASS
-class TransactionPoolEventTarget : public nsIEventTarget
+class TransactionPoolEventTarget : public StackBasedEventTarget
 {
 public:
-  NS_DECL_ISUPPORTS
   NS_DECL_NSIEVENTTARGET
 
   TransactionPoolEventTarget(IDBTransaction* aTransaction)
   : mTransaction(aTransaction)
   { }
 
 private:
   IDBTransaction* mTransaction;
@@ -191,28 +193,51 @@ AsyncConnectionHelper::Run()
       // 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;
     gCurrentTransaction = mTransaction;
 
-    if (mRequest) {
-      nsresult rv = mRequest->NotifyHelperCompleted(this);
-      if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
-        mResultCode = rv;
+    ChildProcessSendResult sendResult =
+      IndexedDatabaseManager::IsMainProcess() ?
+      MaybeSendResponseToChildProcess(mResultCode) :
+      Success_NotSent;
+
+    NS_ASSERTION(sendResult == Success_Sent || sendResult == Success_NotSent ||
+                 sendResult == Error,
+                 "Unknown result from MaybeSendResultsToChildProcess!");
+
+    if (sendResult == Success_Sent) {
+      if (mRequest) {
+        mRequest->NotifyHelperSentResultsToChildProcess(NS_OK);
       }
     }
+    else if (sendResult == Error) {
+      NS_WARNING("MaybeSendResultsToChildProcess failed!");
+      mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+      if (mRequest) {
+        mRequest->NotifyHelperSentResultsToChildProcess(mResultCode);
+      }
+    }
+    else if (sendResult == Success_NotSent) {
+      if (mRequest) {
+        nsresult rv = mRequest->NotifyHelperCompleted(this);
+        if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
+          mResultCode = rv;
+        }
+      }
 
-    // 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();
+      // 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();
+      }
     }
 
     NS_ASSERTION(gCurrentTransaction == mTransaction, "Should be unchanged!");
     gCurrentTransaction = oldTransaction;
 
     if (mDispatched && mTransaction) {
       mTransaction->OnRequestFinished();
     }
@@ -220,16 +245,18 @@ AsyncConnectionHelper::Run()
     ReleaseMainThreadObjects();
 
     NS_ASSERTION(!(mDatabase || mTransaction || mRequest), "Subclass didn't "
                  "call AsyncConnectionHelper::ReleaseMainThreadObjects!");
 
     return NS_OK;
   }
 
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
   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!");
     }
@@ -315,34 +342,26 @@ AsyncConnectionHelper::OnProgress(mozISt
     return mOldProgressHandler->OnProgress(aConnection, _retval);
   }
 
   *_retval = false;
   return NS_OK;
 }
 
 nsresult
-AsyncConnectionHelper::Dispatch(nsIEventTarget* aDatabaseThread)
+AsyncConnectionHelper::Dispatch(nsIEventTarget* aTarget)
 {
-#ifdef DEBUG
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  {
-    bool sameThread;
-    nsresult rv = aDatabaseThread->IsOnCurrentThread(&sameThread);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "IsOnCurrentThread failed!");
-    NS_ASSERTION(!sameThread, "Dispatching to main thread not supported!");
-  }
-#endif
 
   nsresult rv = Init();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  rv = aDatabaseThread->Dispatch(this, NS_DISPATCH_NORMAL);
+  rv = aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mTransaction) {
     mTransaction->OnNewRequest();
   }
 
   mDispatched = true;
 
@@ -353,16 +372,27 @@ nsresult
 AsyncConnectionHelper::DispatchToTransactionPool()
 {
   NS_ASSERTION(mTransaction, "Only ok to call this with a transaction!");
   TransactionPoolEventTarget target(mTransaction);
   return Dispatch(&target);
 }
 
 // static
+void
+AsyncConnectionHelper::SetCurrentTransaction(IDBTransaction* aTransaction)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!aTransaction || !gCurrentTransaction,
+               "Stepping on another transaction!");
+
+  gCurrentTransaction = aTransaction;
+}
+
+// static
 IDBTransaction*
 AsyncConnectionHelper::GetCurrentTransaction()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   return gCurrentTransaction;
 }
 
@@ -466,22 +496,40 @@ AsyncConnectionHelper::ReleaseMainThread
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mDatabase = nsnull;
   mTransaction = nsnull;
 
   HelperBase::ReleaseMainThreadObjects();
 }
 
+nsresult
+AsyncConnectionHelper::OnParentProcessRequestComplete(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  if (aResponseValue.type() == ResponseValue::Tnsresult) {
+    NS_ASSERTION(NS_FAILED(aResponseValue.get_nsresult()), "Huh?");
+    SetError(aResponseValue.get_nsresult());
+  }
+  else {
+    nsresult rv = UnpackResponseFromParentProcess(aResponseValue);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return Run();
+}
+
 // static
 nsresult
 AsyncConnectionHelper::ConvertCloneReadInfosToArray(
-                                JSContext* aCx,
-                                nsTArray<StructuredCloneReadInfo>& aReadInfos,
-                                jsval* aResult)
+                                  JSContext* aCx,
+                                  nsTArray<StructuredCloneReadInfo>& aReadInfos,
+                                  jsval* aResult)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aResult, "Null pointer!");
 
   JSAutoRequest ar(aCx);
 
   nsresult rv = ConvertCloneReadInfosToArrayInternal(aCx, aReadInfos, aResult);
 
@@ -489,40 +537,83 @@ AsyncConnectionHelper::ConvertCloneReadI
     aReadInfos[index].mCloneBuffer.clear();
   }
   aReadInfos.Clear();
 
   return rv;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
-TransactionPoolEventTarget::AddRef()
+StackBasedEventTarget::AddRef()
 {
   NS_NOTREACHED("Don't call me!");
   return 2;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
-TransactionPoolEventTarget::Release()
+StackBasedEventTarget::Release()
 {
   NS_NOTREACHED("Don't call me!");
   return 1;
 }
 
-NS_IMPL_QUERY_INTERFACE1(TransactionPoolEventTarget, nsIEventTarget)
+NS_IMETHODIMP
+StackBasedEventTarget::QueryInterface(REFNSIID aIID,
+                                      void** aInstancePtr)
+{
+  NS_NOTREACHED("Don't call me!");
+  return NS_NOINTERFACE;
+}
+
+NS_IMETHODIMP
+MainThreadEventTarget::Dispatch(nsIRunnable* aRunnable,
+                                PRUint32 aFlags)
+{
+  NS_ASSERTION(aRunnable, "Null pointer!");
+
+  nsCOMPtr<nsIRunnable> runnable = aRunnable;
+  return NS_DispatchToMainThread(aRunnable, aFlags);
+}
+
+NS_IMETHODIMP
+MainThreadEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
+{
+  *aIsOnCurrentThread = NS_IsMainThread();
+  return NS_OK;
+}
 
 NS_IMETHODIMP
 TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
                                      PRUint32 aFlags)
 {
   NS_ASSERTION(aRunnable, "Null pointer!");
   NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");
 
   TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
-  return pool->Dispatch(mTransaction, aRunnable, false, nsnull);
+  NS_ENSURE_TRUE(pool, NS_ERROR_UNEXPECTED);
+
+  nsresult rv = pool->Dispatch(mTransaction, aRunnable, false, nsnull);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-TransactionPoolEventTarget::IsOnCurrentThread(bool* aResult)
+TransactionPoolEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
 {
-  *aResult = false;
+  *aIsOnCurrentThread = false;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+NoDispatchEventTarget::Dispatch(nsIRunnable* aRunnable,
+                                PRUint32 aFlags)
+{
+  nsCOMPtr<nsIRunnable> runnable = aRunnable;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+NoDispatchEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
+{
+  *aIsOnCurrentThread = true;
+  return NS_OK;
+}
--- a/dom/indexedDB/AsyncConnectionHelper.h
+++ b/dom/indexedDB/AsyncConnectionHelper.h
@@ -9,38 +9,59 @@
 
 // Only meant to be included in IndexedDB source files, not exported.
 #include "DatabaseInfo.h"
 #include "IndexedDatabase.h"
 #include "IDBDatabase.h"
 #include "IDBRequest.h"
 
 #include "mozIStorageProgressHandler.h"
+#include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 
 #include "nsDOMEvent.h"
 
 class mozIStorageConnection;
-class nsIEventTarget;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
+class AutoSetCurrentTransaction;
 class IDBTransaction;
 
+namespace ipc {
+class ResponseValue;
+}
+
 // A common base class for AsyncConnectionHelper and OpenDatabaseHelper that
 // IDBRequest can use.
 class HelperBase : public nsIRunnable
 {
   friend class IDBRequest;
+
 public:
+  enum ChildProcessSendResult
+  {
+    Success_Sent = 0,
+    Success_NotSent,
+    Error
+  };
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) = 0;
+
   virtual nsresult GetResultCode() = 0;
 
   virtual nsresult GetSuccessResult(JSContext* aCx,
                                     jsval* aVal) = 0;
 
+  IDBRequest* GetRequest() const
+  {
+    return mRequest;
+  }
+
 protected:
   HelperBase(IDBRequest* aRequest)
     : mRequest(aRequest)
   { }
 
   virtual ~HelperBase();
 
   /**
@@ -68,22 +89,26 @@ protected:
  * subclass can implement GetSuccessResult to properly set the result of the
  * success event. Call Dispatch to start the database operation. Must be created
  * and Dispatched from the main thread only. Target thread may not be the main
  * thread.
  */
 class AsyncConnectionHelper : public HelperBase,
                               public mozIStorageProgressHandler
 {
+  friend class AutoSetCurrentTransaction;
+
 public:
+  typedef ipc::ResponseValue ResponseValue;
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_MOZISTORAGEPROGRESSHANDLER
 
-  nsresult Dispatch(nsIEventTarget* aDatabaseThread);
+  virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread);
 
   // Only for transactions!
   nsresult DispatchToTransactionPool();
 
   void SetError(nsresult aErrorCode)
   {
     NS_ASSERTION(NS_FAILED(aErrorCode), "Not a failure code!");
     mResultCode = aErrorCode;
@@ -96,21 +121,27 @@ public:
     return mTransaction;
   }
 
   nsISupports* GetSource()
   {
     return mRequest ? mRequest->Source() : nsnull;
   }
 
-  nsresult GetResultCode()
+  virtual nsresult GetResultCode() MOZ_OVERRIDE
   {
     return mResultCode;
   }
 
+  virtual nsresult OnParentProcessRequestComplete(
+                                           const ResponseValue& aResponseValue);
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
+
 protected:
   AsyncConnectionHelper(IDBDatabase* aDatabase,
                         IDBRequest* aRequest);
 
   AsyncConnectionHelper(IDBTransaction* aTransaction,
                         IDBRequest* aRequest);
 
   virtual ~AsyncConnectionHelper();
@@ -149,38 +180,62 @@ protected:
    */
   virtual void OnError();
 
   /**
    * This function is called by the request on the main thread when script
    * accesses the result property of the request.
    */
   virtual nsresult GetSuccessResult(JSContext* aCx,
-                                    jsval* aVal);
+                                    jsval* aVal) MOZ_OVERRIDE;
 
   /**
    * Gives the subclass a chance to release any objects that must be released
    * on the main thread, regardless of success or failure. Subclasses that
    * implement this method *MUST* call the base class implementation as well.
    */
-  virtual void ReleaseMainThreadObjects();
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
 
   /**
    * Helper to make a JS array object out of an array of clone buffers.
    */
   static nsresult ConvertCloneReadInfosToArray(
                                 JSContext* aCx,
                                 nsTArray<StructuredCloneReadInfo>& aReadInfos,
                                 jsval* aResult);
 
+  /**
+   * This should only be called by AutoSetCurrentTransaction.
+   */
+  static void SetCurrentTransaction(IDBTransaction* aTransaction);
+
 protected:
   nsRefPtr<IDBDatabase> mDatabase;
   nsRefPtr<IDBTransaction> mTransaction;
 
 private:
   nsCOMPtr<mozIStorageProgressHandler> mOldProgressHandler;
   nsresult mResultCode;
   bool mDispatched;
 };
 
+NS_STACK_CLASS
+class StackBasedEventTarget : public nsIEventTarget
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+};
+
+class MainThreadEventTarget : public StackBasedEventTarget
+{
+public:
+  NS_DECL_NSIEVENTTARGET
+};
+
+class NoDispatchEventTarget : public StackBasedEventTarget
+{
+public:
+  NS_DECL_NSIEVENTTARGET
+};
+
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_asyncconnectionhelper_h__
--- a/dom/indexedDB/DatabaseInfo.cpp
+++ b/dom/indexedDB/DatabaseInfo.cpp
@@ -51,56 +51,54 @@ DatabaseInfo::~DatabaseInfo()
 {
   // Clones are never in the hash.
   if (!cloned) {
     DatabaseInfo::Remove(id);
   }
 }
 
 ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
-: name(aOther.name),
-  id(aOther.id),
-  keyPath(aOther.keyPath),
-  indexes(aOther.indexes),
-  nextAutoIncrementId(aOther.nextAutoIncrementId),
+: nextAutoIncrementId(aOther.nextAutoIncrementId),
   comittedAutoIncrementId(aOther.comittedAutoIncrementId)
 {
+  *static_cast<ObjectStoreInfoGuts*>(this) =
+    static_cast<ObjectStoreInfoGuts&>(aOther);
+
   // Doesn't copy the refcount
   MOZ_COUNT_CTOR(ObjectStoreInfo);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 
 IndexInfo::IndexInfo()
 : id(LL_MININT),
   unique(false),
   multiEntry(false)
 {
   MOZ_COUNT_CTOR(IndexInfo);
 }
 
 IndexInfo::IndexInfo(const IndexInfo& aOther)
-: id(aOther.id),
-  name(aOther.name),
+: name(aOther.name),
+  id(aOther.id),
   keyPath(aOther.keyPath),
   keyPathArray(aOther.keyPathArray),
   unique(aOther.unique),
   multiEntry(aOther.multiEntry)
 {
   MOZ_COUNT_CTOR(IndexInfo);
 }
 
 IndexInfo::~IndexInfo()
 {
   MOZ_COUNT_DTOR(IndexInfo);
 }
 
 ObjectStoreInfo::ObjectStoreInfo()
-: id(0),
-  nextAutoIncrementId(0),
+: nextAutoIncrementId(0),
   comittedAutoIncrementId(0)
 {
   MOZ_COUNT_CTOR(ObjectStoreInfo);
 }
 
 ObjectStoreInfo::~ObjectStoreInfo()
 {
   MOZ_COUNT_DTOR(ObjectStoreInfo);
@@ -265,16 +263,17 @@ already_AddRefed<DatabaseInfo>
 DatabaseInfo::Clone()
 {
   NS_ASSERTION(!cloned, "Should never clone a clone!");
 
   nsRefPtr<DatabaseInfo> dbInfo(new DatabaseInfo());
 
   dbInfo->cloned = true;
   dbInfo->name = name;
+  dbInfo->origin = origin;
   dbInfo->version = version;
   dbInfo->id = id;
   dbInfo->filePath = filePath;
   dbInfo->nextObjectStoreId = nextObjectStoreId;
   dbInfo->nextIndexId = nextIndexId;
 
   if (objectStoreHash) {
     dbInfo->objectStoreHash = new ObjectStoreInfoHash();
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -2,76 +2,85 @@
 /* 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_databaseinfo_h__
 #define mozilla_dom_indexeddb_databaseinfo_h__
 
-// Only meant to be included in IndexedDB source files, not exported.
-#include "IndexedDatabase.h"
+#include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
-#include "Key.h"
-#include "IDBObjectStore.h"
+#include "mozilla/dom/indexedDB/Key.h"
+#include "mozilla/dom/indexedDB/IDBObjectStore.h"
 
 #include "nsRefPtrHashtable.h"
 #include "nsHashKeys.h"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
+class IndexedDBDatabaseChild;
 struct ObjectStoreInfo;
 
 typedef nsRefPtrHashtable<nsStringHashKey, ObjectStoreInfo>
         ObjectStoreInfoHash;
 
-class IDBDatabase;
-class OpenDatabaseHelper;
-
-struct DatabaseInfo
+struct DatabaseInfoGuts
 {
-  friend class IDBDatabase;
-  friend class OpenDatabaseHelper;
+  DatabaseInfoGuts()
+  : nextObjectStoreId(1), nextIndexId(1)
+  { }
 
-private:
+  bool operator==(const DatabaseInfoGuts& aOther) const
+  {
+    return this->name == aOther.name &&
+           this->origin == aOther.origin &&
+           this->version == aOther.version &&
+           this->nextObjectStoreId == aOther.nextObjectStoreId &&
+           this->nextIndexId == aOther.nextIndexId;
+  };
+
+  // Make sure to update ipc/SerializationHelpers.h when changing members here!
+  nsString name;
+  nsCString origin;
+  PRUint64 version;
+  PRInt64 nextObjectStoreId;
+  PRInt64 nextIndexId;
+};
+
+struct DatabaseInfo : public DatabaseInfoGuts
+{
   DatabaseInfo()
-  : nextObjectStoreId(1),
-    nextIndexId(1),
-    cloned(false)
+  : cloned(false)
   { }
+
   ~DatabaseInfo();
 
   static bool Get(nsIAtom* aId,
                   DatabaseInfo** aInfo);
 
   static bool Put(DatabaseInfo* aInfo);
 
-public:
   static void Remove(nsIAtom* aId);
 
   static void RemoveAllForOrigin(const nsACString& aOrigin);
 
   bool GetObjectStoreNames(nsTArray<nsString>& aNames);
   bool ContainsStoreName(const nsAString& aName);
 
   ObjectStoreInfo* GetObjectStore(const nsAString& aName);
 
   bool PutObjectStore(ObjectStoreInfo* aInfo);
 
   void RemoveObjectStore(const nsAString& aName);
 
   already_AddRefed<DatabaseInfo> Clone();
 
-  nsString name;
-  nsCString origin;
-  PRUint64 version;
   nsCOMPtr<nsIAtom> id;
   nsString filePath;
-  PRInt64 nextObjectStoreId;
-  PRInt64 nextIndexId;
   bool cloned;
 
   nsAutoPtr<ObjectStoreInfoHash> objectStoreHash;
 
   NS_INLINE_DECL_REFCOUNTING(DatabaseInfo)
 };
 
 struct IndexInfo
@@ -80,52 +89,79 @@ struct IndexInfo
   IndexInfo();
   IndexInfo(const IndexInfo& aOther);
   ~IndexInfo();
 #else
   IndexInfo()
   : id(LL_MININT), unique(false), multiEntry(false) { }
 #endif
 
+  bool operator==(const IndexInfo& aOther) const
+  {
+    return this->name == aOther.name &&
+           this->id == aOther.id &&
+           this->keyPath == aOther.keyPath &&
+           this->keyPathArray == aOther.keyPathArray &&
+           this->unique == aOther.unique &&
+           this->multiEntry == aOther.multiEntry;
+  };
+
+  // Make sure to update ipc/SerializationHelpers.h when changing members here!
+  nsString name;
   PRInt64 id;
-  nsString name;
   nsString keyPath;
   nsTArray<nsString> keyPathArray;
   bool unique;
   bool multiEntry;
 };
 
-struct ObjectStoreInfo
+struct ObjectStoreInfoGuts
+{
+  ObjectStoreInfoGuts()
+  : id(0), autoIncrement(false)
+  { }
+
+  bool operator==(const ObjectStoreInfoGuts& aOther) const
+  {
+    return this->name == aOther.name &&
+           this->id == aOther.id;
+  };
+
+  // Make sure to update ipc/SerializationHelpers.h when changing members here!
+
+  // Constant members, can be gotten on any thread
+  nsString name;
+  PRInt64 id;
+  nsString keyPath;
+  nsTArray<nsString> keyPathArray;
+  bool autoIncrement;
+
+  // Main-thread only members. This must *not* be touced on the database thread
+  nsTArray<IndexInfo> indexes;
+};
+
+struct ObjectStoreInfo : public ObjectStoreInfoGuts
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   ObjectStoreInfo();
 #else
   ObjectStoreInfo()
-  : id(0), nextAutoIncrementId(0), comittedAutoIncrementId(0) { }
+  : nextAutoIncrementId(0), comittedAutoIncrementId(0) { }
 #endif
 
   ObjectStoreInfo(ObjectStoreInfo& aOther);
 
 private:
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~ObjectStoreInfo();
 #else
   ~ObjectStoreInfo() {}
 #endif
 public:
 
-  // Constant members, can be gotten on any thread
-  nsString name;
-  PRInt64 id;
-  nsString keyPath;
-  nsTArray<nsString> keyPathArray;
-
-  // Main-thread only members. This must *not* be touced on the database thread
-  nsTArray<IndexInfo> indexes;
-
   // Database-thread members. After the ObjectStoreInfo has been initialized,
   // these can *only* be touced on the database thread.
   PRInt64 nextAutoIncrementId;
   PRInt64 comittedAutoIncrementId;
 
   // This is threadsafe since the ObjectStoreInfos are created on the database
   // thread but then only used from the main thread. Ideal would be if we
   // could transfer ownership from the database thread to the main thread, but
@@ -135,16 +171,24 @@ public:
 
 struct IndexUpdateInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   IndexUpdateInfo();
   ~IndexUpdateInfo();
 #endif
 
+  bool operator==(const IndexUpdateInfo& aOther) const
+  {
+    return this->indexId == aOther.indexId &&
+           this->indexUnique == aOther.indexUnique &&
+           this->value == aOther.value;
+  };
+
+  // Make sure to update ipc/SerializationHelpers.h when changing members here!
   PRInt64 indexId;
   bool indexUnique;
   Key value;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_databaseinfo_h__
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "IDBCursor.h"
 
 #include "mozilla/storage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
@@ -16,68 +18,136 @@
 
 #include "AsyncConnectionHelper.h"
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "TransactionThreadPool.h"
 
+#include "ipc/IndexedDBChild.h"
+#include "ipc/IndexedDBParent.h"
+
+#include "IndexedDatabaseInlines.h"
+
 USING_INDEXEDDB_NAMESPACE
 
+MOZ_STATIC_ASSERT(sizeof(size_t) >= sizeof(IDBCursor::Direction),
+                  "Relying on conversion between size_t and "
+                  "IDBCursor::Direction");
+
 namespace {
 
+class CursorHelper : public AsyncConnectionHelper
+{
+public:
+  typedef ipc::CursorRequestParams CursorRequestParams;
+
+  CursorHelper(IDBCursor* aCursor)
+  : AsyncConnectionHelper(aCursor->Transaction(), aCursor->Request()),
+    mCursor(aCursor), mActor(nsnull)
+  {
+    NS_ASSERTION(aCursor, "Null cursor!");
+  }
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(CursorRequestParams& aParams) = 0;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
+
+protected:
+  nsRefPtr<IDBCursor> mCursor;
+
+private:
+  IndexedDBCursorRequestChild* mActor;
+};
+
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBCursor* aCursor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   IDBDatabase* database = aCursor->Transaction()->Database();
   return IDBRequest::Create(aCursor, database, aCursor->Transaction());
 }
 
 } // anonymous namespace
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class ContinueHelper : public AsyncConnectionHelper
+class ContinueHelper : public CursorHelper
 {
 public:
   ContinueHelper(IDBCursor* aCursor,
                  PRInt32 aCount)
-  : AsyncConnectionHelper(aCursor->mTransaction, aCursor->mRequest),
-    mCursor(aCursor), mCount(aCount)
+  : CursorHelper(aCursor), mCount(aCount)
   {
     NS_ASSERTION(aCount > 0, "Must have a count!");
   }
 
   ~ContinueHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
 
-  void ReleaseMainThreadObjects()
-  {
-    mCursor = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult
+  PackArgumentsForParentProcess(CursorRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   virtual nsresult
   BindArgumentsToStatement(mozIStorageStatement* aStatement) = 0;
 
   virtual nsresult
   GatherResultsFromStatement(mozIStorageStatement* aStatement) = 0;
 
-protected:
-  nsRefPtr<IDBCursor> mCursor;
+  void UpdateCursorState()
+  {
+    mCursor->mCachedKey = JSVAL_VOID;
+    mCursor->mCachedPrimaryKey = JSVAL_VOID;
+    mCursor->mCachedValue = JSVAL_VOID;
+    mCursor->mHaveCachedKey = false;
+    mCursor->mHaveCachedPrimaryKey = false;
+    mCursor->mHaveCachedValue = false;
+    mCursor->mContinueCalled = false;
+
+    if (mKey.IsUnset()) {
+      mCursor->mHaveValue = false;
+    }
+    else {
+      NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
+                   !mObjectKey.IsUnset(), "Bad key!");
+
+      // Set new values.
+      mCursor->mKey = mKey;
+      mCursor->mObjectKey = mObjectKey;
+      mCursor->mContinueToKey.Unset();
+
+      mCursor->mCloneReadInfo.Swap(mCloneReadInfo);
+      mCloneReadInfo.mCloneBuffer.clear();
+    }
+  }
+
   PRInt32 mCount;
   Key mKey;
   Key mObjectKey;
   StructuredCloneReadInfo mCloneReadInfo;
 };
 
 class ContinueObjectStoreHelper : public ContinueHelper
 {
@@ -241,18 +311,22 @@ IDBCursor::CreateCommon(IDBRequest* aReq
                         const Key& aRangeKey,
                         const nsACString& aContinueQuery,
                         const nsACString& aContinueToQuery)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aRequest, "Null pointer!");
   NS_ASSERTION(aTransaction, "Null pointer!");
   NS_ASSERTION(aObjectStore, "Null pointer!");
-  NS_ASSERTION(!aContinueQuery.IsEmpty(), "Empty query!");
-  NS_ASSERTION(!aContinueToQuery.IsEmpty(), "Empty query!");
+  NS_ASSERTION(!aContinueQuery.IsEmpty() ||
+               !IndexedDatabaseManager::IsMainProcess(),
+               "Empty query!");
+  NS_ASSERTION(!aContinueToQuery.IsEmpty() ||
+               !IndexedDatabaseManager::IsMainProcess(),
+               "Empty query!");
 
   nsRefPtr<IDBCursor> cursor = new IDBCursor();
 
   IDBDatabase* database = aTransaction->Database();
   cursor->mScriptOwner = database->GetScriptOwner();
 
   if (cursor->mScriptOwner) {
     if (NS_FAILED(NS_HOLD_JS_OBJECTS(cursor, IDBCursor))) {
@@ -275,30 +349,39 @@ IDBCursor::CreateCommon(IDBRequest* aReq
 
 IDBCursor::IDBCursor()
 : mScriptOwner(nsnull),
   mType(OBJECTSTORE),
   mDirection(IDBCursor::NEXT),
   mCachedKey(JSVAL_VOID),
   mCachedPrimaryKey(JSVAL_VOID),
   mCachedValue(JSVAL_VOID),
+  mActorChild(nsnull),
+  mActorParent(nsnull),
   mHaveCachedKey(false),
   mHaveCachedPrimaryKey(false),
   mHaveCachedValue(false),
   mRooted(false),
   mContinueCalled(false),
   mHaveValue(true)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBCursor::~IDBCursor()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->Send__delete__(mActorChild);
+    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
+  }
+
   if (mRooted) {
     NS_DROP_JS_OBJECTS(this, IDBCursor);
   }
   IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
 }
 
 nsresult
 IDBCursor::ContinueInternal(const Key& aKey,
@@ -437,16 +520,22 @@ IDBCursor::GetDirection(nsAString& aDire
     case NEXT_UNIQUE:
       aDirection.AssignLiteral("nextunique");
       break;
     case PREV:
       aDirection.AssignLiteral("prev");
       break;
     case PREV_UNIQUE:
       aDirection.AssignLiteral("prevunique");
+      break;
+
+    case DIRECTION_INVALID:
+    default:
+      NS_NOTREACHED("Bad direction value!");
+      return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBCursor::GetSource(nsISupports** aSource)
 {
@@ -535,22 +624,24 @@ IDBCursor::GetValue(JSContext* aCx,
   }
 
   if (!mHaveCachedValue) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
-    if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &mCachedValue)) {
-      mCachedValue = JSVAL_VOID;
+    jsval val;
+    if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &val)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     mCloneReadInfo.mCloneBuffer.clear();
+
+    mCachedValue = val;
     mHaveCachedValue = true;
   }
 
   *aValue = mCachedValue;
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -689,16 +780,47 @@ IDBCursor::Advance(PRInt32 aCount)
   if (aCount < 1) {
     return NS_ERROR_TYPE_ERR;
   }
 
   Key key;
   return ContinueInternal(key, aCount);
 }
 
+void
+CursorHelper::ReleaseMainThreadObjects()
+{
+  mCursor = nsnull;
+  AsyncConnectionHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+CursorHelper::Dispatch(nsIEventTarget* aDatabaseThread)
+{
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    return AsyncConnectionHelper::Dispatch(aDatabaseThread);
+  }
+
+  IndexedDBCursorChild* cursorActor = mCursor->GetActorChild();
+  NS_ASSERTION(cursorActor, "Must have an actor here!");
+
+  CursorRequestParams params;
+  nsresult rv = PackArgumentsForParentProcess(params);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NoDispatchEventTarget target;
+  rv = AsyncConnectionHelper::Dispatch(&target);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  mActor = new IndexedDBCursorRequestChild(this, mCursor, params.type());
+  cursorActor->SendPIndexedDBRequestConstructor(mActor, params);
+
+  return NS_OK;
+}
+
 nsresult
 ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   // 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
@@ -746,49 +868,105 @@ ContinueHelper::DoDatabaseWork(mozIStora
 
   return NS_OK;
 }
 
 nsresult
 ContinueHelper::GetSuccessResult(JSContext* aCx,
                                  jsval* aVal)
 {
-  // Remove cached stuff from last time.
-  mCursor->mCachedKey = JSVAL_VOID;
-  mCursor->mCachedPrimaryKey = JSVAL_VOID;
-  mCursor->mCachedValue = JSVAL_VOID;
-  mCursor->mHaveCachedKey = false;
-  mCursor->mHaveCachedPrimaryKey = false;
-  mCursor->mHaveCachedValue = false;
-  mCursor->mContinueCalled = false;
+  UpdateCursorState();
 
   if (mKey.IsUnset()) {
-    mCursor->mHaveValue = false;
     *aVal = JSVAL_VOID;
   }
   else {
-    NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
-                 !mObjectKey.IsUnset(), "Bad key!");
-
-    // Set new values.
-    mCursor->mKey = mKey;
-    mCursor->mObjectKey = mObjectKey;
-    mCursor->mContinueToKey.Unset();
-
-    mCursor->mCloneReadInfo.Swap(mCloneReadInfo);
-    mCloneReadInfo.mCloneBuffer.clear();
-
     nsresult rv = WrapNative(aCx, mCursor, aVal);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
+ContinueHelper::PackArgumentsForParentProcess(CursorRequestParams& aParams)
+{
+  ipc::ContinueParams params;
+
+  params.key() = mCursor->mContinueToKey;
+  params.count() = uint32_t(mCount);
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+ContinueHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
+    NS_WARNING("No support for transferring blobs across processes yet!");
+    return Error;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::ContinueResponse continueResponse;
+    continueResponse.key() = mKey;
+    continueResponse.objectKey() = mObjectKey;
+    continueResponse.cloneInfo() = mCloneReadInfo;
+    response = continueResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  UpdateCursorState();
+
+  return Success_Sent;
+}
+
+nsresult
+ContinueHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TContinueResponse,
+               "Bad response type!");
+
+  const ipc::ContinueResponse& response = aResponseValue.get_ContinueResponse();
+
+  mKey = response.key();
+  mObjectKey = response.objectKey();
+
+  const SerializedStructuredCloneReadInfo& cloneInfo = response.cloneInfo();
+
+  NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
+               (cloneInfo.dataLength && cloneInfo.data),
+               "Inconsistent clone info!");
+
+  if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
+    NS_WARNING("Failed to copy clone buffer!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
+}
+
+nsresult
 ContinueObjectStoreHelper::BindArgumentsToStatement(
                                                mozIStorageStatement* aStatement)
 {
   // Bind object store id.
   nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                             mCursor->mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -16,24 +16,25 @@
 #include "nsCycleCollectionParticipant.h"
 
 class nsIRunnable;
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class IDBIndex;
-class IDBRequest;
-class IDBTransaction;
-
 class ContinueHelper;
 class ContinueObjectStoreHelper;
 class ContinueIndexHelper;
 class ContinueIndexObjectHelper;
+class IDBIndex;
+class IDBRequest;
+class IDBTransaction;
+class IndexedDBCursorChild;
+class IndexedDBCursorParent;
 
 class IDBCursor MOZ_FINAL : public nsIIDBCursorWithValue
 {
   friend class ContinueHelper;
   friend class ContinueObjectStoreHelper;
   friend class ContinueIndexHelper;
   friend class ContinueIndexObjectHelper;
 
@@ -51,17 +52,20 @@ public:
     INDEXOBJECT
   };
 
   enum Direction
   {
     NEXT = 0,
     NEXT_UNIQUE,
     PREV,
-    PREV_UNIQUE
+    PREV_UNIQUE,
+
+    // Only needed for IPC serialization helper, should never be used in code.
+    DIRECTION_INVALID
   };
 
   // For OBJECTSTORE cursors.
   static
   already_AddRefed<IDBCursor>
   Create(IDBRequest* aRequest,
          IDBTransaction* aTransaction,
          IDBObjectStore* aObjectStore,
@@ -94,42 +98,68 @@ public:
          Direction aDirection,
          const Key& aRangeKey,
          const nsACString& aContinueQuery,
          const nsACString& aContinueToQuery,
          const Key& aKey,
          const Key& aObjectKey,
          StructuredCloneReadInfo& aCloneReadInfo);
 
-  IDBTransaction* Transaction()
+  IDBTransaction* Transaction() const
   {
     return mTransaction;
   }
 
+  IDBRequest* Request() const
+  {
+    return mRequest;
+  }
+
   static nsresult ParseDirection(const nsAString& aDirection,
                                  Direction* aResult);
 
+  void
+  SetActor(IndexedDBCursorChild* aActorChild)
+  {
+    NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
+    mActorChild = aActorChild;
+  }
+
+  void
+  SetActor(IndexedDBCursorParent* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent,
+                 "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
+  IndexedDBCursorChild*
+  GetActorChild() const
+  {
+    return mActorChild;
+  }
+
+  nsresult
+  ContinueInternal(const Key& aKey,
+                   PRInt32 aCount);
+
 protected:
   IDBCursor();
   ~IDBCursor();
 
   static
   already_AddRefed<IDBCursor>
   CreateCommon(IDBRequest* aRequest,
                IDBTransaction* aTransaction,
                IDBObjectStore* aObjectStore,
                Direction aDirection,
                const Key& aRangeKey,
                const nsACString& aContinueQuery,
                const nsACString& aContinueToQuery);
 
-  nsresult
-  ContinueInternal(const Key& aKey,
-                   PRInt32 aCount);
-
   nsRefPtr<IDBRequest> mRequest;
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBIndex> mIndex;
 
   JSObject* mScriptOwner;
 
   Type mType;
@@ -144,16 +174,19 @@ protected:
 
   Key mRangeKey;
 
   Key mKey;
   Key mObjectKey;
   StructuredCloneReadInfo mCloneReadInfo;
   Key mContinueToKey;
 
+  IndexedDBCursorChild* mActorChild;
+  IndexedDBCursorParent* mActorParent;
+
   bool mHaveCachedKey;
   bool mHaveCachedPrimaryKey;
   bool mHaveCachedValue;
   bool mRooted;
   bool mContinueCalled;
   bool mHaveValue;
 };
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "IDBDatabase.h"
 
 #include "mozilla/Mutex.h"
 #include "mozilla/storage.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMLists.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
@@ -21,71 +23,72 @@
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "IDBFactory.h"
 #include "IndexedDatabaseManager.h"
 #include "TransactionThreadPool.h"
 #include "DictionaryHelpers.h"
-#include "nsDOMEventTargetHelper.h"
+
+#include "ipc/IndexedDBChild.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
-class CreateObjectStoreHelper : public AsyncConnectionHelper
+class NoRequestDatabaseHelper : public AsyncConnectionHelper
+{
+public:
+  NoRequestDatabaseHelper(IDBTransaction* aTransaction)
+  : AsyncConnectionHelper(aTransaction, nsnull)
+  {
+    NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    NS_ASSERTION(aTransaction, "Null transaction!");
+  }
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult OnSuccess() MOZ_OVERRIDE;
+
+  virtual void OnError() MOZ_OVERRIDE;
+};
+
+class CreateObjectStoreHelper : public NoRequestDatabaseHelper
 {
 public:
   CreateObjectStoreHelper(IDBTransaction* aTransaction,
                           IDBObjectStore* aObjectStore)
-  : AsyncConnectionHelper(aTransaction, nsnull), mObjectStore(aObjectStore)
+  : NoRequestDatabaseHelper(aTransaction), mObjectStore(aObjectStore)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-
-  nsresult OnSuccess()
-  {
-    return NS_OK;
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
 
-  void OnError()
-  {
-    NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
-  }
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
 
 private:
   nsRefPtr<IDBObjectStore> mObjectStore;
 };
 
-class DeleteObjectStoreHelper : public AsyncConnectionHelper
+class DeleteObjectStoreHelper : public NoRequestDatabaseHelper
 {
 public:
   DeleteObjectStoreHelper(IDBTransaction* aTransaction,
                           PRInt64 aObjectStoreId)
-  : AsyncConnectionHelper(aTransaction, nsnull), mObjectStoreId(aObjectStoreId)
+  : NoRequestDatabaseHelper(aTransaction), mObjectStoreId(aObjectStoreId)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-
-  nsresult OnSuccess()
-  {
-    return NS_OK;
-  }
-
-  void OnError()
-  {
-    NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
 
 private:
   // In-params.
   PRInt64 mObjectStoreId;
 };
 
 NS_STACK_CLASS
 class AutoRemoveObjectStore
@@ -149,28 +152,37 @@ IDBDatabase::Create(IDBWrapperCache* aOw
     return nsnull;
   }
 
   return db.forget();
 }
 
 IDBDatabase::IDBDatabase()
 : mDatabaseId(0),
+  mActorChild(nsnull),
+  mActorParent(nsnull),
   mInvalidated(0),
   mRegistered(false),
   mClosed(false),
   mRunningVersionChange(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBDatabase::~IDBDatabase()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->Send__delete__(mActorChild);
+    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
+  }
+
   if (mRegistered) {
     CloseInternal(true);
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     if (mgr) {
       mgr->UnregisterDatabase(this);
     }
   }
@@ -220,16 +232,23 @@ IDBDatabase::CloseInternal(bool aIsDead)
         clonedInfo.swap(mDatabaseInfo);
       }
     }
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     if (mgr) {
       mgr->OnDatabaseClosed(this);
     }
+
+    // And let the parent process know as well.
+    if (mActorChild) {
+      NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+      mActorChild->SendClose(aIsDead);
+    }
+
     mClosed = true;
   }
 }
 
 bool
 IDBDatabase::IsClosed()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -264,16 +283,58 @@ IDBDatabase::OnUnlink()
   if (mgr) {
     mgr->UnregisterDatabase(this);
 
     // Don't try to unregister again in the destructor.
     mRegistered = false;
   }
 }
 
+nsresult
+IDBDatabase::CreateObjectStoreInternal(IDBTransaction* aTransaction,
+                                       const ObjectStoreInfoGuts& aInfo,
+                                       IDBObjectStore** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aTransaction, "Null transaction!");
+
+  DatabaseInfo* databaseInfo = aTransaction->DBInfo();
+
+  nsRefPtr<ObjectStoreInfo> newInfo = new ObjectStoreInfo();
+  *static_cast<ObjectStoreInfoGuts*>(newInfo.get()) = aInfo;
+
+  newInfo->nextAutoIncrementId = aInfo.autoIncrement ? 1 : 0;
+  newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
+
+  if (!databaseInfo->PutObjectStore(newInfo)) {
+    NS_WARNING("Put failed!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  // Don't leave this in the hash if we fail below!
+  AutoRemoveObjectStore autoRemove(databaseInfo, newInfo->name);
+
+  nsRefPtr<IDBObjectStore> objectStore =
+    aTransaction->GetOrCreateObjectStore(newInfo->name, newInfo, true);
+  NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    nsRefPtr<CreateObjectStoreHelper> helper =
+      new CreateObjectStoreHelper(aTransaction, objectStore);
+
+    nsresult rv = helper->DispatchToTransactionPool();
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  autoRemove.forget();
+  objectStore.forget(_retval);
+
+  return NS_OK;
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(versionchange)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -360,112 +421,100 @@ IDBDatabase::CreateObjectStore(const nsA
 
   DatabaseInfo* databaseInfo = transaction->DBInfo();
 
   mozilla::dom::IDBObjectStoreParameters params;
   nsString keyPath;
   keyPath.SetIsVoid(true);
   nsTArray<nsString> keyPathArray;
 
+  nsresult rv;
+
   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
-    nsresult rv = params.Init(aCx, &aOptions);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = params.Init(aCx, &aOptions);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
 
     // Get keyPath
     jsval val = params.keyPath;
     if (!JSVAL_IS_VOID(val) && !JSVAL_IS_NULL(val)) {
       if (!JSVAL_IS_PRIMITIVE(val) &&
           JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(val))) {
-    
+
         JSObject* obj = JSVAL_TO_OBJECT(val);
-    
+
         uint32_t length;
         if (!JS_GetArrayLength(aCx, obj, &length)) {
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
-    
+
         if (!length) {
           return NS_ERROR_DOM_SYNTAX_ERR;
         }
-    
+
         keyPathArray.SetCapacity(length);
-    
+
         for (uint32_t index = 0; index < length; index++) {
           jsval val;
           JSString* jsstr;
           nsDependentJSString str;
           if (!JS_GetElement(aCx, obj, index, &val) ||
               !(jsstr = JS_ValueToString(aCx, val)) ||
               !str.init(aCx, jsstr)) {
             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           }
-    
+
           if (!IDBObjectStore::IsValidKeyPath(aCx, str)) {
             return NS_ERROR_DOM_SYNTAX_ERR;
           }
-    
+
           keyPathArray.AppendElement(str);
         }
-    
+
         NS_ASSERTION(!keyPathArray.IsEmpty(), "This shouldn't have happened!");
       }
       else {
         JSString* jsstr;
         nsDependentJSString str;
         if (!(jsstr = JS_ValueToString(aCx, val)) ||
             !str.init(aCx, jsstr)) {
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
-    
+
         if (!IDBObjectStore::IsValidKeyPath(aCx, str)) {
           return NS_ERROR_DOM_SYNTAX_ERR;
         }
-    
+
         keyPath = str;
       }
     }
   }
 
   if (databaseInfo->ContainsStoreName(aName)) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
   if (params.autoIncrement &&
       ((!keyPath.IsVoid() && keyPath.IsEmpty()) || !keyPathArray.IsEmpty())) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
-  nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
-
-  newInfo->name = aName;
-  newInfo->id = databaseInfo->nextObjectStoreId++;
-  newInfo->keyPath = keyPath;
-  newInfo->keyPathArray = keyPathArray;
-  newInfo->nextAutoIncrementId = params.autoIncrement ? 1 : 0;
-  newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
-
-  if (!databaseInfo->PutObjectStore(newInfo)) {
-    NS_WARNING("Put failed!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
+  ObjectStoreInfoGuts guts;
 
-  // Don't leave this in the hash if we fail below!
-  AutoRemoveObjectStore autoRemove(databaseInfo, aName);
-
-  nsRefPtr<IDBObjectStore> objectStore =
-    transaction->GetOrCreateObjectStore(aName, newInfo);
-  NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  guts.name = aName;
+  guts.id = databaseInfo->nextObjectStoreId++;
+  guts.keyPath = keyPath;
+  guts.keyPathArray = keyPathArray;
+  guts.autoIncrement = params.autoIncrement;
 
-  nsRefPtr<CreateObjectStoreHelper> helper =
-    new CreateObjectStoreHelper(transaction, objectStore);
-
-  nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  autoRemove.forget();
+  nsRefPtr<IDBObjectStore> objectStore;
+  rv = CreateObjectStoreInternal(transaction, guts,
+                                 getter_AddRefs(objectStore));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   objectStore.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::DeleteObjectStore(const nsAString& aName)
 {
@@ -479,20 +528,31 @@ IDBDatabase::DeleteObjectStore(const nsA
   }
 
   DatabaseInfo* info = transaction->DBInfo();
   ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
   if (!objectStoreInfo) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
-  nsRefPtr<DeleteObjectStoreHelper> helper =
-    new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
-  nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsresult rv;
+
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    nsRefPtr<DeleteObjectStoreHelper> helper =
+      new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
+
+    rv = helper->DispatchToTransactionPool();
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    IndexedDBTransactionChild* actor = transaction->GetActorChild();
+    NS_ASSERTION(actor, "Must have an actor here!");
+
+    actor->SendDeleteObjectStore(nsString(aName));
+  }
 
   transaction->RemoveObjectStore(aName);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::Transaction(const jsval& aStoreNames,
@@ -663,23 +723,54 @@ IDBDatabase::PostHandleEvent(nsEventChai
         CreateGenericEvent(type, eDoesNotBubble, eNotCancelable);
       NS_ENSURE_STATE(duplicateEvent);
 
       nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(owner));
       NS_ASSERTION(target, "How can this happen?!");
 
       bool dummy;
       rv = target->DispatchEvent(duplicateEvent, &dummy);
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
     }
   }
 
   return NS_OK;
 }
 
+HelperBase::ChildProcessSendResult
+NoRequestDatabaseHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  return Success_NotSent;
+}
+
+nsresult
+NoRequestDatabaseHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  MOZ_NOT_REACHED("Should never get here!");
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+NoRequestDatabaseHelper::OnSuccess()
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  return NS_OK;
+}
+
+void
+NoRequestDatabaseHelper::OnError()
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  mTransaction->AbortWithCode(GetResultCode());
+}
+
 nsresult
 CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   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)"
   ));
@@ -717,23 +808,29 @@ CreateObjectStoreHelper::DoDatabaseWork(
                                 mObjectStore->KeyPath());
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else {
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
-
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
+void
+CreateObjectStoreHelper::ReleaseMainThreadObjects()
+{
+  mObjectStore = nsnull;
+  NoRequestDatabaseHelper::ReleaseMainThreadObjects();
+}
+
 nsresult
 DeleteObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     "DELETE FROM object_store "
     "WHERE id = :id "
   ));
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -21,16 +21,19 @@ class nsPIDOMWindow;
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 struct DatabaseInfo;
 class IDBIndex;
 class IDBObjectStore;
 class IDBTransaction;
 class IndexedDatabaseManager;
+class IndexedDBDatabaseChild;
+class IndexedDBDatabaseParent;
+struct ObjectStoreInfoGuts;
 
 class IDBDatabase : public IDBWrapperCache,
                     public nsIIDBDatabase
 {
   friend class AsyncConnectionHelper;
   friend class IndexedDatabaseManager;
 
 public:
@@ -98,36 +101,65 @@ public:
   void EnterSetVersionTransaction();
   void ExitSetVersionTransaction();
 
   FileManager* Manager() const
   {
     return mFileManager;
   }
 
+  void
+  SetActor(IndexedDBDatabaseChild* aActorChild)
+  {
+    NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
+    mActorChild = aActorChild;
+  }
+
+  void
+  SetActor(IndexedDBDatabaseParent* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent,
+                 "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
+  IndexedDBDatabaseChild*
+  GetActorChild() const
+  {
+    return mActorChild;
+  }
+
+  nsresult
+  CreateObjectStoreInternal(IDBTransaction* aTransaction,
+                            const ObjectStoreInfoGuts& aInfo,
+                            IDBObjectStore** _retval);
+
 private:
   IDBDatabase();
   ~IDBDatabase();
 
   void OnUnlink();
 
   nsRefPtr<DatabaseInfo> mDatabaseInfo;
   nsCOMPtr<nsIAtom> mDatabaseId;
   nsString mName;
   nsString mFilePath;
   nsCString mASCIIOrigin;
 
-  PRInt32 mInvalidated;
-  bool mRegistered;
-  bool mClosed;
-  bool mRunningVersionChange;
-
   nsRefPtr<FileManager> mFileManager;
 
   // Only touched on the main thread.
   NS_DECL_EVENT_HANDLER(abort)
   NS_DECL_EVENT_HANDLER(error)
   NS_DECL_EVENT_HANDLER(versionchange)
+
+  IndexedDBDatabaseChild* mActorChild;
+  IndexedDBDatabaseParent* mActorParent;
+
+  PRInt32 mInvalidated;
+  bool mRegistered;
+  bool mClosed;
+  bool mRunningVersionChange;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbdatabase_h__
--- a/dom/indexedDB/IDBEvents.cpp
+++ b/dom/indexedDB/IDBEvents.cpp
@@ -109,21 +109,22 @@ NS_IMETHODIMP
 IDBVersionChangeEvent::GetOldVersion(PRUint64* aOldVersion)
 {
   NS_ENSURE_ARG_POINTER(aOldVersion);
   *aOldVersion = mOldVersion;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBVersionChangeEvent::GetNewVersion(JS::Value* aNewVersion)
+IDBVersionChangeEvent::GetNewVersion(JSContext* aCx,
+                                     JS::Value* aNewVersion)
 {
   NS_ENSURE_ARG_POINTER(aNewVersion);
 
   if (!mNewVersion) {
     *aNewVersion = JSVAL_NULL;
   }
-  else {
-    *aNewVersion = INT_TO_JSVAL(mNewVersion);
+  else if (!JS_NewNumberValue(aCx, double(mNewVersion), aNewVersion)) {
+    return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -4,109 +4,168 @@
  * 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 "nsILocalFile.h"
+#include "nsIPrincipal.h"
 #include "nsIScriptContext.h"
 
 #include "mozilla/storage.h"
-#include "mozilla/dom/ContentChild.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
-#include "nsIPrincipal.h"
 #include "nsHashKeys.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCID.h"
-#include "nsXULAppAPI.h"
 
 #include "AsyncConnectionHelper.h"
 #include "CheckPermissionsHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IndexedDatabaseManager.h"
 #include "Key.h"
 
-using namespace mozilla;
+#include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/TabChild.h"
+using mozilla::dom::TabChild;
+
+#include "ipc/IndexedDBChild.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
-GeckoProcessType gAllowedProcessType = GeckoProcessType_Invalid;
-
 struct ObjectStoreInfoMap
 {
   ObjectStoreInfoMap()
   : id(LL_MININT), info(nsnull) { }
 
   PRInt64 id;
   ObjectStoreInfo* info;
 };
 
 } // anonymous namespace
 
 IDBFactory::IDBFactory()
-: mOwningObject(nsnull)
+: mOwningObject(nsnull), mActorChild(nsnull), mActorParent(nsnull)
 {
-  IDBFactory::NoteUsedByProcessType(XRE_GetProcessType());
 }
 
 IDBFactory::~IDBFactory()
 {
+  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->Send__delete__(mActorChild);
+    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
+  }
 }
 
 // static
-already_AddRefed<nsIIDBFactory>
-IDBFactory::Create(nsPIDOMWindow* aWindow)
+nsresult
+IDBFactory::Create(nsPIDOMWindow* aWindow,
+                   const nsACString& aASCIIOrigin,
+                   IDBFactory** aFactory)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aASCIIOrigin.IsEmpty() || nsContentUtils::IsCallerChrome(),
+               "Non-chrome may not supply their own origin!");
 
-  NS_ENSURE_TRUE(aWindow, nsnull);
+  NS_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (aWindow->IsOuterWindow()) {
     aWindow = aWindow->GetCurrentInnerWindow();
-    NS_ENSURE_TRUE(aWindow, nsnull);
+    NS_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  // Make sure that the manager is up before we do anything here since lots of
+  // decisions depend on which process we're running in.
+  nsRefPtr<indexedDB::IndexedDatabaseManager> mgr =
+    indexedDB::IndexedDatabaseManager::GetOrCreate();
+  NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  nsresult rv;
+
+  nsCString origin(aASCIIOrigin);
+  if (origin.IsEmpty()) {
+    rv = IndexedDatabaseManager::GetASCIIOriginFromWindow(aWindow, origin);
+    if (NS_FAILED(rv)) {
+      // Not allowed.
+      *aFactory = nsnull;
+      return NS_OK;
+    }
   }
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
+  factory->mASCIIOrigin = origin;
   factory->mWindow = aWindow;
-  return factory.forget();
+
+  if (!IndexedDatabaseManager::IsMainProcess()) {
+    TabChild* tabChild = GetTabChildFrom(aWindow);
+    NS_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    IndexedDBChild* actor = new IndexedDBChild(origin);
+
+    bool allowed;
+    tabChild->SendPIndexedDBConstructor(actor, origin, &allowed);
+
+    if (!allowed) {
+      actor->Send__delete__(actor);
+      *aFactory = nsnull;
+      return NS_OK;
+    }
+
+    actor->SetFactory(factory);
+  }
+
+  factory.forget(aFactory);
+  return NS_OK;
 }
 
 // static
-already_AddRefed<nsIIDBFactory>
+nsresult
 IDBFactory::Create(JSContext* aCx,
-                   JSObject* aOwningObject)
+                   JSObject* aOwningObject,
+                   IDBFactory** aFactory)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aOwningObject, "Null object!");
   NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
                "Not a global object!");
+  NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+
+  nsCString origin;
+  nsresult rv =
+    IndexedDatabaseManager::GetASCIIOriginFromWindow(nsnull, origin);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<IDBFactory> factory = new IDBFactory();
+  factory->mASCIIOrigin = origin;
   factory->mOwningObject = aOwningObject;
-  return factory.forget();
+
+  factory.forget(aFactory);
+  return NS_OK;
 }
 
 // static
 already_AddRefed<mozIStorageConnection>
 IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
 {
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")),
                "Bad file path!");
 
   nsCOMPtr<nsILocalFile> dbFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
   NS_ENSURE_TRUE(dbFile, nsnull);
 
   nsresult rv = dbFile->InitWithPath(aDatabaseFilePath);
   NS_ENSURE_SUCCESS(rv, nsnull);
@@ -129,27 +188,16 @@ IDBFactory::GetConnection(const nsAStrin
   rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "PRAGMA foreign_keys = ON;"
   ));
   NS_ENSURE_SUCCESS(rv, nsnull);
 
   return connection.forget();
 }
 
-// static
-void
-IDBFactory::NoteUsedByProcessType(GeckoProcessType aProcessType)
-{
-  if (gAllowedProcessType == GeckoProcessType_Invalid) {
-    gAllowedProcessType = aProcessType;
-  } else if (aProcessType != gAllowedProcessType) {
-    NS_RUNTIMEABORT("More than one process type is accessing IndexedDB!");
-  }
-}
-
 inline
 bool
 IgnoreWhitespace(PRUnichar c)
 {
   return false;
 }
 
 // static
@@ -216,16 +264,18 @@ IDBFactory::LoadDatabaseInformation(mozI
         info->keyPath = keyPath;
       }
 
     }
 
     info->nextAutoIncrementId = stmt->AsInt64(3);
     info->comittedAutoIncrementId = info->nextAutoIncrementId;
 
+    info->autoIncrement = !!info->nextAutoIncrementId;
+
     ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
     NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY);
 
     mapEntry->id = info->id;
     mapEntry->info = info;
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -373,100 +423,126 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDB
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 DOMCI_DATA(IDBFactory, IDBFactory)
 
 nsresult
 IDBFactory::OpenCommon(const nsAString& aName,
                        PRInt64 aVersion,
                        bool aDeleting,
-                       nsIIDBOpenDBRequest** _retval)
+                       IDBOpenDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mWindow || mOwningObject, "Must have one of these!");
 
-  if (XRE_GetProcessType() == GeckoProcessType_Content) {
-    // Force ContentChild to cache the path from the parent, so that
-    // we do not end up in a side thread that asks for the path (which
-    // would make ContentChild try to send a message in a thread other
-    // than the main one).
-    ContentChild::GetSingleton()->GetIndexedDBPath();
-  }
-
   nsCOMPtr<nsPIDOMWindow> window;
   nsCOMPtr<nsIScriptGlobalObject> sgo;
   JSObject* scriptOwner = nsnull;
 
   if (mWindow) {
     window = mWindow;
   }
   else {
     scriptOwner = mOwningObject;
   }
 
-  nsCString origin;
-  nsresult rv =
-    IndexedDatabaseManager::GetASCIIOriginFromWindow(window, origin);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsRefPtr<IDBOpenDBRequest> request =
     IDBOpenDBRequest::Create(window, scriptOwner);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  nsRefPtr<OpenDatabaseHelper> openHelper =
-    new OpenDatabaseHelper(request, aName, origin, aVersion, aDeleting);
+  nsresult rv;
+
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    nsRefPtr<OpenDatabaseHelper> openHelper =
+      new OpenDatabaseHelper(request, aName, mASCIIOrigin, aVersion, aDeleting);
 
-  rv = openHelper->Init();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    rv = openHelper->Init();
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    nsRefPtr<CheckPermissionsHelper> permissionHelper =
+      new CheckPermissionsHelper(openHelper, window, mASCIIOrigin, aDeleting);
+
+    IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
+    NS_ASSERTION(mgr, "This should never be null!");
 
-  nsRefPtr<CheckPermissionsHelper> permissionHelper =
-    new CheckPermissionsHelper(openHelper, window, origin, aDeleting);
+    rv = 
+      mgr->WaitForOpenAllowed(mASCIIOrigin, openHelper->Id(), permissionHelper);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else if (aDeleting) {
+    nsCOMPtr<nsIAtom> databaseId =
+      IndexedDatabaseManager::GetDatabaseId(mASCIIOrigin, aName);
+    NS_ENSURE_TRUE(databaseId, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    IndexedDBDeleteDatabaseRequestChild* actor =
+      new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId);
 
-  nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
-  NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor(
+                                                               actor,
+                                                               nsString(aName));
+  }
+  else {
+    IndexedDBDatabaseChild* dbActor =
+      static_cast<IndexedDBDatabaseChild*>(
+        mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName),
+                                                       aVersion));
 
-  rv = mgr->WaitForOpenAllowed(origin, openHelper->Id(), permissionHelper);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    dbActor->SetRequest(request);
+  }
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBFactory::Open(const nsAString& aName,
                  PRInt64 aVersion,
                  PRUint8 aArgc,
                  nsIIDBOpenDBRequest** _retval)
 {
   if (aVersion < 1 && aArgc) {
     return NS_ERROR_TYPE_ERR;
   }
 
-  return OpenCommon(aName, aVersion, false, _retval);
+  nsRefPtr<IDBOpenDBRequest> request;
+  nsresult rv = OpenCommon(aName, aVersion, false, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  request.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBFactory::DeleteDatabase(const nsAString& aName,
                            nsIIDBOpenDBRequest** _retval)
 {
-  return OpenCommon(aName, 0, true, _retval);
+  nsRefPtr<IDBOpenDBRequest> request;
+  nsresult rv = OpenCommon(aName, 0, true, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  request.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBFactory::Cmp(const jsval& aFirst,
                 const jsval& aSecond,
                 JSContext* aCx,
                 PRInt16* _retval)
 {
   Key first, second;
   nsresult rv = first.SetFromJSVal(aCx, aFirst);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   rv = second.SetFromJSVal(aCx, aSecond);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   if (first.IsUnset() || second.IsUnset()) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   *_retval = Key::CompareKeys(first, second);
   return NS_OK;
 }
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -8,73 +8,102 @@
 #define mozilla_dom_indexeddb_idbfactory_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "mozIStorageConnection.h"
 #include "nsIIDBFactory.h"
 
 #include "nsCycleCollectionParticipant.h"
-#include "nsXULAppAPI.h"
 
 class nsIAtom;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo;
 class IDBDatabase;
+class IDBOpenDBRequest;
+class IndexedDBChild;
+class IndexedDBParent;
+
 struct ObjectStoreInfo;
 
 class IDBFactory MOZ_FINAL : public nsIIDBFactory
 {
   typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBFactory)
   NS_DECL_NSIIDBFACTORY
 
-  static already_AddRefed<nsIIDBFactory> Create(nsPIDOMWindow* aWindow);
+  static nsresult Create(nsPIDOMWindow* aWindow,
+                         const nsACString& aASCIIOrigin,
+                         IDBFactory** aFactory);
 
-  static already_AddRefed<nsIIDBFactory> Create(JSContext* aCx,
-                                                JSObject* aOwningObject);
+  static nsresult Create(nsPIDOMWindow* aWindow,
+                         nsIIDBFactory** aFactory)
+  {
+    nsRefPtr<IDBFactory> factory;
+    nsresult rv = Create(aWindow, EmptyCString(), getter_AddRefs(factory));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    factory.forget(aFactory);
+    return NS_OK;
+  }
+
+  static nsresult Create(JSContext* aCx,
+                         JSObject* aOwningObject,
+                         IDBFactory** aFactory);
 
   static already_AddRefed<mozIStorageConnection>
   GetConnection(const nsAString& aDatabaseFilePath);
 
-  // Called when a process uses an IndexedDB factory. We only allow
-  // a single process type to use IndexedDB - the chrome/single process
-  // in Firefox, and the child process in Fennec - so access by more
-  // than one process type is a very serious error.
-  static void
-  NoteUsedByProcessType(GeckoProcessType aProcessType);
-
   static nsresult
   LoadDatabaseInformation(mozIStorageConnection* aConnection,
                           nsIAtom* aDatabaseId,
                           PRUint64* aVersion,
                           ObjectStoreInfoArray& aObjectStores);
 
   static nsresult
   SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
                       PRUint64 aVersion,
                       ObjectStoreInfoArray& aObjectStores);
 
+  nsresult
+  OpenCommon(const nsAString& aName,
+             PRInt64 aVersion,
+             bool aDeleting,
+             IDBOpenDBRequest** _retval);
+
+  void
+  SetActor(IndexedDBChild* aActorChild)
+  {
+    NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
+    mActorChild = aActorChild;
+  }
+
+  void
+  SetActor(IndexedDBParent* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent, "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
 private:
   IDBFactory();
   ~IDBFactory();
 
-  nsresult
-  OpenCommon(const nsAString& aName,
-             PRInt64 aVersion,
-             bool aDeleting,
-             nsIIDBOpenDBRequest** _retval);
+  nsCString mASCIIOrigin;
 
   // If this factory lives on a window then mWindow must be non-null. Otherwise
   // mOwningObject must be non-null.
   nsCOMPtr<nsPIDOMWindow> mWindow;
   JSObject* mOwningObject;
+
+  IndexedDBChild* mActorChild;
+  IndexedDBParent* mActorParent;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbfactory_h__
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
 
 #include "IDBIndex.h"
 
 #include "nsIIDBKeyRange.h"
 #include "nsIJSContextStack.h"
 
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
@@ -19,45 +20,88 @@
 #include "AsyncConnectionHelper.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 
+#include "ipc/IndexedDBChild.h"
+#include "ipc/IndexedDBParent.h"
+
+#include "IndexedDatabaseInlines.h"
+
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
-class GetKeyHelper : public AsyncConnectionHelper
+class IndexHelper : public AsyncConnectionHelper
+{
+public:
+  typedef ipc::IndexRequestParams IndexRequestParams;
+
+  IndexHelper(IDBTransaction* aTransaction,
+              IDBRequest* aRequest,
+              IDBIndex* aIndex)
+  : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
+    mActor(nsnull)
+  {
+    NS_ASSERTION(aTransaction, "Null transaction!");
+    NS_ASSERTION(aRequest, "Null request!");
+    NS_ASSERTION(aIndex, "Null index!");
+  }
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) = 0;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
+
+protected:
+  nsRefPtr<IDBIndex> mIndex;
+
+private:
+  IndexedDBIndexRequestChild* mActor;
+};
+
+class GetKeyHelper : public IndexHelper
 {
 public:
   GetKeyHelper(IDBTransaction* aTransaction,
                IDBRequest* aRequest,
                IDBIndex* aIndex,
                IDBKeyRange* aKeyRange)
-  : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange)
+  : IndexHelper(aTransaction, aRequest, aIndex), mKeyRange(aKeyRange)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mIndex = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   // In-params.
-  nsRefPtr<IDBIndex> mIndex;
   nsRefPtr<IDBKeyRange> mKeyRange;
 
   // Out-params.
   Key mKey;
 };
 
 class GetHelper : public GetKeyHelper
 {
@@ -69,44 +113,64 @@ public:
   : GetKeyHelper(aTransaction, aRequest, aIndex, aKeyRange)
   { }
 
   ~GetHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
-    GetKeyHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   StructuredCloneReadInfo mCloneReadInfo;
 };
 
 class GetAllKeysHelper : public GetKeyHelper
 {
 public:
   GetAllKeysHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBIndex* aIndex,
                    IDBKeyRange* aKeyRange,
                    const PRUint32 aLimit)
   : GetKeyHelper(aTransaction, aRequest, aIndex, aKeyRange), mLimit(aLimit)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   const PRUint32 mLimit;
   nsTArray<Key> mKeys;
 };
 
 class GetAllHelper : public GetKeyHelper
 {
@@ -122,138 +186,157 @@ public:
   ~GetAllHelper()
   {
     for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
       IDBObjectStore::ClearStructuredCloneBuffer(
         mCloneReadInfos[index].mCloneBuffer);
     }
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
-      IDBObjectStore::ClearStructuredCloneBuffer(
-        mCloneReadInfos[index].mCloneBuffer);
-    }
-    GetKeyHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   const PRUint32 mLimit;
   nsTArray<StructuredCloneReadInfo> mCloneReadInfos;
 };
 
-class OpenKeyCursorHelper : public AsyncConnectionHelper
+class OpenKeyCursorHelper : public IndexHelper
 {
 public:
   OpenKeyCursorHelper(IDBTransaction* aTransaction,
                       IDBRequest* aRequest,
                       IDBIndex* aIndex,
                       IDBKeyRange* aKeyRange,
                       IDBCursor::Direction aDirection)
-  : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange), mDirection(aDirection)
+  : IndexHelper(aTransaction, aRequest, aIndex), mKeyRange(aKeyRange),
+    mDirection(aDirection)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
+  ~OpenKeyCursorHelper()
   {
-    mIndex = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
+    NS_ASSERTION(true, "bas");
   }
 
-private:
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
+
+protected:
+  virtual nsresult EnsureCursor();
+
   // In-params.
-  nsRefPtr<IDBIndex> mIndex;
   nsRefPtr<IDBKeyRange> mKeyRange;
   const IDBCursor::Direction mDirection;
 
   // Out-params.
   Key mKey;
   Key mObjectKey;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
+
+  // Only used in the parent process.
+  nsRefPtr<IDBCursor> mCursor;
 };
 
-class OpenCursorHelper : public AsyncConnectionHelper
+class OpenCursorHelper : public OpenKeyCursorHelper
 {
 public:
   OpenCursorHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBIndex* aIndex,
                    IDBKeyRange* aKeyRange,
                    IDBCursor::Direction aDirection)
-  : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange), mDirection(aDirection)
+  : OpenKeyCursorHelper(aTransaction, aRequest, aIndex, aKeyRange, aDirection)
   { }
 
   ~OpenCursorHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mIndex = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
 
 private:
-  // In-params.
-  nsRefPtr<IDBIndex> mIndex;
-  nsRefPtr<IDBKeyRange> mKeyRange;
-  const IDBCursor::Direction mDirection;
-
-  // Out-params.
-  Key mKey;
-  Key mObjectKey;
+  virtual nsresult EnsureCursor();
+
   StructuredCloneReadInfo mCloneReadInfo;
-  nsCString mContinueQuery;
-  nsCString mContinueToQuery;
-  Key mRangeKey;
+
+  // Only used in the parent process.
+  SerializedStructuredCloneReadInfo mSerializedCloneReadInfo;
 };
 
-class CountHelper : public AsyncConnectionHelper
+class CountHelper : public IndexHelper
 {
 public:
   CountHelper(IDBTransaction* aTransaction,
               IDBRequest* aRequest,
               IDBIndex* aIndex,
               IDBKeyRange* aKeyRange)
-  : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
-    mKeyRange(aKeyRange), mCount(0)
+  : IndexHelper(aTransaction, aRequest, aIndex), mKeyRange(aKeyRange), mCount(0)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mIndex = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 private:
-  nsRefPtr<IDBIndex> mIndex;
   nsRefPtr<IDBKeyRange> mKeyRange;
   PRUint64 mCount;
 };
 
 inline
 already_AddRefed<IDBRequest>
 GenerateRequest(IDBIndex* aIndex)
 {
@@ -263,45 +346,312 @@ GenerateRequest(IDBIndex* aIndex)
   return IDBRequest::Create(aIndex, database, transaction);
 }
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBIndex>
 IDBIndex::Create(IDBObjectStore* aObjectStore,
-                 const IndexInfo* aIndexInfo)
+                 const IndexInfo* aIndexInfo,
+                 bool aCreating)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(aIndexInfo, "Null pointer!");
 
   nsRefPtr<IDBIndex> index = new IDBIndex();
 
   index->mObjectStore = aObjectStore;
   index->mId = aIndexInfo->id;
   index->mName = aIndexInfo->name;
   index->mKeyPath = aIndexInfo->keyPath;
   index->mKeyPathArray = aIndexInfo->keyPathArray;
   index->mUnique = aIndexInfo->unique;
   index->mMultiEntry = aIndexInfo->multiEntry;
 
+  if (!IndexedDatabaseManager::IsMainProcess()) {
+    IndexedDBObjectStoreChild* objectStoreActor = aObjectStore->GetActorChild();
+    NS_ASSERTION(objectStoreActor, "Must have an actor here!");
+
+    nsAutoPtr<IndexedDBIndexChild> actor(new IndexedDBIndexChild(index));
+
+    ipc::IndexConstructorParams params;
+
+    if (aCreating) {
+      ipc::CreateIndexParams createParams;
+      createParams.info() = *aIndexInfo;
+      params = createParams;
+    }
+    else {
+      ipc::GetIndexParams getParams;
+      getParams.name() = aIndexInfo->name;
+      params = getParams;
+    }
+
+    objectStoreActor->SendPIndexedDBIndexConstructor(actor.forget(), params);
+  }
+
   return index.forget();
 }
 
 IDBIndex::IDBIndex()
 : mId(LL_MININT),
-  mUnique(false)
+  mActorChild(nsnull),
+  mActorParent(nsnull),
+  mUnique(false),
+  mMultiEntry(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBIndex::~IDBIndex()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->Send__delete__(mActorChild);
+    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
+  }
+}
+
+nsresult
+IDBIndex::GetInternal(IDBKeyRange* aKeyRange,
+                      IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::GetKeyInternal(IDBKeyRange* aKeyRange,
+                         IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::GetAllInternal(IDBKeyRange* aKeyRange,
+                         PRUint32 aLimit,
+                         IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::GetAllKeysInternal(IDBKeyRange* aKeyRange,
+                             PRUint32 aLimit,
+                             IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::CountInternal(IDBKeyRange* aKeyRange,
+                        IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::OpenKeyCursorInternal(IDBKeyRange* aKeyRange,
+                                size_t aDirection,
+                                IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  IDBCursor::Direction direction =
+    static_cast<IDBCursor::Direction>(aDirection);
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::OpenCursorInternal(IDBKeyRange* aKeyRange,
+                             size_t aDirection,
+                             IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBTransaction* transaction = mObjectStore->Transaction();
+  if (!transaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  IDBCursor::Direction direction =
+    static_cast<IDBCursor::Direction>(aDirection);
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::OpenCursorFromChildProcess(IDBRequest* aRequest,
+                                     size_t aDirection,
+                                     const Key& aKey,
+                                     const Key& aObjectKey,
+                                     IDBCursor** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IDBCursor::Direction direction =
+    static_cast<IDBCursor::Direction>(aDirection);
+
+  nsRefPtr<IDBCursor> cursor =
+    IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
+                      Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey);
+  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  cursor.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBIndex::OpenCursorFromChildProcess(
+                            IDBRequest* aRequest,
+                            size_t aDirection,
+                            const Key& aKey,
+                            const Key& aObjectKey,
+                            const SerializedStructuredCloneReadInfo& aCloneInfo,
+                            IDBCursor** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) ||
+               (aCloneInfo.dataLength && aCloneInfo.data),
+               "Inconsistent clone info!");
+
+  IDBCursor::Direction direction =
+    static_cast<IDBCursor::Direction>(aDirection);
+
+  StructuredCloneReadInfo cloneInfo;
+
+  if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
+    NS_WARNING("Failed to copy clone buffer!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  nsRefPtr<IDBCursor> cursor =
+    IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
+                      Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
+                      cloneInfo);
+  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
+
+  cursor.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObjectStore)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -417,23 +767,19 @@ IDBIndex::Get(const jsval& aKey,
   nsresult rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!keyRange) {
     // Must specify a key or keyRange for get().
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<GetHelper> helper =
-    new GetHelper(transaction, request, this, keyRange);
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = GetInternal(keyRange, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetKey(const jsval& aKey,
                  JSContext* aCx,
@@ -450,24 +796,19 @@ IDBIndex::GetKey(const jsval& aKey,
   nsresult rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!keyRange) {
     // Must specify a key or keyRange for get().
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<GetKeyHelper> helper =
-    new GetKeyHelper(transaction, request, this, keyRange);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = GetKeyInternal(keyRange, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetAll(const jsval& aKey,
                  PRUint32 aLimit,
@@ -489,24 +830,19 @@ IDBIndex::GetAll(const jsval& aKey,
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aOptionalArgCount < 2 || aLimit == 0) {
     aLimit = PR_UINT32_MAX;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<GetAllHelper> helper =
-    new GetAllHelper(transaction, request, this, keyRange, aLimit);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = GetAllInternal(keyRange, aLimit, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::GetAllKeys(const jsval& aKey,
                      PRUint32 aLimit,
@@ -528,24 +864,19 @@ IDBIndex::GetAllKeys(const jsval& aKey,
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aOptionalArgCount < 2 || aLimit == 0) {
     aLimit = PR_UINT32_MAX;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<GetAllKeysHelper> helper =
-    new GetAllKeysHelper(transaction, request, this, keyRange, aLimit);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = GetAllKeysInternal(keyRange, aLimit, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::OpenCursor(const jsval& aKey,
                      const nsAString& aDirection,
@@ -612,24 +943,19 @@ IDBIndex::OpenKeyCursor(const jsval& aKe
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aOptionalArgCount >= 2) {
       rv = IDBCursor::ParseDirection(aDirection, &direction);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<OpenKeyCursorHelper> helper =
-    new OpenKeyCursorHelper(transaction, request, this, keyRange, direction);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = OpenKeyCursorInternal(keyRange, direction, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::Count(const jsval& aKey,
                 JSContext* aCx,
@@ -644,28 +970,55 @@ IDBIndex::Count(const jsval& aKey,
   nsresult rv;
 
   nsRefPtr<IDBKeyRange> keyRange;
   if (aOptionalArgCount) {
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<CountHelper> helper =
-    new CountHelper(transaction, request, this, keyRange);
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = CountInternal(keyRange, getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(_retval);
   return NS_OK;
 }
 
+void
+IndexHelper::ReleaseMainThreadObjects()
+{
+  mIndex = nsnull;
+  AsyncConnectionHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+IndexHelper::Dispatch(nsIEventTarget* aDatabaseThread)
+{
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    return AsyncConnectionHelper::Dispatch(aDatabaseThread);
+  }
+
+  IndexedDBIndexChild* indexActor = mIndex->GetActorChild();
+  NS_ASSERTION(indexActor, "Must have an actor here!");
+
+  IndexRequestParams params;
+  nsresult rv = PackArgumentsForParentProcess(params);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NoDispatchEventTarget target;
+  rv = AsyncConnectionHelper::Dispatch(&target);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  mActor = new IndexedDBIndexRequestChild(this, mIndex, params.type());
+  indexActor->SendPIndexedDBRequestConstructor(mActor, params);
+
+  return NS_OK;
+}
+
 nsresult
 GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
@@ -711,16 +1064,75 @@ GetKeyHelper::DoDatabaseWork(mozIStorage
 
 nsresult
 GetKeyHelper::GetSuccessResult(JSContext* aCx,
                                jsval* aVal)
 {
   return mKey.ToJSVal(aCx, aVal);
 }
 
+void
+GetKeyHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  IndexHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+GetKeyHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  NS_ASSERTION(mKeyRange, "This should never be null!");
+
+  ipc::GetKeyParams params;
+
+  mKeyRange->ToSerializedKeyRange(params.keyRange());
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+GetKeyHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::GetKeyResponse getKeyResponse;
+    getKeyResponse.key() = mKey;
+    response = getKeyResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+GetKeyHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetKeyResponse,
+               "Bad response type!");
+
+  mKey = aResponseValue.get_GetKeyResponse().key();
+  return NS_OK;
+}
+
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
@@ -774,16 +1186,91 @@ GetHelper::GetSuccessResult(JSContext* a
   bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal);
 
   mCloneReadInfo.mCloneBuffer.clear();
 
   NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
+void
+GetHelper::ReleaseMainThreadObjects()
+{
+  IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
+  GetKeyHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+GetHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  NS_ASSERTION(mKeyRange, "This should never be null!");
+
+  ipc::FIXME_Bug_521898_index::GetParams params;
+
+  mKeyRange->ToSerializedKeyRange(params.keyRange());
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
+    NS_WARNING("No support for transferring blobs across processes yet!");
+    return Error;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    SerializedStructuredCloneReadInfo readInfo;
+    readInfo = mCloneReadInfo;
+    ipc::GetResponse getResponse = readInfo;
+    response = getResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
+               "Bad response type!");
+
+  const SerializedStructuredCloneReadInfo& cloneInfo =
+    aResponseValue.get_GetResponse().cloneInfo();
+
+  NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
+               (cloneInfo.dataLength && cloneInfo.data),
+               "Inconsistent clone info!");
+
+  if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
+    NS_WARNING("Failed to copy clone buffer!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
+}
+
 nsresult
 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   nsCString tableName;
   if (mIndex->IsUnique()) {
     tableName.AssignLiteral("unique_index_data");
   }
   else {
@@ -883,16 +1370,75 @@ GetAllKeysHelper::GetSuccessResult(JSCon
     }
   }
 
   *aVal = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
+GetAllKeysHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  ipc::GetAllKeysParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_index::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  params.limit() = mLimit;
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+GetAllKeysHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::GetAllKeysResponse getAllKeysResponse;
+    getAllKeysResponse.keys().AppendElements(mKeys);
+    response = getAllKeysResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+GetAllKeysHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllKeysResponse,
+               "Bad response type!");
+
+  mKeys.AppendElements(aResponseValue.get_GetAllKeysResponse().keys());
+  return NS_OK;
+}
+
+nsresult
 GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   nsCString indexTable;
   if (mIndex->IsUnique()) {
     indexTable.AssignLiteral("unique_index_data");
   }
   else {
     indexTable.AssignLiteral("index_data");
@@ -961,16 +1507,116 @@ GetAllHelper::GetSuccessResult(JSContext
   for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
     mCloneReadInfos[index].mCloneBuffer.clear();
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
+void
+GetAllHelper::ReleaseMainThreadObjects()
+{
+  for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
+    IDBObjectStore::ClearStructuredCloneBuffer(
+      mCloneReadInfos[index].mCloneBuffer);
+  }
+  GetKeyHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+GetAllHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  ipc::FIXME_Bug_521898_index::GetAllParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_index::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  params.limit() = mLimit;
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
+    if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
+      NS_WARNING("No support for transferring blobs across processes yet!");
+      return Error;
+    }
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::GetAllResponse getAllResponse;
+
+    InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
+      getAllResponse.cloneInfos();
+
+    infos.SetCapacity(mCloneReadInfos.Length());
+
+    for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
+      SerializedStructuredCloneReadInfo* info = infos.AppendElement();
+      *info = mCloneReadInfos[index];
+    }
+
+    response = getAllResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+GetAllHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
+               "Bad response type!");
+
+  const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
+    aResponseValue.get_GetAllResponse().cloneInfos();
+
+  mCloneReadInfos.SetCapacity(cloneInfos.Length());
+
+  for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
+    const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
+
+    StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
+    if (!destInfo->SetFromSerialized(srcInfo)) {
+      NS_WARNING("Failed to copy clone buffer!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+  }
+
+  return NS_OK;
+}
+
 nsresult
 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
   nsCString table;
   if (mIndex->IsUnique()) {
     table.AssignLiteral("unique_index_data");
@@ -1126,30 +1772,177 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
   return NS_OK;
 }
 
 nsresult
-OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
-                                      jsval* aVal)
+OpenKeyCursorHelper::EnsureCursor()
 {
-  if (mKey.IsUnset()) {
-    *aVal = JSVAL_VOID;
+  if (mCursor || mKey.IsUnset()) {
     return NS_OK;
   }
 
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
                       mContinueQuery, mContinueToQuery, mKey, mObjectKey);
   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  return WrapNative(aCx, cursor, aVal);
+  mCursor.swap(cursor);
+  return NS_OK;
+}
+
+nsresult
+OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
+                                      jsval* aVal)
+{
+  nsresult rv = EnsureCursor();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mCursor) {
+    rv = WrapNative(aCx, mCursor, aVal);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    *aVal = JSVAL_VOID;
+  }
+
+  return NS_OK;
+}
+
+void
+OpenKeyCursorHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  mCursor = nsnull;
+  IndexHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+OpenKeyCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  ipc::OpenKeyCursorParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_index::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  params.direction() = mDirection;
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+OpenKeyCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
+
+  if (NS_SUCCEEDED(aResultCode)) {
+    nsresult rv = EnsureCursor();
+    if (NS_FAILED(rv)) {
+      NS_WARNING("EnsureCursor failed!");
+      aResultCode = rv;
+    }
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::OpenCursorResponse openCursorResponse;
+
+    if (!mCursor) {
+      openCursorResponse = mozilla::void_t();
+    }
+    else {
+      IndexedDBIndexParent* indexActor = mIndex->GetActorParent();
+      NS_ASSERTION(indexActor, "Must have an actor here!");
+
+      IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
+      NS_ASSERTION(requestActor, "Must have an actor here!");
+
+      ipc::IndexCursorConstructorParams params;
+      params.requestParent() = requestActor;
+      params.direction() = mDirection;
+      params.key() = mKey;
+      params.objectKey() = mObjectKey;
+      params.optionalCloneInfo() = mozilla::void_t();
+
+      IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
+
+      if (!indexActor->SendPIndexedDBCursorConstructor(cursorActor, params)) {
+        return Error;
+      }
+
+      openCursorResponse = cursorActor;
+    }
+
+    response = openCursorResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+OpenKeyCursorHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TOpenCursorResponse,
+               "Bad response type!");
+  NS_ASSERTION(aResponseValue.get_OpenCursorResponse().type() ==
+               ipc::OpenCursorResponse::Tvoid_t ||
+               aResponseValue.get_OpenCursorResponse().type() ==
+               ipc::OpenCursorResponse::TPIndexedDBCursorChild,
+               "Bad response union type!");
+  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
+
+  const ipc::OpenCursorResponse& response =
+    aResponseValue.get_OpenCursorResponse();
+
+  switch (response.type()) {
+    case ipc::OpenCursorResponse::Tvoid_t:
+      break;
+
+    case ipc::OpenCursorResponse::TPIndexedDBCursorChild: {
+      IndexedDBCursorChild* actor =
+        static_cast<IndexedDBCursorChild*>(
+          response.get_PIndexedDBCursorChild());
+
+      mCursor = actor->ForgetStrongCursor();
+      NS_ASSERTION(mCursor, "This should never be null!");
+
+    } break;
+
+    default:
+      NS_NOTREACHED("Unknown response union type!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
   nsCString indexTable;
@@ -1319,33 +2112,144 @@ OpenCursorHelper::DoDatabaseWork(mozISto
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
   return NS_OK;
 }
 
 nsresult
-OpenCursorHelper::GetSuccessResult(JSContext* aCx,
-                                   jsval* aVal)
+OpenCursorHelper::EnsureCursor()
 {
-  if (mKey.IsUnset()) {
-    *aVal = JSVAL_VOID;
+  if (mCursor || mKey.IsUnset()) {
     return NS_OK;
   }
 
+  mSerializedCloneReadInfo = mCloneReadInfo;
+
+  NS_ASSERTION(mSerializedCloneReadInfo.data &&
+               mSerializedCloneReadInfo.dataLength,
+               "Shouldn't be possible!");
+
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
                       mContinueQuery, mContinueToQuery, mKey, mObjectKey,
                       mCloneReadInfo);
   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
 
-  return WrapNative(aCx, cursor, aVal);
+  mCursor.swap(cursor);
+  return NS_OK;
+}
+
+void
+OpenCursorHelper::ReleaseMainThreadObjects()
+{
+  IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
+
+  // These don't need to be released on the main thread but they're only valid
+  // as long as mCursor is set.
+  mSerializedCloneReadInfo.data = nsnull;
+  mSerializedCloneReadInfo.dataLength = 0;
+
+  OpenKeyCursorHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+OpenCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  ipc::FIXME_Bug_521898_index::OpenCursorParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_index::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  params.direction() = mDirection;
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
+    NS_WARNING("No support for transferring blobs across processes yet!");
+    return Error;
+  }
+
+  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
+
+  if (NS_SUCCEEDED(aResultCode)) {
+    nsresult rv = EnsureCursor();
+    if (NS_FAILED(rv)) {
+      NS_WARNING("EnsureCursor failed!");
+      aResultCode = rv;
+    }
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::OpenCursorResponse openCursorResponse;
+
+    if (!mCursor) {
+      openCursorResponse = mozilla::void_t();
+    }
+    else {
+      IndexedDBIndexParent* indexActor = mIndex->GetActorParent();
+      NS_ASSERTION(indexActor, "Must have an actor here!");
+
+      IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
+      NS_ASSERTION(requestActor, "Must have an actor here!");
+
+      NS_ASSERTION(mSerializedCloneReadInfo.data &&
+                   mSerializedCloneReadInfo.dataLength,
+                   "Shouldn't be possible!");
+
+      ipc::IndexCursorConstructorParams params;
+      params.requestParent() = requestActor;
+      params.direction() = mDirection;
+      params.key() = mKey;
+      params.objectKey() = mObjectKey;
+      params.optionalCloneInfo() = mSerializedCloneReadInfo;
+
+      IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
+
+      if (!indexActor->SendPIndexedDBCursorConstructor(cursorActor, params)) {
+        return Error;
+      }
+
+      openCursorResponse = cursorActor;
+    }
+
+    response = openCursorResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
 }
 
 nsresult
 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   nsCString table;
   if (mIndex->IsUnique()) {
     table.AssignLiteral("unique_index_data");
@@ -1401,10 +2305,78 @@ CountHelper::DoDatabaseWork(mozIStorageC
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               jsval* aVal)
 {
-  return JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal);
+  if (!JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal)) {
+    NS_WARNING("Failed to make number value!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
+}
+
+void
+CountHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  IndexHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+CountHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
+{
+  ipc::FIXME_Bug_521898_index::CountParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_index::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  aParams = params;
+  return NS_OK;
 }
+
+HelperBase::ChildProcessSendResult
+CountHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::CountResponse countResponse = mCount;
+    response = countResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+CountHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TCountResponse,
+               "Bad response type!");
+
+  mCount = aResponseValue.get_CountResponse().count();
+  return NS_OK;
+}
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -14,30 +14,38 @@
 #include "nsCycleCollectionParticipant.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
+class IDBCursor;
+class IDBKeyRange;
 class IDBObjectStore;
+class IDBRequest;
+class IndexedDBIndexChild;
+class IndexedDBIndexParent;
+class Key;
+
 struct IndexInfo;
 
 class IDBIndex MOZ_FINAL : public nsIIDBIndex
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBINDEX
 
   NS_DECL_CYCLE_COLLECTION_CLASS(IDBIndex)
 
   static already_AddRefed<IDBIndex>
   Create(IDBObjectStore* aObjectStore,
-         const IndexInfo* aIndexInfo);
+         const IndexInfo* aIndexInfo,
+         bool aCreating);
 
   IDBObjectStore* ObjectStore()
   {
     return mObjectStore;
   }
 
   const PRInt64 Id() const
   {
@@ -69,25 +77,96 @@ public:
     return !mKeyPathArray.IsEmpty();
   }
   
   const nsTArray<nsString>& KeyPathArray() const
   {
     return mKeyPathArray;
   }
 
+  void
+  SetActor(IndexedDBIndexChild* aActorChild)
+  {
+    NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
+    mActorChild = aActorChild;
+  }
+
+  void
+  SetActor(IndexedDBIndexParent* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent,
+                 "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
+  IndexedDBIndexChild*
+  GetActorChild() const
+  {
+    return mActorChild;
+  }
+
+  IndexedDBIndexParent*
+  GetActorParent() const
+  {
+    return mActorParent;
+  }
+
+  nsresult GetInternal(IDBKeyRange* aKeyRange,
+                       IDBRequest** _retval);
+
+  nsresult GetKeyInternal(IDBKeyRange* aKeyRange,
+                          IDBRequest** _retval);
+
+  nsresult GetAllInternal(IDBKeyRange* aKeyRange,
+                          PRUint32 aLimit,
+                          IDBRequest** _retval);
+
+  nsresult GetAllKeysInternal(IDBKeyRange* aKeyRange,
+                              PRUint32 aLimit,
+                              IDBRequest** _retval);
+
+  nsresult CountInternal(IDBKeyRange* aKeyRange,
+                         IDBRequest** _retval);
+
+  nsresult OpenCursorFromChildProcess(
+                            IDBRequest* aRequest,
+                            size_t aDirection,
+                            const Key& aKey,
+                            const Key& aObjectKey,
+                            IDBCursor** _retval);
+
+  nsresult OpenKeyCursorInternal(IDBKeyRange* aKeyRange,
+                                 size_t aDirection,
+                                 IDBRequest** _retval);
+
+  nsresult OpenCursorInternal(IDBKeyRange* aKeyRange,
+                              size_t aDirection,
+                              IDBRequest** _retval);
+
+  nsresult OpenCursorFromChildProcess(
+                            IDBRequest* aRequest,
+                            size_t aDirection,
+                            const Key& aKey,
+                            const Key& aObjectKey,
+                            const SerializedStructuredCloneReadInfo& aCloneInfo,
+                            IDBCursor** _retval);
+
 private:
   IDBIndex();
   ~IDBIndex();
 
   nsRefPtr<IDBObjectStore> mObjectStore;
 
   PRInt64 mId;
   nsString mName;
   nsString mKeyPath;
   nsTArray<nsString> mKeyPathArray;
+
+  IndexedDBIndexChild* mActorChild;
+  IndexedDBIndexParent* mActorParent;
+
   bool mUnique;
   bool mMultiEntry;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbindex_h__
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -1,25 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "IDBKeyRange.h"
 
 #include "nsIXPConnect.h"
 
 #include "nsDOMClassInfo.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 
 #include "Key.h"
 
+#include "mozilla/dom/indexedDB/PIndexedDBIndex.h"
+#include "mozilla/dom/indexedDB/PIndexedDBObjectStore.h"
+
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 inline
 bool
 ReturnKeyRange(JSContext* aCx,
                jsval* aVp,
@@ -252,31 +257,62 @@ IDBKeyRange::FromJSVal(JSContext* aCx,
   else {
     // An object is not permitted unless it's another IDBKeyRange.
     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     NS_ASSERTION(xpc, "This should never be null!");
 
     nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     rv = xpc->GetWrappedNativeOfJSObject(aCx, JSVAL_TO_OBJECT(aVal),
                                          getter_AddRefs(wrapper));
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    if (NS_FAILED(rv)) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    }
 
     nsCOMPtr<nsIIDBKeyRange> iface;
     if (!wrapper || !(iface = do_QueryInterface(wrapper->Native()))) {
       // Some random JS object?
       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
 
     keyRange = static_cast<IDBKeyRange*>(iface.get());
   }
 
   keyRange.forget(aKeyRange);
   return NS_OK;
 }
 
+// static
+template <class T>
+already_AddRefed<IDBKeyRange>
+IDBKeyRange::FromSerializedKeyRange(const T& aKeyRange)
+{
+  nsRefPtr<IDBKeyRange> keyRange =
+    new IDBKeyRange(aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
+                    aKeyRange.isOnly());
+  keyRange->Lower() = aKeyRange.lower();
+  if (!keyRange->IsOnly()) {
+    keyRange->Upper() = aKeyRange.upper();
+  }
+  return keyRange.forget();
+}
+
+template <class T>
+void
+IDBKeyRange::ToSerializedKeyRange(T& aKeyRange)
+{
+  aKeyRange.lowerOpen() = IsLowerOpen();
+  aKeyRange.upperOpen() = IsUpperOpen();
+  aKeyRange.isOnly() = IsOnly();
+
+  aKeyRange.lower() = Lower();
+  if (!IsOnly()) {
+    aKeyRange.upper() = Upper();
+  }
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
   if (JSVAL_IS_GCTHING(tmp->mCachedLowerVal)) {
@@ -375,8 +411,25 @@ IDBKeyRange::GetLowerOpen(bool* aLowerOp
 NS_IMETHODIMP
 IDBKeyRange::GetUpperOpen(bool* aUpperOpen)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   *aUpperOpen = mUpperOpen;
   return NS_OK;
 }
+
+// Explicitly instantiate for all our key range types... Grumble.
+template already_AddRefed<IDBKeyRange>
+IDBKeyRange::FromSerializedKeyRange<ipc::FIXME_Bug_521898_objectstore::KeyRange>
+(const ipc::FIXME_Bug_521898_objectstore::KeyRange& aKeyRange);
+
+template already_AddRefed<IDBKeyRange>
+IDBKeyRange::FromSerializedKeyRange<ipc::FIXME_Bug_521898_index::KeyRange>
+(const ipc::FIXME_Bug_521898_index::KeyRange& aKeyRange);
+
+template void
+IDBKeyRange::ToSerializedKeyRange<ipc::FIXME_Bug_521898_objectstore::KeyRange>
+(ipc::FIXME_Bug_521898_objectstore::KeyRange& aKeyRange);
+
+template void
+IDBKeyRange::ToSerializedKeyRange<ipc::FIXME_Bug_521898_index::KeyRange>
+(ipc::FIXME_Bug_521898_index::KeyRange& aKeyRange);
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -13,32 +13,43 @@
 #include "nsIIDBKeyRange.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class mozIStorageStatement;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
+namespace ipc {
+namespace FIXME_Bug_521898_objectstore {
+class KeyRange;
+} // namespace FIXME_Bug_521898_objectstore
+} // namespace ipc
+
 class IDBKeyRange MOZ_FINAL : public nsIIDBKeyRange
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBKEYRANGE
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBKeyRange)
 
   static JSBool DefineConstructors(JSContext* aCx,
                                    JSObject* aObject);
 
-  static
-  nsresult FromJSVal(JSContext* aCx,
-                     const jsval& aVal,
-                     IDBKeyRange** aKeyRange);
+  static nsresult FromJSVal(JSContext* aCx,
+                            const jsval& aVal,
+                            IDBKeyRange** aKeyRange);
 
-  IDBKeyRange(bool aLowerOpen, bool aUpperOpen, bool aIsOnly)
+  template <class T>
+  static already_AddRefed<IDBKeyRange>
+  FromSerializedKeyRange(const T& aKeyRange);
+
+  IDBKeyRange(bool aLowerOpen,
+              bool aUpperOpen,
+              bool aIsOnly)
   : mCachedLowerVal(JSVAL_VOID), mCachedUpperVal(JSVAL_VOID),
     mLowerOpen(aLowerOpen), mUpperOpen(aUpperOpen), mIsOnly(aIsOnly),
     mHaveCachedLowerVal(false), mHaveCachedUpperVal(false), mRooted(false)
   { }
 
   const Key& Lower() const
   {
     return mLower;
@@ -78,18 +89,18 @@ public:
                         nsACString& _retval) const
   {
     NS_NAMED_LITERAL_CSTRING(andStr, " AND ");
     NS_NAMED_LITERAL_CSTRING(spacecolon, " :");
     NS_NAMED_LITERAL_CSTRING(lowerKey, "lower_key");
 
     if (IsOnly()) {
       // Both keys are set and they're equal.
-      _retval = andStr + aKeyColumnName + NS_LITERAL_CSTRING(" =") + spacecolon +
-                lowerKey;
+      _retval = andStr + aKeyColumnName + NS_LITERAL_CSTRING(" =") +
+                spacecolon + lowerKey;
     }
     else {
       nsCAutoString clause;
 
       if (!Lower().IsUnset()) {
         // Lower key is set.
         clause.Append(andStr + aKeyColumnName);
         clause.AppendLiteral(" >");
@@ -131,17 +142,20 @@ public:
     if (!Upper().IsUnset()) {
       rv = Upper().BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     return NS_OK;
   }
 
-protected:
+  template <class T>
+  void ToSerializedKeyRange(T& aKeyRange);
+
+private:
   ~IDBKeyRange();
 
   Key mLower;
   Key mUpper;
   jsval mCachedLowerVal;
   jsval mCachedUpperVal;
   bool mLowerOpen;
   bool mUpperOpen;
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "IDBObjectStore.h"
 
 #include "nsIJSContextStack.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/storage.h"
 #include "nsCharSeparatedTokenizer.h"
@@ -28,97 +30,175 @@
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBIndex.h"
 #include "IDBKeyRange.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 #include "DictionaryHelpers.h"
 
+#include "ipc/IndexedDBChild.h"
+#include "ipc/IndexedDBParent.h"
+
+#include "IndexedDatabaseInlines.h"
+
 #define FILE_COPY_BUFFER_SIZE 32768
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
-class AddHelper : public AsyncConnectionHelper
+class ObjectStoreHelper : public AsyncConnectionHelper
+{
+public:
+  typedef ipc::ObjectStoreRequestParams ObjectStoreRequestParams;
+
+  ObjectStoreHelper(IDBTransaction* aTransaction,
+                    IDBRequest* aRequest,
+                    IDBObjectStore* aObjectStore)
+  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
+    mActor(nsnull)
+  {
+    NS_ASSERTION(aTransaction, "Null transaction!");
+    NS_ASSERTION(aRequest, "Null request!");
+    NS_ASSERTION(aObjectStore, "Null object store!");
+  }
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) = 0;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
+
+protected:
+  nsRefPtr<IDBObjectStore> mObjectStore;
+
+private:
+  IndexedDBObjectStoreRequestChild* mActor;
+};
+
+class NoRequestObjectStoreHelper : public AsyncConnectionHelper
+{
+public:
+  NoRequestObjectStoreHelper(IDBTransaction* aTransaction,
+                             IDBObjectStore* aObjectStore)
+  : AsyncConnectionHelper(aTransaction, nsnull), mObjectStore(aObjectStore)
+  {
+    NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    NS_ASSERTION(aTransaction, "Null transaction!");
+    NS_ASSERTION(aObjectStore, "Null object store!");
+  }
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+                                            MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult OnSuccess() MOZ_OVERRIDE;
+
+  virtual void OnError() MOZ_OVERRIDE;
+
+protected:
+  nsRefPtr<IDBObjectStore> mObjectStore;
+};
+
+class AddHelper : public ObjectStoreHelper
 {
 public:
   AddHelper(IDBTransaction* aTransaction,
             IDBRequest* aRequest,
             IDBObjectStore* aObjectStore,
             StructuredCloneWriteInfo& aCloneWriteInfo,
             const Key& aKey,
             bool aOverwrite,
             nsTArray<IndexUpdateInfo>& aIndexUpdateInfo)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
-    mKey(aKey), mOverwrite(aOverwrite)
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), mKey(aKey),
+    mOverwrite(aOverwrite)
   {
     mCloneWriteInfo.Swap(aCloneWriteInfo);
     mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
   }
 
   ~AddHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneWriteInfo.mCloneBuffer);
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    IDBObjectStore::ClearStructuredCloneBuffer(mCloneWriteInfo.mCloneBuffer);
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 private:
-  // In-params.
-  nsRefPtr<IDBObjectStore> mObjectStore;
-
   // These may change in the autoincrement case.
   StructuredCloneWriteInfo mCloneWriteInfo;
   Key mKey;
+  nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
   const bool mOverwrite;
-  nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
 };
 
-class GetHelper : public AsyncConnectionHelper
+class GetHelper : public ObjectStoreHelper
 {
 public:
   GetHelper(IDBTransaction* aTransaction,
             IDBRequest* aRequest,
             IDBObjectStore* aObjectStore,
             IDBKeyRange* aKeyRange)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
     mKeyRange(aKeyRange)
-  { }
+  {
+    NS_ASSERTION(aKeyRange, "Null key range!");
+  }
 
   ~GetHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    mKeyRange = nsnull;
-    IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   // In-params.
-  nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBKeyRange> mKeyRange;
 
 private:
   // Out-params.
   StructuredCloneReadInfo mCloneReadInfo;
 };
 
 class DeleteHelper : public GetHelper
@@ -126,229 +206,239 @@ class DeleteHelper : public GetHelper
 public:
   DeleteHelper(IDBTransaction* aTransaction,
                IDBRequest* aRequest,
                IDBObjectStore* aObjectStore,
                IDBKeyRange* aKeyRange)
   : GetHelper(aTransaction, aRequest, aObjectStore, aKeyRange)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 };
 
-class ClearHelper : public AsyncConnectionHelper
+class ClearHelper : public ObjectStoreHelper
 {
 public:
   ClearHelper(IDBTransaction* aTransaction,
               IDBRequest* aRequest,
               IDBObjectStore* aObjectStore)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore)
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
-
-protected:
-  // In-params.
-  nsRefPtr<IDBObjectStore> mObjectStore;
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 };
 
-class OpenCursorHelper : public AsyncConnectionHelper
+class OpenCursorHelper : public ObjectStoreHelper
 {
 public:
   OpenCursorHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBObjectStore* aObjectStore,
                    IDBKeyRange* aKeyRange,
                    IDBCursor::Direction aDirection)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
     mKeyRange(aKeyRange), mDirection(aDirection)
   { }
 
   ~OpenCursorHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    mKeyRange = nsnull;
-    IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 private:
+  nsresult EnsureCursor();
+
   // In-params.
-  nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBKeyRange> mKeyRange;
   const IDBCursor::Direction mDirection;
 
   // Out-params.
   Key mKey;
   StructuredCloneReadInfo mCloneReadInfo;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
+
+  // Only used in the parent process.
+  nsRefPtr<IDBCursor> mCursor;
+  SerializedStructuredCloneReadInfo mSerializedCloneReadInfo;
 };
 
-class CreateIndexHelper : public AsyncConnectionHelper
+class CreateIndexHelper : public NoRequestObjectStoreHelper
 {
 public:
-  CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex);
-
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-
-  nsresult OnSuccess()
+  CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex)
+  : NoRequestObjectStoreHelper(aTransaction, aIndex->ObjectStore()),
+    mIndex(aIndex)
   {
-    return NS_OK;
+    if (sTLSIndex == BAD_TLS_INDEX) {
+      PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry);
+    }
+
+    NS_ASSERTION(sTLSIndex != BAD_TLS_INDEX,
+                 "PR_NewThreadPrivateIndex failed!");
   }
 
-  void OnError()
-  {
-    NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
-  }
-
-  void ReleaseMainThreadObjects()
-  {
-    mIndex = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
 
 private:
   nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection);
 
   static void DestroyTLSEntry(void* aPtr);
 
   static PRUintn sTLSIndex;
 
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
 };
 
 PRUintn CreateIndexHelper::sTLSIndex = PRUintn(BAD_TLS_INDEX);
 
-class DeleteIndexHelper : public AsyncConnectionHelper
+class DeleteIndexHelper : public NoRequestObjectStoreHelper
 {
 public:
   DeleteIndexHelper(IDBTransaction* aTransaction,
-                    const nsAString& aName,
-                    IDBObjectStore* aObjectStore)
-  : AsyncConnectionHelper(aTransaction, nsnull), mName(aName),
-    mObjectStore(aObjectStore)
+                    IDBObjectStore* aObjectStore,
+                    const nsAString& aName)
+  : NoRequestObjectStoreHelper(aTransaction, aObjectStore), mName(aName)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-
-  nsresult OnSuccess()
-  {
-    return NS_OK;
-  }
-
-  void OnError()
-  {
-    NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
-  }
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
 
 private:
   // In-params
   nsString mName;
-  nsRefPtr<IDBObjectStore> mObjectStore;
 };
 
-class GetAllHelper : public AsyncConnectionHelper
+class GetAllHelper : public ObjectStoreHelper
 {
 public:
   GetAllHelper(IDBTransaction* aTransaction,
                IDBRequest* aRequest,
                IDBObjectStore* aObjectStore,
                IDBKeyRange* aKeyRange,
                const PRUint32 aLimit)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
     mKeyRange(aKeyRange), mLimit(aLimit)
   { }
 
   ~GetAllHelper()
   {
     for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
       IDBObjectStore::ClearStructuredCloneBuffer(
         mCloneReadInfos[index].mCloneBuffer);
     }
   }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    mKeyRange = nsnull;
-    for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
-      IDBObjectStore::ClearStructuredCloneBuffer(
-        mCloneReadInfos[index].mCloneBuffer);
-    }
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 protected:
   // In-params.
-  nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBKeyRange> mKeyRange;
   const PRUint32 mLimit;
 
 private:
   // Out-params.
   nsTArray<StructuredCloneReadInfo> mCloneReadInfos;
 };
 
-class CountHelper : public AsyncConnectionHelper
+class CountHelper : public ObjectStoreHelper
 {
 public:
   CountHelper(IDBTransaction* aTransaction,
               IDBRequest* aRequest,
               IDBObjectStore* aObjectStore,
               IDBKeyRange* aKeyRange)
-  : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
+  : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
     mKeyRange(aKeyRange), mCount(0)
   { }
 
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-  void ReleaseMainThreadObjects()
-  {
-    mObjectStore = nsnull;
-    mKeyRange = nsnull;
-    AsyncConnectionHelper::ReleaseMainThreadObjects();
-  }
-
-protected:
-  nsRefPtr<IDBObjectStore> mObjectStore;
-  nsRefPtr<IDBKeyRange> mKeyRange;
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
+
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
+
+  virtual nsresult
+  PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+                                  MOZ_OVERRIDE;
 
 private:
+  nsRefPtr<IDBKeyRange> mKeyRange;
   PRUint64 mCount;
 };
 
 NS_STACK_CLASS
 class AutoRemoveIndex
 {
 public:
   AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo,
@@ -373,16 +463,88 @@ public:
     mObjectStoreInfo = nsnull;
   }
 
 private:
   ObjectStoreInfo* mObjectStoreInfo;
   nsString mIndexName;
 };
 
+class ThreadLocalJSRuntime
+{
+  JSRuntime* mRuntime;
+  JSContext* mContext;
+  JSObject* mGlobal;
+
+  static JSClass sGlobalClass;
+  static const unsigned sRuntimeHeapSize = 256 * 1024;
+
+  ThreadLocalJSRuntime()
+  : mRuntime(NULL), mContext(NULL), mGlobal(NULL)
+  {
+      MOZ_COUNT_CTOR(ThreadLocalJSRuntime);
+  }
+
+  nsresult Init()
+  {
+    mRuntime = JS_NewRuntime(sRuntimeHeapSize);
+    NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
+
+    mContext = JS_NewContext(mRuntime, 0);
+    NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
+
+    JSAutoRequest ar(mContext);
+
+    mGlobal = JS_NewCompartmentAndGlobalObject(mContext, &sGlobalClass, NULL);
+    NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
+
+    JS_SetGlobalObject(mContext, mGlobal);
+    return NS_OK;
+  }
+
+ public:
+  static ThreadLocalJSRuntime *Create()
+  {
+    ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime();
+    NS_ENSURE_TRUE(entry, nsnull);
+
+    if (NS_FAILED(entry->Init())) {
+      delete entry;
+      return nsnull;
+    }
+
+    return entry;
+  }
+
+  JSContext *Context() const
+  {
+    return mContext;
+  }
+
+  ~ThreadLocalJSRuntime()
+  {
+    MOZ_COUNT_DTOR(ThreadLocalJSRuntime);
+
+    if (mContext) {
+      JS_DestroyContext(mContext);
+    }
+
+    if (mRuntime) {
+      JS_DestroyRuntime(mRuntime);
+    }
+  }
+};
+
+JSClass ThreadLocalJSRuntime::sGlobalClass = {
+  "IndexedDBTransactionThreadGlobal",
+  JSCLASS_GLOBAL_FLAGS,
+  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+};
+
 inline
 bool
 IgnoreWhitespace(PRUnichar c)
 {
   return false;
 }
 
 typedef nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> KeyPathTokenizer;
@@ -487,31 +649,55 @@ JSClass gDummyPropClass = {
 };
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBObjectStore>
 IDBObjectStore::Create(IDBTransaction* aTransaction,
                        ObjectStoreInfo* aStoreInfo,
-                       nsIAtom* aDatabaseId)
+                       nsIAtom* aDatabaseId,
+                       bool aCreating)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore();
 
   objectStore->mTransaction = aTransaction;
   objectStore->mName = aStoreInfo->name;
   objectStore->mId = aStoreInfo->id;
   objectStore->mKeyPath = aStoreInfo->keyPath;
   objectStore->mKeyPathArray = aStoreInfo->keyPathArray;
-  objectStore->mAutoIncrement = !!aStoreInfo->nextAutoIncrementId;
+  objectStore->mAutoIncrement = aStoreInfo->autoIncrement;
   objectStore->mDatabaseId = aDatabaseId;
   objectStore->mInfo = aStoreInfo;
 
+  if (!IndexedDatabaseManager::IsMainProcess()) {
+    IndexedDBTransactionChild* transactionActor = aTransaction->GetActorChild();
+    NS_ASSERTION(transactionActor, "Must have an actor here!");
+
+    ipc::ObjectStoreConstructorParams params;
+
+    if (aCreating) {
+      ipc::CreateObjectStoreParams createParams;
+      createParams.info() = *aStoreInfo;
+      params = createParams;
+    }
+    else {
+      ipc::GetObjectStoreParams getParams;
+      getParams.name() = aStoreInfo->name;
+      params = getParams;
+    }
+
+    IndexedDBObjectStoreChild* actor =
+      new IndexedDBObjectStoreChild(objectStore);
+
+    transactionActor->SendPIndexedDBObjectStoreConstructor(actor, params);
+  }
+
   return objectStore.forget();
 }
 
 // static
 bool
 IDBObjectStore::IsValidKeyPath(JSContext* aCx,
                                const nsAString& aKeyPath)
 {
@@ -547,24 +733,25 @@ IDBObjectStore::IsValidKeyPath(JSContext
     return false;
   }
 
   return true;
 }
 
 // static
 nsresult
-IDBObjectStore::AppendIndexUpdateInfo(PRInt64 aIndexID,
-                                      const nsAString& aKeyPath,
-                                      const nsTArray<nsString>& aKeyPathArray,
-                                      bool aUnique,
-                                      bool aMultiEntry,
-                                      JSContext* aCx,
-                                      jsval aVal,
-                                      nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
+IDBObjectStore::AppendIndexUpdateInfo(
+                                    PRInt64 aIndexID,
+                                    const nsAString& aKeyPath,
+                                    const nsTArray<nsString>& aKeyPathArray,
+                                    bool aUnique,
+                                    bool aMultiEntry,
+                                    JSContext* aCx,
+                                    jsval aVal,
+                                    nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
 {
   nsresult rv;
   if (!aKeyPathArray.IsEmpty()) {
     Key arrayKey;
     rv = GetKeyFromValue(aCx, aVal, aKeyPathArray, arrayKey);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!arrayKey.IsUnset()) {
@@ -914,18 +1101,20 @@ IDBObjectStore::StructuredCloneReadCallb
                                             uint32_t aTag,
                                             uint32_t aData,
                                             void* aClosure)
 {
   if (aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE) {
     StructuredCloneReadInfo* cloneReadInfo =
       reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
 
-    NS_ASSERTION(aData < cloneReadInfo->mFileInfos.Length(),
-                 "Bad blob index!");
+    if (aData >= cloneReadInfo->mFileInfos.Length()) {
+      NS_ERROR("Bad blob index!");
+      return nsnull;
+    }
 
     nsRefPtr<FileInfo> fileInfo = cloneReadInfo->mFileInfos[aData];
     nsRefPtr<FileManager> fileManager = fileInfo->Manager();
     nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
     if (!directory) {
       return nsnull;
     }
 
@@ -1094,24 +1283,32 @@ IDBObjectStore::ConvertFileIdsToArray(co
     *element = id;
   }
 
   return NS_OK;
 }
 
 IDBObjectStore::IDBObjectStore()
 : mId(LL_MININT),
-  mAutoIncrement(false)
+  mAutoIncrement(false),
+  mActorChild(nsnull),
+  mActorParent(nsnull)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBObjectStore::~IDBObjectStore()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->Send__delete__(mActorChild);
+    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
+  }
 }
 
 nsresult
 IDBObjectStore::GetAddInfo(JSContext* aCx,
                            jsval aValue,
                            jsval aKeyVal,
                            StructuredCloneWriteInfo& aCloneWriteInfo,
                            Key& aKey,
@@ -1125,17 +1322,19 @@ IDBObjectStore::GetAddInfo(JSContext* aC
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   JSAutoRequest ar(aCx);
 
   if (!HasKeyPath()) {
     // Out-of-line keys must be passed in.
     rv = aKey.SetFromJSVal(aCx, aKeyVal);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
   }
   else if (!mAutoIncrement) {
     // Inline keys live on the object. Make sure that the value passed in is an
     // object.
     if (UsesKeyPathArray()) {
       rv = GetKeyFromValue(aCx, aValue, mKeyPathArray, aKey);
     }
     else {
@@ -1224,17 +1423,18 @@ IDBObjectStore::GetAddInfo(JSContext* aC
           targetObjectPropName = token;
         }
       }
 
       if (targetObject) {
         // We have started inserting new objects or are about to just insert
         // the first one.
         if (tokenizer.hasMoreTokens()) {
-          // If we're not at the end, we need to add a dummy object to the chain.
+          // If we're not at the end, we need to add a dummy object to the
+          // chain.
           JSObject* dummy = JS_NewObject(aCx, nsnull, nsnull, nsnull);
           if (!dummy) {
             rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
             break;
           }
   
           if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
                                    token.Length(),
@@ -1290,18 +1490,18 @@ IDBObjectStore::GetAddInfo(JSContext* aC
   return rv;
 }
 
 nsresult
 IDBObjectStore::AddOrPut(const jsval& aValue,
                          const jsval& aKey,
                          JSContext* aCx,
                          PRUint8 aOptionalArgCount,
-                         nsIIDBRequest** _retval,
-                         bool aOverwrite)
+                         bool aOverwrite,
+                         IDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   if (!IsWriteAllowed()) {
@@ -1319,26 +1519,336 @@ IDBObjectStore::AddOrPut(const jsval& aV
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<AddHelper> helper =
-    new AddHelper(mTransaction, request, this, cloneWriteInfo, key, aOverwrite,
-                  updateInfo);
+    new AddHelper(mTransaction, request, this, cloneWriteInfo, key,
+                  aOverwrite, updateInfo);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
+nsresult
+IDBObjectStore::AddOrPutInternal(
+                      const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
+                      const Key& aKey,
+                      const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
+                      bool aOverwrite,
+                      IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  if (!IsWriteAllowed()) {
+    return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  StructuredCloneWriteInfo cloneWriteInfo;
+  if (!cloneWriteInfo.SetFromSerialized(aCloneWriteInfo)) {
+    NS_WARNING("Failed to copy structured clone buffer!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  Key key(aKey);
+
+  nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray);
+
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::GetInternal(IDBKeyRange* aKeyRange,
+                            IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aKeyRange, "Null pointer!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::GetAllInternal(IDBKeyRange* aKeyRange,
+                               PRUint32 aLimit,
+                               IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::DeleteInternal(IDBKeyRange* aKeyRange,
+                               IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aKeyRange, "Null key range!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  if (!IsWriteAllowed()) {
+    return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::ClearInternal(IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  if (!IsWriteAllowed()) {
+    return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::CountInternal(IDBKeyRange* aKeyRange,
+                              IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::OpenCursorInternal(IDBKeyRange* aKeyRange,
+                                   size_t aDirection,
+                                   IDBRequest** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  IDBCursor::Direction direction =
+    static_cast<IDBCursor::Direction>(aDirection);
+
+  nsRefPtr<IDBRequest> request = GenerateRequest(this);
+  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);
+
+  request.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::OpenCursorFromChildProcess(
+                            IDBRequest* aRequest,
+                            size_t aDirection,
+                            const Key& aKey,
+                            const SerializedStructuredCloneReadInfo& aCloneInfo,
+                            IDBCursor** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) ||
+               (aCloneInfo.dataLength && aCloneInfo.data),
+               "Inconsistent clone info!");
+
+  IDBCursor::Direction direction =
+    static_cast<IDBCursor::Direction>(aDirection);
+
+  StructuredCloneReadInfo cloneInfo;
+
+  if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
+    NS_WARNING("Failed to copy clone buffer!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  nsRefPtr<IDBCursor> cursor =
+    IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
+                      EmptyCString(), EmptyCString(), aKey, cloneInfo);
+  NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
+
+  cursor.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::CreateIndexInternal(const IndexInfo& aInfo,
+                                    nsTArray<nsString>& aKeyPathArray,
+                                    IDBIndex** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  IndexInfo* indexInfo = mInfo->indexes.AppendElement();
+
+  indexInfo->name = aInfo.name;
+  indexInfo->id = aInfo.id;
+  indexInfo->keyPath = aInfo.keyPath;
+  indexInfo->keyPathArray.SwapElements(aKeyPathArray);
+  indexInfo->unique = aInfo.unique;
+  indexInfo->multiEntry = aInfo.multiEntry;
+
+  // Don't leave this in the list if we fail below!
+  AutoRemoveIndex autoRemove(mInfo, aInfo.name);
+
+  nsRefPtr<IDBIndex> index = IDBIndex::Create(this, indexInfo, true);
+
+  mCreatedIndexes.AppendElement(index);
+
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    nsRefPtr<CreateIndexHelper> helper =
+      new CreateIndexHelper(mTransaction, index);
+
+    nsresult rv = helper->DispatchToTransactionPool();
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  autoRemove.forget();
+
+  index.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBObjectStore::IndexInternal(const nsAString& aName,
+                              IDBIndex** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (!mTransaction->IsOpen()) {
+    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
+  }
+
+  IndexInfo* indexInfo = nsnull;
+  PRUint32 indexCount = mInfo->indexes.Length();
+  for (PRUint32 index = 0; index < indexCount; index++) {
+    if (mInfo->indexes[index].name == aName) {
+      indexInfo = &(mInfo->indexes[index]);
+      break;
+    }
+  }
+
+  if (!indexInfo) {
+    return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
+  }
+
+  nsRefPtr<IDBIndex> retval;
+  for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
+    nsRefPtr<IDBIndex>& index = mCreatedIndexes[i];
+    if (index->Name() == aName) {
+      retval = index;
+      break;
+    }
+  }
+
+  if (!retval) {
+    retval = IDBIndex::Create(this, indexInfo, false);
+    NS_ENSURE_TRUE(retval, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (!mCreatedIndexes.AppendElement(retval)) {
+      NS_WARNING("Out of memory!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+  }
+
+  retval.forget(_retval);
+  return NS_OK;
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
                                                        nsIDOMEventTarget)
 
   for (PRUint32 i = 0; i < tmp->mCreatedIndexes.Length(); i++) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedIndexes[i]");
@@ -1459,24 +1969,21 @@ IDBObjectStore::Get(const jsval& aKey,
   nsresult rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!keyRange) {
     // Must specify a key or keyRange for get().
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<GetHelper> helper =
-    new GetHelper(mTransaction, request, this, keyRange);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = GetInternal(keyRange, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::GetAll(const jsval& aKey,
                        PRUint32 aLimit,
@@ -1497,51 +2004,64 @@ IDBObjectStore::GetAll(const jsval& aKey
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aOptionalArgCount < 2 || aLimit == 0) {
     aLimit = PR_UINT32_MAX;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<GetAllHelper> helper =
-    new GetAllHelper(mTransaction, request, this, keyRange, aLimit);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = GetAllInternal(keyRange, aLimit, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Add(const jsval& aValue,
                     const jsval& aKey,
                     JSContext* aCx,
                     PRUint8 aOptionalArgCount,
                     nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  return AddOrPut(aValue, aKey, aCx, aOptionalArgCount, _retval, false);
+  nsRefPtr<IDBRequest> request;
+  nsresult rv = AddOrPut(aValue, aKey, aCx, aOptionalArgCount, false,
+                         getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  request.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Put(const jsval& aValue,
                     const jsval& aKey,
                     JSContext* aCx,
                     PRUint8 aOptionalArgCount,
                     nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  return AddOrPut(aValue, aKey, aCx, aOptionalArgCount, _retval, true);
+  nsRefPtr<IDBRequest> request;
+  nsresult rv = AddOrPut(aValue, aKey, aCx, aOptionalArgCount, true,
+                         getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  request.forget(_retval);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Delete(const jsval& aKey,
                        JSContext* aCx,
                        nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -1551,57 +2071,46 @@ IDBObjectStore::Delete(const jsval& aKey
   }
 
   if (!IsWriteAllowed()) {
     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
   }
 
   nsRefPtr<IDBKeyRange> keyRange;
   nsresult rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   if (!keyRange) {
     // Must specify a key or keyRange for delete().
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<DeleteHelper> helper =
-    new DeleteHelper(mTransaction, request, this, keyRange);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = DeleteInternal(keyRange, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Clear(nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!mTransaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
-  }
-
-  if (!IsWriteAllowed()) {
-    return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
+  nsRefPtr<IDBRequest> request;
+  nsresult rv = ClearInternal(getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  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);
-
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::OpenCursor(const jsval& aKey,
                            const nsAString& aDirection,
                            JSContext* aCx,
@@ -1624,24 +2133,23 @@ IDBObjectStore::OpenCursor(const jsval& 
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aOptionalArgCount >= 2) {
       rv = IDBCursor::ParseDirection(aDirection, &direction);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<OpenCursorHelper> helper =
-    new OpenCursorHelper(mTransaction, request, this, keyRange, direction);
-
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  size_t argDirection = static_cast<size_t>(direction);
+
+  nsRefPtr<IDBRequest> request;
+  rv = OpenCursorInternal(keyRange, argDirection, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::CreateIndex(const nsAString& aName,
                             const jsval& aKeyPath,
@@ -1725,118 +2233,79 @@ IDBObjectStore::CreateIndex(const nsAStr
   }
 
   if (found) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
 
+#ifdef DEBUG
+  for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) {
+    if (mCreatedIndexes[index]->Name() == aName) {
+      NS_ERROR("Already created this one!");
+    }
+  }
+#endif
+
+  nsresult rv;
   mozilla::dom::IDBIndexParameters params;
 
   // Get optional arguments.
   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
-    nsresult rv = params.Init(aCx, &aOptions);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = params.Init(aCx, &aOptions);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
   }
 
   if (params.multiEntry && !keyPathArray.IsEmpty()) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   DatabaseInfo* databaseInfo = mTransaction->DBInfo();
 
-  IndexInfo* indexInfo = mInfo->indexes.AppendElement();
-  indexInfo->id = databaseInfo->nextIndexId++;
-  indexInfo->name = aName;
-  indexInfo->keyPath = keyPath;
-  indexInfo->keyPathArray.SwapElements(keyPathArray);
-  indexInfo->unique = params.unique;
-  indexInfo->multiEntry = params.multiEntry;
-
-  // Don't leave this in the list if we fail below!
-  AutoRemoveIndex autoRemove(mInfo, aName);
-
-#ifdef DEBUG
-  for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) {
-    if (mCreatedIndexes[index]->Name() == aName) {
-      NS_ERROR("Already created this one!");
-    }
+  IndexInfo info;
+
+  info.name = aName;
+  info.id = databaseInfo->nextIndexId++;
+  info.keyPath = keyPath;
+  info.unique = params.unique;
+  info.multiEntry = params.multiEntry;
+
+  nsRefPtr<IDBIndex> index;
+  rv = CreateIndexInternal(info, keyPathArray, getter_AddRefs(index));
+  if (NS_FAILED(rv)) {
+    return rv;
   }
-#endif
-
-  nsRefPtr<IDBIndex> index(IDBIndex::Create(this, indexInfo));
-
-  if (!mCreatedIndexes.AppendElement(index)) {
-    NS_WARNING("Out of memory!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  nsRefPtr<CreateIndexHelper> helper =
-    new CreateIndexHelper(mTransaction, index);
-
-  nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  autoRemove.forget();
 
   index.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Index(const nsAString& aName,
                       nsIIDBIndex** _retval)
 {
-  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
-
-  if (!mTransaction->IsOpen()) {
-    return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
-  }
-
-  IndexInfo* indexInfo = nsnull;
-  PRUint32 indexCount = mInfo->indexes.Length();
-  for (PRUint32 index = 0; index < indexCount; index++) {
-    if (mInfo->indexes[index].name == aName) {
-      indexInfo = &(mInfo->indexes[index]);
-      break;
-    }
-  }
-
-  if (!indexInfo) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBIndex> index;
+  nsresult rv = IndexInternal(aName, getter_AddRefs(index));
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
-  nsRefPtr<IDBIndex> retval;
-  for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
-    nsRefPtr<IDBIndex>& index = mCreatedIndexes[i];
-    if (index->Name() == aName) {
-      retval = index;
-      break;
-    }
-  }
-
-  if (!retval) {
-    retval = IDBIndex::Create(this, indexInfo);
-    NS_ENSURE_TRUE(retval, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    if (!mCreatedIndexes.AppendElement(retval)) {
-      NS_WARNING("Out of memory!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-  }
-
-  retval.forget(_retval);
+  index.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::DeleteIndex(const nsAString& aName)
 {
-  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
       transaction != mTransaction ||
       mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
@@ -1849,21 +2318,30 @@ IDBObjectStore::DeleteIndex(const nsAStr
       break;
     }
   }
 
   if (index == mInfo->indexes.Length()) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
-  nsRefPtr<DeleteIndexHelper> helper =
-    new DeleteIndexHelper(mTransaction, aName, this);
-
-  nsresult rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsresult rv;
+
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    nsRefPtr<DeleteIndexHelper> helper =
+      new DeleteIndexHelper(mTransaction, this, aName);
+
+    rv = helper->DispatchToTransactionPool();
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    NS_ASSERTION(mActorChild, "Must have an actor here!");
+
+    mActorChild->SendDeleteIndex(nsString(aName));
+  }
 
   mInfo->indexes.RemoveElementAt(index);
 
   for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
     if (mCreatedIndexes[i]->Name() == aName) {
       mCreatedIndexes.RemoveElementAt(i);
       break;
     }
@@ -1885,23 +2363,21 @@ IDBObjectStore::Count(const jsval& aKey,
   nsresult rv;
 
   nsRefPtr<IDBKeyRange> keyRange;
   if (aOptionalArgCount) {
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsRefPtr<IDBRequest> request = GenerateRequest(this);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<CountHelper> helper =
-    new CountHelper(mTransaction, request, this, keyRange);
-  rv = helper->DispatchToTransactionPool();
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  nsRefPtr<IDBRequest> request;
+  rv = CountInternal(keyRange, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   request.forget(_retval);
   return NS_OK;
 }
 
 inline nsresult
 CopyData(nsIInputStream* aStream, quota_FILE* aFile)
 {
@@ -1922,36 +2398,107 @@ CopyData(nsIInputStream* aStream, quota_
 
   // Flush and sync
   NS_ENSURE_TRUE(sqlite3_quota_fflush(aFile, 1) == 0,
                  NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
+void
+ObjectStoreHelper::ReleaseMainThreadObjects()
+{
+  mObjectStore = nsnull;
+  AsyncConnectionHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+ObjectStoreHelper::Dispatch(nsIEventTarget* aDatabaseThread)
+{
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    return AsyncConnectionHelper::Dispatch(aDatabaseThread);
+  }
+
+  IndexedDBObjectStoreChild* objectStoreActor = mObjectStore->GetActorChild();
+  NS_ASSERTION(objectStoreActor, "Must have an actor here!");
+
+  ObjectStoreRequestParams params;
+  nsresult rv = PackArgumentsForParentProcess(params);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NoDispatchEventTarget target;
+  rv = AsyncConnectionHelper::Dispatch(&target);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  mActor =
+    new IndexedDBObjectStoreRequestChild(this, mObjectStore, params.type());
+  objectStoreActor->SendPIndexedDBRequestConstructor(mActor, params);
+
+  return NS_OK;
+}
+
+void
+NoRequestObjectStoreHelper::ReleaseMainThreadObjects()
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  mObjectStore = nsnull;
+  AsyncConnectionHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+NoRequestObjectStoreHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_NOTREACHED("Should never get here!");
+  return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+}
+
+HelperBase::ChildProcessSendResult
+NoRequestObjectStoreHelper::MaybeSendResponseToChildProcess(
+                                                           nsresult aResultCode)
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  return Success_NotSent;
+}
+
+nsresult
+NoRequestObjectStoreHelper::OnSuccess()
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  return NS_OK;
+}
+
+void
+NoRequestObjectStoreHelper::OnError()
+{
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  mTransaction->AbortWithCode(GetResultCode());
+}
+
 nsresult
 AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
-  NS_PRECONDITION(aConnection, "Passed a null connection!");
+  NS_ASSERTION(aConnection, "Passed a null connection!");
 
   nsresult rv;
   bool keyUnset = mKey.IsUnset();
   PRInt64 osid = mObjectStore->Id();
   const nsString& keyPath = mObjectStore->KeyPath();
 
   // 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
   // detectable errors rather than corrupting data
   nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ?
     mTransaction->GetCachedStatement(
       "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
       "VALUES (:osid, :key_value, :data, :file_ids)") :
     mTransaction->GetCachedStatement(
-      "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, file_ids) "
+      "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, "
+                                          "file_ids) "
       "VALUES (:osid, :key_value, :data, :file_ids)");
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -2003,17 +2550,18 @@ AddHelper::DoDatabaseWork(mozIStorageCon
   size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
   // This will hold our compressed data until the end of the method. The
   // BindBlobByName function will copy it.
   nsAutoArrayPtr<char> compressed(new char[compressedLength]);
 
   snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(),
                       &compressedLength);
 
-  const PRUint8* dataBuffer = reinterpret_cast<const PRUint8*>(compressed.get());
+  const PRUint8* dataBuffer =
+    reinterpret_cast<const PRUint8*>(compressed.get());
   size_t dataBufferLength = compressedLength;
 
   rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
                             dataBufferLength);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Handle blobs
   nsRefPtr<FileManager> fileManager = mDatabase->Manager();
@@ -2116,16 +2664,92 @@ AddHelper::GetSuccessResult(JSContext* a
 {
   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
 
   mCloneWriteInfo.mCloneBuffer.clear();
 
   return mKey.ToJSVal(aCx, aVal);
 }
 
+void
+AddHelper::ReleaseMainThreadObjects()
+{
+  IDBObjectStore::ClearStructuredCloneBuffer(mCloneWriteInfo.mCloneBuffer);
+  ObjectStoreHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
+{
+  ipc::AddPutParams commonParams;
+  commonParams.cloneInfo() = mCloneWriteInfo;
+  commonParams.key() = mKey;
+  commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo);
+
+  if (mOverwrite) {
+    ipc::PutParams putParams;
+    putParams.commonParams() = commonParams;
+    aParams = putParams;
+  }
+  else {
+    ipc::AddParams addParams;
+    addParams.commonParams() = commonParams;
+    aParams = addParams;
+  }
+
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+AddHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response =  aResultCode;
+  }
+  else if (mOverwrite) {
+    ipc::PutResponse putResponse;
+    putResponse.key() = mKey;
+    response = putResponse;
+  }
+  else {
+    ipc::AddResponse addResponse;
+    addResponse.key() = mKey;
+    response = addResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+AddHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TAddResponse ||
+               aResponseValue.type() == ResponseValue::TPutResponse,
+               "Bad response type!");
+
+  mKey = mOverwrite ?
+         aResponseValue.get_PutResponse().key() :
+         aResponseValue.get_AddResponse().key();
+
+  return NS_OK;
+}
+
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
   nsCString keyRangeClause;
   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
 
@@ -2135,17 +2759,18 @@ GetHelper::DoDatabaseWork(mozIStorageCon
                                        "WHERE object_store_id = :osid") +
                     keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
+  nsresult rv =
+    stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -2162,17 +2787,93 @@ GetHelper::DoDatabaseWork(mozIStorageCon
 nsresult
 GetHelper::GetSuccessResult(JSContext* aCx,
                             jsval* aVal)
 {
   bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal);
 
   mCloneReadInfo.mCloneBuffer.clear();
 
-  NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(result, NS_ERROR_DOM_DATA_CLONE_ERR);
+  return NS_OK;
+}
+
+void
+GetHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
+  ObjectStoreHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+GetHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
+{
+  NS_ASSERTION(mKeyRange, "This should never be null!");
+
+  ipc::FIXME_Bug_521898_objectstore::GetParams params;
+
+  mKeyRange->ToSerializedKeyRange(params.keyRange());
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
+    NS_WARNING("No support for transferring blobs across processes yet!");
+    return Error;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    SerializedStructuredCloneReadInfo readInfo;
+    readInfo = mCloneReadInfo;
+    ipc::GetResponse getResponse = readInfo;
+    response = getResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
+               "Bad response type!");
+
+  const SerializedStructuredCloneReadInfo& cloneInfo =
+    aResponseValue.get_GetResponse().cloneInfo();
+
+  NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
+               (cloneInfo.dataLength && cloneInfo.data),
+               "Inconsistent clone info!");
+
+  if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
+    NS_WARNING("Failed to copy clone buffer!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
@@ -2207,16 +2908,65 @@ nsresult
 DeleteHelper::GetSuccessResult(JSContext* aCx,
                                jsval* aVal)
 {
   *aVal = JSVAL_VOID;
   return NS_OK;
 }
 
 nsresult
+DeleteHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
+{
+  NS_ASSERTION(mKeyRange, "This should never be null!");
+
+  ipc::DeleteParams params;
+
+  mKeyRange->ToSerializedKeyRange(params.keyRange());
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+DeleteHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    response = ipc::DeleteResponse();
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+DeleteHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TDeleteResponse,
+               "Bad response type!");
+
+  return NS_OK;
+}
+
+nsresult
 ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       NS_LITERAL_CSTRING("DELETE FROM object_data "
                          "WHERE object_store_id = :osid"));
@@ -2230,16 +2980,59 @@ ClearHelper::DoDatabaseWork(mozIStorageC
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
+ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
+{
+  aParams = ipc::ClearParams();
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+ClearHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    response = ipc::ClearResponse();
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+ClearHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TClearResponse,
+               "Bad response type!");
+
+  return NS_OK;
+}
+
+nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
   }
@@ -2349,120 +3142,205 @@ OpenCursorHelper::DoDatabaseWork(mozISto
 
   mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause +
                      NS_LITERAL_CSTRING(" LIMIT ");
 
   return NS_OK;
 }
 
 nsresult
-OpenCursorHelper::GetSuccessResult(JSContext* aCx,
-                                   jsval* aVal)
+OpenCursorHelper::EnsureCursor()
 {
-  if (mKey.IsUnset()) {
-    *aVal = JSVAL_VOID;
+  if (mCursor || mKey.IsUnset()) {
     return NS_OK;
   }
 
+  mSerializedCloneReadInfo = mCloneReadInfo;
+
+  NS_ASSERTION(mSerializedCloneReadInfo.data &&
+               mSerializedCloneReadInfo.dataLength,
+               "Shouldn't be possible!");
+
   nsRefPtr<IDBCursor> cursor =
     IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
                       mRangeKey, mContinueQuery, mContinueToQuery, mKey,
                       mCloneReadInfo);
   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
 
-  return WrapNative(aCx, cursor, aVal);
+  mCursor.swap(cursor);
+  return NS_OK;
 }
 
-class ThreadLocalJSRuntime
+nsresult
+OpenCursorHelper::GetSuccessResult(JSContext* aCx,
+                                   jsval* aVal)
 {
-  JSRuntime* mRuntime;
-  JSContext* mContext;
-  JSObject* mGlobal;
-
-  static JSClass sGlobalClass;
-  static const unsigned sRuntimeHeapSize = 256 * 1024;  // should be enough for anyone
-
-  ThreadLocalJSRuntime()
-  : mRuntime(NULL), mContext(NULL), mGlobal(NULL)
-  {
-      MOZ_COUNT_CTOR(ThreadLocalJSRuntime);
-  }
-
-  nsresult Init()
-  {
-    mRuntime = JS_NewRuntime(sRuntimeHeapSize);
-    NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
-
-    mContext = JS_NewContext(mRuntime, 0);
-    NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
-
-    JSAutoRequest ar(mContext);
-
-    mGlobal = JS_NewCompartmentAndGlobalObject(mContext, &sGlobalClass, NULL);
-    NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
-
-    JS_SetGlobalObject(mContext, mGlobal);
-    return NS_OK;
+  nsresult rv = EnsureCursor();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (mCursor) {
+    rv = WrapNative(aCx, mCursor, aVal);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
-
- public:
-  static ThreadLocalJSRuntime *Create()
-  {
-    ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime();
-    NS_ENSURE_TRUE(entry, nsnull);
-
-    if (NS_FAILED(entry->Init())) {
-      delete entry;
-      return nsnull;
-    }
-
-    return entry;
-  }
-
-  JSContext *Context() const
-  {
-    return mContext;
+  else {
+    *aVal = JSVAL_VOID;
   }
 
-  ~ThreadLocalJSRuntime()
-  {
-    MOZ_COUNT_DTOR(ThreadLocalJSRuntime);
-
-    if (mContext) {
-      JS_DestroyContext(mContext);
-    }
-
-    if (mRuntime) {
-      JS_DestroyRuntime(mRuntime);
-    }
-  }
-};
-
-JSClass ThreadLocalJSRuntime::sGlobalClass = {
-  "IndexedDBTransactionThreadGlobal",
-  JSCLASS_GLOBAL_FLAGS,
-  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
-};
-
-CreateIndexHelper::CreateIndexHelper(IDBTransaction* aTransaction,
-                                     IDBIndex* aIndex)
-  : AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
-{
-  if (sTLSIndex == BAD_TLS_INDEX) {
-    PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry);
-  }
+  return NS_OK;
 }
 
 void
-CreateIndexHelper::DestroyTLSEntry(void* aPtr)
+OpenCursorHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
+
+  mCursor = nsnull;
+
+  // These don't need to be released on the main thread but they're only valid
+  // as long as mCursor is set.
+  mSerializedCloneReadInfo.data = nsnull;
+  mSerializedCloneReadInfo.dataLength = 0;
+
+  ObjectStoreHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+OpenCursorHelper::PackArgumentsForParentProcess(
+                                              ObjectStoreRequestParams& aParams)
+{
+  ipc::FIXME_Bug_521898_objectstore::OpenCursorParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_objectstore::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  params.direction() = mDirection;
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
 {
-  delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
+    NS_WARNING("No support for transferring blobs across processes yet!");
+    return Error;
+  }
+
+  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
+
+  if (NS_SUCCEEDED(aResultCode)) {
+    nsresult rv = EnsureCursor();
+    if (NS_FAILED(rv)) {
+      NS_WARNING("EnsureCursor failed!");
+      aResultCode = rv;
+    }
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::OpenCursorResponse openCursorResponse;
+
+    if (!mCursor) {
+      openCursorResponse = mozilla::void_t();
+    }
+    else {
+      IndexedDBObjectStoreParent* objectStoreActor =
+        mObjectStore->GetActorParent();
+      NS_ASSERTION(objectStoreActor, "Must have an actor here!");
+
+      IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
+      NS_ASSERTION(requestActor, "Must have an actor here!");
+
+      NS_ASSERTION(mSerializedCloneReadInfo.data &&
+                   mSerializedCloneReadInfo.dataLength,
+                   "Shouldn't be possible!");
+
+      ipc::ObjectStoreCursorConstructorParams params;
+      params.requestParent() = requestActor;
+      params.direction() = mDirection;
+      params.key() = mKey;
+      params.cloneInfo() = mSerializedCloneReadInfo;
+
+      IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
+
+      if (!objectStoreActor->SendPIndexedDBCursorConstructor(cursorActor,
+                                                             params)) {
+        return Error;
+      }
+
+      openCursorResponse = cursorActor;
+    }
+
+    response = openCursorResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+OpenCursorHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TOpenCursorResponse,
+               "Bad response type!");
+  NS_ASSERTION(aResponseValue.get_OpenCursorResponse().type() ==
+               ipc::OpenCursorResponse::Tvoid_t ||
+               aResponseValue.get_OpenCursorResponse().type() ==
+               ipc::OpenCursorResponse::TPIndexedDBCursorChild,
+               "Bad response union type!");
+  NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
+
+  const ipc::OpenCursorResponse& response =
+    aResponseValue.get_OpenCursorResponse();
+
+  switch (response.type()) {
+    case ipc::OpenCursorResponse::Tvoid_t:
+      break;
+
+    case ipc::OpenCursorResponse::TPIndexedDBCursorChild: {
+      IndexedDBCursorChild* actor =
+        static_cast<IndexedDBCursorChild*>(
+          response.get_PIndexedDBCursorChild());
+
+      mCursor = actor->ForgetStrongCursor();
+      NS_ASSERTION(mCursor, "This should never be null!");
+
+    } break;
+
+    default:
+      NS_NOTREACHED("Unknown response union type!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
 }
 
 nsresult
 CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   // Insert the data into the database.
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
@@ -2529,32 +3407,40 @@ CreateIndexHelper::DoDatabaseWork(mozISt
   rv = InsertDataFromObjectStore(aConnection);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
+void
+CreateIndexHelper::ReleaseMainThreadObjects()
+{
+  mIndex = nsnull;
+  NoRequestObjectStoreHelper::ReleaseMainThreadObjects();
+}
+
 nsresult
 CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
 {
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
-      NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM object_data "
-                         "WHERE object_store_id = :osid"));
+      NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM "
+                         "object_data WHERE object_store_id = :osid"));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mIndex->ObjectStore()->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX,
+                 NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   if (!hasResult) {
     // Bail early if we have no data to avoid creating the below runtime
     return NS_OK;
   }
@@ -2613,16 +3499,22 @@ CreateIndexHelper::InsertDataFromObjectS
     NS_ENSURE_SUCCESS(rv, rv);
 
   } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
+void
+CreateIndexHelper::DestroyTLSEntry(void* aPtr)
+{
+  delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
+}
+
 nsresult
 DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
       "DELETE FROM object_store_index "
@@ -2739,16 +3631,118 @@ GetAllHelper::GetSuccessResult(JSContext
   for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
     mCloneReadInfos[index].mCloneBuffer.clear();
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
+void
+GetAllHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
+    IDBObjectStore::ClearStructuredCloneBuffer(
+      mCloneReadInfos[index].mCloneBuffer);
+  }
+  ObjectStoreHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+GetAllHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
+{
+  ipc::FIXME_Bug_521898_objectstore::GetAllParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_objectstore::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  params.limit() = mLimit;
+
+  aParams = params;
+  return NS_OK;
+}
+
+HelperBase::ChildProcessSendResult
+GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
+    if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
+      NS_WARNING("No support for transferring blobs across processes yet!");
+      return Error;
+    }
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::GetAllResponse getAllResponse;
+
+    InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
+      getAllResponse.cloneInfos();
+
+    infos.SetCapacity(mCloneReadInfos.Length());
+
+    for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
+      SerializedStructuredCloneReadInfo* info = infos.AppendElement();
+      *info = mCloneReadInfos[index];
+    }
+
+    getAllResponse = infos;
+    response = getAllResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+GetAllHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
+               "Bad response type!");
+
+  const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
+    aResponseValue.get_GetAllResponse().cloneInfos();
+
+  mCloneReadInfos.SetCapacity(cloneInfos.Length());
+
+  for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
+    const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
+
+    StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
+    if (!destInfo->SetFromSerialized(srcInfo)) {
+      NS_WARNING("Failed to copy clone buffer!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+  }
+
+  return NS_OK;
+}
+
 nsresult
 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsCAutoString keyRangeClause;
   if (mKeyRange) {
@@ -2807,10 +3801,78 @@ CountHelper::DoDatabaseWork(mozIStorageC
   mCount = stmt->AsInt64(0);
   return NS_OK;
 }
 
 nsresult
 CountHelper::GetSuccessResult(JSContext* aCx,
                               jsval* aVal)
 {
-  return JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal);
+  if (!JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal)) {
+    NS_WARNING("Failed to make number value!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
+}
+
+void
+CountHelper::ReleaseMainThreadObjects()
+{
+  mKeyRange = nsnull;
+  ObjectStoreHelper::ReleaseMainThreadObjects();
+}
+
+nsresult
+CountHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
+{
+  ipc::FIXME_Bug_521898_objectstore::CountParams params;
+
+  if (mKeyRange) {
+    ipc::FIXME_Bug_521898_objectstore::KeyRange keyRange;
+    mKeyRange->ToSerializedKeyRange(keyRange);
+    params.optionalKeyRange() = keyRange;
+  }
+  else {
+    params.optionalKeyRange() = mozilla::void_t();
+  }
+
+  aParams = params;
+  return NS_OK;
 }
+
+HelperBase::ChildProcessSendResult
+CountHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
+  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
+  if (!actor) {
+    return Success_NotSent;
+  }
+
+  ipc::ResponseValue response;
+  if (NS_FAILED(aResultCode)) {
+    response = aResultCode;
+  }
+  else {
+    ipc::CountResponse countResponse = mCount;
+    response = countResponse;
+  }
+
+  if (!actor->Send__delete__(actor, response)) {
+    return Error;
+  }
+
+  return Success_Sent;
+}
+
+nsresult
+CountHelper::UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+{
+  NS_ASSERTION(aResponseValue.type() == ResponseValue::TCountResponse,
+               "Bad response type!");
+
+  mCount = aResponseValue.get_CountResponse().count();
+  return NS_OK;
+}
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -17,36 +17,41 @@
 #include "mozilla/dom/indexedDB/IDBTransaction.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
+class IDBCursor;
+class IDBKeyRange;
+class IndexedDBObjectStoreChild;
+class IndexedDBObjectStoreParent;
 class Key;
 
-struct ObjectStoreInfo;
 struct IndexInfo;
 struct IndexUpdateInfo;
+struct ObjectStoreInfo;
 struct StructuredCloneReadInfo;
 struct StructuredCloneWriteInfo;
 
 class IDBObjectStore MOZ_FINAL : public nsIIDBObjectStore
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBOBJECTSTORE
 
   NS_DECL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
 
   static already_AddRefed<IDBObjectStore>
   Create(IDBTransaction* aTransaction,
          ObjectStoreInfo* aInfo,
-         nsIAtom* aDatabaseId);
+         nsIAtom* aDatabaseId,
+         bool aCreating);
 
   static bool
   IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath);
 
   static nsresult
   AppendIndexUpdateInfo(PRInt64 aIndexID,
                         const nsAString& aKeyPath,
                         const nsTArray<nsString>& aKeyPathArray,
@@ -146,44 +151,116 @@ public:
     return mTransaction;
   }
 
   ObjectStoreInfo* Info()
   {
     return mInfo;
   }
 
+  void
+  SetActor(IndexedDBObjectStoreChild* aActorChild)
+  {
+    NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
+    mActorChild = aActorChild;
+  }
+
+  void
+  SetActor(IndexedDBObjectStoreParent* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent,
+                 "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
+  IndexedDBObjectStoreChild*
+  GetActorChild() const
+  {
+    return mActorChild;
+  }
+
+  IndexedDBObjectStoreParent*
+  GetActorParent() const
+  {
+    return mActorParent;
+  }
+
+  nsresult
+  CreateIndexInternal(const IndexInfo& aInfo,
+                      nsTArray<nsString>& aKeyPathArray,
+                      IDBIndex** _retval);
+
+  nsresult
+  IndexInternal(const nsAString& aName,
+                IDBIndex** _retval);
+
+  nsresult AddOrPutInternal(
+                      const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
+                      const Key& aKey,
+                      const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
+                      bool aOverwrite,
+                      IDBRequest** _retval);
+
+  nsresult GetInternal(IDBKeyRange* aKeyRange,
+                       IDBRequest** _retval);
+
+  nsresult GetAllInternal(IDBKeyRange* aKeyRange,
+                          PRUint32 aLimit,
+                          IDBRequest** _retval);
+
+  nsresult DeleteInternal(IDBKeyRange* aKeyRange,
+                          IDBRequest** _retval);
+
+  nsresult ClearInternal(IDBRequest** _retval);
+
+  nsresult CountInternal(IDBKeyRange* aKeyRange,
+                         IDBRequest** _retval);
+
+  nsresult OpenCursorInternal(IDBKeyRange* aKeyRange,
+                              size_t aDirection,
+                              IDBRequest** _retval);
+
+  nsresult OpenCursorFromChildProcess(
+                            IDBRequest* aRequest,
+                            size_t aDirection,
+                            const Key& aKey,
+                            const SerializedStructuredCloneReadInfo& aCloneInfo,
+                            IDBCursor** _retval);
+
 protected:
   IDBObjectStore();
   ~IDBObjectStore();
 
   nsresult GetAddInfo(JSContext* aCx,
                       jsval aValue,
                       jsval aKeyVal,
                       StructuredCloneWriteInfo& aCloneWriteInfo,
                       Key& aKey,
                       nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
 
   nsresult AddOrPut(const jsval& aValue,
                     const jsval& aKey,
                     JSContext* aCx,
                     PRUint8 aOptionalArgCount,
-                    nsIIDBRequest** _retval,
-                    bool aOverwrite);
+                    bool aOverwrite,
+                    IDBRequest** _retval);
 
 private:
   nsRefPtr<IDBTransaction> mTransaction;
 
   PRInt64 mId;
   nsString mName;
   nsString mKeyPath;
   nsTArray<nsString> mKeyPathArray;
   bool mAutoIncrement;
   nsCOMPtr<nsIAtom> mDatabaseId;
   nsRefPtr<ObjectStoreInfo> mInfo;
   PRUint32 mStructuredCloneVersion;
 
   nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes;
+
+  IndexedDBObjectStoreChild* mActorChild;
+  IndexedDBObjectStoreParent* mActorParent;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbobjectstore_h__
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -23,16 +23,18 @@
 #include "IDBEvents.h"
 #include "IDBTransaction.h"
 #include "DOMError.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 IDBRequest::IDBRequest()
 : mResultVal(JSVAL_VOID),
+  mActorParent(nsnull),
+  mErrorCode(NS_OK),
   mHaveResultOrErrorCode(false),
   mRooted(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBRequest::~IDBRequest()
 {
@@ -85,40 +87,28 @@ IDBRequest::NotifyHelperCompleted(Helper
   }
 
   mHaveResultOrErrorCode = true;
 
   nsresult rv = aHelper->GetResultCode();
 
   // If the request failed then set the error code and return.
   if (NS_FAILED(rv)) {
-    mError = DOMError::CreateForNSResult(rv);
+    SetError(rv);
     return NS_OK;
   }
 
   // Otherwise we need to get the result from the helper.
-  JSContext* cx;
-  if (GetScriptOwner()) {
-    nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
-    NS_ASSERTION(cxStack, "Failed to get thread context stack!");
-
-    cx = cxStack->GetSafeJSContext();
-    if (!cx) {
-      NS_WARNING("Failed to get safe JSContext!");
-      rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-      mError = DOMError::CreateForNSResult(rv);
-      return rv;
-    }
+  JSContext* cx = GetJSContext();
+  if (!cx) {
+    NS_WARNING("Failed to get safe JSContext!");
+    rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    SetError(rv);
+    return rv;
   }
-  else {
-    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-    NS_ENSURE_STATE(sc);
-    cx = sc->GetNativeContext();
-    NS_ASSERTION(cx, "Failed to get a context!");
-  } 
 
   JSObject* global = GetParentObject();
   NS_ASSERTION(global, "This should never be null!");
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
   if (ac.enter(cx, global)) {
     RootResultVal();
@@ -132,30 +122,94 @@ IDBRequest::NotifyHelperCompleted(Helper
     NS_WARNING("Failed to enter correct compartment!");
     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (NS_SUCCEEDED(rv)) {
     mError = nsnull;
   }
   else {
-    mError = DOMError::CreateForNSResult(rv);
+    SetError(rv);
     mResultVal = JSVAL_VOID;
   }
 
   return rv;
 }
 
 void
-IDBRequest::SetError(nsresult rv)
+IDBRequest::NotifyHelperSentResultsToChildProcess(nsresult aRv)
 {
-  NS_ASSERTION(NS_FAILED(rv), "Er, what?");
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
+  NS_ASSERTION(!PreservingWrapper(), "Already rooted?!");
+  NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
+
+  // See if our window is still valid. If not then we're going to pretend that
+  // we never completed.
+  if (NS_FAILED(CheckInnerWindowCorrectness())) {
+    return;
+  }
+
+  mHaveResultOrErrorCode = true;
+
+  if (NS_FAILED(aRv)) {
+    SetError(aRv);
+  }
+}
+
+void
+IDBRequest::SetError(nsresult aRv)
+{
+  NS_ASSERTION(NS_FAILED(aRv), "Er, what?");
   NS_ASSERTION(!mError, "Already have an error?");
 
-  mError = DOMError::CreateForNSResult(rv);
+  mHaveResultOrErrorCode = true;
+  mError = DOMError::CreateForNSResult(aRv);
+  mErrorCode = aRv;
+
+  mResultVal = JSVAL_VOID;
+  UnrootResultVal();
+}
+
+#ifdef DEBUG
+nsresult
+IDBRequest::GetErrorCode() const
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(mHaveResultOrErrorCode, "Don't call me yet!");
+  return mErrorCode;
+}
+#endif
+
+JSContext*
+IDBRequest::GetJSContext()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  JSContext* cx;
+
+  if (GetScriptOwner()) {
+    nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
+    NS_ASSERTION(cxStack, "Failed to get thread context stack!");
+
+    cx = cxStack->GetSafeJSContext();
+    NS_ENSURE_TRUE(cx, nsnull);
+
+    return cx;
+  }
+
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+  NS_ENSURE_TRUE(sc, nsnull);
+
+  cx = sc->GetNativeContext();
+  NS_ASSERTION(cx, "Failed to get a context!");
+
+  return cx;
 }
 
 void
 IDBRequest::RootResultValInternal()
 {
   NS_HOLD_JS_OBJECTS(this, IDBRequest);
 }
 
@@ -302,16 +356,21 @@ IDBOpenDBRequest::Create(nsPIDOMWindow* 
   }
 
   return request.forget();
 }
 
 void
 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  NS_ASSERTION(!aTransaction || !mTransaction,
+               "Shouldn't have a transaction here!");
+
   mTransaction = aTransaction;
 }
 
 void
 IDBOpenDBRequest::RootResultValInternal()
 {
   NS_HOLD_JS_OBJECTS(this, IDBOpenDBRequest);
 }
@@ -343,8 +402,42 @@ NS_INTERFACE_MAP_END_INHERITING(IDBReque
 
 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
 
 DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest)
 
 NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked);
 NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded);
+
+nsresult
+IDBOpenDBRequest::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
+{
+  NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
+
+  nsPIDOMWindow* owner = GetOwner();
+  if (!owner) {
+    return NS_OK;
+  }
+
+  if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
+    nsString type;
+    nsresult rv = aVisitor.mDOMEvent->GetType(type);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (type.EqualsLiteral(ERROR_EVT_STR)) {
+      nsRefPtr<nsDOMEvent> duplicateEvent =
+        CreateGenericEvent(type, eDoesNotBubble, eNotCancelable);
+      NS_ENSURE_STATE(duplicateEvent);
+
+      nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(owner));
+      NS_ASSERTION(target, "How can this happen?!");
+
+      bool dummy;
+      rv = target->DispatchEvent(duplicateEvent, &dummy);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+    }
+  }
+
+  return NS_OK;
+}
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -16,16 +16,17 @@
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class HelperBase;
 class IDBTransaction;
+class IndexedDBRequestParentBase;
 
 class IDBRequest : public IDBWrapperCache,
                    public nsIIDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBREQUEST
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest,
@@ -42,18 +43,45 @@ public:
   nsISupports* Source()
   {
     return mSource;
   }
 
   void Reset();
 
   nsresult NotifyHelperCompleted(HelperBase* aHelper);
+  void NotifyHelperSentResultsToChildProcess(nsresult aRv);
 
-  void SetError(nsresult rv);
+  void SetError(nsresult aRv);
+
+  nsresult
+  GetErrorCode() const
+#ifdef DEBUG
+  ;
+#else
+  {
+    return mErrorCode;
+  }
+#endif
+
+  JSContext* GetJSContext();
+
+  void
+  SetActor(IndexedDBRequestParentBase* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent,
+                 "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
+  IndexedDBRequestParentBase*
+  GetActorParent() const
+  {
+    return mActorParent;
+  }
 
 protected:
   IDBRequest();
   ~IDBRequest();
 
   virtual void RootResultValInternal();
   virtual void UnrootResultValInternal();
 
@@ -77,16 +105,20 @@ protected:
   nsRefPtr<IDBTransaction> mTransaction;
 
   NS_DECL_EVENT_HANDLER(success)
   NS_DECL_EVENT_HANDLER(error)
 
   jsval mResultVal;
 
   nsCOMPtr<nsIDOMDOMError> mError;
+
+  IndexedDBRequestParentBase* mActorParent;
+
+  nsresult mErrorCode;
   bool mHaveResultOrErrorCode;
   bool mRooted;
 };
 
 class IDBOpenDBRequest : public IDBRequest,
                          public nsIIDBOpenDBRequest
 {
 public:
@@ -105,16 +137,19 @@ public:
   Create(IDBWrapperCache* aOwnerCache)
   {
     return Create(aOwnerCache->GetOwner(),
                   aOwnerCache->GetScriptOwner());
   }
 
   void SetTransaction(IDBTransaction* aTransaction);
 
+  // nsIDOMEventTarget
+  virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
+
 protected:
   ~IDBOpenDBRequest();
 
   virtual void RootResultValInternal();
   virtual void UnrootResultValInternal();
 
   // Only touched on the main thread.
   NS_DECL_EVENT_HANDLER(blocked)
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "IDBTransaction.h"
 
 #include "nsIAppShell.h"
 #include "nsIScriptContext.h"
 
 #include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
@@ -23,16 +25,18 @@
 #include "DatabaseInfo.h"
 #include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBObjectStore.h"
 #include "IndexedDatabaseManager.h"
 #include "TransactionThreadPool.h"
 
+#include "ipc/IndexedDBChild.h"
+
 #define SAVEPOINT_NAME "savepoint"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
@@ -72,68 +76,97 @@ NS_IMETHODIMP_(nsrefcnt) StartTransactio
 }
 
 NS_IMPL_QUERY_INTERFACE1(StartTransactionRunnable, nsIRunnable)
 
 StartTransactionRunnable gStartTransactionRunnable;
 
 } // anonymous namespace
 
+
 // static
 already_AddRefed<IDBTransaction>
-IDBTransaction::Create(IDBDatabase* aDatabase,
-                       nsTArray<nsString>& aObjectStoreNames,
-                       Mode aMode,
-                       bool aDispatchDelayed)
+IDBTransaction::CreateInternal(IDBDatabase* aDatabase,
+                               nsTArray<nsString>& aObjectStoreNames,
+                               Mode aMode,
+                               bool aDispatchDelayed,
+                               bool aIsVersionChangeTransactionChild)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess() || !aDispatchDelayed,
+               "No support for delayed-dispatch transactions in child "
+               "process!");
+  NS_ASSERTION(!aIsVersionChangeTransactionChild ||
+               (!IndexedDatabaseManager::IsMainProcess() &&
+                aMode == IDBTransaction::VERSION_CHANGE),
+               "Busted logic!");
 
   nsRefPtr<IDBTransaction> transaction = new IDBTransaction();
 
   transaction->BindToOwner(aDatabase);
   if (!transaction->SetScriptOwner(aDatabase->GetScriptOwner())) {
     return nsnull;
   }
 
   transaction->mDatabase = aDatabase;
   transaction->mMode = aMode;
-  
   transaction->mDatabaseInfo = aDatabase->Info();
+  transaction->mObjectStoreNames.AppendElements(aObjectStoreNames);
+
+  IndexedDBTransactionChild* actor = nsnull;
+
+  if (IndexedDatabaseManager::IsMainProcess()) {
+    transaction->mCachedStatements.Init();
+
+    if (aMode != IDBTransaction::VERSION_CHANGE) {
+      TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
+      NS_ENSURE_TRUE(pool, nsnull);
 
-  if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) {
-    NS_ERROR("Out of memory!");
-    return nsnull;
+      pool->Dispatch(transaction, &gStartTransactionRunnable, false, nsnull);
+    }
   }
+  else if (!aIsVersionChangeTransactionChild) {
+    IndexedDBDatabaseChild* dbActor = aDatabase->GetActorChild();
+    NS_ASSERTION(dbActor, "Must have an actor here!");
 
-  transaction->mCachedStatements.Init();
+    ipc::NormalTransactionParams params;
+    params.names().AppendElements(aObjectStoreNames);
+    params.mode() = aMode;
+
+    actor = new IndexedDBTransactionChild();
+
+    dbActor->SendPIndexedDBTransactionConstructor(actor, params);
+  }
 
   if (!aDispatchDelayed) {
     nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
     NS_ENSURE_TRUE(appShell, nsnull);
 
     nsresult rv = appShell->RunBeforeNextEvent(transaction);
     NS_ENSURE_SUCCESS(rv, nsnull);
 
     transaction->mCreating = true;
   }
 
-  if (aMode != IDBTransaction::VERSION_CHANGE) {
-    TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
-    pool->Dispatch(transaction, &gStartTransactionRunnable, false, nsnull);
+  if (actor) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    actor->SetTransaction(transaction);
   }
 
   return transaction.forget();
 }
 
 IDBTransaction::IDBTransaction()
 : mReadyState(IDBTransaction::INITIAL),
   mMode(IDBTransaction::READ_ONLY),
   mPendingRequests(0),
   mSavepointCount(0),
-  mAborted(false),
+  mActorChild(nsnull),
+  mActorParent(nsnull),
+  mAbortCode(NS_OK),
   mCreating(false)
 #ifdef DEBUG
   , mFiredCompleteOrAbort(false)
 #endif
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
@@ -141,16 +174,23 @@ IDBTransaction::~IDBTransaction()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mPendingRequests, "Should have no pending requests here!");
   NS_ASSERTION(!mSavepointCount, "Should have released them all!");
   NS_ASSERTION(!mConnection, "Should have called CommitOrRollback!");
   NS_ASSERTION(!mCreating, "Should have been cleared already!");
   NS_ASSERTION(mFiredCompleteOrAbort, "Should have fired event!");
 
+  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->Send__delete__(mActorChild);
+    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
+  }
+
   nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this);
 }
 
 void
 IDBTransaction::OnNewRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   if (!mPendingRequests) {
@@ -163,17 +203,17 @@ IDBTransaction::OnNewRequest()
 
 void
 IDBTransaction::OnRequestFinished()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mPendingRequests, "Mismatched calls!");
   --mPendingRequests;
   if (!mPendingRequests) {
-    NS_ASSERTION(mAborted || mReadyState == IDBTransaction::LOADING,
+    NS_ASSERTION(mAbortCode || mReadyState == IDBTransaction::LOADING,
                  "Bad state!");
     mReadyState = IDBTransaction::COMMITTING;
     CommitOrRollback();
   }
 }
 
 void
 IDBTransaction::RemoveObjectStore(const nsAString& aName)
@@ -199,22 +239,29 @@ IDBTransaction::SetTransactionListener(I
   mListener = aListener;
 }
 
 nsresult
 IDBTransaction::CommitOrRollback()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  if (!IndexedDatabaseManager::IsMainProcess()) {
+    NS_ASSERTION(mActorChild, "Must have an actor!");
+
+    mActorChild->SendAllRequestsFinished();
+    return NS_OK;
+  }
+
+  nsRefPtr<CommitHelper> helper =
+    new CommitHelper(this, mListener, mCreatedObjectStores);
+
   TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
   NS_ENSURE_STATE(pool);
 
-  nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener,
-                                                 mCreatedObjectStores));
-
   mCachedStatements.Enumerate(DoomCachedStatements, helper);
   NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");
 
   nsresult rv = pool->Dispatch(this, helper, true, helper);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
@@ -281,16 +328,17 @@ IDBTransaction::RollbackSavepoint()
 
   nsresult rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv,);
 }
 
 nsresult
 IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
 {
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   if (mDatabase->IsInvalidated()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mConnection) {
     nsCOMPtr<mozIStorageConnection> connection =
@@ -368,18 +416,16 @@ IDBTransaction::GetCachedStatement(const
 
 bool
 IDBTransaction::IsOpen() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   // If we haven't started anything then we're open.
   if (mReadyState == IDBTransaction::INITIAL) {
-    NS_ASSERTION(AsyncConnectionHelper::GetCurrentTransaction() != this,
-                 "This should be some other transaction (or null)!");
     return true;
   }
 
   // If we've already started then we need to check to see if we still have the
   // mCreating flag set. If we do (i.e. we haven't returned to the event loop
   // from the time we were created) then we are open. Otherwise check the
   // currently running transaction to see if it's the same. We only allow other
   // requests to be made if this transaction is currently running.
@@ -393,32 +439,36 @@ IDBTransaction::IsOpen() const
     }
   }
 
   return false;
 }
 
 already_AddRefed<IDBObjectStore>
 IDBTransaction::GetOrCreateObjectStore(const nsAString& aName,
-                                       ObjectStoreInfo* aObjectStoreInfo)
+                                       ObjectStoreInfo* aObjectStoreInfo,
+                                       bool aCreating)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aObjectStoreInfo, "Null pointer!");
+  NS_ASSERTION(!aCreating || GetMode() == IDBTransaction::VERSION_CHANGE,
+               "How else can we create here?!");
 
   nsRefPtr<IDBObjectStore> retval;
 
   for (PRUint32 index = 0; index < mCreatedObjectStores.Length(); index++) {
     nsRefPtr<IDBObjectStore>& objectStore = mCreatedObjectStores[index];
     if (objectStore->Name() == aName) {
       retval = objectStore;
       return retval.forget();
     }
   }
 
-  retval = IDBObjectStore::Create(this, aObjectStoreInfo, mDatabaseInfo->id);
+  retval = IDBObjectStore::Create(this, aObjectStoreInfo, mDatabaseInfo->id,
+                                  aCreating);
 
   mCreatedObjectStores.AppendElement(retval);
 
   return retval.forget();
 }
 
 void
 IDBTransaction::OnNewFileInfo(FileInfo* aFileInfo)
@@ -427,16 +477,52 @@ IDBTransaction::OnNewFileInfo(FileInfo* 
 }
 
 void
 IDBTransaction::ClearCreatedFileInfos()
 {
   mCreatedFileInfos.Clear();
 }
 
+nsresult
+IDBTransaction::AbortWithCode(nsresult aAbortCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  // We can't use IsOpen here since we need it to be possible to call Abort()
+  // even from outside of transaction callbacks.
+  if (mReadyState != IDBTransaction::INITIAL &&
+      mReadyState != IDBTransaction::LOADING) {
+    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+  }
+
+  if (mActorChild) {
+    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mActorChild->SendAbort(aAbortCode);
+  }
+
+  bool needToCommitOrRollback = mReadyState == IDBTransaction::INITIAL;
+
+  mAbortCode = aAbortCode;
+  mReadyState = IDBTransaction::DONE;
+
+  if (Mode() == IDBTransaction::VERSION_CHANGE) {
+    // If a version change transaction is aborted, the db must be closed
+    mDatabase->Close();
+  }
+
+  // Fire the abort event if there are no outstanding requests. Otherwise the
+  // abort event will be fired when all outstanding requests finish.
+  if (needToCommitOrRollback) {
+    return CommitOrRollback();
+  }
+
+  return NS_OK;
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBTransaction)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBTransaction,
                                                   IDBWrapperCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mDatabase,
                                                        nsIDOMEventTarget)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(complete)
@@ -492,16 +578,22 @@ IDBTransaction::GetMode(nsAString& aMode
     case READ_ONLY:
       aMode.AssignLiteral("readonly");
       break;
     case READ_WRITE:
       aMode.AssignLiteral("readwrite");
       break;
     case VERSION_CHANGE:
       aMode.AssignLiteral("versionchange");
+      break;
+
+    case MODE_INVALID:
+    default:
+      NS_NOTREACHED("Bad mode value!");
+      return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBTransaction::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores)
 {
@@ -532,67 +624,61 @@ IDBTransaction::GetObjectStoreNames(nsID
 }
 
 NS_IMETHODIMP
 IDBTransaction::ObjectStore(const nsAString& aName,
                             nsIIDBObjectStore** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  nsRefPtr<IDBObjectStore> objectStore;
+  nsresult rv = ObjectStoreInternal(aName, getter_AddRefs(objectStore));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  objectStore.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+IDBTransaction::ObjectStoreInternal(const nsAString& aName,
+                                    IDBObjectStore** _retval)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   if (!IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   ObjectStoreInfo* info = nsnull;
 
   if (mMode == IDBTransaction::VERSION_CHANGE ||
       mObjectStoreNames.Contains(aName)) {
     info = mDatabaseInfo->GetObjectStore(aName);
   }
 
   if (!info) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
-  nsRefPtr<IDBObjectStore> objectStore = GetOrCreateObjectStore(aName, info);
+  nsRefPtr<IDBObjectStore> objectStore =
+    GetOrCreateObjectStore(aName, info, false);
   NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   objectStore.forget(_retval);
   return NS_OK;
 }
 
+
 NS_IMETHODIMP
 IDBTransaction::Abort()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  // We can't use IsOpen here since we need it to be possible to call Abort()
-  // even from outside of transaction callbacks.
-  if (mReadyState != IDBTransaction::INITIAL &&
-      mReadyState != IDBTransaction::LOADING) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
-  }
-
-  bool needToCommitOrRollback = mReadyState == IDBTransaction::INITIAL;
-
-  mAborted = true;
-  mReadyState = IDBTransaction::DONE;
-
-  if (Mode() == IDBTransaction::VERSION_CHANGE) {
-    // If a version change transaction is aborted, the db must be closed
-    mDatabase->Close();
-  }
-
-  // Fire the abort event if there are no outstanding requests. Otherwise the
-  // abort event will be fired when all outstanding requests finish.
-  if (needToCommitOrRollback) {
-    return CommitOrRollback();
-  }
-
-  return NS_OK;
+  return AbortWithCode(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
 }
 
 nsresult
 IDBTransaction::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   aVisitor.mParentTarget = mDatabase;
   return NS_OK;
@@ -619,29 +705,39 @@ IDBTransaction::Run()
 }
 
 CommitHelper::CommitHelper(
               IDBTransaction* aTransaction,
               IDBTransactionListener* aListener,
               const nsTArray<nsRefPtr<IDBObjectStore> >& aUpdatedObjectStores)
 : mTransaction(aTransaction),
   mListener(aListener),
-  mAborted(!!aTransaction->mAborted)
+  mAbortCode(aTransaction->mAbortCode)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   mConnection.swap(aTransaction->mConnection);
   mUpdateFileRefcountFunction.swap(aTransaction->mUpdateFileRefcountFunction);
 
   for (PRUint32 i = 0; i < aUpdatedObjectStores.Length(); i++) {
     ObjectStoreInfo* info = aUpdatedObjectStores[i]->Info();
     if (info->comittedAutoIncrementId != info->nextAutoIncrementId) {
       mAutoIncrementObjectStores.AppendElement(aUpdatedObjectStores[i]);
     }
   }
 }
 
+CommitHelper::CommitHelper(IDBTransaction* aTransaction,
+                           nsresult aAbortCode)
+: mTransaction(aTransaction),
+  mAbortCode(aAbortCode)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+}
+
 CommitHelper::~CommitHelper()
 {
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(CommitHelper, nsIRunnable)
 
 NS_IMETHODIMP
 CommitHelper::Run()
@@ -655,17 +751,17 @@ CommitHelper::Run()
     // destroyed on correct thread.
     mTransaction->ClearCreatedFileInfos();
     if (mUpdateFileRefcountFunction) {
       mUpdateFileRefcountFunction->ClearFileInfoEntries();
       mUpdateFileRefcountFunction = nsnull;
     }
 
     nsCOMPtr<nsIDOMEvent> event;
-    if (mAborted) {
+    if (mAbortCode) {
       if (mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE) {
         // This will make the database take a snapshot of it's DatabaseInfo
         mTransaction->Database()->Close();
         // Then remove the info from the hash as it contains invalid data.
         DatabaseInfo::Remove(mTransaction->Database()->Id());
       }
 
       event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR),
@@ -693,45 +789,45 @@ CommitHelper::Run()
 
     mTransaction = nsnull;
 
     return NS_OK;
   }
 
   IDBDatabase* database = mTransaction->Database();
   if (database->IsInvalidated()) {
-    mAborted = true;
+    mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (mConnection) {
     IndexedDatabaseManager::SetCurrentWindow(database->GetOwner());
 
-    if (!mAborted && mUpdateFileRefcountFunction &&
+    if (!mAbortCode && mUpdateFileRefcountFunction &&
         NS_FAILED(mUpdateFileRefcountFunction->UpdateDatabase(mConnection))) {
-      mAborted = true;
+      mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
-    if (!mAborted && NS_FAILED(WriteAutoIncrementCounts())) {
-      mAborted = true;
+    if (!mAbortCode && NS_FAILED(WriteAutoIncrementCounts())) {
+      mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
-    if (!mAborted) {
+    if (!mAbortCode) {
       NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
       if (NS_SUCCEEDED(mConnection->ExecuteSimpleSQL(release))) {
         if (mUpdateFileRefcountFunction) {
           mUpdateFileRefcountFunction->UpdateFileInfos();
         }
         CommitAutoIncrementCounts();
       }
       else {
-        mAborted = true;
+        mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
-    if (mAborted) {
+    if (mAbortCode) {
       RevertAutoIncrementCounts();
       NS_NAMED_LITERAL_CSTRING(rollback, "ROLLBACK TRANSACTION");
       if (NS_FAILED(mConnection->ExecuteSimpleSQL(rollback))) {
         NS_WARNING("Failed to rollback transaction!");
       }
     }
   }
 
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -25,16 +25,19 @@
 #include "mozilla/dom/indexedDB/FileInfo.h"
 
 class nsIThread;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 class CommitHelper;
+class IndexedDBDatabaseChild;
+class IndexedDBTransactionChild;
+class IndexedDBTransactionParent;
 struct ObjectStoreInfo;
 class TransactionThreadPool;
 class UpdateRefcountFunction;
 
 class IDBTransactionListener
 {
 public:
   NS_IMETHOD_(nsrefcnt) AddRef() = 0;
@@ -44,46 +47,54 @@ public:
 };
 
 class IDBTransaction : public IDBWrapperCache,
                        public nsIIDBTransaction,
                        public nsIRunnable
 {
   friend class AsyncConnectionHelper;
   friend class CommitHelper;
+  friend class IndexedDBDatabaseChild;
   friend class ThreadObserver;
   friend class TransactionThreadPool;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBTRANSACTION
   NS_DECL_NSIRUNNABLE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, IDBWrapperCache)
 
   enum Mode
   {
     READ_ONLY = 0,
     READ_WRITE,
-    VERSION_CHANGE
+    VERSION_CHANGE,
+
+    // Only needed for IPC serialization helper, should never be used in code.
+    MODE_INVALID
   };
 
   enum ReadyState
   {
     INITIAL = 0,
     LOADING,
     COMMITTING,
     DONE
   };
 
   static already_AddRefed<IDBTransaction>
   Create(IDBDatabase* aDatabase,
          nsTArray<nsString>& aObjectStoreNames,
          Mode aMode,
-         bool aDispatchDelayed);
+         bool aDispatchDelayed)
+  {
+    return CreateInternal(aDatabase, aObjectStoreNames, aMode, aDispatchDelayed,
+                          false);
+  }
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   void OnNewRequest();
   void OnRequestFinished();
 
   void RemoveObjectStore(const nsAString& aName);
@@ -111,17 +122,17 @@ public:
 
   bool IsWriteAllowed() const
   {
     return mMode == READ_WRITE || mMode == VERSION_CHANGE;
   }
 
   bool IsAborted() const
   {
-    return mAborted;
+    return NS_FAILED(mAbortCode);
   }
 
   // 'Get' prefix is to avoid name collisions with the enum
   Mode GetMode()
   {
     return mMode;
   }
 
@@ -133,23 +144,66 @@ public:
 
   DatabaseInfo* DBInfo() const
   {
     return mDatabaseInfo;
   }
 
   already_AddRefed<IDBObjectStore>
   GetOrCreateObjectStore(const nsAString& aName,
-                         ObjectStoreInfo* aObjectStoreInfo);
+                         ObjectStoreInfo* aObjectStoreInfo,
+                         bool aCreating);
 
   void OnNewFileInfo(FileInfo* aFileInfo);
 
   void ClearCreatedFileInfos();
 
+  void
+  SetActor(IndexedDBTransactionChild* aActorChild)
+  {
+    NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
+    mActorChild = aActorChild;
+  }
+
+  void
+  SetActor(IndexedDBTransactionParent* aActorParent)
+  {
+    NS_ASSERTION(!aActorParent || !mActorParent,
+                 "Shouldn't have more than one!");
+    mActorParent = aActorParent;
+  }
+
+  IndexedDBTransactionChild*
+  GetActorChild() const
+  {
+    return mActorChild;
+  }
+
+  nsresult
+  ObjectStoreInternal(const nsAString& aName,
+                      IDBObjectStore** _retval);
+
+  nsresult
+  AbortWithCode(nsresult aAbortCode);
+
+  nsresult
+  GetAbortCode() const
+  {
+    return mAbortCode;
+  }
+
 private:
+  // Should only be called directly through IndexedDBDatabaseChild.
+  static already_AddRefed<IDBTransaction>
+  CreateInternal(IDBDatabase* aDatabase,
+                 nsTArray<nsString>& aObjectStoreNames,
+                 Mode aMode,
+                 bool aDispatchDelayed,
+                 bool aIsVersionChangeTransactionChild);
+
   IDBTransaction();
   ~IDBTransaction();
 
   nsresult CommitOrRollback();
 
   nsRefPtr<IDBDatabase> mDatabase;
   nsRefPtr<DatabaseInfo> mDatabaseInfo;
   nsTArray<nsString> mObjectStoreNames;
@@ -170,36 +224,41 @@ private:
   // Only touched on the database thread.
   nsCOMPtr<mozIStorageConnection> mConnection;
 
   // Only touched on the database thread.
   PRUint32 mSavepointCount;
 
   nsTArray<nsRefPtr<IDBObjectStore> > mCreatedObjectStores;
 
-  bool mAborted;
+  nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
+  nsTArray<nsRefPtr<FileInfo> > mCreatedFileInfos;
+
+  IndexedDBTransactionChild* mActorChild;
+  IndexedDBTransactionParent* mActorParent;
+
+  nsresult mAbortCode;
   bool mCreating;
 
 #ifdef DEBUG
   bool mFiredCompleteOrAbort;
 #endif
-
-  nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
-  nsTArray<nsRefPtr<FileInfo> > mCreatedFileInfos;
 };
 
 class CommitHelper MOZ_FINAL : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
   CommitHelper(IDBTransaction* aTransaction,
                IDBTransactionListener* aListener,
                const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores);
+  CommitHelper(IDBTransaction* aTransaction,
+               nsresult aAbortCode);
   ~CommitHelper();
 
   template<class T>
   bool AddDoomedObject(nsCOMPtr<T>& aCOMPtr)
   {
     if (aCOMPtr) {
       if (!mDoomedObjects.AppendElement(do_QueryInterface(aCOMPtr))) {
         NS_ERROR("Out of memory!");
@@ -222,17 +281,17 @@ private:
 
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBTransactionListener> mListener;
   nsCOMPtr<mozIStorageConnection> mConnection;
   nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
   nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
   nsAutoTArray<nsRefPtr<IDBObjectStore>, 10> mAutoIncrementObjectStores;
 
-  bool mAborted;
+  nsresult mAbortCode;
 };
 
 class UpdateRefcountFunction MOZ_FINAL : public mozIStorageFunction
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGEFUNCTION
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -4,16 +4,17 @@
  * 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_indexeddatabase_h__
 #define mozilla_dom_indexeddb_indexeddatabase_h__
 
 #include "nsIProgrammingLanguage.h"
 
+#include "mozilla/Attributes.h"
 #include "jsapi.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDOMError.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
@@ -27,58 +28,112 @@
   using namespace mozilla::dom::indexedDB;
 
 class nsIDOMBlob;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class FileInfo;
 
-struct StructuredCloneReadInfo {
-  void Swap(StructuredCloneReadInfo& aCloneReadInfo) {
+struct SerializedStructuredCloneReadInfo;
+
+struct StructuredCloneReadInfo
+{
+  void Swap(StructuredCloneReadInfo& aCloneReadInfo)
+  {
     mCloneBuffer.swap(aCloneReadInfo.mCloneBuffer);
     mFileInfos.SwapElements(aCloneReadInfo.mFileInfos);
   }
 
+  // In IndexedDatabaseInlines.h
+  inline bool
+  SetFromSerialized(const SerializedStructuredCloneReadInfo& aOther);
+
   JSAutoStructuredCloneBuffer mCloneBuffer;
   nsTArray<nsRefPtr<FileInfo> > mFileInfos;
 };
 
-struct StructuredCloneWriteInfo {
-  void Swap(StructuredCloneWriteInfo& aCloneWriteInfo) {
+struct SerializedStructuredCloneReadInfo
+{
+  SerializedStructuredCloneReadInfo()
+  : data(nsnull), dataLength(0)
+  { }
+
+  bool
+  operator==(const SerializedStructuredCloneReadInfo& aOther) const
+  {
+    return this->data == aOther.data &&
+           this->dataLength == aOther.dataLength;
+  }
+
+  SerializedStructuredCloneReadInfo&
+  operator=(const StructuredCloneReadInfo& aOther)
+  {
+    data = aOther.mCloneBuffer.data();
+    dataLength = aOther.mCloneBuffer.nbytes();
+    return *this;
+  }
+
+  // Make sure to update ipc/SerializationHelpers.h when changing members here!
+  uint64_t* data;
+  size_t dataLength;
+};
+
+struct SerializedStructuredCloneWriteInfo;
+
+struct StructuredCloneWriteInfo
+{
+  void Swap(StructuredCloneWriteInfo& aCloneWriteInfo)
+  {
     mCloneBuffer.swap(aCloneWriteInfo.mCloneBuffer);
     mBlobs.SwapElements(aCloneWriteInfo.mBlobs);
     mOffsetToKeyProp = aCloneWriteInfo.mOffsetToKeyProp;
   }
 
+  bool operator==(const StructuredCloneWriteInfo& aOther) const
+  {
+    return this->mCloneBuffer.nbytes() == aOther.mCloneBuffer.nbytes() &&
+           this->mCloneBuffer.data() == aOther.mCloneBuffer.data() &&
+           this->mBlobs == aOther.mBlobs &&
+           this->mOffsetToKeyProp == aOther.mOffsetToKeyProp;
+  }
+
+  // In IndexedDatabaseInlines.h
+  inline bool
+  SetFromSerialized(const SerializedStructuredCloneWriteInfo& aOther);
+
   JSAutoStructuredCloneBuffer mCloneBuffer;
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
   PRUint64 mOffsetToKeyProp;
 };
 
-inline
-void
-AppendConditionClause(const nsACString& aColumnName,
-                      const nsACString& aArgName,
-                      bool aLessThan,
-                      bool aEquals,
-                      nsACString& aResult)
+struct SerializedStructuredCloneWriteInfo
 {
-  aResult += NS_LITERAL_CSTRING(" AND ") + aColumnName +
-             NS_LITERAL_CSTRING(" ");
+  SerializedStructuredCloneWriteInfo()
+  : data(nsnull), dataLength(0), offsetToKeyProp(0)
+  { }
 
-  if (aLessThan) {
-    aResult.AppendLiteral("<");
-  }
-  else {
-    aResult.AppendLiteral(">");
+  bool
+  operator==(const SerializedStructuredCloneWriteInfo& aOther) const
+  {
+    return this->data == aOther.data &&
+           this->dataLength == aOther.dataLength &&
+           this->offsetToKeyProp == aOther.offsetToKeyProp;
   }
 
-  if (aEquals) {
-    aResult.AppendLiteral("=");
+  SerializedStructuredCloneWriteInfo&
+  operator=(const StructuredCloneWriteInfo& aOther)
+  {
+    data = aOther.mCloneBuffer.data();
+    dataLength = aOther.mCloneBuffer.nbytes();
+    offsetToKeyProp = aOther.mOffsetToKeyProp;
+    return *this;
   }
 
-  aResult += NS_LITERAL_CSTRING(" :") + aArgName;
-}
+  // Make sure to update ipc/SerializationHelpers.h when changing members here!
+  uint64_t* data;
+  size_t dataLength;
+  uint64_t offsetToKeyProp;
+};
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_indexeddatabase_h__
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -0,0 +1,69 @@
+/* -*- 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_indexeddatabase_h__
+#error Must include IndexedDatabase.h first
+#endif
+
+BEGIN_INDEXEDDB_NAMESPACE
+
+inline
+bool
+StructuredCloneWriteInfo::SetFromSerialized(
+                               const SerializedStructuredCloneWriteInfo& aOther)
+{
+  if (!aOther.dataLength) {
+    mCloneBuffer.clear();
+  }
+  else if (!mCloneBuffer.copy(aOther.data, aOther.dataLength)) {
+    return false;
+  }
+
+  mBlobs.Clear();
+  mOffsetToKeyProp = aOther.offsetToKeyProp;
+  return true;
+}
+
+inline
+bool
+StructuredCloneReadInfo::SetFromSerialized(
+                                const SerializedStructuredCloneReadInfo& aOther)
+{
+  if (aOther.dataLength &&
+      !mCloneBuffer.copy(aOther.data, aOther.dataLength)) {
+    return false;
+  }
+
+  mFileInfos.Clear();
+  return true;
+}
+
+inline
+void
+AppendConditionClause(const nsACString& aColumnName,
+                      const nsACString& aArgName,
+                      bool aLessThan,
+                      bool aEquals,
+                      nsACString& aResult)
+{
+  aResult += NS_LITERAL_CSTRING(" AND ") + aColumnName +
+             NS_LITERAL_CSTRING(" ");
+
+  if (aLessThan) {
+    aResult.AppendLiteral("<");
+  }
+  else {
+    aResult.AppendLiteral(">");
+  }
+
+  if (aEquals) {
+    aResult.AppendLiteral("=");
+  }
+
+  aResult += NS_LITERAL_CSTRING(" :") + aArgName;
+}
+
+END_INDEXEDDB_NAMESPACE
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -1,16 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "base/basictypes.h"
-
 #include "IndexedDatabaseManager.h"
 #include "DatabaseInfo.h"
 
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsIFile.h"
 #include "nsILocalFile.h"
 #include "nsIObserverService.h"
 #include "nsIScriptObjectPrincipal.h"
@@ -18,17 +16,16 @@
 #include "nsISHEntry.h"
 #include "nsISimpleEnumerator.h"
 #include "nsITimer.h"
 
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/storage.h"
-#include "mozilla/dom/ContentChild.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsContentUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "test_quota.h"
 #include "xpcpublic.h"
@@ -163,40 +160,37 @@ IndexedDatabaseManager::IndexedDatabaseM
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!gInstance, "More than one instance!");
 }
 
 IndexedDatabaseManager::~IndexedDatabaseManager()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(gInstance == this, "Different instances!");
+  NS_ASSERTION(!gInstance || gInstance == this, "Different instances!");
   gInstance = nsnull;
 }
 
+bool IndexedDatabaseManager::sIsMainProcess = false;
+
 // static
 already_AddRefed<IndexedDatabaseManager>
 IndexedDatabaseManager::GetOrCreate()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (IsShuttingDown()) {
     NS_ERROR("Calling GetOrCreateInstance() after shutdown!");
     return nsnull;
   }
 
   nsRefPtr<IndexedDatabaseManager> instance(gInstance);
 
   if (!instance) {
-    if (NS_FAILED(Preferences::AddIntVarCache(&gIndexedDBQuotaMB,
-                                              PREF_INDEXEDDB_QUOTA,
-                                              DEFAULT_QUOTA_MB))) {
-      NS_WARNING("Unable to respond to quota pref changes!");
-      gIndexedDBQuotaMB = DEFAULT_QUOTA_MB;
-    }
+    sIsMainProcess = XRE_GetProcessType() == GeckoProcessType_Default;
 
     instance = new IndexedDatabaseManager();
 
     instance->mLiveDatabases.Init();
     instance->mQuotaHelperHash.Init();
     instance->mFileManagers.Init();
 
     // We need a thread-local to hold the current window.
@@ -204,47 +198,57 @@ IndexedDatabaseManager::GetOrCreate()
 
     if (PR_NewThreadPrivateIndex(&instance->mCurrentWindowIndex, nsnull) !=
         PR_SUCCESS) {
       NS_ERROR("PR_NewThreadPrivateIndex failed, IndexedDB disabled");
       instance->mCurrentWindowIndex = BAD_TLS_INDEX;
       return nsnull;
     }
 
-    nsCOMPtr<nsIFile> dbBaseDirectory;
-    nsresult rv =
-      NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                             getter_AddRefs(dbBaseDirectory));
-    NS_ENSURE_SUCCESS(rv, nsnull);
+    nsresult rv;
+
+    if (sIsMainProcess) {
+      nsCOMPtr<nsIFile> dbBaseDirectory;
+      rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                  getter_AddRefs(dbBaseDirectory));
+      NS_ENSURE_SUCCESS(rv, nsnull);
+
+      rv = dbBaseDirectory->Append(NS_LITERAL_STRING("indexedDB"));
+      NS_ENSURE_SUCCESS(rv, nsnull);
+
+      rv = dbBaseDirectory->GetPath(instance->mDatabaseBasePath);
+      NS_ENSURE_SUCCESS(rv, nsnull);
 
-    rv = dbBaseDirectory->Append(NS_LITERAL_STRING("indexedDB"));
-    NS_ENSURE_SUCCESS(rv, nsnull);
+      // Make a lazy thread for any IO we need (like clearing or enumerating the
+      // contents of indexedDB database directories).
+      instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
+                                                LazyIdleThread::ManualShutdown);
 
-    rv = dbBaseDirectory->GetPath(instance->mDatabaseBasePath);
-    NS_ENSURE_SUCCESS(rv, nsnull);
+      // We need one quota callback object to hand to SQLite.
+      instance->mQuotaCallbackSingleton = new QuotaCallback();
 
-    // Make a timer here to avoid potential failures later. We don't actually
-    // initialize the timer until shutdown.
-    instance->mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-    NS_ENSURE_TRUE(instance->mShutdownTimer, nsnull);
+      // Make a timer here to avoid potential failures later. We don't actually
+      // initialize the timer until shutdown.
+      instance->mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+      NS_ENSURE_TRUE(instance->mShutdownTimer, nsnull);
+    }
 
     nsCOMPtr<nsIObserverService> obs = GetObserverService();
     NS_ENSURE_TRUE(obs, nsnull);
 
     // We need this callback to know when to shut down all our threads.
     rv = obs->AddObserver(instance, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     NS_ENSURE_SUCCESS(rv, nsnull);
 
-    // Make a lazy thread for any IO we need (like clearing or enumerating the
-    // contents of indexedDB database directories).
-    instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
-                                             LazyIdleThread::ManualShutdown);
-
-    // We need one quota callback object to hand to SQLite.
-    instance->mQuotaCallbackSingleton = new QuotaCallback();
+    if (NS_FAILED(Preferences::AddIntVarCache(&gIndexedDBQuotaMB,
+                                              PREF_INDEXEDDB_QUOTA,
+                                              DEFAULT_QUOTA_MB))) {
+      NS_WARNING("Unable to respond to quota pref changes!");
+      gIndexedDBQuotaMB = DEFAULT_QUOTA_MB;
+    }
 
     // The observer service will hold our last reference, don't AddRef here.
     gInstance = instance;
   }
 
   return instance.forget();
 }
 
@@ -269,33 +273,44 @@ nsresult
 IndexedDatabaseManager::GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
                                               nsIFile** aDirectory) const
 {
   nsresult rv;
   nsCOMPtr<nsILocalFile> directory =
     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  const nsString& path = XRE_GetProcessType() == GeckoProcessType_Default ?
-                         GetBaseDirectory() :
-                         ContentChild::GetSingleton()->GetIndexedDBPath();
-
-  rv = directory->InitWithPath(path);
+  rv = directory->InitWithPath(GetBaseDirectory());
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
   originSanitized.ReplaceChar(":/", '+');
 
   rv = directory->Append(originSanitized);
   NS_ENSURE_SUCCESS(rv, rv);
 
   directory.forget(reinterpret_cast<nsILocalFile**>(aDirectory));
   return NS_OK;
 }
 
+// static
+already_AddRefed<nsIAtom>
+IndexedDatabaseManager::GetDatabaseId(const nsACString& aOrigin,
+                                      const nsAString& aName)
+{
+  nsCString str(aOrigin);
+  str.Append("*");
+  str.Append(NS_ConvertUTF16toUTF8(aName));
+
+  nsCOMPtr<nsIAtom> atom = do_GetAtom(str);
+  NS_ENSURE_TRUE(atom, nsnull);
+
+  return atom.forget();
+}
+
 bool
 IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aDatabase, "Null pointer!");
 
   // Don't allow any new databases to be created after shutdown.
   if (IsShuttingDown()) {
@@ -687,17 +702,17 @@ IndexedDatabaseManager::EnsureOriginIsIn
   nsAutoTArray<nsString, 20> subdirsToProcess;
   nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
 
   nsAutoPtr<nsTArray<nsRefPtr<FileManager> > > fileManagers(
     new nsTArray<nsRefPtr<FileManager> >());
 
   nsTHashtable<nsStringHashKey> validSubdirs;
   validSubdirs.Init(20);
-  
+
   nsCOMPtr<nsISimpleEnumerator> entries;
   rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore;
   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
     nsCOMPtr<nsISupports> entry;
     rv = entries->GetNext(getter_AddRefs(entry));
@@ -705,16 +720,20 @@ IndexedDatabaseManager::EnsureOriginIsIn
 
     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
     NS_ENSURE_TRUE(file, NS_NOINTERFACE);
 
     nsString leafName;
     rv = file->GetLeafName(leafName);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
+      continue;
+    }
+
     bool isDirectory;
     rv = file->IsDirectory(&isDirectory);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (isDirectory) {
       if (!validSubdirs.GetEntry(leafName)) {
         subdirsToProcess.AppendElement(leafName);
       }
@@ -879,17 +898,17 @@ nsresult
 IndexedDatabaseManager::GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow,
                                                  nsCString& aASCIIOrigin)
 {
   NS_ASSERTION(NS_IsMainThread(),
                "We're about to touch a window off the main thread!");
 
   if (!aWindow) {
     aASCIIOrigin.AssignLiteral("chrome");
-    NS_ASSERTION(nsContentUtils::IsCallerChrome(), 
+    NS_ASSERTION(nsContentUtils::IsCallerChrome(),
                  "Null window but not chrome!");
     return NS_OK;
   }
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
   NS_ENSURE_TRUE(sop, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
@@ -906,16 +925,29 @@ IndexedDatabaseManager::GetASCIIOriginFr
       NS_WARNING("IndexedDB databases not allowed for this principal!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
 
   return NS_OK;
 }
 
+#ifdef DEBUG
+//static
+bool
+IndexedDatabaseManager::IsMainProcess()
+{
+  NS_ASSERTION(gInstance,
+               "IsMainProcess() called before indexedDB has been initialized!");
+  NS_ASSERTION((XRE_GetProcessType() == GeckoProcessType_Default) ==
+               sIsMainProcess, "XRE_GetProcessType changed its tune!");
+  return sIsMainProcess;
+}
+#endif
+
 already_AddRefed<FileManager>
 IndexedDatabaseManager::GetOrCreateFileManager(const nsACString& aOrigin,
                                                const nsAString& aDatabaseName)
 {
   nsTArray<nsRefPtr<FileManager> >* array;
   if (!mFileManagers.Get(aOrigin, &array)) {
     nsAutoPtr<nsTArray<nsRefPtr<FileManager> > > newArray(
       new nsTArray<nsRefPtr<FileManager> >());
@@ -1211,46 +1243,50 @@ IndexedDatabaseManager::Observe(nsISuppo
 
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     // Setting this flag prevents the service from being recreated and prevents
     // further databases from being created.
     if (PR_ATOMIC_SET(&gShutdown, 1)) {
       NS_ERROR("Shutdown more than once?!");
     }
 
-    // Make sure to join with our IO thread.
-    if (NS_FAILED(mIOThread->Shutdown())) {
-      NS_WARNING("Failed to shutdown IO thread!");
-    }
+    if (sIsMainProcess) {
+      // Make sure to join with our IO thread.
+      if (NS_FAILED(mIOThread->Shutdown())) {
+        NS_WARNING("Failed to shutdown IO thread!");
+      }
 
-    // Kick off the shutdown timer.
-    if (NS_FAILED(mShutdownTimer->Init(this, DEFAULT_SHUTDOWN_TIMER_MS,
-                                       nsITimer::TYPE_ONE_SHOT))) {
-      NS_WARNING("Failed to initialize shutdown timer!");
-    }
+      // Kick off the shutdown timer.
+      if (NS_FAILED(mShutdownTimer->Init(this, DEFAULT_SHUTDOWN_TIMER_MS,
+                                         nsITimer::TYPE_ONE_SHOT))) {
+        NS_WARNING("Failed to initialize shutdown timer!");
+      }
 
-    // This will spin the event loop while we wait on all the database threads
-    // to close. Our timer may fire during that loop.
-    TransactionThreadPool::Shutdown();
+      // This will spin the event loop while we wait on all the database threads
+      // to close. Our timer may fire during that loop.
+      TransactionThreadPool::Shutdown();
 
-    // Cancel the timer regardless of whether it actually fired.
-    if (NS_FAILED(mShutdownTimer->Cancel())) {
-      NS_WARNING("Failed to cancel shutdown timer!");
+      // Cancel the timer regardless of whether it actually fired.
+      if (NS_FAILED(mShutdownTimer->Cancel())) {
+        NS_WARNING("Failed to cancel shutdown timer!");
+      }
     }
 
     mFileManagers.EnumerateRead(InvalidateAllFileManagers, nsnull);
 
     if (PR_ATOMIC_SET(&gClosed, 1)) {
       NS_ERROR("Close more than once?!");
     }
 
     return NS_OK;
   }
 
   if (!strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC)) {
+    NS_ASSERTION(sIsMainProcess, "Should only happen in the main process!");
+
     NS_WARNING("Some database operations are taking longer than expected "
                "during shutdown and will be aborted!");
 
     // Grab all live databases, for all origins.
     nsAutoTArray<IDBDatabase*, 50> liveDatabases;
     mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
 
     // Invalidate them all.
@@ -1587,21 +1623,24 @@ IndexedDatabaseManager::InitWindowless(c
   // in xpcshell we will get typed (dom) exceptions, instead of general
   // exceptions.
   nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID));
 
   JSObject* obj = JSVAL_TO_OBJECT(aObj);
 
   JSObject* global = JS_GetGlobalForObject(aCx, obj);
 
-  nsCOMPtr<nsIIDBFactory> factory = IDBFactory::Create(aCx, global);
-  NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
+  nsRefPtr<IDBFactory> factory;
+  nsresult rv = IDBFactory::Create(aCx, global, getter_AddRefs(factory));
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(factory, "This should never fail for chrome!");
 
   jsval mozIndexedDBVal;
-  nsresult rv = nsContentUtils::WrapNative(aCx, obj, factory, &mozIndexedDBVal);
+  rv = nsContentUtils::WrapNative(aCx, obj, factory, &mozIndexedDBVal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!JS_DefineProperty(aCx, obj, "mozIndexedDB", mozIndexedDBVal, nsnull,
                          nsnull, JSPROP_ENUMERATE)) {
     return NS_ERROR_FAILURE;
   }
 
   JSObject* keyrangeObj = JS_NewObject(aCx, nsnull, nsnull, nsnull);
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -140,16 +140,26 @@ public:
     NS_ASSERTION(mgr, "Must have a manager here!");
 
     mgr->CancelPromptsForWindowInternal(aWindow);
   }
 
   static nsresult
   GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow, nsCString& aASCIIOrigin);
 
+  static bool
+  IsMainProcess()
+#ifdef DEBUG
+  ;
+#else
+  {
+    return sIsMainProcess;
+  }
+#endif
+
   already_AddRefed<FileManager>
   GetOrCreateFileManager(const nsACString& aOrigin,
                          const nsAString& aDatabaseName);
 
   already_AddRefed<FileManager>
   GetFileManager(const nsACString& aOrigin,
                  const nsAString& aDatabaseName);
 
@@ -174,16 +184,20 @@ public:
   static mozilla::Mutex& FileMutex()
   {
     IndexedDatabaseManager* mgr = Get();
     NS_ASSERTION(mgr, "Must have a manager here!");
 
     return mgr->mFileMutex;
   }
 
+  static already_AddRefed<nsIAtom>
+  GetDatabaseId(const nsACString& aOrigin,
+                const nsAString& aName);
+
 private:
   IndexedDatabaseManager();
   ~IndexedDatabaseManager();
 
   nsresult AcquireExclusiveAccess(const nsACString& aOrigin, 
                                   IDBDatabase* aDatabase,
                                   AsyncConnectionHelper* aHelper,
                                   WaitingOnDatabasesCallback aCallback,
@@ -363,16 +377,18 @@ private:
   nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton;
 
   // Lock protecting FileManager.mFileInfos and nsDOMFileBase.mFileInfos
   // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
   // and FileInfo.mSliceRefCnt
   mozilla::Mutex mFileMutex;
 
   nsString mDatabaseBasePath;
+
+  static bool sIsMainProcess;
 };
 
 class AutoEnterWindow
 {
 public:
   AutoEnterWindow(nsPIDOMWindow* aWindow)
   {
     IndexedDatabaseManager::SetCurrentWindow(aWindow);
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -152,17 +152,19 @@ Key::EncodeJSValInternal(JSContext* aCx,
       for (uint32_t index = 0; index < length; index++) {
         jsval val;
         if (!JS_GetElement(aCx, obj, index, &val)) {
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
 
         nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset,
                                           aRecursionDepth + 1);
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_FAILED(rv)) {
+          return rv;
+        }
 
         aTypeOffset = 0;
       }
 
       mBuffer.Append(eTerminator + aTypeOffset);
 
       return NS_OK;
     }
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -6,20 +6,26 @@
 
 #ifndef mozilla_dom_indexeddb_key_h__
 #define mozilla_dom_indexeddb_key_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "mozIStorageStatement.h"
 
+namespace IPC {
+template <typename T> struct ParamTraits;
+} // namespace IPC
+
 BEGIN_INDEXEDDB_NAMESPACE
 
 class Key
 {
+  friend struct IPC::ParamTraits<Key>;
+
 public:
   Key()
   {
     Unset();
   }
 
   Key& operator=(const nsAString& aString)
   {
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -36,16 +36,17 @@ CPPSRCS = \
   IDBWrapperCache.cpp \
   IndexedDatabaseManager.cpp \
   Key.cpp \
   OpenDatabaseHelper.cpp \
   TransactionThreadPool.cpp \
   $(NULL)
 
 EXPORTS_mozilla/dom/indexedDB = \
+  DatabaseInfo.h \
   IDBCursor.h \
   IDBDatabase.h \
   IDBEvents.h \
   IDBIndex.h \
   IDBKeyRange.h \
   IDBObjectStore.h \
   IDBRequest.h \
   IDBTransaction.h \
@@ -81,13 +82,14 @@ XPIDLSRCS = \
   nsIIDBObjectStore.idl \
   nsIIDBRequest.idl \
   nsIIDBTransaction.idl \
   nsIIDBVersionChangeEvent.idl \
   nsIIDBOpenDBRequest.idl \
   nsIIndexedDatabaseManager.idl \
   $(NULL)
 
+DIRS += ipc
 TEST_DIRS += test
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -1325,47 +1325,66 @@ UpgradeSchemaFrom11_0To12_0(mozIStorageC
 }
 
 class VersionChangeEventsRunnable;
 
 class SetVersionHelper : public AsyncConnectionHelper,
                          public IDBTransactionListener
 {
   friend class VersionChangeEventsRunnable;
+
 public:
   SetVersionHelper(IDBTransaction* aTransaction,
                    IDBOpenDBRequest* aRequest,
                    OpenDatabaseHelper* aHelper,
                    PRUint64 aRequestedVersion,
                    PRUint64 aCurrentVersion)
   : AsyncConnectionHelper(aTransaction, aRequest),
     mOpenRequest(aRequest), mOpenHelper(aHelper),
     mRequestedVersion(aRequestedVersion),
     mCurrentVersion(aCurrentVersion)
   {
     mTransaction->SetTransactionListener(this);
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
 
 protected:
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult Init();
+  virtual nsresult Init() MOZ_OVERRIDE;
+
+  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
+                                  MOZ_OVERRIDE;
 
   // SetVersionHelper never fires an error event at the request.  It hands that
   // responsibility back to the OpenDatabaseHelper
-  void OnError() { }
+  virtual void OnError() MOZ_OVERRIDE
+  { }
 
   // Need an upgradeneeded event here.
-  already_AddRefed<nsDOMEvent> CreateSuccessEvent();
-
-  nsresult NotifyTransactionComplete(IDBTransaction* aTransaction);
+  virtual already_AddRefed<nsDOMEvent> CreateSuccessEvent() MOZ_OVERRIDE;
+
+  virtual nsresult NotifyTransactionComplete(IDBTransaction* aTransaction)
+                                             MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE
+  {
+    return Success_NotSent;
+  }
+
+  virtual nsresult UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+                                            MOZ_OVERRIDE
+  {
+    MOZ_NOT_REACHED("Should never get here!");
+    return NS_ERROR_UNEXPECTED;
+  }
 
   PRUint64 RequestedVersion() const
   {
     return mRequestedVersion;
   }
 
 private:
   // In-params
@@ -1406,25 +1425,41 @@ protected:
   nsresult Init();
 
   // DeleteDatabaseHelper never fires events at the request.  It hands that
   // responsibility back to the OpenDatabaseHelper
   void OnError()
   {
     mOpenHelper->NotifyDeleteFinished();
   }
+
   nsresult OnSuccess()
   {
     return mOpenHelper->NotifyDeleteFinished();
   }
 
   PRUint64 RequestedVersion() const
   {
     return 0;
   }
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE
+  {
+    return Success_NotSent;
+  }
+
+  virtual nsresult UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+                                            MOZ_OVERRIDE
+  {
+    MOZ_NOT_REACHED("Should never get here!");
+    return NS_ERROR_UNEXPECTED;
+  }
+
 private:
   // In-params
   nsRefPtr<OpenDatabaseHelper> mOpenHelper;
   nsRefPtr<IDBOpenDBRequest> mOpenRequest;
   PRUint64 mCurrentVersion;
   nsString mName;
   nsCString mASCIIOrigin;
 };
@@ -1520,24 +1555,19 @@ private:
 
 } // anonymous namespace
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable);
 
 nsresult
 OpenDatabaseHelper::Init()
 {
-  nsCString str(mASCIIOrigin);
-  str.Append("*");
-  str.Append(NS_ConvertUTF16toUTF8(mName));
-
-  nsCOMPtr<nsIAtom> atom = do_GetAtom(str);
-  NS_ENSURE_TRUE(atom, NS_ERROR_FAILURE);
-
-  atom.swap(mDatabaseId);
+  mDatabaseId = IndexedDatabaseManager::GetDatabaseId(mASCIIOrigin, mName);
+  NS_ENSURE_TRUE(mDatabaseId, NS_ERROR_FAILURE);
+
   return NS_OK;
 }
 
 nsresult
 OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
 {
   NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
   mState = eDBWork;
@@ -1678,16 +1708,17 @@ OpenDatabaseHelper::DoDatabaseWork()
 // static
 nsresult
 OpenDatabaseHelper::CreateDatabaseConnection(
                                         const nsAString& aName,
                                         nsIFile* aDBFile,
                                         nsIFile* aFileManagerDirectory,
                                         mozIStorageConnection** aConnection)
 {
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
 
   nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
 
@@ -1993,16 +2024,18 @@ OpenDatabaseHelper::Run()
 
     manager->AllowNextSynchronizedOp(mASCIIOrigin, mDatabaseId);
 
     ReleaseMainThreadObjects();
 
     return NS_OK;
   }
 
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+
   // If we're on the DB thread, do that
   NS_ASSERTION(mState == eDBWork, "Why are we here?");
   mResultCode = DoDatabaseWork();
   NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");
 
   return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
 }
 
@@ -2281,17 +2314,17 @@ SetVersionHelper::NotifyTransactionCompl
   // If we hit an error, the OpenDatabaseHelper needs to get that error too.
   nsresult rv = GetResultCode();
   if (NS_FAILED(rv)) {
     mOpenHelper->SetError(rv);
   }
 
   // If the transaction was aborted, we should throw an error message.
   if (aTransaction->IsAborted()) {
-    mOpenHelper->SetError(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
+    mOpenHelper->SetError(aTransaction->GetAbortCode());
   }
 
   mOpenRequest->SetTransaction(nsnull);
   mOpenRequest = nsnull;
 
   rv = mOpenHelper->NotifySetVersionFinished();
   mOpenHelper = nsnull;
 
--- a/dom/indexedDB/OpenDatabaseHelper.h
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -43,17 +43,23 @@ public:
   nsresult RunImmediately();
 
   void SetError(nsresult rv)
   {
     NS_ASSERTION(NS_FAILED(rv), "Why are you telling me?");
     mResultCode = rv;
   }
 
-  nsresult GetResultCode()
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE
+  {
+    return Success_NotSent;
+  }
+
+  virtual nsresult GetResultCode() MOZ_OVERRIDE
   {
     return mResultCode;
   }
 
   nsresult NotifySetVersionFinished();
   nsresult NotifyDeleteFinished();
   void BlockDatabase();
 
@@ -74,26 +80,25 @@ public:
                                     nsIFile* aFileManagerDirectory,
                                     mozIStorageConnection** aConnection);
 
 protected:
   // Methods only called on the main thread
   nsresult EnsureSuccessResult();
   nsresult StartSetVersion();
   nsresult StartDelete();
-  nsresult GetSuccessResult(JSContext* aCx,
-                          jsval* aVal);
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) MOZ_OVERRIDE;
   void DispatchSuccessEvent();
   void DispatchErrorEvent();
-  void ReleaseMainThreadObjects();
+  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
 
   // Methods only called on the DB thread
   nsresult DoDatabaseWork();
 
-private:
   // In-params.
   nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
   nsString mName;
   nsCString mASCIIOrigin;
   PRUint64 mRequestedVersion;
   bool mForDeletion;
   nsCOMPtr<nsIAtom> mDatabaseId;
 
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/ipc/IndexedDBChild.cpp
@@ -0,0 +1,1171 @@
+/* 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 "IndexedDBChild.h"
+
+#include "mozilla/Assertions.h"
+
+#include "nsIAtom.h"
+
+#include "AsyncConnectionHelper.h"
+#include "DatabaseInfo.h"
+#include "IDBEvents.h"
+#include "IDBFactory.h"
+#include "IDBIndex.h"
+#include "IDBObjectStore.h"
+#include "IDBTransaction.h"
+#include "IndexedDatabaseManager.h"
+
+USING_INDEXEDDB_NAMESPACE
+
+namespace {
+
+class IPCOpenDatabaseHelper : public AsyncConnectionHelper
+{
+public:
+  IPCOpenDatabaseHelper(IDBDatabase* aDatabase, IDBOpenDBRequest* aRequest)
+  : AsyncConnectionHelper(aDatabase, aRequest)
+  {
+    MOZ_ASSERT(aRequest);
+  }
+
+  virtual nsresult UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+                                            MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetSuccessResult(JSContext* aCx, jsval* aVal) MOZ_OVERRIDE;
+
+  virtual nsresult
+  DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE;
+};
+
+class IPCSetVersionHelper : public AsyncConnectionHelper
+{
+  IndexedDBTransactionChild* mActor;
+  nsRefPtr<IDBOpenDBRequest> mOpenRequest;
+  uint64_t mOldVersion;
+  uint64_t mRequestedVersion;
+
+public:
+  IPCSetVersionHelper(IndexedDBTransactionChild* aActor,
+                      IDBTransaction* aTransaction, IDBOpenDBRequest* aRequest,
+                      uint64_t aOldVersion, uint64_t aRequestedVersion)
+  : AsyncConnectionHelper(aTransaction, aRequest),mActor(aActor),
+    mOpenRequest(aRequest), mOldVersion(aOldVersion),
+    mRequestedVersion(aRequestedVersion)
+  {
+    MOZ_ASSERT(aActor);
+    MOZ_ASSERT(aTransaction);
+    MOZ_ASSERT(aRequest);
+  }
+
+  virtual nsresult UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+                                            MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<nsDOMEvent>
+  CreateSuccessEvent() MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetSuccessResult(JSContext* aCx, jsval* aVal) MOZ_OVERRIDE;
+};
+
+class IPCDeleteDatabaseHelper : public AsyncConnectionHelper
+{
+public:
+  IPCDeleteDatabaseHelper(IDBRequest* aRequest)
+  : AsyncConnectionHelper(static_cast<IDBDatabase*>(NULL), aRequest)
+  { }
+
+  virtual nsresult UnpackResponseFromParentProcess(
+                                            const ResponseValue& aResponseValue)
+                                            MOZ_OVERRIDE;
+
+  virtual ChildProcessSendResult
+  MaybeSendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetSuccessResult(JSContext* aCx, jsval* aVal) MOZ_OVERRIDE;
+
+  virtual nsresult
+  DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE;
+};
+
+} // anonymous namespace
+
+/*******************************************************************************
+ * IndexedDBChild
+ ******************************************************************************/
+
+IndexedDBChild::IndexedDBChild(const nsCString& aASCIIOrigin)
+: mFactory(nsnull), mASCIIOrigin(aASCIIOrigin)
+{
+  MOZ_COUNT_CTOR(IndexedDBChild);
+}
+
+IndexedDBChild::~IndexedDBChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBChild);
+  MOZ_ASSERT(!mFactory);
+}
+
+void
+IndexedDBChild::SetFactory(IDBFactory* aFactory)
+{
+  MOZ_ASSERT(aFactory);
+  MOZ_ASSERT(!mFactory);
+
+  aFactory->SetActor(this);
+  mFactory = aFactory;
+}
+
+void
+IndexedDBChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mFactory) {
+    mFactory->SetActor(static_cast<IndexedDBChild*>(NULL));
+#ifdef DEBUG
+    mFactory = NULL;
+#endif
+  }
+}
+
+PIndexedDBDatabaseChild*
+IndexedDBChild::AllocPIndexedDBDatabase(const nsString& aName,
+                                        const uint64_t& aVersion)
+{
+  return new IndexedDBDatabaseChild(aName, aVersion);
+}
+
+bool
+IndexedDBChild::DeallocPIndexedDBDatabase(PIndexedDBDatabaseChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+PIndexedDBDeleteDatabaseRequestChild*
+IndexedDBChild::AllocPIndexedDBDeleteDatabaseRequest(const nsString& aName)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct a request!");
+  return NULL;
+}
+
+bool
+IndexedDBChild::DeallocPIndexedDBDeleteDatabaseRequest(
+                                   PIndexedDBDeleteDatabaseRequestChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * IndexedDBDatabaseChild
+ ******************************************************************************/
+
+IndexedDBDatabaseChild::IndexedDBDatabaseChild(const nsString& aName,
+                                               uint64_t aVersion)
+: mDatabase(NULL), mName(aName), mVersion(aVersion)
+{
+  MOZ_COUNT_CTOR(IndexedDBDatabaseChild);
+}
+
+IndexedDBDatabaseChild::~IndexedDBDatabaseChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBDatabaseChild);
+  MOZ_ASSERT(!mDatabase);
+  MOZ_ASSERT(!mStrongDatabase);
+}
+
+void
+IndexedDBDatabaseChild::SetRequest(IDBOpenDBRequest* aRequest)
+{
+  MOZ_ASSERT(aRequest);
+  MOZ_ASSERT(!mRequest);
+
+  mRequest = aRequest;
+}
+
+bool
+IndexedDBDatabaseChild::EnsureDatabase(
+                           IDBRequest* aRequest,
+                           const DatabaseInfoGuts& aDBInfo,
+                           const InfallibleTArray<ObjectStoreInfoGuts>& aOSInfo)
+{
+  nsCOMPtr<nsIAtom> databaseId;
+  if (mDatabase) {
+    databaseId = mDatabase->Id();
+  }
+  else {
+    databaseId =
+      IndexedDatabaseManager::GetDatabaseId(aDBInfo.origin, aDBInfo.name);
+  }
+  NS_ENSURE_TRUE(databaseId, false);
+
+  nsRefPtr<DatabaseInfo> dbInfo;
+  if (DatabaseInfo::Get(databaseId, getter_AddRefs(dbInfo))) {
+    dbInfo->version = aDBInfo.version;
+  }
+  else {
+    nsRefPtr<DatabaseInfo> newInfo = new DatabaseInfo();
+
+    *static_cast<DatabaseInfoGuts*>(newInfo.get()) = aDBInfo;
+    newInfo->id = databaseId;
+
+    if (!DatabaseInfo::Put(newInfo)) {
+      NS_WARNING("Out of memory!");
+      return false;
+    }
+
+    newInfo.swap(dbInfo);
+
+    // This is more or less copied from IDBFactory::SetDatabaseMetadata.
+    for (uint32_t i = 0; i < aOSInfo.Length(); i++) {
+      nsRefPtr<ObjectStoreInfo> newInfo = new ObjectStoreInfo();
+      *static_cast<ObjectStoreInfoGuts*>(newInfo.get()) = aOSInfo[i];
+
+      if (!dbInfo->PutObjectStore(newInfo)) {
+        NS_WARNING("Out of memory!");
+        return false;
+      }
+    }
+  }
+
+  if (!mDatabase) {
+    nsRefPtr<IDBDatabase> database =
+      IDBDatabase::Create(aRequest, dbInfo.forget(), aDBInfo.origin, NULL);
+    if (!database) {
+      NS_WARNING("Failed to create database!");
+      return false;
+    }
+
+    database->SetActor(this);
+
+    mDatabase = database;
+    mStrongDatabase = database.forget();
+  }
+
+  return true;
+}
+
+void
+IndexedDBDatabaseChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_ASSERT(!mStrongDatabase);
+  if (mDatabase) {
+    mDatabase->SetActor(static_cast<IndexedDBDatabaseChild*>(NULL));
+#ifdef DEBUG
+    mDatabase = NULL;
+#endif
+  }
+}
+
+bool
+IndexedDBDatabaseChild::RecvSuccess(
+                           const DatabaseInfoGuts& aDBInfo,
+                           const InfallibleTArray<ObjectStoreInfoGuts>& aOSInfo)
+{
+#ifdef DEBUG
+  {
+    IndexedDBChild* manager = static_cast<IndexedDBChild*>(Manager());
+    MOZ_ASSERT(aDBInfo.origin == manager->ASCIIOrigin());
+    MOZ_ASSERT(aDBInfo.name == mName);
+    MOZ_ASSERT(!mVersion || aDBInfo.version == mVersion);
+  }
+#endif
+
+  MOZ_ASSERT(mRequest);
+
+  nsRefPtr<IDBOpenDBRequest> request;
+  mRequest.swap(request);
+
+  nsRefPtr<AsyncConnectionHelper> openHelper;
+  mOpenHelper.swap(openHelper);
+
+  if (!EnsureDatabase(request, aDBInfo, aOSInfo)) {
+    return false;
+  }
+
+  MOZ_ASSERT(mStrongDatabase);
+  nsRefPtr<IDBDatabase> database;
+  mStrongDatabase.swap(database);
+
+  if (openHelper) {
+    request->Reset();
+    database->ExitSetVersionTransaction();
+  }
+  else {
+    openHelper = new IPCOpenDatabaseHelper(mDatabase, request);
+  }
+
+  request->SetTransaction(NULL);
+
+  MainThreadEventTarget target;
+  if (NS_FAILED(openHelper->Dispatch(&target))) {
+    NS_WARNING("Dispatch of IPCOpenDatabaseHelper failed!");
+    return false;
+  }
+
+  return true;
+}
+
+bool
+IndexedDBDatabaseChild::RecvError(const nsresult& aRv)
+{
+  MOZ_ASSERT(mRequest);
+
+  nsRefPtr<IDBOpenDBRequest> request;
+  mRequest.swap(request);
+
+  nsRefPtr<IDBDatabase> database;
+  mStrongDatabase.swap(database);
+
+  nsRefPtr<AsyncConnectionHelper> openHelper;
+  mOpenHelper.swap(openHelper);
+
+  if (openHelper) {
+    request->Reset();
+    database->ExitSetVersionTransaction();
+  }
+  else {
+    openHelper = new IPCOpenDatabaseHelper(NULL, request);
+  }
+
+  openHelper->SetError(aRv);
+  request->SetTransaction(NULL);
+
+  MainThreadEventTarget target;
+  if (NS_FAILED(openHelper->Dispatch(&target))) {
+    NS_WARNING("Dispatch of IPCOpenDatabaseHelper failed!");
+    return false;
+  }
+
+  return true;
+}
+
+bool
+IndexedDBDatabaseChild::RecvBlocked(const uint64_t& aOldVersion)
+{
+  MOZ_ASSERT(mRequest);
+  MOZ_ASSERT(!mDatabase);
+
+  nsRefPtr<nsDOMEvent> event =
+    IDBVersionChangeEvent::CreateBlocked(aOldVersion, mVersion);
+
+  bool dummy;
+  if (NS_FAILED(mRequest->DispatchEvent(event, &dummy))) {
+    NS_WARNING("Failed to dispatch blocked event!");
+  }
+
+  return true;
+}
+
+bool
+IndexedDBDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
+                                          const uint64_t& aNewVersion)
+{
+  MOZ_ASSERT(mDatabase);
+
+  if (mDatabase->IsClosed()) {
+    return true;
+  }
+
+  nsRefPtr<nsDOMEvent> event =
+    IDBVersionChangeEvent::Create(aOldVersion, aNewVersion);
+
+  bool dummy;
+  if (NS_FAILED(mDatabase->DispatchEvent(event, &dummy))) {
+    NS_WARNING("Failed to dispatch blocked event!");
+  }
+
+  return true;
+}
+
+bool
+IndexedDBDatabaseChild::RecvPIndexedDBTransactionConstructor(
+                                             PIndexedDBTransactionChild* aActor,
+                                             const TransactionParams& aParams)
+{
+  // This only happens when the parent has created a version-change transaction
+  // for us.
+
+  IndexedDBTransactionChild* actor =
+    static_cast<IndexedDBTransactionChild*>(aActor);
+  MOZ_ASSERT(!actor->GetTransaction());
+
+  MOZ_ASSERT(aParams.type() ==
+             TransactionParams::TVersionChangeTransactionParams);
+
+  const VersionChangeTransactionParams& params =
+    aParams.get_VersionChangeTransactionParams();
+
+  const DatabaseInfoGuts& dbInfo = params.dbInfo();
+  const InfallibleTArray<ObjectStoreInfoGuts>& osInfo = params.osInfo();
+  uint64_t oldVersion = params.oldVersion();
+
+  MOZ_ASSERT(dbInfo.origin ==
+             static_cast<IndexedDBChild*>(Manager())->ASCIIOrigin());
+  MOZ_ASSERT(dbInfo.name == mName);
+  MOZ_ASSERT(!mVersion || dbInfo.version == mVersion);
+  MOZ_ASSERT(!mVersion || oldVersion < mVersion);
+
+  MOZ_ASSERT(mRequest);
+  MOZ_ASSERT(!mDatabase);
+  MOZ_ASSERT(!mOpenHelper);
+
+  if (!EnsureDatabase(mRequest, dbInfo, osInfo)) {
+    return false;
+  }
+
+  nsRefPtr<IPCOpenDatabaseHelper> helper =
+    new IPCOpenDatabaseHelper(mDatabase, mRequest);
+
+  nsTArray<nsString> storesToOpen;
+  nsRefPtr<IDBTransaction> transaction =
+    IDBTransaction::CreateInternal(mDatabase, storesToOpen,
+                                   IDBTransaction::VERSION_CHANGE, false, true);
+  NS_ENSURE_TRUE(transaction, false);
+
+  nsRefPtr<IPCSetVersionHelper> versionHelper =
+    new IPCSetVersionHelper(actor, transaction, mRequest, oldVersion, mVersion);
+
+  mDatabase->EnterSetVersionTransaction();
+
+  MainThreadEventTarget target;
+  if (NS_FAILED(versionHelper->Dispatch(&target))) {
+    NS_WARNING("Dispatch of IPCSetVersionHelper failed!");
+    return false;
+  }
+
+  actor->SetTransaction(transaction);
+
+  mOpenHelper = helper.forget();
+  return true;
+}
+
+PIndexedDBTransactionChild*
+IndexedDBDatabaseChild::AllocPIndexedDBTransaction(
+                                               const TransactionParams& aParams)
+{
+  MOZ_ASSERT(aParams.type() ==
+             TransactionParams::TVersionChangeTransactionParams);
+  return new IndexedDBTransactionChild();
+}
+
+bool
+IndexedDBDatabaseChild::DeallocPIndexedDBTransaction(
+                                             PIndexedDBTransactionChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * IndexedDBTransactionChild
+ ******************************************************************************/
+
+IndexedDBTransactionChild::IndexedDBTransactionChild()
+: mTransaction(NULL)
+{
+  MOZ_COUNT_CTOR(IndexedDBTransactionChild);
+}
+
+IndexedDBTransactionChild::~IndexedDBTransactionChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBTransactionChild);
+  MOZ_ASSERT(!mTransaction);
+  MOZ_ASSERT(!mStrongTransaction);
+}
+
+void
+IndexedDBTransactionChild::SetTransaction(IDBTransaction* aTransaction)
+{
+  MOZ_ASSERT(aTransaction);
+  MOZ_ASSERT(!mTransaction);
+
+  aTransaction->SetActor(this);
+
+  mTransaction = aTransaction;
+  mStrongTransaction = aTransaction;
+}
+
+void
+IndexedDBTransactionChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mTransaction) {
+    mTransaction->SetActor(static_cast<IndexedDBTransactionChild*>(NULL));
+#ifdef DEBUG
+    mTransaction = NULL;
+#endif
+  }
+}
+
+bool
+IndexedDBTransactionChild::RecvComplete(const nsresult& aRv)
+{
+  MOZ_ASSERT(mTransaction);
+  MOZ_ASSERT(mStrongTransaction);
+
+  nsRefPtr<IDBTransaction> transaction;
+  mStrongTransaction.swap(transaction);
+
+  // This is where we should allow the database to start issuing new
+  // transactions once we fix the main thread. E.g.:
+  //
+  //   if (transaction->GetMode() == IDBTransaction::VERSION_CHANGE) {
+  //     transaction->Database()->ExitSetVersionTransaction();
+  //   }
+
+  nsRefPtr<CommitHelper> helper = new CommitHelper(transaction, aRv);
+  if (NS_FAILED(helper->Run())) {
+    NS_WARNING("CommitHelper failed!");
+  }
+
+  return true;
+}
+
+PIndexedDBObjectStoreChild*
+IndexedDBTransactionChild::AllocPIndexedDBObjectStore(
+                                    const ObjectStoreConstructorParams& aParams)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct an object store!");
+  return NULL;
+}
+
+bool
+IndexedDBTransactionChild::DeallocPIndexedDBObjectStore(
+                                             PIndexedDBObjectStoreChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * IndexedDBObjectStoreChild
+ ******************************************************************************/
+
+IndexedDBObjectStoreChild::IndexedDBObjectStoreChild(
+                                                   IDBObjectStore* aObjectStore)
+: mObjectStore(aObjectStore)
+{
+  MOZ_COUNT_CTOR(IndexedDBObjectStoreChild);
+  aObjectStore->SetActor(this);
+}
+
+IndexedDBObjectStoreChild::~IndexedDBObjectStoreChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBObjectStoreChild);
+  MOZ_ASSERT(!mObjectStore);
+}
+
+void
+IndexedDBObjectStoreChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mObjectStore) {
+    mObjectStore->SetActor(static_cast<IndexedDBObjectStoreChild*>(NULL));
+#ifdef DEBUG
+    mObjectStore = NULL;
+#endif
+  }
+}
+
+bool
+IndexedDBObjectStoreChild::RecvPIndexedDBCursorConstructor(
+                              PIndexedDBCursorChild* aActor,
+                              const ObjectStoreCursorConstructorParams& aParams)
+{
+  IndexedDBCursorChild* actor = static_cast<IndexedDBCursorChild*>(aActor);
+
+  IndexedDBObjectStoreRequestChild* requestActor =
+    static_cast<IndexedDBObjectStoreRequestChild*>(aParams.requestChild());
+  NS_ASSERTION(requestActor, "Must have an actor here!");
+
+  nsRefPtr<IDBRequest> request = requestActor->GetRequest();
+  NS_ASSERTION(request, "Must have a request here!");
+
+  size_t direction = static_cast<size_t>(aParams.direction());
+
+  nsRefPtr<IDBCursor> cursor;
+  nsresult rv =
+    mObjectStore->OpenCursorFromChildProcess(request, direction, aParams.key(),
+                                             aParams.cloneInfo(),
+                                             getter_AddRefs(cursor));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  actor->SetCursor(cursor);
+  return true;
+}
+
+PIndexedDBRequestChild*
+IndexedDBObjectStoreChild::AllocPIndexedDBRequest(
+                                        const ObjectStoreRequestParams& aParams)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct a request!");
+  return NULL;
+}
+
+bool
+IndexedDBObjectStoreChild::DeallocPIndexedDBRequest(
+                                                 PIndexedDBRequestChild* aActor)
+{
+  delete aActor;
+  return false;
+}
+
+PIndexedDBIndexChild*
+IndexedDBObjectStoreChild::AllocPIndexedDBIndex(
+                                          const IndexConstructorParams& aParams)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct an index!");
+  return NULL;
+}
+
+bool
+IndexedDBObjectStoreChild::DeallocPIndexedDBIndex(PIndexedDBIndexChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+PIndexedDBCursorChild*
+IndexedDBObjectStoreChild::AllocPIndexedDBCursor(
+                              const ObjectStoreCursorConstructorParams& aParams)
+{
+  return new IndexedDBCursorChild();
+}
+
+bool
+IndexedDBObjectStoreChild::DeallocPIndexedDBCursor(
+                                                  PIndexedDBCursorChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * IndexedDBIndexChild
+ ******************************************************************************/
+
+IndexedDBIndexChild::IndexedDBIndexChild(IDBIndex* aIndex)
+: mIndex(aIndex)
+{
+  MOZ_COUNT_CTOR(IndexedDBIndexChild);
+  aIndex->SetActor(this);
+}
+
+IndexedDBIndexChild::~IndexedDBIndexChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBIndexChild);
+  MOZ_ASSERT(!mIndex);
+}
+
+void
+IndexedDBIndexChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mIndex) {
+    mIndex->SetActor(static_cast<IndexedDBIndexChild*>(NULL));
+#ifdef DEBUG
+    mIndex = NULL;
+#endif
+  }
+}
+
+bool
+IndexedDBIndexChild::RecvPIndexedDBCursorConstructor(
+                                    PIndexedDBCursorChild* aActor,
+                                    const IndexCursorConstructorParams& aParams)
+{
+  IndexedDBCursorChild* actor = static_cast<IndexedDBCursorChild*>(aActor);
+
+  IndexedDBObjectStoreRequestChild* requestActor =
+    static_cast<IndexedDBObjectStoreRequestChild*>(aParams.requestChild());
+  NS_ASSERTION(requestActor, "Must have an actor here!");
+
+  nsRefPtr<IDBRequest> request = requestActor->GetRequest();
+  NS_ASSERTION(request, "Must have a request here!");
+
+  size_t direction = static_cast<size_t>(aParams.direction());
+
+  nsRefPtr<IDBCursor> cursor;
+  nsresult rv;
+
+  typedef ipc::OptionalStructuredCloneReadInfo CursorUnionType;
+
+  switch (aParams.optionalCloneInfo().type()) {
+    case CursorUnionType::TSerializedStructuredCloneReadInfo: {
+      const SerializedStructuredCloneReadInfo& cloneInfo =
+        aParams.optionalCloneInfo().get_SerializedStructuredCloneReadInfo();
+
+      rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(),
+                                              aParams.objectKey(), cloneInfo,
+                                              getter_AddRefs(cursor));
+      NS_ENSURE_SUCCESS(rv, false);
+    } break;
+
+    case CursorUnionType::Tvoid_t:
+      rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(),
+                                              aParams.objectKey(),
+                                              getter_AddRefs(cursor));
+      NS_ENSURE_SUCCESS(rv, false);
+      break;
+
+    default:
+      MOZ_NOT_REACHED("Unknown union type!");
+      return false;
+  }
+
+  actor->SetCursor(cursor);
+  return true;
+}
+
+PIndexedDBRequestChild*
+IndexedDBIndexChild::AllocPIndexedDBRequest(const IndexRequestParams& aParams)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct a request!");
+  return NULL;
+}
+
+bool
+IndexedDBIndexChild::DeallocPIndexedDBRequest(PIndexedDBRequestChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+PIndexedDBCursorChild*
+IndexedDBIndexChild::AllocPIndexedDBCursor(
+                                    const IndexCursorConstructorParams& aParams)
+{
+  return new IndexedDBCursorChild();
+}
+
+bool
+IndexedDBIndexChild::DeallocPIndexedDBCursor(PIndexedDBCursorChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * IndexedDBCursorChild
+ ******************************************************************************/
+
+IndexedDBCursorChild::IndexedDBCursorChild()
+: mCursor(NULL)
+{
+  MOZ_COUNT_CTOR(IndexedDBCursorChild);
+}
+
+IndexedDBCursorChild::~IndexedDBCursorChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBCursorChild);
+  MOZ_ASSERT(!mCursor);
+  MOZ_ASSERT(!mStrongCursor);
+}
+
+void
+IndexedDBCursorChild::SetCursor(IDBCursor* aCursor)
+{
+  MOZ_ASSERT(aCursor);
+  MOZ_ASSERT(!mCursor);
+
+  aCursor->SetActor(this);
+
+  mCursor = aCursor;
+  mStrongCursor = aCursor;
+}
+
+void
+IndexedDBCursorChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mCursor) {
+    mCursor->SetActor(static_cast<IndexedDBCursorChild*>(NULL));
+#ifdef DEBUG
+    mCursor = NULL;
+#endif
+  }
+}
+
+PIndexedDBRequestChild*
+IndexedDBCursorChild::AllocPIndexedDBRequest(const CursorRequestParams& aParams)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct a request!");
+  return NULL;
+}
+
+bool
+IndexedDBCursorChild::DeallocPIndexedDBRequest(PIndexedDBRequestChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * IndexedDBRequestChildBase
+ ******************************************************************************/
+
+IndexedDBRequestChildBase::IndexedDBRequestChildBase(
+                                                 AsyncConnectionHelper* aHelper)
+: mHelper(aHelper)
+{
+  MOZ_COUNT_CTOR(IndexedDBRequestChildBase);
+}
+
+IndexedDBRequestChildBase::~IndexedDBRequestChildBase()
+{
+  MOZ_COUNT_DTOR(IndexedDBRequestChildBase);
+}
+
+IDBRequest*
+IndexedDBRequestChildBase::GetRequest() const
+{
+  return mHelper ? mHelper->GetRequest() : NULL;
+}
+
+bool
+IndexedDBRequestChildBase::Recv__delete__(const ResponseValue& aResponse)
+{
+  MOZ_NOT_REACHED("This should be overridden!");
+  return false;
+}
+
+/*******************************************************************************
+ * IndexedDBObjectStoreRequestChild
+ ******************************************************************************/
+
+IndexedDBObjectStoreRequestChild::IndexedDBObjectStoreRequestChild(
+                                                 AsyncConnectionHelper* aHelper,
+                                                 IDBObjectStore* aObjectStore,
+                                                 RequestType aRequestType)
+: IndexedDBRequestChildBase(aHelper), mObjectStore(aObjectStore),
+  mRequestType(aRequestType)
+{
+  MOZ_COUNT_CTOR(IndexedDBObjectStoreRequestChild);
+  MOZ_ASSERT(aHelper);
+  MOZ_ASSERT(aObjectStore);
+  MOZ_ASSERT(aRequestType > ParamsUnionType::T__None &&
+             aRequestType <= ParamsUnionType::T__Last);
+}
+
+IndexedDBObjectStoreRequestChild::~IndexedDBObjectStoreRequestChild()
+{
+  MOZ_COUNT_DTOR(IndexedDBObjectStoreRequestChild);
+}
+
+bool
+IndexedDBObjectStoreRequestChild::Recv__delete__(const ResponseValue& aResponse)
+{
+  switch (aResponse.type()) {
+    case ResponseValue::Tnsresult:
+      break;
+    case ResponseValue::TGetResponse:
+      MOZ_ASSERT(mRequestType == ParamsUnionType::TGetParams);
+      break;
+    case ResponseValue::TGetAllResponse:
+      MOZ_ASSERT(mRequestType == ParamsUnionType::TGetAllParams);
+      break;
+    case ResponseValue::TAddResponse:
+      MOZ_ASSERT(mRequestType == ParamsUnionType::TAddParams);
+      break;
+    case ResponseValue::TPutResponse: