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 id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewershonzab, blocking-fennec2
bugs584946
milestone2.0b8pre
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 \