Bug 1020172 - Patch 2: Manage TabParent in chrome process - v14. r=khuey
authorKershaw Chang <kechang@mozilla.com>
Wed, 29 Oct 2014 19:11:00 +0100
changeset 213163 01b25915ca374d803fa2e98f1dc47a9b59c007bf
parent 213162 fedce15e6ea22db45b0febcb8decce9ca200db80
child 213164 f644da9988dc60571721050f5c9d9028064d0493
push idunknown
push userunknown
push dateunknown
reviewerskhuey
bugs1020172
milestone36.0a1
Bug 1020172 - Patch 2: Manage TabParent in chrome process - v14. r=khuey
dom/ipc/ContentBridgeChild.cpp
dom/ipc/ContentBridgeChild.h
dom/ipc/ContentBridgeParent.cpp
dom/ipc/ContentBridgeParent.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/ContentProcessManager.cpp
dom/ipc/ContentProcessManager.h
dom/ipc/IdType.h
dom/ipc/PBrowserOrId.ipdlh
dom/ipc/PContent.ipdl
dom/ipc/PContentBridge.ipdl
dom/ipc/PTabContext.ipdlh
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabContext.cpp
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/moz.build
dom/ipc/nsIContentChild.cpp
dom/ipc/nsIContentChild.h
dom/ipc/nsIContentParent.cpp
dom/ipc/nsIContentParent.h
netwerk/ipc/PNecko.ipdl
netwerk/protocol/http/HttpChannelParent.h
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -76,23 +76,25 @@ PBlobChild*
 ContentBridgeChild::SendPBlobConstructor(PBlobChild* actor,
                                          const BlobConstructorParams& params)
 {
   return PContentBridgeChild::SendPBlobConstructor(actor, params);
 }
 
 bool
 ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
                                             const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return PContentBridgeChild::SendPBrowserConstructor(aActor,
+                                                      aTabId,
                                                       aContext,
                                                       aChromeFlags,
                                                       aCpID,
                                                       aIsForApp,
                                                       aIsForBrowser);
 }
 
 // This implementation is identical to ContentChild::GetCPOWManager but we can't
@@ -116,44 +118,48 @@ ContentBridgeChild::AllocPJavaScriptChil
 
 bool
 ContentBridgeChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
 {
   return nsIContentChild::DeallocPJavaScriptChild(child);
 }
 
 PBrowserChild*
-ContentBridgeChild::AllocPBrowserChild(const IPCTabContext &aContext,
+ContentBridgeChild::AllocPBrowserChild(const TabId& aTabId,
+                                       const IPCTabContext &aContext,
                                        const uint32_t& aChromeFlags,
                                        const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
-  return nsIContentChild::AllocPBrowserChild(aContext,
+  return nsIContentChild::AllocPBrowserChild(aTabId,
+                                             aContext,
                                              aChromeFlags,
                                              aCpID,
                                              aIsForApp,
                                              aIsForBrowser);
 }
 
 bool
 ContentBridgeChild::DeallocPBrowserChild(PBrowserChild* aChild)
 {
   return nsIContentChild::DeallocPBrowserChild(aChild);
 }
 
 bool
 ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
                                             const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return ContentChild::GetSingleton()->RecvPBrowserConstructor(aActor,
+                                                               aTabId,
                                                                aContext,
                                                                aChromeFlags,
                                                                aCpID,
                                                                aIsForApp,
                                                                aIsForBrowser);
 }
 
 PBlobChild*
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -34,32 +34,35 @@ public:
 
   virtual PBlobChild*
   SendPBlobConstructor(PBlobChild* actor,
                        const BlobConstructorParams& params);
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
   virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
                                        const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
 protected:
   virtual ~ContentBridgeChild();
 
-  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                            const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
                                             const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserChild(PBrowserChild*) MOZ_OVERRIDE;
   virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
                                        const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild() MOZ_OVERRIDE;
   virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -82,23 +82,25 @@ PBlobParent*
 ContentBridgeParent::SendPBlobConstructor(PBlobParent* actor,
                                           const BlobConstructorParams& params)
 {
   return PContentBridgeParent::SendPBlobConstructor(actor, params);
 }
 
 PBrowserParent*
 ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
+                                             const TabId& aTabId,
                                              const IPCTabContext& aContext,
                                              const uint32_t& aChromeFlags,
                                              const ContentParentId& aCpID,
                                              const bool& aIsForApp,
                                              const bool& aIsForBrowser)
 {
   return PContentBridgeParent::SendPBrowserConstructor(aActor,
+                                                       aTabId,
                                                        aContext,
                                                        aChromeFlags,
                                                        aCpID,
                                                        aIsForApp,
                                                        aIsForBrowser);
 }
 
 PBlobParent*
