Backed out 18 changesets (bug 792652) for build bustage on linux64 a=backout CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Tue, 08 Nov 2016 12:05:28 -0800
changeset 321737 d2098e1d1f2ddf408152ba14ad75e68566b7bc68
parent 321736 ebda706f310334b62b524d357dc8fffeaa868c00
child 321738 e6992502f673232fe03419e7cdcbeb551adfb381
push id30934
push usercbook@mozilla.com
push dateWed, 09 Nov 2016 15:38:21 +0000
treeherdermozilla-central@336759fad462 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs792652
milestone52.0a1
backs out90eaf6aec002136b753bb7f921cce5141dcd0f12
ddd915ab4a483afcbf4deb2913c4e1af5c21a86c
95eff6c45cae4aa5735aba99fbf74e3633c3556b
75855b5a9ab958643a0e0d90c222461313087e70
b658ebaad5d70a92a76e67ae33a96cfe8f48b773
2ba36b8ac60c01b555ee7311706720458739f7c2
94fcd3bf3f34dc20e2b2fbe7ff44ecfa47371f28
cf9c4164eb435ebf23cb3056eb1830861e8e8087
59e6d0a4f35b0559157423e844df5e5320841819
bdf86b8b9c43a5fc7e9b9d481f15d82925f0ae53
8edf4b247250cf585bb0e0ec9d533cbf7ad85d4c
63a3c8e4016edb83f9079390cac98fcb3277e731
e3e496eab99124260d5b8dd66f4ca2efcb1a5708
5a1e3136323a6a2c2607ef157643253f75e3a5db
dbbe3a8c00e7ce274da0c78b9338cf76957a8958
1829d53588088806844de65624363b71453a2ad3
004cd692ba6d4ae50ad7b082d67745760e9213c6
92e7fee81fa21b99f7774443e4b48f42101bdd66
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 18 changesets (bug 792652) for build bustage on linux64 a=backout CLOSED TREE Backed out changeset 90eaf6aec002 (bug 792652) Backed out changeset ddd915ab4a48 (bug 792652) Backed out changeset 95eff6c45cae (bug 792652) Backed out changeset 75855b5a9ab9 (bug 792652) Backed out changeset b658ebaad5d7 (bug 792652) Backed out changeset 2ba36b8ac60c (bug 792652) Backed out changeset 94fcd3bf3f34 (bug 792652) Backed out changeset cf9c4164eb43 (bug 792652) Backed out changeset 59e6d0a4f35b (bug 792652) Backed out changeset bdf86b8b9c43 (bug 792652) Backed out changeset 8edf4b247250 (bug 792652) Backed out changeset 63a3c8e4016e (bug 792652) Backed out changeset e3e496eab991 (bug 792652) Backed out changeset 5a1e3136323a (bug 792652) Backed out changeset dbbe3a8c00e7 (bug 792652) Backed out changeset 1829d5358808 (bug 792652) Backed out changeset 004cd692ba6d (bug 792652) Backed out changeset 92e7fee81fa2 (bug 792652)
dom/cache/CacheOpParent.cpp
dom/cache/CacheOpParent.h
dom/ipc/CrashReporterParent.cpp
dom/ipc/CrashReporterParent.h
dom/media/ipc/VideoDecoderManagerChild.cpp
dom/media/ipc/VideoDecoderManagerChild.h
dom/media/ipc/VideoDecoderManagerParent.h
dom/media/systemservices/MediaParent.h
dom/plugins/ipc/PluginMessageUtils.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/storage/DOMStorageIPC.cpp
dom/storage/DOMStorageIPC.h
gfx/ipc/VsyncBridgeChild.cpp
gfx/ipc/VsyncBridgeChild.h
gfx/layers/IPDLActor.h
gfx/layers/ipc/APZCTreeManagerChild.cpp
gfx/layers/ipc/APZCTreeManagerChild.h
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/vr/ipc/VRManagerChild.cpp
gfx/vr/ipc/VRManagerChild.h
hal/sandbox/SandboxHal.cpp
ipc/glue/MessageChannel.cpp
ipc/glue/MessageChannel.h
ipc/glue/MessageLink.h
ipc/glue/ProtocolUtils.cpp
ipc/glue/ProtocolUtils.h
ipc/glue/WindowsMessageLoop.cpp
ipc/ipdl/ipdl/lower.py
js/ipc/WrapperOwner.h
netwerk/cookie/CookieServiceParent.cpp
netwerk/cookie/CookieServiceParent.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
--- a/dom/cache/CacheOpParent.cpp
+++ b/dom/cache/CacheOpParent.cpp
@@ -49,30 +49,30 @@ CacheOpParent::~CacheOpParent()
 
 void
 CacheOpParent::Execute(ManagerId* aManagerId)
 {
   NS_ASSERT_OWNINGTHREAD(CacheOpParent);
   MOZ_ASSERT(!mManager);
   MOZ_ASSERT(!mVerifier);
 
-  RefPtr<cache::Manager> manager;
-  nsresult rv = cache::Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
+  RefPtr<Manager> manager;
+  nsresult rv = Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ErrorResult result(rv);
     Unused << Send__delete__(this, result, void_t());
     result.SuppressException();
     return;
   }
 
   Execute(manager);
 }
 
 void
-CacheOpParent::Execute(cache::Manager* aManager)
+CacheOpParent::Execute(Manager* aManager)
 {
   NS_ASSERT_OWNINGTHREAD(CacheOpParent);
   MOZ_ASSERT(!mManager);
   MOZ_ASSERT(!mVerifier);
 
   mManager = aManager;
 
   // Handle put op
--- a/dom/cache/CacheOpParent.h
+++ b/dom/cache/CacheOpParent.h
@@ -32,17 +32,17 @@ public:
   CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager,
                 Namespace aNamespace, const CacheOpArgs& aOpArgs);
   ~CacheOpParent();
 
   void
   Execute(ManagerId* aManagerId);
 
   void
-  Execute(cache::Manager* aManager);
+  Execute(Manager* aManager);
 
   void
   WaitForVerification(PrincipalVerifier* aVerifier);
 
 private:
   // PCacheOpParent methods
   virtual void
   ActorDestroy(ActorDestroyReason aReason) override;
@@ -62,17 +62,17 @@ private:
   // utility methods
   already_AddRefed<nsIInputStream>
   DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
 
   mozilla::ipc::PBackgroundParent* mIpcManager;
   const CacheId mCacheId;
   const Namespace mNamespace;
   const CacheOpArgs mOpArgs;
-  RefPtr<cache::Manager> mManager;
+  RefPtr<Manager> mManager;
   RefPtr<PrincipalVerifier> mVerifier;
 
   NS_DECL_OWNINGTHREAD
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -42,16 +42,44 @@ CrashReporterParent::ActorDestroy(ActorD
 
 bool
 CrashReporterParent::RecvAppendAppNotes(const nsCString& data)
 {
   mAppNotes.Append(data);
   return true;
 }
 
+mozilla::ipc::IProtocol*
+CrashReporterParent::CloneProtocol(Channel* aChannel,
+                                   mozilla::ipc::ProtocolCloneContext* aCtx)
+{
+#ifdef MOZ_CRASHREPORTER
+  ContentParent* contentParent = aCtx->GetContentParent();
+  CrashReporter::ThreadId childThreadId = contentParent->Pid();
+  GeckoProcessType childProcessType =
+    contentParent->Process()->GetProcessType();
+
+  nsAutoPtr<PCrashReporterParent> actor(
+    contentParent->AllocPCrashReporterParent(childThreadId,
+                                             childProcessType)
+  );
+  if (!actor ||
+      !contentParent->RecvPCrashReporterConstructor(actor,
+                                                    childThreadId,
+                                                    childThreadId)) {
+    return nullptr;
+  }
+
+  return actor.forget();
+#else
+  MOZ_CRASH("Not Implemented");
+  return nullptr;
+#endif
+}
+
 CrashReporterParent::CrashReporterParent()
   :
 #ifdef MOZ_CRASHREPORTER
     mNotes(4),
 #endif
     mStartTime(::time(nullptr))
   , mInitialized(false)
 {
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -155,16 +155,20 @@ public:
                                        const nsCString& aData) override
   {
     AnnotateCrashReport(aKey, aData);
     return true;
   }
 
   virtual bool RecvAppendAppNotes(const nsCString& aData) override;
 
+  virtual mozilla::ipc::IProtocol*
+  CloneProtocol(Channel* aChannel,
+                mozilla::ipc::ProtocolCloneContext *aCtx) override;
+
 #ifdef MOZ_CRASHREPORTER
   void
   NotifyCrashService();
 #endif
 
 #ifdef MOZ_CRASHREPORTER
   AnnotationTable mNotes;
 #endif
--- a/dom/media/ipc/VideoDecoderManagerChild.cpp
+++ b/dom/media/ipc/VideoDecoderManagerChild.cpp
@@ -241,15 +241,15 @@ VideoDecoderManagerChild::DeallocateSurf
   sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([ref, sd]() {
     if (ref->mCanSend) {
       ref->SendDeallocateSurfaceDescriptorGPUVideo(sd);
     }
   }), NS_DISPATCH_NORMAL);
 }
 
 void
