Bug 584946 - e10s: localStorage, r=honzab, a=blocking-fennec2.0b3+
authorJosh Matthews <josh@joshmatthews.net>
Thu, 18 Nov 2010 20:15:23 -0500
changeset 58092 4973e2b9a905c183a573097f0bf369d7fbb8e50a
parent 58091 cbdf3ff3e88af95430416c0043e63ee6b0359643
child 58093 43a10e7fbef398cd9d629e7cb094f01a5eb175ab
push id17151
push userhonzab.moz@firemni.cz
push dateTue, 23 Nov 2010 19:38:40 +0000
treeherdermozilla-central@4973e2b9a905 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab, blocking-fennec2
bugs584946
milestone2.0b8pre
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 584946 - e10s: localStorage, r=honzab, a=blocking-fennec2.0b3+
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PContent.ipdl
dom/src/storage/Makefile.in
dom/src/storage/PStorage.ipdl
dom/src/storage/StorageChild.cpp
dom/src/storage/StorageChild.h
dom/src/storage/StorageParent.cpp
dom/src/storage/StorageParent.h
dom/src/storage/ipdl.mk
dom/src/storage/nsDOMStorage.cpp
dom/src/storage/nsDOMStorage.h
dom/src/storage/nsDOMStorageDBWrapper.cpp
dom/src/storage/nsDOMStorageDBWrapper.h
dom/src/storage/nsDOMStorageMemoryDB.cpp
dom/src/storage/nsDOMStorageMemoryDB.h
dom/src/storage/nsDOMStoragePersistentDB.cpp
dom/src/storage/nsDOMStoragePersistentDB.h
ipc/ipdl/Makefile.in
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -49,16 +49,17 @@
 #include "TabChild.h"
 #include "AudioChild.h"
 
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/jsipc/PContextWrapperChild.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
+#include "mozilla/dom/StorageChild.h"
 
 #include "nsAudioStream.h"
 
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
 #include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