@@ -121,23 +123,25 @@ ContentBridgeParent::AllocPJavaScriptPar
 
 bool
 ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
   return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentBridgeParent::AllocPBrowserParent(const IPCTabContext &aContext,
+ContentBridgeParent::AllocPBrowserParent(const TabId& aTabId,
+                                         const IPCTabContext &aContext,
                                          const uint32_t& aChromeFlags,
                                          const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser)
 {
-  return nsIContentParent::AllocPBrowserParent(aContext,
+  return nsIContentParent::AllocPBrowserParent(aTabId,
+                                               aContext,
                                                aChromeFlags,
                                                aCpID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -29,16 +29,17 @@ public:
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   virtual PBlobParent*
   SendPBlobConstructor(PBlobParent* actor,
                        const BlobConstructorParams& params) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* aActor,
+                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
                           const ContentParentId& aCpID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
@@ -82,17 +83,18 @@ protected:
                                 const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
   virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() MOZ_OVERRIDE;
   virtual bool
   DeallocPJavaScriptParent(jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
-  AllocPBrowserParent(const IPCTabContext &aContext,
+  AllocPBrowserParent(const TabId& aTabId,
+                      const IPCTabContext &aContext,
                       const uint32_t& aChromeFlags,
                       const ContentParentId& aCpID,
                       const bool& aIsForApp,
                       const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserParent(PBrowserParent*) MOZ_OVERRIDE;
 
   virtual PBlobParent*
   AllocPBlobParent(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1113,47 +1113,52 @@ ContentChild::AllocPJavaScriptChild()
 
 bool
 ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
 {
     return nsIContentChild::DeallocPJavaScriptChild(aChild);
 }
 
 PBrowserChild*
-ContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+ContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                 const IPCTabContext& aContext,
                                  const uint32_t& aChromeFlags,
                                  const ContentParentId& aCpID,
                                  const bool& aIsForApp,
                                  const bool& aIsForBrowser)
 {
-    return nsIContentChild::AllocPBrowserChild(aContext,
+    return nsIContentChild::AllocPBrowserChild(aTabId,
+                                               aContext,
                                                aChromeFlags,
                                                aCpID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       const ContentParentId& aCpID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     return PContentChild::SendPBrowserConstructor(aActor,
+                                                  aTabId,
                                                   aContext,
                                                   aChromeFlags,
                                                   aCpID,
                                                   aIsForApp,
                                                   aIsForBrowser);
 }
 
 bool
 ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       const ContentParentId& aCpID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     // This runs after AllocPBrowserChild() returns and the IPC machinery for this
     // PBrowserChild has been set up.
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -130,17 +130,18 @@ public:
 #endif
 
     virtual bool RecvSetProcessSandbox() MOZ_OVERRIDE;
 
     PBackgroundChild*
     AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess)
                           MOZ_OVERRIDE;
 
-    virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+    virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                              const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
                                               const ContentParentId& aCpID,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
     virtual bool DeallocPBrowserChild(PBrowserChild*);
 
     virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequestChild(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*);
@@ -372,23 +373,25 @@ public:
 
     virtual PFileDescriptorSetChild*
     AllocPFileDescriptorSetChild(const FileDescriptor&) MOZ_OVERRIDE;
 
     virtual bool
     DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*) MOZ_OVERRIDE;
 
     virtual bool SendPBrowserConstructor(PBrowserChild* actor,
+                                         const TabId& aTabId,
                                          const IPCTabContext& context,
                                          const uint32_t& chromeFlags,
                                          const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
 
     virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
+                                         const TabId& aTabId,
                                          const IPCTabContext& aContext,
                                          const uint32_t& aChromeFlags,
                                          const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE;
     virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -128,16 +128,17 @@
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "gfxPrefs.h"
 #include "prio.h"
 #include "private/pprio.h"
+#include "ContentProcessManager.h"
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #if defined(XP_LINUX)
 #include "mozilla/Hal.h"
 #endif
@@ -843,27 +844,24 @@ ContentParent::PreallocatedProcessReady(
 {
 #ifdef MOZ_NUWA_PROCESS
     return PreallocatedProcessManager::PreallocatedProcessReady();
 #else
     return true;
 #endif
 }
 
-typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap;
-static GrandchildMap sGrandchildProcessMap;
-
-std::map<uint64_t, ContentParent*> sContentParentMap;
-
 bool
 ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
                                       const hal::ProcessPriority& aPriority,
-                                      uint64_t* aId,
+                                      const TabId& aOpenerTabId,
+                                      ContentParentId* aCpId,
                                       bool* aIsForApp,
-                                      bool* aIsForBrowser)
+                                      bool* aIsForBrowser,
+                                      TabId* aTabId)
 {
 #if 0
     if (!CanOpenBrowser(aContext)) {
         return false;
     }
 #endif
     nsRefPtr<ContentParent> cp;
     MaybeInvalidTabContext tc(aContext);
@@ -882,50 +880,77 @@ ContentParent::RecvCreateChildProcess(co
     }
     else {
         cp = GetNewOrUsedBrowserProcess(/* isBrowserElement = */ true,
                                         aPriority,
                                         this);
     }
 
     if (!cp) {
-        *aId = 0;
+        *aCpId = 0;
         *aIsForApp = false;
         *aIsForBrowser = false;
         return true;
     }
 
-    *aId = cp->ChildID();
+    *aCpId = cp->ChildID();
     *aIsForApp = cp->IsForApp();
     *aIsForBrowser = cp->IsForBrowser();
-    sContentParentMap[*aId] = cp;
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter == sGrandchildProcessMap.end()) {
-        std::set<ContentParent*> children;
-        children.insert(cp);
-        sGrandchildProcessMap[this] = children;
-    } else {
-        iter->second.insert(cp);
+
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    cpm->AddContentProcess(cp, this->ChildID());
+
+    if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID())) {
+        // Pre-allocate a TabId here to save one time IPC call at app startup.
+        *aTabId = AllocateTabId(aOpenerTabId,
+                                aContext,
+                                cp->ChildID());
+        return (*aTabId != 0);
     }
-    return true;
+
+    return false;
 }
 
 bool
-ContentParent::AnswerBridgeToChildProcess(const uint64_t& id)
+ContentParent::AnswerBridgeToChildProcess(const ContentParentId& aCpId)
 {
-    ContentParent* cp = sContentParentMap[id];
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter != sGrandchildProcessMap.end() &&
-        iter->second.find(cp) != iter->second.end()) {
-        return PContentBridge::Bridge(this, cp);
-    } else {
-        // You can't bridge to a process you didn't open!
-        KillHard();
-        return false;
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    ContentParent* cp = cpm->GetContentProcessById(aCpId);
+
+    if (cp) {
+        ContentParentId parentId;
+        if (cpm->GetParentProcessId(cp->ChildID(), &parentId) &&
+            parentId == this->ChildID()) {
+            return PContentBridge::Bridge(this, cp);
+        }
     }
+
+    // You can't bridge to a process you didn't open!
+    KillHard();
+    return false;
+}
+
+static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
+{
+    // Propagate the private-browsing status of the element's parent
+    // docshell to the remote docshell, via the chrome flags.
+    nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
+    MOZ_ASSERT(frameElement);
+    nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
+    if (!win) {
+        NS_WARNING("Remote frame has no window");
+        return nullptr;
+    }
+    nsIDocShell* docShell = win->GetDocShell();
+    if (!docShell) {
+        NS_WARNING("Remote frame has no docshell");
+        return nullptr;
+    }
+
+    return docShell;
 }
 
 bool
 ContentParent::AnswerLoadPlugin(const uint32_t& aPluginId)
 {
     return mozilla::plugins::SetupBridge(aPluginId, this);
 }
 
@@ -943,67 +968,69 @@ ContentParent::CreateBrowserOrApp(const 
                                   ContentParent* aOpenerContentParent)
 {
     if (!sCanLaunchSubprocesses) {
         return nullptr;
     }
 
     ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
     bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
+    TabId tabId;
+
+    nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
+    TabId openerTabId;
+    if (docShell) {
+        openerTabId = TabParent::GetTabIdFrom(docShell);
+    }
 
     if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
         nsRefPtr<TabParent> tp;
         nsRefPtr<nsIContentParent> constructorSender;
         if (isInContentProcess) {
             MOZ_ASSERT(aContext.IsBrowserElement());
-            constructorSender =
-                CreateContentBridgeParent(aContext, initialPriority);
+            constructorSender = CreateContentBridgeParent(aContext,
+                                                          initialPriority,
+                                                          openerTabId,
+                                                          &tabId);
         } else {
-          if (aOpenerContentParent) {
-            constructorSender = aOpenerContentParent;
-          } else {
-            constructorSender =
-                GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
-                                           initialPriority);
-          }
+            if (aOpenerContentParent) {
+                constructorSender = aOpenerContentParent;
+            } else {
+                constructorSender =
+                    GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
+                                               initialPriority);
+            }
+            tabId = AllocateTabId(openerTabId,
+                                  aContext.AsIPCTabContext(),
+                                  constructorSender->ChildID());
         }
         if (constructorSender) {
             uint32_t chromeFlags = 0;
 
-            // Propagate the private-browsing status of the element's parent
-            // docshell to the remote docshell, via the chrome flags.
-            nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
-            MOZ_ASSERT(frameElement);
-            nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
-            if (!win) {
-                NS_WARNING("Remote frame has no window");
-                return nullptr;
-            }
-            nsIDocShell* docShell = win->GetDocShell();
-            if (!docShell) {
-                NS_WARNING("Remote frame has no docshell");
-                return nullptr;
-            }
             nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
             if (loadContext && loadContext->UsePrivateBrowsing()) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
             }
             bool affectLifetime;
             docShell->GetAffectPrivateSessionLifetime(&affectLifetime);
             if (affectLifetime) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
             }
 
-            nsRefPtr<TabParent> tp(new TabParent(constructorSender,
+            if (tabId == 0) {
+                return nullptr;
+            }
+            nsRefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
                                                  aContext, chromeFlags));
             tp->SetOwnerElement(aFrameElement);
 
             PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
                 // DeallocPBrowserParent() releases this ref.
                 tp.forget().take(),
+                tabId,
                 aContext.AsIPCTabContext(),
                 chromeFlags,
                 constructorSender->ChildID(),
                 constructorSender->IsForApp(),
                 constructorSender->IsForBrowser());
             return static_cast<TabParent*>(browser);
         }
         return nullptr;
@@ -1013,17 +1040,20 @@ ContentParent::CreateBrowserOrApp(const 
     // shouldn't be null, because we otherwise would have gone into the
     // !HasOwnApp() branch above.
     nsRefPtr<nsIContentParent> parent;
     bool reused = false;
     bool tookPreallocated = false;
     nsAutoString manifestURL;
 
     if (isInContentProcess) {
-      parent = CreateContentBridgeParent(aContext, initialPriority);
+      parent = CreateContentBridgeParent(aContext,
+                                         initialPriority,
+                                         openerTabId,
+                                         &tabId);
     }
     else {
         nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
 
         if (!sAppContentParents) {
             sAppContentParents =
                 new nsDataHashtable<nsStringHashKey, ContentParent*>();
         }
@@ -1083,30 +1113,34 @@ ContentParent::CreateBrowserOrApp(const 
         if (!p) {
             p = GetNewOrPreallocatedAppProcess(ownApp,
                                                initialPriority,
                                                nullptr,
                                                &tookPreallocated);
             MOZ_ASSERT(p);
             sAppContentParents->Put(manifestURL, p);
         }
+        tabId = AllocateTabId(openerTabId,
+                              aContext.AsIPCTabContext(),
+                              p->ChildID());
         parent = static_cast<nsIContentParent*>(p);
     }
 
-    if (!parent) {
+    if (!parent || (tabId == 0)) {
         return nullptr;
     }
 
     uint32_t chromeFlags = 0;
 
-    nsRefPtr<TabParent> tp = new TabParent(parent, aContext, chromeFlags);
+    nsRefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags);
     tp->SetOwnerElement(aFrameElement);
     PBrowserParent* browser = parent->SendPBrowserConstructor(
         // DeallocPBrowserParent() releases this ref.
         nsRefPtr<TabParent>(tp).forget().take(),
+        tabId,
         aContext.AsIPCTabContext(),
         chromeFlags,
         parent->ChildID(),
         parent->IsForApp(),
         parent->IsForBrowser());
 
     if (isInContentProcess) {
         // Just return directly without the following check in content process.
@@ -1139,37 +1173,43 @@ ContentParent::CreateBrowserOrApp(const 
 
     parent->AsContentParent()->MaybeTakeCPUWakeLock(aFrameElement);
 
     return static_cast<TabParent*>(browser);
 }
 
 /*static*/ ContentBridgeParent*
 ContentParent::CreateContentBridgeParent(const TabContext& aContext,
-                                         const hal::ProcessPriority& aPriority)
+                                         const hal::ProcessPriority& aPriority,
+                                         const TabId& aOpenerTabId,
+                                         /*out*/ TabId* aTabId)
 {
+    MOZ_ASSERT(aTabId);
+
     ContentChild* child = ContentChild::GetSingleton();
-    uint64_t id;
+    ContentParentId cpId;
     bool isForApp;
     bool isForBrowser;
     if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(),
                                        aPriority,
-                                       &id,
+                                       aOpenerTabId,
+                                       &cpId,
                                        &isForApp,
-                                       &isForBrowser)) {
+                                       &isForBrowser,
+                                       aTabId)) {
         return nullptr;
     }
-    if (id == 0) {
+    if (cpId == 0) {
         return nullptr;
     }
-    if (!child->CallBridgeToChildProcess(id)) {
+    if (!child->CallBridgeToChildProcess(cpId)) {
         return nullptr;
     }
     ContentBridgeParent* parent = child->GetLastBridge();
-    parent->SetChildID(id);
+    parent->SetChildID(cpId);
     parent->SetIsForApp(isForApp);
     parent->SetIsForBrowser(isForBrowser);
     return parent;
 }
 
 void
 ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
 {
@@ -1495,23 +1535,16 @@ ContentParent::MarkAsDead()
         sPrivateContent->RemoveElement(this);
         if (!sPrivateContent->Length()) {
             delete sPrivateContent;
             sPrivateContent = nullptr;
         }
     }
 
     mIsAlive = false;
-
-    sGrandchildProcessMap.erase(this);
-    for (auto iter = sGrandchildProcessMap.begin();
-         iter != sGrandchildProcessMap.end();
-         iter++) {
-        iter->second.erase(this);
-    }
 }
 
 void
 ContentParent::OnChannelError()
 {
     nsRefPtr<ContentParent> content(this);
 #ifdef MOZ_NUWA_PROCESS
     // Handle app or Nuwa process exit before normal channel error handling.
@@ -1739,27 +1772,27 @@ ContentParent::ActorDestroy(ActorDestroy
     // |this|.  If so, when we go out of scope here, we're deleted and
     // all hell breaks loose.
     //
     // This runnable ensures that a reference to |this| lives on at
     // least until after the current task finishes running.
     NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
 
     // Destroy any processes created by this ContentParent
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter != sGrandchildProcessMap.end()) {
-        for(auto child = iter->second.begin();
-            child != iter->second.end();
-            child++) {
-            MessageLoop::current()->PostTask(
-                FROM_HERE,
-                NewRunnableMethod(*child, &ContentParent::ShutDownProcess,
-                                  /* closeWithError */ false));
-        }
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    nsTArray<ContentParentId> childIDArray =
+        cpm->GetAllChildProcessById(this->ChildID());
+    for(uint32_t i = 0; i < childIDArray.Length(); i++) {
+        ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
+        MessageLoop::current()->PostTask(
+            FROM_HERE,
+            NewRunnableMethod(cp, &ContentParent::ShutDownProcess,
+                              /* closeWithError */ false));
     }
+    cpm->RemoveContentProcess(this->ChildID());
 }
 
 void
 ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
 {
     // There can be more than one PBrowser for a given app process
     // because of popup windows.  PBrowsers can also destroy
     // concurrently.  When all the PBrowsers are destroying, kick off
@@ -1912,16 +1945,18 @@ ContentParent::ContentParent(mozIApplica
     }
     mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
 
     Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
 
     InitInternal(aInitialPriority,
                  true, /* Setup off-main thread compositing */
                  true  /* Send registered chrome */);
+
+    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static const mozilla::ipc::FileDescriptor*
 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
                         ProtocolId aProtoId)
 {
     for (unsigned int i = 0; i < aFds.Length(); i++) {
@@ -1989,16 +2024,18 @@ ContentParent::ContentParent(ContentPare
         priority = PROCESS_PRIORITY_PREALLOC;
     } else {
         priority = PROCESS_PRIORITY_FOREGROUND;
     }
 
     InitInternal(priority,
                  false, /* Setup Off-main thread compositing */
                  false  /* Send registered chrome */);
+
+    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 #endif  // MOZ_NUWA_PROCESS
 
 ContentParent::~ContentParent()
 {
     if (mForceKillTask) {
         mForceKillTask->Cancel();
     }
@@ -2850,23 +2887,25 @@ ContentParent::AllocPJavaScriptParent()
 
 bool
 ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
     return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
+ContentParent::AllocPBrowserParent(const TabId& aTabId,
+                                   const IPCTabContext& aContext,
                                    const uint32_t& aChromeFlags,
                                    const ContentParentId& aCpId,
                                    const bool& aIsForApp,
                                    const bool& aIsForBrowser)
 {
-    return nsIContentParent::AllocPBrowserParent(aContext,
+    return nsIContentParent::AllocPBrowserParent(aTabId,
+                                                 aContext,
                                                  aChromeFlags,
                                                  aCpId,
                                                  aIsForApp,
                                                  aIsForBrowser);
 }
 
 bool
 ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
@@ -3859,23 +3898,25 @@ bool
 ContentParent::RecvSystemMessageHandled()
 {
     SystemMessageHandledListener::OnSystemMessageHandled();
     return true;
 }
 
 PBrowserParent*
 ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
                                        const ContentParentId& aCpId,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
     return PContentParent::SendPBrowserConstructor(aActor,
+                                                   aTabId,
                                                    aContext,
                                                    aChromeFlags,
                                                    aCpId,
                                                    aIsForApp,
                                                    aIsForBrowser);
 }
 
 bool
@@ -4167,16 +4208,76 @@ ContentParent::NotifyUpdatedDictionaries
     InfallibleTArray<nsString> dictionaries;
     spellChecker->GetDictionaryList(&dictionaries);
 
     for (size_t i = 0; i < processes.Length(); ++i) {
         unused << processes[i]->SendUpdateDictionaryList(dictionaries);
     }
 }
 
+/*static*/ TabId
+ContentParent::AllocateTabId(const TabId& aOpenerTabId,
+                             const IPCTabContext& aContext,
+                             const ContentParentId& aCpId)
+{
+    TabId tabId;
+    if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+        tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
+    }
+    else {
+        ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
+                                                        aContext,
+                                                        aCpId,
+                                                        &tabId);
+    }
+    return tabId;
+}
+
+/*static*/ void
+ContentParent::DeallocateTabId(const TabId& aTabId,
+                               const ContentParentId& aCpId)
+{
+    if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
+                                                               aTabId);
+    }
+    else {
+        ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
+    }
+}
+
+bool
+ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
+                                 const IPCTabContext& aContext,
+                                 const ContentParentId& aCpId,
+                                 TabId* aTabId)
+{
+    *aTabId = AllocateTabId(aOpenerTabId, aContext, aCpId);
+    if (!(*aTabId)) {
+        return false;
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvDeallocateTabId(const TabId& aTabId)
+{
+    DeallocateTabId(aTabId, this->ChildID());
+    return true;
+}
+
+nsTArray<TabContext>
+ContentParent::GetManagedTabContext()
+{
+    return Move(ContentProcessManager::GetSingleton()->
+        GetTabContextByContentProcess(this->ChildID()));
+}
+
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -138,20 +138,22 @@ public:
     static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
     static bool IgnoreIPCPrincipal();
 
     static void NotifyUpdatedDictionaries();
 
     virtual bool RecvCreateChildProcess(const IPCTabContext& aContext,
                                         const hal::ProcessPriority& aPriority,
-                                        uint64_t* aId,
+                                        const TabId& aOpenerTabId,
+                                        ContentParentId* aCpId,
                                         bool* aIsForApp,
-                                        bool* aIsForBrowser) MOZ_OVERRIDE;
-    virtual bool AnswerBridgeToChildProcess(const uint64_t& id) MOZ_OVERRIDE;
+                                        bool* aIsForBrowser,
+                                        TabId* aTabId) MOZ_OVERRIDE;
+    virtual bool AnswerBridgeToChildProcess(const ContentParentId& aCpId) MOZ_OVERRIDE;
 
     virtual bool AnswerLoadPlugin(const uint32_t& aPluginId) MOZ_OVERRIDE;
     virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
                                  nsTArray<PluginTag>* aPlugins,
                                  uint32_t* aNewPluginEpoch) MOZ_OVERRIDE;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
