Bug 540111, part 1: Add a new IProtocolManager::RemoveManagee interface to break reliance on the |Manager()| interface. r=bent
authorChris Jones <jones.chris.g@gmail.com>
Tue, 26 Jan 2010 22:56:09 -0600
changeset 46611 d813355607dd9c40d979011207e1ba20cf452536
parent 46610 645dd195d5db91ded307c1664f5ae54308f3e7ec
child 46612 fffccafd827fc2cce40c6185c461cbcc4dce0683
push idunknown
push userunknown
push dateunknown
reviewersbent
bugs540111
milestone1.9.3a1pre
Bug 540111, part 1: Add a new IProtocolManager::RemoveManagee interface to break reliance on the |Manager()| interface. r=bent
ipc/glue/ProtocolUtils.h
ipc/ipdl/ipdl/cxx/ast.py
ipc/ipdl/ipdl/lower.py
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -81,16 +81,17 @@ public:
     };
 
     typedef base::ProcessHandle ProcessHandle;
 
     virtual int32 Register(ListenerT*) = 0;
     virtual int32 RegisterID(ListenerT*, int32) = 0;
     virtual ListenerT* Lookup(int32) = 0;
     virtual void Unregister(int32) = 0;
+    virtual void RemoveManagee(int32, ListenerT*) = 0;
     // XXX odd duck, acknowledged
     virtual ProcessHandle OtherProcess() const = 0;
 };
 
 
 // This message is automatically sent by IPDL-generated code when a
 // new shmem segment is allocated.  It should never be used directly.
 class __internal__ipdl__ShmemCreated : public IPC::Message
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -710,16 +710,17 @@ class StmtFor(Block):
 class StmtSwitch(Block):
     def __init__(self, expr):
         Block.__init__(self)
         self.expr = expr
         self.nr_cases = 0
 
     def addcase(self, case, block):
         '''NOTE: |case| is not checked for uniqueness'''
+        assert not isinstance(case, str)
         assert (isinstance(block, StmtBreak)
                 or isinstance(block, StmtReturn)
                 or (hasattr(block, 'stmts')
                     and (isinstance(block.stmts[-1], StmtBreak)
                          or isinstance(block.stmts[-1], StmtReturn))))
         self.addstmt(case)
         self.addstmt(block)
         self.nr_cases += 1
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -94,16 +94,25 @@ def _includeGuardStart(headerfile):
     guard = _includeGuardMacroName(headerfile)
     return [ CppDirective('ifndef', guard),
              CppDirective('define', guard)  ]
 
 def _includeGuardEnd(headerfile):
     guard = _includeGuardMacroName(headerfile)
     return [ CppDirective('endif', '// ifndef '+ guard) ]
 
+def _messageStartName(ptype):
+    return ptype.name() +'MsgStart'
+
+def _protocolId(ptype):
+    return ExprVar(_messageStartName(ptype))
+
+def _protocolIdType():
+    return Type('int32')
+
 def _actorName(pname, side):
     """|pname| is the protocol name. |side| is 'Parent' or 'Child'."""
     tag = side
     if not tag[0].isupper():  tag = side.title()
     return pname + tag
 
 def _actorIdType():
     return Type('int32')
@@ -337,16 +346,21 @@ def _callCxxArrayInsertSorted(arr, elt):
 
 def _callCxxArrayRemoveSorted(arr, elt):
     return ExprCall(ExprSelect(arr, '.', 'RemoveElementSorted'),
                     args=[ elt ])
 
 def _callCxxArrayClear(arr):
     return ExprCall(ExprSelect(arr, '.', 'Clear'))
 
+def _cxxArrayHasElementSorted(arr, elt):
+    return ExprBinary(
+        ExprVar('nsTArray_base::NoIndex'), '!=',
+        ExprCall(ExprSelect(arr, '.', 'BinaryIndexOf'), args=[ elt ]))
+
 def _otherSide(side):
     if side == 'child':  return 'parent'
     if side == 'parent':  return 'child'
     assert 0
 
 def _ifLogging(stmts):
     iflogging = StmtIf(ExprCall(ExprVar('mozilla::ipc::LoggingEnabled')))
     iflogging.addifstmts(stmts)
@@ -450,16 +464,19 @@ class _ConvertToCxxType(TypeVisitor):
     def visitShmemType(self, s):
         return Type(s.name())
 
     def visitProtocolType(self, p): assert 0
     def visitMessageType(self, m): assert 0
     def visitVoidType(self, v): assert 0
     def visitStateType(self, st): assert 0
 
+def _bareCxxType(ipdltype, side):
+    return ipdltype.accept(_ConvertToCxxType(side))
+
 def _allocMethod(ptype):
     return ExprVar('Alloc'+ ptype.name())
 
 def _deallocMethod(ptype):
     return ExprVar('Dealloc'+ ptype.name())
 
 class _ConvertToSerializableCxxType(TypeVisitor):
     def visitBuiltinCxxType(self, t):
