add initial support for protocol management in IPDL. small changes to existing protocols in preparation for merge from libchromiumipc.
authorChris Jones <jones.chris.g@gmail.com>
Thu, 02 Jul 2009 00:45:19 -0500
changeset 35744 768081a8a21175c0a2cae6313cc2fc914e413f9b
parent 35743 2514fa68b1784bd1d9c94b47663c787237afda0e
child 35745 11c34494c1f3a364a9250c85e9d82639c29bf0d9
push idunknown
push userunknown
push dateunknown
milestone1.9.2a1pre
add initial support for protocol management in IPDL. small changes to existing protocols in preparation for merge from libchromiumipc.
dom/ipc/IFrameEmbeddingProtocolChild.h
dom/ipc/IFrameEmbeddingProtocolParent.h
dom/plugins/NPAPI.ipdl
dom/plugins/NPAPIProtocolChild.h
dom/plugins/NPAPIProtocolParent.h
dom/plugins/NPP.ipdl
dom/plugins/NPPProtocolChild.h
dom/plugins/NPPProtocolParent.h
ipc/glue/IPCMessageUtils.h
ipc/glue/Makefile.in
ipc/glue/ProtocolUtils.h
ipc/glue/RPCChannel.cpp
ipc/glue/RPCChannel.h
ipc/ipdl/Makefile
ipc/ipdl/ipdl/builtin.py
ipc/ipdl/ipdl/cxx/ast.py
ipc/ipdl/ipdl/cxx/cgen.py
ipc/ipdl/ipdl/lower.py
ipc/ipdl/ipdl/type.py
--- a/dom/ipc/IFrameEmbeddingProtocolChild.h
+++ b/dom/ipc/IFrameEmbeddingProtocolChild.h
@@ -23,43 +23,43 @@ public:
         return mRpc.Open(aChannel, aIOLoop);
     }
 
     void Close()
     {
         mRpc.Close();
     }
 
-    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    virtual Result OnCallReceived(const Message& msg, Message*& reply)
     {
         switch (msg.type()) {
         case IFrameEmbedding_ParentToChildMsg_init__ID: {
             MagicWindowHandle parentWidget;
             MagicWindowHandle p;
             IFrameEmbedding_ParentToChildMsg_init::Read(&msg, &p);
 
             parentWidget = p;
 
             nsresult _rv = mChild->init(
                 parentWidget);
-            *reply = new IFrameEmbedding_ChildToParentMsg_Reply_init();
-            (*reply)->set_reply();
+            reply = new IFrameEmbedding_ChildToParentMsg_Reply_init();
+            reply->set_reply();
             return MsgProcessed;
         }
         case IFrameEmbedding_ParentToChildMsg_loadURL__ID: {
             String uri;
             String p;
             IFrameEmbedding_ParentToChildMsg_loadURL::Read(&msg, &p);
 
             uri = p;
 
             nsresult _rv = mChild->loadURL(
                 uri);
-            *reply = new IFrameEmbedding_ChildToParentMsg_Reply_loadURL();
-            (*reply)->set_reply();
+            reply = new IFrameEmbedding_ChildToParentMsg_Reply_loadURL();
+            reply->set_reply();
             return MsgProcessed;
         }
         case IFrameEmbedding_ParentToChildMsg_move__ID: {
             uint32_t x;
             uint32_t y;
             uint32_t width;
             uint32_t height;
             IFrameEmbedding_ParentToChildMsg_move::Param p;
@@ -67,18 +67,18 @@ public:
 
             x = p.a;
             y = p.b;
             width = p.c;
             height = p.d;
 
             nsresult _rv = mChild->move(
                 x, y, width, height);
-            *reply = new IFrameEmbedding_ChildToParentMsg_Reply_move();
-            (*reply)->set_reply();
+            reply = new IFrameEmbedding_ChildToParentMsg_Reply_move();
+            reply->set_reply();
             return MsgProcessed;
         }
         default: {
             return MsgNotKnown;
         }
         }
     }
 
--- a/dom/ipc/IFrameEmbeddingProtocolParent.h
+++ b/dom/ipc/IFrameEmbeddingProtocolParent.h
@@ -62,17 +62,17 @@ public:
             x, y, width, height)
             , &reply);
 
         if (NS_OK == _rv) {
         }
         return _rv;
     }
 
-    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    virtual Result OnCallReceived(const Message& msg, Message*& reply)
     {
         switch (msg.type()) {
         default: {
             return MsgNotKnown;
         }
         }
     }
 
new file mode 100644
--- /dev/null
+++ b/dom/plugins/NPAPI.ipdl
@@ -0,0 +1,30 @@
+include "npapi.h";
+
+include protocol "NPP.ipdl";
+//include protocol "NPObject.ipdl";
+
+using NPError;
+
+namespace mozilla {
+namespace plugins {
+
+rpc protocol NPAPI
+{
+    manages NPP;
+//    manages NPObject;
+
+    rpc out NP_Initialize() returns (NPError rv);
+
+
+    rpc out NPP(String aMimeType,
+                int aHandle,
+                uint16_t aMode,
+                StringArray aNames,
+                StringArray aValues) returns (NPError rv);
+    rpc out ~NPP() returns (NPError rv);
+
+//    rpc in TradeNPPsForSomeReason(NPP n) returns (NPP n2);
+};
+
+} // namespace plugins
+} // namespace mozilla
--- a/dom/plugins/NPAPIProtocolChild.h
+++ b/dom/plugins/NPAPIProtocolChild.h
@@ -111,25 +111,25 @@ public:
     virtual void NPN_GetValue(/*...*/)
     {
         _MSG_LOG("outcall NPN_GetValue()");
         // mRpc->Send(...);
     }
     // ...
 
     // Implement the RPCChannel::Listener interface
