Bug 772700 - 'IndexedDB - OOP from a JS component or JSM doesn't work'. r=khuey+mrbkap.
authorBen Turner <bent.mozilla@gmail.com>
Sat, 14 Jul 2012 07:24:20 -0400
changeset 99309 06ba7dd9f841264ef6506a173107e1ab8df76e1f
parent 99288 2ff61044edbd8c8418cbb00dd12e15788fb3e544
child 99310 247fb4c3ad5fda3569122ce341fb8a20ffa1740a
push id23118
push userryanvm@gmail.com
push dateSat, 14 Jul 2012 23:14:51 +0000
treeherdermozilla-central@d229299ec2be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs772700
milestone16.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 772700 - 'IndexedDB - OOP from a JS component or JSM doesn't work'. r=khuey+mrbkap.
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
dom/indexedDB/ipc/IndexedDBParent.h
dom/indexedDB/ipc/Makefile.in
dom/indexedDB/ipc/PIndexedDB.ipdl
dom/indexedDB/ipc/unit/head.js
dom/indexedDB/ipc/unit/xpcshell.ini
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/unit/head.js
dom/indexedDB/test/unit/head_idb.js
dom/indexedDB/test/unit/xpcshell.ini
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/TabChild.h
testing/xpcshell/xpcshell.ini
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -4,19 +4,26 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "IDBFactory.h"
 
 #include "nsIFile.h"
+#include "nsIJSContextStack.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptContext.h"
+#include "nsIXPConnect.h"
+#include "nsIXPCScriptable.h"
 
+#include "jsdbgapi.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/storage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsGlobalWindow.h"
 #include "nsHashKeys.h"
@@ -29,50 +36,53 @@
 #include "CheckPermissionsHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IndexedDatabaseManager.h"
 #include "Key.h"
 
-#include "mozilla/dom/PBrowserChild.h"
-#include "mozilla/dom/TabChild.h"
-using mozilla::dom::TabChild;
-
 #include "ipc/IndexedDBChild.h"
 
 USING_INDEXEDDB_NAMESPACE
 
+using mozilla::dom::ContentChild;
+using mozilla::dom::TabChild;
+
 namespace {
 
 struct ObjectStoreInfoMap
 {
   ObjectStoreInfoMap()
   : id(LL_MININT), info(nsnull) { }
 
   PRInt64 id;
   ObjectStoreInfo* info;
 };
 
 } // anonymous namespace
 
 IDBFactory::IDBFactory()
-: mOwningObject(nsnull), mActorChild(nsnull), mActorParent(nsnull)
+: mOwningObject(nsnull), mActorChild(nsnull), mActorParent(nsnull),
+  mRootedOwningObject(false)
 {
 }
 
 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__!");
   }