@@ -335,16 +336,31 @@ ContentChild::AllocPExternalHelperApp(co
 bool
 ContentChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
 {
     ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
     child->Release();
     return true;
 }
 
+PStorageChild*
+ContentChild::AllocPStorage(const StorageConstructData& aData)
+{
+    NS_NOTREACHED("We should never be manually allocating PStorageChild actors");
+    return nsnull;
+}
+
+bool
+ContentChild::DeallocPStorage(PStorageChild* aActor)
+{
+    StorageChild* child = static_cast<StorageChild*>(aActor);
+    child->ReleaseIPDLReference();
+    return true;
+}
+
 bool
 ContentChild::RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                  const InfallibleTArray<ResourceMapping>& resources,
                                  const InfallibleTArray<OverrideMapping>& overrides)
 {
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryContent* chromeRegistry =
         static_cast<nsChromeRegistryContent*>(registrySvc.get());
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -51,16 +51,17 @@ struct ResourceMapping;
 struct OverrideMapping;
 
 namespace mozilla {
 namespace dom {
 
 class AlertObserver;
 class PrefObserver;
 class ConsoleListener;
+class PStorageChild;
 
 class ContentChild : public PContentChild
 {
 public:
     ContentChild();
     virtual ~ContentChild();
 
     bool Init(MessageLoop* aIOLoop,
@@ -95,16 +96,19 @@ public:
             const IPC::URI& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const PRInt64& aContentLength,
             const IPC::URI& aReferrer);
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
 
+    virtual PStorageChild* AllocPStorage(const StorageConstructData& aData);
+    virtual bool DeallocPStorage(PStorageChild* aActor);
+
     virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                     const InfallibleTArray<ResourceMapping>& resources,
                                     const InfallibleTArray<OverrideMapping>& overrides);
 
     virtual bool RecvSetOffline(const PRBool& offline);
 
     virtual bool RecvNotifyVisited(const IPC::URI& aURI);
     // auto remove when alertfinished is received.
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -68,16 +68,17 @@
 #include "nsConsoleMessage.h"
 #include "AudioParent.h"
 
 #ifdef MOZ_PERMISSIONS
 #include "nsPermissionManager.h"
 #endif
 
 #include "mozilla/dom/ExternalHelperAppParent.h"
+#include "mozilla/dom/StorageParent.h"
 #include "nsAccelerometer.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 using namespace mozilla::places;
 using mozilla::MonitorAutoEnter;
 
 namespace mozilla {
@@ -411,16 +412,29 @@ ContentParent::AllocPExternalHelperApp(c
 bool
 ContentParent::DeallocPExternalHelperApp(PExternalHelperAppParent* aService)
 {
     ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
     parent->Release();
     return true;
 }
 
+PStorageParent*
+ContentParent::AllocPStorage(const StorageConstructData& aData)
+{
+    return new StorageParent(aData);
+}
+
+bool
+ContentParent::DeallocPStorage(PStorageParent* aActor)
+{
+    delete aActor;
+    return true;
+}
+
 void
 ContentParent::ReportChildAlreadyBlocked()
 {
     if (!mRunToCompletionDepth) {
 #ifdef DEBUG
         printf("Running to completion...\n");
 #endif
         mRunToCompletionDepth = 1;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -57,16 +57,17 @@ namespace mozilla {
 
 namespace ipc {
 class TestShellParent;
 }
 
 namespace dom {
 
 class TabParent;
+class PStorageParent;
 
 class ContentParent : public PContentParent
                     , public nsIObserver
                     , public nsIThreadObserver
                     , public nsIDOMGeoPositionCallback
                     , public nsIAccelerationListener
 {
 private:
@@ -129,16 +130,19 @@ private:
             const IPC::URI& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const PRInt64& aContentLength,
             const IPC::URI& aReferrer);
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
 
+    virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
+    virtual bool DeallocPStorage(PStorageParent* aActor);
+
     virtual bool RecvReadPrefsArray(InfallibleTArray<PrefTuple> *retValue);
 
     void EnsurePrefService();
 
     virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions);
 
     virtual bool RecvStartVisitedQuery(const IPC::URI& uri);
 
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -79,16 +79,17 @@ include $(topsrcdir)/config/rules.mk
 LOCAL_INCLUDES += \
 		-I$(srcdir)/../../content/base/src \
 		-I$(srcdir)/../../content/events/src \
 		-I$(srcdir)/../../toolkit/components/places/src \
 		-I$(topsrcdir)/chrome/src \
 		-I$(topsrcdir)/uriloader/exthandler \
 		-I$(srcdir)/../../netwerk/base/src \
 		-I$(srcdir)/../src/base \
+		-I$(srcdir)/../src/storage \
 		-I$(srcdir)/../../xpcom/base \
 		-I$(topsrcdir)/extensions/cookie \
 		$(NULL)
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
 
 ifdef MOZ_PERMISSIONS
 DEFINES += -DMOZ_PERMISSIONS
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -36,42 +36,62 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PAudio;
 include protocol PBrowser;
 include protocol PTestShell;
 include protocol PNecko;
 include protocol PExternalHelperApp;
+include protocol PStorage;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
 include "nsGeoPositionIPCSerialiser.h";
 include "PPrefTuple.h";
 
 using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
 using IPC::URI;
 using IPC::Permission;
+using mozilla::null_t;
 
 namespace mozilla {
 namespace dom {
 
+// Data required to clone an existing DOMStorageImpl in the parent
+struct StorageClone
+{
+    // Existing cross-process storage actor to clone
+    PStorage actor;
+    // Result of calling IsCallerSecure() in the child
+    bool callerSecure;
+};
+
+// When creating a new PStorage protocol, an existing one can be
+// cloned (see nsDOMStorage2::Clone)
+union StorageConstructData
+{
+    null_t;
+    StorageClone;
+};
+
 rpc protocol PContent
 {
     manages PAudio;
     manages PBrowser;
     manages PTestShell;
     manages PNecko;
     manages PExternalHelperApp;
+    manages PStorage;
 
 child:
     PBrowser(PRUint32 chromeFlags);
 
     PTestShell();
 
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides);
@@ -88,16 +108,18 @@ child:
 
     // nsIPermissionManager messages
     AddPermission(Permission permission);
 
     AccelerationChanged(double x, double y, double z);
 
 parent:
     PNecko();
+    
+    PStorage(StorageConstructData data);
 
     PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
 
     // Services remoting
 
     async StartVisitedQuery(URI uri);
     async VisitURI(URI uri, URI referrer, PRUint32 flags);
     async SetURITitle(URI uri, nsString title);
--- a/dom/src/storage/Makefile.in
+++ b/dom/src/storage/Makefile.in
@@ -49,20 +49,29 @@ LIBXUL_LIBRARY = 1
 
 
 CPPSRCS =                  \
        nsDOMStorage.cpp    \
        $(NULL)
 
 ifdef MOZ_STORAGE
 CPPSRCS += nsDOMStorageDBWrapper.cpp nsDOMStoragePersistentDB.cpp nsDOMStorageMemoryDB.cpp
+
+ifdef MOZ_IPC
+CPPSRCS += StorageChild.cpp StorageParent.cpp
+
+EXPORTS_NAMESPACES = mozilla/dom
+EXPORTS_mozilla/dom = StorageChild.h StorageParent.h
+endif
 endif
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 LOCAL_INCLUDES = \
                 -I$(topsrcdir)/dom/base \
 		-I$(topsrcdir)/content/events/src
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/src/storage/PStorage.ipdl
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Content App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+include protocol PContent;
+
+using mozilla::null_t;
+
+namespace mozilla {
+namespace dom {
+
+struct ItemData
+{
+  nsString value;
+  PRBool secure;
+};
+
+// A cross-process GetValue result -- either null, or containing the parameters
+// with which to initialize an nsIDOMStorageItem.
+union StorageItem
+{
+  null_t;
+  ItemData;
+};
+
+// This protocol is little more than a thin wrapper around the DOMStorageBase
+// class in nsDOMStorage.h.  The child implementation simply forwards the
+// arguments for any given call to the parent, and returns the result.
+sync protocol PStorage
+{
+  manager PContent;
+
+parent:
+  __delete__();
+
+  Init(bool useDB, bool canUseChromePersist, nsCString domain,
+       nsCString scopeDBKey, nsCString quotaDomainDBKey,
+       nsCString quotaETLDplus1DomainDBKey, PRUint32 storageType);
+  
+  sync GetKeys(bool callerSecure)
+      returns (nsString[] keys);
+  sync GetLength(bool callerSecure)
+      returns (PRUint32 length, nsresult rv);
+  sync GetKey(bool callerSecure, PRUint32 index)
+      returns (nsString key, nsresult rv);
+  sync GetValue(bool callerSecure, nsString key)
+      returns (StorageItem item, nsresult rv);
+  sync SetValue(bool callerSecure, nsString key, nsString data)
+      returns (nsString oldValue, nsresult rv);
+  sync RemoveValue(bool callerSecure, nsString key)
+      returns (nsString oldValue, nsresult rv);
+  sync Clear(bool callerSecure)
+      returns (PRInt32 oldCount, nsresult rv);
+
+  sync GetDBValue(nsString key)
+      returns (nsString value, PRBool secure, nsresult rv);
+  sync SetDBValue(nsString key, nsString value, PRBool secure)
+      returns (nsresult rv);
+  sync SetSecure(nsString key, PRBool secure)
+      returns (nsresult rv);
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/src/storage/StorageChild.cpp
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla DOM Storage.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "StorageChild.h"
+#include "mozilla/dom/ContentChild.h"
+#include "nsDOMError.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_1(StorageChild, mStorage)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageChild)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageChild)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP_(nsrefcnt) StorageChild::Release(void)
+{
+  NS_PRECONDITION(0 != mRefCnt, "dup release");
+  NS_ASSERT_OWNINGTHREAD(StorageChild);
+  nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(StorageChild)::Upcast(this);
+  nsrefcnt count = mRefCnt.decr(base);
+  NS_LOG_RELEASE(this, count, "StorageChild");
+  if (count == 1 && mIPCOpen) {
+    Send__delete__(this);
+    return 0;
+  }
+  if (count == 0) {
+    mRefCnt.stabilizeForDeletion(base);
+    delete this;
+    return 0;
+  }
+  return count;
+}
+
+StorageChild::StorageChild(nsDOMStorage* aOwner)
+: mStorage(aOwner)
+, mIPCOpen(false)
+{
+}
+
+StorageChild::StorageChild(nsDOMStorage* aOwner, StorageChild& aOther)
+: DOMStorageBase(aOther)
+, mStorage(aOwner)
+, mIPCOpen(false)
+{
+}
+
+void
+StorageChild::AddIPDLReference()
+{
+  NS_ABORT_IF_FALSE(!mIPCOpen, "Attempting to retain multiple IPDL references");
+  mIPCOpen = true;
+  AddRef();
+}
+
+void
+StorageChild::ReleaseIPDLReference()
+{
+  NS_ABORT_IF_FALSE(mIPCOpen, "Attempting to release non-existent IPDL reference");
+  mIPCOpen = false;
+  Release();
+}
+
+bool
+StorageChild::CacheStoragePermissions()
+{
+  nsDOMStorage* storage = static_cast<nsDOMStorage*>(mStorage.get());
+  return storage->CacheStoragePermissions();
+}
+
+void
+StorageChild::InitRemote()
+{
+  ContentChild* child = ContentChild::GetSingleton();
+  AddIPDLReference();
+  child->SendPStorageConstructor(this, null_t());
+  SendInit(mUseDB, mCanUseChromePersist, mDomain, mScopeDBKey,
+           mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
+}
+
+void
+StorageChild::InitAsSessionStorage(nsIURI* aDomainURI)
+{
+  DOMStorageBase::InitAsSessionStorage(aDomainURI);
+  InitRemote();
+}
+
+void
+StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist)
+{
+  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist);
+  InitRemote();
+}
+
+void
+StorageChild::InitAsGlobalStorage(const nsACString& aDomainDemanded)
+{
+  DOMStorageBase::InitAsGlobalStorage(aDomainDemanded);
+  InitRemote();
+}
+
+nsTArray<nsString>*
+StorageChild::GetKeys(bool aCallerSecure)
+{
+  InfallibleTArray<nsString> remoteKeys;
+  SendGetKeys(aCallerSecure, &remoteKeys);
+  nsTArray<nsString>* keys = new nsTArray<nsString>;
+  *keys = remoteKeys;
+  return keys;
+}
+
+nsresult
+StorageChild::GetLength(bool aCallerSecure, PRUint32* aLength)
+{
+  nsresult rv;
+  SendGetLength(aCallerSecure, aLength, &rv);
+  return rv;
+}
+
+nsresult
+StorageChild::GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey)
+{
+  nsresult rv;
+  nsString key;
+  SendGetKey(aCallerSecure, aIndex, &key, &rv);
+  if (NS_FAILED(rv))
+    return rv;
+  aKey = key;
+  return NS_OK;
+}
+
+// Unlike other cross-process forwarding methods, GetValue needs to replicate
+// the following behaviour of DOMStorageImpl::GetValue:
+//
+// - if a security error occurs, or the item isn't found, return null without
+//   propogating the error.
+//
+// If DOMStorageImpl::GetValue ever changes its behaviour, this should be kept
+// in sync.
+nsIDOMStorageItem*
+StorageChild::GetValue(bool aCallerSecure, const nsAString& aKey, nsresult* rv)
+{
+  nsresult rv2 = *rv = NS_OK;
+  StorageItem storageItem;
+  SendGetValue(aCallerSecure, nsString(aKey), &storageItem, &rv2);
+  if (rv2 == NS_ERROR_DOM_SECURITY_ERR || rv2 == NS_ERROR_DOM_NOT_FOUND_ERR)
+    return nsnull;
+  *rv = rv2;
+  if (NS_FAILED(*rv) || storageItem.type() == StorageItem::Tnull_t)
+    return nsnull;
+  const ItemData& data = storageItem.get_ItemData();
+  nsIDOMStorageItem* item = new nsDOMStorageItem(this, aKey, data.value(),
+                                                 data.secure());
+  return item;
+}
+
+nsresult
+StorageChild::SetValue(bool aCallerSecure, const nsAString& aKey,
+                       const nsAString& aData, nsAString& aOldData)
+{
+  nsresult rv;
+  nsString oldData;
+  SendSetValue(aCallerSecure, nsString(aKey), nsString(aData), &oldData, &rv);
+  if (NS_FAILED(rv))
+    return rv;
+  aOldData = oldData;
+  return NS_OK;
+}
+
+nsresult
+StorageChild::RemoveValue(bool aCallerSecure, const nsAString& aKey,
+                          nsAString& aOldData)
+{
+  nsresult rv;
+  nsString oldData;
+  SendRemoveValue(aCallerSecure, nsString(aKey), &oldData, &rv);
+  if (NS_FAILED(rv))
+    return rv;
+  aOldData = oldData;
+  return NS_OK;
+}
+
+nsresult
+StorageChild::Clear(bool aCallerSecure, PRInt32* aOldCount)
+{
+  nsresult rv;
+  PRInt32 oldCount;
+  SendClear(aCallerSecure, &oldCount, &rv);
+  if (NS_FAILED(rv))
+    return rv;
+  *aOldCount = oldCount;
+  return NS_OK;
+}
+
+bool
+StorageChild::CanUseChromePersist()
+{
+  return mCanUseChromePersist;
+}
+
+nsresult
+StorageChild::GetDBValue(const nsAString& aKey, nsAString& aValue,
+                         PRBool* aSecure)
+{
+  nsresult rv;
+  nsString value;
+  SendGetDBValue(nsString(aKey), &value, aSecure, &rv);
+  aValue = value;
+  return rv;
+}
+
+nsresult
+StorageChild::SetDBValue(const nsAString& aKey,
+                         const nsAString& aValue,
+                         PRBool aSecure)
+{
+  nsresult rv;
+  SendSetDBValue(nsString(aKey), nsString(aValue), aSecure, &rv);
+  return rv;
+}
+
+nsresult
+StorageChild::SetSecure(const nsAString& aKey, PRBool aSecure)
+{
+  nsresult rv;
+  SendSetSecure(nsString(aKey), aSecure, &rv);
+  return rv;
+}
+
+nsresult
+StorageChild::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat)
+{
+  StorageChild* other = static_cast<StorageChild*>(aThat);
+  ContentChild* child = ContentChild::GetSingleton();
+  StorageClone clone(nsnull, other, aCallerSecure);
+  AddIPDLReference();
+  child->SendPStorageConstructor(this, clone);
+  SendInit(mUseDB, mCanUseChromePersist, mDomain, mScopeDBKey,
+           mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
+  return NS_OK;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/src/storage/StorageChild.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla DOM Storage.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_StorageChild_h
+#define mozilla_dom_StorageChild_h
+
+#include "mozilla/dom/PStorageChild.h"
+#include "nsDOMStorage.h"
+#include "nsCycleCollectionParticipant.h"
+
+namespace mozilla {
+namespace dom {
+
+class StorageChild : public PStorageChild
+                   , public DOMStorageBase
+{
+public:
+  NS_DECL_CYCLE_COLLECTION_CLASS(StorageChild)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  
+  StorageChild(nsDOMStorage* aOwner);
+  StorageChild(nsDOMStorage* aOwner, StorageChild& aOther);
+
+  virtual void InitAsSessionStorage(nsIURI* aDomainURI);
+  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist);
+  virtual void InitAsGlobalStorage(const nsACString& aDomainDemanded);
+
+  virtual bool CacheStoragePermissions();
+  
+  virtual nsTArray<nsString>* GetKeys(bool aCallerSecure);
+  virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength);
+  virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey);
+  virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey,
+                                      nsresult* rv);
+  virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey,
+                            const nsAString& aData, nsAString& aOldValue);
+  virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey,
+                               nsAString& aOldValue);
+  virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount);
+
+  virtual bool CanUseChromePersist();
+
+  virtual nsresult GetDBValue(const nsAString& aKey,
+                              nsAString& aValue,
+                              PRBool* aSecure);
+  virtual nsresult SetDBValue(const nsAString& aKey,
+                              const nsAString& aValue,
+                              PRBool aSecure);
+  virtual nsresult SetSecure(const nsAString& aKey, PRBool aSecure);
+
+  virtual nsresult CloneFrom(bool aCallerSecure, DOMStorageBase* aThat);
+
+  void AddIPDLReference();
+  void ReleaseIPDLReference();
+
+private:
+  void InitRemote();
+
+  // Unimplemented
+  StorageChild(const StorageChild&);
+
+  nsCOMPtr<nsIDOMStorageObsolete> mStorage;
+  bool mIPCOpen;
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/src/storage/StorageParent.cpp
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla DOM Storage.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "StorageParent.h"
+#include "mozilla/dom/PContentParent.h"
+#include "mozilla/unused.h"
+#include "nsDOMString.h"
+
+using mozilla::unused;
+
+namespace mozilla {
+namespace dom {
+
+StorageParent::StorageParent(const StorageConstructData& aData)
+{
+  if (aData.type() == StorageConstructData::Tnull_t) {
+    mStorage = new DOMStorageImpl(nsnull);
+  } else {
+    const StorageClone& clone = aData.get_StorageClone();
+    StorageParent* other = static_cast<StorageParent*>(clone.actorParent());
+    mStorage = new DOMStorageImpl(nsnull, *other->mStorage.get());
+    mStorage->CloneFrom(clone.callerSecure(), other->mStorage);
+  }
+}
+
+bool
+StorageParent::RecvInit(const bool& aUseDB,
+                        const bool& aCanUseChromePersist,
+                        const nsCString& aDomain,
+                        const nsCString& aScopeDBKey,
+                        const nsCString& aQuotaDomainDBKey,
+                        const nsCString& aQuotaETLDplus1DomainDBKey,
+                        const PRUint32& aStorageType)
+{
+  mStorage->InitFromChild(aUseDB, aCanUseChromePersist, aDomain, aScopeDBKey,
+                          aQuotaDomainDBKey, aQuotaETLDplus1DomainDBKey,
+                          aStorageType);
+  return true;
+}
+
+bool
+StorageParent::RecvGetKeys(const bool& aCallerSecure, InfallibleTArray<nsString>* aKeys)
+{
+  // Callers are responsible for deallocating the array returned by mStorage->GetKeys
+  nsAutoPtr<nsTArray<nsString> > keys(mStorage->GetKeys(aCallerSecure));
+  aKeys->SwapElements(*keys);
+  return true;
+}
+
+bool
+StorageParent::RecvGetLength(const bool& aCallerSecure, PRUint32* aLength,
+                             nsresult* rv)
+{
+  *rv = mStorage->GetLength(aCallerSecure, aLength);
+  return true;
+}
+
+bool
+StorageParent::RecvGetKey(const bool& aCallerSecure, const PRUint32& aIndex,
+                          nsString* aKey, nsresult* rv)
+{
+  *rv = mStorage->GetKey(aCallerSecure, aIndex, *aKey);
+  return true;
+}
+
+bool
+StorageParent::RecvGetValue(const bool& aCallerSecure, const nsString& aKey,
+                            StorageItem* aItem, nsresult* rv)
+{
+  // We need to ensure that a proper null representation is sent to the child
+  // if no item is found or an error occurs.
+
+  *rv = NS_OK;
+  nsCOMPtr<nsIDOMStorageItem> item = mStorage->GetValue(aCallerSecure, aKey, rv);
+  if (NS_FAILED(*rv) || !item) {
+    *aItem = null_t();
+    return true;
+  }
+
+  ItemData data(EmptyString(), false);
+  nsDOMStorageItem* internalItem = static_cast<nsDOMStorageItem*>(item.get());
+  data.value() = internalItem->GetValueInternal();
+  if (aCallerSecure)
+    data.secure() = internalItem->IsSecure();
+  *aItem = data;
+  return true;
+}
+
+bool
+StorageParent::RecvSetValue(const bool& aCallerSecure, const nsString& aKey,
+                            const nsString& aData, nsString* aOldValue,
+                            nsresult* rv)
+{
+  *rv = mStorage->SetValue(aCallerSecure, aKey, aData, *aOldValue);
+  return true;
+}
+
+bool
+StorageParent::RecvRemoveValue(const bool& aCallerSecure, const nsString& aKey,
+                               nsString* aOldValue, nsresult* rv)
+{
+  *rv = mStorage->RemoveValue(aCallerSecure, aKey, *aOldValue);
+  return true;
+}
+
+bool
+StorageParent::RecvClear(const bool& aCallerSecure, PRInt32* aOldCount,
+                         nsresult* rv)
+{
+  *rv = mStorage->Clear(aCallerSecure, aOldCount);
+  return true;
+}
+
+bool
+StorageParent::RecvGetDBValue(const nsString& aKey, nsString* aValue,
+                              PRBool* aSecure, nsresult* rv)
+{
+  *rv = mStorage->GetDBValue(aKey, *aValue, aSecure);
+  return true;
+}
+
+bool
+StorageParent::RecvSetDBValue(const nsString& aKey, const nsString& aValue,
+                              const PRBool& aSecure, nsresult* rv)
+{
+  *rv = mStorage->SetDBValue(aKey, aValue, aSecure);
+  return true;
+}
+
+bool
+StorageParent::RecvSetSecure(const nsString& aKey, const PRBool& aSecure,
+                             nsresult* rv)
+{
+  *rv = mStorage->SetSecure(aKey, aSecure);
+  return true;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/src/storage/StorageParent.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla DOM Storage.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_StorageParent_h
+#define mozilla_dom_StorageParent_h
+
+#include "mozilla/dom/PStorageParent.h"
+#include "nsDOMStorage.h"
+
+namespace mozilla {
+namespace dom {
+
+class StorageConstructData;
+
+class StorageParent : public PStorageParent
+{
+public:
+  StorageParent(const StorageConstructData& aData);
+
+private:
+  bool RecvGetKeys(const bool& aCallerSecure, InfallibleTArray<nsString>* aKeys);
+  bool RecvGetLength(const bool& aCallerSecure, PRUint32* aLength, nsresult* rv);
+  bool RecvGetKey(const bool& aCallerSecure, const PRUint32& aIndex,
+                  nsString* aKey, nsresult* rv);
+  bool RecvGetValue(const bool& aCallerSecure, const nsString& aKey,
+                    StorageItem* aItem, nsresult* rv);
+  bool RecvSetValue(const bool& aCallerSecure, const nsString& aKey,
+                    const nsString& aData, nsString* aOldValue, nsresult* rv);
+  bool RecvRemoveValue(const bool& aCallerSecure, const nsString& aKey,
+                       nsString* aOldData, nsresult* rv);
+  bool RecvClear(const bool& aCallerSecure, PRInt32* aOldCount, nsresult* rv);
+
+  bool RecvGetDBValue(const nsString& aKey, nsString* aValue, PRBool* aSecure,
+                      nsresult* rv);
+  bool RecvSetDBValue(const nsString& aKey, const nsString& aValue,
+                      const PRBool& aSecure, nsresult* rv);
+  bool RecvSetSecure(const nsString& aKey, const PRBool& aSecure,
+                     nsresult* rv);
+
+  bool RecvInit(const bool& aUseDB,
+                const bool& aCanUseChromePersist,
+                const nsCString& aDomain,
+                const nsCString& aScopeDBKey,
+                const nsCString& aQuotaDomainDBKey,
+                const nsCString& aQuotaETLDplus1DomainDBKey,
+                const PRUint32& aStorageType);
+
+  nsRefPtr<DOMStorageImpl> mStorage;
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/src/storage/ipdl.mk
@@ -0,0 +1,39 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla DOM Storage.
+#
+# The Initial Developer of the Original Code is
+#   The Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+IPDLSRCS = \
+  PStorage.ipdl \
+  $(NULL)
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -19,31 +19,39 @@
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Neil Deakin <enndeakin@sympatico.ca>
  *   Johnny Stenback <jst@mozilla.com>
  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
  *   Honza Bambas <honzab@firemni.cz>
+ *   Josh Matthews <josh@joshmatthews.net>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifdef MOZ_IPC
+#include "StorageChild.h"
+#include "StorageParent.h"
+#include "nsXULAppAPI.h"
+using mozilla::dom::StorageChild;
+#endif
+
 #include "prnetdb.h"
 #include "nsCOMPtr.h"
 #include "nsDOMError.h"
 #include "nsDOMClassInfo.h"
 #include "nsUnicharUtils.h"
 #include "nsIDocument.h"
 #include "nsDOMStorage.h"
 #include "nsEscape.h"
@@ -289,18 +297,18 @@ nsDOMStorageManager::GetInstance()
 //static
 void
 nsDOMStorageManager::Shutdown()
 {
   NS_IF_RELEASE(gStorageManager);
   gStorageManager = nsnull;
 
 #ifdef MOZ_STORAGE
-  delete nsDOMStorage::gStorageDB;
-  nsDOMStorage::gStorageDB = nsnull;
+  delete DOMStorageImpl::gStorageDB;
+  DOMStorageImpl::gStorageDB = nsnull;
 #endif
 }
 
 static PLDHashOperator
 ClearStorage(nsDOMStorageEntry* aEntry, void* userArg)
 {
   aEntry->mStorage->ClearAll();
   return PL_DHASH_REMOVE;
@@ -355,46 +363,46 @@ nsDOMStorageManager::Observe(nsISupports
   if (!strcmp(aTopic, "profile-after-change")) {
     nsCOMPtr<nsIPrivateBrowsingService> pbs =
       do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
     if (pbs)
       pbs->GetPrivateBrowsingEnabled(&gStorageManager->mInPrivateBrowsing);
   }
   else if (!strcmp(aTopic, "offline-app-removed")) {
 #ifdef MOZ_STORAGE
-    nsresult rv = nsDOMStorage::InitDB();
+    nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
-    return nsDOMStorage::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData),
-                                                 PR_TRUE);
+    return DOMStorageImpl::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData),
+                                                   PR_TRUE);
 #endif
   } else if (!strcmp(aTopic, "cookie-changed") &&
              !nsCRT::strcmp(aData, NS_LITERAL_STRING("cleared").get())) {
     mStorages.EnumerateEntries(ClearStorage, nsnull);
 
 #ifdef MOZ_STORAGE
-    nsresult rv = nsDOMStorage::InitDB();
+    nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Remove global storage for domains that aren't marked for offline use.
     nsTArray<nsString> domains;
     rv = GetOfflineDomains(domains);
     NS_ENSURE_SUCCESS(rv, rv);
-    return nsDOMStorage::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_FALSE);
+    return DOMStorageImpl::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_FALSE);
 #endif
   } else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
     mStorages.EnumerateEntries(ClearStorage, nsnull);
     if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get()))
       mInPrivateBrowsing = PR_TRUE;
     else if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).get()))
       mInPrivateBrowsing = PR_FALSE;
 #ifdef MOZ_STORAGE
-    nsresult rv = nsDOMStorage::InitDB();
+    nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
 
-    return nsDOMStorage::gStorageDB->DropPrivateBrowsingStorages();
+    return DOMStorageImpl::gStorageDB->DropPrivateBrowsingStorages();
 #endif
   } else if (!strcmp(aTopic, "perm-changed")) {
     // Check for cookie permission change
     nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
     if (perm) {
       nsCAutoString type;
       perm->GetType(type);
       if (type != NS_LITERAL_CSTRING("cookie"))
@@ -407,52 +415,52 @@ nsDOMStorageManager::Observe(nsISupports
         return NS_OK;
 
       nsCAutoString host;
       perm->GetHost(host);
       if (host.IsEmpty())
         return NS_OK;
 
 #ifdef MOZ_STORAGE
-      nsresult rv = nsDOMStorage::InitDB();
+      nsresult rv = DOMStorageImpl::InitDB();
       NS_ENSURE_SUCCESS(rv, rv);
 
-      return nsDOMStorage::gStorageDB->DropSessionOnlyStoragesForHost(host);
+      return DOMStorageImpl::gStorageDB->DropSessionOnlyStoragesForHost(host);
 #endif
     }
   } else if (!strcmp(aTopic, "timer-callback")) {
     nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService();
     if (obsserv)
       obsserv->NotifyObservers(nsnull, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, nsnull);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMStorageManager::GetUsage(const nsAString& aDomain,
                               PRInt32 *aUsage)
 {
-  nsresult rv = nsDOMStorage::InitDB();
+  nsresult rv = DOMStorageImpl::InitDB();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return nsDOMStorage::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain),
-                                            PR_FALSE, aUsage);
+  return DOMStorageImpl::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain),
+                                              PR_FALSE, aUsage);
 }
 
 NS_IMETHODIMP
 nsDOMStorageManager::ClearOfflineApps()
 {
-    nsresult rv = nsDOMStorage::InitDB();
+    nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsTArray<nsString> domains;
     rv = GetOfflineDomains(domains);
     NS_ENSURE_SUCCESS(rv, rv);
-    return nsDOMStorage::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_TRUE);
+    return DOMStorageImpl::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_TRUE);
 }
 
 NS_IMETHODIMP
 nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal,
                                                  const nsSubstring &aDocumentURI,
                                                  nsIDOMStorage **aResult)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