@@ -179,16 +181,23 @@ public:
     void NotifyTabDestroyed(PBrowserParent* aTab,
                             bool aNotifiedDestroying);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
     jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
+    static TabId
+    AllocateTabId(const TabId& aOpenerTabId,
+                  const IPCTabContext& aContext,
+                  const ContentParentId& aCpId);
+    static void
+    DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId);
+
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
     virtual bool IsForApp() MOZ_OVERRIDE;
     virtual bool IsForBrowser() MOZ_OVERRIDE
     {
       return mIsForBrowser;
@@ -286,16 +295,24 @@ public:
     bool CycleCollectWithLogs(bool aDumpAllTraces,
                               nsICycleCollectorLogSink* aSink,
                               nsIDumpGCAndCCLogsCallback* aCallback);
 
     virtual PBlobParent* SendPBlobConstructor(
         PBlobParent* aActor,
         const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
+    virtual bool RecvAllocateTabId(const TabId& aOpenerTabId,
+                                   const IPCTabContext& aContext,
+                                   const ContentParentId& aCpId,
+                                   TabId* aTabId) MOZ_OVERRIDE;
+
+    virtual bool RecvDeallocateTabId(const TabId& aTabId) MOZ_OVERRIDE;
+
+    nsTArray<TabContext> GetManagedTabContext();
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
 
 private:
@@ -314,22 +331,25 @@ private:
     GetNewOrPreallocatedAppProcess(mozIApplication* aApp,
                                    hal::ProcessPriority aInitialPriority,
                                    ContentParent* aOpener,
                                    /*out*/ bool* aTookPreAllocated = nullptr);
 
     static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
 
     static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,
-                                                          const hal::ProcessPriority& aPriority);
+                                                          const hal::ProcessPriority& aPriority,
+                                                          const TabId& aOpenerTabId,
+                                                          /*out*/ TabId* aTabId);
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     virtual PBrowserParent* SendPBrowserConstructor(
         PBrowserParent* actor,
+        const TabId& aTabId,
         const IPCTabContext& context,
         const uint32_t& chromeFlags,
         const ContentParentId& aCpId,
         const bool& aIsForApp,
         const bool& aIsForBrowser) MOZ_OVERRIDE;
     using PContentParent::SendPTestShellConstructor;
 
     // No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