+  if (mRootedOwningObject) {
+    NS_DROP_JS_OBJECTS(this, IDBFactory);
+  }
 }
 
 // static
 nsresult
 IDBFactory::Create(nsPIDOMWindow* aWindow,
                    const nsACString& aASCIIOrigin,
                    IDBFactory** aFactory)
 {
@@ -148,16 +158,102 @@ IDBFactory::Create(JSContext* aCx,
   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;
 
+  if (!IndexedDatabaseManager::IsMainProcess()) {
+    ContentChild* contentChild = ContentChild::GetSingleton();
+    NS_ENSURE_TRUE(contentChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    IndexedDBChild* actor = new IndexedDBChild(origin);
+
+    contentChild->SendPIndexedDBConstructor(actor);
+
+    actor->SetFactory(factory);
+  }
+
+  factory.forget(aFactory);
+  return NS_OK;
+}
+
+// static
+nsresult
+IDBFactory::Create(IDBFactory** aFactory)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
+
+#ifdef DEBUG
+  {
+    nsIThreadJSContextStack* cxStack = nsContentUtils::ThreadJSContextStack();
+    NS_ASSERTION(cxStack, "Couldn't get ThreadJSContextStack!");
+
+    JSContext* lastCx;
+    if (NS_SUCCEEDED(cxStack->Peek(&lastCx))) {
+      NS_ASSERTION(!lastCx, "We should only be called from C++!");
+    }
+    else {
+      NS_ERROR("nsIThreadJSContextStack::Peek should never fail!");
+    }
+  }
+#endif
+
+  nsCString origin;
+  nsresult rv =
+    IndexedDatabaseManager::GetASCIIOriginFromWindow(nsnull, origin);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPrincipal> principal =
+    do_CreateInstance("@mozilla.org/nullprincipal;1");
+  NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
+
+  JSContext* cx = nsContentUtils::GetSafeJSContext();
+  NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
+
+  nsCxPusher pusher;
+  if (!pusher.Push(cx)) {
+    NS_WARNING("Failed to push safe JS context!");
+    return NS_ERROR_FAILURE;
+  }
+
+  JSAutoRequest ar(cx);
+
+  nsIXPConnect* xpc = nsContentUtils::XPConnect();
+  NS_ASSERTION(xpc, "This should never be null!");
+
+  nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
+  rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  JSObject* global;
+  rv = globalHolder->GetJSObject(&global);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // The CreateSandbox call returns a proxy to the actual sandbox object. We
+  // don't need a proxy here.
+  global = JS_UnwrapObject(global);
+
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, global)) {
+    NS_WARNING("Failed to enter compartment!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<IDBFactory> factory;
+  rv = Create(cx, global, getter_AddRefs(factory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_HOLD_JS_OBJECTS(factory, IDBFactory);
+  factory->mRootedOwningObject = true;
+
   factory.forget(aFactory);
   return NS_OK;
 }
 
 // static
 already_AddRefed<mozIStorageConnection>
 IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
 {
@@ -384,16 +480,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindow)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
   if (tmp->mOwningObject) {
     tmp->mOwningObject = nsnull;
   }
+  if (tmp->mRootedOwningObject) {
+    NS_DROP_JS_OBJECTS(tmp, IDBFactory);
+    tmp->mRootedOwningObject = false;
+  }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOwningObject)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 DOMCI_DATA(IDBFactory, IDBFactory)
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -31,35 +31,43 @@ class IDBFactory MOZ_FINAL : public nsII
 {
   typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBFactory)
   NS_DECL_NSIIDBFACTORY
 
+  // Called when using IndexedDB from a window in a different process.
   static nsresult Create(nsPIDOMWindow* aWindow,
                          const nsACString& aASCIIOrigin,
                          IDBFactory** aFactory);
 
+  // Called when using IndexedDB from a window in the current process.
   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;
   }
 
+  // Called when using IndexedDB from a JS component or a JSM in the current
+  // process.
   static nsresult Create(JSContext* aCx,
                          JSObject* aOwningObject,
                          IDBFactory** aFactory);
 
+  // Called when using IndexedDB from a JS component or a JSM in a different
+  // process.
+  static nsresult Create(IDBFactory** aFactory);
+
   static already_AddRefed<mozIStorageConnection>
   GetConnection(const nsAString& aDatabaseFilePath);
 
   static nsresult
   LoadDatabaseInformation(mozIStorageConnection* aConnection,
                           nsIAtom* aDatabaseId,
                           PRUint64* aVersion,
                           ObjectStoreInfoArray& aObjectStores);
@@ -85,26 +93,34 @@ public:
 
   void
   SetActor(IndexedDBParent* aActorParent)
   {
     NS_ASSERTION(!aActorParent || !mActorParent, "Shouldn't have more than one!");
     mActorParent = aActorParent;
   }
 
+  const nsCString&
+  GetASCIIOrigin() const
+  {
+    return mASCIIOrigin;
+  }
+
 private:
   IDBFactory();
   ~IDBFactory();
 
   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;
+
+  bool mRootedOwningObject;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbfactory_h__
--- a/dom/indexedDB/ipc/IndexedDBParent.h
+++ b/dom/indexedDB/ipc/IndexedDBParent.h
@@ -17,16 +17,17 @@
 #include "mozilla/dom/indexedDB/PIndexedDBTransactionParent.h"
 
 #include "mozilla/Attributes.h"
 
 #include "nsIDOMEventListener.h"
 
 namespace mozilla {
 namespace dom {
+class ContentParent;
 class TabParent;
 }
 }
 
 class nsIDOMEvent;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
@@ -124,16 +125,17 @@ public:
 };
 
 /*******************************************************************************
  * IndexedDBParent
  ******************************************************************************/
 
 class IndexedDBParent : public PIndexedDBParent
 {
+  friend class mozilla::dom::ContentParent;
   friend class mozilla::dom::TabParent;
 
   nsRefPtr<IDBFactory> mFactory;
   nsCString mASCIIOrigin;
 
 public:
   IndexedDBParent();
   virtual ~IndexedDBParent();
--- a/dom/indexedDB/ipc/Makefile.in
+++ b/dom/indexedDB/ipc/Makefile.in
@@ -26,15 +26,25 @@ EXPORTS_mozilla/dom/indexedDB = Serializ
 
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/indexedDB \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
-MOCHITEST_FILES = \
-  test_ipc.html \
-  $(NULL)
+MOCHITEST_FILES = test_ipc.html
+
+XPCSHELL_TESTS = unit
+
+# We're copying tests from another directory so this check is wrong for us.
+NO_XPCSHELL_MANIFEST_CHECK = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
+
+# Copy all the normal xpcshell tests from the regular unit directory.
+copy-xpcshell-tests:
+	$(DIR_INSTALL) $(wildcard $(topsrcdir)/dom/indexedDB/test/unit/test_*.js) \
+    $(testxpcobjdir)/$(relativesrcdir)/$(XPCSHELL_TESTS)
+
+libs-xpcshell-tests: copy-xpcshell-tests
--- a/dom/indexedDB/ipc/PIndexedDB.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDB.ipdl
@@ -1,23 +1,24 @@
 /* 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 protocol PBrowser;
+include protocol PContent;
 include protocol PIndexedDBDatabase;
 include protocol PIndexedDBDeleteDatabaseRequest;
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 protocol PIndexedDB
 {
-  manager PBrowser;
+  manager PBrowser or PContent;
 
   manages PIndexedDBDatabase;
   manages PIndexedDBDeleteDatabaseRequest;
 
 parent:
   __delete__();
 
   PIndexedDBDatabase(nsString name, uint64_t version);
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/ipc/unit/head.js
@@ -0,0 +1,18 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const INDEXEDDB_UNIT_DIR = "../../test/unit/";
+const INDEXEDDB_HEAD_FILE = INDEXEDDB_UNIT_DIR + "head.js";
+
+function run_test() {
+  // IndexedDB needs a profile.
+  do_get_profile();
+
+  let thisTest = _TEST_FILE.toString().replace(/\\/g, "/");
+  thisTest = thisTest.substring(thisTest.lastIndexOf("/") + 1);
+
+  _HEAD_FILES.push(do_get_file(INDEXEDDB_HEAD_FILE).path.replace(/\\/g, "/"));
+  run_test_in_child(INDEXEDDB_UNIT_DIR + thisTest);
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/ipc/unit/xpcshell.ini
@@ -0,0 +1,60 @@
+[DEFAULT]
+head = head.js
+tail =
+
+# When adding files here please also update test/unit/xpcshell.ini!
+
+[test_add_put.js]
+[test_add_twice_failure.js]
+[test_advance.js]
+[test_autoIncrement_indexes.js]
+[test_clear.js]
+[test_complex_keyPaths.js]
+[test_count.js]
+[test_create_index.js]
+[test_create_index_with_integer_keys.js]
+[test_create_objectStore.js]
+[test_cursor_mutation.js]
+[test_cursor_update_updates_indexes.js]
+[test_cursors.js]
+[test_deleteDatabase.js]
+[test_event_source.js]
+[test_getAll.js]
+[test_global_data.js]
+[test_index_empty_keyPath.js]
+[test_index_getAll.js]
+[test_index_getAllObjects.js]
+[test_index_object_cursors.js]
+[test_index_update_delete.js]
+[test_indexes.js]
+[test_indexes_bad_values.js]
+[test_key_requirements.js]
+[test_keys.js]
+[test_multientry.js]
+[test_names_sorted.js]
+[test_object_identity.js]
+[test_objectCursors.js]
+[test_objectStore_inline_autoincrement_key_added_on_put.js]
+[test_objectStore_remove_values.js]
+[test_odd_result_order.js]
+[test_open_empty_db.js]
+[test_open_objectStore.js]
+[test_optionalArguments.js]
+[test_overlapping_transactions.js]
+[test_put_get_values.js]
+[test_put_get_values_autoIncrement.js]
+[test_remove_index.js]
+[test_remove_objectStore.js]
+[test_request_readyState.js]
+[test_setVersion.js]
+[test_setVersion_abort.js]
+[test_setVersion_events.js]
+[test_setVersion_exclusion.js]
+[test_success_events_after_abort.js]
+[test_traffic_jam.js]
+[test_transaction_abort.js]
+[test_transaction_lifetimes.js]
+[test_transaction_lifetimes_nested.js]
+[test_transaction_ordering.js]
+
+# When adding files here please also update test/unit/xpcshell.ini!
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -2,20 +2,21 @@
 # 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/.
 
 DEPTH = ../../..
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 relativesrcdir = dom/indexedDB/test
-DIRS += unit
 
 include $(DEPTH)/config/autoconf.mk
 
+TEST_DIRS = unit
+
 XPCSHELL_TESTS = unit
 
 MOCHITEST_FILES = \
   bfcache_iframe1.html \
   bfcache_iframe2.html \
   error_events_abort_transactions_iframe.html \
   event_propagation_iframe.html \
   exceptions_in_events_iframe.html \
@@ -120,9 +121,8 @@ MOCHITEST_BROWSER_FILES = \
   browser_quotaPromptDatabases.js \
   browser_quotaPromptDelete.html \
   browser_quotaPromptDelete.js \
   head.js \
   $(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
-
rename from dom/indexedDB/test/unit/head_idb.js
rename to dom/indexedDB/test/unit/head.js
--- a/dom/indexedDB/test/unit/head_idb.js
+++ b/dom/indexedDB/test/unit/head.js
@@ -11,23 +11,16 @@ const IDBTransaction = Ci.nsIIDBTransact
 const IDBOpenDBRequest = Ci.nsIIDBOpenDBRequest;
 const IDBVersionChangeEvent = Ci.nsIIDBVersionChangeEvent
 const IDBDatabase = Ci.nsIIDBDatabase
 const IDBFactory = Ci.nsIIDBFactory
 const IDBIndex = Ci.nsIIDBIndex
 const IDBObjectStore = Ci.nsIIDBObjectStore
 const IDBRequest = Ci.nsIIDBRequest
 
-// XPCShell does not get a profile by default.
-do_get_profile();
-
-var idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"].
-                 getService(Ci.nsIIndexedDatabaseManager);
-idbManager.initWindowless(this);
-
 function is(a, b, msg) {
   dump("is(" + a + ", " + b + ", \"" + msg + "\")");
   do_check_eq(a, b, Components.stack.caller);
 }
 
 function ok(cond, msg) {
   dump("ok(" + cond + ", \"" + msg + "\")");
   do_check_true(!!cond, Components.stack.caller); 
@@ -47,16 +40,23 @@ function todo(condition, name, diag) {
 }
 
 function run_test() {
   runTest();
 };
 
 function runTest()
 {
+  // XPCShell does not get a profile by default.
+  do_get_profile();
+
+  var idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"].
+                   getService(Ci.nsIIndexedDatabaseManager);
+  idbManager.initWindowless(this);
+
   do_test_pending();
   testGenerator.next();
 }
 
 function finishTest()
 {
   do_execute_soon(function(){
     testGenerator.close();
--- a/dom/indexedDB/test/unit/xpcshell.ini
+++ b/dom/indexedDB/test/unit/xpcshell.ini
@@ -1,11 +1,13 @@
 [DEFAULT]
-head = head_idb.js
-tail = 
+head = head.js
+tail =
+
+# When adding files here please also update ipc/unit/xpcshell.ini!
 
 [test_add_put.js]
 [test_add_twice_failure.js]
 [test_advance.js]
 [test_autoIncrement_indexes.js]
 [test_clear.js]
 [test_complex_keyPaths.js]
 [test_count.js]
@@ -48,9 +50,11 @@ tail =
 [test_setVersion_abort.js]
 [test_setVersion_events.js]
 [test_setVersion_exclusion.js]
 [test_success_events_after_abort.js]
 [test_traffic_jam.js]
 [test_transaction_abort.js]
 [test_transaction_lifetimes.js]
 [test_transaction_lifetimes_nested.js]
-[test_transaction_ordering.js]
\ No newline at end of file
+[test_transaction_ordering.js]
+
+# When adding files here please also update ipc/unit/xpcshell.ini!
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -83,16 +83,17 @@
 
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 using namespace mozilla::places;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
+using namespace mozilla::dom::indexedDB;
 
 namespace mozilla {
 namespace dom {
 
 class MemoryReportRequestChild : public PMemoryReportRequestChild
 {
 public:
     MemoryReportRequestChild();
@@ -424,16 +425,30 @@ ContentChild::AllocPHal()
 
 bool
 ContentChild::DeallocPHal(PHalChild* aHal)
 {
     delete aHal;
     return true;
 }
 
+PIndexedDBChild*
+ContentChild::AllocPIndexedDB()
+{
+  NS_NOTREACHED("Should never get here!");
+  return NULL;
+}
+
+bool
+ContentChild::DeallocPIndexedDB(PIndexedDBChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 PTestShellChild*
 ContentChild::AllocPTestShell()
 {
     return new TestShellChild();
 }
 
 bool
 ContentChild::DeallocPTestShell(PTestShellChild* shell)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -66,16 +66,19 @@ public:
     AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
                         const PRUint32& processType);
     virtual bool
     DeallocPCrashReporter(PCrashReporterChild*);
 
     NS_OVERRIDE virtual PHalChild* AllocPHal();
     NS_OVERRIDE virtual bool DeallocPHal(PHalChild*);
 
+    virtual PIndexedDBChild* AllocPIndexedDB();
+    virtual bool DeallocPIndexedDB(PIndexedDBChild* aActor);
+
     virtual PMemoryReportRequestChild*
     AllocPMemoryReportRequest();
 
     virtual bool
     DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor);
 
     virtual bool
     RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -78,28 +78,33 @@
 #include "mozilla/dom/sms/SmsParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "nsDebugImpl.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "mozilla/Preferences.h"
 
+#include "IDBFactory.h"
+#include "IndexedDatabaseManager.h"
+#include "IndexedDBParent.h"
+
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
 
 using mozilla::Preferences;
 using namespace mozilla::ipc;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::net;
 using namespace mozilla::places;
 using mozilla::unused; // heh
 using base::KillProcess;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
+using namespace mozilla::dom::indexedDB;
 
 namespace mozilla {
 namespace dom {
 
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 
 class MemoryReportRequestParent : public PMemoryReportRequestParent
 {
@@ -824,16 +829,52 @@ ContentParent::AllocPHal()
 
 bool
 ContentParent::DeallocPHal(PHalParent* aHal)
 {
     delete aHal;
     return true;
 }
 
+PIndexedDBParent*
+ContentParent::AllocPIndexedDB()
+{
+  return new IndexedDBParent();
+}
+
+bool
+ContentParent::DeallocPIndexedDB(PIndexedDBParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+bool
+ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor)
+{
+  nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
+  NS_ENSURE_TRUE(mgr, false);
+
+  if (!IndexedDatabaseManager::IsMainProcess()) {
+    NS_RUNTIMEABORT("Not supported yet!");
+  }
+
+  nsRefPtr<IDBFactory> factory;
+  nsresult rv = IDBFactory::Create(getter_AddRefs(factory));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  NS_ASSERTION(factory, "This should never be null!");
+
+  IndexedDBParent* actor = static_cast<IndexedDBParent*>(aActor);
+  actor->mFactory = factory;
+  actor->mASCIIOrigin = factory->GetASCIIOrigin();
+
+  return true;
+}
+
 PMemoryReportRequestParent*
 ContentParent::AllocPMemoryReportRequest()
 {
   MemoryReportRequestParent* parent = new MemoryReportRequestParent();
   return parent;
 }
 
 bool
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -118,16 +118,23 @@ private:
     virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
     virtual bool RecvPCrashReporterConstructor(PCrashReporterParent* actor,
                                                const NativeThreadId& tid,
                                                const PRUint32& processType);
 
     NS_OVERRIDE virtual PHalParent* AllocPHal();
     NS_OVERRIDE virtual bool DeallocPHal(PHalParent*);
 
+    virtual PIndexedDBParent* AllocPIndexedDB();
+
+    virtual bool DeallocPIndexedDB(PIndexedDBParent* aActor);
+
+    virtual bool
+    RecvPIndexedDBConstructor(PIndexedDBParent* aActor);
+
     virtual PMemoryReportRequestParent* AllocPMemoryReportRequest();
     virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
 
     virtual PTestShellParent* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellParent* shell);
 
     virtual PAudioParent* AllocPAudio(const PRInt32&,
                                      const PRInt32&,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PAudio;
 include protocol PBrowser;
 include protocol PCrashReporter;
 include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PHal;
+include protocol PIndexedDB;
 include protocol PMemoryReportRequest;
 include protocol PNecko;
 include protocol PSms;
 include protocol PStorage;
 include protocol PTestShell;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
@@ -97,16 +98,17 @@ union DeviceStorageParams
 rpc protocol PContent
 {
     manages PAudio;
     manages PBrowser;
     manages PCrashReporter;
     manages PDeviceStorageRequest;
     manages PExternalHelperApp;
     manages PHal;
+    manages PIndexedDB;
     manages PMemoryReportRequest;
     manages PNecko;
     manages PSms;
     manages PStorage;
     manages PTestShell;
 
 both:
     // Depending on exactly how the new browser is being created, it might be
@@ -162,16 +164,18 @@ parent:
     PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
 
     PDeviceStorageRequest(DeviceStorageParams params);
 
     sync PCrashReporter(NativeThreadId tid, PRUint32 processType);
 
     PHal();
 
+    PIndexedDB();
+
     PNecko();
 
     PSms();
     
     PStorage(StorageConstructData data);
 
     // Services remoting
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -239,17 +239,17 @@ protected:
     NS_OVERRIDE
     virtual bool RecvDestroy();
 
     bool DispatchWidgetEvent(nsGUIEvent& event);
 
     virtual PIndexedDBChild* AllocPIndexedDB(const nsCString& aASCIIOrigin,
                                              bool* /* aAllowed */);
 
-    virtual bool DeallocPIndexedDB(PIndexedDBChild* actor);
+    virtual bool DeallocPIndexedDB(PIndexedDBChild* aActor);
 
 private:
     void ActorDestroy(ActorDestroyReason why);
 
     bool InitTabChildGlobal();
     bool InitWidget(const nsIntSize& size);
     void DestroyWindow();
 
--- a/testing/xpcshell/xpcshell.ini
+++ b/testing/xpcshell/xpcshell.ini
@@ -123,8 +123,12 @@ run-if.config = ipc
 [include:netwerk/cookie/test/unit_ipc/xpcshell.ini]
 [include:toolkit/components/contentprefs/tests/unit_ipc/xpcshell.ini]
 [include:uriloader/exthandler/tests/unit_ipc/xpcshell.ini]
 
 [include:modules/libmar/tests/unit/xpcshell.ini]
 skip-if = os == "android"
 
 [include:tools/profiler/tests/xpcshell.ini]
+
+[include:dom/indexedDB/ipc/unit/xpcshell.ini]
+run-if.config = ipc
+skip-if.os != "win"