-VideoDecoderManagerChild::HandleFatalError(const char* aName, const char* aMsg) const
+VideoDecoderManagerChild::FatalError(const char* const aName, const char* const aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/ipc/VideoDecoderManagerChild.h
+++ b/dom/media/ipc/VideoDecoderManagerChild.h
@@ -53,17 +53,17 @@ public:
   // Main thread only
   static void Initialize();
   static void Shutdown();
 
 protected:
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void DeallocPVideoDecoderManagerChild() override;
 
-  void HandleFatalError(const char* aName, const char* aMsg) const override;
+  void FatalError(const char* const aName, const char* const aMsg) const override;
 
   PVideoDecoderChild* AllocPVideoDecoderChild() override;
   bool DeallocPVideoDecoderChild(PVideoDecoderChild* actor) override;
 
 private:
   VideoDecoderManagerChild()
     : mCanSend(false)
   {}
--- a/dom/media/ipc/VideoDecoderManagerParent.h
+++ b/dom/media/ipc/VideoDecoderManagerParent.h
@@ -28,17 +28,17 @@ public:
 
 protected:
   PVideoDecoderParent* AllocPVideoDecoderParent() override;
   bool DeallocPVideoDecoderParent(PVideoDecoderParent* actor) override;
 
   bool RecvReadback(const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) override;
   bool RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override;
 
-  void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override {}
+  void ActorDestroy(mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason) override {}
 
   void DeallocPVideoDecoderManagerParent() override;
 
  private:
   VideoDecoderManagerParent();
   ~VideoDecoderManagerParent();
 
   void Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
--- a/dom/media/systemservices/MediaParent.h
+++ b/dom/media/systemservices/MediaParent.h
@@ -17,17 +17,17 @@ namespace media {
 
 // media::Parent implements the chrome-process side of ipc for media::Child APIs
 // A same-process version may also be created to service non-e10s calls.
 
 class OriginKeyStore;
 
 class NonE10s
 {
-  typedef mozilla::ipc::IProtocol::ActorDestroyReason
+  typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason
       ActorDestroyReason;
 public:
   virtual ~NonE10s() {}
 protected:
   virtual bool RecvGetOriginKey(const uint32_t& aRequestId,
                                 const nsCString& aOrigin,
                                 const bool& aPrivateBrowsing,
                                 const bool& aPersist) = 0;
@@ -40,17 +40,17 @@ protected:
                                 nsCString aKey);
 };
 
 // Super = PMediaParent or NonE10s
 
 template<class Super>
 class Parent : public Super
 {
-  typedef mozilla::ipc::IProtocol::ActorDestroyReason
+  typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason
       ActorDestroyReason;
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Parent<Super>)
 
   virtual bool RecvGetOriginKey(const uint32_t& aRequestId,
                                 const nsCString& aOrigin,
                                 const bool& aPrivateBrowsing,
                                 const bool& aPersist) override;
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -5,19 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DOM_PLUGINS_PLUGINMESSAGEUTILS_H
 #define DOM_PLUGINS_PLUGINMESSAGEUTILS_H
 
 #include "ipc/IPCMessageUtils.h"
 #include "base/message_loop.h"
 
+#include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/CrossProcessMutex.h"
-#include "mozilla/ipc/MessageChannel.h"
-#include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/UniquePtr.h"
 #include "gfxipc/ShadowLayerUtils.h"
 
 #include "npapi.h"
 #include "npruntime.h"
 #include "npfunctions.h"
 #include "nsString.h"
 #include "nsTArray.h"
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1031,17 +1031,18 @@ PluginModuleChromeParent::GetInvokingPro
  *
  * This function needs to be updated if the subprotocols are modified in
  * PPluginInstance.ipdl.
  */
 PluginInstanceParent*
 PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol)
 {
     MOZ_ASSERT(aProtocol);
-    mozilla::ipc::IProtocol* listener = aProtocol;
+    mozilla::ipc::MessageListener* listener =
+        static_cast<mozilla::ipc::MessageListener*>(aProtocol);
     switch (listener->GetProtocolTypeId()) {
         case PPluginInstanceMsgStart:
             // In this case, aProtocol is the instance itself. Just cast it.
             return static_cast<PluginInstanceParent*>(aProtocol);
         case PPluginBackgroundDestroyerMsgStart: {
             PPluginBackgroundDestroyerParent* actor =
                 static_cast<PPluginBackgroundDestroyerParent*>(aProtocol);
             return static_cast<PluginInstanceParent*>(actor->Manager());
--- a/dom/storage/DOMStorageIPC.cpp
+++ b/dom/storage/DOMStorageIPC.cpp
@@ -366,16 +366,28 @@ DOMStorageDBParent::DOMStorageDBParent()
 DOMStorageDBParent::~DOMStorageDBParent()
 {
   DOMStorageObserver* observer = DOMStorageObserver::Self();
   if (observer) {
     observer->RemoveSink(this);
   }
 }
 
+mozilla::ipc::IProtocol*
+DOMStorageDBParent::CloneProtocol(Channel* aChannel,
+                                  mozilla::ipc::ProtocolCloneContext* aCtx)
+{
+  ContentParent* contentParent = aCtx->GetContentParent();
+  nsAutoPtr<PStorageParent> actor(contentParent->AllocPStorageParent());
+  if (!actor || !contentParent->RecvPStorageConstructor(actor)) {
+    return nullptr;
+  }
+  return actor.forget();
+}
+
 DOMStorageDBParent::CacheParentBridge*
 DOMStorageDBParent::NewCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix)
 {
   return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
 }
 
 void
 DOMStorageDBParent::ActorDestroy(ActorDestroyReason aWhy)
--- a/dom/storage/DOMStorageIPC.h
+++ b/dom/storage/DOMStorageIPC.h
@@ -120,16 +120,20 @@ private:
 class DOMStorageDBParent final : public PStorageParent
                                , public DOMStorageObserverSink
 {
   virtual ~DOMStorageDBParent();
 
 public:
   DOMStorageDBParent();
 
+  virtual mozilla::ipc::IProtocol*
+  CloneProtocol(Channel* aChannel,
+                mozilla::ipc::ProtocolCloneContext* aCtx) override;
+
   NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
   NS_IMETHOD_(MozExternalRefCountType) Release(void);
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
   bool IPCOpen() { return mIPCOpen; }
 
--- a/gfx/ipc/VsyncBridgeChild.cpp
+++ b/gfx/ipc/VsyncBridgeChild.cpp
@@ -141,15 +141,15 @@ VsyncBridgeChild::DeallocPVsyncBridgeChi
 
 void
 VsyncBridgeChild::ProcessingError(Result aCode, const char* aReason)
 {
   MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in VsyncBridgeChild");
 }
 
 void
-VsyncBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+VsyncBridgeChild::FatalError(const char* const aName, const char* const aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/ipc/VsyncBridgeChild.h
+++ b/gfx/ipc/VsyncBridgeChild.h
@@ -28,17 +28,17 @@ public:
   void Close();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void DeallocPVsyncBridgeChild() override;
   void ProcessingError(Result aCode, const char* aReason) override;
 
   void NotifyVsync(TimeStamp aTimeStamp, const uint64_t& aLayersId);
 
-  virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+  virtual void FatalError(const char* const aName, const char* const aMsg) const override;
 
 private:
   VsyncBridgeChild(RefPtr<VsyncIOThreadHolder>, const uint64_t& aProcessToken);
   ~VsyncBridgeChild();
 
   void Open(Endpoint<PVsyncBridgeChild>&& aEndpoint);
 
   void NotifyVsyncImpl(TimeStamp aTimeStamp, const uint64_t& aLayersId);
--- a/gfx/layers/IPDLActor.h
+++ b/gfx/layers/IPDLActor.h
@@ -33,17 +33,17 @@ public:
 
   virtual bool RecvDestroy() override
   {
     DestroyIfNeeded();
     Unused << Protocol::Send__delete__(this);
     return true;
   }
 
-  typedef ipc::IProtocol::ActorDestroyReason Why;
+  typedef ipc::IProtocolManager<ipc::IProtocol>::ActorDestroyReason Why;
 
   virtual void ActorDestroy(Why) override {
     DestroyIfNeeded();
   }
 
 protected:
   void DestroyIfNeeded() {
     if (!mDestroyed) {
--- a/gfx/layers/ipc/APZCTreeManagerChild.cpp
+++ b/gfx/layers/ipc/APZCTreeManagerChild.cpp
@@ -257,10 +257,18 @@ APZCTreeManagerChild::RecvNotifyPinchGes
   // of the pinch is. This may change in the future.
   if (mCompositorSession &&
       mCompositorSession->GetWidget()) {
     APZCCallbackHelper::NotifyPinchGesture(aType, aSpanChange, aModifiers, mCompositorSession->GetWidget());
   }
   return true;
 }
 
+void
+APZCTreeManagerChild::OnProcessingError(
+        Result aCode,
+        const char* aReason)
+{
+  MOZ_RELEASE_ASSERT(aCode != MsgDropped);
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/APZCTreeManagerChild.h
+++ b/gfx/layers/ipc/APZCTreeManagerChild.h
@@ -81,16 +81,21 @@ public:
           LayoutDeviceIntPoint* aRefPoint,
           ScrollableLayerGuid* aOutTargetGuid) override;
 
   void
   UpdateWheelTransaction(
           LayoutDeviceIntPoint aRefPoint,
           EventMessage aEventMessage) override;
 
+  void
+  OnProcessingError(
+          Result aCode,
+          const char* aReason) override;
+
 protected:
   bool RecvHandleTap(const TapType& aType,
                      const LayoutDevicePoint& aPoint,
                      const Modifiers& aModifiers,
                      const ScrollableLayerGuid& aGuid,
                      const uint64_t& aInputBlockId) override;
 
   bool RecvNotifyPinchGesture(const PinchGestureType& aType,
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1119,16 +1119,16 @@ CompositorBridgeChild::ProcessingError(R
 
 void
 CompositorBridgeChild::WillEndTransaction()
 {
   ResetShmemCounter();
 }
 
 void
-CompositorBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+CompositorBridgeChild::FatalError(const char* const aName, const char* const aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -129,17 +129,17 @@ public:
 
   virtual bool
   RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
   virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
                                        LayersBackend aLayersBackend,
                                        TextureFlags aFlags,
                                        uint64_t aSerial) override;
 
-  virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+  virtual void FatalError(const char* const aName, const char* const aMsg) const override;
 
   /**
    * Request that the parent tell us when graphics are ready on GPU.
    * When we get that message, we bounce it to the TabParent via
    * the TabChild
    * @param tabChild The object to bounce the note to.  Non-NULL.
    */
   void RequestNotifyAfterRemotePaint(TabChild* aTabChild);
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -1225,15 +1225,15 @@ ImageBridgeChild::Destroy(CompositableCh
 bool
 ImageBridgeChild::CanSend() const
 {
   MOZ_ASSERT(InImageBridgeChildThread());
   return mCanSend;
 }
 
 void
-ImageBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+ImageBridgeChild::FatalError(const char* const aName, const char* const aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -344,17 +344,17 @@ public:
 
   virtual void UpdateFwdTransactionId() override { ++mFwdTransactionId; }
   virtual uint64_t GetFwdTransactionId() override { return mFwdTransactionId; }
 
   bool InForwarderThread() override {
     return InImageBridgeChildThread();
   }
 
-  virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+  virtual void FatalError(const char* const aName, const char* const aMsg) const override;
 
 protected:
   ImageBridgeChild();
   bool DispatchAllocShmemInternal(size_t aSize,
                                   SharedMemory::SharedMemoryType aType,
                                   Shmem* aShmem,
                                   bool aUnsafe);
 
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -563,17 +563,17 @@ VRManagerChild::RemoveListener(dom::VREv
 
   mListeners.RemoveElement(aObserver);
   if (mListeners.IsEmpty()) {
     Unused << SendSetHaveEventListener(false);
   }
 }
 
 void
-VRManagerChild::HandleFatalError(const char* aName, const char* aMsg) const
+VRManagerChild::FatalError(const char* const aName, const char* const aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
 void
 VRManagerChild::SetGamepadManager(dom::GamepadManager* aGamepadManager)
 {
   MOZ_ASSERT(aGamepadManager);
--- a/gfx/vr/ipc/VRManagerChild.h
+++ b/gfx/vr/ipc/VRManagerChild.h
@@ -82,17 +82,17 @@ public:
   // the same singleton GamepadManager from the same process.
   void SetGamepadManager(dom::GamepadManager* aGamepadManager);
 
   void UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates);
   void FireDOMVRDisplayConnectEvent();
   void FireDOMVRDisplayDisconnectEvent();
   void FireDOMVRDisplayPresentChangeEvent();
 
-  virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+  virtual void FatalError(const char* const aName, const char* const aMsg) const override;
 
 protected:
   explicit VRManagerChild();
   ~VRManagerChild();
   void Destroy();
   static void DeferredDestroy(RefPtr<VRManagerChild> aVRManagerChild);
 
   virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -896,16 +896,28 @@ public:
     } else {
       // Invalid factory reset reason. That should never happen.
       return false;
     }
 
     hal::FactoryReset(reason);
     return true;
   }
+
+  virtual mozilla::ipc::IProtocol*
+  CloneProtocol(Channel* aChannel,
+                mozilla::ipc::ProtocolCloneContext* aCtx) override
+  {
+    ContentParent* contentParent = aCtx->GetContentParent();
+    nsAutoPtr<PHalParent> actor(contentParent->AllocPHalParent());
+    if (!actor || !contentParent->RecvPHalConstructor(actor)) {
+      return nullptr;
+    }
+    return actor.forget();
+  }
 };
 
 class HalChild : public PHalChild {
 public:
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) override
   {
     sHalChildDestroyed = true;
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -467,17 +467,17 @@ private:
 
     // Next item in mChan->mTransactionStack.
     AutoEnterTransaction *mNext;
 
     // Pointer the a reply received for this message, if one was received.
     nsAutoPtr<IPC::Message> mReply;
 };
 
-MessageChannel::MessageChannel(IToplevelProtocol *aListener)
+MessageChannel::MessageChannel(MessageListener *aListener)
   : mListener(aListener),
     mChannelState(ChannelClosed),
     mSide(UnknownSide),
     mLink(nullptr),
     mWorkerLoop(nullptr),
     mChannelErrorTask(nullptr),
     mWorkerLoopID(-1),
     mTimeoutMs(kNoTimeout),
@@ -1852,58 +1852,28 @@ MessageChannel::MaybeUndeferIncall()
 
     MOZ_RELEASE_ASSERT(call.nested_level() == IPC::Message::NOT_NESTED);
     RefPtr<MessageTask> task = new MessageTask(this, Move(call));
     mPending.insertBack(task);
     task->Post();
 }
 
 void
-MessageChannel::EnteredCxxStack()
-{
-    mListener->EnteredCxxStack();
-}
-
-void
 MessageChannel::ExitedCxxStack()
 {
-    mListener->ExitedCxxStack();
+    mListener->OnExitedCxxStack();
     if (mSawInterruptOutMsg) {
         MonitorAutoLock lock(*mMonitor);
         // see long comment in OnMaybeDequeueOne()
         EnqueuePendingMessages();
         mSawInterruptOutMsg = false;
     }
 }
 
 void
-MessageChannel::EnteredCall()
-{
-    mListener->EnteredCall();
-}
-
-void
-MessageChannel::ExitedCall()
-{
-    mListener->ExitedCall();
-}
-
-void
-MessageChannel::EnteredSyncSend()
-{
-    mListener->OnEnteredSyncSend();
-}
-
-void
-MessageChannel::ExitedSyncSend()
-{
-    mListener->OnExitedSyncSend();
-}
-
-void
 MessageChannel::EnqueuePendingMessages()
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
     MaybeUndeferIncall();
 
     // XXX performance tuning knob: could process all or k pending
@@ -1978,17 +1948,17 @@ bool
 MessageChannel::ShouldContinueFromTimeout()
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
     bool cont;
     {
         MonitorAutoUnlock unlock(*mMonitor);
-        cont = mListener->ShouldContinueFromReplyTimeout();
+        cont = mListener->OnReplyTimeout();
         mListener->ArtificialSleep();
     }
 
     static enum { UNKNOWN, NOT_DEBUGGING, DEBUGGING } sDebuggingChildren = UNKNOWN;
 
     if (sDebuggingChildren == UNKNOWN) {
         sDebuggingChildren = getenv("MOZ_DEBUG_CHILD_PROCESS") ? DEBUGGING : NOT_DEBUGGING;
     }
@@ -2027,17 +1997,17 @@ MessageChannel::DispatchOnChannelConnect
     MOZ_RELEASE_ASSERT(mPeerPidSet);
     mListener->OnChannelConnected(mPeerPid);
 }
 
 void
 MessageChannel::ReportMessageRouteError(const char* channelName) const
 {
     PrintErrorMessage(mSide, channelName, "Need a route");
-    mListener->ProcessingError(MsgRouteError, "MsgRouteError");
+    mListener->OnProcessingError(MsgRouteError, "MsgRouteError");
 }
 
 void
 MessageChannel::ReportConnectionError(const char* aChannelName, Message* aMsg) const
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
@@ -2069,17 +2039,17 @@ MessageChannel::ReportConnectionError(co
                        aMsg->type(), aMsg->name(), errorMsg);
 
         PrintErrorMessage(mSide, aChannelName, reason);
     } else {
         PrintErrorMessage(mSide, aChannelName, errorMsg);
     }
 
     MonitorAutoUnlock unlock(*mMonitor);
-    mListener->ProcessingError(MsgDropped, errorMsg);
+    mListener->OnProcessingError(MsgDropped, errorMsg);
 }
 
 bool
 MessageChannel::MaybeHandleError(Result code, const Message& aMsg, const char* channelName)
 {
     if (MsgProcessed == code)
         return true;
 
@@ -2114,17 +2084,17 @@ MessageChannel::MaybeHandleError(Result 
     if (msgname[0] == '?') {
         SprintfLiteral(reason,"(msgtype=0x%X) %s", aMsg.type(), errorMsg);
     } else {
         SprintfLiteral(reason,"%s %s", msgname, errorMsg);
     }
 
     PrintErrorMessage(mSide, channelName, reason);
 
-    mListener->ProcessingError(code, reason);
+    mListener->OnProcessingError(code, reason);
 
     return false;
 }
 
 void
 MessageChannel::OnChannelErrorFromLink()
 {
     AssertLinkThread();
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -28,17 +28,16 @@
 #include <deque>
 #include <stack>
 #include <math.h>
 
 namespace mozilla {
 namespace ipc {
 
 class MessageChannel;
-class IToplevelProtocol;
 
 class RefCountedMonitor : public Monitor
 {
   public:
     RefCountedMonitor()
         : Monitor("mozilla.ipc.MessageChannel.mMonitor")
     {}
 
@@ -56,25 +55,16 @@ enum class SyncSendError {
     NotConnectedBeforeSend,
     DisconnectedDuringSend,
     CancelledBeforeSend,
     CancelledAfterSend,
     TimedOut,
     ReplyError,
 };
 
-enum ChannelState {
-    ChannelClosed,
-    ChannelOpening,
-    ChannelConnected,
-    ChannelTimeout,
-    ChannelClosing,
-    ChannelError
-};
-
 class AutoEnterTransaction;
 
 class MessageChannel : HasResultCodes
 {
     friend class ProcessLink;
     friend class ThreadLink;
 
     class CxxStackFrame;
@@ -84,17 +74,17 @@ class MessageChannel : HasResultCodes
 
   public:
     static const int32_t kNoTimeout;
 
     typedef IPC::Message Message;
     typedef IPC::MessageInfo MessageInfo;
     typedef mozilla::ipc::Transport Transport;
 
-    explicit MessageChannel(IToplevelProtocol *aListener);
+    explicit MessageChannel(MessageListener *aListener);
     ~MessageChannel();
 
     // "Open" from the perspective of the transport layer; the underlying
     // socketpair/pipe should already be created.
     //
     // Returns true if the transport layer was successfully connected,
     // i.e., mChannelState == ChannelConnected.
     bool Open(Transport* aTransport, MessageLoop* aIOLoop=0, Side aSide=UnknownSide);
@@ -333,26 +323,39 @@ class MessageChannel : HasResultCodes
     int32_t NextSeqno() {
         AssertWorkerThread();
         return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno;
     }
 
     // This helper class manages mCxxStackDepth on behalf of MessageChannel.
     // When the stack depth is incremented from zero to non-zero, it invokes
     // a callback, and similarly for when the depth goes from non-zero to zero.
-    void EnteredCxxStack();
+    void EnteredCxxStack() {
+       mListener->OnEnteredCxxStack();
+    }
+
     void ExitedCxxStack();
 
-    void EnteredCall();
-    void ExitedCall();
+    void EnteredCall() {
+        mListener->OnEnteredCall();
+    }
+
+    void ExitedCall() {
+        mListener->OnExitedCall();
+    }
 
-    void EnteredSyncSend();
-    void ExitedSyncSend();
+    void EnteredSyncSend() {
+        mListener->OnEnteredSyncSend();
+    }
 
-    IToplevelProtocol *Listener() const {
+    void ExitedSyncSend() {
+        mListener->OnExitedSyncSend();
+    }
+
+    MessageListener *Listener() const {
         return mListener;
     }
 
     void DebugAbort(const char* file, int line, const char* cond,
                     const char* why,
                     bool reply=false);
 
     // This method is only safe to call on the worker thread, or in a
@@ -487,17 +490,17 @@ class MessageChannel : HasResultCodes
 
     typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
     typedef std::map<size_t, Message> MessageMap;
     typedef IPC::Message::msgid_t msgid_t;
 
   private:
     // Based on presumption the listener owns and overlives the channel,
     // this is never nullified.
-    IToplevelProtocol* mListener;
+    MessageListener* mListener;
     ChannelState mChannelState;
     RefPtr<RefCountedMonitor> mMonitor;
     Side mSide;
     MessageLink* mLink;
     MessageLoop* mWorkerLoop;           // thread where work is done
     RefPtr<CancelableRunnable> mChannelErrorTask;  // NotifyMaybeChannelError runnable
 
     // id() of mWorkerLoop.  This persists even after mWorkerLoop is cleared
--- a/ipc/glue/MessageLink.h
+++ b/ipc/glue/MessageLink.h
@@ -34,16 +34,123 @@ struct HasResultCodes
 };
 
 enum Side {
     ParentSide,
     ChildSide,
     UnknownSide
 };
 
+enum ChannelState {
+    ChannelClosed,
+    ChannelOpening,
+    ChannelConnected,
+    ChannelTimeout,
+    ChannelClosing,
+    ChannelError
+};
+
+// What happens if Interrupt calls race?
+enum RacyInterruptPolicy {
+    RIPError,
+    RIPChildWins,
+    RIPParentWins
+};
+
+class MessageListener
+  : protected HasResultCodes,
+    public mozilla::SupportsWeakPtr<MessageListener>
+{
+  public:
+    MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MessageListener)
+    typedef IPC::Message Message;
+    typedef IPC::MessageInfo MessageInfo;
+
+    virtual ~MessageListener() { }
+
+    virtual void OnChannelClose() = 0;
+    virtual void OnChannelError() = 0;
+    virtual Result OnMessageReceived(const Message& aMessage) = 0;
+    virtual Result OnMessageReceived(const Message& aMessage, Message *& aReply) = 0;
+    virtual Result OnCallReceived(const Message& aMessage, Message *& aReply) = 0;
+    virtual void OnProcessingError(Result aError, const char* aMsgName) = 0;
+    virtual void OnChannelConnected(int32_t peer_pid) {}
+    virtual bool OnReplyTimeout() {
+        return false;
+    }
+
+    // WARNING: This function is called with the MessageChannel monitor held.
+    virtual void IntentionalCrash() {
+        MOZ_CRASH("Intentional IPDL crash");
+    }
+
+    // The code here is only useful for fuzzing. It should not be used for any
+    // other purpose.
+#ifdef DEBUG
+    // Returns true if we should simulate a timeout.
+    // WARNING: This is a testing-only function that is called with the
+    // MessageChannel monitor held. Don't do anything fancy here or we could
+    // deadlock.
+    virtual bool ArtificialTimeout() {
+        return false;
+    }
+
+    // Returns true if we want to cause the worker thread to sleep with the
+    // monitor unlocked.
+    virtual bool NeedArtificialSleep() {
+        return false;
+    }
+
+    // This function should be implemented to sleep for some amount of time on
+    // the worker thread. Will only be called if NeedArtificialSleep() returns
+    // true.
+    virtual void ArtificialSleep() {}
+#else
+    bool ArtificialTimeout() { return false; }
+    bool NeedArtificialSleep() { return false; }
+    void ArtificialSleep() {}
+#endif
+
+    virtual void OnEnteredCxxStack() {
+        NS_RUNTIMEABORT("default impl shouldn't be invoked");
+    }
+    virtual void OnExitedCxxStack() {
+        NS_RUNTIMEABORT("default impl shouldn't be invoked");
+    }
+    virtual void OnEnteredCall() {
+        NS_RUNTIMEABORT("default impl shouldn't be invoked");
+    }
+    virtual void OnExitedCall() {
+        NS_RUNTIMEABORT("default impl shouldn't be invoked");
+    }
+    virtual RacyInterruptPolicy MediateInterruptRace(const MessageInfo& parent,
+                                                     const MessageInfo& child)
+    {
+        return RIPChildWins;
+    }
+
+    /**
+     * Return true if windows messages can be handled while waiting for a reply
+     * to a sync IPDL message.
+     */
+    virtual bool HandleWindowsMessages(const Message& aMsg) const { return true; }
+
+    virtual void OnEnteredSyncSend() {
+    }
+    virtual void OnExitedSyncSend() {
+    }
+
+    virtual void ProcessRemoteNativeEventsInInterruptCall() {
+    }
+
+    // FIXME/bug 792652: this doesn't really belong here, but a
+    // large refactoring is needed to put it where it belongs.
+    virtual int32_t GetProtocolTypeId() = 0;
+};
+
 class MessageLink
 {
   public:
     typedef IPC::Message Message;
 
     explicit MessageLink(MessageChannel *aChan);
     virtual ~MessageLink();
 
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -12,17 +12,16 @@
 #endif
 
 #include "mozilla/ipc/ProtocolUtils.h"
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/StaticMutex.h"
-#include "mozilla/Unused.h"
 #include "nsPrintfCString.h"
 
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #endif
 
 #if defined(MOZ_CRASHREPORTER) && defined(XP_WIN)
@@ -49,16 +48,41 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLAT
                                           ::LocalFree)
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPSecurityDescriptor, \
                                           RemovePointer<PSECURITY_DESCRIPTOR>::Type, \
                                           ::LocalFree)
 #endif
 
 namespace ipc {
 
+ProtocolCloneContext::ProtocolCloneContext()
+  : mNeckoParent(nullptr)
+{}
+
+ProtocolCloneContext::~ProtocolCloneContext()
+{}
+
+void ProtocolCloneContext::SetContentParent(ContentParent* aContentParent)
+{
+  mContentParent = aContentParent;
+}
+
+IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId)
+ : mProtocolId(aProtoId)
+{
+}
+
+IToplevelProtocol::~IToplevelProtocol()
+{
+  if (mTrans) {
+    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTrans.release());
+    XRE_GetIOMessageLoop()->PostTask(task.forget());
+  }
+}
+
 class ChannelOpened : public IPC::Message
 {
 public:
   ChannelOpened(TransportDescriptor aDescriptor,
                 ProcessId aOtherProcess,
                 ProtocolId aProtocol,
                 NestedLevel aNestedLevel = NOT_NESTED)
     : IPC::Message(MSG_ROUTING_CONTROL, // these only go to top-level actors
@@ -348,373 +372,10 @@ TableToArray(const nsTHashtable<nsPtrHas
   uint32_t i = 0;
   void** elements = aArray.AppendElements(aTable.Count());
   for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
     elements[i] = iter.Get()->GetKey();
     ++i;
   }
 }
 
-Maybe<IProtocol*>
-IProtocol::ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
-                     const char* aActorDescription, int32_t aProtocolTypeId)
-{
-    int32_t id;
-    if (!IPC::ReadParam(aMessage, aIter, &id)) {
-        ActorIdReadError(aActorDescription);
-        return Nothing();
-    }
-
-    if (id == 1 || (id == 0 && !aNullable)) {
-        BadActorIdError(aActorDescription);
-        return Nothing();
-    }
-
-    if (id == 0) {
-        return Some(static_cast<IProtocol*>(nullptr));
-    }
-
-    IProtocol* listener = this->Lookup(id);
-    if (!listener) {
-        ActorLookupError(aActorDescription);
-        return Nothing();
-    }
-
-    if (listener->GetProtocolTypeId() != aProtocolTypeId) {
-        MismatchedActorTypeError(aActorDescription);
-        return Nothing();
-    }
-
-    return Some(listener);
-}
-
-int32_t
-IProtocol::Register(IProtocol* aRouted)
-{
-  return Manager()->Register(aRouted);
-}
-
-int32_t
-IProtocol::RegisterID(IProtocol* aRouted, int32_t aId)
-{
-  return Manager()->RegisterID(aRouted, aId);
-}
-
-IProtocol*
-IProtocol::Lookup(int32_t aId)
-{
-  return Manager()->Lookup(aId);
-}
-
-void
-IProtocol::Unregister(int32_t aId)
-{
-  Manager()->Unregister(aId);
-}
-
-Shmem::SharedMemory*
-IProtocol::CreateSharedMemory(size_t aSize,
-                              SharedMemory::SharedMemoryType aType,
-                              bool aUnsafe,
-                              int32_t* aId)
-{
-  return Manager()->CreateSharedMemory(aSize, aType, aUnsafe, aId);
-}
-
-Shmem::SharedMemory*
-IProtocol::LookupSharedMemory(int32_t aId)
-{
-  return Manager()->LookupSharedMemory(aId);
-}
-
-bool
-IProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* aSegment)
-{
-  return Manager()->IsTrackingSharedMemory(aSegment);
-}
-
-bool
-IProtocol::DestroySharedMemory(Shmem& aShmem)
-{
-  return Manager()->DestroySharedMemory(aShmem);
-}
-
-ProcessId
-IProtocol::OtherPid() const
-{
-  return Manager()->OtherPid();
-}
-
-void
-IProtocol::FatalError(const char* const aErrorMsg) const
-{
-  HandleFatalError(ProtocolName(), aErrorMsg);
-}
-
-void
-IProtocol::HandleFatalError(const char* aProtocolName, const char* aErrorMsg) const
-{
-  if (IProtocol* manager = Manager()) {
-    manager->HandleFatalError(aProtocolName, aErrorMsg);
-    return;
-  }
-
-  mozilla::ipc::FatalError(aProtocolName, aErrorMsg, mSide == ParentSide);
-}
-
-bool
-IProtocol::AllocShmem(size_t aSize,
-                      Shmem::SharedMemory::SharedMemoryType aType,
-                      Shmem* aOutMem)
-{
-  Shmem::id_t id;
-  Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, aType, false, &id));
-  if (!rawmem) {
-    return false;
-  }
-
-  *aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
-  return true;
-}
-
-bool
-IProtocol::AllocUnsafeShmem(size_t aSize,
-                            Shmem::SharedMemory::SharedMemoryType aType,
-                            Shmem* aOutMem)
-{
-  Shmem::id_t id;
-  Shmem::SharedMemory* rawmem(CreateSharedMemory(aSize, aType, true, &id));
-  if (!rawmem) {
-    return false;
-  }
-
-  *aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
-  return true;
-}
-
-bool
-IProtocol::DeallocShmem(Shmem& aMem)
-{
-  bool ok = DestroySharedMemory(aMem);
-#ifdef DEBUG
-  if (!ok) {
-    if (mSide == ChildSide) {
-      FatalError("bad Shmem");
-    } else {
-      NS_WARNING("bad Shmem");
-    }
-    return false;
-  }
-#endif // DEBUG
-  aMem.forget(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
-  return ok;
-}
-
-IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId, Side aSide)
- : IProtocol(aSide),
-   mProtocolId(aProtoId),
-   mOtherPid(mozilla::ipc::kInvalidProcessId),
-   mLastRouteId(aSide == ParentSide ? 1 : 0),
-   mLastShmemId(aSide == ParentSide ? 1 : 0)
-{
-}
-
-IToplevelProtocol::~IToplevelProtocol()
-{
-  if (mTrans) {
-    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTrans.release());
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-  }
-}
-
-base::ProcessId
-IToplevelProtocol::OtherPid() const
-{
-  return mOtherPid;
-}
-
-void
-IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid)
-{
-  mOtherPid = aOtherPid;
-}
-
-bool
-IToplevelProtocol::TakeMinidump(nsIFile** aDump, uint32_t* aSequence)
-{
-  MOZ_RELEASE_ASSERT(GetSide() == ParentSide);
-#ifdef MOZ_CRASHREPORTER
-  return XRE_TakeMinidumpForChild(OtherPid(), aDump, aSequence);
-#else
-  return false;
-#endif
-}
-
-bool
-IToplevelProtocol::Open(mozilla::ipc::Transport* aTransport,
-                        base::ProcessId aOtherPid,
-                        MessageLoop* aThread,
-                        mozilla::ipc::Side aSide)
-{
-  SetOtherProcessId(aOtherPid);
-  return GetIPCChannel()->Open(aTransport, aThread, aSide);
-}
-
-bool
-IToplevelProtocol::Open(MessageChannel* aChannel,
-                        MessageLoop* aMessageLoop,
-                        mozilla::ipc::Side aSide)
-{
-  SetOtherProcessId(base::GetCurrentProcId());
-  return GetIPCChannel()->Open(aChannel, aMessageLoop, aSide);
-}
-
-void
-IToplevelProtocol::Close()
-{
-  GetIPCChannel()->Close();
-}
-
-void
-IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs)
-{
-  GetIPCChannel()->SetReplyTimeoutMs(aTimeoutMs);
-}
-
-bool
-IToplevelProtocol::IsOnCxxStack() const
-{
-  return GetIPCChannel()->IsOnCxxStack();
-}
-
-int32_t
-IToplevelProtocol::Register(IProtocol* aRouted)
-{
-  int32_t id = GetSide() == ParentSide ? ++mLastRouteId : --mLastRouteId;
-  mActorMap.AddWithID(aRouted, id);
-  return id;
-}
-
-int32_t
-IToplevelProtocol::RegisterID(IProtocol* aRouted,
-                              int32_t aId)
-{
-  mActorMap.AddWithID(aRouted, aId);
-  return aId;
-}
-
-IProtocol*
-IToplevelProtocol::Lookup(int32_t aId)
-{
-  return mActorMap.Lookup(aId);
-}
-
-void
-IToplevelProtocol::Unregister(int32_t aId)
-{
-  return mActorMap.Remove(aId);
-}
-
-Shmem::SharedMemory*
-IToplevelProtocol::CreateSharedMemory(size_t aSize,
-                                      Shmem::SharedMemory::SharedMemoryType aType,
-                                      bool aUnsafe,
-                                      Shmem::id_t* aId)
-{
-  RefPtr<Shmem::SharedMemory> segment(
-    Shmem::Alloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aSize, aType, aUnsafe));
-  if (!segment) {
-    return nullptr;
-  }
-  int32_t id = GetSide() == ParentSide ? ++mLastShmemId : --mLastShmemId;
-  Shmem shmem(
-    Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(),
-    segment.get(),
-    id);
-  Message* descriptor = shmem.ShareTo(
-    Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), OtherPid(), MSG_ROUTING_CONTROL);
-  if (!descriptor) {
-    return nullptr;
-  }
-  Unused << GetIPCChannel()->Send(descriptor);
-
-  *aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
-  Shmem::SharedMemory* rawSegment = segment.get();
-  mShmemMap.AddWithID(segment.forget().take(), *aId);
-  return rawSegment;
-}
-
-Shmem::SharedMemory*
-IToplevelProtocol::LookupSharedMemory(Shmem::id_t aId)
-{
-  return mShmemMap.Lookup(aId);
-}
-
-bool
-IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* segment)
-{
-  return mShmemMap.HasData(segment);
-}
-
-bool
-IToplevelProtocol::DestroySharedMemory(Shmem& shmem)
-{
-  Shmem::id_t aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
-  Shmem::SharedMemory* segment = LookupSharedMemory(aId);
-  if (!segment) {
-    return false;
-  }
-
-  Message* descriptor = shmem.UnshareFrom(
-    Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), OtherPid(), MSG_ROUTING_CONTROL);
-
-  mShmemMap.Remove(aId);
-  Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), segment);
-
-  if (!GetIPCChannel()->CanSend()) {
-    delete descriptor;
-    return true;
-  }
-
-  return descriptor && GetIPCChannel()->Send(descriptor);
-}
-
-void
-IToplevelProtocol::DeallocShmems()
-{
-  for (IDMap<SharedMemory>::const_iterator cit = mShmemMap.begin(); cit != mShmemMap.end(); ++cit) {
-    Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), cit->second);
-  }
-  mShmemMap.Clear();
-}
-
-bool
-IToplevelProtocol::ShmemCreated(const Message& aMsg)
-{
-  Shmem::id_t id;
-  RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aMsg, &id, true));
-  if (!rawmem) {
-    return false;
-  }
-  mShmemMap.AddWithID(rawmem.forget().take(), id);
-  return true;
-}
-
-bool
-IToplevelProtocol::ShmemDestroyed(const Message& aMsg)
-{
-  Shmem::id_t id;
-  PickleIterator iter = PickleIterator(aMsg);
-  if (!IPC::ReadParam(&aMsg, &iter, &id)) {
-    return false;
-  }
-  aMsg.EndRead(iter);
-
-  Shmem::SharedMemory* rawmem = LookupSharedMemory(id);
-  if (rawmem) {
-    mShmemMap.Remove(id);
-    Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem);
-  }
-  return true;
-}
-
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -1,19 +1,18 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=4 ts=4 et :
  */
 /* 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_ipc_ProtocolUtils_h
 #define mozilla_ipc_ProtocolUtils_h 1
 
-#include "base/id_map.h"
 #include "base/process.h"
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 
 #include "prenv.h"
 
 #include "IPCMessageStart.h"
 #include "mozilla/Attributes.h"
@@ -61,18 +60,16 @@ class ContentParent;
 } // namespace dom
 
 namespace net {
 class NeckoParent;
 } // namespace net
 
 namespace ipc {
 
-class MessageChannel;
-
 #ifdef XP_WIN
 const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE;
 
 // In theory, on Windows, this is a valid process ID, but in practice they are
 // currently divisible by four. Process IDs share the kernel handle allocation
 // code and they are guaranteed to be divisible by four.
 // As this could change for process IDs we shouldn't generally rely on this
 // property, however even if that were to change, it seems safe to rely on this
@@ -128,229 +125,127 @@ struct Trigger
     {
       MOZ_ASSERT(0 <= msg && msg < INT32_MAX);
     }
 
     uint32_t mAction : 1;
     uint32_t mMessage : 31;
 };
 
-// What happens if Interrupt calls race?
-enum RacyInterruptPolicy {
-    RIPError,
-    RIPChildWins,
-    RIPParentWins
+class ProtocolCloneContext
+{
+  typedef mozilla::dom::ContentParent ContentParent;
+  typedef mozilla::net::NeckoParent NeckoParent;
+
+  RefPtr<ContentParent> mContentParent;
+  NeckoParent* mNeckoParent;
+
+public:
+  ProtocolCloneContext();
+
+  ~ProtocolCloneContext();
+
+  void SetContentParent(ContentParent* aContentParent);
+
+  ContentParent* GetContentParent() { return mContentParent; }
+
+  void SetNeckoParent(NeckoParent* aNeckoParent)
+  {
+    mNeckoParent = aNeckoParent;
+  }
+
+  NeckoParent* GetNeckoParent() { return mNeckoParent; }
 };
 
-class IProtocol : public HasResultCodes
+template<class ListenerT>
+class IProtocolManager
 {
 public:
     enum ActorDestroyReason {
         FailedConstructor,
         Deletion,
         AncestorDeletion,
         NormalShutdown,
         AbnormalShutdown
     };
 
     typedef base::ProcessId ProcessId;
-    typedef IPC::Message Message;
-    typedef IPC::MessageInfo MessageInfo;
 
-    IProtocol(Side aSide) : mId(0), mSide(aSide), mManager(nullptr), mChannel(nullptr) {}
-
-    virtual int32_t Register(IProtocol*);
-    virtual int32_t RegisterID(IProtocol*, int32_t);
-    virtual IProtocol* Lookup(int32_t);
-    virtual void Unregister(int32_t);
-    virtual void RemoveManagee(int32_t, IProtocol*) = 0;
+    virtual int32_t Register(ListenerT*) = 0;
+    virtual int32_t RegisterID(ListenerT*, int32_t) = 0;
+    virtual ListenerT* Lookup(int32_t) = 0;
+    virtual void Unregister(int32_t) = 0;
+    virtual void RemoveManagee(int32_t, ListenerT*) = 0;
 
     virtual Shmem::SharedMemory* CreateSharedMemory(
-        size_t, SharedMemory::SharedMemoryType, bool, int32_t*);
-    virtual Shmem::SharedMemory* LookupSharedMemory(int32_t);
-    virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*);
-    virtual bool DestroySharedMemory(Shmem&);
+        size_t, SharedMemory::SharedMemoryType, bool, int32_t*) = 0;
+    virtual Shmem::SharedMemory* LookupSharedMemory(int32_t) = 0;
+    virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0;
+    virtual bool DestroySharedMemory(Shmem&) = 0;
 
     // XXX odd ducks, acknowledged
-    virtual ProcessId OtherPid() const;
-    Side GetSide() const { return mSide; }
-
-    virtual const char* ProtocolName() const = 0;
-    void FatalError(const char* const aErrorMsg) const;
-    virtual void HandleFatalError(const char* aProtocolName, const char* aErrorMsg) const;
-
-    Maybe<IProtocol*> ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
-                                const char* aActorDescription, int32_t aProtocolTypeId);
-
-    virtual Result OnMessageReceived(const Message& aMessage) = 0;
-    virtual Result OnMessageReceived(const Message& aMessage, Message *& aReply) = 0;
-    virtual Result OnCallReceived(const Message& aMessage, Message *& aReply) = 0;
-
-    virtual int32_t GetProtocolTypeId() = 0;
+    virtual ProcessId OtherPid() const = 0;
+    virtual MessageChannel* GetIPCChannel() = 0;
 
-    int32_t Id() const { return mId; }
-    IProtocol* Manager() const { return mManager; }
-    virtual const MessageChannel* GetIPCChannel() const { return mChannel; }
-    virtual MessageChannel* GetIPCChannel() { return mChannel; }
-
-    bool AllocShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
-    bool AllocUnsafeShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
-    bool DeallocShmem(Shmem& aMem);
+    virtual void FatalError(const char* const aProtocolName, const char* const aErrorMsg) const = 0;
 
-protected:
-    void SetId(int32_t aId) { mId = aId; }
-    void SetManager(IProtocol* aManager) { mManager = aManager; }
-    void SetIPCChannel(MessageChannel* aChannel) { mChannel = aChannel; }
-
-private:
-    int32_t mId;
-    Side mSide;
-    IProtocol* mManager;
-    MessageChannel* mChannel;
+    Maybe<ListenerT*> ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
+                                const char* aActorDescription, int32_t aProtocolTypeId);
 };
 
 typedef IPCMessageStart ProtocolId;
 
+/**
+ * All RPC protocols should implement this interface.
+ */
+class IProtocol : public MessageListener
+{
+public:
+    /**
+     * This function is used to clone this protocol actor.
+     *
+     * see IProtocol::CloneProtocol()
+     */
+    virtual IProtocol*
+    CloneProtocol(MessageChannel* aChannel,
+                  ProtocolCloneContext* aCtx) = 0;
+};
+
 template<class PFooSide>
 class Endpoint;
 
 /**
  * All top-level protocols should inherit this class.
  *
  * IToplevelProtocol tracks all top-level protocol actors created from
  * this protocol actor.
  */