@@ -424,17 +444,18 @@ private:
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                                InfallibleTArray<nsString>* dictionaries,
                                                ClipboardCapabilities* clipboardCaps)
         MOZ_OVERRIDE;
 
     virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
     virtual bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) MOZ_OVERRIDE;
-    virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
+    virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
+                                                const IPCTabContext& aContext,
                                                 const uint32_t& aChromeFlags,
                                                 const ContentParentId& aCpId,
                                                 const bool& aIsForApp,
                                                 const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual bool DeallocPBrowserParent(PBrowserParent* frame) MOZ_OVERRIDE;
 
     virtual PDeviceStorageRequestParent*
     AllocPDeviceStorageRequestParent(const DeviceStorageParams&) MOZ_OVERRIDE;
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessManager.cpp
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ContentProcessManager.h"
+#include "ContentParent.h"
+
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ClearOnShutdown.h"
+
+#include "nsPrintfCString.h"
+
+// XXX need another bug to move this to a common header.
+#ifdef DISABLE_ASSERTS_FOR_FUZZING
+#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
+#else
+#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
+#endif
+
+namespace mozilla {
+namespace dom {
+
+static uint64_t gTabId = 0;
+
+/* static */
+StaticAutoPtr<ContentProcessManager>
+ContentProcessManager::sSingleton;
+
+/* static */ ContentProcessManager*
+ContentProcessManager::GetSingleton()
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+
+  if (!sSingleton) {
+    sSingleton = new ContentProcessManager();
+    ClearOnShutdown(&sSingleton);
+  }
+  return sSingleton;
+}
+
+void
+ContentProcessManager::AddContentProcess(ContentParent* aChildCp,
+                                         const ContentParentId& aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aChildCp);
+
+  ContentProcessInfo info;
+  info.mCp = aChildCp;
+  info.mParentCpId = aParentCpId;
+  mContentParentMap[aChildCp->ChildID()] = info;
+}
+
+void
+ContentProcessManager::RemoveContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mContentParentMap.find(aChildCpId) != mContentParentMap.end());
+
+  mContentParentMap.erase(aChildCpId);
+  for (auto iter = mContentParentMap.begin();
+       iter != mContentParentMap.end();
+       ++iter) {
+    if (!iter->second.mChildrenCpId.empty()) {
+      iter->second.mChildrenCpId.erase(aChildCpId);
+    }
+  }
+}
+
+bool
+ContentProcessManager::AddGrandchildProcess(const ContentParentId& aParentCpId,
+                                            const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aParentCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING("Parent process should be already in map!");
+    return false;
+  }
+  iter->second.mChildrenCpId.insert(aChildCpId);
+  return true;
+}
+
+bool
+ContentProcessManager::GetParentProcessId(const ContentParentId& aChildCpId,
+                                          /*out*/ ContentParentId* aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+  *aParentCpId = iter->second.mParentCpId;
+  return true;
+}
+
+ContentParent*
+ContentProcessManager::GetContentProcessById(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+  return iter->second.mCp;
+}
+
+nsTArray<ContentParentId>
+ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<ContentParentId> cpIdArray;
+  auto iter = mContentParentMap.find(aParentCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(cpIdArray);
+  }
+
+  for (auto cpIter = iter->second.mChildrenCpId.begin();
+       cpIter != iter->second.mChildrenCpId.end();
+       ++cpIter) {
+    cpIdArray.AppendElement(*cpIter);
+  }
+
+  return Move(cpIdArray);
+}
+
+TabId
+ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
+                                     const IPCTabContext& aContext,
+                                     const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return TabId(0);
+  }
+
+  struct RemoteFrameInfo info;
+
+  const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
+  // If it's a PopupIPCTabContext, it's the case that a TabChild want to
+  // open a new tab. aOpenerTabId has to be it's parent frame's opener id.
+  if (appBrowser.type() == IPCTabAppBrowserContext::TPopupIPCTabContext) {
+    auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
+    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
+      ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
+      return TabId(0);
+    }
+
+    info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
+
+    const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
+    MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId);
+
+    remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId());
+    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
+      ASSERT_UNLESS_FUZZING("Failed to find tab id.");
+      return TabId(0);
+    }
+
+    info.mContext = remoteFrameIter->second.mContext;
+  }
+  else {
+    MaybeInvalidTabContext tc(aContext);
+    if (!tc.IsValid()) {
+      NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
+                               "the child process. (%s)",
+                               tc.GetInvalidReason()).get());
+      return TabId(0);
+    }
+    info.mOpenerTabId = aOpenerTabId;
+    info.mContext = tc.GetTabContext();
+  }
+
+  mUniqueId = ++gTabId;
+  iter->second.mRemoteFrames[mUniqueId] = info;
+
+  return mUniqueId;
+}
+
+void
+ContentProcessManager::DeallocateTabId(const ContentParentId& aChildCpId,
+                                       const TabId& aChildTabId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return;
+  }
+
+  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
+  if (remoteFrameIter != iter->second.mRemoteFrames.end()) {
+    iter->second.mRemoteFrames.erase(aChildTabId);
+  }
+}
+
+nsTArray<uint64_t>
+ContentProcessManager::GetAppIdsByContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<uint64_t> appIdArray;
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(appIdArray);
+  }
+
+  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
+       remoteFrameIter != iter->second.mRemoteFrames.end();
+       ++remoteFrameIter) {
+    appIdArray.AppendElement(remoteFrameIter->second.mContext.OwnOrContainingAppId());
+  }
+
+  return Move(appIdArray);
+}
+
+nsTArray<TabContext>
+ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<TabContext> tabContextArray;
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(tabContextArray);
+  }
+
+  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
+       remoteFrameIter != iter->second.mRemoteFrames.end();
+       ++remoteFrameIter) {
+    tabContextArray.AppendElement(remoteFrameIter->second.mContext);
+  }
+
+  return Move(tabContextArray);
+}
+
+bool
+ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
+                                                 const TabId& aChildTabId,
+                                                 /*out*/TabId* aOpenerTabId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+
+  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
+  if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+
+  *aOpenerTabId = remoteFrameIter->second.mOpenerTabId;
+
+  return true;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessManager.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ContentProcessManager_h
+#define mozilla_dom_ContentProcessManager_h
+
+#include <map>
+#include <set>
+#include "mozilla/StaticPtr.h"
+#include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+class ContentParent;
+
+struct RemoteFrameInfo
+{
+  TabId mOpenerTabId;
+  TabContext mContext;
+};
+
+struct ContentProcessInfo
+{
+  ContentParent* mCp;
+  ContentParentId mParentCpId;
+  std::set<ContentParentId> mChildrenCpId;
+  std::map<TabId, RemoteFrameInfo> mRemoteFrames;
+};
+
+class ContentProcessManager MOZ_FINAL
+{
+public:
+  static ContentProcessManager* GetSingleton();
+  ~ContentProcessManager() {MOZ_COUNT_DTOR(ContentProcessManager);};
+
+  /**
+   * Add a new content process into the map.
+   * If aParentCpId is not 0, it's a nested content process.
+   */
+  void AddContentProcess(ContentParent* aChildCp,
+                         const ContentParentId& aParentCpId = ContentParentId(0));
+  /**
+   * Remove the content process by id.
+   */
+  void RemoveContentProcess(const ContentParentId& aChildCpId);
+  /**
+   * Add a grandchild content process into the map.
+   * aParentCpId must be already added in the map by AddContentProcess().
+   */
+  bool AddGrandchildProcess(const ContentParentId& aParentCpId,
+                            const ContentParentId& aChildCpId);
+  /**
+   * Get the parent process's id by child process's id.
+   * Used to check if a child really belongs to the parent.
+   */
+  bool GetParentProcessId(const ContentParentId& aChildCpId,
+                          /*out*/ ContentParentId* aParentCpId);
+  /**
+   * Return the ContentParent pointer by id.
+   */
+  ContentParent* GetContentProcessById(const ContentParentId& aChildCpId);
+
+  /**
+   * Return a list of all child process's id.
+   */
+  nsTArray<ContentParentId>
+  GetAllChildProcessById(const ContentParentId& aParentCpId);
+
+  /**
+   * Allocate a tab id for the given content process's id.
+   * Used when a content process wants to create a new tab. aOpenerTabId and
+   * aContext are saved in RemoteFrameInfo, which is a part of ContentProcessInfo.
+   * We can use the tab id and process id to locate the TabContext for future use.
+   */
+  TabId AllocateTabId(const TabId& aOpenerTabId,
+                      const IPCTabContext& aContext,
+                      const ContentParentId& aChildCpId);
+
+  /**
+   * Remove the RemoteFrameInfo by the given process and tab id.
+   */
+  void DeallocateTabId(const ContentParentId& aChildCpId,
+                       const TabId& aChildTabId);
+
+  /**
+   * Get all app ids which are inside the given content process.
+   * XXX Currently not used. Plan to be used for bug 1020186.
+   */
+  nsTArray<uint64_t>
+  GetAppIdsByContentProcess(const ContentParentId& aChildCpId);
+
+  /**
+   * Get all TabContext which are inside the given content process.
+   * Used for AppProcessChecker to cehck app status.
+   */
+  nsTArray<TabContext>
+  GetTabContextByContentProcess(const ContentParentId& aChildCpId);
+
+  /**
+   * Query a tab's opener id by the given process and tab id.
+   * XXX Currently not used. Plan to be used for bug 1020179.
+   */
+  bool GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
+                                 const TabId& aChildTabId,
+                                 /*out*/ TabId* aOpenerTabId);
+
+private:
+  static StaticAutoPtr<ContentProcessManager> sSingleton;
+  TabId mUniqueId;
+  std::map<ContentParentId, ContentProcessInfo> mContentParentMap;
+
+  ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);};
+};
+
+} // namespace dom
+} // namespace mozilla
+#endif
\ No newline at end of file
--- a/dom/ipc/IdType.h
+++ b/dom/ipc/IdType.h
@@ -2,19 +2,26 @@
 /* vim: set sw=4 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_IdType_h
 #define mozilla_dom_IdType_h
 
+#include "ipc/IPCMessageUtils.h"
+
+namespace IPC {
+template<typename T> struct ParamTraits;
+}
+
 namespace mozilla {
 namespace dom {
 class ContentParent;
+class TabParent;
 
 
 template<typename T>
 class IdType
 {
 
   friend struct IPC::ParamTraits<IdType<T>>;
 
@@ -33,16 +40,17 @@ public:
   bool operator<(const IdType& rhs)
   {
     return mId < rhs.mId;
   }
 private:
   uint64_t mId;
 };
 
+typedef IdType<TabParent> TabId;
 typedef IdType<ContentParent> ContentParentId;
 
 } // namespace dom
 } // namespace mozilla
 
 namespace IPC {
 
 template<typename T>
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PBrowserOrId.ipdlh
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=c: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PBrowser;
+
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+
+namespace mozilla {
+namespace dom {
+
+union PBrowserOrId
+{
+  nullable PBrowser;
+  TabId;
+};
+
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -65,16 +65,17 @@ using struct mozilla::void_t from "ipc/I
 using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h";
 using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using gfxIntSize from "nsSize.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     ResourceMapping;
 };
@@ -387,17 +388,17 @@ both:
     // browser element.
     //
     // This allows the parent to prevent a malicious child from escalating its
     // privileges by requesting a PBrowser corresponding to a highly-privileged
     // app; the child can only request privileges for an app which the child has
     // access to (in the form of a TabChild).
     //
     // Keep the last 3 attributes in sync with GetProcessAttributes!
-    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
+    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
                    ContentParentId cpId, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     PFileDescriptorSet(FileDescriptor fd);
 
 child:
     /**
@@ -528,19 +529,20 @@ parent:
      */
     sync GetProcessAttributes()
         returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
     sync GetXPCOMProcessAttributes()
         returns (bool isOffline, nsString[] dictionaries,
                  ClipboardCapabilities clipboardCaps);
 
     sync CreateChildProcess(IPCTabContext context,
-                            ProcessPriority priority)
-        returns (uint64_t id, bool isForApp, bool isForBrowser);
-    intr BridgeToChildProcess(uint64_t id);
+                            ProcessPriority priority,
+                            TabId openerTabId)
+        returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
+    intr BridgeToChildProcess(ContentParentId cpId);
 
     /**
      * This call connects the content process to a plugin process. While this
      * call runs, a new PluginModuleParent will be created in the ContentChild
      * via bridging. The corresponding PluginModuleChild will live in the plugin
      * process. We use intr semantics here to ensure that the PluginModuleParent
      * allocation message is dispatched before LoadPlugin returns.
      */
