Bug 1323532 - Part 1 - don't codegen State enums in ipdl, just statically define the two types we need; r?froydnj draft
authorAlex Gaynor <agaynor@mozilla.com>
Mon, 30 Apr 2018 15:22:18 -0400
changeset 790202 8d105e2ac9a2901ca940d8d2100624e66036879e
parent 790147 d2a4720d1c334b64d88a51678758c27ba8f03c89
child 790203 2bdb0aea243f37c4fc2acfb0925f675797263d13
push id108448
push userbmo:agaynor@mozilla.com
push dateTue, 01 May 2018 16:45:22 +0000
reviewersfroydnj
bugs1323532
milestone61.0a1
Bug 1323532 - Part 1 - don't codegen State enums in ipdl, just statically define the two types we need; r?froydnj MozReview-Commit-ID: CSfCBiQnKxZ
ipc/glue/ProtocolUtils.h
ipc/ipdl/ipdl/lower.py
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -126,16 +126,29 @@ struct ActorHandle
 
 // What happens if Interrupt calls race?
 enum RacyInterruptPolicy {
     RIPError,
     RIPChildWins,
     RIPParentWins
 };
 
+enum class State {
+    Dead,
+    Null,
+    Start = Null
+};
+
+enum class ReEntrantDeleteState {
+    Dead,
+    Null,
+    Dying,
+    Start = Null,
+};
+
 class IToplevelProtocol;
 
 class IProtocol : public HasResultCodes
 {
 public:
     enum ActorDestroyReason {
         FailedConstructor,
         Deletion,
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -133,38 +133,16 @@ def _actorState(actor):
     return ExprSelect(actor, '->', 'mState')
 
 def _backstagePass():
     return ExprCall(ExprVar('mozilla::ipc::PrivateIPDLInterface'))
 
 def _iterType(ptr):
     return Type('PickleIterator', ptr=ptr)
 
-def _nullState(proto=None):
-    pfx = ''
-    if proto is not None:  pfx = proto.name() +'::'
-    return ExprVar(pfx +'__Null')
-
-def _deadState(proto=None):
-    pfx = ''
-    if proto is not None:  pfx = proto.name() +'::'
-    return ExprVar(pfx +'__Dead')
-
-def _dyingState(proto=None):
-    pfx = ''
-    if proto is not None:  pfx = proto.name() +'::'
-    return ExprVar(pfx +'__Dying')
-
-def _startState(proto=None, fq=False):
-    pfx = ''
-    if proto:
-        if fq:  pfx = proto.fullname() +'::'
-        else:   pfx = proto.name() +'::'
-    return ExprVar(pfx +'__Start')
-
 def _deleteId():
     return ExprVar('Msg___delete____ID')
 
 def _deleteReplyId():
     return ExprVar('Reply___delete____ID')
 
 def _lookupListener(idexpr):
     return ExprCall(ExprVar('Lookup'), args=[ idexpr ])
@@ -1072,16 +1050,27 @@ def _subtreeUsesShmem(p):
 
     ptype = p.decl.type
     for mgd in ptype.manages:
         if ptype is not mgd:
             if _subtreeUsesShmem(mgd._ast):
                 return True
     return False
 
+def _stateType(hasReentrantDelete):
+    if hasReentrantDelete:
+        return Type('mozilla::ipc::ReEntrantDeleteState')
+    else:
+        return Type('mozilla::ipc::State')
+
+def _startState(hasReentrantDelete):
+    pfx = _stateType(hasReentrantDelete).name + '::'
+    return ExprVar(pfx + 'Start')
+
+
 class Protocol(ipdl.ast.Protocol):
     def cxxTypedefs(self):
         return self.decl.cxxtypedefs
 
     def channelSel(self):
         if self.decl.type.isToplevel():  return '.'
         return '->'
 
@@ -1192,26 +1181,33 @@ class Protocol(ipdl.ast.Protocol):
         return ExprCall(ExprVar('Id'))
 
     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')
+        return _stateType(self.decl.type.hasReentrantDelete)
 
     def startState(self):
-        return _startState(self.decl.type)
+        return _startState(self.decl.type.hasReentrantDelete)
 
     def nullState(self):
-        return _nullState(self.decl.type)
+        pfx = self.fqStateType().name + '::'
+        return ExprVar(pfx + 'Null')
 
     def deadState(self):
-        return _deadState(self.decl.type)
+        pfx = self.fqStateType().name + '::'
+        return ExprVar(pfx + 'Dead')
+
+    def dyingState(self):
+        assert self.decl.type.hasReentrantDelete
+        pfx = self.fqStateType().name + '::'
+        return ExprVar(pfx + 'Dying')
 
     def managerVar(self, thisexpr=None):
         assert thisexpr is not None or not self.decl.type.isToplevel()
         mvar = ExprCall(ExprVar('Manager'), args=[])
         if thisexpr is not None:
             mvar = ExprCall(ExprSelect(thisexpr, '->', 'Manager'), args=[])
         return mvar
 
@@ -1565,28 +1561,16 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         ns = Namespace(self.protocol.name)
         self.hdrfile.addthing(_putInNamespaces(ns, p.namespaces))
         ns.addstmt(Whitespace.NL)
 
         edecl, edefn = _splitFuncDeclDefn(self.genEndpointFunc())
         ns.addstmts([ edecl, Whitespace.NL ])
         self.funcDefns.append(edefn)
 
-        # state information
-        stateenum = TypeEnum('State')
-        # NB: __Dead is the first state on purpose, so that it has
-        # value '0'
-        stateenum.addId(_deadState().name)
-        stateenum.addId(_nullState().name)
-        if self.protocol.decl.type.hasReentrantDelete:
-            stateenum.addId(_dyingState().name)
-        stateenum.addId(_startState().name, _nullState().name)
-
-        ns.addstmts([ StmtDecl(Decl(stateenum,'')), Whitespace.NL ])
-
         # spit out message type enum and classes
         msgenum = msgenums(self.protocol)
         ns.addstmts([ StmtDecl(Decl(msgenum, '')), Whitespace.NL ])
 
         tfDecl, tfDefn = _splitFuncDeclDefn(self.genTransitionFunc())
         ns.addstmts([ tfDecl, Whitespace.NL ])
         self.funcDefns.append(tfDefn)
 
@@ -1651,51 +1635,51 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         # bool Transition(MessageType msg, State* next)
         # The state we are transitioning from is stored in *next.
         msgtypevar = ExprVar('msg')
         nextvar = ExprVar('next')
 
         transitionfunc = FunctionDefn(FunctionDecl(
             'Transition',
             params=[ Decl(Type('MessageType'), msgtypevar.name),
-                     Decl(Type('State', ptr=1), nextvar.name) ],
+                     Decl(Type(self.protocol.fqStateType().name, ptr=1), nextvar.name) ],
             ret=Type.VOID))
 
         fromswitch = StmtSwitch(ExprDeref(nextvar))
 
         # special case for Null
         nullerrorblock = Block()
         if ptype.hasDelete:
             ifdelete = StmtIf(ExprBinary(_deleteId(), '==', msgtypevar))
             if ptype.hasReentrantDelete:
-                nextState = _dyingState()
+                nextState = self.protocol.dyingState()
             else:
-                nextState = _deadState()
+                nextState = self.protocol.deadState()
             ifdelete.addifstmt(
                 StmtExpr(ExprAssn(ExprDeref(nextvar), nextState)))
             nullerrorblock.addstmt(ifdelete)
         nullerrorblock.addstmt(StmtBreak())
-        fromswitch.addcase(CaseLabel(_nullState().name), nullerrorblock)
+        fromswitch.addcase(CaseLabel(self.protocol.nullState().name), nullerrorblock)
 
         # special case for Dead
         deadblock = Block()
         deadblock.addstmts([
             _logicError('__delete__()d actor'),
             StmtBreak() ])
-        fromswitch.addcase(CaseLabel(_deadState().name), deadblock)
+        fromswitch.addcase(CaseLabel(self.protocol.deadState().name), deadblock)
 
         # special case for Dying
         if ptype.hasReentrantDelete:
             dyingblock = Block()
             ifdelete = StmtIf(ExprBinary(_deleteReplyId(), '==', msgtypevar))
             ifdelete.addifstmt(
-                StmtExpr(ExprAssn(ExprDeref(nextvar), _deadState())))
+                StmtExpr(ExprAssn(ExprDeref(nextvar), self.protocol.deadState())))
             dyingblock.addstmt(ifdelete)
             dyingblock.addstmt(StmtBreak())
