Bug 1323532 - Part 2 - don't codegen Transition functions in ipdl, just statically define the two variants we need; r=froydnj
authorAlex Gaynor <agaynor@mozilla.com>
Mon, 30 Apr 2018 17:10:27 -0400
changeset 472530 e8097237f4be577ec43a6c03669d57de7a221b5b
parent 472529 4c6d8b9e3b3b4fd3a7a019489b7d781bcda9c5f5
child 472531 487a4df356a361400b2f7e5822005e2eacd337a1
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1323532
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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):