@@ -470,37 +478,37 @@ nsDOMStorageManager::GetLocalStorageForP
 
   *aResult = storage.get();
   storage.forget();
 
   return NS_OK;
 }
 
 void
-nsDOMStorageManager::AddToStoragesHash(nsDOMStorage* aStorage)
+nsDOMStorageManager::AddToStoragesHash(DOMStorageImpl* aStorage)
 {
   nsDOMStorageEntry* entry = mStorages.PutEntry(aStorage);
   if (entry)
     entry->mStorage = aStorage;
 }
 
 void
-nsDOMStorageManager::RemoveFromStoragesHash(nsDOMStorage* aStorage)
+nsDOMStorageManager::RemoveFromStoragesHash(DOMStorageImpl* aStorage)
 {
   nsDOMStorageEntry* entry = mStorages.GetEntry(aStorage);
   if (entry)
     mStorages.RemoveEntry(aStorage);
 }
 
 //
 // nsDOMStorage
 //
 
 #ifdef MOZ_STORAGE
-nsDOMStorageDBWrapper* nsDOMStorage::gStorageDB = nsnull;
+nsDOMStorageDBWrapper* DOMStorageImpl::gStorageDB = nsnull;
 #endif
 
 nsDOMStorageEntry::nsDOMStorageEntry(KeyTypePointer aStr)
   : nsVoidPtrHashKey(aStr), mStorage(nsnull)
 {
 }
 
 nsDOMStorageEntry::nsDOMStorageEntry(const nsDOMStorageEntry& aToCopy)
@@ -508,46 +516,26 @@ nsDOMStorageEntry::nsDOMStorageEntry(con
 {
   NS_ERROR("DOMStorage horked.");
 }
 
 nsDOMStorageEntry::~nsDOMStorageEntry()
 {
 }
 
-PLDHashOperator
-SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) {
-  nsCycleCollectionTraversalCallback *cb = 
-    static_cast<nsCycleCollectionTraversalCallback*>(userArg);
-
-  cb->NoteXPCOMChild((nsIDOMStorageItem *) aEntry->mItem);
-
-  return PL_DHASH_NEXT;
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMStorage)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorage)
-  {
-    if (tmp->mItems.IsInitialized()) {
-      tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb);
-    }
-  }
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_1(nsDOMStorage, mStorageImpl)
 
 DOMCI_DATA(StorageObsolete, nsDOMStorage)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageObsolete)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageObsolete)
   NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
-  NS_INTERFACE_MAP_ENTRY(nsIObserver)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageObsolete)
 NS_INTERFACE_MAP_END
 
 nsresult
 NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult)
 {
   nsDOMStorage* storage = new nsDOMStorage();
   if (!storage)
@@ -561,57 +549,866 @@ NS_NewDOMStorage2(nsISupports* aOuter, R
 {
   nsDOMStorage2* storage = new nsDOMStorage2();
   if (!storage)
     return NS_ERROR_OUT_OF_MEMORY;
 
   return storage->QueryInterface(aIID, aResult);
 }
 
-nsDOMStorage::nsDOMStorage()
-  : mUseDB(PR_FALSE)
+DOMStorageBase::DOMStorageBase()
+  : mStorageType(nsPIDOMStorage::Unknown)
+  , mUseDB(PR_FALSE)
+  , mSessionOnly(PR_TRUE)
+  , mCanUseChromePersist(false)
+{
+}
+
+DOMStorageBase::DOMStorageBase(DOMStorageBase& aThat)
+  : mStorageType(aThat.mStorageType)
+  , mUseDB(PR_FALSE) // Clones don't use the DB
   , mSessionOnly(PR_TRUE)
-  , mStorageType(nsPIDOMStorage::Unknown)
-  , mItemsCached(PR_FALSE)
-  , mEventBroadcaster(nsnull)
-  , mCanUseChromePersist(false)
-  , mLoadedTemporaryTable(false)
+  , mDomain(aThat.mDomain)
+  , mScopeDBKey(aThat.mScopeDBKey)
+  , mQuotaETLDplus1DomainDBKey(aThat.mQuotaETLDplus1DomainDBKey)
+  , mQuotaDomainDBKey(aThat.mQuotaDomainDBKey)
+  , mCanUseChromePersist(aThat.mCanUseChromePersist)
+{
+}
+
+void
+DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI)
+{
+  // No need to check for a return value. If this would fail we would not get
+  // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
+  // nsDOMStorage::CanUseStorage before we query the storage manager for a new
+  // sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we
+  // won't get to InitAsSessionStorage.
+  aDomainURI->GetAsciiHost(mDomain);
+
+#ifdef MOZ_STORAGE
+  mUseDB = PR_FALSE;
+  mScopeDBKey.Truncate();
+  mQuotaDomainDBKey.Truncate();
+#endif
+  mStorageType = nsPIDOMStorage::SessionStorage;
+}
+
+void
+DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
+                                   bool aCanUseChromePersist)
 {
-  mSecurityChecker = this;
-  mItems.Init(8);
-  if (nsDOMStorageManager::gStorageManager)
-    nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
+  // No need to check for a return value. If this would fail we would not get
+  // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
+  // nsDOMStorage::CanUseStorage before we query the storage manager for a new
+  // localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't
+  // get to InitAsLocalStorage. Actually, mDomain will get replaced with
+  // mPrincipal in bug 455070. It is not even used for localStorage.
+  aDomainURI->GetAsciiHost(mDomain);
+
+#ifdef MOZ_STORAGE
+  nsDOMStorageDBWrapper::CreateOriginScopeDBKey(aDomainURI, mScopeDBKey);
+
+  // XXX Bug 357323, we have to solve the issue how to define
+  // origin for file URLs. In that case CreateOriginScopeDBKey
+  // fails (the result is empty) and we must avoid database use
+  // in that case because it produces broken entries w/o owner.
+  mUseDB = !mScopeDBKey.IsEmpty();
+
+  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
+                                                PR_TRUE, PR_FALSE, mQuotaDomainDBKey);
+  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
+                                                PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey);
+#endif
+  mCanUseChromePersist = aCanUseChromePersist;
+  mStorageType = nsPIDOMStorage::LocalStorage;
 }
 
-nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
-  : mUseDB(PR_FALSE) // Any clone is not using the database
-  , mDomain(aThat.mDomain)
-  , mSessionOnly(PR_TRUE)
-  , mStorageType(aThat.mStorageType)
-  , mItemsCached(PR_FALSE)
+void
+DOMStorageBase::InitAsGlobalStorage(const nsACString& aDomainDemanded)
+{
+  mDomain = aDomainDemanded;
+
 #ifdef MOZ_STORAGE
-  , mScopeDBKey(aThat.mScopeDBKey)
+  nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aDomainDemanded, mScopeDBKey);
+
+  // XXX Bug 357323, we have to solve the issue how to define
+  // origin for file URLs. In that case CreateOriginScopeDBKey
+  // fails (the result is empty) and we must avoid database use
+  // in that case because it produces broken entries w/o owner.
+  if (!(mUseDB = !mScopeDBKey.IsEmpty()))
+    mScopeDBKey.AppendLiteral(":");
+
+  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded,
+                                                PR_TRUE, PR_FALSE, mQuotaDomainDBKey);
+  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded,
+                                                PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey);
 #endif
-  , mEventBroadcaster(nsnull)
-  , mCanUseChromePersist(aThat.mCanUseChromePersist)
+  mStorageType = nsPIDOMStorage::GlobalStorage;
+}
+
+PLDHashOperator
+SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) {
+  nsCycleCollectionTraversalCallback *cb = 
+      static_cast<nsCycleCollectionTraversalCallback*>(userArg);
+
+  cb->NoteXPCOMChild((nsIDOMStorageItem *) aEntry->mItem);
+
+  return PL_DHASH_NEXT;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMStorageImpl)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_0(DOMStorageImpl)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMStorageImpl)
+{
+  if (tmp->mItems.IsInitialized()) {
+    tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb);
+  }
+}
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(DOMStorageImpl, nsIObserver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(DOMStorageImpl, nsIObserver)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMStorageImpl)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+NS_INTERFACE_MAP_END
+
+DOMStorageImpl::DOMStorageImpl(nsDOMStorage* aStorage)
+  : mLoadedTemporaryTable(false)
+{
+  Init(aStorage);
+}
+
+DOMStorageImpl::DOMStorageImpl(nsDOMStorage* aStorage, DOMStorageImpl& aThat)
+  : DOMStorageBase(aThat)
   , mLoadedTemporaryTable(aThat.mLoadedTemporaryTable)
   , mLastTemporaryTableAccessTime(aThat.mLastTemporaryTableAccessTime)
   , mTemporaryTableAge(aThat.mTemporaryTableAge)
 {
-  mSecurityChecker = this;
+  Init(aStorage);
+}
+
+void
+DOMStorageImpl::Init(nsDOMStorage* aStorage)
+{
+  mItemsCached = PR_FALSE;
   mItems.Init(8);
-
+  mOwner = aStorage;
   if (nsDOMStorageManager::gStorageManager)
     nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
 }
 