@@ -770,15 +772,23 @@ parent:
     // Use only for testing!
     sync GetFileReferences(PersistenceType persistenceType,
                            nsCString origin,
                            nsString databaseName,
                            int64_t fileId)
       returns (int32_t refCnt, int32_t dBRefCnt, int32_t sliceRefCnt,
                bool result);
 
+    /**
+     * Tell the chrome process there is an creation of PBrowser.
+     * return a system-wise unique Id.
+     */
+    sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
+        returns (TabId tabId);
+    async DeallocateTabId(TabId tabId);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -9,16 +9,17 @@ include protocol PBrowser;
 include protocol PContent;
 include protocol PJavaScript;
 
 include DOMTypes;
 include JavaScriptTypes;
 include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace dom {
 
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
@@ -37,17 +38,17 @@ prio(normal upto high) intr protocol PCo
 
 parent:
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 both:
     // Both the parent and the child can construct the PBrowser.
     // See the comment in PContent::PBrowser().
-    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
+    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
                    ContentParentId cpId, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     async PJavaScript();
 
     AsyncMessage(nsString aMessage, ClonedMessageData aData,
                  CpowEntry[] aCpows, Principal aPrincipal);
--- a/dom/ipc/PTabContext.ipdlh
+++ b/dom/ipc/PTabContext.ipdlh
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBrowser;
-
+include PBrowserOrId;
 
 using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 // An IPCTabContext which corresponds to a PBrowser opened by a child when it
 // receives window.open().
@@ -22,17 +22,17 @@ namespace dom {
 // If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal
 // to the opener's app-id.
 //
 // It's an error to set isBrowserElement == false if opener is a browser
 // element.  Such a PopupIPCTabContext should be rejected by code which receives
 // it.
 struct PopupIPCTabContext
 {
-  PBrowser opener;
+  PBrowserOrId opener;
   bool isBrowserElement;
 };
 
 // An IPCTabContext which corresponds to an app frame.
 struct AppFrameIPCTabContext
 {
   // The ID of the app this frame corresponds to.  May be NO_APP_ID.
   uint32_t ownAppId;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -728,33 +728,34 @@ private:
         mInfo->FireCallback();
         return NS_OK;
     }
 };
 
 StaticRefPtr<TabChild> sPreallocatedTab;
 
 /*static*/
-std::map<uint64_t, nsRefPtr<TabChild> >&
+std::map<TabId, nsRefPtr<TabChild>>&
 TabChild::NestedTabChildMap()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  static std::map<uint64_t, nsRefPtr<TabChild> > sNestedTabChildMap;
+  static std::map<TabId, nsRefPtr<TabChild>> sNestedTabChildMap;
   return sNestedTabChildMap;
 }
 
 /*static*/ void
 TabChild::PreloadSlowThings()
 {
     MOZ_ASSERT(!sPreallocatedTab);
 
     // Pass nullptr to aManager since at this point the TabChild is
     // not connected to any manager. Any attempt to use the TabChild
     // in IPC will crash.
     nsRefPtr<TabChild> tab(new TabChild(nullptr,
+                                        TabId(0),
                                         TabContext(), /* chromeFlags */ 0));
     if (!NS_SUCCEEDED(tab->Init()) ||
         !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
         return;
     }
     // Just load and compile these scripts, but don't run them.
     tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
     // Load, compile, and run these scripts.
@@ -775,41 +776,44 @@ TabChild::PreloadSlowThings()
     }
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(nsIContentChild* aManager,
+                 const TabId& aTabId,
                  const TabContext &aContext,
                  uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
         aContext.IsBrowserOrApp()) {
 
         nsRefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
         MOZ_ASSERT(!child->mTriedBrowserInit);
 
         child->mManager = aManager;
+        child->SetTabId(aTabId);
         child->SetTabContext(aContext);
         child->NotifyTabContextUpdated();
         return child.forget();
     }
 