-            fromswitch.addcase(CaseLabel(_dyingState().name), dyingblock)
+            fromswitch.addcase(CaseLabel(self.protocol.dyingState().name), dyingblock)
 
         unreachedblock = Block()
         unreachedblock.addstmts([
             _logicError('corrupted actor state'),
             StmtBreak() ])
         fromswitch.addcase(DefaultLabel(), unreachedblock)
 
         transitionfunc.addstmt(fromswitch)
@@ -3056,16 +3040,19 @@ 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', '"mozilla/ipc/MessageChannel.h"'),
             Whitespace.NL ])
+        self.hdrfile.addthings([
+            CppDirective('include', '"mozilla/ipc/ProtocolUtils.h"'),
+            Whitespace.NL ])
 
         hasAsyncReturns = False
         for md in p.messageDecls:
             if md.hasAsyncReturns():
                 hasAsyncReturns = True
                 break
 
         inherits = []
@@ -3122,18 +3109,16 @@ class _GenerateProtocolActorCode(ipdl.as
         self.cls.addstmt(Label.PROTECTED)
         for typedef in p.cxxTypedefs():
             self.cls.addstmt(typedef)
         for typedef in self.includedActorTypedefs:
             self.cls.addstmt(typedef)
 
         self.cls.addstmt(Whitespace.NL)
 
-        self.cls.addstmts([ Typedef(p.fqStateType(), 'State'), Whitespace.NL ])
-
         if hasAsyncReturns:
             self.cls.addstmt(Label.PUBLIC)
             for md in p.messageDecls:
                 if self.sendsMessage(md) and md.hasAsyncReturns():
                     self.cls.addstmt(
                         Typedef(_makePromise(md.returns, self.side),
                                 md.promiseName()))
                 if self.receivesMessage(md) and md.hasAsyncReturns():
@@ -3395,17 +3380,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
                 method.addstmts([ routedecl, routeif, Whitespace.NL ])
 
             # in the event of an Interrupt delete message, we want to loudly complain about
             # messages that are received that are not a reply to the original message
             if ptype.hasReentrantDelete:
                 msgVar = ExprVar(params[0].name)
                 ifdying = StmtIf(ExprBinary(
-                    ExprBinary(ExprVar('mState'), '==', _dyingState(ptype)),
+                    ExprBinary(ExprVar('mState'), '==', self.protocol.dyingState()),
                     '&&',
                     ExprBinary(
                         ExprBinary(ExprCall(ExprSelect(msgVar, '.', 'is_reply')), '!=', ExprLiteral.TRUE),
                         '||',
                         ExprBinary(ExprCall(ExprSelect(msgVar, '.', 'is_interrupt')), '!=', ExprLiteral.TRUE))))
                 ifdying.addifstmts([_fatalError('incoming message racing with actor deletion'),
                                     StmtReturn(_Result.Processed)])
                 method.addstmt(ifdying)
@@ -3614,17 +3599,17 @@ class _GenerateProtocolActorCode(ipdl.as
         # we're toplevel
         self.cls.addstmts([ deallocsubtree, Whitespace.NL ])
 
         if ptype.isToplevel():
             deallocself = MethodDefn(MethodDecl(deallocselfvar.name, methodspec=MethodSpec.VIRTUAL))
             self.cls.addstmts([ deallocself, Whitespace.NL ])
 
         ## private members
-        self.cls.addstmt(StmtDecl(Decl(Type('State'), p.stateVar().name)))
+        self.cls.addstmt(StmtDecl(Decl(self.protocol.fqStateType(), p.stateVar().name)))
 
         for managed in ptype.manages:
             self.cls.addstmts([
                 StmtDecl(Decl(
                     p.managedVarType(managed, self.side),
                     p.managedVar(managed, self.side).name)) ])
 
     def implementManagerIface(self):
@@ -3897,17 +3882,17 @@ class _GenerateProtocolActorCode(ipdl.as
         return [
             self.failIfNullActor(actorvar, errfn, msg="Error constructing actor %s" % actortype.name() + self.side.capitalize()),
             StmtExpr(setmanager),
             StmtExpr(_callInsertManagedActor(
                 self.protocol.managedVar(md.decl.type.constructedType(),
                                          self.side),
                 actorvar)),
             StmtExpr(ExprAssn(_actorState(actorvar),
-                              _startState(actorproto, fq=1)))
+                              _startState(md.decl.type.cdtype.hasReentrantDelete)))
         ]
 
     def failCtorIf(self, md, cond):
         actorvar = md.actorDecl().var()
         type = md.decl.type.constructedType()
         failif = StmtIf(cond)
 
         if self.side=='child':