+DOMStorageImpl::~DOMStorageImpl()
+{
+  if (nsDOMStorageManager::gStorageManager)
+    nsDOMStorageManager::gStorageManager->RemoveFromStoragesHash(this);
+}
+
+nsresult
+DOMStorageImpl::InitDB()
+{
+#ifdef MOZ_STORAGE
+  if (!gStorageDB) {
+    gStorageDB = new nsDOMStorageDBWrapper();
+    if (!gStorageDB)
+      return NS_ERROR_OUT_OF_MEMORY;
+
+    nsresult rv = gStorageDB->Init();
+    if (NS_FAILED(rv)) {
+      // Failed to initialize the DB, delete it and null out the
+      // pointer so we don't end up attempting to use an
+      // un-initialized DB later on.
+
+      delete gStorageDB;
+      gStorageDB = nsnull;
+
+      return rv;
+    }
+  }
+#endif
+
+  return NS_OK;
+}
+
+void
+DOMStorageImpl::InitFromChild(bool aUseDB, bool aCanUseChromePersist,
+                              const nsACString& aDomain,
+                              const nsACString& aScopeDBKey,
+                              const nsACString& aQuotaDomainDBKey,
+                              const nsACString& aQuotaETLDplus1DomainDBKey,
+                              PRUint32 aStorageType)
+{
+  mUseDB = aUseDB;
+  mCanUseChromePersist = aCanUseChromePersist;
+  mDomain = aDomain;
+  mScopeDBKey = aScopeDBKey;
+  mQuotaDomainDBKey = aQuotaDomainDBKey;
+  mQuotaETLDplus1DomainDBKey = aQuotaETLDplus1DomainDBKey;
+  mStorageType = static_cast<nsPIDOMStorage::nsDOMStorageType>(aStorageType);
+  if (mStorageType != nsPIDOMStorage::SessionStorage)
+    RegisterObservers();
+  CacheStoragePermissions();
+}
+
+void
+DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI)
+{
+  DOMStorageBase::InitAsSessionStorage(aDomainURI);
+}
+
+void
+DOMStorageImpl::InitAsLocalStorage(nsIURI* aDomainURI,
+                                   bool aCanUseChromePersist)
+{
+  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist);
+  RegisterObservers();
+}
+
+void
+DOMStorageImpl::InitAsGlobalStorage(const nsACString& aDomainDemanded)
+{
+  DOMStorageBase::InitAsGlobalStorage(aDomainDemanded);
+  RegisterObservers();
+}
+
+bool
+DOMStorageImpl::CacheStoragePermissions()
+{
+  // If this is a cross-process situation, we don't have a real storage owner.
+  // All the correct checks have been done on the child, so we just need to
+  // make sure that our session-only status is correctly updated.
+  if (!mOwner)
+    return nsDOMStorage::CanUseStorage(&mSessionOnly);
+  
+  return mOwner->CacheStoragePermissions();
+}
+
+bool
+DOMStorageImpl::CanUseChromePersist()
+{
+  return mCanUseChromePersist;
+}
+
+nsresult
+DOMStorageImpl::GetCachedValue(const nsAString& aKey, nsAString& aValue,
+                               PRBool* aSecure)
+{
+  aValue.Truncate();
+  *aSecure = PR_FALSE;
+
+  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
+  if (!entry)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  aValue = entry->mItem->GetValueInternal();
+  *aSecure = entry->mItem->IsSecure();
+
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::GetDBValue(const nsAString& aKey, nsAString& aValue,
+                           PRBool* aSecure)
+{
+  aValue.Truncate();
+
+#ifdef MOZ_STORAGE
+  if (!UseDB())
+    return NS_OK;
+
+  nsresult rv = InitDB();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString value;
+  rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure);
+
+  if (rv == NS_ERROR_DOM_NOT_FOUND_ERR &&
+      mStorageType != nsPIDOMStorage::GlobalStorage) {
+    SetDOMStringToNull(aValue);
+  }
+
+  if (NS_FAILED(rv))
+    return rv;
+
+  aValue.Assign(value);
+#endif
+
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::SetDBValue(const nsAString& aKey,
+                           const nsAString& aValue,
+                           PRBool aSecure)
+{
+#ifdef MOZ_STORAGE
+  if (!UseDB())
+    return NS_OK;
+
+  nsresult rv = InitDB();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRInt32 offlineAppPermission;
+  PRInt32 quota;
+  PRInt32 warnQuota;
+  offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota,
+                                  CanUseChromePersist());
+
+  PRInt32 usage;
+  rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota,
+                         !IS_PERMISSION_ALLOWED(offlineAppPermission),
+                         &usage);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Before bug 536544 got fixed we were dropping mItemsCached flag here
+
+  if (warnQuota >= 0 && usage > warnQuota) {
+    // try to include the window that exceeded the warn quota
+    nsCOMPtr<nsIDOMWindow> window;
+    JSContext *cx;
+    nsCOMPtr<nsIJSContextStack> stack =
+        do_GetService("@mozilla.org/js/xpc/ContextStack;1");
+    if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
+      nsCOMPtr<nsIScriptContext> scriptContext;
+      scriptContext = GetScriptContextFromJSContext(cx);
+      if (scriptContext) {
+        window = do_QueryInterface(scriptContext->GetGlobalObject());
+      }
+    }
+
+    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+    os->NotifyObservers(window, "dom-storage-warn-quota-exceeded",
+                       NS_ConvertUTF8toUTF16(mDomain).get());
+  }
+
+#endif
+
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::SetSecure(const nsAString& aKey, PRBool aSecure)
+{
+#ifdef MOZ_STORAGE
+  if (UseDB()) {
+    nsresult rv = InitDB();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return gStorageDB->SetSecure(this, aKey, aSecure);
+  }
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+
+  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
+  NS_ASSERTION(entry, "Don't use SetSecure() with nonexistent keys!");
+
+  if (entry) {
+    entry->mItem->SetSecureInternal(aSecure);
+  }  
+
+  return NS_OK;
+}
+
+static PLDHashOperator
+ClearStorageItem(nsSessionStorageEntry* aEntry, void* userArg)
+{
+  aEntry->mItem->SetValueInternal(EmptyString());
+  return PL_DHASH_NEXT;
+}
+
+void
+DOMStorageImpl::ClearAll()
+{
+  mItems.EnumerateEntries(ClearStorageItem, nsnull);
+  mItemsCached = PR_FALSE;
+}
+
+struct CopyArgs {
+  DOMStorageImpl* storage;
+  bool callerSecure;
+};
+
+static PLDHashOperator
+CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
+{
+  // When copying items from one impl to another, we may not
+  // have an mOwner that we can call SetItem on. Therefore we need
+  // to replicate its behaviour.
+  
+  CopyArgs* args = static_cast<CopyArgs*>(userArg);
+
+  nsAutoString unused;
+  nsresult rv = args->storage->SetValue(args->callerSecure, aEntry->GetKey(),
+                                        aEntry->mItem->GetValueInternal(), unused);
+  if (NS_FAILED(rv))
+    return PL_DHASH_NEXT;
+
+  if (aEntry->mItem->IsSecure()) {
+    args->storage->SetSecure(aEntry->GetKey(), PR_TRUE);
+  }
+
+  return PL_DHASH_NEXT;
+}
+
+nsresult
+DOMStorageImpl::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat)
+{
+  // For various reasons, we no longer call SetItem in CopyStorageItems,
+  // so we need to ensure that the storage permissions are correct.
+  if (!CacheStoragePermissions())
+    return NS_ERROR_DOM_SECURITY_ERR;
+  
+  DOMStorageImpl* that = static_cast<DOMStorageImpl*>(aThat);
+  CopyArgs args = { this, aCallerSecure };
+  that->mItems.EnumerateEntries(CopyStorageItems, &args);
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::RegisterObservers()
+{
+  nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService();
+  if (obsserv) {
+    obsserv->AddObserver(this, "profile-before-change", PR_TRUE);
+    obsserv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
+    obsserv->AddObserver(this, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, PR_TRUE);
+  }
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::MaybeCommitTemporaryTable(bool force)
+{
+#ifdef MOZ_STORAGE
+  if (!UseDB())
+    return NS_OK;
+
+  if (!mLoadedTemporaryTable)
+    return NS_OK;
+
+  // If we are not forced to flush (e.g. on shutdown) then don't flush if the
+  // last table access is less then 5 seconds ago or the table itself is not
+  // older then 30 secs
+  if (!force &&
+      ((TimeStamp::Now() - mLastTemporaryTableAccessTime).ToSeconds() < 
+       NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_INACTIVITY_TIME) &&
+      ((TimeStamp::Now() - mTemporaryTableAge).ToSeconds() < 
+       NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_AGE))
+    return NS_OK;
+
+  return gStorageDB->FlushAndDeleteTemporaryTableForStorage(this);
+#endif
+
+  return NS_OK;
+}
+
+bool
+DOMStorageImpl::WasTemporaryTableLoaded()
+{
+  return mLoadedTemporaryTable;
+}
+
+void
+DOMStorageImpl::SetTemporaryTableLoaded(bool loaded)
+{
+  if (loaded) {
+    mLastTemporaryTableAccessTime = TimeStamp::Now();
+    if (!mLoadedTemporaryTable)
+      mTemporaryTableAge = mLastTemporaryTableAccessTime;
+  }
+
+  mLoadedTemporaryTable = loaded;
+}
+
+NS_IMETHODIMP
+DOMStorageImpl::Observe(nsISupports *subject,
+                      const char *topic,
+                      const PRUnichar *data)
+{
+  bool isProfileBeforeChange = !strcmp(topic, "profile-before-change");
+  bool isXPCOMShutdown = !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+  bool isFlushTimer = !strcmp(topic, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER);
+
+  if (isXPCOMShutdown || isProfileBeforeChange || isFlushTimer) {
+    nsresult rv = MaybeCommitTemporaryTable(isXPCOMShutdown || isProfileBeforeChange);
+    if (NS_FAILED(rv)) {
+      NS_WARNING("DOMStorage: temporary table commit failed");
+    }
+
+    return NS_OK;
+  }
+
+  NS_WARNING("Unrecognized topic in nsDOMStorage::Observe");
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::CacheKeysFromDB()
+{
+#ifdef MOZ_STORAGE
+  // cache all the keys in the hash. This is used by the Length and Key methods
+  // use this cache for better performance. The disadvantage is that the
+  // order may break if someone changes the keys in the database directly.
+  if (!mItemsCached) {
+    nsresult rv = InitDB();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    mItems.Clear();
+
+    rv = gStorageDB->GetAllKeys(this, &mItems);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    mItemsCached = PR_TRUE;
+  }
+#endif
+
+  return NS_OK;
+}
+
+struct KeysArrayBuilderStruct
+{
+  PRBool callerIsSecure;
+  nsTArray<nsString> *keys;
+};
+
+static PLDHashOperator
+KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg)
+{
+  KeysArrayBuilderStruct *keystruct = (KeysArrayBuilderStruct *)userArg;
+  
+  if (keystruct->callerIsSecure || !aEntry->mItem->IsSecure())
+    keystruct->keys->AppendElement(aEntry->GetKey());
+
+  return PL_DHASH_NEXT;
+}
+
+nsTArray<nsString>*
+DOMStorageImpl::GetKeys(bool aCallerSecure)
+{
+  if (UseDB())
+    CacheKeysFromDB();
+
+  KeysArrayBuilderStruct keystruct;
+  keystruct.callerIsSecure = aCallerSecure;
+  keystruct.keys = new nsTArray<nsString>();
+  if (keystruct.keys)
+    mItems.EnumerateEntries(KeysArrayBuilder, &keystruct);
+ 
+  return keystruct.keys;
+}
+
+class ItemCounterState
+{
+ public:
+  ItemCounterState(PRBool aIsCallerSecure)
+  : mIsCallerSecure(aIsCallerSecure), mCount(0)
+  {
+  }
+
+  PRBool mIsCallerSecure;
+  PRBool mCount;
+ private:
+  ItemCounterState(); // Not to be implemented
+};
+
+static PLDHashOperator
+ItemCounter(nsSessionStorageEntry* aEntry, void* userArg)
+{
+  ItemCounterState *state = (ItemCounterState *)userArg;
+
+  if (state->mIsCallerSecure || !aEntry->mItem->IsSecure()) {
+    ++state->mCount;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
+nsresult
+DOMStorageImpl::GetLength(bool aCallerSecure, PRUint32* aLength)
+{
+  // Force reload of items from database.  This ensures sync localStorages for
+  // same origins among different windows.
+  mItemsCached = PR_FALSE;
+  if (UseDB())
+    CacheKeysFromDB();
+
+  ItemCounterState state(aCallerSecure);
+
+  mItems.EnumerateEntries(ItemCounter, &state);
+
+  *aLength = state.mCount;
+  return NS_OK;
+}
+
+class IndexFinderData
+{
+ public:
+  IndexFinderData(PRBool aIsCallerSecure, PRUint32 aWantedIndex)
+  : mIsCallerSecure(aIsCallerSecure), mIndex(0), mWantedIndex(aWantedIndex),
+    mItem(nsnull)
+  {
+  }
+
+  PRBool mIsCallerSecure;
+  PRUint32 mIndex;
+  PRUint32 mWantedIndex;
+  nsSessionStorageEntry *mItem;
+
+ private:
+  IndexFinderData(); // Not to be implemented
+};
+
+static PLDHashOperator
+IndexFinder(nsSessionStorageEntry* aEntry, void* userArg)
+{
+  IndexFinderData *data = (IndexFinderData *)userArg;
+
+  if (data->mIndex == data->mWantedIndex &&
+      (data->mIsCallerSecure || !aEntry->mItem->IsSecure())) {
+    data->mItem = aEntry;
+
+    return PL_DHASH_STOP;
+  }
+
+  ++data->mIndex;
+
+  return PL_DHASH_NEXT;
+}
+
+nsresult
+DOMStorageImpl::GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey)
+{
+  // XXXjst: This is as retarded as the DOM spec is, takes an unsigned
+  // int, but the spec talks about what to do if a negative value is
+  // passed in.
+
+  // XXX: This does a linear search for the key at index, which would
+  // suck if there's a large numer of indexes. Do we care? If so,
+  // maybe we need to have a lazily populated key array here or
+  // something?
+
+  if (UseDB())
+    CacheKeysFromDB();
+
+  IndexFinderData data(aCallerSecure, aIndex);
+  mItems.EnumerateEntries(IndexFinder, &data);
+
+  if (!data.mItem) {
+    // aIndex was larger than the number of accessible keys. Throw.
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+
+  aKey = data.mItem->GetKey();
+  return NS_OK;
+}
+
+// The behaviour of this function must be kept in sync with StorageChild::GetValue.
+// See the explanatory comment there for more details.
+nsIDOMStorageItem*
+DOMStorageImpl::GetValue(bool aCallerSecure, const nsAString& aKey,
+                         nsresult* aResult)
+{
+  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
+  nsIDOMStorageItem* item = nsnull;
+  if (entry) {
+    if (aCallerSecure || !entry->mItem->IsSecure()) {
+      item = entry->mItem;
+    }
+  }
+  else if (UseDB()) {
+    PRBool secure;
+    nsAutoString value;
+    nsresult rv = GetDBValue(aKey, value, &secure);
+    // return null if access isn't allowed or the key wasn't found
+    if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR ||
+        (!aCallerSecure && secure))
+      return nsnull;
+
+    *aResult = rv;
+    NS_ENSURE_SUCCESS(rv, nsnull);
+
+    nsRefPtr<nsDOMStorageItem> newitem =
+        new nsDOMStorageItem(this, aKey, value, secure);
+    if (newitem && (entry = mItems.PutEntry(aKey))) {
+      item = entry->mItem = newitem;
+    }
+    else {
+      *aResult = NS_ERROR_OUT_OF_MEMORY;
+    }
+  }
+  return item;
+}
+
+nsresult
+DOMStorageImpl::SetValue(bool aIsCallerSecure, const nsAString& aKey,
+                         const nsAString& aData, nsAString& aOldValue)
+{
+  if (aKey.IsEmpty())
+    return NS_OK;
+
+  nsresult rv;
+  nsString oldValue;
+  SetDOMStringToNull(oldValue);
+
+  // First store the value to the database, we need to do this before we update
+  // the mItems cache.  SetDBValue is using the old cached value to decide
+  // on quota checking.
+  if (UseDB()) {
+    rv = SetDBValue(aKey, aData, aIsCallerSecure);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
+  if (entry) {
+    if (entry->mItem->IsSecure() && !aIsCallerSecure) {
+      return NS_ERROR_DOM_SECURITY_ERR;
+    }
+    oldValue = entry->mItem->GetValueInternal();
+    entry->mItem->SetValueInternal(aData);
+  }
+  else {
+    nsRefPtr<nsDOMStorageItem> newitem =
+        new nsDOMStorageItem(this, aKey, aData, aIsCallerSecure);
+    if (!newitem)
+      return NS_ERROR_OUT_OF_MEMORY;
+    entry = mItems.PutEntry(aKey);
+    NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
+    entry->mItem = newitem;
+  }
+  aOldValue = oldValue;
+  return NS_OK;
+}
+
+nsresult
+DOMStorageImpl::RemoveValue(bool aCallerSecure, const nsAString& aKey,
+                            nsAString& aOldValue)
+{
+  if (!CacheStoragePermissions())
+    return NS_ERROR_DOM_SECURITY_ERR;
+  
+  nsString oldValue;
+  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
+
+  if (entry && entry->mItem->IsSecure() && !aCallerSecure) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  if (UseDB()) {
+#ifdef MOZ_STORAGE
+    nsresult rv = InitDB();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsAutoString value;
+    PRBool secureItem;
+    rv = GetDBValue(aKey, value, &secureItem);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (!aCallerSecure && secureItem)
+      return NS_ERROR_DOM_SECURITY_ERR;
+
+    oldValue = value;
+
+    rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain),
+                               aKey.Length() + value.Length());
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Before bug 536544 got fixed we were dropping mItemsCached flag here
+#endif
+  }
+  else if (entry) {
+    // clear string as StorageItems may be referencing this item
+    oldValue = entry->mItem->GetValueInternal();
+    entry->mItem->ClearValue();
+  }
+
+  if (entry) {
+    mItems.RawRemoveEntry(entry);
+  }
+  aOldValue = oldValue;
+  return NS_OK;
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+CheckSecure(nsSessionStorageEntry* aEntry, void* userArg)
+{
+  PRBool* secure = (PRBool*)userArg;
+  if (aEntry->mItem->IsSecure()) {
+    *secure = PR_TRUE;
+    return PL_DHASH_STOP;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
+nsresult
+DOMStorageImpl::Clear(bool aCallerSecure, PRInt32* aOldCount)
+{
+  if (UseDB())
+    CacheKeysFromDB();
+
+  PRInt32 oldCount = mItems.Count();
+
+  PRBool foundSecureItem = PR_FALSE;
+  mItems.EnumerateEntries(CheckSecure, &foundSecureItem);
+
+  if (foundSecureItem && !aCallerSecure) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+#ifdef MOZ_STORAGE
+  if (UseDB()) {
+    nsresult rv = InitDB();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = gStorageDB->ClearStorage(this);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+#endif
+
+  *aOldCount = oldCount;
+  mItems.Clear();
+  return NS_OK;
+}
+
+nsDOMStorage::nsDOMStorage()
+  : mStorageType(nsPIDOMStorage::Unknown)
+  , mEventBroadcaster(nsnull)
+{
+  mSecurityChecker = this;
+
+#ifdef MOZ_IPC
+  if (XRE_GetProcessType() != GeckoProcessType_Default)
+    mStorageImpl = new StorageChild(this);
+  else
+#endif
+  mStorageImpl = new DOMStorageImpl(this);
+}
+
+nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
+  : mStorageType(aThat.mStorageType)
+  , mEventBroadcaster(nsnull)
+{
+  mSecurityChecker = this;
+
+#ifdef MOZ_IPC
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    StorageChild* other = static_cast<StorageChild*>(aThat.mStorageImpl.get());
+    mStorageImpl = new StorageChild(this, *other);
+  } else
+#endif
+  {
+    DOMStorageImpl* other = static_cast<DOMStorageImpl*>(aThat.mStorageImpl.get());
+    mStorageImpl = new DOMStorageImpl(this, *other);
+  }
+}
+
 nsDOMStorage::~nsDOMStorage()
 {
-  if (nsDOMStorageManager::gStorageManager)
-    nsDOMStorageManager::gStorageManager->RemoveFromStoragesHash(this);
 }
 
 static
 nsresult
 GetDomainURI(nsIPrincipal *aPrincipal, PRBool aIncludeDomain, nsIURI **_domain)
 {
   nsCOMPtr<nsIURI> uri;
 
@@ -640,125 +1437,51 @@ GetDomainURI(nsIPrincipal *aPrincipal, P
 
 nsresult
 nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
 {
   nsCOMPtr<nsIURI> domainURI;
   nsresult rv = GetDomainURI(aPrincipal, PR_TRUE, getter_AddRefs(domainURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // No need to check for a return value. If this would fail we would not get
-  // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
-  // nsDOMStorage::CanUseStorage before we query the storage manager for a new
-  // sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we
-  // won't get to InitAsSessionStorage.
-  domainURI->GetAsciiHost(mDomain);
-
   mDocumentURI = aDocumentURI;
 
-#ifdef MOZ_STORAGE
-  mUseDB = PR_FALSE;
-  mScopeDBKey.Truncate();
-  mQuotaDomainDBKey.Truncate();
-#endif
-
   mStorageType = SessionStorage;
+
+  mStorageImpl->InitAsSessionStorage(domainURI);
   return NS_OK;
 }
 
 nsresult
 nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
 {
   nsCOMPtr<nsIURI> domainURI;
   nsresult rv = GetDomainURI(aPrincipal, PR_FALSE, getter_AddRefs(domainURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // No need to check for a return value. If this would fail we would not get
-  // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
-  // nsDOMStorage::CanUseStorage before we query the storage manager for a new
-  // localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't
-  // get to InitAsLocalStorage. Actually, mDomain will get replaced with
-  // mPrincipal in bug 455070. It is not even used for localStorage.
-  domainURI->GetAsciiHost(mDomain);
-
   mDocumentURI = aDocumentURI;
 
-#ifdef MOZ_STORAGE
-  nsDOMStorageDBWrapper::CreateOriginScopeDBKey(domainURI, mScopeDBKey);
-
-  // XXX Bug 357323, we have to solve the issue how to define
-  // origin for file URLs. In that case CreateOriginScopeDBKey
-  // fails (the result is empty) and we must avoid database use
-  // in that case because it produces broken entries w/o owner.
-  mUseDB = !mScopeDBKey.IsEmpty();
-
-  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
-      PR_TRUE, PR_FALSE, mQuotaDomainDBKey);
-  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
-      PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey);
-#endif
-
   mStorageType = LocalStorage;
 
+  bool canUseChromePersist = false;
   nsCOMPtr<nsIURI> URI;
   if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) {
-    mCanUseChromePersist = URICanUseChromePersist(URI);
+    canUseChromePersist = URICanUseChromePersist(URI);
   }
-
-  RegisterObservers();
-
+  
+  mStorageImpl->InitAsLocalStorage(domainURI, canUseChromePersist);
   return NS_OK;
 }
 
 nsresult
 nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded)
 {
-  mDomain = aDomainDemanded;
-#ifdef MOZ_STORAGE
-  nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aDomainDemanded, mScopeDBKey);
-
-  // XXX Bug 357323, we have to solve the issue how to define
-  // origin for file URLs. In that case CreateOriginScopeDBKey
-  // fails (the result is empty) and we must avoid database use
-  // in that case because it produces broken entries w/o owner.
-  if (!(mUseDB = !mScopeDBKey.IsEmpty()))
-    mScopeDBKey.AppendLiteral(":");
-
-  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded,
-      PR_TRUE, PR_FALSE, mQuotaDomainDBKey);
-  nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded,
-      PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey);
-#endif
-
   mStorageType = GlobalStorage;
   mEventBroadcaster = this;
-
-  RegisterObservers();
-
-  return NS_OK;
-}
-
-static PLDHashOperator
-CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
-{
-  nsDOMStorage* newstorage = static_cast<nsDOMStorage*>(userArg);
-
-  newstorage->SetItem(aEntry->GetKey(), aEntry->mItem->GetValueInternal());
-
-  if (aEntry->mItem->IsSecure()) {
-    newstorage->SetSecure(aEntry->GetKey(), PR_TRUE);
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-nsresult
-nsDOMStorage::CloneFrom(nsDOMStorage* aThat)
-{
-  aThat->mItems.EnumerateEntries(CopyStorageItems, this);
+  mStorageImpl->InitAsGlobalStorage(aDomainDemanded);
   return NS_OK;
 }
 
 //static
 PRBool
 nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly)
 {
   // check if the calling domain can use storage. Downgrade to session
@@ -824,17 +1547,17 @@ nsDOMStorage::CanUseStorage(PRPackedBool
 }
 
 PRBool
 nsDOMStorage::CacheStoragePermissions()
 {
   // Bug 488446, disallowing storage use when in session only mode.
   // This is temporary fix before we find complete solution for storage
   // behavior in private browsing mode or session-only cookies mode.
-  if (!CanUseStorage(&mSessionOnly))
+  if (!CanUseStorage(&mStorageImpl->mSessionOnly))
     return PR_FALSE;
 
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   if (!ssm)
     return PR_FALSE;
 
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
@@ -847,176 +1570,47 @@ nsDOMStorage::CacheStoragePermissions()
 PRBool
 nsDOMStorage::URICanUseChromePersist(nsIURI* aURI) {
   PRBool isAbout;
   return
     (NS_SUCCEEDED(aURI->SchemeIs("moz-safe-about", &isAbout)) && isAbout) ||
     (NS_SUCCEEDED(aURI->SchemeIs("about", &isAbout)) && isAbout);
 }
 
-bool
-nsDOMStorage::CanUseChromePersist()
-{
-  return mCanUseChromePersist;
-}
-
-class ItemCounterState
-{
-public:
-  ItemCounterState(PRBool aIsCallerSecure)
-    : mIsCallerSecure(aIsCallerSecure), mCount(0)
-  {
-  }
-
-  PRBool mIsCallerSecure;
-  PRBool mCount;
-private:
-  ItemCounterState(); // Not to be implemented
-};
-
-static PLDHashOperator
-ItemCounter(nsSessionStorageEntry* aEntry, void* userArg)
-{
-  ItemCounterState *state = (ItemCounterState *)userArg;
-
-  if (state->mIsCallerSecure || !aEntry->mItem->IsSecure()) {
-    ++state->mCount;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
 NS_IMETHODIMP
 nsDOMStorage::GetLength(PRUint32 *aLength)
 {
   if (!CacheStoragePermissions())
     return NS_ERROR_DOM_SECURITY_ERR;
-
-  // Force reload of items from database.  This ensures sync localStorages for
-  // same origins among different windows.
-  mItemsCached = PR_FALSE;
-  if (UseDB())
-    CacheKeysFromDB();
-
-  ItemCounterState state(IsCallerSecure());
-
-  mItems.EnumerateEntries(ItemCounter, &state);
-
-  *aLength = state.mCount;
-
-  return NS_OK;
-}
-
-class IndexFinderData
-{
-public:
-  IndexFinderData(PRBool aIsCallerSecure, PRUint32 aWantedIndex)
-    : mIsCallerSecure(aIsCallerSecure), mIndex(0), mWantedIndex(aWantedIndex),
-      mItem(nsnull)
-  {
-  }
-
-  PRBool mIsCallerSecure;
-  PRUint32 mIndex;
-  PRUint32 mWantedIndex;
-  nsSessionStorageEntry *mItem;
-
-private:
-  IndexFinderData(); // Not to be implemented
-};
-
-static PLDHashOperator
-IndexFinder(nsSessionStorageEntry* aEntry, void* userArg)
-{
-  IndexFinderData *data = (IndexFinderData *)userArg;
-
-  if (data->mIndex == data->mWantedIndex &&
-      (data->mIsCallerSecure || !aEntry->mItem->IsSecure())) {
-    data->mItem = aEntry;
-
-    return PL_DHASH_STOP;
-  }
-
-  ++data->mIndex;
-
-  return PL_DHASH_NEXT;
+  
+  return mStorageImpl->GetLength(IsCallerSecure(), aLength);
 }
 
 NS_IMETHODIMP
 nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey)
 {
-  // XXXjst: This is as retarded as the DOM spec is, takes an unsigned
-  // int, but the spec talks about what to do if a negative value is
-  // passed in.
-
-  // XXX: This does a linear search for the key at index, which would
-  // suck if there's a large numer of indexes. Do we care? If so,
-  // maybe we need to have a lazily populated key array here or
-  // something?
-
   if (!CacheStoragePermissions())
     return NS_ERROR_DOM_SECURITY_ERR;
 
-  if (UseDB())
-    CacheKeysFromDB();
-
-  IndexFinderData data(IsCallerSecure(), aIndex);
-  mItems.EnumerateEntries(IndexFinder, &data);
-
-  if (!data.mItem) {
-    // aIndex was larger than the number of accessible keys. Throw.
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  aKey = data.mItem->GetKey();
-
-  return NS_OK;
+  return mStorageImpl->GetKey(IsCallerSecure(), aIndex, aKey);
 }
 
 nsIDOMStorageItem*
 nsDOMStorage::GetNamedItem(const nsAString& aKey, nsresult* aResult)
 {
   if (!CacheStoragePermissions()) {
     *aResult = NS_ERROR_DOM_SECURITY_ERR;
     return nsnull;
   }
 
   *aResult = NS_OK;
   if (aKey.IsEmpty())
     return nsnull;
-
-  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
-  nsIDOMStorageItem* item = nsnull;
-  if (entry) {
-    if (IsCallerSecure() || !entry->mItem->IsSecure()) {
-      item = entry->mItem;
-    }
-  }
-  else if (UseDB()) {
-    PRBool secure;
-    nsAutoString value;
-    nsresult rv = GetDBValue(aKey, value, &secure);
-    // return null if access isn't allowed or the key wasn't found
-    if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR)
-      return nsnull;
-
-    *aResult = rv;
-    NS_ENSURE_SUCCESS(rv, nsnull);
-
-    nsRefPtr<nsDOMStorageItem> newitem =
-      new nsDOMStorageItem(this, aKey, value, secure);
-    if (newitem && (entry = mItems.PutEntry(aKey))) {
-      item = entry->mItem = newitem;
-    }
-    else {
-      *aResult = NS_ERROR_OUT_OF_MEMORY;
-    }
-  }
-
-  return item;
+  
+  return mStorageImpl->GetValue(IsCallerSecure(), aKey, aResult);
 }
 
 nsresult
 nsDOMStorage::GetItem(const nsAString& aKey, nsAString &aData)
 {
   nsresult rv;
 
   // IMPORTANT:
@@ -1052,349 +1646,71 @@ nsDOMStorage::GetItem(const nsAString& a
 }
 
 NS_IMETHODIMP
 nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData)
 {
   if (!CacheStoragePermissions())
     return NS_ERROR_DOM_SECURITY_ERR;
 
-  if (aKey.IsEmpty())
-    return NS_OK;
-
-  nsresult rv;
   nsString oldValue;
-  SetDOMStringToNull(oldValue);
-
-  // First store the value to the database, we need to do this before we update
-  // the mItems cache.  SetDBValue is using the old cached value to decide
-  // on quota checking.
-  bool isCallerSecure = IsCallerSecure();
-  if (UseDB()) {
-    rv = SetDBValue(aKey, aData, isCallerSecure);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
-  if (entry) {
-    if (entry->mItem->IsSecure() && !isCallerSecure) {
-      return NS_ERROR_DOM_SECURITY_ERR;
-    }
-    oldValue = entry->mItem->GetValueInternal();
-    entry->mItem->SetValueInternal(aData);
-  }
-  else {
-    nsRefPtr<nsDOMStorageItem> newitem =
-      new nsDOMStorageItem(this, aKey, aData, isCallerSecure);
-    if (!newitem)
-      return NS_ERROR_OUT_OF_MEMORY;
-    entry = mItems.PutEntry(aKey);
-    NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
-    entry->mItem = newitem;
-  }
+  nsresult rv = mStorageImpl->SetValue(IsCallerSecure(), aKey, aData, oldValue);
+  if (NS_FAILED(rv))
+    return rv;
 
   if ((oldValue != aData || mStorageType == GlobalStorage) && mEventBroadcaster)
     mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, aData);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey)
 {
   if (!CacheStoragePermissions())
     return NS_ERROR_DOM_SECURITY_ERR;
 
   if (aKey.IsEmpty())
     return NS_OK;
 
   nsString oldValue;
-  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
-
-  if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  if (UseDB()) {
-#ifdef MOZ_STORAGE
-    nsresult rv = InitDB();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsAutoString value;
-    PRBool secureItem;
-    rv = GetDBValue(aKey, value, &secureItem);
-    if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
-      return NS_OK;
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    oldValue = value;
-
-    rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain),
-                               aKey.Length() + value.Length());
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Before bug 536544 got fixed we were dropping mItemsCached flag here
-#endif
-  }
-  else if (entry) {
-    // clear string as StorageItems may be referencing this item
-    oldValue = entry->mItem->GetValueInternal();
-    entry->mItem->ClearValue();
-  }
-
-  if (entry) {
-    mItems.RawRemoveEntry(entry);
-  }
+  nsresult rv = mStorageImpl->RemoveValue(IsCallerSecure(), aKey, oldValue);
+  if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
+    return NS_OK;
+  if (NS_FAILED(rv))
+    return rv;
 
   if ((!oldValue.IsEmpty() && mStorageType != GlobalStorage) && mEventBroadcaster) {
     nsAutoString nullString;
     SetDOMStringToNull(nullString);
     mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, nullString);
   }
 
   return NS_OK;
 }
 
-PR_STATIC_CALLBACK(PLDHashOperator)
-CheckSecure(nsSessionStorageEntry* aEntry, void* userArg)
-{
-  PRBool* secure = (PRBool*)userArg;
-  if (aEntry->mItem->IsSecure()) {
-    *secure = PR_TRUE;
-    return PL_DHASH_STOP;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
 nsresult
 nsDOMStorage::Clear()
 {
   if (!CacheStoragePermissions())
     return NS_ERROR_DOM_SECURITY_ERR;
 
-  if (UseDB())
-    CacheKeysFromDB();
-
-  PRInt32 oldCount = mItems.Count();
-
-  PRBool foundSecureItem = PR_FALSE;
-  mItems.EnumerateEntries(CheckSecure, &foundSecureItem);
-
-  if (foundSecureItem && !IsCallerSecure()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-#ifdef MOZ_STORAGE
-  if (UseDB()) {
-    nsresult rv = InitDB();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = gStorageDB->ClearStorage(this);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-#endif
-
-  mItems.Clear();
-
+  PRInt32 oldCount;
+  nsresult rv = mStorageImpl->Clear(IsCallerSecure(), &oldCount);
+  if (NS_FAILED(rv))
+    return rv;
+  
   if (oldCount && mEventBroadcaster) {
     nsAutoString nullString;
     SetDOMStringToNull(nullString);
     mEventBroadcaster->BroadcastChangeNotification(nullString, nullString, nullString);
   }
 
   return NS_OK;
 }
 
-nsresult
-nsDOMStorage::InitDB()
-{
-#ifdef MOZ_STORAGE
-  if (!gStorageDB) {
-    gStorageDB = new nsDOMStorageDBWrapper();
-    if (!gStorageDB)
-      return NS_ERROR_OUT_OF_MEMORY;
-
-    nsresult rv = gStorageDB->Init();
-    if (NS_FAILED(rv)) {
-      // Failed to initialize the DB, delete it and null out the
-      // pointer so we don't end up attempting to use an
-      // un-initialized DB later on.
-
-      delete gStorageDB;
-      gStorageDB = nsnull;
-
-      return rv;
-    }
-  }
-#endif
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMStorage::CacheKeysFromDB()
-{
-#ifdef MOZ_STORAGE
-  // cache all the keys in the hash. This is used by the Length and Key methods
-  // use this cache for better performance. The disadvantage is that the
-  // order may break if someone changes the keys in the database directly.
-  if (!mItemsCached) {
-    nsresult rv = InitDB();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mItems.Clear();
-
-    rv = gStorageDB->GetAllKeys(this, &mItems);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mItemsCached = PR_TRUE;
-  }
-#endif
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMStorage::GetCachedValue(const nsAString& aKey, nsAString& aValue,
-                             PRBool* aSecure)
-{
-  aValue.Truncate();
-  *aSecure = PR_FALSE;
-
-  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
-  if (!entry)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  aValue = entry->mItem->GetValueInternal();
-  *aSecure = entry->mItem->IsSecure();
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue,
-                         PRBool* aSecure)
-{
-  aValue.Truncate();
-
-#ifdef MOZ_STORAGE
-  if (!UseDB())
-    return NS_OK;
-
-  nsresult rv = InitDB();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString value;
-  rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure);
-
-  if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && mStorageType != GlobalStorage) {
-    SetDOMStringToNull(aValue);
-  }
-
-  if (NS_FAILED(rv))
-    return rv;
-
-  if (!IsCallerSecure() && *aSecure) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  aValue.Assign(value);
-#endif
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMStorage::SetDBValue(const nsAString& aKey,
-                         const nsAString& aValue,
-                         PRBool aSecure)
-{
-#ifdef MOZ_STORAGE
-  if (!UseDB())
-    return NS_OK;
-
-  nsresult rv = InitDB();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRInt32 offlineAppPermission;
-  PRInt32 quota;
-  PRInt32 warnQuota;
-  offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota,
-                                  CanUseChromePersist());
-
-  PRInt32 usage;
-  rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota,
-                          !IS_PERMISSION_ALLOWED(offlineAppPermission),
-                          &usage);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Before bug 536544 got fixed we were dropping mItemsCached flag here
-
-  if (warnQuota >= 0 && usage > warnQuota) {
-    // try to include the window that exceeded the warn quota
-    nsCOMPtr<nsIDOMWindow> window;
-    JSContext *cx;
-    nsCOMPtr<nsIJSContextStack> stack =
-      do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-    if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
-      nsCOMPtr<nsIScriptContext> scriptContext;
-      scriptContext = GetScriptContextFromJSContext(cx);
-      if (scriptContext) {
-        window = do_QueryInterface(scriptContext->GetGlobalObject());
-      }
-    }
-
-    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    os->NotifyObservers(window, "dom-storage-warn-quota-exceeded",
-                        NS_ConvertUTF8toUTF16(mDomain).get());
-  }
-
-#endif
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMStorage::SetSecure(const nsAString& aKey, PRBool aSecure)
-{
-#ifdef MOZ_STORAGE
-  if (UseDB()) {
-    nsresult rv = InitDB();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    return gStorageDB->SetSecure(this, aKey, aSecure);
-  }
-#else
-  return NS_ERROR_NOT_IMPLEMENTED;
-#endif
-
-  nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
-  NS_ASSERTION(entry, "Don't use SetSecure() with nonexistent keys!");
-
-  if (entry) {
-    entry->mItem->SetSecureInternal(aSecure);
-  }  
-
-  return NS_OK;
-}
-
-static PLDHashOperator
-ClearStorageItem(nsSessionStorageEntry* aEntry, void* userArg)
-{
-  aEntry->mItem->SetValueInternal(EmptyString());
-  return PL_DHASH_NEXT;
-}
-
-void
-nsDOMStorage::ClearAll()
-{
-  mItems.EnumerateEntries(ClearStorageItem, nsnull);
-  mItemsCached = PR_FALSE;
-}
-
 already_AddRefed<nsIDOMStorage>
 nsDOMStorage::Clone()
 {
   NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement cloning");
   return nsnull;
 }
 
 already_AddRefed<nsIDOMStorage>
@@ -1405,46 +1721,26 @@ nsDOMStorage::Fork(const nsSubstring &aD
 }
 
 PRBool nsDOMStorage::IsForkOf(nsIDOMStorage* aThat)
 {
   NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement forking");
   return PR_FALSE;
 }
 
-struct KeysArrayBuilderStruct
+nsresult
+nsDOMStorage::CloneFrom(nsDOMStorage* aThat)
 {
-  PRBool callerIsSecure;
-  nsTArray<nsString> *keys;
-};
-
-static PLDHashOperator
-KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg)
-{
-  KeysArrayBuilderStruct *keystruct = (KeysArrayBuilderStruct *)userArg;
-  
-  if (keystruct->callerIsSecure || !aEntry->mItem->IsSecure())
-    keystruct->keys->AppendElement(aEntry->GetKey());
-
-  return PL_DHASH_NEXT;
+  return mStorageImpl->CloneFrom(IsCallerSecure(), aThat->mStorageImpl);
 }
 
 nsTArray<nsString> *
 nsDOMStorage::GetKeys()
 {
-  if (UseDB())
-    CacheKeysFromDB();
-
-  KeysArrayBuilderStruct keystruct;
-  keystruct.callerIsSecure = IsCallerSecure();
-  keystruct.keys = new nsTArray<nsString>();
-  if (keystruct.keys)
-    mItems.EnumerateEntries(KeysArrayBuilder, &keystruct);
- 
-  return keystruct.keys;
+  return mStorageImpl->GetKeys(IsCallerSecure());
 }
 
 nsIPrincipal*
 nsDOMStorage::Principal()
 {
   return nsnull;
 }
 
@@ -1472,17 +1768,17 @@ nsDOMStorage::CanAccess(nsIPrincipal *aP
     return PR_TRUE;
 
   nsCAutoString domain;
   nsCOMPtr<nsIURI> unused;
   nsresult rv = GetPrincipalURIAndHost(aPrincipal,
                                        getter_AddRefs(unused), domain);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
-  return domain.Equals(mDomain);
+  return domain.Equals(mStorageImpl->mDomain);
 }
 
 nsPIDOMStorage::nsDOMStorageType
 nsDOMStorage::StorageType()
 {
   return mStorageType;
 }
 
@@ -1497,95 +1793,17 @@ nsDOMStorage::BroadcastChangeNotificatio
     return;
   }
 
   // Fire off a notification that a storage object changed. If the
   // storage object is a session storage object, we don't pass a
   // domain, but if it's a global storage object we do.
   observerService->NotifyObservers((nsIDOMStorageObsolete *)this,
                                    "dom-storage-changed",
-                                   NS_ConvertUTF8toUTF16(mDomain).get());
-}
-
-nsresult
-nsDOMStorage::MaybeCommitTemporaryTable(bool force)
-{
-#ifdef MOZ_STORAGE
-  if (!UseDB())
-    return NS_OK;
-
-  if (!mLoadedTemporaryTable)
-    return NS_OK;
-
-  // If we are not forced to flush (e.g. on shutdown) then don't flush if the
-  // last table access is less then 5 seconds ago or the table itself is not
-  // older then 30 secs
-  if (!force &&
-     ((TimeStamp::Now() - mLastTemporaryTableAccessTime).ToSeconds() < 
-       NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_INACTIVITY_TIME) &&
-     ((TimeStamp::Now() - mTemporaryTableAge).ToSeconds() < 
-       NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_AGE))
-    return NS_OK;
-
-  return gStorageDB->FlushAndDeleteTemporaryTableForStorage(this);
-#endif
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMStorage::RegisterObservers()
-{
-  nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService();
-  if (obsserv) {
-    obsserv->AddObserver(this, "profile-before-change", PR_TRUE);
-    obsserv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
-    obsserv->AddObserver(this, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, PR_TRUE);
-  }
-  return NS_OK;
-}
-
-bool
-nsDOMStorage::WasTemporaryTableLoaded()
-{
-  return mLoadedTemporaryTable;
-}
-
-void
-nsDOMStorage::SetTemporaryTableLoaded(bool loaded)
-{
-  if (loaded) {
-    mLastTemporaryTableAccessTime = TimeStamp::Now();
-    if (!mLoadedTemporaryTable)
-      mTemporaryTableAge = mLastTemporaryTableAccessTime;
-  }
-
-  mLoadedTemporaryTable = loaded;
-}
-
-NS_IMETHODIMP
-nsDOMStorage::Observe(nsISupports *subject,
-                      const char *topic,
-                      const PRUnichar *data)
-{
-  bool isProfileBeforeChange = !strcmp(topic, "profile-before-change");
-  bool isXPCOMShutdown = !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
-  bool isFlushTimer = !strcmp(topic, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER);
-
-  if (isXPCOMShutdown || isProfileBeforeChange || isFlushTimer) {
-    nsresult rv = MaybeCommitTemporaryTable(isXPCOMShutdown || isProfileBeforeChange);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("DOMStorage: temporary table commit failed");
-    }
-
-    return NS_OK;
-  }
-
-  NS_WARNING("Unrecognized topic in nsDOMStorage::Observe");
-  return NS_OK;
+                                   NS_ConvertUTF8toUTF16(mStorageImpl->mDomain).get());
 }
 
 //
 // nsDOMStorage2
 //
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage2)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorage2)
@@ -2003,33 +2221,33 @@ NS_NewDOMStorageList(nsIDOMStorageList**
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageItem)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorageItem)
   {
     tmp->mStorage = nsnull;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorageItem)
   {
-    cb.NoteXPCOMChild((nsIDOMStorageObsolete*) tmp->mStorage);
+    cb.NoteXPCOMChild((nsISupports*) tmp->mStorage);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem)
 
 DOMCI_DATA(StorageItem, nsDOMStorageItem)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorageItem)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageItem)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageItem)
   NS_INTERFACE_MAP_ENTRY(nsIDOMToString)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageItem)
 NS_INTERFACE_MAP_END
 