@@ -509,17 +526,17 @@ info needed by later passes, along with 
         self.name = name
         self.idnum = 0
 
     def var(self):
         return ExprVar(self.name)
 
     def bareType(self, side):
         """Return this decl's unqualified C++ type."""
-        return self.ipdltype.accept(_ConvertToCxxType(side))
+        return _bareCxxType(self.ipdltype, side)
 
     def refType(self, side):
         """Return this decl's C++ type as a 'reference' type, which is not
 necessarily a C++ reference."""
         t = self.bareType(side)
         t.ref = 1
         return t
 
@@ -1284,21 +1301,25 @@ class Protocol(ipdl.ast.Protocol):
     def fqListenerName(self):
         return self.channelName() +'::'+ _semsToListener(self.sendSems())
 
     def managerInterfaceType(self, ptr=0):
         return Type('mozilla::ipc::IProtocolManager',
                     ptr=ptr,
                     T=Type(self.fqListenerName()))
 
+    def _ipdlmgrtype(self):
+        return self.decl.type.manager
+
     def managerActorType(self, side, ptr=0):
-        return Type(_actorName(self.decl.type.manager.name(), side),
+        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');
 
     # FIXME/bug 525181: implement
     def stateMethod(self):
         return ExprVar('state');
 
@@ -1311,16 +1332,19 @@ class Protocol(ipdl.ast.Protocol):
     def lookupIDMethod(self):
         return ExprVar('Lookup')
 
     def unregisterMethod(self, actorThis=None):
         if actorThis is not None:
             return ExprSelect(actorThis, '->', 'Unregister')
         return ExprVar('Unregister')
 
+    def removeManageeMethod(self):
+        return ExprVar('RemoveManagee')
+
     def otherProcessMethod(self):
         return ExprVar('OtherProcess')
 
     def nextActorIdExpr(self, side):
         assert self.decl.type.isToplevel()
         if side is 'parent':   op = '++'
         elif side is 'child':  op = '--'
         else: assert 0
@@ -1359,19 +1383,22 @@ class Protocol(ipdl.ast.Protocol):
         if actorThis is not None:
             return ExprSelect(actorThis, '->', self.idVar().name)
         return self.idVar()
 
     def idVar(self):
         assert not self.decl.type.isToplevel()
         return ExprVar('mId')
 
-    def managerVar(self):
+    def managerVar(self, thisexpr=None):
         assert not self.decl.type.isToplevel()
-        return ExprVar('mManager')
+        mvar = ExprVar('mManager')
+        if thisexpr is not None:
+            mvar = ExprSelect(thisexpr, '->', mvar.name)
+        return mvar
 
     def otherProcessVar(self):
         assert self.decl.type.isToplevel()
         return ExprVar('mOtherProcess')
 
     def managedCxxType(self, actortype, side):
         assert self.decl.type.isManagerOf(actortype)
         return Type(_actorName(actortype.name(), side), ptr=1)
@@ -1576,18 +1603,18 @@ child actors.'''
         stateenum.addId('StateStart', startstate)
         stateenum.addId('StateError')
         stateenum.addId('StateLast')
 
         ns.addstmts([ StmtDecl(Decl(stateenum,'')), Whitespace.NL ])
 
         # spit out message type enum and classes
         msgenum = TypeEnum('MessageType')
-        msgstart = self.protocol.name +'MsgStart << 10'
-        msgenum.addId(self.protocol.name +'Start', msgstart)
+        msgstart = _messageStartName(self.protocol.decl.type) +' << 10'
+        msgenum.addId(self.protocol.name + 'Start', msgstart)
         msgenum.addId(self.protocol.name +'PreStart', '('+ msgstart +') - 1')
 
         for md in p.messageDecls:
             msgenum.addId(md.msgId())
             if md.hasReply():
                 msgenum.addId(md.replyId())
 
         msgenum.addId(self.protocol.name +'End')
@@ -2802,19 +2829,19 @@ class _GenerateProtocolActorCode(ipdl.as
         onerror = MethodDefn(MethodDecl('OnChannelError'))
         onerror.addstmts([
             StmtExpr(ExprCall(destroysubtreevar,
                               args=[ _DestroyReason.AbnormalShutdown ])),
             StmtExpr(ExprCall(deallocsubtreevar))
         ])
         self.cls.addstmts([ onerror, Whitespace.NL ])
 
-        # FIXME: only manager protocols and non-manager protocols with
-        # union types need Lookup().  we'll give it to all for the
-        # time being (simpler)
+        # FIXME/bug 535053: only manager protocols and non-manager
+        # protocols with union types need Lookup().  we'll give it to
+        # all for the time being (simpler)
         if 1 or p.decl.type.isManager():
             self.cls.addstmts(self.implementManagerIface())
 
         if p.usesShmem():
             self.cls.addstmts(self.makeShmemIface())
 
         if p.decl.type.isToplevel() and self.side is 'parent':
             ## bool GetMinidump(nsIFile** dump)
@@ -3053,38 +3080,76 @@ class _GenerateProtocolActorCode(ipdl.as
             ])
             lookup.addstmt(StmtReturn(
                 ExprCall(ExprSelect(p.actorMapVar(), '.', 'Lookup'),
                          [ idvar ])))
             unregister.addstmt(StmtReturn(
                 ExprCall(ExprSelect(p.actorMapVar(), '.', 'Remove'),
                          [ idvar ])))
             otherprocess.addstmt(StmtReturn(p.otherProcessVar()))
-        # delegate registration to manager
         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 ])))
             otherprocess.addstmt(StmtReturn(ExprCall(
                 ExprSelect(p.managerVar(), '->',
                            p.otherProcessMethod().name))))
 
+        # all protocols share the "same" RemoveManagee() implementation
+        pvar = ExprVar('aProtocolId')
+        listenervar = ExprVar('aListener')
+        removemanagee = MethodDefn(MethodDecl(
+            p.removeManageeMethod().name,
+            params=[ Decl(_protocolIdType(), pvar.name),
+                     Decl(listenertype, listenervar.name) ],
+            virtual=1))
+
+        switchontype = StmtSwitch(pvar)
+        for managee in p.managesStmts:
+            case = StmtBlock()
+            actorvar = ExprVar('actor')
+            manageeipdltype = managee.decl.type
+            manageecxxtype = _bareCxxType(ipdl.type.ActorType(manageeipdltype),
+                                       self.side)
+            manageearray = p.managedVar(manageeipdltype, self.side)
+
+            case.addstmts([
+                StmtDecl(Decl(manageecxxtype, actorvar.name),
+                         ExprCast(listenervar, manageecxxtype, static=1)),
+                _abortIfFalse(
+                    _cxxArrayHasElementSorted(manageearray, actorvar),
+                    "actor not managed by this!"),
+                Whitespace.NL,
+                StmtExpr(_callCxxArrayRemoveSorted(manageearray, actorvar)),
+                StmtReturn()
+            ])
+            switchontype.addcase(CaseLabel(_protocolId(manageeipdltype).name),
+                                 case)
+
+        default = StmtBlock()
+        default.addstmts([ _runtimeAbort('unreached'), StmtReturn() ])
+        switchontype.addcase(DefaultLabel(), default)
+
+        removemanagee.addstmt(switchontype)
+
         return [ register,
                  registerid,
                  lookup,
                  unregister,
+                 removemanagee,
                  otherprocess,
                  Whitespace.NL ]
 
 
     def makeShmemIface(self):
         p = self.protocol
         idvar = ExprVar('aId')
 
@@ -3388,20 +3453,17 @@ class _GenerateProtocolActorCode(ipdl.as
         ]
 
     def failCtorIf(self, md, cond):
         actorvar = md.actorDecl().var()
         failif = StmtIf(cond)
         failif.addifstmts(
             self.unregisterActor(actorvar)
             + [ StmtExpr(ExprCall(_deallocMethod(md.decl.type.constructedType()), args=[actorvar])),
-                StmtExpr(_callCxxArrayRemoveSorted(
-                    self.protocol.managedVar(
-                        md.decl.type.constructedType(), self.side),
-                    actorvar)),
+                StmtExpr(self.callRemoveActor(actorvar)),
                 StmtReturn(ExprLiteral.NULL),
             ])
         return [ failif ]
 
     def genHelperCtor(self, md):
         helperdecl = self.makeSendMethodDecl(md)
         helperdecl.params = helperdecl.params[1:]
         helper = MethodDefn(helperdecl)
@@ -3785,23 +3847,25 @@ class _GenerateProtocolActorCode(ipdl.as
             _allocMethod(md.decl.type.constructedType()),
             args=md.makeCxxArgs(params=1, retsems=retsems, retcallsems='out',
                                 implicit=0))
 
     def callActorDestroy(self, actorexpr, why=_DestroyReason.Deletion):
         return ExprCall(ExprSelect(actorexpr, '->', 'DestroySubtree'),
                         args=[ why ])
 
-    def callRemoveActor(self, actorexpr, actorarray=None):
+    def callRemoveActor(self, actorexpr):
         if not self.protocol.decl.type.isManaged():
             return Whitespace('// unmanaged protocol')
-        
-        if actorarray is None:
-            actorarray = self.protocol.managerArrayExpr(actorexpr, self.side)
-        return _callCxxArrayRemoveSorted(actorarray, actorexpr)
+
+        return ExprCall(
+            ExprSelect(self.protocol.managerVar(actorexpr),
+                       '->', self.protocol.removeManageeMethod().name),
+            args=[ _protocolId(self.protocol.decl.type),
+                   actorexpr ])
 
     def callDeallocSubtree(self, md, actorexpr):
         return ExprCall(ExprSelect(actorexpr, '->', 'DeallocSubtree'))
 
     def callDeallocActor(self, md, actorexpr):
         actor = md.decl.type.constructedType()
         return ExprCall(
             ExprSelect(ExprCall(self.protocol.managerMethod(actorexpr)), '->',