-    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    virtual Result OnCallReceived(const Message& msg, Message*& reply)
     {
         switch(msg.type()) {
         case NPAPI_ParentToChildMsg_NP_Initialize__ID: {
             _MSG_LOG("incall NP_Initialize()");
 
             NPError val0 = mChild->NP_Initialize();
-            *reply = new NPAPI_ChildToParentMsg_Reply_NP_Initialize(val0);
-            (*reply)->set_reply();
+            reply = new NPAPI_ChildToParentMsg_Reply_NP_Initialize(val0);
+            reply->set_reply();
             return MsgProcessed;
         }
 
         case NPAPI_ParentToChildMsg_NPP_New__ID: {
             mozilla::ipc::String aMimeType;
             int aHandle;
             uint16_t aMode;
             mozilla::ipc::StringArray aNames;
@@ -147,18 +147,18 @@ public:
             _MSG_LOG("incall NPP_New(%s, %d, %d, <vec>, <vec>)",
                      aMimeType.c_str(), aHandle, aMode);
 
             NPError val0 = mChild->NPP_New(aMimeType,
                                            aHandle,
                                            aMode,
                                            aNames,
                                            aValues);
-            *reply = new NPAPI_ChildToParentMsg_Reply_NPP_New(val0);
-            (*reply)->set_reply();
+            reply = new NPAPI_ChildToParentMsg_Reply_NPP_New(val0);
+            reply->set_reply();
             return MsgProcessed;
         }
 
         default:
             // FIXME/cjones: HACK ALERT! use routing, do checks, etc.
             return HACK_npp->OnCallReceived(msg, reply);
             
             
--- a/dom/plugins/NPAPIProtocolParent.h
+++ b/dom/plugins/NPAPIProtocolParent.h
@@ -160,17 +160,17 @@ public:
 
     virtual void NPP_Destroy()
     {
         _MSG_LOG("outcall NPP_New()");
     }
     // ...
 
     // Implement the RPCChannel::Listener interface
-    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    virtual Result OnCallReceived(const Message& msg, Message*& reply)
     {
         switch(msg.type()) {
         default:
             // FIXME/cjones: HACK ALERT! use routing, do checks, etc.
             return HACK_npp->OnCallReceived(msg, reply);
 
 
 //            return MsgNotKnown;
new file mode 100644
--- /dev/null
+++ b/dom/plugins/NPP.ipdl
@@ -0,0 +1,25 @@
+include protocol "NPAPI.ipdl";
+//include protocol "NPStream.ipdl";
+
+include "PluginMessageUtils.h";
+
+using NPError;
+using NPWindow;
+
+namespace mozilla {
+namespace plugins {
+
+rpc protocol NPP
+{
+    manager NPAPI;
+
+    // manages NPStream;
+
+    rpc out NPP_SetWindow(NPWindow window) returns (NPError rv);
+
+    rpc out NPP_GetValue(String key) returns (String value);
+    rpc in NPN_GetValue(String key) returns (String value);
+};
+
+} // namespace plugins
+} // namespace mozilla
--- a/dom/plugins/NPPProtocolChild.h
+++ b/dom/plugins/NPPProtocolChild.h
@@ -112,17 +112,17 @@ public:
                    &reply);
         NS_ASSERTION(NPP_ParentToChildMsg_Reply_NPN_GetValue__ID
                      == reply.type(),
                      "wrong reply msg to NPN_GetValue()");
         // nothing to unpack
         return;
     }
 
-    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    virtual Result OnCallReceived(const Message& msg, Message*& reply)
     {
         switch(msg.type()) {
         case NPP_ParentToChildMsg_NPP_SetWindow__ID: {
             XID aWindow;
             int32_t aWidth;
             int32_t aHeight;
 
             NPP_ParentToChildMsg_NPP_SetWindow::Param p;
@@ -131,18 +131,18 @@ public:
             aWindow = p.a;
             aWidth = p.b;
             aHeight = p.c;
 
             _MSG_LOG("incall NPP_SetWindow(%lx, %d, %d)\n",
                      aWindow, aWidth, aHeight);
 
             NPError val0 = mChild->NPP_SetWindow(aWindow, aWidth, aHeight);
-            *reply = new NPP_ChildToParentMsg_Reply_NPP_SetWindow(val0);
-            (*reply)->set_reply();
+            reply = new NPP_ChildToParentMsg_Reply_NPP_SetWindow(val0);
+            reply->set_reply();
             return MsgProcessed;
         }
 
         default:
             return MsgNotKnown;
         }
     }
 
--- a/dom/plugins/NPPProtocolParent.h
+++ b/dom/plugins/NPPProtocolParent.h
@@ -123,26 +123,26 @@ public:
         NPError ret0;
         NS_ASSERTION(NPP_ChildToParentMsg_Reply_NPP_SetWindow
                      ::Read(&reply, &ret0),
                      "bad types in reply msg to NPP_SetWindow()");
 
         return ret0;
     }
 
-    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    virtual Result OnCallReceived(const Message& msg, Message*& reply)
     {
         switch(msg.type()) {
         case NPP_ChildToParentMsg_NPN_GetValue__ID: {
             _MSG_LOG("incall NPN_GetValue()");
 
             // nothing to unpack
             mParent->NPN_GetValue();
 
-            *reply = new NPP_ParentToChildMsg_Reply_NPN_GetValue();
+            reply = new NPP_ParentToChildMsg_Reply_NPN_GetValue();
             return MsgProcessed;
         }
 
         default:
             return MsgNotKnown;
         }
     }
 
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -41,16 +41,19 @@
 
 #include "prtypes.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 // Used by chrome code, we override this here and #ifdef theirs out. See the
 // comments in chrome/common/ipc_message_utils.h for info about this enum.
 enum IPCMessageStart {
+  //NPAPIProtocolMsgStart = 0,
+  //NPPProtocolMsgStart = 0,
+  // FIXME/cjones: blow these away when plugin fixes are merged
   NPAPI_ParentToChildMsgStart = 0,
   NPAPI_ChildToParentMsgStart,
   NPP_ParentToChildMsgStart,
   NPP_ChildToParentMsgStart,
   NPObject_ParentToChildMsgStart,
   NPObject_ChildToParentMsgStart,
 
   IFrameEmbedding_ParentToChildMsgStart,
--- a/ipc/glue/Makefile.in
+++ b/ipc/glue/Makefile.in
@@ -53,16 +53,17 @@ EXPORTS_IPC =					\
   IPCMessageUtils.h 				\
   $(NULL)
 
 # FIXME/cjones: "ChromeThread" is a misnomer
 EXPORTS_mozilla/ipc =				\
   GeckoChildProcessHost.h			\
   GeckoThread.h 				\
   MessageTypes.h 				\
+  ProtocolUtils.h				\
   RPCChannel.h					\
   ScopedXREEmbed.h				\
   $(NULL)
 
 ENABLE_CXX_EXCEPTIONS = 1
 DEFINES += -DNO_NSPR_10_SUPPORT=1
 
 REQUIRES += \
new file mode 100644
--- /dev/null
+++ b/ipc/glue/ProtocolUtils.h
@@ -0,0 +1,103 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ *   Chris Jones <jones.chris.g@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_ipc_ProtocolUtils_h
+#define mozilla_ipc_ProtocolUtils_h 1
+
+#include "chrome/common/ipc_message_utils.h"
+
+#include "mozilla/ipc/RPCChannel.h"
+
+namespace mozilla {
+namespace ipc {
+
+
+// Used to pass references to protocol actors across the wire.  An actor
+// has a parent-side "routing ID" and another routing ID on the child side.
+struct ActorHandle
+{
+    int mParentId;
+    int mChildId;
+};
+
+
+class /*NS_INTERFACE_CLASS*/ IProtocolManager
+{
+public:
+    virtual int32 Register(RPCChannel::Listener*) = 0;
+    RPCChannel::Listener* Lookup(int32) = 0;
+    virtual void Unregister(int32) = 0;
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::ipc::ActorHandle>
+{
+  typedef mozilla::ipc::ActorHandle paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    IPC::WriteParam(aMsg, aParam.mParentId);
+    IPC::WriteParam(aMsg, aParam.mChildId);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    int parentId, childId;
+    if (IPC::ReadParam(aMsg, aIter, &parentId)
+        && ReadParam(aMsg, aIter, &childId)) {
+      aResult->mParentId = parentId;
+      aResult->mChildId = childId;
+      return true;
+    }
+    return false;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    aLog->append(StringPrintf(L"(%d,%d)", aParam.mParentId, aParam.mChildId));
+  }
+};
+
+} // namespace IPC
+
+
+#endif  // mozilla_ipc_ProtocolUtils_h
--- a/ipc/glue/RPCChannel.cpp
+++ b/ipc/glue/RPCChannel.cpp
@@ -31,18 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/ipc/RPCChannel.h"
 #include "mozilla/ipc/GeckoThread.h"
-#include "mozilla/ipc/RPCChannel.h"
 
 #include "nsDebug.h"
 
 using mozilla::MutexAutoLock;
 
 template<>
 struct RunnableMethodTraits<mozilla::ipc::RPCChannel>
 {
@@ -94,16 +94,18 @@ RPCChannel::Close()
     // FIXME impl
 
     mChannelState = ChannelClosed;
 }
 
 bool
 RPCChannel::Call(Message* msg, Message* reply)
 {
+    NS_PRECONDITION(MSG_ROUTING_NONE != msg->routing_id(), "need a route");
+
     mMutex.Lock();
 
     mPending.push(*msg);
     mIOLoop->PostTask(FROM_HERE, NewRunnableMethod(this,
                                                    &RPCChannel::SendCall,
                                                    msg));
     while (1) {
         // here we're waiting for something to happen.  it may either
@@ -140,26 +142,29 @@ RPCChannel::Call(Message* msg, Message* 
     return true;
 }
 
 bool
 RPCChannel::ProcessIncomingCall(Message call)
 {
    Message* reply;
 
-    switch (mListener->OnCallReceived(call, &reply)) {
+    switch (mListener->OnCallReceived(call, reply)) {
     case Listener::MsgProcessed:
         mIOLoop->PostTask(FROM_HERE,
                           NewRunnableMethod(this,
                                             &RPCChannel::SendReply,
                                             reply));
         return true;
 
     case Listener::MsgNotKnown:
     case Listener::MsgNotAllowed:
+    case Listener::MsgPayloadError:
+    case Listener::MsgRouteError:
+    case Listener::MsgValueError:
         //OnError()?
         return false;
 
     default:
         NOTREACHED();
         return false;
     }
 }
@@ -190,17 +195,17 @@ RPCChannel::OnMessageReceived(const Mess
     else {
         // let the worker know something new has happened
         mPending.push(msg);
         mCvar.Notify();
     }
 }
 
 void
-RPCChannel::OnChannelConnected(int peer_pid)
+RPCChannel::OnChannelConnected(int32 peer_pid)
 {
     mChannelState = ChannelConnected;
 }
 
 void
 RPCChannel::OnChannelError()
 {
     // FIXME/cjones impl
--- a/ipc/glue/RPCChannel.h
+++ b/ipc/glue/RPCChannel.h
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef ipc_glue_RPCChannel_h
 #define ipc_glue_RPCChannel_h 1
 
 // FIXME/cjones probably shouldn't depend on this
 #include <stack>
 
+#include "base/basictypes.h"
 #include "base/message_loop.h"
 #include "chrome/common/ipc_channel.h"
 
 #include "mozilla/CondVar.h"
 #include "mozilla/Mutex.h"
 
 namespace mozilla {
 namespace ipc {
@@ -68,27 +69,27 @@ private:
 public:
     typedef IPC::Channel Transport;
     typedef IPC::Message Message;
 
     class Listener
     {
     public:
         enum Result {
-            // We processed the message, and it can be forgotten
             MsgProcessed,
-            // We haven't heard of this message type
             MsgNotKnown,
-            // We weren't in a state to receive this message
-            MsgNotAllowed
+            MsgNotAllowed,
+            MsgPayloadError,
+            MsgRouteError,
+            MsgValueError,
         };
 
         virtual ~Listener() { }
         virtual Result OnCallReceived(const Message& aMessage,
-                                      Message** aReply) = 0;
+                                      Message*& aReply) = 0;
     };
 
     /**
      * Convert the asynchronous channel |aChannel| into a channel with
      * RPC semantics.  Received messages are passed down to
      * |aListener|.
      *
      * FIXME do away with |aMode|
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/Makefile
@@ -0,0 +1,5 @@
+.PHONY: clean
+
+clean: 
+	rm -f *~ *.h
+	make -C ipdl clean
--- a/ipc/ipdl/ipdl/builtin.py
+++ b/ipc/ipdl/ipdl/builtin.py
@@ -60,9 +60,10 @@ Types = (
     'mozilla::ipc::StringArray',
 )
 
 
 Includes = (
     'nscore.h',
     'IPC/IPCMessageUtils.h',
     'mozilla/ipc/MessageTypes.h',
+    'mozilla/ipc/ProtocolUtils.h',
 )
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -102,16 +102,20 @@ class Visitor:
         self.visitBlock(dd)
 
     def visitExprVar(self, v):
         pass
 
     def visitExprPrefixUnop(self, e):
         e.expr.accept(self)
 
+    def visitExprBinary(self, e):
+        e.left.accept(self)
+        e.right.accept(self)
+
     def visitExprAddrOf(self, eao):
         self.visitExprPrefixUnop(eao)
 
     def visitExprDeref(self, ed):
         self.visitExprPrefixUnop(ed)
 
     def visitExprSelect(self, es):
         es.obj.accept(self)
@@ -252,31 +256,39 @@ class Decl(Node):
         self.name = name
     def __deepcopy__(self, memo):
         return Decl(copy.deepcopy(self.type, memo), self.name)
 
 ##------------------------------
 # class stuff
 class Class(Block):
     def __init__(self, name, inherits=[ ],
-                 interface=False, final=False):
+                 interface=False, abstract=False, final=False):
+        assert not (interface and abstract)
+        assert not (abstract and final)
         assert not (interface and final)
 
         Block.__init__(self)
         self.name = name
         self.inherits = inherits # array of (viz, Type) pairs
         self.interface = interface
+        self.abstract = abstract
         self.final = final
 
 class Inherit(Node):
     def __init__(self, name, viz='public'):
         Node.__init__(self)
         self.name = name
         self.viz = viz
 
+class FriendClassDecl(Node):
+    def __init__(self, friend):
+        Node.__init__(self)
+        self.friend = friend
+
 class MethodDecl(Node):
     def __init__(self, name, params=[ ], ret=Type('void'),
                  virtual=False, const=False, pure=False, static=False):
         assert not (virtual and static)
         assert not pure or virtual # pure => virtual
 
         Node.__init__(self)
         self.name = name
@@ -312,16 +324,26 @@ class DestructorDecl(MethodDecl):
     def __init__(self, name, virtual=False):
         MethodDecl.__init__(self, name, params=[ ], ret=None,
                             virtual=virtual)
 class DestructorDefn(MethodDefn):
     def __init__(self, decl):  MethodDefn.__init__(self, decl)
 
 ##------------------------------
 # expressions
+class ExprLiteral(Node):
+    def __init__(self, value, type):
+        '''|type| is a Python format specifier; 'd' for example'''
+        Node.__init__(self)
+        self.value = value
+        self.type = type
+    def __str__(self):
+        return ('%'+ self.type)% (self.value)
+ExprLiteral.ZERO = ExprLiteral(0, 'd')
+
 class ExprVar(Node):
     def __init__(self, name):
         Node.__init__(self)
         self.name = name
 
 class ExprPrefixUnop(Node):
     def __init__(self, expr, op):
         self.expr = expr
@@ -330,16 +352,36 @@ class ExprPrefixUnop(Node):
 class ExprAddrOf(ExprPrefixUnop):
     def __init__(self, expr):
         ExprPrefixUnop.__init__(self, expr, '&')
 
 class ExprDeref(ExprPrefixUnop):
     def __init__(self, expr):
         ExprPrefixUnop.__init__(self, expr, '*')
 
+class ExprCast(Node):
+    def __init__(self, expr, type,
+                 dynamic=0, static=0, reinterpret=0, const=0, C=0):
+        assert 1 == reduce(lambda a, x: a+x, [ dynamic, static, reinterpret, const, C ])
+
+        Node.__init__(self)
+        self.expr = expr
+        self.type = type
+        self.dynamic = dynamic
+        self.static = static
+        self.reinterpret = reinterpret
+        self.const = const
+        self.C = C
+
+class ExprBinary(Node):
+    def __init__(self, left, op, right):
+        self.left = left
+        self.op = op
+        self.right = right
+
 class ExprSelect(Node):
     def __init__(self, obj, op, field):
         Node.__init__(self)
         self.obj = obj
         self.op = op
         self.field = field
 
 class ExprAssn(Node):
--- a/ipc/ipdl/ipdl/cxx/cgen.py
+++ b/ipc/ipdl/ipdl/cxx/cgen.py
@@ -92,18 +92,21 @@ class CxxCodeGen(CodePrinter, Visitor):
         if d.name:
             self.write(' '+ d.name)
 
     def visitClass(self, c):
         self.printdent('class')
         if c.interface:
             # FIXME/cjones: turn this "on" when we get the analysis
             self.write(' /*NS_INTERFACE_CLASS*/')
+        if c.abstract:
+            # FIXME/cjones: turn this "on" when we get the analysis
+            self.write(' /*NS_ABSTRACT_CLASS*/')
         if c.final:
-            self.write(' /*NS_FINAL_CLASS*/')
+            self.write(' NS_FINAL_CLASS')
         self.write(' '+ c.name)
 
         ninh = len(c.inherits)
         if 0 < ninh:
             self.println(' :')
             self.indent()
             for i, inherit in enumerate(c.inherits):
                 self.printdent()
@@ -119,16 +122,18 @@ class CxxCodeGen(CodePrinter, Visitor):
         self.visitBlock(c)
 
         self.dedent()
         self.printdentln('};')
 
     def visitInherit(self, inh):
         self.write(inh.viz +' '+ inh.name)
 
+    def visitFriendClassDecl(self, fcd):
+        self.printdentln('friend class '+ fcd.friend +';')
 
     def visitMethodDecl(self, md):
         assert not (md.static and md.virtual)
         if md.static:
             self.write('static ')
         if md.virtual:
             self.write('virtual ')
         if md.ret:
@@ -196,25 +201,48 @@ class CxxCodeGen(CodePrinter, Visitor):
         self.indent()
 
         self.visitBlock(dd)
 
         self.dedent()
         self.printdentln('}')
 
 
+    def visitExprLiteral(self, el):
+        self.write(str(el))
+
     def visitExprVar(self, ev):
         self.write(ev.name)
 
     def visitExprPrefixUnop(self, e):
         self.write(e.op)
         self.write('(')
         e.expr.accept(self)
         self.write(')')
 
+    def visitExprCast(self, c):
+        pfx, sfx = '', ''
+        if c.dynamic:        pfx, sfx = 'dynamic_cast<', '>'
+        elif c.static:       pfx, sfx = 'static_cast<', '>'
+        elif c.reinterpret:  pfx, sfx = 'reinterpret_cast<', '>'
+        elif c.const:        pfx, sfx = 'const_cast<', '>'
+        elif c.C:            pfx, sfx = '(', ')'
+        self.write(pfx)
+        c.type.accept(self)
+        self.write(sfx +'(')
+        c.expr.accept(self)
+        self.write(')')
+
+    def visitExprBinary(self, e):
+        self.write('(')
+        e.left.accept(self)
+        self.write(') '+ e.op +' (')
+        e.right.accept(self)
+        self.write(')')
+
     def visitExprSelect(self, es):
         es.obj.accept(self)
         self.write(es.op + es.field)
 
     def visitExprAssn(self, ea):
         ea.lhs.accept(self)
         self.write(' = ')
         ea.rhs.accept(self)
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -52,27 +52,28 @@ def _protocolHeaderName(pname):
 
 class _struct: pass
 
 class LowerToCxx:
     def lower(self, tu):
         '''returns a list of cxx.File representing the lowered form of |tu|'''
         pname = _protocolHeaderName(tu.protocol.name)
         pheader = cxx.File(pname +'.h')
-        GenerateProtocolHeader().lower(tu, pname, pheader)
+        gph = GenerateProtocolHeader()
+        gph.lower(tu, pname, pheader)
 
         parentname = pname +'Parent'
         parentheader = cxx.File(parentname +'.h')
         GenerateProtocolParentHeader().lower(
-            tu, pname, parentname, parentheader)
+            tu, pname, parentname, parentheader, gph.typedefs)
 
         childname = pname +'Child'
         childheader = cxx.File(childname +'.h')
         GenerateProtocolChildHeader().lower(
-            tu, pname, childname, childheader)
+            tu, pname, childname, childheader, gph.typedefs)
 
         return pheader, parentheader, childheader
 
 
 ##-----------------------------------------------------------------------------
 class GenerateProtocolHeader(Visitor):
     '''creates a "generic" protocol header from an IPDL AST'''
     def __init__(self):
@@ -159,36 +160,16 @@ class GenerateProtocolHeader(Visitor):
         ns.addstmt(cxx.Whitespace.NL)
         ns.addstmt(cxx.Whitespace.NL)
 
         # previsit the messages and stash away some common info used
         # several times later
         for md in p.messageDecls:
             md.accept(self)
 
-        # generate parent and child interfaces
-        iparent = cxx.Class('IParent', interface=True)
-        iparent.addstmt(cxx.Label('protected'))
-        self.injectTypedefs(iparent)
-        iparent.addstmt(cxx.Whitespace.NL)
-
-        p.accept(GenerateParentInterface(iparent))
-        ns.addstmt(iparent)
-        ns.addstmt(cxx.Whitespace.NL)
-
-        ns.addstmt(cxx.Whitespace.NL)
-        ichild = cxx.Class('IChild', interface=True)
-        ichild.addstmt(cxx.Label('protected'))
-        self.injectTypedefs(ichild)
-        ichild.addstmt(cxx.Whitespace.NL)
-
-        p.accept(GenerateChildInterface(ichild))
-        ns.addstmt(ichild)
-        ns.addstmt(cxx.Whitespace.NL)
-
         # TODO
         for ts in p.transitionStmts:
             ts.accept(self)
         ns.addstmt(cxx.StmtDecl(cxx.Decl(cxx.TypeEnum('State'), '')))
         ns.addstmt(cxx.Whitespace.NL)
 
         # spit out message type enum and classes
         msgstart = self.pname +'MsgStart << 12'
@@ -246,70 +227,17 @@ class GenerateProtocolHeader(Visitor):
         # the ID is used by the IPC layer only
         md._cxx.id = 'Msg_%s'% (md.decl.progname)
         md._cxx.nsid = '%s::%s'% (self.pname, md._cxx.id)
         if md.decl.type.hasReply():
             md._cxx.replyid = 'Reply_%s'% (md.decl.progname)
             md._cxx.nsreplyid = '%s::%s'% (self.pname, md._cxx.replyid)
 
 
-class GenerateInterface(Visitor):
-    def __init__(self, iface, name):
-        self.iface = iface
-        self.name = name
-
-    def visitProtocol(self, p):
-        ifc = self.iface
-        n = self.name
-
-        ifc.addstmt(cxx.Label('public'))
-        nmsgs = len(p.messageDecls)
-        for i, msgdecl in enumerate(p.messageDecls):
-            msgdecl.accept(self)
-
-        ifc.addstmt(cxx.Whitespace.NL)
-        ifc.addstmt(cxx.Label('protected'))
-        ifc.addstmt(cxx.ConstructorDefn(
-                cxx.ConstructorDecl(n)))
-        ifc.addstmt(cxx.DestructorDefn(
-                cxx.DestructorDecl(n, virtual=True)))
-
-        # disable unwanted ctors/operators
-        ifc.addstmt(cxx.Whitespace.NL)
-        ifc.addstmt(cxx.Label('private'))
-        ref = cxx.Type(n, ref=True)
-        constref = cxx.Type(n, const=True, ref=True)
-        ifc.addstmt(cxx.StmtDecl(
-                cxx.ConstructorDecl(n,
-                                    params=[ cxx.Decl(constref, '')])))
-        ifc.addstmt(cxx.StmtDecl(
-                cxx.MethodDecl('operator=',
-                               params= [ cxx.Decl(constref, '') ],
-                               ret=ref)))
-
-    def visitMessageDecl(self, md):
-        if self.msgComesIn(md.decl.type):
-            method = deepcopy(md._cxx.method)
-            method.pure = True
-            self.iface.addstmt(cxx.StmtDecl(method))
-            self.iface.addstmt(cxx.Whitespace.NL)
-
-
-class GenerateParentInterface(GenerateInterface):
-    def __init__(self, iparent):
-        GenerateInterface.__init__(self, iparent, iparent.name)
-    def msgComesIn(self, mtype):  return mtype.isIn() or mtype.isInout()
-
-class GenerateChildInterface(GenerateInterface):
-    def __init__(self, iparent):
-        GenerateInterface.__init__(self, iparent, iparent.name)
-    def msgComesIn(self, mtype):  return mtype.isOut() or mtype.isInout()
-
-
-def generateMsgClass(clsname, params, typedefInjector):
+def generateMsgClass(md, clsname, params, typedefInjector):
         cls = cxx.Class(name=clsname,
                         inherits=[ cxx.Inherit('IPC::Message') ])
         cls.addstmt(cxx.Label('private'))
         typedefInjector(cls)
         cls.addstmt(cxx.Whitespace.NL)
 
         cls.addstmt(cxx.Label('public'))
 
@@ -319,42 +247,51 @@ def generateMsgClass(clsname, params, ty
 
         # FIXME/cjones: need to handle "managed" messages
 
         constparams = deepcopy(params)
         writestmts = [ ]
         for cparam in constparams:
             cparam.type.const = True
             cparam.type.ref = True
-            writestmts.append(
-                cxx.StmtExpr(cxx.ExprCall(cxx.ExprVar('IPC::WriteParam'),
-                                          [ cxx.ExprVar('this'),
-                                            cxx.ExprVar(cparam.name) ])))
+
+        if md.decl.type.hasImplicitActorParam():
+            constparams.append(cxx.Decl(
+                    cxx.Type('mozilla::ipc::ActorHandle', const=1, ref=1),
+                    '__ah'))
 
         # make the message constructor (serializer)
         ctordecl = cxx.ConstructorDecl(clsname, params=constparams)
 
         superinit = cxx.ExprMemberInit(
             cxx.ExprVar('IPC::Message'),
-            [ cxx.ExprVar('MSG_ROUTING_CONTROL'),
+            [ cxx.ExprVar('MSG_ROUTING_NONE'),
               cxx.ExprVar('ID'),
               cxx.ExprVar('PRIORITY_NORMAL') ])
 
         ctor = cxx.ConstructorDefn(ctordecl, [ superinit ])
-        for writestmt in writestmts:
-            ctor.addstmt(writestmt)
+        for cparam in constparams:
+            ctor.addstmt(
+                cxx.StmtExpr(cxx.ExprCall(cxx.ExprVar('IPC::WriteParam'),
+                                          [ cxx.ExprVar('this'),
+                                            cxx.ExprVar(cparam.name) ])))
         cls.addstmt(ctor)
 
         cls.addstmt(cxx.Whitespace.NL)
 
         # make the message deserializer
         outparams = deepcopy(params)
         for oparam in outparams:
             oparam.type.ptr = True
 
+        if md.decl.type.hasImplicitActorParam():
+            outparams.append(cxx.Decl(
+                    cxx.Type('mozilla::ipc::ActorHandle', ptr=1),
+                    '__ah'))
+
         reader = cxx.MethodDefn(
             cxx.MethodDecl(
                 'Read',
                 params=([ cxx.Decl(cxx.Type('Message', ptr=True, const=True),
                                    'msg') ]
                         + outparams),
                 ret=cxx.Type('bool'),
                 static=True))
@@ -384,43 +321,45 @@ def generateMsgClass(clsname, params, ty
         # false isn't a var
         reader.addstmt(cxx.StmtReturn(cxx.ExprVar('true')))
 
         cls.addstmt(reader)
 
         return cls
 
 def generateMessageClass(md, typedefInjector):
-    return generateMsgClass(md._cxx.id, md._cxx.params, typedefInjector)
+    return generateMsgClass(md, md._cxx.id, md._cxx.params, typedefInjector)
 
 def generateReplyClass(md, typedefInjector):
-    return generateMsgClass(md._cxx.replyid, md._cxx.returns, typedefInjector)
+    return generateMsgClass(md, md._cxx.replyid, md._cxx.returns, typedefInjector)
 
 
 ##-----------------------------------------------------------------------------
 _channelTable = {
     'Async': [ 'mozilla', 'ipc', 'AsyncChannel' ],
     'Sync': [ 'mozilla', 'ipc', 'SyncChannel' ],
     'Rpc': [ 'mozilla', 'ipc', 'RPCChannel' ]
 }
 
 
 class GenerateProtocolActorHeader(Visitor):
-    def __init__(self, thisiface, thatiface):
-        self.thisiface = thisiface
-        self.thatiface = thatiface
+    def __init__(self, myside, otherside):
+        self.myside = myside  # "Parent" or "Child"
+        self.otherside = otherside
         self.clsname = None
         self.pname = None
         self.file = None
         self.ns = None
+        self.typedefs = None
 
-    def lower(self, tu, pname, clsname, cxxHeaderFile):
+    def lower(self, tu, pname, clsname, cxxHeaderFile, typedefs):
         self.pname = pname
         self.clsname = clsname
         self.file = cxxHeaderFile
+        self.typedefs = typedefs
         tu.accept(self)
 
     def visitTranslationUnit(self, tu):
         f = self.file
 
         f.addthing(cxx.Whitespace('''//
 // Automatically generated by ipdlc.
 // Edit at your own risk
@@ -430,23 +369,38 @@ class GenerateProtocolActorHeader(Visito
         includeguard = _protocolIncludeGuard(tu.protocol, self.clsname)
         f.addthing(cxx.CppDirective('ifndef', includeguard))
         f.addthing(cxx.CppDirective('define', includeguard))
         f.addthing(cxx.Whitespace.NL)
 
         mainheader = _protocolHeaderFilename(tu.protocol, self.pname)
         f.addthing(cxx.CppDirective('include', '"'+ mainheader +'"'))
 
+        self.protocol = tu.protocol
+
+        for pinc in tu.protocolIncludes:
+            pinc.accept(self)
+
         tu.protocol.accept(self)
 
         f.addthing(cxx.Whitespace.NL)
         f.addthing(cxx.CppDirective('endif', '// ifndef '+ includeguard))
 
+    def visitProtocolInclude(self, pi):
+        p = pi.tu.protocol
+        if self.protocol.decl.type.isManagerOf(p.decl.type):
+            header = _protocolHeaderFilename(
+                p, _protocolHeaderName(p.name)+ self.myside)
+            self.file.addthing(cxx.CppDirective('include', '"'+ header +'"'))
+
 
     def visitProtocol(self, p):
+        if p.decl.type.isManager():
+            self.file.addthing(cxx.CppDirective('include', '"base/id_map.h"'))
+
         channel = _channelTable[p.decl.type.sendSemantics.pretty]
         channelname = '::'.join(channel)
         channelfile = '/'.join(channel) +'.h'
         if p.decl.type.isToplevel():
             self.channelsel = '.'
         else:
             self.channelsel = '->'
 
@@ -464,45 +418,71 @@ class GenerateProtocolActorHeader(Visito
             for ns in innernamespaces:
                 innerns = cxx.Namespace(ns.namespace)
                 self.ns.addstmt(innerns)
                 self.ns = innerns
 
         self.ns.addstmt(cxx.Whitespace.NL)
         self.ns.addstmt(cxx.Whitespace.NL)
 
-        iface = p.decl.fullname +'Protocol::'+ self.thatiface
-        cls = cxx.Class(self.clsname,
-                        inherits=[ cxx.Inherit(iface),
-                                   cxx.Inherit(channelname +'::Listener') ],
-                        final=True)
+        inherits = [ cxx.Inherit(channelname +'::Listener') ]
+        if p.decl.type.isManager():
+            inherits.append(cxx.Inherit('mozilla::ipc::IProtocolManager'))
+        cls = cxx.Class(self.clsname, inherits=inherits, abstract=True)
+
+        if p.decl.type.isManaged():
+            cls.addstmt(cxx.FriendClassDecl(
+                    _protocolHeaderName(p.decl.type.manager.name())
+                                        + self.myside))
+            cls.addstmt(cxx.Whitespace.NL)
+
+        cls.addstmt(cxx.Label('protected'))
+        for typedef in self.typedefs:
+            cls.addstmt(typedef)
+        cls.addstmt(cxx.Whitespace.NL)
+
+        # constructor/destructor interface for subclass to impl
+        for md in p.messageDecls:
+            if md.decl.type.isCtor() or md.decl.type.isDtor():
+                objtype = cxx.Type(
+                    (_protocolHeaderName(md.decl.type.constructedType().name())
+                     + self.myside),
+                    ptr=1)
+                meth = deepcopy(md._cxx.method)
+                meth.pure = True
+                if md.decl.type.isCtor():
+                    meth.ret = objtype
+                else:
+                    meth.params.insert(0, cxx.Decl(objtype, '__a'))
+                cls.addstmt(cxx.StmtDecl(meth))
+
+            elif self.receivesMessage(md):
+                if md.decl.type.isRpc():  pfx = 'Answer'
+                else:                     pfx = 'Recv'
+                meth = deepcopy(md._cxx.method);
+                meth.pure = True
+                meth.name = pfx + meth.name
+                cls.addstmt(cxx.StmtDecl(meth))
+        cls.addstmt(cxx.Whitespace.NL)
 
         cls.addstmt(cxx.Label('private'))
-        impliface = p.decl.fullname +'Protocol::'+ self.thisiface
         cls.addstmt(cxx.Typedef(cxx.Type('IPC::Message'),
                                 cxx.Type('Message')))
         cls.addstmt(cxx.Typedef(cxx.Type(channelname),
                                 cxx.Type('Channel')))
-        cls.addstmt(cxx.Typedef(cxx.Type(impliface),
-                                cxx.Type(self.thisiface)))
         cls.addstmt(cxx.Whitespace.NL)
         
         # TODO manager param to constructor, when protocol is managed
 
         cls.addstmt(cxx.Label('public'))
-        ctor = cxx.ConstructorDefn(
-            cxx.ConstructorDecl(
-                self.clsname,
-                [ cxx.Decl(cxx.Type(self.thisiface, ptr=True), 'aImpl') ]),
-            [ cxx.ExprMemberInit(cxx.ExprVar('mImpl'),
-                                 [ cxx.ExprVar('aImpl') ]) ])
+        ctor = cxx.ConstructorDefn(cxx.ConstructorDecl(self.clsname))
         if p.decl.type.isToplevel():
-            ctor.memberinits.append(
+            ctor.memberinits = [
                 cxx.ExprMemberInit(cxx.ExprVar('mChannel'),
-                                   [ cxx.ExprVar('this') ]))
+                                   [ cxx.ExprVar('this') ]) ]
         cls.addstmt(ctor)
         cls.addstmt(cxx.Whitespace.NL)
 
         dtor = cxx.DestructorDefn(
             cxx.DestructorDecl(self.clsname, virtual=True))
         cls.addstmt(dtor)
         cls.addstmt(cxx.Whitespace.NL)
 
@@ -536,16 +516,17 @@ class GenerateProtocolActorHeader(Visito
             cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('msg'), '.', 'type'), [ ]))
         if p.decl.type.talksSync():
             self.syncswitch = deepcopy(self.asyncswitch)
             if p.decl.type.talksRpc():
                 self.rpcswitch = deepcopy(self.syncswitch)
 
         # implement child iface and add handlers to message switches
         self.cls = cls
+        self.p = p
         for md in p.messageDecls:
             self.visitMessageDecl(md)
 
         # add default cases
         default = cxx.StmtBlock()
         default.addstmt(cxx.StmtReturn(cxx.ExprVar('MsgNotKnown')))
         
         self.asyncswitch.addcase(cxx.DefaultLabel(), default)
@@ -564,166 +545,477 @@ class GenerateProtocolActorHeader(Visito
             synchandler = deepcopy(asynchandler)
             synchandler.decl.params.append(cxx.Decl(
                     cxx.Type('Message', ref=1, ptr=1), 'reply'))
 
             if p.decl.type.talksRpc():
                 rpchandler = deepcopy(synchandler)
                 rpchandler.decl.name = 'OnCallReceived'
 
+
+        def addDispatcher(mdefn, dispatchMethod, params):
+            mdefn.addstmt(cxx.StmtDecl(cxx.Decl(cxx.Type('int'), '__route')))
+            routevar = cxx.ExprVar('__route')
+            mdefn.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                        routevar,
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('msg'),
+                                                    '.', 'routing_id')))))
+            routeif = cxx.StmtIf(cxx.ExprBinary(
+                    cxx.ExprVar('MSG_ROUTING_CONTROL'), '!=', routevar))
+            routeif.ifb.addstmt(cxx.StmtDecl(cxx.Decl(
+                        cxx.Type('Channel::Listener', ptr=1), '__routed')))
+            routedvar = cxx.ExprVar('__routed')
+            routeif.ifb.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                        routedvar,
+                        cxx.ExprCall(cxx.ExprVar('Lookup'), [ routevar ]))))
+
+            failif = cxx.StmtIf(cxx.ExprPrefixUnop(routedvar, '!'))
+            failif.ifb.addstmt(cxx.StmtReturn(cxx.ExprVar('MsgRouteError')))
+            routeif.ifb.addstmt(failif)
+
+            routeif.ifb.addstmt(cxx.StmtReturn(cxx.ExprCall(
+                        cxx.ExprSelect(routedvar, '->', dispatchMethod),
+                        params)))
+            mdefn.addstmt(routeif)
+            mdefn.addstmt(cxx.Whitespace.NL)
+
+
+        if p.decl.type.isToplevel():
+            addDispatcher(asynchandler, 'OnMessageReceived',
+                          [ cxx.ExprVar('msg') ])
         asynchandler.addstmt(self.asyncswitch)
         cls.addstmt(asynchandler)
         cls.addstmt(cxx.Whitespace.NL)
 
         if p.decl.type.talksSync():
+            if p.decl.type.isToplevel():
+                addDispatcher(synchandler, 'OnMessageReceived',
+                              [ cxx.ExprVar('msg'), cxx.ExprVar('reply') ])
             synchandler.addstmt(self.syncswitch)
             cls.addstmt(synchandler)
             cls.addstmt(cxx.Whitespace.NL)
 
             if p.decl.type.talksRpc():
+                if p.decl.type.isToplevel():
+                    addDispatcher(rpchandler, 'OnCallReceived',
+                                  [ cxx.ExprVar('msg'), cxx.ExprVar('reply') ])
                 rpchandler.addstmt(self.rpcswitch)
                 cls.addstmt(rpchandler)
                 cls.addstmt(cxx.Whitespace.NL)
 
-        # private members and methods
-
-        # TODO handle manager stuff: lookups, routing
+        # implement IProtocolManager interface
+        if p.decl.type.isManager():
+            register = cxx.MethodDefn(
+                cxx.MethodDecl(
+                    'Register',
+                    [ cxx.Decl(cxx.Type('Channel::Listener', ptr=1), 'aRouted') ],
+                    ret=cxx.Type('int32'),
+                    virtual=1))
+            lookup = cxx.MethodDefn(
+                cxx.MethodDecl(
+                    'Lookup',
+                    [ cxx.Decl(cxx.Type('int32'), 'aId') ],
+                    ret=cxx.Type('Channel::Listener', ptr=1),
+                    virtual=1))
+            unregister = cxx.MethodDefn(
+                cxx.MethodDecl(
+                    'Unregister',
+                    [ cxx.Decl(cxx.Type('int32'), 'aId') ],
+                    ret=cxx.Type('void'),
+                    virtual=1))
 
+            if p.decl.type.isToplevel():
+                register.addstmt(cxx.StmtReturn(
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('mActorMap'),
+                                                    '.', 'Add'),
+                                     [ cxx.ExprVar('aRouted') ])))
+                lookup.addstmt(cxx.StmtReturn(
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('mActorMap'),
+                                                    '.', 'Lookup'),
+                                     [ cxx.ExprVar('aId') ])))
+                unregister.addstmt(cxx.StmtReturn(
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('mActorMap'),
+                                                    '.', 'Remove'),
+                                     [ cxx.ExprVar('aId') ])))
+            else:
+                register.addstmt(cxx.StmtReturn(
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('mManager'),
+                                                    '->', 'Register'),
+                                     [ cxx.ExprVar('aRouted') ])))
+                lookup.addstmt(cxx.StmtReturn(
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('mManager'),
+                                                    '->', 'Lookup'),
+                                     [ cxx.ExprVar('aId') ])))
+                unregister.addstmt(cxx.StmtReturn(
+                        cxx.ExprCall(cxx.ExprSelect(cxx.ExprVar('mManager'),
+                                                    '->', 'Unregister'),
+                                     [ cxx.ExprVar('aId') ])))
+            cls.addstmt(register)
+            cls.addstmt(lookup)
+            cls.addstmt(unregister)
+            cls.addstmt(cxx.Whitespace.NL)
+
+        # private members and methods
         cls.addstmt(cxx.Label('private'))
-        cls.addstmt(cxx.StmtDecl(cxx.Decl(cxx.Type(self.thisiface, ptr=True),
-                                          'mImpl')))
         channeltype = cxx.Type('Channel')
         if p.decl.type.isManaged():
             channeltype.ptr = True # subprotocols inherit this
         cls.addstmt(cxx.StmtDecl(cxx.Decl(channeltype, 'mChannel')))
-
+        if p.decl.type.isToplevel():
+            cls.addstmt(cxx.StmtDecl(cxx.Decl(
+                        cxx.Type('IDMap<Channel::Listener>'), 'mActorMap')))
+        else:
+            cls.addstmt(cxx.StmtDecl(cxx.Decl(cxx.Type('int'), 'mId')))
+            cls.addstmt(cxx.StmtDecl(cxx.Decl(cxx.Type('int'), 'mPeerId')))
+            cls.addstmt(cxx.StmtDecl(cxx.Decl(
+                        cxx.Type('mozilla::ipc::IProtocolManager', ptr=1),
+                        'mManager')))
         self.ns.addstmt(cls)
         self.ns.addstmt(cxx.Whitespace.NL)
         self.ns.addstmt(cxx.Whitespace.NL)
 
 
     def visitMessageDecl(self, md):
         # TODO special handling of constructor messages
 
         # create method for "that" interface
         if self.sendsMessage(md):
-            impl = cxx.MethodDefn(md._cxx.method)
+            pfx = None
+            if md.decl.type.isRpc():
+                pfx = 'Call'
+            else:
+                pfx = 'Send'
+
+            mdecl = deepcopy(md._cxx.method)
+            mdecl.name = pfx + mdecl.name
+            mdecl.virtual = False
+            if md.decl.type.hasImplicitActorParam():
+                objtype = cxx.Type(
+                    (_protocolHeaderName(md.decl.type.constructedType().name())
+                     + self.myside),
+                    ptr=1)
+            if md.decl.type.isCtor():
+                mdecl.ret = objtype
+            elif md.decl.type.isDtor():
+                mdecl.params.insert(0, cxx.Decl(objtype, '__a'))
+                objvar = cxx.ExprVar('__a')
+            impl = cxx.MethodDefn(mdecl)
+
+            if md.decl.type.isCtor():
+                impl.addstmt(cxx.StmtDecl(cxx.Decl(objtype, '__a')))
+                objvar = cxx.ExprVar('__a')
+
+                okcode = objvar
+                failerrcode = cxx.ExprLiteral.ZERO
+                valueerrcode = cxx.ExprLiteral.ZERO
+
+                impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            objvar,
+                            cxx.ExprCall(cxx.ExprVar(md._cxx.method.name),
+                                         [ cxx.ExprVar(p.name) for
+                                           p in md._cxx.method.params ]))))
+                failif = cxx.StmtIf(cxx.ExprPrefixUnop(objvar, '!'))
+                failif.ifb.addstmt(cxx.StmtReturn(cxx.ExprLiteral.ZERO))
+                impl.addstmt(failif)
+
+                objid = cxx.ExprSelect(objvar, '->', 'mId')
+                impl.addstmt(cxx.StmtExpr(
+                        cxx.ExprAssn(objid,
+                                     cxx.ExprCall(cxx.ExprVar('Register'),
+                                                  [ objvar ]))))
 
-            impl.addstmt(cxx.StmtDecl(cxx.Decl(cxx.Type('nsresult'), '__rv')))
-            rv = cxx.ExprVar('__rv')
-            failif = cxx.StmtIf(rv)
-            failif.ifb.addstmt(cxx.StmtReturn(rv))
+                impl.addstmt(cxx.StmtDecl(
+                        cxx.Decl(cxx.Type('mozilla::ipc::ActorHandle'),
+                                 '__ah')))
+                ahvar = cxx.ExprVar('__ah')
+                impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            cxx.ExprSelect(ahvar, '.', 'm'+ self.myside +'Id'),
+                            objid)))
+
+                impl.addstmt(cxx.Whitespace.NL)
+
+            elif md.decl.type.isDtor():
+                okcode = cxx.ExprVar('NS_OK')
+                failerrcode = cxx.ExprVar('NS_ERROR_FAILURE')
+                valueerrcode = cxx.ExprVar('NS_ERROR_ILLEGAL_VALUE')
+
+                failif = cxx.StmtIf(cxx.ExprPrefixUnop(objvar, '!'))
+                failif.ifb.addstmt(cxx.StmtReturn(valueerrcode))
+                impl.addstmt(failif)
+
+                # verify that this object indeed exists
+                objid = cxx.ExprSelect(objvar, '->', 'mId')
+
+                impl.addstmt(cxx.StmtDecl(cxx.Decl(objtype, '__b')))
+                bvar = cxx.ExprVar('__b')
+                impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            bvar,
+                            cxx.ExprCast(
+                                cxx.ExprCall(cxx.ExprVar('Lookup'), [ objid ]),
+                                objtype, dynamic=1))))
+                failif = cxx.StmtIf(cxx.ExprBinary(objvar, '!=', bvar))
+                failif.ifb.addstmt(cxx.StmtReturn(valueerrcode))
+                impl.addstmt(failif)
+                impl.addstmt(cxx.Whitespace.NL)
+
+                impl.addstmt(cxx.StmtDecl(cxx.Decl(
+                            cxx.Type('mozilla::ipc::ActorHandle'), '__ah')))
+                ahvar = cxx.ExprVar('__ah')
+                impl.addstmt(cxx.StmtExpr(
+                        cxx.ExprAssn(
+                            cxx.ExprSelect(ahvar,
+                                           '.', 'm'+ self.myside +'Id'),
+                            objid)))
+                impl.addstmt(cxx.StmtExpr(
+                        cxx.ExprAssn(
+                            cxx.ExprSelect(ahvar,
+                                           '.', 'm'+ self.otherside +'Id'),
+                            cxx.ExprSelect(objvar,
+                                           '->', 'mPeerId'))))
+                impl.addstmt(cxx.Whitespace.NL)
+
+            else:               # normal message
+                okcode = cxx.ExprVar('NS_OK')
+                failerrcode = cxx.ExprVar('NS_ERROR_FAILURE')
+                valueerrcode = cxx.ExprVar('NS_ERROR_ILLEGAL_VALUE')
 
             hasreply = md.decl.type.hasReply()
             if hasreply:
                 impl.addstmt(cxx.StmtDecl(
-                        cxx.Decl(cxx.Type('Message'), 'reply')))
-                reply = cxx.ExprVar('reply')
-            impl.addstmt(cxx.Whitespace.NL)
+                        cxx.Decl(cxx.Type('Message'), '__reply')))
+                replyvar = cxx.ExprVar('__reply')
+            impl.addstmt(cxx.StmtDecl(cxx.Decl(cxx.Type('Message', ptr=1),
+                                               '__msg')))
+            msgvar = cxx.ExprVar('__msg')
+
+            msgctor = cxx.ExprNew(cxx.Type(md._cxx.nsid),
+                                  [ cxx.ExprVar(p.name)
+                                    for p in md._cxx.params ])
+            if md.decl.type.hasImplicitActorParam():
+                msgctor.args.append(ahvar)
+                
+            if self.p.decl.type.isManaged():
+                route = cxx.ExprVar('mPeerId')
+            else:
+                route = cxx.ExprVar('MSG_ROUTING_CONTROL')
+
+            impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(msgvar, msgctor)))
+            impl.addstmt(cxx.StmtExpr(
+                    cxx.ExprCall(cxx.ExprSelect(msgvar, '->', 'set_routing_id'),
+                                 [ route ])))
 
             sendcall = cxx.ExprCall(
                 cxx.ExprSelect(
                     cxx.ExprVar('mChannel'), self.channelsel, 'Call'),
-                [ cxx.ExprNew(cxx.Type(md._cxx.nsid),
-                              [ cxx.ExprVar(p.name)
-                                for p in md._cxx.params ]) ])
+                [ msgvar ])
             if hasreply:
-                sendcall.args.append(cxx.ExprAddrOf(reply))
-
-            # TODO special handling of actor handles
+                sendcall.args.append(cxx.ExprAddrOf(replyvar))
 
-            impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(rv, sendcall)))
-            if not hasreply:
-                impl.addstmt(cxx.StmtReturn(rv))
-                self.cls.addstmt(impl)
-                self.cls.addstmt(cxx.Whitespace.NL)
-            else:
-                impl.addstmt(failif)
+            failif = cxx.StmtIf(cxx.ExprPrefixUnop(sendcall, '!'))
+            failif.ifb.addstmt(cxx.StmtReturn(failerrcode))
+            impl.addstmt(failif)
 
+            if hasreply:
                 unpack = cxx.ExprCall(cxx.ExprVar(md._cxx.nsreplyid +'::Read'),
-                                      [ cxx.ExprAddrOf(cxx.ExprVar('reply')) ]
+                                      [ cxx.ExprAddrOf(replyvar) ]
                                       + [ cxx.ExprVar(r.name)
                                           for r in md._cxx.returns ])
+                if md.decl.type.hasImplicitActorParam():
+                    unpack.args.append(cxx.ExprAddrOf(ahvar))
                 errhandle = cxx.StmtIf(cxx.ExprPrefixUnop(unpack, '!'))
-                errhandle.ifb.addstmt(cxx.StmtReturn(
-                        cxx.ExprVar('MsgPayloadError')))
+                errhandle.ifb.addstmt(cxx.StmtReturn(valueerrcode))
                 impl.addstmt(errhandle)
 
-                # TODO special handling of actor handles
+                # FIXME/cjones: assuming we have sync/rpc constructors, need
+                # code for async ones if that makes sense
+                if md.decl.type.isCtor():
+                    impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                                cxx.ExprSelect(objvar, '->', 'mPeerId'),
+                                cxx.ExprSelect(ahvar, '.',
+                                               'm'+ self.otherside +'Id'))))
+                    impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                                cxx.ExprSelect(objvar, '->', 'mManager'),
+                                cxx.ExprVar('this'))))
+                    if self.p.decl.type.isManaged():
+                        channelvar = cxx.ExprVar('mChannel')
+                    else:
+                        channelvar = cxx.ExprAddrOf(cxx.ExprVar('mChannel'))
+                    impl.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                                cxx.ExprSelect(objvar, '->', 'mChannel'),
+                                channelvar)))
 
-                impl.addstmt(cxx.StmtReturn(cxx.ExprVar('NS_OK')))
+                elif md.decl.type.isDtor():
+                    impl.addstmt(cxx.StmtExpr(
+                        cxx.ExprCall(cxx.ExprVar('Unregister'), [ objid ])))
+                    impl.addstmt(cxx.StmtExpr(
+                            cxx.ExprAssn(objid, cxx.ExprLiteral(-1, 'd'))))
+                    impl.addstmt(cxx.StmtExpr(
+                            cxx.ExprAssn(
+                                cxx.ExprSelect(objvar, '->', 'mManager'),
+                                cxx.ExprLiteral.ZERO)))
+                    impl.addstmt(cxx.StmtExpr(
+                            cxx.ExprAssn(
+                                cxx.ExprSelect(objvar, '->', 'mPeerId'),
+                                cxx.ExprLiteral(-1, 'd'))))
 
+            impl.addstmt(cxx.StmtReturn(okcode))
             self.cls.addstmt(impl)
             self.cls.addstmt(cxx.Whitespace.NL)
 
 
         # create case for this message in the big handler switch statement
         if self.receivesMessage(md):
+            if md.decl.type.isRpc():  pfx = 'Answer'
+            else:                     pfx = 'Recv'
+
             case = cxx.CaseLabel(md._cxx.nsid +'__ID')
             block = cxx.StmtBlock()
+            hasactor = md.decl.type.hasImplicitActorParam()
+            if hasactor:
+                objtype = cxx.Type(
+                    (_protocolHeaderName(md.decl.type.constructedType().name())
+                     + self.myside),
+                    ptr=1)
+                objvar = cxx.ExprVar('__a')
+                objid = cxx.ExprSelect(objvar, '->', 'mId')
 
-            rv = cxx.ExprVar('__rv')
             for param in md._cxx.params:
                 block.addstmt(cxx.StmtDecl(param))
             for ret in md._cxx.returns:
                 block.addstmt(cxx.StmtDecl(ret))
+            if hasactor:
+                block.addstmt(cxx.StmtDecl(cxx.Decl(
+                            cxx.Type('mozilla::ipc::ActorHandle'), '__ah')))
+                ahvar = cxx.ExprVar('__ah')
             block.addstmt(cxx.Whitespace.NL)
 
             unpack = cxx.ExprCall(cxx.ExprVar(md._cxx.nsid +'::Read'),
                                   [ cxx.ExprAddrOf(cxx.ExprVar('msg')) ]
                                   + [ cxx.ExprAddrOf(cxx.ExprVar(p.name))
                                       for p in md._cxx.params ])
+            if hasactor:
+                unpack.args.append(cxx.ExprAddrOf(ahvar))
             errhandle = cxx.StmtIf(cxx.ExprPrefixUnop(unpack, '!'))
             errhandle.ifb.addstmt(cxx.StmtReturn(
                     cxx.ExprVar('MsgPayloadError')))
             block.addstmt(errhandle)
 
-            # TODO special handling of actor handles
+            if md.decl.type.isCtor():
+                block.addstmt(cxx.Whitespace.NL)
+                block.addstmt(cxx.StmtDecl(cxx.Decl(objtype, '__a')))
+
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            objvar,
+                            cxx.ExprCall(
+                                cxx.ExprVar(md._cxx.method.name),
+                                ([ cxx.ExprVar(p.name) for
+                                   p in md._cxx.params ]
+                                 + [ cxx.ExprAddrOf(cxx.ExprVar(r.name)) for
+                                     r in md._cxx.returns ])))))
+                errhandle = cxx.StmtIf(cxx.ExprPrefixUnop(objvar, '!'))
+                errhandle.ifb.addstmt(cxx.StmtReturn(cxx.ExprVar('MsgValueError')))
+                block.addstmt(errhandle)
+
+            elif md.decl.type.isDtor():
+                block.addstmt(cxx.StmtDecl(cxx.Decl(objtype, '__a')))
+
+                routevar = cxx.ExprSelect(ahvar, '.', 'm'+ self.myside +'Id')
+                dcast = cxx.ExprCast(
+                    cxx.ExprCall(cxx.ExprVar('Lookup'), [ routevar ]),
+                    objtype,
+                    dynamic=1)
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(objvar, dcast)))
+
+                failif = cxx.StmtIf(cxx.ExprPrefixUnop(objvar, '!'))
+                failif.ifb.addstmt(cxx.StmtReturn(cxx.ExprVar('MsgValueError')))
+                block.addstmt(failif)
 
-            callimpl = cxx.ExprCall(
-                cxx.ExprSelect(cxx.ExprVar('mImpl'), '->',
-                               md.decl.progname), [ ])
-            callimpl.args += [ cxx.ExprVar(p.name) for p in md._cxx.params ]
-            callimpl.args += [ cxx.ExprAddrOf(cxx.ExprVar(r.name))
+                failif = cxx.StmtIf(cxx.ExprCall(
+                        cxx.ExprVar(md._cxx.method.name),
+                        ([ objvar ]
+                         + [ cxx.ExprVar(p.name) for p in md._cxx.params ]
+                         + [ cxx.ExprAddrOf(cxx.ExprVar(r.name)) for
+                             r in md._cxx.returns ])))
+                failif.ifb.addstmt(cxx.StmtReturn(cxx.ExprVar('MsgValueError')))
+                block.addstmt(failif)
+                block.addstmt(cxx.StmtExpr(
+                        cxx.ExprCall(cxx.ExprVar('Unregister'), [ routevar ])))
+                block.addstmt(cxx.StmtExpr(
+                        cxx.ExprAssn(routevar, cxx.ExprLiteral(-1, 'd'))))
+
+            else:
+                callimpl = cxx.ExprCall(
+                    cxx.ExprVar(pfx + md.decl.progname), [ ])
+                callimpl.args += [ cxx.ExprVar(p.name) for p in md._cxx.params ]
+                callimpl.args += [ cxx.ExprAddrOf(cxx.ExprVar(r.name))
                                for r in md._cxx.returns ]
-            errhandle = cxx.StmtIf(callimpl)
-            errhandle.ifb.addstmt(cxx.StmtReturn(
-                    cxx.ExprVar('MsgValueError')))
-            block.addstmt(errhandle)
+                errhandle = cxx.StmtIf(callimpl)
+                errhandle.ifb.addstmt(cxx.StmtReturn(
+                        cxx.ExprVar('MsgValueError')))
+                block.addstmt(errhandle)
+
+            block.addstmt(cxx.Whitespace.NL)
 
-            # TODO special handling of actor handles
+            if md.decl.type.isCtor():
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            cxx.ExprSelect(ahvar, '.',
+                                           'm'+ self.myside +'Id'),
+                            cxx.ExprAssn(objid,
+                                         cxx.ExprCall(cxx.ExprVar('Register'),
+                                                      [ objvar ])))))
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            cxx.ExprSelect(objvar, '->', 'mPeerId'),
+                            cxx.ExprSelect(ahvar, '.',
+                                           'm'+ self.otherside +'Id'))))
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            cxx.ExprSelect(objvar, '->', 'mManager'),
+                            cxx.ExprVar('this'))))
+                if self.p.decl.type.isToplevel():
+                    channelvar = cxx.ExprAddrOf(cxx.ExprVar('mChannel'))
+                else:
+                    channelvar = cxx.ExprVar('mChannel')
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(
+                            cxx.ExprSelect(objvar, '->', 'mChannel'),
+                            channelvar)))
+                block.addstmt(cxx.Whitespace.NL)
 
             if md.decl.type.hasReply():
-                replymsg = cxx.ExprNew(
+                replyvar = cxx.ExprVar('reply')
+                replymsgctor = cxx.ExprNew(
                     cxx.Type(md._cxx.nsreplyid),
                     [ cxx.ExprVar(r.name) for r in md._cxx.returns ])
-                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(cxx.ExprVar('reply'),
-                                                        replymsg)))
+                if md.decl.type.hasImplicitActorParam():
+                    replymsgctor.args.append(ahvar)
+                block.addstmt(cxx.StmtExpr(cxx.ExprAssn(replyvar,
+                                                        replymsgctor)))
+                block.addstmt(cxx.StmtExpr(cxx.ExprCall(
+                            cxx.ExprSelect(replyvar, '->', 'set_reply'),
+                            [ ])))
 
             block.addstmt(cxx.StmtReturn(cxx.ExprVar('MsgProcessed')))
 
             if md.decl.type.isAsync():
                 self.asyncswitch.addcase(case, block)
             elif md.decl.type.isSync():
                 self.syncswitch.addcase(case, block)
             else:
                 self.rpcswitch.addcase(case, block)
 
 
 class GenerateProtocolParentHeader(GenerateProtocolActorHeader):
     def __init__(self):
-        GenerateProtocolActorHeader.__init__(self, 'IParent', 'IChild')
+        GenerateProtocolActorHeader.__init__(self, 'Parent', 'Child')
 
     def sendsMessage(self, md):
         return not md.decl.type.isIn()
 
     def receivesMessage(self, md):
         return md.decl.type.isInout() or md.decl.type.isIn()
 
 class GenerateProtocolChildHeader(GenerateProtocolActorHeader):
     def __init__(self):
-        GenerateProtocolActorHeader.__init__(self, 'IChild', 'IParent')
+        GenerateProtocolActorHeader.__init__(self, 'Child', 'Parent')
 
     def sendsMessage(self, md):
         return not md.decl.type.isOut()
 
     def receivesMessage(self, md):
         return md.decl.type.isInout() or md.decl.type.isOut()
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -147,38 +147,42 @@ class MessageType(IPDLType):
     def isCtor(self): return self.ctor
     def isDtor(self): return self.dtor
     def constructedType(self):  return self.cdtype
 
     def isIn(self): return self.direction is IN
     def isOut(self): return self.direction is OUT
     def isInout(self): return self.direction is INOUT
 
+    def hasImplicitActorParam(self):
+        return self.isCtor() or self.isDtor()
+
 class ProtocolType(IPDLType):
     def __init__(self, qname, sendSemantics):
         self.qname = qname
         self.sendSemantics = sendSemantics
         self.manager = None
         self.manages = [ ]
     def isProtocol(self): return True
 
     def name(self):
         return self.qname.baseid
     def fullname(self):
         return str(self.qname)
 
     def managedBy(self, mgr):
         self.manager = mgr
 
-    def isManager(self, pt):
+    def isManagerOf(self, pt):
         for managed in self.manages:
             if pt is managed:
                 return True
         return False
-
+    def isManager(self):
+        return len(self.manages) > 0
     def isManaged(self):
         return self.manager is not None
     def isToplevel(self):
         return not self.isManaged()
 
 ##--------------------
 _builtinloc = Loc('<builtin>', 0)
 def makeBuiltinUsing(tname):
@@ -639,17 +643,17 @@ class CheckTypes(Visitor):
         mgrtype, mgrname = mgrdecl.type, mgrdecl.shortname
 
         # we added this information; sanity check it
         assert ptype.manager is mgrtype
 
         loc = mgr.loc
 
         # check that the "manager" protocol agrees
-        if not mgrtype.isManager(ptype):
+        if not mgrtype.isManagerOf(ptype):
             self.errors.append(errormsg(
                     loc,
                     "|manager| declaration in protocol `%s' does not match any |manages| declaration in protocol `%s'",
                     pname, mgrname))
 
 
     def visitMessageDecl(self, md):
         mtype, mname = md.decl.type, md.decl.progname
@@ -666,14 +670,14 @@ class CheckTypes(Visitor):
 
         if mtype.isAsync() and len(mtype.returns):
             # XXX/cjones could modify grammar to disallow this ...
             self.errors.append(errormsg(
                     loc,
                     "asynchronous message `%s' requests returned values",
                     mname))
 
-        if (mtype.isCtor() or mtype.isDtor()) and not ptype.isManager(mtype.constructedType()):
+        if (mtype.isCtor() or mtype.isDtor()) and not ptype.isManagerOf(mtype.constructedType()):
             self.errors.append(errormsg(
                     loc,
                     "ctor/dtor for protocol `%s', which is not managed by protocol `%s'", 
                     mname[:-len('constructor')],
                     pname))