-nsDOMStorageItem::nsDOMStorageItem(nsDOMStorage* aStorage,
+nsDOMStorageItem::nsDOMStorageItem(DOMStorageBase* aStorage,
                                    const nsAString& aKey,
                                    const nsAString& aValue,
                                    PRBool aSecure)
   : mSecure(aSecure),
     mKey(aKey),
     mValue(aValue),
     mStorage(aStorage)
 {
@@ -2073,21 +2291,22 @@ nsDOMStorageItem::SetSecure(PRBool aSecu
 
 NS_IMETHODIMP
 nsDOMStorageItem::GetValue(nsAString& aValue)
 {
   if (!mStorage->CacheStoragePermissions())
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
 
   if (mStorage->UseDB()) {
-    // GetDBValue checks the secure state so no need to do it here
     PRBool secure;
     nsresult rv = mStorage->GetDBValue(mKey, aValue, &secure);
     if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
       return NS_OK;
+    if (NS_SUCCEEDED(rv) && !IsCallerSecure() && secure)
+      return NS_ERROR_DOM_SECURITY_ERR;
     return rv;
   }
 
   if (IsSecure() && !IsCallerSecure()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   aValue = mValue;
--- a/dom/src/storage/nsDOMStorage.h
+++ b/dom/src/storage/nsDOMStorage.h
@@ -75,25 +75,34 @@
 
 class nsDOMStorage;
 class nsIDOMStorage;
 class nsDOMStorageItem;
 
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 
+namespace mozilla {
+namespace dom {
+class StorageParent;
+}
+}
+using mozilla::dom::StorageParent;
+
+class DOMStorageImpl;
+
 class nsDOMStorageEntry : public nsVoidPtrHashKey
 {
 public:
   nsDOMStorageEntry(KeyTypePointer aStr);
   nsDOMStorageEntry(const nsDOMStorageEntry& aToCopy);
   ~nsDOMStorageEntry();
 
   // weak reference so that it can be deleted when no longer used
-  nsDOMStorage* mStorage;
+  DOMStorageImpl* mStorage;
 };
 
 class nsSessionStorageEntry : public nsStringHashKey
 {
 public:
   nsSessionStorageEntry(KeyTypePointer aStr);
   nsSessionStorageEntry(const nsSessionStorageEntry& aToCopy);
   ~nsSessionStorageEntry();
@@ -111,18 +120,18 @@ public:
   // nsIDOMStorageManager
   NS_DECL_NSIDOMSTORAGEMANAGER
 
   // nsIObserver
   NS_DECL_NSIOBSERVER
 
   nsDOMStorageManager();
 
-  void AddToStoragesHash(nsDOMStorage* aStorage);
-  void RemoveFromStoragesHash(nsDOMStorage* aStorage);
+  void AddToStoragesHash(DOMStorageImpl* aStorage);
+  void RemoveFromStoragesHash(DOMStorageImpl* aStorage);
 
   nsresult ClearAllStorages();
 
   PRBool InPrivateBrowsingMode() { return mInPrivateBrowsing; }
 
   static nsresult Initialize();
   static nsDOMStorageManager* GetInstance();
   static void Shutdown();
@@ -130,31 +139,235 @@ public:
   static nsDOMStorageManager* gStorageManager;
 
 protected:
 
   nsTHashtable<nsDOMStorageEntry> mStorages;
   PRBool mInPrivateBrowsing;
 };
 
+class DOMStorageBase : public nsISupports
+{
+public:
+  DOMStorageBase();
+  DOMStorageBase(DOMStorageBase&);
+
+  virtual void InitAsSessionStorage(nsIURI* aDomainURI);
+  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist);
+  virtual void InitAsGlobalStorage(const nsACString& aDomainDemanded);
+
+  virtual nsTArray<nsString>* GetKeys(bool aCallerSecure) = 0;
+  virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength) = 0;
+  virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey) = 0;
+  virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey,
+                                      nsresult* rv) = 0;
+  virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey,
+                            const nsAString& aData, nsAString& aOldValue) = 0;
+  virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey,
+                               nsAString& aOldValue) = 0;
+  virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount) = 0;
+  
+  // If true, the contents of the storage should be stored in the
+  // database, otherwise this storage should act like a session
+  // storage.
+  // This call relies on mSessionOnly, and should only be used
+  // after a CacheStoragePermissions() call.  See the comments
+  // for mSessionOnly below.
+  PRBool UseDB() {
+    return mUseDB;
+  }
+
+  // retrieve the value and secure state corresponding to a key out of storage.
+  virtual nsresult
+  GetDBValue(const nsAString& aKey,
+             nsAString& aValue,
+             PRBool* aSecure) = 0;
+
+  // set the value corresponding to a key in the storage. If
+  // aSecure is false, then attempts to modify a secure value
+  // throw NS_ERROR_DOM_INVALID_ACCESS_ERR
+  virtual nsresult
+  SetDBValue(const nsAString& aKey,
+             const nsAString& aValue,
+             PRBool aSecure) = 0;
+
+  // set the value corresponding to a key as secure.
+  virtual nsresult
+  SetSecure(const nsAString& aKey, PRBool aSecure) = 0;
+
+  virtual nsresult
+  CloneFrom(bool aCallerSecure, DOMStorageBase* aThat) = 0;
+
+  // e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending
+  // on association with a domain (globalStorage) or
+  // an origin (localStorage).
+  nsCString& GetScopeDBKey() {return mScopeDBKey;}
+
+  // e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain or
+  // reversed offline application allowed domain.
+  nsCString& GetQuotaDomainDBKey(PRBool aOfflineAllowed)
+  {
+    return aOfflineAllowed ? mQuotaDomainDBKey : mQuotaETLDplus1DomainDBKey;
+  }
+
+  virtual bool CacheStoragePermissions() = 0;
+
+protected:
+  friend class nsDOMStorageManager;
+  friend class nsDOMStorage;
+
+  nsPIDOMStorage::nsDOMStorageType mStorageType;
+  
+  // true if the storage database should be used for values
+  PRPackedBool mUseDB;
+
+  // true if the preferences indicates that this storage should be
+  // session only. This member is updated by
+  // CacheStoragePermissions(), using the current principal.
+  // CacheStoragePermissions() must be called at each entry point to
+  // make sure this stays up to date.
+  PRPackedBool mSessionOnly;
+
+  // domain this store is associated with
+  nsCString mDomain;
+
+  // keys are used for database queries.
+  // see comments of the getters bellow.
+  nsCString mScopeDBKey;
+  nsCString mQuotaETLDplus1DomainDBKey;
+  nsCString mQuotaDomainDBKey;
+
+  bool mCanUseChromePersist;
+};
+
+class DOMStorageImpl : public DOMStorageBase
+                     , public nsIObserver
+                     , public nsSupportsWeakReference
+
+{
+public:
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMStorageImpl, nsIObserver)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  DOMStorageImpl(nsDOMStorage*);
+  DOMStorageImpl(nsDOMStorage*, DOMStorageImpl&);
+  ~DOMStorageImpl();
+
+  // Cross-process storage implementations never have InitAs(Session|Local|Global)Storage
+  // called, so the appropriate initialization needs to happen from the child.
+  void InitFromChild(bool aUseDB, bool aCanUseChromePersist,
+                     const nsACString& aDomain,
+                     const nsACString& aScopeDBKey,
+                     const nsACString& aQuotaDomainDBKey,
+                     const nsACString& aQuotaETLDplus1DomainDBKey,
+                     PRUint32 aStorageType);
+
+  virtual void InitAsSessionStorage(nsIURI* aDomainURI);
+  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist);
+  virtual void InitAsGlobalStorage(const nsACString& aDomainDemanded);
+
+  PRBool SessionOnly() {
+    return mSessionOnly;
+  }
+
+  virtual nsTArray<nsString>* GetKeys(bool aCallerSecure);
+  virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength);
+  virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey);
+  virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey,
+                                      nsresult* rv);
+  virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey,
+                            const nsAString& aData, nsAString& aOldValue);
+  virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey,
+                               nsAString& aOldValue);
+  virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount);
+
+  // cache the keys from the database for faster lookup
+  nsresult CacheKeysFromDB();
+  
+  // Some privileged internal pages can use a persistent storage even in
+  // session-only or private-browsing modes.
+  bool CanUseChromePersist();
+
+  // retrieve the value and secure state corresponding to a key out of storage
+  // that has been cached in mItems hash table.
+  nsresult
+  GetCachedValue(const nsAString& aKey,
+                 nsAString& aValue,
+                 PRBool* aSecure);
+
+  // retrieve the value and secure state corresponding to a key out of storage.
+  virtual nsresult
+  GetDBValue(const nsAString& aKey,
+             nsAString& aValue,
+             PRBool* aSecure);
+
+  // set the value corresponding to a key in the storage. If
+  // aSecure is false, then attempts to modify a secure value
+  // throw NS_ERROR_DOM_INVALID_ACCESS_ERR
+  virtual nsresult
+  SetDBValue(const nsAString& aKey,
+             const nsAString& aValue,
+             PRBool aSecure);
+
+  // set the value corresponding to a key as secure.
+  virtual nsresult
+  SetSecure(const nsAString& aKey, PRBool aSecure);
+
+  // clear all values from the store
+  void ClearAll();
+
+  virtual nsresult
+  CloneFrom(bool aCallerSecure, DOMStorageBase* aThat);
+
+  nsresult RegisterObservers();
+  nsresult MaybeCommitTemporaryTable(bool force);
+
+  bool WasTemporaryTableLoaded();
+  void SetTemporaryTableLoaded(bool loaded);
+
+  virtual bool CacheStoragePermissions();
+
+private:
+#ifdef MOZ_STORAGE
+  static nsDOMStorageDBWrapper* gStorageDB;
+#endif
+  friend class nsDOMStorageManager;
+  friend class StorageParent;
+
+  void Init(nsDOMStorage*);
+
+  static nsresult InitDB();
+
+  // true if items from the database are cached
+  PRPackedBool mItemsCached;
+
+  // the key->value item pairs
+  nsTHashtable<nsSessionStorageEntry> mItems;
+
+  // Weak reference to the owning storage instance
+  nsDOMStorage* mOwner;
+
+  bool mLoadedTemporaryTable;
+  TimeStamp mLastTemporaryTableAccessTime;
+  TimeStamp mTemporaryTableAge;
+};
+
 class nsDOMStorage : public nsIDOMStorageObsolete,