-    nsRefPtr<TabChild> iframe = new TabChild(aManager,
+    nsRefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
                                              aContext, aChromeFlags);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
 }
 
 
 TabChild::TabChild(nsIContentChild* aManager,
+                   const TabId& aTabId,
                    const TabContext& aContext,
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mLayersId(0)
   , mOuterRect(0, 0, 0, 0)
@@ -823,25 +827,31 @@ TabChild::TabChild(nsIContentChild* aMan
   , mUpdateHitRegion(false)
   , mPendingTouchPreventedResponse(false)
   , mPendingTouchPreventedBlockId(0)
   , mTouchEndCancelled(false)
   , mEndTouchIsClick(false)
   , mIgnoreKeyPressEvent(false)
   , mActiveElementManager(new ActiveElementManager())
   , mHasValidInnerSize(false)
-  , mUniqueId(0)
   , mDestroyed(false)
+  , mUniqueId(aTabId)
 {
   if (!sActiveDurationMsSet) {
     Preferences::AddIntVarCache(&sActiveDurationMs,
                                 "ui.touch_activation.duration_ms",
                                 sActiveDurationMs);
     sActiveDurationMsSet = true;
   }
+
+  // preloaded TabChild should not be added to child map
+  if (mUniqueId) {
+    MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
+    NestedTabChildMap()[mUniqueId] = this;
+  }
 }
 
 NS_IMETHODIMP
 TabChild::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
   if (eventType.EqualsLiteral("DOMMetaAdded")) {
@@ -1429,36 +1439,46 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     nsIURI* aURI,
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
-  nsRefPtr<TabChild> newChild =
-      new TabChild(ContentChild::GetSingleton(),
-                   /* TabContext */ *this, /* chromeFlags */ 0);
-  if (!NS_SUCCEEDED(newChild->Init())) {
-      return NS_ERROR_ABORT;
-  }
+  ContentChild* cc = ContentChild::GetSingleton();
+  const TabId openerTabId = GetTabId();
 
   // We must use PopupIPCTabContext here; ContentParent will not accept the
   // result of this->AsIPCTabContext() (which will be a
   // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
   // reasons.
   PopupIPCTabContext context;
-  context.openerChild() = this;
+  context.opener() = openerTabId;
   context.isBrowserElement() = IsBrowserElement();
 
-  ContentChild* cc = static_cast<ContentChild*>(Manager());
+  IPCTabContext ipcContext(context, mScrolling);
+
+  TabId tabId;
+  cc->SendAllocateTabId(openerTabId,
+                        ipcContext,
+                        cc->GetID(),
+                        &tabId);
+
+  nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
+                                             /* TabContext */ *this, /* chromeFlags */ 0);
+  if (NS_FAILED(newChild->Init())) {
+    return NS_ERROR_ABORT;
+  }
+
+  context.opener() = this;
   unused << Manager()->SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       nsRefPtr<TabChild>(newChild).forget().take(),
-      IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
+      tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
       cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
@@ -1558,18 +1578,18 @@ TabChild::ActorDestroy(ActorDestroyReaso
     static_cast<nsFrameMessageManager*>
       (mTabChildGlobal->mMessageManager.get())->Disconnect();
     mTabChildGlobal->mMessageManager = nullptr;
   }
 
   CompositorChild* compositorChild = static_cast<CompositorChild*>(CompositorChild::Get());
   compositorChild->CancelNotifyAfterRemotePaint(this);
 
-  if (Id() != 0) {
-    NestedTabChildMap().erase(Id());
+  if (GetTabId() != 0) {
+    NestedTabChildMap().erase(GetTabId());
   }
 }
 
 TabChild::~TabChild()
 {
     DestroyWindow();
 
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -29,16 +29,17 @@
 #include "nsITooltipListener.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "nsIWebBrowserChrome3.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
@@ -249,48 +250,35 @@ class TabChild MOZ_FINAL : public TabChi
                            public nsITooltipListener
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
     typedef mozilla::layers::ActiveElementManager ActiveElementManager;
 
 public:
-    static std::map<uint64_t, nsRefPtr<TabChild> >& NestedTabChildMap();
+    static std::map<TabId, nsRefPtr<TabChild>>& NestedTabChildMap();
 
 public:
     /** 
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
-    Create(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags);
 
     bool IsRootContentDocument();
 
-    const uint64_t Id() const {
-        return mUniqueId;
-    }
-
-    static uint64_t
-    GetTabChildId(TabChild* aTabChild)
-    {
-        MOZ_ASSERT(NS_IsMainThread());
-        if (aTabChild->Id() != 0) {
-            return aTabChild->Id();
-        }
-        static uint64_t sId = 0;
-        sId++;
-        aTabChild->mUniqueId = sId;
-        NestedTabChildMap()[sId] = aTabChild;
-        return sId;
+    const TabId GetTabId() const {
+      MOZ_ASSERT(mUniqueId != 0);
+      return mUniqueId;
     }
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
@@ -514,17 +502,20 @@ private:
     /**
      * Create a new TabChild object.
      *
      * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).
      */
-    TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabChild(nsIContentChild* aManager,
+             const TabId& aTabId,
+             const TabContext& aContext,
+             uint32_t aChromeFlags);
 
     nsresult Init();
 
     class DelayedFireSingleTapEvent;
     class DelayedFireContextMenuEvent;
 
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
@@ -562,16 +553,24 @@ private:
                               bool* aWindowIsNew,
                               nsIDOMWindow** aReturn);
 
     bool HasValidInnerSize();
 
     void SendPendingTouchPreventedResponse(bool aPreventDefault,
                                            const ScrollableLayerGuid& aGuid);
 
+    void SetTabId(const TabId& aTabId)
+    {
+      MOZ_ASSERT(mUniqueId == 0);
+
+      mUniqueId = aTabId;
+      NestedTabChildMap()[mUniqueId] = this;
+    }
+
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
     RenderFrameChild* mRemoteFrame;
@@ -605,18 +604,18 @@ private:
     void FireSingleTapEvent(LayoutDevicePoint aPoint);
 
     bool mTouchEndCancelled;
     bool mEndTouchIsClick;
 
     bool mIgnoreKeyPressEvent;
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
-    uint64_t mUniqueId;
     bool mDestroyed;
+    TabId mUniqueId;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 }
 }
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -251,29 +251,34 @@ MaybeInvalidTabContext::MaybeInvalidTabC
   uint32_t containingAppId = NO_APP_ID;
 
   const IPCTabAppBrowserContext& appBrowser = aParams.appBrowserContext();
   switch(appBrowser.type()) {
     case IPCTabAppBrowserContext::TPopupIPCTabContext: {
       const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
 
       TabContext *context;
-      if (ipcContext.openerParent()) {
-        context = static_cast<TabParent*>(ipcContext.openerParent());
+      if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
+        context = static_cast<TabParent*>(ipcContext.opener().get_PBrowserParent());
         if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) {
           // If the TabParent corresponds to a browser element, then it can only
           // open other browser elements, for security reasons.  We should have
           // checked this before calling the TabContext constructor, so this is
           // a fatal error.
           mInvalidReason = "Child is-browser process tried to "
                            "open a non-browser tab.";
           return;
         }
-      } else if (ipcContext.openerChild()) {
-        context = static_cast<TabChild*>(ipcContext.openerChild());
+      } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) {
+        context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild());
+      } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) {
+        // We should never get here because this PopupIPCTabContext is only
+        // used for allocating a new tab id, not for allocating a PBrowser.
+        mInvalidReason = "Child process tried to open an tab without the opener information.";
+        return;
       } else {
         // This should be unreachable because PopupIPCTabContext::opener is not a
         // nullable field.
         mInvalidReason = "PopupIPCTabContext::opener was null (?!).";
         return;
       }
 
       // Browser elements can't nest other browser elements.  So if
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -213,17 +213,20 @@ TabParent* sEventCapturer;
 TabParent *TabParent::mIMETabParent = nullptr;
 
 NS_IMPL_ISUPPORTS(TabParent,
                   nsITabParent,
                   nsIAuthPromptProvider,
                   nsISecureBrowserUI,
                   nsISupportsWeakReference)
 