-class IToplevelProtocol : public IProtocol
+class IToplevelProtocol
 {
     template<class PFooSide> friend class Endpoint;
 
 protected:
-    explicit IToplevelProtocol(ProtocolId aProtoId, Side aSide);
+    explicit IToplevelProtocol(ProtocolId aProtoId);
     ~IToplevelProtocol();
 
 public:
     void SetTransport(UniquePtr<Transport> aTrans)
     {
         mTrans = Move(aTrans);
     }
 
     Transport* GetTransport() const { return mTrans.get(); }
 
     ProtocolId GetProtocolId() const { return mProtocolId; }
 
-    base::ProcessId OtherPid() const;
-    void SetOtherProcessId(base::ProcessId aOtherPid);
-
-    bool TakeMinidump(nsIFile** aDump, uint32_t* aSequence);
-
-    virtual void OnChannelClose() = 0;
-    virtual void OnChannelError() = 0;
-    virtual void ProcessingError(Result aError, const char* aMsgName) {}
-    virtual void OnChannelConnected(int32_t peer_pid) {}
-
-    bool Open(mozilla::ipc::Transport* aTransport,
-              base::ProcessId aOtherPid,
-              MessageLoop* aThread = nullptr,
-              mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
-
-    bool Open(MessageChannel* aChannel,
-              MessageLoop* aMessageLoop,
-              mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
-
-    void Close();
-
-    void SetReplyTimeoutMs(int32_t aTimeoutMs);
-
-    virtual int32_t Register(IProtocol*);
-    virtual int32_t RegisterID(IProtocol*, int32_t);
-    virtual IProtocol* Lookup(int32_t);
-    virtual void Unregister(int32_t);
-
-    virtual Shmem::SharedMemory* CreateSharedMemory(
-        size_t, SharedMemory::SharedMemoryType, bool, int32_t*);
-    virtual Shmem::SharedMemory* LookupSharedMemory(int32_t);
-    virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*);
-    virtual bool DestroySharedMemory(Shmem&);
-
-    void DeallocShmems();
-
-    bool ShmemCreated(const Message& aMsg);
-    bool ShmemDestroyed(const Message& aMsg);
-
-    virtual bool ShouldContinueFromReplyTimeout() {
-        return false;
-    }
-
-    // WARNING: This function is called with the MessageChannel monitor held.
-    virtual void IntentionalCrash() {
-        MOZ_CRASH("Intentional IPDL crash");
-    }
-
-    // The code here is only useful for fuzzing. It should not be used for any
-    // other purpose.
-#ifdef DEBUG
-    // Returns true if we should simulate a timeout.
-    // WARNING: This is a testing-only function that is called with the
-    // MessageChannel monitor held. Don't do anything fancy here or we could
-    // deadlock.
-    virtual bool ArtificialTimeout() {
-        return false;
-    }
-
-    // Returns true if we want to cause the worker thread to sleep with the
-    // monitor unlocked.
-    virtual bool NeedArtificialSleep() {
-        return false;
-    }
-
-    // This function should be implemented to sleep for some amount of time on
-    // the worker thread. Will only be called if NeedArtificialSleep() returns
-    // true.
-    virtual void ArtificialSleep() {}
-#else
-    bool ArtificialTimeout() { return false; }
-    bool NeedArtificialSleep() { return false; }
-    void ArtificialSleep() {}
-#endif
-
-    virtual void EnteredCxxStack() {}
-    virtual void ExitedCxxStack() {}
-    virtual void EnteredCall() {}
-    virtual void ExitedCall() {}
-
-    bool IsOnCxxStack() const;
-
-    virtual RacyInterruptPolicy MediateInterruptRace(const MessageInfo& parent,
-                                                     const MessageInfo& child)
-    {
-        return RIPChildWins;
-    }
-
-    /**
-     * Return true if windows messages can be handled while waiting for a reply
-     * to a sync IPDL message.
-     */
-    virtual bool HandleWindowsMessages(const Message& aMsg) const { return true; }
-
-    virtual void OnEnteredSyncSend() {
-    }
-    virtual void OnExitedSyncSend() {
-    }
-
-    virtual void ProcessRemoteNativeEventsInInterruptCall() {
-    }
+    virtual MessageChannel* GetIPCChannel() = 0;
 
 private:
     ProtocolId mProtocolId;
     UniquePtr<Transport> mTrans;
-    base::ProcessId mOtherPid;
-    IDMap<IProtocol> mActorMap;
-    int32_t mLastRouteId;
-    IDMap<Shmem::SharedMemory> mShmemMap;
-    Shmem::id_t mLastShmemId;
 };
 
 class IShmemAllocator
 {
 public:
   virtual bool AllocShmem(size_t aSize,
                           mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
                           mozilla::ipc::Shmem* aShmem) = 0;
@@ -453,16 +348,50 @@ Open(const PrivateIPDLInterface&,
      MessageChannel*, base::ProcessId, Transport::Mode,
      ProtocolId, ProtocolId);
 
 bool
 UnpackChannelOpened(const PrivateIPDLInterface&,
                     const IPC::Message&,
                     TransportDescriptor*, base::ProcessId*, ProtocolId*);
 
+template<typename ListenerT>
+Maybe<ListenerT*>
+IProtocolManager<ListenerT>::ReadActor(const IPC::Message* aMessage, PickleIterator* aIter, bool aNullable,
+                                       const char* aActorDescription, int32_t aProtocolTypeId)
+{
+    int32_t id;
+    if (!IPC::ReadParam(aMessage, aIter, &id)) {
+        ActorIdReadError(aActorDescription);
+        return Nothing();
+    }
+
+    if (id == 1 || (id == 0 && !aNullable)) {
+        BadActorIdError(aActorDescription);
+        return Nothing();
+    }
+
+    if (id == 0) {
+        return Some(static_cast<ListenerT*>(nullptr));
+    }
+
+    ListenerT* listener = this->Lookup(id);
+    if (!listener) {
+        ActorLookupError(aActorDescription);
+        return Nothing();
+    }
+
+    if (static_cast<MessageListener*>(listener)->GetProtocolTypeId() != aProtocolTypeId) {
+        MismatchedActorTypeError(aActorDescription);
+        return Nothing();
+    }
+
+    return Some(listener);
+}
+
 #if defined(XP_WIN)
 // This is a restricted version of Windows' DuplicateHandle() function
 // that works inside the sandbox and can send handles but not retrieve
 // them.  Unlike DuplicateHandle(), it takes a process ID rather than
 // a process handle.  It returns true on success, false otherwise.
 bool
 DuplicateHandle(HANDLE aSourceHandle,
                 DWORD aTargetProcessId,
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -12,17 +12,16 @@
 
 #include "nsAutoPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsIXULAppInfo.h"
 #include "WinUtils.h"
 
 #include "mozilla/ArrayUtils.h"
-#include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/PaintTracker.h"
 #include "mozilla/WindowsVersion.h"
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace mozilla::ipc::windows;
 
 /**
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -115,24 +115,27 @@ def _actorName(pname, side):
 def _actorIdType():
     return Type.INT32
 
 def _actorTypeTagType():
     return Type.INT32
 
 def _actorId(actor=None):
     if actor is not None:
-        return ExprCall(ExprSelect(actor, '->', 'Id'))
-    return ExprCall(ExprVar('Id'))
+        return ExprSelect(actor, '->', 'mId')
+    return ExprVar('mId')
 
 def _actorHId(actorhandle):
     return ExprSelect(actorhandle, '.', 'mId')
 
+def _actorChannel(actor):
+    return ExprSelect(actor, '->', 'mChannel')
+
 def _actorManager(actor):
-    return ExprCall(ExprSelect(actor, '->', 'Manager'), args=[])
+    return ExprSelect(actor, '->', 'mManager')
 
 def _actorState(actor):
     return ExprSelect(actor, '->', 'mState')
 
 def _backstagePass():
     return ExprCall(ExprVar('mozilla::ipc::PrivateIPDLInterface'))
 
 def _iterType(ptr):
@@ -387,16 +390,36 @@ def _printErrorMessage(msg):
         ExprCall(ExprVar('NS_ERROR'), args=[ msg ]))
 
 def _protocolErrorBreakpoint(msg):
     if isinstance(msg, str):
         msg = ExprLiteral.String(msg)
     return StmtExpr(ExprCall(ExprVar('mozilla::ipc::ProtocolErrorBreakpoint'),
                              args=[ msg ]))
 
+def _ipcFatalError(name, msg):
+    if isinstance(name, str):
+        name = ExprLiteral.String(name)
+    if isinstance(msg, str):
+        msg = ExprLiteral.String(msg)
+    return StmtExpr(ExprCall(ExprVar('FatalError'),
+                             args=[ name, msg ]))
+
+def _ipcFatalErrorWithClassname(name, msg, p, isparent):
+    if isinstance(name, str):
+        name = ExprLiteral.String(name)
+    if isinstance(msg, str):
+        msg = ExprLiteral.String(msg)
+    if p.decl.type.isToplevel():
+        return StmtExpr(ExprCall(ExprVar('mozilla::ipc::FatalError'),
+                                 args=[ name, msg, isparent ]))
+    else:
+        return StmtExpr(ExprCall(ExprSelect(p.managerVar(), '->', 'FatalError'),
+                                 [ name, msg ]))
+
 def _printWarningMessage(msg):
     if isinstance(msg, str):
         msg = ExprLiteral.String(msg)
     return StmtExpr(
         ExprCall(ExprVar('NS_WARNING'), args=[ msg ]))
 
 def _fatalError(msg):
     return StmtExpr(
@@ -1062,31 +1085,45 @@ class Protocol(ipdl.ast.Protocol):
         return '->'
 
     def channelType(self):
         return Type('Channel', ptr=not self.decl.type.isToplevel())
 
     def channelHeaderFile(self):
         return '/'.join(_semsToChannelParts(self.sendSems())) +'.h'
 
+    def fqListenerName(self):
+      return 'mozilla::ipc::MessageListener'
+
+    def fqBaseClass(self):
+        return 'mozilla::ipc::IProtocol'
+
     def managerInterfaceType(self, ptr=0):
-        return Type('mozilla::ipc::IProtocol', ptr=ptr)
+        return Type('mozilla::ipc::IProtocolManager',
+                    ptr=ptr,
+                    T=Type(self.fqBaseClass()))
 
     def openedProtocolInterfaceType(self, ptr=0):
         return Type('mozilla::ipc::IToplevelProtocol',
                     ptr=ptr)
 
     def _ipdlmgrtype(self):
         assert 1 == len(self.decl.type.managers)
         for mgr in self.decl.type.managers:  return mgr
 
     def managerActorType(self, side, ptr=0):
         return Type(_actorName(self._ipdlmgrtype().name(), side),
                     ptr=ptr)
 
+    def managerMethod(self, actorThis=None):
+        _ = self._ipdlmgrtype()
+        if actorThis is not None:
+            return ExprSelect(actorThis, '->', 'Manager')
+        return ExprVar('Manager');
+
     def stateMethod(self):
         return ExprVar('state');
 
     def registerMethod(self):
         return ExprVar('Register')
 
     def registerIDMethod(self):
         return ExprVar('RegisterID')
@@ -1127,16 +1164,19 @@ class Protocol(ipdl.ast.Protocol):
         return ExprVar('GetIPCChannel')
 
     def callGetChannel(self, actorThis=None):
         fn = self.getChannelMethod()
         if actorThis is not None:
             fn = ExprSelect(actorThis, '->', fn.name)
         return ExprCall(fn)
 
+    def cloneProtocol(self):
+        return ExprVar('CloneProtocol')
+
     def processingErrorVar(self):
         assert self.decl.type.isToplevel()
         return ExprVar('ProcessingError')
 
     def shouldContinueFromTimeoutVar(self):
         assert self.decl.type.isToplevel()
         return ExprVar('ShouldContinueFromReplyTimeout')
 
@@ -1155,28 +1195,60 @@ class Protocol(ipdl.ast.Protocol):
     def exitedCallVar(self):
         assert self.decl.type.isToplevel()
         return ExprVar('ExitedCall')
 
     def onCxxStackVar(self):
         assert self.decl.type.isToplevel()
         return ExprVar('IsOnCxxStack')
 
+    def nextActorIdExpr(self, side):
+        assert self.decl.type.isToplevel()
+        if side is 'parent':   op = '++'
+        elif side is 'child':  op = '--'
+        else: assert 0
+        return ExprPrefixUnop(self.lastActorIdVar(), op)
+
+    def actorIdInit(self, side):
+        assert self.decl.type.isToplevel()
+
+        # parents go up from FREED, children go down from NULL
+        if side is 'parent':  return _FREED_ACTOR_ID
+        elif side is 'child': return _NULL_ACTOR_ID
+        else: assert 0
+
     # an actor's C++ private variables
+    def lastActorIdVar(self):
+        assert self.decl.type.isToplevel()
+        return ExprVar('mLastRouteId')
+
+    def actorMapVar(self):
+        assert self.decl.type.isToplevel()
+        return ExprVar('mActorMap')
+
     def channelVar(self, actorThis=None):
         if actorThis is not None:
             return ExprSelect(actorThis, '->', 'mChannel')
         return ExprVar('mChannel')
 
+    def channelForSubactor(self):
+        if self.decl.type.isToplevel():
+            return ExprAddrOf(self.channelVar())
+        return self.channelVar()
+
     def routingId(self, actorThis=None):
         if self.decl.type.isToplevel():
             return ExprVar('MSG_ROUTING_CONTROL')
         if actorThis is not None:
-            return ExprCall(ExprSelect(actorThis, '->', 'Id'))
-        return ExprCall(ExprVar('Id'))
+            return ExprSelect(actorThis, '->', self.idVar().name)
+        return self.idVar()
+
+    def idVar(self):
+        assert not self.decl.type.isToplevel()
+        return ExprVar('mId')
 
     def stateVar(self, actorThis=None):
         if actorThis is not None:
             return ExprSelect(actorThis, '->', 'mState')
         return ExprVar('mState')
 
     def fqStateType(self):
         return Type(self.decl.type.name() +'::State')
@@ -1187,21 +1259,25 @@ class Protocol(ipdl.ast.Protocol):
     def nullState(self):
         return _nullState(self.decl.type)
 
     def deadState(self):
         return _deadState(self.decl.type)
 
     def managerVar(self, thisexpr=None):
         assert thisexpr is not None or not self.decl.type.isToplevel()
-        mvar = ExprCall(ExprVar('Manager'), args=[])
+        mvar = ExprVar('mManager')
         if thisexpr is not None:
-            mvar = ExprCall(ExprSelect(thisexpr, '->', 'Manager'), args=[])
+            mvar = ExprSelect(thisexpr, '->', mvar.name)
         return mvar
 
+    def otherPidVar(self):
+        assert self.decl.type.isToplevel()
+        return ExprVar('mOtherPid')
+
     def managedCxxType(self, actortype, side):
         assert self.decl.type.isManagerOf(actortype)
         return Type(_actorName(actortype.name(), side), ptr=1)
 
     def managedMethod(self, actortype, side):
         assert self.decl.type.isManagerOf(actortype)
         return ExprVar('Managed'+  _actorName(actortype.name(), side))
 
@@ -1209,16 +1285,58 @@ class Protocol(ipdl.ast.Protocol):
         assert self.decl.type.isManagerOf(actortype)
         return ExprVar('mManaged'+ _actorName(actortype.name(), side))
 
     def managedVarType(self, actortype, side, const=0, ref=0):
         assert self.decl.type.isManagerOf(actortype)
         return _cxxManagedContainerType(Type(_actorName(actortype.name(), side)),
                                         const=const, ref=ref)
 
+    def managerArrayExpr(self, thisvar, side):
+        """The member var my manager keeps of actors of my type."""
+        assert self.decl.type.isManaged()
+        return ExprSelect(
+            ExprCall(self.managerMethod(thisvar)),
+            '->', 'mManaged'+ _actorName(self.decl.type.name(), side))
+
+    # shmem stuff
+    def shmemMapType(self):
+        assert self.decl.type.isToplevel()
+        return Type('IDMap', T=_rawShmemType())
+
+    def shmemIteratorType(self):
+        assert self.decl.type.isToplevel()
+        # XXX breaks abstractions
+        return Type('IDMap<SharedMemory>::const_iterator')
+
+    def shmemMapVar(self):
+        assert self.decl.type.isToplevel()
+        return ExprVar('mShmemMap')
+
+    def lastShmemIdVar(self):
+        assert self.decl.type.isToplevel()
+        return ExprVar('mLastShmemId')
+
+    def shmemIdInit(self, side):
+        assert self.decl.type.isToplevel()
+        # use the same scheme for shmem IDs as actor IDs
+        if side is 'parent':  return _FREED_ACTOR_ID
+        elif side is 'child': return _NULL_ACTOR_ID
+        else: assert 0
+
+    def nextShmemIdExpr(self, side):
+        assert self.decl.type.isToplevel()
+        if side is 'parent':   op = '++'
+        elif side is 'child':  op = '--'
+        return ExprPrefixUnop(self.lastShmemIdVar(), op)
+
+    def removeShmemId(self, idexpr):
+        return ExprCall(ExprSelect(self.shmemMapVar(), '.', 'Remove'),
+                        args=[ idexpr ])
+
     # XXX this is sucky, fix
     def usesShmem(self):
         return _usesShmem(self)
 
     def subtreeUsesShmem(self):
         return _subtreeUsesShmem(self)
 
     @staticmethod
@@ -2505,24 +2623,26 @@ class _GenerateProtocolActorCode(ipdl.as
     def lower(self, tu, clsname, cxxHeaderFile, cxxFile):
         self.clsname = clsname
         self.hdrfile = cxxHeaderFile
         self.cppfile = cxxFile
         tu.accept(self)
 
     def standardTypedefs(self):
         return [
-            Typedef(Type('mozilla::ipc::IProtocol'), 'ProtocolBase'),
+            Typedef(Type(self.protocol.fqBaseClass()), 'ProtocolBase'),
             Typedef(Type('IPC::Message'), 'Message'),
             Typedef(Type(self.protocol.channelName()), 'Channel'),
-            Typedef(Type('mozilla::ipc::IProtocol'), 'ChannelListener'),
+            Typedef(Type(self.protocol.fqListenerName()), 'ChannelListener'),
             Typedef(Type('base::ProcessHandle'), 'ProcessHandle'),
             Typedef(Type('mozilla::ipc::MessageChannel'), 'MessageChannel'),
             Typedef(Type('mozilla::ipc::SharedMemory'), 'SharedMemory'),
             Typedef(Type('mozilla::ipc::Trigger'), 'Trigger'),
+            Typedef(Type('mozilla::ipc::ProtocolCloneContext'),
+                    'ProtocolCloneContext')
         ]
 
 
     def visitTranslationUnit(self, tu):
         self.protocol = tu.protocol
 
         hf = self.hdrfile
         cf = self.cppfile
@@ -2694,32 +2814,31 @@ class _GenerateProtocolActorCode(ipdl.as
         # FIXME: all actors impl Iface for now
         if ptype.isManager() or 1:
             self.hdrfile.addthing(CppDirective('include', '"base/id_map.h"'))
 
         self.hdrfile.addthings([
             CppDirective('include', '"'+ p.channelHeaderFile() +'"'),
             Whitespace.NL ])
 
-        inherits = []
+        optinherits = []
         if ptype.isToplevel():
-            inherits.append(Inherit(p.openedProtocolInterfaceType(),
-                                    viz='public'))
-        else:
-            inherits.append(Inherit(p.managerInterfaceType(), viz='public'))
-
+            optinherits.append(Inherit(p.openedProtocolInterfaceType(),
+                                      viz='public'))
         if ptype.isToplevel() and self.side is 'parent':
             self.hdrfile.addthings([
                     _makeForwardDeclForQClass('nsIFile', []),
                     Whitespace.NL
                     ])
 
         self.cls = Class(
             self.clsname,
-            inherits=inherits,
+            inherits=[ Inherit(Type(p.fqBaseClass()), viz='public'),
+                       Inherit(p.managerInterfaceType(), viz='protected') ] +
+            optinherits,
             abstract=True)
 
         bridgeActorsCreated = ProcessGraph.bridgeEndpointsOf(ptype, self.side)
         opensActorsCreated = ProcessGraph.opensEndpointsOf(ptype, self.side)
         channelOpenedActors = OrderedDict.fromkeys(bridgeActorsCreated + opensActorsCreated, None)
 
         friends = _FindFriends().findFriends(ptype)
         if ptype.isManaged():
@@ -2855,55 +2974,133 @@ class _GenerateProtocolActorCode(ipdl.as
             [ Label.PUBLIC ]
             + self.standardTypedefs()
             + [ Whitespace.NL ]
         ))
 
         self.cls.addstmt(Label.PUBLIC)
         # Actor()
         ctor = ConstructorDefn(ConstructorDecl(self.clsname))
-        side = ExprVar('mozilla::ipc::' + self.side.title() + 'Side')
         if ptype.isToplevel():
             ctor.memberinits = [
-                ExprMemberInit(ExprVar('mozilla::ipc::IToplevelProtocol'),
-                               [_protocolId(ptype), side]),
                 ExprMemberInit(p.channelVar(), [
                     ExprCall(ExprVar('ALLOW_THIS_IN_INITIALIZER_LIST'),
                              [ ExprVar.THIS ]) ]),
+                ExprMemberInit(p.lastActorIdVar(),
+                               [ p.actorIdInit(self.side) ]),
+                ExprMemberInit(p.otherPidVar(),
+                               [ ExprVar('mozilla::ipc::kInvalidProcessId') ]),
+                ExprMemberInit(p.lastShmemIdVar(),
+                               [ p.shmemIdInit(self.side) ]),
                 ExprMemberInit(p.stateVar(),
                                [ p.startState() ])
             ]
+            if ptype.isToplevel():
+                ctor.memberinits = [ExprMemberInit(
+                    p.openedProtocolInterfaceType(),
+                    [ _protocolId(ptype) ])] + ctor.memberinits
         else:
             ctor.memberinits = [
-                ExprMemberInit(ExprVar('mozilla::ipc::IProtocol'), [side]),
+                ExprMemberInit(p.idVar(), [ ExprLiteral.ZERO ]),
                 ExprMemberInit(p.stateVar(),
                                [ p.deadState() ])
             ]
 
         ctor.addstmt(StmtExpr(ExprCall(ExprVar('MOZ_COUNT_CTOR'),
                                        [ ExprVar(self.clsname) ])))
         self.cls.addstmts([ ctor, Whitespace.NL ])
 
         # ~Actor()
         dtor = DestructorDefn(
             DestructorDecl(self.clsname, virtual=True))
         dtor.addstmt(StmtExpr(ExprCall(ExprVar('MOZ_COUNT_DTOR'),
                                                [ ExprVar(self.clsname) ])))
 
         self.cls.addstmts([ dtor, Whitespace.NL ])
 
+        if ptype.isToplevel():
+            # Open(Transport*, ProcessId, MessageLoop*, Side)
+            aTransportVar = ExprVar('aTransport')
+            aThreadVar = ExprVar('aThread')
+            otherPidVar = ExprVar('aOtherPid')
+            sidevar = ExprVar('aSide')
+            openmeth = MethodDefn(
+                MethodDecl(
+                    'Open',
+                    params=[ Decl(Type('Channel::Transport', ptr=True),
+                                      aTransportVar.name),
+                             Decl(Type('base::ProcessId'), otherPidVar.name),
+                             Param(Type('MessageLoop', ptr=True),
+                                   aThreadVar.name,
+                                   default=ExprLiteral.NULL),
+                             Param(Type('mozilla::ipc::Side'),
+                                   sidevar.name,
+                                   default=ExprVar('mozilla::ipc::UnknownSide')) ],
+                    ret=Type.BOOL))
+
+            openmeth.addstmts([
+                StmtExpr(ExprAssn(p.otherPidVar(), otherPidVar)),
+                StmtReturn(ExprCall(ExprSelect(p.channelVar(), '.', 'Open'),
+                                    [ aTransportVar, aThreadVar, sidevar ]))
+            ])
+            self.cls.addstmts([
+                openmeth,
+                Whitespace.NL ])
+
+            # Open(MessageChannel *, MessageLoop *, Side)
+            aChannel = ExprVar('aChannel')
+            aMessageLoop = ExprVar('aMessageLoop')
+            sidevar = ExprVar('aSide')
+            openmeth = MethodDefn(
+                MethodDecl(
+                    'Open',
+                    params=[ Decl(Type('MessageChannel', ptr=True),
+                                      aChannel.name),
+                             Param(Type('MessageLoop', ptr=True),
+                                   aMessageLoop.name),
+                             Param(Type('mozilla::ipc::Side'),
+                                   sidevar.name,
+                                   default=ExprVar('mozilla::ipc::UnknownSide')) ],
+                    ret=Type.BOOL))
+
+            openmeth.addstmts([
+                StmtExpr(ExprAssn(p.otherPidVar(), ExprCall(ExprVar('base::GetCurrentProcId')))),
+                StmtReturn(ExprCall(ExprSelect(p.channelVar(), '.', 'Open'),
+                                    [ aChannel, aMessageLoop, sidevar ]))
+            ])
+            self.cls.addstmts([
+                openmeth,
+                Whitespace.NL ])
+
+            # Close()
+            closemeth = MethodDefn(MethodDecl('Close'))
+            closemeth.addstmt(StmtExpr(
+                ExprCall(ExprSelect(p.channelVar(), '.', 'Close'))))
+            self.cls.addstmts([ closemeth, Whitespace.NL ])
+
+            if ptype.isSync() or ptype.isInterrupt():
+                # SetReplyTimeoutMs()
+                timeoutvar = ExprVar('aTimeoutMs')
+                settimeout = MethodDefn(MethodDecl(
+                    'SetReplyTimeoutMs',
+                    params=[ Decl(Type.INT32, timeoutvar.name) ]))
+                settimeout.addstmt(StmtExpr(
+                    ExprCall(
+                        ExprSelect(p.channelVar(), '.', 'SetReplyTimeoutMs'),
+                        args=[ timeoutvar ])))
+                self.cls.addstmts([ settimeout, Whitespace.NL ])
+
         if not ptype.isToplevel():
             if 1 == len(p.managers):
                 ## manager() const
                 managertype = p.managerActorType(self.side, ptr=1)
                 managermeth = MethodDefn(MethodDecl(
-                    'Manager', ret=managertype, const=1))
-                managerexp = ExprCall(ExprVar('IProtocol::Manager'), args=[])
+                    p.managerMethod().name, ret=managertype, const=1))
                 managermeth.addstmt(StmtReturn(
-                    ExprCast(managerexp, managertype, static=1)))
+                    ExprCast(p.managerVar(), managertype, static=1)))
 
                 self.cls.addstmts([ managermeth, Whitespace.NL ])
 
         def actorFromIter(itervar):
             return ExprCall(ExprSelect(ExprCall(ExprSelect(itervar, '.', 'Get')),
                                        '->', 'GetKey'))
         def forLoopOverHashtable(hashtable, itervar, const=False):
             return StmtFor(
@@ -3071,44 +3268,122 @@ class _GenerateProtocolActorCode(ipdl.as
             Whitespace.NL
         ])
 
         destroysubtreevar = ExprVar('DestroySubtree')
         deallocsubtreevar = ExprVar('DeallocSubtree')
         deallocshmemvar = ExprVar('DeallocShmems')
         deallocselfvar = ExprVar('Dealloc' + _actorName(ptype.name(), self.side))
 
+        # OnProcesingError(code)
+        codevar = ExprVar('aCode')
+        reasonvar = ExprVar('aReason')
+        onprocessingerror = MethodDefn(
+            MethodDecl('OnProcessingError',
+                       params=[ Param(_Result.Type(), codevar.name),
+                                Param(Type('char', const=1, ptr=1), reasonvar.name) ]))
+        if ptype.isToplevel():
+            onprocessingerror.addstmt(StmtReturn(
+                ExprCall(p.processingErrorVar(), args=[ codevar, reasonvar ])))
+        else:
+            onprocessingerror.addstmt(
+                _fatalError("`OnProcessingError' called on non-toplevel actor"))
+        self.cls.addstmts([ onprocessingerror, Whitespace.NL ])
+
         # int32_t GetProtocolTypeId() { return PFoo; }
         gettypetag = MethodDefn(
             MethodDecl('GetProtocolTypeId', ret=_actorTypeTagType()))
         gettypetag.addstmt(StmtReturn(_protocolId(ptype)))
         self.cls.addstmts([ gettypetag, Whitespace.NL ])
 
+        # OnReplyTimeout()
+        if toplevel.isSync() or toplevel.isInterrupt():
+            ontimeout = MethodDefn(
+                MethodDecl('OnReplyTimeout', ret=Type.BOOL))
+
+            if ptype.isToplevel():
+                ontimeout.addstmt(StmtReturn(
+                    ExprCall(p.shouldContinueFromTimeoutVar())))
+            else:
+                ontimeout.addstmts([
+                    _fatalError("`OnReplyTimeout' called on non-toplevel actor"),
+                    StmtReturn.FALSE
+                ])
+
+            self.cls.addstmts([ ontimeout, Whitespace.NL ])
+
+        # C++-stack-related methods
         if ptype.isToplevel():
-            # OnChannelClose()
-            onclose = MethodDefn(MethodDecl('OnChannelClose'))
+            # OnEnteredCxxStack()
+            onentered = MethodDefn(MethodDecl('OnEnteredCxxStack'))
+            onentered.addstmt(StmtReturn(ExprCall(p.enteredCxxStackVar())))
+
+            # OnExitedCxxStack()
+            onexited = MethodDefn(MethodDecl('OnExitedCxxStack'))
+            onexited.addstmt(StmtReturn(ExprCall(p.exitedCxxStackVar())))
+
+            # OnEnteredCxxStack()
+            onenteredcall = MethodDefn(MethodDecl('OnEnteredCall'))
+            onenteredcall.addstmt(StmtReturn(ExprCall(p.enteredCallVar())))
+
+            # OnExitedCxxStack()
+            onexitedcall = MethodDefn(MethodDecl('OnExitedCall'))
+            onexitedcall.addstmt(StmtReturn(ExprCall(p.exitedCallVar())))
+
+            # bool IsOnCxxStack()
+            onstack = MethodDefn(
+                MethodDecl(p.onCxxStackVar().name, ret=Type.BOOL, const=1))
+            onstack.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.channelVar(), '.', p.onCxxStackVar().name))))
+
+            self.cls.addstmts([ onentered, onexited,
+                                onenteredcall, onexitedcall,
+                                onstack, Whitespace.NL ])
+
+        # OnChannelClose()
+        onclose = MethodDefn(MethodDecl('OnChannelClose'))
+        if ptype.isToplevel():
             onclose.addstmts([
                 StmtExpr(ExprCall(destroysubtreevar,
                                   args=[ _DestroyReason.NormalShutdown ])),
                 StmtExpr(ExprCall(deallocsubtreevar)),
                 StmtExpr(ExprCall(deallocshmemvar)),
                 StmtExpr(ExprCall(deallocselfvar))
             ])
-            self.cls.addstmts([ onclose, Whitespace.NL ])
-
-            # OnChannelError()
-            onerror = MethodDefn(MethodDecl('OnChannelError'))
+        else:
+            onclose.addstmt(
+                _fatalError("`OnClose' called on non-toplevel actor"))
+        self.cls.addstmts([ onclose, Whitespace.NL ])
+
+        # OnChannelError()
+        onerror = MethodDefn(MethodDecl('OnChannelError'))
+        if ptype.isToplevel():
             onerror.addstmts([
                 StmtExpr(ExprCall(destroysubtreevar,
                                   args=[ _DestroyReason.AbnormalShutdown ])),
                 StmtExpr(ExprCall(deallocsubtreevar)),
                 StmtExpr(ExprCall(deallocshmemvar)),
                 StmtExpr(ExprCall(deallocselfvar))
             ])
-            self.cls.addstmts([ onerror, Whitespace.NL ])
+        else:
+            onerror.addstmt(
+                _fatalError("`OnError' called on non-toplevel actor"))
+        self.cls.addstmts([ onerror, Whitespace.NL ])
+
+        # OnChannelConnected()
+        onconnected = MethodDefn(MethodDecl('OnChannelConnected',
+                                            params=[ Decl(Type.INT32, 'aPid') ]))
+        if not ptype.isToplevel():
+            onconnected.addstmt(
+                _fatalError("'OnConnected' called on non-toplevel actor"))
+
+        self.cls.addstmts([ onconnected, Whitespace.NL ])
+
+        # User-facing shmem methods
+        self.cls.addstmts(self.makeShmemIface())
 
         if (ptype.isToplevel() and ptype.isInterrupt()):
 
             processnative = MethodDefn(
                 MethodDecl('ProcessNativeEventsInInterruptCall', ret=Type.VOID))
 
             processnative.addstmts([
                     CppDirective('ifdef', 'OS_WIN'),
@@ -3117,28 +3392,81 @@ class _GenerateProtocolActorCode(ipdl.as
                                        'ProcessNativeEventsInInterruptCall'))),
                     CppDirective('else'),
                     _fatalError('This method is Windows-only'),
                     CppDirective('endif'),
                     ])
 
             self.cls.addstmts([ processnative, Whitespace.NL ])
 
+        if ptype.isToplevel() and self.side is 'parent':
+            ## void SetOtherProcessId(ProcessId aOtherPid)
+            otherpidvar = ExprVar('aOtherPid')
+            setotherprocessid = MethodDefn(MethodDecl(
+                    'SetOtherProcessId',
+                    params=[ Decl(Type('base::ProcessId'), otherpidvar.name)]))
+            setotherprocessid.addstmts([
+                StmtExpr(ExprAssn(p.otherPidVar(), otherpidvar)),
+            ])
+            self.cls.addstmts([
+                    setotherprocessid,
+                    Whitespace.NL])
+
+            ## bool GetMinidump(nsIFile** dump)
+            self.cls.addstmt(Label.PROTECTED)
+
+            dumpvar = ExprVar('aDump')
+            seqvar = ExprVar('aSequence')
+            getdump = MethodDefn(MethodDecl(
+                'TakeMinidump',
+                params=[ Decl(Type('nsIFile', ptrptr=1), dumpvar.name),
+                         Decl(Type.UINT32PTR, seqvar.name)],
+                ret=Type.BOOL,
+                const=1))
+            getdump.addstmts([
+                CppDirective('ifdef', 'MOZ_CRASHREPORTER'),
+                StmtReturn(ExprCall(
+                    ExprVar('XRE_TakeMinidumpForChild'),
+                    args=[ ExprCall(p.otherPidMethod()), dumpvar, seqvar ])),
+                CppDirective('else'),
+                StmtReturn.FALSE,
+                CppDirective('endif')
+            ])
+            self.cls.addstmts([ getdump, Whitespace.NL ])
+
         ## private methods
         self.cls.addstmt(Label.PRIVATE)
 
-        ## ProtocolName()
+        ## FatalError()
+        msgparam = ExprVar('aMsg')
         actorname = _actorName(p.name, self.side)
-        protocolname = MethodDefn(MethodDecl(
-            'ProtocolName', params=[],
-            const=1, virtual=1, ret=Type('char', const=1, ptr=1)))
-        protocolname.addstmts([
-            StmtReturn(ExprLiteral.String(actorname))
+        fatalerror = MethodDefn(MethodDecl(
+            'FatalError',
+            params=[ Decl(Type('char', const=1, ptrconst=1), msgparam.name) ],
+            const=1, never_inline=1))
+        if self.side is 'parent':
+            isparent = ExprLiteral.TRUE
+        else:
+            isparent = ExprLiteral.FALSE
+        fatalerror.addstmts([
+            _ipcFatalError(actorname, msgparam)
         ])
-        self.cls.addstmts([ protocolname, Whitespace.NL ])
+        self.cls.addstmts([ fatalerror, Whitespace.NL ])
+
+        protocolnameparam = ExprVar('aProtocolName')
+
+        fatalerrorwithclassname = MethodDefn(MethodDecl(
+            'FatalError',
+            params=[ Decl(Type('char', const=1, ptrconst=1), protocolnameparam.name),
+                     Decl(Type('char', const=1, ptrconst=1), msgparam.name) ],
+            const=1))
+        fatalerrorwithclassname.addstmts([
+            _ipcFatalErrorWithClassname(protocolnameparam, msgparam, self.protocol, isparent)
+        ])
+        self.cls.addstmts([ fatalerrorwithclassname, Whitespace.NL ])
 
         ## DestroySubtree(bool normal)
         whyvar = ExprVar('why')
         subtreewhyvar = ExprVar('subtreewhy')
         kidsvar = ExprVar('kids')
         ivar = ExprVar('i')
         itervar = ExprVar('iter')
         ithkid = ExprIndex(kidsvar, ivar)
@@ -3237,24 +3565,64 @@ class _GenerateProtocolActorCode(ipdl.as
 
             ])
             deallocsubtree.addstmt(block)
         # don't delete outselves: either the manager will do it, or
         # we're toplevel
         self.cls.addstmts([ deallocsubtree, Whitespace.NL ])
 
         if ptype.isToplevel():
+            ## DeallocShmem():
+            #    for (cit = map.begin(); cit != map.end(); ++cit)
+            #      Dealloc(cit->second)
+            #    map.Clear()
+            deallocshmem = MethodDefn(MethodDecl(deallocshmemvar.name))
+
+            citvar = ExprVar('cit')
+            begin = ExprCall(ExprSelect(p.shmemMapVar(), '.', 'begin'))
+            end = ExprCall(ExprSelect(p.shmemMapVar(), '.', 'end'))
+            shmem = ExprSelect(citvar, '->', 'second')
+            foreachdealloc = StmtFor(
+                Param(p.shmemIteratorType(), citvar.name, begin),
+                ExprBinary(citvar, '!=', end),
+                ExprPrefixUnop(citvar, '++'))
+            foreachdealloc.addstmt(StmtExpr(_shmemDealloc(shmem)))
+
+            deallocshmem.addstmts([
+                foreachdealloc,
+                StmtExpr(ExprCall(ExprSelect(p.shmemMapVar(), '.', 'Clear')))
+            ])
+            self.cls.addstmts([ deallocshmem, Whitespace.NL ])
+
             deallocself = MethodDefn(MethodDecl(deallocselfvar.name, virtual=1))
             self.cls.addstmts([ deallocself, Whitespace.NL ])
 
         self.implementPickling()
 
         ## private members
+        self.cls.addstmt(StmtDecl(Decl(p.channelType(), 'mChannel')))
         if ptype.isToplevel():
-            self.cls.addstmt(StmtDecl(Decl(p.channelType(), 'mChannel')))
+            self.cls.addstmts([
+                StmtDecl(Decl(Type('IDMap', T=Type('ProtocolBase')),
+                              p.actorMapVar().name)),
+                StmtDecl(Decl(_actorIdType(), p.lastActorIdVar().name)),
+                StmtDecl(Decl(Type('base::ProcessId'),
+                              p.otherPidVar().name))
+            ])
+        elif ptype.isManaged():
+            self.cls.addstmts([
+                StmtDecl(Decl(p.managerInterfaceType(ptr=1),
+                              p.managerVar().name)),
+                StmtDecl(Decl(_actorIdType(), p.idVar().name))
+            ])
+        if p.decl.type.isToplevel():
+            self.cls.addstmts([
+                StmtDecl(Decl(p.shmemMapType(), p.shmemMapVar().name)),
+                StmtDecl(Decl(_shmemIdType(), p.lastShmemIdVar().name))
+            ])
 
         self.cls.addstmt(StmtDecl(Decl(Type('State'), p.stateVar().name)))
 
         for managed in ptype.manages:
             self.cls.addstmts([
                 StmtDecl(Decl(
                     p.managedVarType(managed, self.side),
                     p.managedVar(managed, self.side).name)) ])
@@ -3268,38 +3636,215 @@ class _GenerateProtocolActorCode(ipdl.as
         sizevar = ExprVar('aSize')
         typevar = ExprVar('aType')
         unsafevar = ExprVar('aUnsafe')
         protocolbase = Type('ProtocolBase', ptr=1)
         sourcevar = ExprVar('aSource')
         ivar = ExprVar('i')
         kidsvar = ExprVar('kids')
         ithkid = ExprIndex(kidsvar, ivar)
-
-        methods = []
-
-        if p.decl.type.isToplevel():
-            getchannel = MethodDefn(MethodDecl(
-                p.getChannelMethod().name,
-                ret=Type('MessageChannel', ptr=1),
-                virtual=1))
-            getchannel.addstmt(StmtReturn(ExprAddrOf(p.channelVar())))
-
-            getchannelconst = MethodDefn(MethodDecl(
-                p.getChannelMethod().name,
-                ret=Type('MessageChannel', ptr=1, const=1),
-                virtual=1, const=1))
-            getchannelconst.addstmt(StmtReturn(ExprAddrOf(p.channelVar())))
-
-            methods += [ getchannel,
-                         getchannelconst ]
+        clonecontexttype = Type('ProtocolCloneContext', ptr=1)
+        clonecontextvar = ExprVar('aCtx')
+
+        register = MethodDefn(MethodDecl(
+            p.registerMethod().name,
+            params=[ Decl(protocolbase, routedvar.name) ],
+            ret=_actorIdType(), virtual=1))
+        registerid = MethodDefn(MethodDecl(
+            p.registerIDMethod().name,
+            params=[ Decl(protocolbase, routedvar.name),
+                     Decl(_actorIdType(), idvar.name) ],
+            ret=_actorIdType(),
+            virtual=1))
+        lookup = MethodDefn(MethodDecl(
+            p.lookupIDMethod().name,
+            params=[ Decl(_actorIdType(), idvar.name) ],
+            ret=protocolbase, virtual=1))
+        unregister = MethodDefn(MethodDecl(
+            p.unregisterMethod().name,
+            params=[ Decl(_actorIdType(), idvar.name) ],
+            virtual=1))
+
+        createshmem = MethodDefn(MethodDecl(
+            p.createSharedMemory().name,
+            ret=_rawShmemType(ptr=1),
+            params=[ Decl(Type.SIZE, sizevar.name),
+                     Decl(_shmemTypeType(), typevar.name),
+                     Decl(Type.BOOL, unsafevar.name),
+                     Decl(_shmemIdType(ptr=1), idvar.name) ],
+            virtual=1))
+        lookupshmem = MethodDefn(MethodDecl(
+            p.lookupSharedMemory().name,
+            ret=_rawShmemType(ptr=1),
+            params=[ Decl(_shmemIdType(), idvar.name) ],
+            virtual=1))
+        destroyshmem = MethodDefn(MethodDecl(
+            p.destroySharedMemory().name,
+            ret=Type.BOOL,
+            params=[ Decl(_shmemType(ref=1), shmemvar.name) ],
+            virtual=1))
+        istracking = MethodDefn(MethodDecl(
+            p.isTrackingSharedMemory().name,
+            ret=Type.BOOL,
+            params=[ Decl(_rawShmemType(ptr=1), rawvar.name) ],
+            virtual=1))
+
+        otherpid = MethodDefn(MethodDecl(
+            p.otherPidMethod().name,
+            ret=Type('base::ProcessId'),
+            const=1,
+            virtual=1))
+
+        getchannel = MethodDefn(MethodDecl(
+            p.getChannelMethod().name,
+            ret=Type('MessageChannel', ptr=1),
+            virtual=1))
+
+        cloneprotocol = MethodDefn(MethodDecl(
+            p.cloneProtocol().name,
+            params=[ Decl(Type('Channel', ptr=True), 'aChannel'),
+                     Decl(clonecontexttype, clonecontextvar.name) ],
+            ret=Type(p.fqBaseClass(), ptr=1),
+            virtual=1))
 
         if p.decl.type.isToplevel():
             tmpvar = ExprVar('tmp')
 
+            register.addstmts([
+                StmtDecl(Decl(_actorIdType(), tmpvar.name),
+                         p.nextActorIdExpr(self.side)),
+                StmtExpr(ExprCall(
+                    ExprSelect(p.actorMapVar(), '.', 'AddWithID'),
+                    [ routedvar, tmpvar ])),
+                StmtReturn(tmpvar)
+            ])
+            registerid.addstmts([
+                StmtExpr(
+                    ExprCall(ExprSelect(p.actorMapVar(), '.', 'AddWithID'),
+                             [ routedvar, idvar ])),
+                StmtReturn(idvar)
+            ])
+            lookup.addstmt(StmtReturn(
+                ExprCall(ExprSelect(p.actorMapVar(), '.', 'Lookup'),
+                         [ idvar ])))
+            unregister.addstmt(StmtReturn(
+                ExprCall(ExprSelect(p.actorMapVar(), '.', 'Remove'),
+                         [ idvar ])))
+
+            # SharedMemory* CreateSharedMemory(size_t aSize, Type aType, bool aUnsafe, id_t* aId):
+            #   RefPtr<SharedMemory> segment(Shmem::Alloc(aSize, aType, aUnsafe));
+            #   if (!segment)
+            #     return nullptr;
+            #   Shmem shmem(segment.get(), [nextshmemid]);
+            #   Message descriptor = shmem.ShareTo(subprocess, mId, descriptor);
+            #   if (!descriptor)
+            #     return nullptr;
+            #   mChannel.Send(descriptor);
+            #   *aId = shmem.Id();
+            #   SharedMemory* rawSegment = segment.get();
+            #   mShmemMap.Add(segment.forget().take(), *aId);
+            #   return rawSegment;
+            createshmem.addstmt(StmtDecl(
+                Decl(_refptr(_rawShmemType()), rawvar.name),
+                initargs=[ _shmemAlloc(sizevar, typevar, unsafevar) ]))
+            failif = StmtIf(ExprNot(rawvar))
+            failif.addifstmt(StmtReturn(ExprLiteral.NULL))
+            createshmem.addstmt(failif)
+
+            descriptorvar = ExprVar('descriptor')
+            createshmem.addstmts([
+                StmtDecl(
+                    Decl(_shmemType(), shmemvar.name),
+                    initargs=[ _shmemBackstagePass(),
+                               _refptrGet(rawvar),
+                               p.nextShmemIdExpr(self.side) ]),
+                StmtDecl(Decl(Type('Message', ptr=1), descriptorvar.name),
+                         init=_shmemShareTo(shmemvar,
+                                            p.callOtherPid(),
+                                            p.routingId()))
+            ])
+            failif = StmtIf(ExprNot(descriptorvar))
+            failif.addifstmt(StmtReturn(ExprLiteral.NULL))
+            createshmem.addstmt(failif)
+
+            failif = StmtIf(ExprNot(ExprCall(
+                ExprSelect(p.channelVar(), p.channelSel(), 'Send'),
+                args=[ descriptorvar ])))
+            createshmem.addstmt(failif)
+
+            rawsegmentvar = ExprVar('rawSegment')
+            createshmem.addstmts([
+                StmtExpr(ExprAssn(ExprDeref(idvar), _shmemId(shmemvar))),
+                StmtDecl(Decl(_rawShmemType(ptr=1), rawsegmentvar.name),
+                         init=_refptrGet(rawvar)),
+                StmtExpr(ExprCall(
+                    ExprSelect(p.shmemMapVar(), '.', 'AddWithID'),
+                    args=[ _refptrTake(_refptrForget(rawvar)), ExprDeref(idvar) ])),
+                StmtReturn(rawsegmentvar)
+            ])
+
+            # SharedMemory* Lookup(id)
+            lookupshmem.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.shmemMapVar(), '.', 'Lookup'),
+                args=[ idvar ])))
+
+            # bool IsTrackingSharedMemory(mem)
+            istracking.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.shmemMapVar(), '.', 'HasData'),
+                args=[ rawvar ])))
+
+            # bool DestroySharedMemory(shmem):
+            #   id = shmem.Id()
+            #   SharedMemory* rawmem = Lookup(id)
+            #   if (!rawmem)
+            #     return false;
+            #   Message descriptor = UnShare(subprocess, mId, descriptor)
+            #   mShmemMap.Remove(id)
+            #   Shmem::Dealloc(rawmem)
+            #   if (!mChannel.CanSend()) {
+            #     delete descriptor;
+            #     return true;
+            #   }
+            #   return descriptor && Send(descriptor)
+            destroyshmem.addstmts([
+                StmtDecl(Decl(_shmemIdType(), idvar.name),
+                         init=_shmemId(shmemvar)),
+                StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name),
+                         init=_lookupShmem(idvar))
+            ])
+
+            failif = StmtIf(ExprNot(rawvar))
+            failif.addifstmt(StmtReturn.FALSE)
+            cansend = ExprCall(ExprSelect(p.channelVar(), '.', 'CanSend'), [])
+            returnif = StmtIf(ExprNot(cansend))
+            returnif.addifstmts([
+                    StmtExpr(ExprDelete(descriptorvar)),
+                    StmtReturn.TRUE])
+            destroyshmem.addstmts([
+                failif,
+                Whitespace.NL,
+                StmtDecl(Decl(Type('Message', ptr=1), descriptorvar.name),
+                         init=_shmemUnshareFrom(
+                             shmemvar,
+                             p.callOtherPid(),
+                             p.routingId())),
+                Whitespace.NL,
+                StmtExpr(p.removeShmemId(idvar)),
+                StmtExpr(_shmemDealloc(rawvar)),
+                Whitespace.NL,
+                returnif,
+                Whitespace.NL,
+                StmtReturn(ExprBinary(
+                    descriptorvar, '&&',
+                    ExprCall(
+                        ExprSelect(p.channelVar(), p.channelSel(), 'Send'),
+                        args=[ descriptorvar ])))
+            ])
+
+
             # "private" message that passes shmem mappings from one process
             # to the other
             if p.subtreeUsesShmem():
                 self.asyncSwitch.addcase(
                     CaseLabel('SHMEM_CREATED_MESSAGE_TYPE'),
                     self.genShmemCreatedHandler())
                 self.asyncSwitch.addcase(
                     CaseLabel('SHMEM_DESTROYED_MESSAGE_TYPE'),
@@ -3310,16 +3855,54 @@ class _GenerateProtocolActorCode(ipdl.as
                     _fatalError('this protocol tree does not use shmem'),
                     StmtReturn(_Result.NotKnown)
                 ])
                 self.asyncSwitch.addcase(
                     CaseLabel('SHMEM_CREATED_MESSAGE_TYPE'), abort)
                 self.asyncSwitch.addcase(
                     CaseLabel('SHMEM_DESTROYED_MESSAGE_TYPE'), abort)
 
+            otherpid.addstmt(StmtReturn(p.otherPidVar()))
+            getchannel.addstmt(StmtReturn(ExprAddrOf(p.channelVar())))
+        else:
+            # delegate registration to manager
+            register.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.registerMethod().name),
+                [ routedvar ])))
+            registerid.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.registerIDMethod().name),
+                [ routedvar, idvar ])))
+            lookup.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.lookupIDMethod().name),
+                [ idvar ])))
+            unregister.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.unregisterMethod().name),
+                [ idvar ])))
+            createshmem.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.createSharedMemory().name),
+                [ sizevar, typevar, unsafevar, idvar ])))
+            lookupshmem.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.lookupSharedMemory().name),
+                [ idvar ])))
+            istracking.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->',
+                           p.isTrackingSharedMemory().name),
+                [ rawvar ])))
+            destroyshmem.addstmt(StmtReturn(ExprCall(
+                ExprSelect(p.managerVar(), '->', p.destroySharedMemory().name),
+                [ shmemvar ])))
+            otherpid.addstmt(StmtReturn(
+                p.callOtherPid(p.managerVar())))
+            getchannel.addstmt(StmtReturn(p.channelVar()))
+
+        cloneprotocol.addstmts([
+            _fatalError('Clone() has not yet been implemented'),
+            StmtReturn(ExprLiteral.NULL)
+        ])
+
         othervar = ExprVar('other')
         managertype = Type(_actorName(p.name, self.side), ptr=1)
 
         # Keep track of types created with an INOUT ctor. We need to call
         # Register() or RegisterID() for them depending on the side the managee
         # is created.
         inoutCtorTypes = []
         for msg in p.messageDecls:
@@ -3368,45 +3951,197 @@ class _GenerateProtocolActorCode(ipdl.as
                 ])
                 switchontype.addcase(CaseLabel(_protocolId(manageeipdltype).name),
                                      case)
             default = StmtBlock()
             default.addstmts([ _fatalError('unreached'), StmtReturn() ])
             switchontype.addcase(DefaultLabel(), default)
             removemanagee.addstmt(switchontype)
 
-        return methods + [removemanagee, Whitespace.NL]
+        return [ register,
+                 registerid,
+                 lookup,
+                 unregister,
+                 removemanagee,
+                 createshmem,
+                 lookupshmem,
+                 istracking,
+                 destroyshmem,
+                 otherpid,
+                 getchannel,
+                 cloneprotocol,
+                 Whitespace.NL ]
+
+    def makeShmemIface(self):
+        p = self.protocol
+        idvar = ExprVar('id')
+        sizevar = ExprVar('aSize')
+        typevar = ExprVar('aType')
+        memvar = ExprVar('aMem')
+        outmemvar = ExprVar('aOutMem')
+        rawvar = ExprVar('rawmem')
+
+        def allocShmemMethod(name, unsafe):
+            # bool Alloc*Shmem(size_t aSize, Type aType, Shmem* aOutMem):
+            #   id_t id;
+            #   SharedMemory* rawmem(CreateSharedMemory(aSize, aType, false, &id));
+            #   if (!rawmem)
+            #     return false;
+            #   *aOutMem = Shmem(rawmem, id)
+            #   return true;
+            method = MethodDefn(MethodDecl(
+                name,
+                params=[ Decl(Type.SIZE, sizevar.name),
+                         Decl(_shmemTypeType(), typevar.name),
+                         Decl(_shmemType(ptr=1), outmemvar.name) ],
+                ret=Type.BOOL))
+
+            ifallocfails = StmtIf(ExprNot(rawvar))
+            ifallocfails.addifstmt(StmtReturn.FALSE)
+
+            if unsafe:
+                unsafe = ExprLiteral.TRUE
+            else:
+                unsafe = ExprLiteral.FALSE
+            method.addstmts([
+                StmtDecl(Decl(_shmemIdType(), idvar.name)),
+                StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name),
+                         initargs=[ ExprCall(p.createSharedMemory(),
+                                         args=[ sizevar,
+                                                typevar,
+                                                unsafe,
+                                                ExprAddrOf(idvar) ]) ]),
+                ifallocfails,
+                Whitespace.NL,
+                StmtExpr(ExprAssn(
+                    ExprDeref(outmemvar), _shmemCtor(rawvar, idvar))),
+                StmtReturn.TRUE
+            ])
+            return method
+
+        # bool AllocShmem(size_t size, Type type, Shmem* outmem):
+        allocShmem = allocShmemMethod('AllocShmem', False)
+
+        # bool AllocUnsafeShmem(size_t size, Type type, Shmem* outmem):
+        allocUnsafeShmem = allocShmemMethod('AllocUnsafeShmem', True)
+
+        # bool DeallocShmem(Shmem& mem):
+        #   bool ok = DestroySharedMemory(mem);
+        ##ifdef DEBUG
+        #   if (!ok) {
+        #     NS_WARNING("bad Shmem"); // or NS_RUNTIMEABORT on child side
+        #     return false;
+        #   }
+        ##endif // DEBUG
+        #   mem.forget();
+        #   return ok;
+        deallocShmem = MethodDefn(MethodDecl(
+            'DeallocShmem',
+            params=[ Decl(_shmemType(ref=1), memvar.name) ],
+            ret=Type.BOOL))
+        okvar = ExprVar('ok')
+
+        ifbad = StmtIf(ExprNot(okvar))
+        badShmemActions = []
+        if (self.side == 'child'):
+            badShmemActions.append(_fatalError('bad Shmem'));
+        else:
+            badShmemActions.append(_printWarningMessage('bad Shmem'));
+        badShmemActions.append(StmtReturn.FALSE);
+        ifbad.addifstmts(badShmemActions)
+
+        deallocShmem.addstmts([
+            StmtDecl(Decl(Type.BOOL, okvar.name),
+                     init=ExprCall(p.destroySharedMemory(),
+                                   args=[ memvar ])),
+            CppDirective('ifdef', 'DEBUG'),
+            ifbad,
+            CppDirective('endif', '// DEBUG'),
+            StmtExpr(_shmemForget(memvar)),
+            StmtReturn(okvar)
+        ])
+
+        return [ Whitespace('// Methods for managing shmem\n', indent=1),
+                 allocShmem,
+                 Whitespace.NL,
+                 allocUnsafeShmem,
+                 Whitespace.NL,
+                 deallocShmem,
+                 Whitespace.NL ]
 
     def genShmemCreatedHandler(self):
         p = self.protocol
         assert p.decl.type.isToplevel()
 
         case = StmtBlock()
 
-        ifstmt = StmtIf(ExprNot(ExprCall(ExprVar('ShmemCreated'), args=[self.msgvar])))
+        rawvar = ExprVar('rawmem')
+        idvar = ExprVar('id')
         case.addstmts([
-            ifstmt,
+            StmtDecl(Decl(_shmemIdType(), idvar.name)),
+            StmtDecl(Decl(_refptr(_rawShmemType()), rawvar.name),
+                     initargs=[ _shmemOpenExisting(self.msgvar,
+                                                   ExprAddrOf(idvar)) ])
+        ])
+        failif = StmtIf(ExprNot(rawvar))
+        failif.addifstmt(StmtReturn(_Result.PayloadError))
+
+        case.addstmts([
+            failif,
+            StmtExpr(ExprCall(
+                ExprSelect(p.shmemMapVar(), '.', 'AddWithID'),
+                args=[ _refptrTake(_refptrForget(rawvar)), idvar ])),
+            Whitespace.NL,
             StmtReturn(_Result.Processed)
         ])
-        ifstmt.addifstmt(StmtReturn(_Result.PayloadError))
 
         return case
 
     def genShmemDestroyedHandler(self):
         p = self.protocol
         assert p.decl.type.isToplevel()
 
         case = StmtBlock()
 
-        ifstmt = StmtIf(ExprNot(ExprCall(ExprVar('ShmemDestroyed'), args=[self.msgvar])))
+        rawvar = ExprVar('rawmem')
+        idvar = ExprVar('id')
+        itervar = ExprVar('iter')
+        case.addstmts([
+            StmtDecl(Decl(_shmemIdType(), idvar.name)),
+            StmtDecl(Decl(_iterType(ptr=0), itervar.name), init=ExprCall(ExprVar('PickleIterator'),
+                                                                         args=[ self.msgvar ]))
+        ])
+
+        failif = StmtIf(ExprNot(
+            ExprCall(ExprVar('IPC::ReadParam'),
+                     args=[ ExprAddrOf(self.msgvar), ExprAddrOf(itervar),
+                            ExprAddrOf(idvar) ])))
+        failif.addifstmt(StmtReturn(_Result.PayloadError))
+
         case.addstmts([
-            ifstmt,
+            failif,
+            StmtExpr(ExprCall(ExprSelect(self.msgvar, '.', 'EndRead'),
+                              args=[ itervar ])),
+            Whitespace.NL,
+            StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name),
+                     init=ExprCall(p.lookupSharedMemory(), args=[ idvar ]))
+        ])
+
+        # Here we don't return an error if we failed to look the shmem up. This
+        # is because we don't have a way to know if it is because we failed to
+        # map the shmem or if the id is wrong. In the latter case it would be
+        # better to catch the error but the former case is legit...
+        lookupif = StmtIf(rawvar)
+        lookupif.addifstmt(StmtExpr(p.removeShmemId(idvar)))
+        lookupif.addifstmt(StmtExpr(_shmemDealloc(rawvar)))
+
+        case.addstmts([
+            lookupif,
             StmtReturn(_Result.Processed)
         ])
-        ifstmt.addifstmt(StmtReturn(_Result.PayloadError))
 
         return case
 
 
     def makeChannelOpenedHandlers(self, actors):
         handlers = StmtBlock()
 
         # unpack the transport descriptor et al.
@@ -4099,20 +4834,20 @@ class _GenerateProtocolActorCode(ipdl.as
             idexpr = ExprCall(self.protocol.registerMethod(),
                               args=[ actorvar ])
         else:
             idexpr = ExprCall(self.protocol.registerIDMethod(),
                               args=[ actorvar, idexpr ])
 
         return [
             self.failIfNullActor(actorvar, errfn, msg="Error constructing actor %s" % actortype.name() + self.side.capitalize()),
-            StmtExpr(ExprCall(ExprSelect(actorvar, '->', 'SetId'), args=[idexpr])),
-            StmtExpr(ExprCall(ExprSelect(actorvar, '->', 'SetManager'), args=[ExprVar.THIS])),
-            StmtExpr(ExprCall(ExprSelect(actorvar, '->', 'SetIPCChannel'),
-                              args=[self.protocol.callGetChannel()])),
+            StmtExpr(ExprAssn(_actorId(actorvar), idexpr)),
+            StmtExpr(ExprAssn(_actorManager(actorvar), ExprVar.THIS)),
+            StmtExpr(ExprAssn(_actorChannel(actorvar),
+                              self.protocol.channelForSubactor())),
             StmtExpr(_callInsertManagedActor(
                 self.protocol.managedVar(md.decl.type.constructedType(),
                                          self.side),
                 actorvar)),
             StmtExpr(ExprAssn(_actorState(actorvar),
                               _startState(actorproto, fq=1)))
         ]
 
@@ -4351,20 +5086,20 @@ class _GenerateProtocolActorCode(ipdl.as
 
     def failIfNullActor(self, actorExpr, retOnNull=ExprLiteral.FALSE, msg=None):
         failif = StmtIf(ExprNot(actorExpr))
         if msg:
             failif.addifstmt(_printWarningMessage(msg))
         failif.addifstmt(StmtReturn(retOnNull))
         return failif
 
-    def unregisterActor(self):
-        return [ StmtExpr(ExprCall(self.protocol.unregisterMethod(),
-                                   args=[ _actorId() ])),
-                 StmtExpr(ExprCall(ExprVar('SetId'), args=[_FREED_ACTOR_ID])) ]
+    def unregisterActor(self, actorexpr=None):
+        return [ StmtExpr(ExprCall(self.protocol.unregisterMethod(actorexpr),
+                                   args=[ _actorId(actorexpr) ])),
+                 StmtExpr(ExprAssn(_actorId(actorexpr), _FREED_ACTOR_ID)) ]
 
     def makeMessage(self, md, errfn, fromActor=None):
         msgvar = self.msgvar
         routingId = self.protocol.routingId(fromActor)
         this = None
         if md.decl.type.isDtor():  this = md.actorDecl().var()
 
         stmts = ([ StmtDecl(Decl(Type('IPC::Message', ptr=1), msgvar.name),
@@ -4526,35 +5261,35 @@ class _GenerateProtocolActorCode(ipdl.as
             sendok,
             ([ Whitespace.NL,
                self.logMessage(md, msgexpr, 'Sending ', actor),
                self.profilerLabel(md) ]
             + self.transition(md, 'out', actor)
             + [ Whitespace.NL,
                 StmtDecl(Decl(Type.BOOL, sendok.name),
                          init=ExprCall(
-                             ExprSelect(self.protocol.callGetChannel(actor),
-                                        '->', 'Send'),
+                             ExprSelect(self.protocol.channelVar(actor),
+                                        self.protocol.channelSel(), 'Send'),
                              args=[ msgexpr ]))
             ])
         )
 
     def sendBlocking(self, md, msgexpr, replyexpr, actor=None):
         sendok = ExprVar('sendok__')
         return (
             sendok,
             ([ Whitespace.NL,
                self.logMessage(md, msgexpr, 'Sending ', actor),
                self.profilerLabel(md) ]
             + self.transition(md, 'out', actor)
             + [ Whitespace.NL,
                 StmtDecl(
                     Decl(Type.BOOL, sendok.name),
-                    init=ExprCall(ExprSelect(self.protocol.callGetChannel(actor),
-                                             '->',
+                    init=ExprCall(ExprSelect(self.protocol.channelVar(actor),
+                                             self.protocol.channelSel(),
                                              _sendPrefix(md.decl.type)),
                                   args=[ msgexpr, ExprAddrOf(replyexpr) ]))
             ])
         )
 
     def callAllocActor(self, md, retsems, side):
         return ExprCall(
             _allocMethod(md.decl.type.constructedType(), side),
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -15,17 +15,18 @@
 #include "js/Proxy.h"
 
 namespace mozilla {
 namespace jsipc {
 
 class WrapperOwner : public virtual JavaScriptShared
 {
   public:
-    typedef mozilla::ipc::IProtocol::ActorDestroyReason
+    typedef mozilla::ipc::IProtocolManager<
+                       mozilla::ipc::IProtocol>::ActorDestroyReason
            ActorDestroyReason;
 
     WrapperOwner();
     bool init();
 
     // Standard internal methods.
     // (The traps should be in the same order like js/Proxy.h)
     bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
--- a/netwerk/cookie/CookieServiceParent.cpp
+++ b/netwerk/cookie/CookieServiceParent.cpp
@@ -147,11 +147,23 @@ CookieServiceParent::RecvSetCookieString
   // NB: dummyChannel could be null if something failed in CreateDummyChannel.
   nsDependentCString cookieString(aCookieString, 0);
   mCookieService->SetCookieStringInternal(hostURI, aIsForeign, cookieString,
                                           aServerTime, aFromHttp, aAttrs,
                                           isPrivate, dummyChannel);
   return true;
 }
 
+mozilla::ipc::IProtocol*
+CookieServiceParent::CloneProtocol(Channel* aChannel,
+                                   mozilla::ipc::ProtocolCloneContext* aCtx)
+{
+  NeckoParent* manager = aCtx->GetNeckoParent();
+  nsAutoPtr<PCookieServiceParent> actor(manager->AllocPCookieServiceParent());
+  if (!actor || !manager->RecvPCookieServiceConstructor(actor)) {
+    return nullptr;
+  }
+  return actor.forget();
+}
+
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/cookie/CookieServiceParent.h
+++ b/netwerk/cookie/CookieServiceParent.h
@@ -31,16 +31,20 @@ protected:
 
   virtual bool RecvSetCookieString(const URIParams& aHost,
                                    const bool& aIsForeign,
                                    const nsCString& aCookieString,
                                    const nsCString& aServerTime,
                                    const bool& aFromHttp,
                                    const NeckoOriginAttributes& aAttrs) override;
 
+  virtual mozilla::ipc::IProtocol*
+  CloneProtocol(Channel* aChannel,
+                mozilla::ipc::ProtocolCloneContext* aCtx) override;
+
   RefPtr<nsCookieService> mCookieService;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_CookieServiceParent_h
 
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -740,16 +740,28 @@ NeckoParent::AllocPTransportProviderPare
 bool
 NeckoParent::DeallocPTransportProviderParent(PTransportProviderParent* aActor)
 {
   RefPtr<TransportProviderParent> provider =
     dont_AddRef(static_cast<TransportProviderParent*>(aActor));
   return true;
 }
 
+mozilla::ipc::IProtocol*
+NeckoParent::CloneProtocol(Channel* aChannel,
+                           mozilla::ipc::ProtocolCloneContext* aCtx)
+{
+  ContentParent* contentParent = aCtx->GetContentParent();
+  nsAutoPtr<PNeckoParent> actor(contentParent->AllocPNeckoParent());
+  if (!actor || !contentParent->RecvPNeckoConstructor(actor)) {
+    return nullptr;
+  }
+  return actor.forget();
+}
+
 namespace {
 std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> >&
 CallbackMap()
 {
   MOZ_ASSERT(NS_IsMainThread());
   static std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> > sCallbackMap;
   return sCallbackMap;
 }
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -162,16 +162,20 @@ protected:
                                    const uint16_t& flags) override;
   virtual bool RecvCancelHTMLDNSPrefetch(const nsString& hostname,
                                          const uint16_t& flags,
                                          const nsresult& reason) override;
   virtual PWebSocketEventListenerParent*
     AllocPWebSocketEventListenerParent(const uint64_t& aInnerWindowID) override;
   virtual bool DeallocPWebSocketEventListenerParent(PWebSocketEventListenerParent*) override;
 
+  virtual mozilla::ipc::IProtocol*
+  CloneProtocol(Channel* aChannel,
+                mozilla::ipc::ProtocolCloneContext* aCtx) override;
+
   virtual PDataChannelParent*
     AllocPDataChannelParent(const uint32_t& channelId) override;
   virtual bool DeallocPDataChannelParent(PDataChannelParent* parent) override;
 
   virtual bool RecvPDataChannelConstructor(PDataChannelParent* aActor,
                                            const uint32_t& channelId) override;
 
   virtual PRtspControllerParent* AllocPRtspControllerParent() override;