-                     public nsPIDOMStorage,
-                     public nsIObserver,
-                     public nsSupportsWeakReference
+                     public nsPIDOMStorage
 {
 public:
   nsDOMStorage();
   nsDOMStorage(nsDOMStorage& aThat);
   virtual ~nsDOMStorage();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete)
 
   NS_DECL_NSIDOMSTORAGEOBSOLETE
-  NS_DECL_NSIOBSERVER
 
   // Helpers for implementing nsIDOMStorage
   nsresult GetItem(const nsAString& key, nsAString& aData);
   nsresult Clear();
 
   // nsPIDOMStorage
   virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI);
   virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI);
@@ -165,167 +378,66 @@ public:
   virtual nsTArray<nsString> *GetKeys();
   virtual nsIPrincipal* Principal();
   virtual PRBool CanAccess(nsIPrincipal *aPrincipal);
   virtual nsDOMStorageType StorageType();
   virtual void BroadcastChangeNotification(const nsSubstring &aKey,
                                            const nsSubstring &aOldValue,
                                            const nsSubstring &aNewValue);
 
-  // If true, the contents of the storage should be stored in the
-  // database, otherwise this storage should act like a session
-  // storage.
-  // This call relies on mSessionOnly, and should only be used
-  // after a CacheStoragePermissions() call.  See the comments
-  // for mSessionOnly below.
-  PRBool UseDB() {
-    return mUseDB;
-  }
-
-  PRBool SessionOnly() {
-    return mSessionOnly;
-  }
-
-  // Some privileged internal pages can use a persistent storage even in
-  // session-only or private-browsing modes.
-  bool CanUseChromePersist();
-
   // Check whether storage may be used by the caller, and whether it
   // is session only.  Returns true if storage may be used.
   static PRBool
   CanUseStorage(PRPackedBool* aSessionOnly);
 
   // Check whether this URI can use chrome persist storage.  This kind of
   // storage can bypass cookies limits, private browsing and uses the offline
   // apps quota.
   static PRBool
   URICanUseChromePersist(nsIURI* aURI);
   
   // Check whether storage may be used.  Updates mSessionOnly based on
   // the result of CanUseStorage.
   PRBool
   CacheStoragePermissions();
 