-TabParent::TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags)
+TabParent::TabParent(nsIContentParent* aManager,
+                     const TabId& aTabId,
+                     const TabContext& aContext,
+                     uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mIMESelectionAnchor(0)
   , mIMESelectionFocus(0)
   , mIMEComposing(false)
   , mIMECompositionEnding(false)
   , mIMECompositionStart(0)
   , mIMESeqno(0)
@@ -237,16 +240,17 @@ TabParent::TabParent(nsIContentParent* a
   , mShown(false)
   , mUpdatedDimensions(false)
   , mManager(aManager)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mAppPackageFileDescriptorSent(false)
   , mSendOfflineStatus(true)
   , mChromeFlags(aChromeFlags)
+  , mTabId(aTabId)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -313,17 +317,23 @@ TabParent::Destroy()
   mMarkedDestroying = true;
 }
 
 bool
 TabParent::Recv__delete__()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
+    ContentParent::DeallocateTabId(mTabId,
+                                   Manager()->AsContentParent()->ChildID());
   }
+  else {
+    ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
+  }
+
   return true;
 }
 
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
   if (sEventCapturer == this) {
     sEventCapturer = nullptr;
@@ -1645,16 +1655,26 @@ TabParent::GetFrom(nsIContent* aContent)
   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
   if (!loaderOwner) {
     return nullptr;
   }
   nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
   return GetFrom(frameLoader);
 }
 
+/*static*/ TabId
+TabParent::GetTabIdFrom(nsIDocShell *docShell)
+{
+  nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
+  if (tabChild) {
+    return static_cast<TabChild*>(tabChild.get())->GetTabId();
+  }
+  return TabId(0);
+}
+
 RenderFrameParent*
 TabParent::GetRenderFrame()
 {
   if (ManagedPRenderFrameParent().IsEmpty()) {
     return nullptr;
   }
   return static_cast<RenderFrameParent*>(ManagedPRenderFrameParent()[0]);
 }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/ipc/IdType.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
 #include "Units.h"
@@ -23,16 +24,17 @@
 
 class nsFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsIWidget;
 class nsILoadContext;
 class CpowHolder;
