Bug 1323532 - Part 2 - don't codegen Transition functions in ipdl, just statically define the two variants we need; r?froydnj draft
authorAlex Gaynor <agaynor@mozilla.com>
Mon, 30 Apr 2018 17:10:27 -0400
changeset 790203 2bdb0aea243f37c4fc2acfb0925f675797263d13
parent 790202 8d105e2ac9a2901ca940d8d2100624e66036879e
push id108448
push userbmo:agaynor@mozilla.com
push dateTue, 01 May 2018 16:45:22 +0000
reviewersfroydnj
bugs1323532
milestone61.0a1
Bug 1323532 - Part 2 - don't codegen Transition functions in ipdl, just statically define the two variants we need; r?froydnj MozReview-Commit-ID: GdATc0Wdsxi
ipc/glue/ProtocolUtils.cpp
ipc/glue/ProtocolUtils.h
ipc/ipdl/ipdl/lower.py
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -350,16 +350,59 @@ ArrayLengthReadError(const char* aElemen
 
 void
 SentinelReadError(const char* aClassName)
 {
   MOZ_CRASH_UNSAFE_PRINTF("incorrect sentinel when reading %s", aClassName);
 }
 
 void
+StateTransition(bool aIsDelete, State* aNext)
+{
+  switch (*aNext) {
+    case State::Null:
+      if (aIsDelete) {
+        *aNext = State::Dead;
+      }
+      break;
+    case State::Dead:
+      LogicError("__delete__()d actor");
+      break;
+    default:
+      LogicError("corrupted actor state");
+      break;
+  }
+}
+
+void
+ReEntrantDeleteStateTransition(bool aIsDelete,
+                               bool aIsDeleteReply,
+                               ReEntrantDeleteState* aNext)
+{
+  switch (*aNext) {
+    case ReEntrantDeleteState::Null:
+      if (aIsDelete) {
+        *aNext = ReEntrantDeleteState::Dying;
+      }
+      break;
+    case ReEntrantDeleteState::Dead:
+      LogicError("__delete__()d actor");
+      break;
+    case ReEntrantDeleteState::Dying:
+      if (aIsDeleteReply) {
+        *aNext = ReEntrantDeleteState::Dead;
+      }
+      break;
+    default:
+      LogicError("corrupted actor state");
+      break;
+  }
+}
+
+void
 TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
              nsTArray<void*>& aArray)
 {
   uint32_t i = 0;
   void** elements = aArray.AppendElements(aTable.Count());
   for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
     elements[i] = iter.Get()->GetKey();
     ++i;
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -126,28 +126,16 @@ 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,
@@ -757,16 +745,39 @@ DuplicateHandle(HANDLE aSourceHandle,
 #endif
 
 /**
  * Annotate the crash reporter with the error code from the most recent system
  * call. Returns the system error.
  */
 void AnnotateSystemError();
 
+enum class State
+{
+  Dead,
+  Null,
+  Start = Null
+};
+
+void
+StateTransition(bool aIsDelete, State* aNext);
+
+enum class ReEntrantDeleteState
+{
+  Dead,
+  Null,
+  Dying,
+  Start = Null,
+};
+
+void
+ReEntrantDeleteStateTransition(bool aIsDelete,
+                               bool aIsDeleteReply,
+                               ReEntrantDeleteState* aNext);
+
 /**
  * An endpoint represents one end of a partially initialized IPDL channel. To
  * set up a new top-level protocol:
  *
  * Endpoint<PFooParent> parentEp;
  * Endpoint<PFooChild> childEp;
  * nsresult rv;
  * rv = PFoo::CreateEndpoints(parentPid, childPid, &parentEp, &childEp);
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1565,20 +1565,16 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         edecl, edefn = _splitFuncDeclDefn(self.genEndpointFunc())
         ns.addstmts([ edecl, Whitespace.NL ])
         self.funcDefns.append(edefn)
 
         # 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)
-
         for md in p.messageDecls:
             decls = []
 
             # Look up the segment capacity used for serializing this
             # message. If the capacity is not specified, use '0' for
             # the default capacity (defined in ipc_message.cc)
             name = '%s::%s' % (md.namespace, md.decl.progname)
             segmentcapacity = self.segmentcapacitydict.get(name, 0)
@@ -1624,72 +1620,16 @@ class _GenerateProtocolCode(ipdl.ast.Vis
             ExprVar('mozilla::ipc::CreateEndpoints'),
             args=[ _backstagePass(),
                    parentpidvar, childpidvar,
                    parentvar, childvar
                    ])))
         return openfunc
 
 
-    def genTransitionFunc(self):
-        ptype = self.protocol.decl.type
-
-        # 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(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 = self.protocol.dyingState()
-            else:
-                nextState = self.protocol.deadState()
-            ifdelete.addifstmt(
-                StmtExpr(ExprAssn(ExprDeref(nextvar), nextState)))
-            nullerrorblock.addstmt(ifdelete)
-        nullerrorblock.addstmt(StmtBreak())
-        fromswitch.addcase(CaseLabel(self.protocol.nullState().name), nullerrorblock)
-
-        # special case for Dead
-        deadblock = Block()
-        deadblock.addstmts([
-            _logicError('__delete__()d actor'),
-            StmtBreak() ])
-        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), self.protocol.deadState())))
-            dyingblock.addstmt(ifdelete)
-            dyingblock.addstmt(StmtBreak())
-            fromswitch.addcase(CaseLabel(self.protocol.dyingState().name), dyingblock)
-
-        unreachedblock = Block()
-        unreachedblock.addstmts([
-            _logicError('corrupted actor state'),
-            StmtBreak() ])
-        fromswitch.addcase(DefaultLabel(), unreachedblock)
-
-        transitionfunc.addstmt(fromswitch)
-
-        return transitionfunc
 
 ##--------------------------------------------------
 
 def _generateMessageConstructor(md, segmentSize, protocol, forReply=False):
     if forReply:
         clsname = md.replyCtorFunc()
         msgid = md.replyId()
         replyEnum = 'REPLY'
@@ -4683,23 +4623,38 @@ class _GenerateProtocolActorCode(ipdl.as
             # avoid unused-variable warnings
             saveIdStmts = [ StmtDecl(Decl(_actorIdType(), idvar.name),
                                      self.protocol.routingId()) ]
         else:
             saveIdStmts = [ ]
         return idvar, saveIdStmts
 
     def transition(self, md, actor=None, reply=False):
-        if actor is not None:  stateexpr = _actorState(actor)
-        else:                  stateexpr = self.protocol.stateVar()
-
         msgid = md.pqMsgId() if not reply else md.pqReplyId()
-        return [ StmtExpr(ExprCall(ExprVar(self.protocol.name +'::Transition'),
-                                   args=[ ExprVar(msgid),
-                                   ExprAddrOf(stateexpr) ])) ]
+        args = [
+            ExprVar('true' if _deleteId().name == msgid else 'false'),
+        ]
+        if self.protocol.decl.type.hasReentrantDelete:
+            function = 'ReEntrantDeleteStateTransition'
+            args.append(
+                ExprVar('true' if _deleteReplyId().name == msgid else 'false'),
+            )
+        else:
+            function = 'StateTransition'
+
+        if actor is not None:
+            stateexpr = _actorState(actor)
+        else:
+            stateexpr = self.protocol.stateVar()
+
+        args.append(ExprAddrOf(stateexpr))
+
+        return [
+            StmtExpr(ExprCall(ExprVar(function), args=args))
+        ]
 
     def endRead(self, msgexpr, iterexpr):
         msgtype = ExprCall(ExprSelect(msgexpr, '.', 'type'), [ ])
         return StmtExpr(ExprCall(ExprSelect(msgexpr, '.', 'EndRead'),
                                  args=[ iterexpr, msgtype ]))
 
 class _GenerateProtocolParentCode(_GenerateProtocolActorCode):
     def __init__(self):