-  // retrieve the value and secure state corresponding to a key out of storage
-  // that has been cached in mItems hash table.
-  nsresult
-  GetCachedValue(const nsAString& aKey,
-                 nsAString& aValue,
-                 PRBool* aSecure);
-
-  // retrieve the value and secure state corresponding to a key out of storage.
-  nsresult
-  GetDBValue(const nsAString& aKey,
-             nsAString& aValue,
-             PRBool* aSecure);
-
-  // set the value corresponding to a key in the storage. If
-  // aSecure is false, then attempts to modify a secure value
-  // throw NS_ERROR_DOM_INVALID_ACCESS_ERR
-  nsresult
-  SetDBValue(const nsAString& aKey,
-             const nsAString& aValue,
-             PRBool aSecure);
-
-  // set the value corresponding to a key as secure.
-  nsresult
-  SetSecure(const nsAString& aKey, PRBool aSecure);
-
-  // clear all values from the store
-  void ClearAll();
-
-  nsresult
-  CloneFrom(nsDOMStorage* aThat);
-
   nsIDOMStorageItem* GetNamedItem(const nsAString& aKey, nsresult* aResult);
 
   static nsDOMStorage* FromSupports(nsISupports* aSupports)
   {
     return static_cast<nsDOMStorage*>(static_cast<nsIDOMStorageObsolete*>(aSupports));
   }
 
-  nsresult RegisterObservers();
-  nsresult MaybeCommitTemporaryTable(bool force);
+  nsresult SetSecure(const nsAString& aKey, PRBool aSecure)
+  {
+    return mStorageImpl->SetSecure(aKey, aSecure);
+  }
 
-  bool WasTemporaryTableLoaded();
-  void SetTemporaryTableLoaded(bool loaded);
+  nsresult CloneFrom(nsDOMStorage* aThat);
 
-protected:
-
-  friend class nsDOMStorageManager;
+ protected:
   friend class nsDOMStorage2;
   friend class nsDOMStoragePersistentDB;
 
-  static nsresult InitDB();
-
-  // cache the keys from the database for faster lookup
-  nsresult CacheKeysFromDB();
+  nsRefPtr<DOMStorageBase> mStorageImpl;
 
   PRBool CanAccessSystem(nsIPrincipal *aPrincipal);
 
-  // true if the storage database should be used for values
-  PRPackedBool mUseDB;
-
-  // domain this store is associated with
-  nsCString mDomain;
-
   // document URI of the document this storage is bound to
   nsString mDocumentURI;
 
-  // true if the preferences indicates that this storage should be
-  // session only. This member is updated by
-  // CacheStoragePermissions(), using the current principal.
-  // CacheStoragePermissions() must be called at each entry point to
-  // make sure this stays up to date.
-  PRPackedBool mSessionOnly;
-
   // true if this storage was initialized as a localStorage object.  localStorage
   // objects are scoped to scheme/host/port in the database, while globalStorage
   // objects are scoped just to host.  this flag also tells the manager to map
   // this storage also in mLocalStorages hash table.
   nsDOMStorageType mStorageType;
 
-  // true if items from the database are cached
-  PRPackedBool mItemsCached;
-
-  // the key->value item pairs
-  nsTHashtable<nsSessionStorageEntry> mItems;
-
-  // keys are used for database queries.
-  // see comments of the getters bellow.
-  nsCString mScopeDBKey;
-  nsCString mQuotaETLDplus1DomainDBKey;
-  nsCString mQuotaDomainDBKey;
-
   friend class nsIDOMStorage2;
   nsPIDOMStorage* mSecurityChecker;
   nsPIDOMStorage* mEventBroadcaster;
-
-  bool mCanUseChromePersist;
-
-  bool mLoadedTemporaryTable;
-  TimeStamp mLastTemporaryTableAccessTime;
-  TimeStamp mTemporaryTableAge;
-
-public:
-  // e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending
-  // on association with a domain (globalStorage) or
-  // an origin (localStorage).
-  nsCString& GetScopeDBKey() {return mScopeDBKey;}
-
-  // e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain or
-  // reversed offline application allowed domain.
-  nsCString& GetQuotaDomainDBKey(PRBool aOfflineAllowed)
-  {
-    return aOfflineAllowed ? mQuotaDomainDBKey : mQuotaETLDplus1DomainDBKey;
-  }
-
- #ifdef MOZ_STORAGE
-   static nsDOMStorageDBWrapper* gStorageDB;
- #endif
 };
 
 class nsDOMStorage2 : public nsIDOMStorage,
                       public nsPIDOMStorage
 {
 public:
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -418,17 +530,17 @@ protected:
 
   nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorageObsolete> mStorages;
 };
 
 class nsDOMStorageItem : public nsIDOMStorageItem,
                          public nsIDOMToString
 {
 public:
-  nsDOMStorageItem(nsDOMStorage* aStorage,
+  nsDOMStorageItem(DOMStorageBase* aStorage,
                    const nsAString& aKey,
                    const nsAString& aValue,
                    PRBool aSecure);
   virtual ~nsDOMStorageItem();
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem)
@@ -472,17 +584,17 @@ protected:
   // key for the item
   nsString mKey;
 
   // value of the item
   nsString mValue;
 
   // If this item came from the db, mStorage points to the storage
   // object where this item came from.
-  nsRefPtr<nsDOMStorage> mStorage;
+  nsRefPtr<DOMStorageBase> mStorage;
 };
 
 class nsDOMStorageEvent : public nsDOMEvent,
                           public nsIDOMStorageEvent
 {
 public:
   nsDOMStorageEvent()
     : nsDOMEvent(nsnull, nsnull)
--- a/dom/src/storage/nsDOMStorageDBWrapper.cpp
+++ b/dom/src/storage/nsDOMStorageDBWrapper.cpp
@@ -103,73 +103,73 @@ nsDOMStorageDBWrapper::Init()
   rv = mFlushTimer->Init(nsDOMStorageManager::gStorageManager, 5000,
                          nsITimer::TYPE_REPEATING_SLACK);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageDBWrapper::EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage)
+nsDOMStorageDBWrapper::EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.EnsureLoadTemporaryTableForStorage(aStorage);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return NS_OK;
   if (aStorage->SessionOnly())
     return NS_OK;
 
   return mPersistentDB.EnsureLoadTemporaryTableForStorage(aStorage);
 }
 
 nsresult
-nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage)
+nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.FlushAndDeleteTemporaryTableForStorage(aStorage);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return NS_OK;
   if (aStorage->SessionOnly())
     return NS_OK;
 
   return mPersistentDB.FlushAndDeleteTemporaryTableForStorage(aStorage);
 }
 
 nsresult
-nsDOMStorageDBWrapper::GetAllKeys(nsDOMStorage* aStorage,
+nsDOMStorageDBWrapper::GetAllKeys(DOMStorageImpl* aStorage,
                                   nsTHashtable<nsSessionStorageEntry>* aKeys)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.GetAllKeys(aStorage, aKeys);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return mPrivateBrowsingDB.GetAllKeys(aStorage, aKeys);
   if (aStorage->SessionOnly())
     return mSessionOnlyDB.GetAllKeys(aStorage, aKeys);
 
   return mPersistentDB.GetAllKeys(aStorage, aKeys);
 }
 
 nsresult
-nsDOMStorageDBWrapper::GetKeyValue(nsDOMStorage* aStorage,
+nsDOMStorageDBWrapper::GetKeyValue(DOMStorageImpl* aStorage,
                                    const nsAString& aKey,
                                    nsAString& aValue,
                                    PRBool* aSecure)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.GetKeyValue(aStorage, aKey, aValue, aSecure);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return mPrivateBrowsingDB.GetKeyValue(aStorage, aKey, aValue, aSecure);
   if (aStorage->SessionOnly())
     return mSessionOnlyDB.GetKeyValue(aStorage, aKey, aValue, aSecure);
 
   return mPersistentDB.GetKeyValue(aStorage, aKey, aValue, aSecure);
 }
 
 nsresult
-nsDOMStorageDBWrapper::SetKey(nsDOMStorage* aStorage,
+nsDOMStorageDBWrapper::SetKey(DOMStorageImpl* aStorage,
                               const nsAString& aKey,
                               const nsAString& aValue,
                               PRBool aSecure,
                               PRInt32 aQuota,
                               PRBool aExcludeOfflineFromUsage,
                               PRInt32 *aNewUsage)
 {
   if (aStorage->CanUseChromePersist())
@@ -182,48 +182,48 @@ nsDOMStorageDBWrapper::SetKey(nsDOMStora
     return mSessionOnlyDB.SetKey(aStorage, aKey, aValue, aSecure,
                                       aQuota, aExcludeOfflineFromUsage, aNewUsage);
 
   return mPersistentDB.SetKey(aStorage, aKey, aValue, aSecure,
                                    aQuota, aExcludeOfflineFromUsage, aNewUsage);
 }
 
 nsresult
-nsDOMStorageDBWrapper::SetSecure(nsDOMStorage* aStorage,
+nsDOMStorageDBWrapper::SetSecure(DOMStorageImpl* aStorage,
                                  const nsAString& aKey,
                                  const PRBool aSecure)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.SetSecure(aStorage, aKey, aSecure);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return mPrivateBrowsingDB.SetSecure(aStorage, aKey, aSecure);
   if (aStorage->SessionOnly())
     return mSessionOnlyDB.SetSecure(aStorage, aKey, aSecure);
 
   return mPersistentDB.SetSecure(aStorage, aKey, aSecure);
 }
 
 nsresult
-nsDOMStorageDBWrapper::RemoveKey(nsDOMStorage* aStorage,
+nsDOMStorageDBWrapper::RemoveKey(DOMStorageImpl* aStorage,
                                  const nsAString& aKey,
                                  PRBool aExcludeOfflineFromUsage,
                                  PRInt32 aKeyUsage)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return mPrivateBrowsingDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage);
   if (aStorage->SessionOnly())
     return mSessionOnlyDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage);
 
   return mPersistentDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage);
 }
 
 nsresult
-nsDOMStorageDBWrapper::ClearStorage(nsDOMStorage* aStorage)
+nsDOMStorageDBWrapper::ClearStorage(DOMStorageImpl* aStorage)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.ClearStorage(aStorage);
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return mPrivateBrowsingDB.ClearStorage(aStorage);
   if (aStorage->SessionOnly())
     return mSessionOnlyDB.ClearStorage(aStorage);
 
@@ -301,17 +301,17 @@ nsDOMStorageDBWrapper::RemoveAll()
 
   rv = mPersistentDB.RemoveAll();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return rv;
 }
 
 nsresult
-nsDOMStorageDBWrapper::GetUsage(nsDOMStorage* aStorage,
+nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage,
                                 PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage)
 {
   if (aStorage->CanUseChromePersist())
     return mChromePersistentDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage);    
   if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
     return mPrivateBrowsingDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage);
   if (aStorage->SessionOnly())
     return mSessionOnlyDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage);
--- a/dom/src/storage/nsDOMStorageDBWrapper.h
+++ b/dom/src/storage/nsDOMStorageDBWrapper.h
@@ -88,73 +88,73 @@ class nsDOMStorageDBWrapper
 public:
   nsDOMStorageDBWrapper();
   ~nsDOMStorageDBWrapper();
 
   nsresult
   Init();
 
   nsresult
-  EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage);
+  EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage);
   nsresult
-  FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage);
+  FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage);
 
   /**
    * Retrieve a list of all the keys associated with a particular domain.
    */
   nsresult