+class nsIDocShell;
 
 namespace mozilla {
 
 namespace layers {
 struct FrameMetrics;
 struct TextureFactoryIdentifier;
 }
 
@@ -62,17 +64,20 @@ class TabParent : public PBrowserParent
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
 
     virtual ~TabParent();
 
 public:
     // nsITabParent
     NS_DECL_NSITABPARENT
 
-    TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabParent(nsIContentParent* aManager,
+              const TabId& aTabId,
+              const TabContext& aContext,
+              uint32_t aChromeFlags);
     Element* GetOwnerElement() const { return mFrameElement; }
     void SetOwnerElement(Element* aElement);
 
     /**
      * Get the mozapptype attribute from this TabParent's owner DOM element.
      */
     void GetAppType(nsAString& aOut);
 
@@ -319,27 +324,33 @@ public:
 
     static TabParent *GetIMETabParent() { return mIMETabParent; }
     bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
     bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
     bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
 
     static TabParent* GetFrom(nsFrameLoader* aFrameLoader);
     static TabParent* GetFrom(nsIContent* aContent);
+    static TabId GetTabIdFrom(nsIDocShell* docshell);
 
     nsIContentParent* Manager() { return mManager; }
 
     /**
      * Let managees query if Destroy() is already called so they don't send out
      * messages when the PBrowser actor is being destroyed.
      */
     bool IsDestroyed() const { return mIsDestroyed; }
 
     already_AddRefed<nsIWidget> GetWidget() const;
 
+    const TabId GetTabId() const
+    {
+      return mTabId;
+    }
+
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
                         const StructuredCloneData* aCloneData,
                         CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         InfallibleTArray<nsString>* aJSONRetVal = nullptr);
 
@@ -436,14 +447,16 @@ private:
 
     // Whether we need to send the offline status to the TabChild
     // This is true, until the first call of LoadURL
     bool mSendOfflineStatus;
 
     uint32_t mChromeFlags;
 
     nsCOMPtr<nsILoadContext> mLoadContext;
+
+    TabId mTabId;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -16,16 +16,17 @@ EXPORTS.mozilla.dom.ipc += [
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
+    'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
@@ -43,16 +44,17 @@ EXPORTS.mozilla += [
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
+    'ContentProcessManager.cpp',
     'CrashReporterParent.cpp',
     'FilePickerParent.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'ScreenManagerParent.cpp',
@@ -73,16 +75,17 @@ SOURCES += [
     'CrashReporterChild.cpp',
 ]
 
 IPDL_SOURCES += [
     'DOMTypes.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
+    'PBrowserOrId.ipdlh',
     'PColorPicker.ipdl',
     'PContent.ipdl',
     'PContentBridge.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PCycleCollectWithLogs.ipdl',
     'PDocumentRenderer.ipdl',
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -45,17 +45,18 @@ nsIContentChild::AllocPJavaScriptChild()
 bool
 nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild)
 {
   static_cast<JavaScriptChild*>(aChild)->decref();
   return true;
 }
 
 PBrowserChild*
-nsIContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+nsIContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                    const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
                                     const ContentParentId& aCpID,
                                     const bool& aIsForApp,
                                     const bool& aIsForBrowser)
 {
   // We'll happily accept any kind of IPCTabContext here; we don't need to
   // check that it's of a certain type for security purposes, because we
   // believe whatever the parent process tells us.
@@ -64,17 +65,17 @@ nsIContentChild::AllocPBrowserChild(cons
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason()).get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
   nsRefPtr<TabChild> child =
-    TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
+    TabChild::Create(this, aTabId, tc.GetTabContext(), aChromeFlags);
 
   // The ref here is released in DeallocPBrowserChild.
   return child.forget().take();
 }
 
 bool
 nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
 {
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -49,26 +49,28 @@ public:
   BlobChild* GetOrCreateActorForBlob(File* aBlob);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
+                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
                           const ContentParentId& aCpID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) = 0;
 protected:
   virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
   virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
 
-  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                            const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
                                             const ContentParentId& aCpId,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser);
   virtual bool DeallocPBrowserChild(PBrowserChild*);
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
 
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -19,16 +19,23 @@
 
 #include "JavaScriptParent.h"
 #include "nsFrameMessageManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla::jsipc;
 
+// XXX need another bug to move this to a common header.
+#ifdef DISABLE_ASSERTS_FOR_FUZZING
+#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
+#else
+#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
+#endif
+
 namespace mozilla {
 namespace dom {
 
 nsIContentParent::nsIContentParent()
 {
   mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
 }
 
@@ -69,64 +76,70 @@ nsIContentParent::CanOpenBrowser(const I
 {
   const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
 
   // We don't trust the IPCTabContext we receive from the child, so we'll bail
   // if we receive an IPCTabContext that's not a PopupIPCTabContext.
   // (PopupIPCTabContext lets the child process prove that it has access to
   // the app it's trying to open.)
   if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) {
-    NS_ERROR("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
     return false;
   }
 
   const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext();
-  TabParent* opener = static_cast<TabParent*>(popupContext.openerParent());
+  if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) {
+    ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type.  Aborting AllocPBrowserParent.");
+    return false;
+  }
+
+  auto opener = static_cast<TabParent*>(popupContext.opener().get_PBrowserParent());
   if (!opener) {
-    NS_ERROR("Got null opener from child; aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
     return false;
   }
 
   // Popup windows of isBrowser frames must be isBrowser if the parent
   // isBrowser.  Allocating a !isBrowser frame with same app ID would allow
   // the content to access data it's not supposed to.
   if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
-    NS_ERROR("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
     return false;
   }
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
                              "Aborting AllocPBrowserParent.",
                              tc.GetInvalidReason()).get());
     return false;
   }
 
   return true;
 }
 
 PBrowserParent*
-nsIContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
+nsIContentParent::AllocPBrowserParent(const TabId& aTabId,
+                                      const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       const ContentParentId& aCpId,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
   unused << aCpId;
   unused << aIsForApp;
   unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
 
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
-  TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags);
+  TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), aChromeFlags);
 
   // We release this ref in DeallocPBrowserParent()
   NS_ADDREF(parent);
   return parent;
 }
 
 bool
 nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -56,33 +56,35 @@ public:
   virtual bool IsForBrowser() = 0;
 
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
     const BlobConstructorParams& aParams) NS_WARN_UNUSED_RESULT = 0;
 
   virtual PBrowserParent* SendPBrowserConstructor(
     PBrowserParent* actor,
+    const TabId& aTabId,
     const IPCTabContext& context,
     const uint32_t& chromeFlags,
     const ContentParentId& aCpId,
     const bool& aIsForApp,
     const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0;
 
   virtual bool IsContentParent() { return false; }
   ContentParent* AsContentParent();
 
 protected: // methods
   bool CanOpenBrowser(const IPCTabContext& aContext);
 
 protected: // IPDL methods
   virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent();
   virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*);
 
-  virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
+  virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
+                                              const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
                                               const ContentParentId& aCpId,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
   virtual bool DeallocPBrowserParent(PBrowserParent* frame);
 
   virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams);
 
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -21,28 +21,23 @@ include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
-
+include PBrowserOrId;
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
 
 namespace mozilla {
 namespace net {
 
-union PBrowserOrId {
-  nullable PBrowser;
-  uint64_t;
-};
-
 //-------------------------------------------------------------------
 sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -22,22 +22,22 @@
 
 class nsICacheEntry;
 class nsIAssociatedContentSecurity;
 
 namespace mozilla {
 
 namespace dom{
 class TabParent;
+class PBrowserOrId;
 }
 
 namespace net {
 
 class HttpChannelParentListener;
-class PBrowserOrId;
 
 class HttpChannelParent : public PHttpChannelParent
                         , public nsIParentRedirectingChannel
                         , public nsIProgressEventSink
                         , public nsIInterfaceRequestor
                         , public ADivertableParentChannel
                         , public nsIAuthPromptProvider
                         , public DisconnectableParent
@@ -49,17 +49,17 @@ public:
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIPARENTREDIRECTINGCHANNEL
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIAUTHPROMPTPROVIDER
 
-  HttpChannelParent(const PBrowserOrId& iframeEmbedding,
+  HttpChannelParent(const dom::PBrowserOrId& iframeEmbedding,
                     nsILoadContext* aLoadContext,
                     PBOverrideStatus aStatus);
 
   bool Init(const HttpChannelCreationArgs& aOpenArgs);
 
   // ADivertableParentChannel functions.
   void DivertTo(nsIStreamListener *aListener) MOZ_OVERRIDE;
   nsresult SuspendForDiversion() MOZ_OVERRIDE;