-  GetAllKeys(nsDOMStorage* aStorage,
+  GetAllKeys(DOMStorageImpl* aStorage,
              nsTHashtable<nsSessionStorageEntry>* aKeys);
 
   /**
    * Retrieve a value and secure flag for a key from storage.
    *
    * @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found
    */
   nsresult
-  GetKeyValue(nsDOMStorage* aStorage,
+  GetKeyValue(DOMStorageImpl* aStorage,
               const nsAString& aKey,
               nsAString& aValue,
               PRBool* aSecure);
 
   /**
    * Set the value and secure flag for a key in storage.
    */
   nsresult
-  SetKey(nsDOMStorage* aStorage,
+  SetKey(DOMStorageImpl* aStorage,
          const nsAString& aKey,
          const nsAString& aValue,
          PRBool aSecure,
          PRInt32 aQuota,
          PRBool aExcludeOfflineFromUsage,
          PRInt32* aNewUsage);
 
   /**
    * Set the secure flag for a key in storage. Does nothing if the key was
    * not found.
    */
   nsresult
-  SetSecure(nsDOMStorage* aStorage,
+  SetSecure(DOMStorageImpl* aStorage,
             const nsAString& aKey,
             const PRBool aSecure);
 
   /**
    * Removes a key from storage.
    */
   nsresult
-  RemoveKey(nsDOMStorage* aStorage,
+  RemoveKey(DOMStorageImpl* aStorage,
             const nsAString& aKey,
             PRBool aExcludeOfflineFromUsage,
             PRInt32 aKeyUsage);
 
   /**
     * Remove all keys belonging to this storage.
     */
   nsresult
-  ClearStorage(nsDOMStorage* aStorage);
+  ClearStorage(DOMStorageImpl* aStorage);
 
   /**
    * Drop session-only storage for a specific host and all it's subdomains
    */
   nsresult
   DropSessionOnlyStoragesForHost(const nsACString& aHostName);
 
   /**
@@ -182,17 +182,17 @@ public:
    */
   nsresult
   RemoveAll();
 
   /**
     * Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
     */
   nsresult
-  GetUsage(nsDOMStorage* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage);
+  GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage);
 
   /**
     * Returns usage of the domain and optionaly by any subdomain.
     */
   nsresult
   GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage);
 
   /**
--- a/dom/src/storage/nsDOMStorageMemoryDB.cpp
+++ b/dom/src/storage/nsDOMStorageMemoryDB.cpp
@@ -69,17 +69,17 @@ AllKeyEnum(nsSessionStorageEntry* aEntry
   if (NS_FAILED(rv))
     item->mSecure = PR_FALSE;
 
   target->Put(aEntry->GetKey(), item);
   return PL_DHASH_NEXT;
 }
 
 nsresult
-nsDOMStorageMemoryDB::GetItemsTable(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::GetItemsTable(DOMStorageImpl* aStorage,
                                     nsInMemoryStorage** aMemoryStorage)
 {
   if (mData.Get(aStorage->GetScopeDBKey(), aMemoryStorage))
     return NS_OK;
 
   *aMemoryStorage = nsnull;
 
   nsInMemoryStorage* storageData = new nsInMemoryStorage();
@@ -109,17 +109,17 @@ nsDOMStorageMemoryDB::GetItemsTable(nsDO
   *aMemoryStorage = storageData;
 
   return NS_OK;
 }
 
 struct GetAllKeysEnumStruc
 {
   nsTHashtable<nsSessionStorageEntry>* mTarget;
-  nsDOMStorage* mStorage;
+  DOMStorageImpl* mStorage;
 };
 
 static PLDHashOperator
 GetAllKeysEnum(const nsAString& keyname,
                nsDOMStorageMemoryDB::nsInMemoryItem* item,
                void *closure)
 {
   GetAllKeysEnumStruc* struc = (GetAllKeysEnumStruc*)closure;
@@ -134,17 +134,17 @@ GetAllKeysEnum(const nsAString& keyname,
                                       item->mSecure);
   if (!entry->mItem)
     return PL_DHASH_STOP;
 
   return PL_DHASH_NEXT;
 }
 
 nsresult
-nsDOMStorageMemoryDB::GetAllKeys(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::GetAllKeys(DOMStorageImpl* aStorage,
                                  nsTHashtable<nsSessionStorageEntry>* aKeys)
 {
   nsresult rv;
 
   nsInMemoryStorage* storage;
   rv = GetItemsTable(aStorage, &storage);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -152,17 +152,17 @@ nsDOMStorageMemoryDB::GetAllKeys(nsDOMSt
   struc.mTarget = aKeys;
   struc.mStorage = aStorage;
   storage->mTable.EnumerateRead(GetAllKeysEnum, &struc);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageMemoryDB::GetKeyValue(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::GetKeyValue(DOMStorageImpl* aStorage,
                                   const nsAString& aKey,
                                   nsAString& aValue,
                                   PRBool* aSecure)
 {
   if (mPreloading) {
     NS_PRECONDITION(mPreloadDB, "Must have a preload DB set when preloading");
     return mPreloadDB->GetKeyValue(aStorage, aKey, aValue, aSecure);
   }
@@ -178,17 +178,17 @@ nsDOMStorageMemoryDB::GetKeyValue(nsDOMS
     return NS_ERROR_DOM_NOT_FOUND_ERR;
 
   aValue = item->mValue;
   *aSecure = item->mSecure;
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageMemoryDB::SetKey(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
                              const nsAString& aKey,
                              const nsAString& aValue,
                              PRBool aSecure,
                              PRInt32 aQuota,
                              PRBool aExcludeOfflineFromUsage,
                              PRInt32 *aNewUsage)
 {
   nsresult rv;
@@ -232,17 +232,17 @@ nsDOMStorageMemoryDB::SetKey(nsDOMStorag
   item->mSecure = aSecure;
 
   *aNewUsage = usage;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageMemoryDB::SetSecure(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::SetSecure(DOMStorageImpl* aStorage,
                                 const nsAString& aKey,
                                 const PRBool aSecure)
 {
   nsresult rv;
 
   nsInMemoryStorage* storage;
   rv = GetItemsTable(aStorage, &storage);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -252,17 +252,17 @@ nsDOMStorageMemoryDB::SetSecure(nsDOMSto
     return NS_ERROR_DOM_NOT_FOUND_ERR;
 
   item->mSecure = aSecure;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageMemoryDB::RemoveKey(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::RemoveKey(DOMStorageImpl* aStorage,
                                 const nsAString& aKey,
                                 PRBool aExcludeOfflineFromUsage,
                                 PRInt32 aKeyUsage)
 {
   nsresult rv;
 
   nsInMemoryStorage* storage;
   rv = GetItemsTable(aStorage, &storage);
@@ -286,30 +286,30 @@ RemoveAllKeysEnum(const nsAString& keyna
   nsDOMStorageMemoryDB::nsInMemoryStorage* storage =
       (nsDOMStorageMemoryDB::nsInMemoryStorage*)closure;
 
   storage->mUsageDelta -= keyname.Length() + item->mValue.Length();
   return PL_DHASH_REMOVE;
 }
 
 nsresult
-nsDOMStorageMemoryDB::ClearStorage(nsDOMStorage* aStorage)
+nsDOMStorageMemoryDB::ClearStorage(DOMStorageImpl* aStorage)
 {
   nsresult rv;
 
   nsInMemoryStorage* storage;
   rv = GetItemsTable(aStorage, &storage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   storage->mTable.Enumerate(RemoveAllKeysEnum, storage);
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageMemoryDB::DropStorage(nsDOMStorage* aStorage)
+nsDOMStorageMemoryDB::DropStorage(DOMStorageImpl* aStorage)
 {
   mData.Remove(aStorage->GetScopeDBKey());
   return NS_OK;
 }
 
 struct RemoveOwnersStruc
 {
   nsCString* mSubDomain;
@@ -382,17 +382,17 @@ nsDOMStorageMemoryDB::RemoveOwners(const
 nsresult
 nsDOMStorageMemoryDB::RemoveAll()
 {
   mData.Clear(); // XXX Check this releases all instances
   return NS_OK;
 }
 
 nsresult
-nsDOMStorageMemoryDB::GetUsage(nsDOMStorage* aStorage,
+nsDOMStorageMemoryDB::GetUsage(DOMStorageImpl* aStorage,
                                PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage)
 {
   return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage),
                           aExcludeOfflineFromUsage, aUsage);
 }
 
 nsresult
 nsDOMStorageMemoryDB::GetUsage(const nsACString& aDomain,
--- a/dom/src/storage/nsDOMStorageMemoryDB.h
+++ b/dom/src/storage/nsDOMStorageMemoryDB.h
@@ -77,78 +77,78 @@ public:
    */
   nsresult
   Init(nsDOMStoragePersistentDB* aPreloadDB = nsnull);
 
   /**
    *
    */
   nsresult
-  GetItemsTable(nsDOMStorage* aStorage,
+  GetItemsTable(DOMStorageImpl* aStorage,
                 nsInMemoryStorage** aMemoryStorage);
 
   /**
    * Retrieve a list of all the keys associated with a particular domain.
    */
   nsresult
-  GetAllKeys(nsDOMStorage* aStorage,
+  GetAllKeys(DOMStorageImpl* aStorage,
              nsTHashtable<nsSessionStorageEntry>* aKeys);
 
   /**
    * Retrieve a value and secure flag for a key from storage.
    *
    * @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found
    */
   nsresult
-  GetKeyValue(nsDOMStorage* aStorage,
+  GetKeyValue(DOMStorageImpl* aStorage,
               const nsAString& aKey,
               nsAString& aValue,
               PRBool* aSecure);
 
   /**
    * Set the value and secure flag for a key in storage.
    */
   nsresult
-  SetKey(nsDOMStorage* aStorage,
+  SetKey(DOMStorageImpl* aStorage,
          const nsAString& aKey,
          const nsAString& aValue,
          PRBool aSecure,
          PRInt32 aQuota,
          PRBool aExcludeOfflineFromUsage,
          PRInt32* aNewUsage);
 
   /**
    * Set the secure flag for a key in storage. Does nothing if the key was
    * not found.
    */
   nsresult
-  SetSecure(nsDOMStorage* aStorage,
+  SetSecure(DOMStorageImpl* aStorage,
             const nsAString& aKey,
             const PRBool aSecure);
 
   /**
    * Removes a key from storage.
    */
   nsresult
-  RemoveKey(nsDOMStorage* aStorage,
+  RemoveKey(DOMStorageImpl* aStorage,
             const nsAString& aKey,
             PRBool aExcludeOfflineFromUsage,
             PRInt32 aKeyUsage);
 
   /**
     * Remove all keys belonging to this storage.
     */
   nsresult
-  ClearStorage(nsDOMStorage* aStorage);
+  ClearStorage(DOMStorageImpl* aStorage);
 
   /**
    * If we have changed the persistent storage, drop any potential session storages
    */
   nsresult
-  DropStorage(nsDOMStorage* aStorage);
+  DropStorage(DOMStorageImpl* aStorage);
 
   /**
    * Removes all keys added by a given domain.
    */
   nsresult
   RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains);
 
   /**
@@ -164,17 +164,17 @@ public:
    */
   nsresult
   RemoveAll();
 
   /**
     * Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
     */
   nsresult
-  GetUsage(nsDOMStorage* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage);
+  GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage);
 
   /**
     * Returns usage of the domain and optionaly by any subdomain.
     */
   nsresult
   GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage);
 
 protected:
--- a/dom/src/storage/nsDOMStoragePersistentDB.cpp
+++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp
@@ -439,17 +439,17 @@ nsDOMStoragePersistentDB::Init(const nsS
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage)
+nsDOMStoragePersistentDB::EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage)
 {
   if (!aStorage->WasTemporaryTableLoaded()) {
     nsresult rv;
 
     rv = MaybeCommitInsertTransaction();
     NS_ENSURE_SUCCESS(rv, rv);
 
     mozStorageStatementScoper scope(mCopyToTempTableStatement);
@@ -470,17 +470,17 @@ nsDOMStoragePersistentDB::EnsureLoadTemp
 
   // Always call this to update the last access time
   aStorage->SetTemporaryTableLoaded(true);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage)
+nsDOMStoragePersistentDB::FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage)
 {
   if (!aStorage->WasTemporaryTableLoaded())
     return NS_OK;
 
   mozStorageTransaction trans(mConnection, PR_FALSE);
 
   nsresult rv;
 
@@ -525,17 +525,17 @@ nsDOMStoragePersistentDB::FlushAndDelete
   NS_ENSURE_SUCCESS(rv, rv);
 
   aStorage->SetTemporaryTableLoaded(false);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::GetAllKeys(nsDOMStorage* aStorage,
+nsDOMStoragePersistentDB::GetAllKeys(DOMStorageImpl* aStorage,
                                      nsTHashtable<nsSessionStorageEntry>* aKeys)
 {
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = EnsureLoadTemporaryTableForStorage(aStorage);
@@ -578,17 +578,17 @@ nsDOMStoragePersistentDB::GetAllKeys(nsD
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::GetKeyValue(nsDOMStorage* aStorage,
+nsDOMStoragePersistentDB::GetKeyValue(DOMStorageImpl* aStorage,
                                       const nsAString& aKey,
                                       nsAString& aValue,
                                       PRBool* aSecure)
 {
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -628,17 +628,17 @@ nsDOMStoragePersistentDB::GetKeyValue(ns
   }
 
   *aSecure = !!secureInt;
 
   return rv;
 }
 
 nsresult
-nsDOMStoragePersistentDB::SetKey(nsDOMStorage* aStorage,
+nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
                                  const nsAString& aKey,
                                  const nsAString& aValue,
                                  PRBool aSecure,
                                  PRInt32 aQuota,
                                  PRBool aExcludeOfflineFromUsage,
                                  PRInt32 *aNewUsage)
 {
   nsresult rv;
@@ -702,17 +702,17 @@ nsDOMStoragePersistentDB::SetKey(nsDOMSt
   }
 
   *aNewUsage = usage;
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::SetSecure(nsDOMStorage* aStorage,
+nsDOMStoragePersistentDB::SetSecure(DOMStorageImpl* aStorage,
                                     const nsAString& aKey,
                                     const PRBool aSecure)
 {
   nsresult rv;
 
   rv = EnsureLoadTemporaryTableForStorage(aStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -736,17 +736,17 @@ nsDOMStoragePersistentDB::SetSecure(nsDO
 
   rv = binder.Add();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return mSetSecureStatement->Execute();
 }
 
 nsresult
-nsDOMStoragePersistentDB::RemoveKey(nsDOMStorage* aStorage,
+nsDOMStoragePersistentDB::RemoveKey(DOMStorageImpl* aStorage,
                                     const nsAString& aKey,
                                     PRBool aExcludeOfflineFromUsage,
                                     PRInt32 aKeyUsage)
 {
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -772,17 +772,17 @@ nsDOMStoragePersistentDB::RemoveKey(nsDO
 
   rv = mRemoveKeyStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::ClearStorage(nsDOMStorage* aStorage)
+nsDOMStoragePersistentDB::ClearStorage(DOMStorageImpl* aStorage)
 {
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   mozStorageStatementScoper scope(mRemoveStorageStatement);
 
@@ -933,17 +933,17 @@ nsDOMStoragePersistentDB::RemoveAll()
 
   rv = mRemoveAllStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStoragePersistentDB::GetUsage(nsDOMStorage* aStorage,
+nsDOMStoragePersistentDB::GetUsage(DOMStorageImpl* aStorage,
                                    PRBool aExcludeOfflineFromUsage,
                                    PRInt32 *aUsage)
 {
   return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage),
                                                         aExcludeOfflineFromUsage,
                                                         aUsage);
 }
 
--- a/dom/src/storage/nsDOMStoragePersistentDB.h
+++ b/dom/src/storage/nsDOMStoragePersistentDB.h
@@ -39,85 +39,85 @@
 #ifndef nsDOMStoragePersistentDB_h___
 #define nsDOMStoragePersistentDB_h___
 
 #include "nscore.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatement.h"
 #include "nsTHashtable.h"
 
-class nsDOMStorage;
+class DOMStorageImpl;
 class nsSessionStorageEntry;
 
 class nsDOMStoragePersistentDB
 {
 public:
   nsDOMStoragePersistentDB();
   ~nsDOMStoragePersistentDB() {}
 
   nsresult
   Init(const nsString& aDatabaseName);
 
   nsresult
-  EnsureLoadTemporaryTableForStorage(nsDOMStorage* aStorage);
+  EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage);
   nsresult
-  FlushAndDeleteTemporaryTableForStorage(nsDOMStorage* aStorage);
+  FlushAndDeleteTemporaryTableForStorage(DOMStorageImpl* aStorage);
 
   /**
    * Retrieve a list of all the keys associated with a particular domain.
    */
   nsresult
-  GetAllKeys(nsDOMStorage* aStorage,
+  GetAllKeys(DOMStorageImpl* aStorage,
              nsTHashtable<nsSessionStorageEntry>* aKeys);
 
   /**
    * Retrieve a value and secure flag for a key from storage.
    *
    * @throws NS_ERROR_DOM_NOT_FOUND_ERR if key not found
    */
   nsresult
-  GetKeyValue(nsDOMStorage* aStorage,
+  GetKeyValue(DOMStorageImpl* aStorage,
               const nsAString& aKey,
               nsAString& aValue,
               PRBool* aSecure);
 
   /**
    * Set the value and secure flag for a key in storage.
    */
   nsresult
-  SetKey(nsDOMStorage* aStorage,
+  SetKey(DOMStorageImpl* aStorage,
          const nsAString& aKey,
          const nsAString& aValue,
          PRBool aSecure,
          PRInt32 aQuota,
          PRBool aExcludeOfflineFromUsage,
          PRInt32* aNewUsage);
 
   /**
    * Set the secure flag for a key in storage. Does nothing if the key was
    * not found.
    */
   nsresult
-  SetSecure(nsDOMStorage* aStorage,
+  SetSecure(DOMStorageImpl* aStorage,
             const nsAString& aKey,
             const PRBool aSecure);
 
   /**
    * Removes a key from storage.
    */
   nsresult
-  RemoveKey(nsDOMStorage* aStorage,
+  RemoveKey(DOMStorageImpl* aStorage,
             const nsAString& aKey,
             PRBool aExcludeOfflineFromUsage,
             PRInt32 aKeyUsage);
 
   /**
     * Remove all keys belonging to this storage.
     */
-  nsresult ClearStorage(nsDOMStorage* aStorage);
+  nsresult ClearStorage(DOMStorageImpl* aStorage);
 
   /**
    * Removes all keys added by a given domain.
    */
   nsresult
   RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains);
 
   /**
@@ -133,17 +133,17 @@ public:
    */
   nsresult
   RemoveAll();
 
   /**
     * Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
     */
   nsresult
-  GetUsage(nsDOMStorage* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage);
+  GetUsage(DOMStorageImpl* aStorage, PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage);
 
   /**
     * Returns usage of the domain and optionaly by any subdomain.
     */
   nsresult
   GetUsage(const nsACString& aDomain, PRBool aIncludeSubDomains, PRInt32 *aUsage);
 
   /**
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -52,16 +52,17 @@ EXPORT_LIBRARY = 1
 
 ##-----------------------------------------------------------------------------
 ## When you add IPDL files to a source directory, list the directory here.
 ##
 IPDLDIRS =  \
   uriloader/exthandler \
   dom/plugins  \
   dom/ipc  \
+  dom/src/storage \
   gfx/layers/ipc \
   ipc/ipdl/test/cxx  \
   ipc/testshell  \
   js/ipc  \
   js/jetpack \
   layout/ipc \
   netwerk/ipc  \
   netwerk/protocol/ftp \