Bug 1316757, part 7 - Remove IPDL state machine from frontend. r=billm draft
authorAndrew McCreight <continuation@gmail.com>
Wed, 23 Nov 2016 15:04:09 -0800
changeset 449302 fc18900507d531c8b4644973e9e23755bcc844d6
parent 449301 5adad1374174cda402f15ff602be02de836ae495
child 539471 40df942c993ecf695acd455912853abbf426d2c2
push id38540
push userbmo:continuation@gmail.com
push dateTue, 13 Dec 2016 21:31:40 +0000
reviewersbillm
bugs1316757
milestone53.0a1
Bug 1316757, part 7 - Remove IPDL state machine from frontend. r=billm This patch removes all user-specified state machine support from the IPDL parser, then deletes all of the code related to it from the AST, type checking, and code generation. The default state machine code relating to tracking whether the protocol is dead or not will still be generated. In fact, this patch should not change the code that is generated for any protocol that does not use the custom state machine syntax. MozReview-Commit-ID: 1fABHR3zJx
ipc/ipdl/ipdl/ast.py
ipc/ipdl/ipdl/cgen.py
ipc/ipdl/ipdl/lower.py
ipc/ipdl/ipdl/parser.py
ipc/ipdl/ipdl/type.py
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -63,18 +63,16 @@ class Visitor:
         for opens in p.opensStmts:
             opens.accept(self)
         for mgr in p.managers:
             mgr.accept(self)
         for managed in p.managesStmts:
             managed.accept(self)
         for msgDecl in p.messageDecls:
             msgDecl.accept(self)
-        for transitionStmt in p.transitionStmts:
-            transitionStmt.accept(self)
 
     def visitNamespace(self, ns):
         pass
 
     def visitSpawnsStmt(self, spawns):
         pass
 
     def visitBridgesStmt(self, bridges):
@@ -90,28 +88,16 @@ class Visitor:
         pass
 
     def visitMessageDecl(self, md):
         for inParam in md.inParams:
             inParam.accept(self)
         for outParam in md.outParams:
             outParam.accept(self)
 
-    def visitTransitionStmt(self, ts):
-        ts.state.accept(self)
-        for trans in ts.transitions:
-            trans.accept(self)
-
-    def visitTransition(self, t):
-        for toState in t.toStates:
-            toState.accept(self)
-
-    def visitState(self, s):
-        pass
-
     def visitParam(self, decl):
         pass
 
     def visitTypeSpec(self, ts):
         pass
 
     def visitDecl(self, d):
         pass
@@ -241,18 +227,16 @@ class Protocol(NamespacedNode):
         self.sendSemantics = ASYNC
         self.nested = NOT_NESTED
         self.spawnsStmts = [ ]
         self.bridgesStmts = [ ]
         self.opensStmts = [ ]
         self.managers = [ ]
         self.managesStmts = [ ]
         self.messageDecls = [ ]
-        self.transitionStmts = [ ]
-        self.startStates = [ ]
 
 class StructField(Node):
     def __init__(self, loc, type, name):
         Node.__init__(self, loc)
         self.typespec = type
         self.name = name
 
 class StructDecl(NamespacedNode):
@@ -317,93 +301,16 @@ class MessageDecl(Node):
         for modifier in modifiers:
             if modifier.startswith('compress'):
                 self.compress = modifier
             elif modifier == 'verify':
                 self.verify = modifier
             elif modifier != '':
                 raise Exception, "Unexpected message modifier `%s'"% modifier
 
-class Transition(Node):
-    def __init__(self, loc, trigger, msg, toStates):
-        Node.__init__(self, loc)
-        self.trigger = trigger
-        self.msg = msg
-        self.toStates = toStates
-
-    def __cmp__(self, o):
-        c = cmp(self.msg, o.msg)
-        if c: return c
-        c = cmp(self.trigger, o.trigger)
-        if c: return c
-
-    def __hash__(self): return hash(str(self))
-    def __str__(self): return '%s %s'% (self.trigger, self.msg)
-
-    @staticmethod
-    def nameToTrigger(name):
-        return { 'send': SEND, 'recv': RECV, 'call': CALL, 'answer': ANSWER }[name]
-
-Transition.NULL = Transition(Loc.NONE, None, None, [ ])
-
-class TransitionStmt(Node):
-    def __init__(self, loc, state, transitions):
-        Node.__init__(self, loc)
-        self.state = state
-        self.transitions = transitions
-
-    @staticmethod
-    def makeNullStmt(state):
-        return TransitionStmt(Loc.NONE, state, [ Transition.NULL ])
-
-class SEND:
-    pretty = 'send'
-    @classmethod
-    def __hash__(cls): return hash(cls.pretty)
-    @classmethod
-    def direction(cls): return OUT
-class RECV:
-    pretty = 'recv'
-    @classmethod
-    def __hash__(cls): return hash(cls.pretty)
-    @classmethod
-    def direction(cls): return IN
-class CALL:
-    pretty = 'call'
-    @classmethod
-    def __hash__(cls): return hash(cls.pretty)
-    @classmethod
-    def direction(cls): return OUT
-class ANSWER:
-    pretty = 'answer'
-    @classmethod
-    def __hash__(cls): return hash(cls.pretty)
-    @classmethod
-    def direction(cls): return IN
-
-class State(Node):
-    def __init__(self, loc, name, start=False):
-        Node.__init__(self, loc)
-        self.name = name
-        self.start = start
-    def __eq__(self, o):
-         return (isinstance(o, State)
-                 and o.name == self.name
-                 and o.start == self.start)
-    def __hash__(self):
-        return hash(repr(self))
-    def __ne__(self, o):
-        return not (self == o)
-    def __repr__(self): return '<State %r start=%r>'% (self.name, self.start)
-    def __str__(self): return '<State %s start=%s>'% (self.name, self.start)
-
-State.ANY = State(Loc.NONE, '[any]', start=True)
-State.DEAD = State(Loc.NONE, '[dead]', start=False)
-State.DYING = State(Loc.NONE, '[dying]', start=False)
-
 class Param(Node):
     def __init__(self, loc, typespec, name):
         Node.__init__(self, loc)
         self.name = name
         self.typespec = typespec
 
 class TypeSpec(Node):
     def __init__(self, loc, spec):
--- a/ipc/ipdl/ipdl/cgen.py
+++ b/ipc/ipdl/ipdl/cgen.py
@@ -46,35 +46,33 @@ Also known as pretty-printing.'''
         self.println('include "'+ inc.file +'";')
 
     def visitProtocolInclude(self, inc):
         self.println('include protocol "'+ inc.file +'";')
         if inc.tu.filename not in self.printed:
             self.println('/* Included file:')
             IPDLCodeGen(outf=self.outf, indentCols=self.indentCols,
                         printed=self.printed).visitTranslationUnit(inc.tu)
-        
+
             self.println('*/')
 
     def visitProtocol(self, p):
         self.println()
         for namespace in p.namespaces:  namespace.accept(self)
 
         self.println('%s protocol %s\n{'% (p.sendSemantics[0], p.name))
         self.indent()
 
         for mgs in p.managesStmts:
             mgs.accept(self)
         if len(p.managesStmts):  self.println()
 
         for msgDecl in p.messageDecls:  msgDecl.accept(self)
         self.println()
 
-        for transStmt in p.transitionStmts:  transStmt.accept(self)
-
         self.dedent()
         self.println('}')
         self.write('}\n'* len(p.namespaces))
 
     def visitManagerStmt(self, mgr):
         self.printdentln('manager '+ mgr.name +';')
 
     def visitManagesStmt(self, mgs):
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1335,20 +1335,16 @@ with some new IPDL/C++ nodes that are tu
         return _HybridDecl(decl.type, decl.progname)
 
     def visitMessageDecl(self, md):
         md.namespace = self.protocolName
         md.params = [ param.accept(self) for param in md.inParams ]
         md.returns = [ ret.accept(self) for ret in md.outParams ]
         MessageDecl.upgrade(md)
 
-    def visitTransitionStmt(self, ts):
-        name = ts.state.decl.progname
-        ts.state.decl.cxxname = name
-        ts.state.decl.cxxenum = ExprVar(self.protocolName +'::'+ name)
 
 ##-----------------------------------------------------------------------------
 
 def msgenums(protocol, pretty=False):
     msgenum = TypeEnum('MessageType')
     msgstart = _messageStartName(protocol.decl.type) +' << 16'
     msgenum.addId(protocol.name + 'Start', msgstart)
 
@@ -1545,23 +1541,17 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         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)
         stateenum.addId(_errorState().name)
         if self.protocol.decl.type.hasReentrantDelete:
             stateenum.addId(_dyingState().name)
-        for ts in p.transitionStmts:
-            stateenum.addId(ts.state.decl.cxxname)
-        if len(p.transitionStmts):
-            startstate = p.transitionStmts[0].state.decl.cxxname
-        else:
-            startstate = _nullState().name
-        stateenum.addId(_startState().name, startstate)
+        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())
@@ -1676,80 +1666,31 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         return openfunc
 
 
     def genTransitionFunc(self):
         ptype = self.protocol.decl.type
         usesend, sendvar = set(), ExprVar('Send__')
         userecv, recvvar = set(), ExprVar('Recv__')
 
-        def sameTrigger(trigger, actionexpr):
-            if trigger is ipdl.ast.SEND or trigger is ipdl.ast.CALL:
-                usesend.add('yes')
-                return ExprBinary(sendvar, '==', actionexpr)
-            else:
-                userecv.add('yes')
-                return ExprBinary(recvvar, '==',
-                                  actionexpr)
-
-        def stateEnum(s):
-            if s is ipdl.ast.State.DEAD:
-                return _deadState()
-            else:
-                return ExprVar(s.decl.cxxname)
-
         # bool Transition(Trigger trigger, State* next)
         # The state we are transitioning from is stored in *next.
         fromvar = ExprVar('from')
         triggervar = ExprVar('trigger')
         nextvar = ExprVar('next')
         msgexpr = ExprSelect(triggervar, '.', 'mMessage')
-        actionexpr = ExprSelect(triggervar, '.', 'mAction')
 
         transitionfunc = FunctionDefn(FunctionDecl(
             'Transition',
             params=[ Decl(Type('mozilla::ipc::Trigger'), triggervar.name),
                      Decl(Type('State', ptr=1), nextvar.name) ],
             ret=Type.BOOL))
 
         fromswitch = StmtSwitch(fromvar)
 
-        for ts in self.protocol.transitionStmts:
-            msgswitch = StmtSwitch(msgexpr)
-
-            msgToTransitions = { }
-
-            for t in ts.transitions:
-                msgid = t.msg._md.msgId()
-
-                ifsametrigger = StmtIf(sameTrigger(t.trigger, actionexpr))
-                # FIXME multi-out states
-                for nextstate in t.toStates: break
-                ifsametrigger.addifstmts([
-                    StmtExpr(ExprAssn(ExprDeref(nextvar),
-                                      stateEnum(nextstate))),
-                    StmtReturn(ExprLiteral.TRUE)
-                ])
-
-                transitions = msgToTransitions.get(msgid, [ ])
-                transitions.append(ifsametrigger)
-                msgToTransitions[msgid] = transitions
-
-            for msgid, transitions in msgToTransitions.iteritems():
-                block = Block()
-                block.addstmts(transitions +[ StmtBreak() ])
-                msgswitch.addcase(CaseLabel(msgid), block)
-
-            msgblock = Block()
-            msgblock.addstmts([
-                msgswitch,
-                StmtBreak()
-            ])
-            fromswitch.addcase(CaseLabel(ts.state.decl.cxxname), msgblock)
-
         # special cases for Null and Error
         nullerrorblock = Block()
         if ptype.hasDelete:
             ifdelete = StmtIf(ExprBinary(_deleteId(), '==', msgexpr))
             if ptype.hasReentrantDelete:
                 nextState = _dyingState()
             else:
                 nextState = _deadState()
@@ -1795,23 +1736,16 @@ class _GenerateProtocolCode(ipdl.ast.Vis
                 StmtDecl(Decl(Type('int32_t', const=1), recvvar.name),
                          init=ExprVar('mozilla::ipc::Trigger::Recv')))
         if usesend or userecv:
             transitionfunc.addstmt(Whitespace.NL)
 
         transitionfunc.addstmt(StmtDecl(Decl(Type('State'), fromvar.name),
                                         init=ExprDeref(nextvar)))
         transitionfunc.addstmt(fromswitch)
-        # all --> Error transitions break to here.  But only insert this
-        # block if there is any possibility of such transitions.
-        if self.protocol.transitionStmts:
-            transitionfunc.addstmts([
-                StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
-                StmtReturn(ExprLiteral.FALSE),
-            ])
 
         return transitionfunc
 
 ##--------------------------------------------------
 
 def _generateMessageConstructor(clsname, msgid, nested, prio, prettyName, compress):
     routingId = ExprVar('routingId')
 
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -100,48 +100,41 @@ class Parser:
 
 def locFromTok(p, num):
     return Loc(Parser.current.filename, p.lineno(num))
 
 
 ##-----------------------------------------------------------------------------
 
 reserved = set((
-        'answer',
         'as',
         'async',
         'both',
         'bridges',
-        'call',
         'child',
         'class',
         'compress',
         'compressall',
         '__delete__',
         'delete',                       # reserve 'delete' to prevent its use
         'from',
-        'goto',
         'include',
         'intr',
         'manager',
         'manages',
         'namespace',
         'nested',
         'nullable',
         'opens',
         'or',
         'parent',
         'prio',
         'protocol',
-        'recv',
         'returns',
-        'send',
         'spawns',
-        'start',
-        'state',
         'struct',
         'sync',
         'union',
         'upto',
         'using',
         'verify'))
 tokens = [
     'COLONCOLON', 'ID', 'STRING',
@@ -455,19 +448,20 @@ def p_ManagesStmt(p):
     p[0] = ManagesStmt(locFromTok(p, 1), p[2])
 
 
 ##--------------------
 ## Message decls
 
 def p_MessageDeclsOpt(p):
     """MessageDeclsOpt : MessageDeclThing MessageDeclsOpt
-                       | TransitionStmtsOpt"""
-    if 2 == len(p):
-        p[0] = p[1]
+                       | """
+    if 1 == len(p):
+        # we fill in |loc| in the Protocol rule
+        p[0] = Protocol(None)
     else:
         p[2].messageDecls.insert(0, p[1])
         p[0] = p[2]
 
 def p_MessageDeclThing(p):
     """MessageDeclThing : MessageDirectionLabel ':' MessageDecl ';'
                         | MessageDecl ';'"""
     if 3 == len(p):
@@ -555,81 +549,16 @@ def p_MessageVerify(p):
     """MessageVerify : VERIFY"""
     p[0] = p[1]
 
 def p_MessageCompress(p):
     """MessageCompress : COMPRESS
                        | COMPRESSALL"""
     p[0] = p[1]
 
-##--------------------
-## State machine
-
-def p_TransitionStmtsOpt(p):
-    """TransitionStmtsOpt : TransitionStmt TransitionStmtsOpt
-                          |"""
-    if 1 == len(p):
-        # we fill in |loc| in the Protocol rule
-        p[0] = Protocol(None)
-    else:
-        p[2].transitionStmts.insert(0, p[1])
-        p[0] = p[2]
-
-def p_TransitionStmt(p):
-    """TransitionStmt : OptionalStart STATE State ':' Transitions"""
-    p[3].start = p[1]
-    p[0] = TransitionStmt(locFromTok(p, 2), p[3], p[5])
-
-def p_OptionalStart(p):
-    """OptionalStart : START
-                     | """
-    p[0] = (len(p) == 2)                # True iff 'start' specified
-
-def p_Transitions(p):
-    """Transitions : Transitions Transition
-                   | Transition"""
-    if 3 == len(p):
-        p[1].append(p[2])
-        p[0] = p[1]
-    else:
-        p[0] = [ p[1] ]
-
-def p_Transition(p):
-    """Transition : Trigger ID GOTO StateList ';'
-                  | Trigger __DELETE__ ';'
-                  | Trigger DELETE ';'"""
-    if 'delete' == p[2]:
-        _error(locFromTok(p, 1), "`delete' is a reserved identifier")
-
-    loc, trigger = p[1]
-    if 6 == len(p):
-        nextstates = p[4]
-    else:
-        nextstates = [ State.DEAD ]
-    p[0] = Transition(loc, trigger, p[2], nextstates)
-
-def p_Trigger(p):
-    """Trigger : SEND
-               | RECV
-               | CALL
-               | ANSWER"""
-    p[0] = [ locFromTok(p, 1), Transition.nameToTrigger(p[1]) ]
-
-def p_StateList(p):
-    """StateList : StateList OR State
-                 | State"""
-    if 2 == len(p):
-        p[0] = [ p[1] ]
-    else:
-        p[1].append(p[3])
-        p[0] = p[1]
-
-def p_State(p):
-    """State : ID"""
-    p[0] = State(locFromTok(p, 1), p[1])
 
 ##--------------------
 ## Minor stuff
 def p_Nested(p):
     """Nested : ID"""
     kinds = {'not': 1,
              'inside_sync': 2,
              'inside_cpow': 3}
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -1,36 +1,30 @@
 # vim: set ts=4 sw=4 tw=99 et:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os, sys
 
-from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, StructDecl, TransitionStmt
+from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, StructDecl
 from ipdl.ast import TypeSpec, UnionDecl, UsingStmt, Visitor
 from ipdl.ast import ASYNC, SYNC, INTR
-from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
+from ipdl.ast import IN, OUT, INOUT
 from ipdl.ast import NOT_NESTED, INSIDE_SYNC_NESTED, INSIDE_CPOW_NESTED
 import ipdl.builtin as builtin
 
 _DELETE_MSG = '__delete__'
 
 
 def _otherside(side):
     if side == 'parent':  return 'child'
     elif side == 'child': return 'parent'
     else:  assert 0 and 'unknown side "%s"'% (side)
 
-def unique_pairs(s):
-    n = len(s)
-    for i, e1 in enumerate(s):
-        for j in xrange(i+1, n):
-            yield (e1, s[j])
-
 def cartesian_product(s1, s2):
     for e1 in s1:
         for e2 in s2:
             yield (e1, e2)
 
 
 class TypeVisitor:
     def __init__(self):
@@ -44,35 +38,31 @@ class TypeVisitor:
         pass
 
     def visitBuiltinCxxType(self, t, *args):
         pass
 
     def visitImportedCxxType(self, t, *args):
         pass
 
-    def visitStateType(self, s, *args):
-        pass
-
     def visitMessageType(self, m, *args):
         for param in m.params:
             param.accept(self, *args)
         for ret in m.returns:
             ret.accept(self, *args)
         if m.cdtype is not None:
             m.cdtype.accept(self, *args)
 
     def visitProtocolType(self, p, *args):
         # NB: don't visit manager and manages. a naive default impl
         # could result in an infinite loop
         pass
 
     def visitActorType(self, a, *args):
         a.protocol.accept(self, *args)
-        a.state.accept(self, *args)
 
     def visitStructType(self, s, *args):
         if s in self.visited:
             return
 
         self.visited.add(s)
         for field in s.fields:
             field.accept(self, *args)
@@ -190,17 +180,16 @@ class ImportedCxxType(CxxType):
         return self.qname.baseid
     def fullname(self):
         return str(self.qname)
 
 ##--------------------
 class IPDLType(Type):
     def isIPDL(self):  return True
     def isVisible(self): return True
-    def isState(self): return False
     def isMessage(self): return False
     def isProtocol(self): return False
     def isActor(self): return False
     def isStruct(self): return False
     def isUnion(self): return False
     def isArray(self): return False
     def isAtom(self):  return True
     def isCompound(self): return False
@@ -233,27 +222,16 @@ class IPDLType(Type):
         elif greater.isInterrupt():
             return True
 
         return False
 
     def needsMoreJuiceThan(self, o):
         return not IPDLType.convertsTo(self, o)
 
-class StateType(IPDLType):
-    def __init__(self, protocol, name, start=False):
-        self.protocol = protocol
-        self.name = name
-        self.start = start
-    def isState(self): return True
-    def name(self):
-        return self.name
-    def fullname(self):
-        return self.name()
-
 class MessageType(IPDLType):
     def __init__(self, nested, prio, sendSemantics, direction,
                  ctor=False, dtor=False, cdtype=None, compress=False,
                  verify=False):
         assert not (ctor and dtor)
         assert not (ctor or dtor) or type is not None
 
         self.nested = nested
@@ -290,25 +268,24 @@ class Bridge:
     def __cmp__(self, o):
         return cmp(self.parent, o.parent) or cmp(self.child, o.child)
     def __eq__(self, o):
         return self.parent == o.parent and self.child == o.child
     def __hash__(self):
         return hash(self.parent) + hash(self.child)
 
 class ProtocolType(IPDLType):
-    def __init__(self, qname, nestedRange, sendSemantics, stateless=False):
+    def __init__(self, qname, nestedRange, sendSemantics):
         self.qname = qname
         self.nestedRange = nestedRange
         self.sendSemantics = sendSemantics
         self.spawns = set()             # ProtocolType
         self.opens = set()              # ProtocolType
         self.managers = []           # ProtocolType
         self.manages = [ ]
-        self.stateless = stateless
         self.hasDelete = False
         self.hasReentrantDelete = False
     def isProtocol(self): return True
 
     def name(self):
         return self.qname.baseid
     def fullname(self):
         return str(self.qname)
@@ -359,19 +336,18 @@ class ProtocolType(IPDLType):
     def isToplevel(self):
         return not self.isManaged()
 
     def manager(self):
         assert 1 == len(self.managers)
         for mgr in self.managers: return mgr
 
 class ActorType(IPDLType):
-    def __init__(self, protocol, state=None, nullable=0):
+    def __init__(self, protocol, nullable=0):
         self.protocol = protocol
-        self.state = state
         self.nullable = nullable
     def isActor(self): return True
 
     def name(self):
         return self.protocol.name()
     def fullname(self):
         return self.protocol.fullname()
 
@@ -634,20 +610,16 @@ With this information, it finally type c
         # now that the nodes have decls, type checking is much easier.
         if not runpass(CheckTypes(self.errors)):
             return False
 
         if not (runpass(BuildProcessGraph(self.errors))
                 and runpass(CheckProcessGraph(self.errors))):
             return False
 
-        if (tu.protocol
-            and len(tu.protocol.startStates)
-            and not runpass(CheckStateMachine(self.errors))):
-            return False
         return True
 
     def reportErrors(self, errout):
         for error in self.errors:
             print >>errout, error
 
 
 class TcheckVisitor(Visitor):
@@ -707,18 +679,17 @@ class GatherDecls(TcheckVisitor):
             # to put both the namespace and non-namespaced name in the
             # global scope.  try to figure out something better; maybe
             # a type-neutral |using| that works for C++ and protocol
             # types?
             qname = p.qname()
             fullname = str(qname)
             p.decl = self.declare(
                 loc=p.loc,
-                type=ProtocolType(qname, p.nestedRange, p.sendSemantics,
-                                  stateless=(0 == len(p.transitionStmts))),
+                type=ProtocolType(qname, p.nestedRange, p.sendSemantics),
                 shortname=p.name,
                 fullname=None if 0 == len(qname.quals) else fullname)
 
             p.parentEndpointDecl = self.declare(
                 loc=p.loc,
                 type=EndpointType(QualifiedId(p.loc, 'Endpoint<' + fullname + 'Parent>', ['mozilla', 'ipc'])),
                 shortname='Endpoint<' + p.name + 'Parent>')
             p.childEndpointDecl = self.declare(
@@ -921,104 +892,16 @@ class GatherDecls(TcheckVisitor):
             ctordecl = self.symtab.lookup(mgdname +'Constructor')
 
             if not (ctordecl and ctordecl.type.isCtor()):
                 self.error(
                     managed.loc,
                     "constructor declaration required for managed protocol `%s' (managed by protocol `%s')",
                     mgdname, p.name)
 
-        p.states = { }
-
-        if len(p.transitionStmts):
-            p.startStates = [ ts for ts in p.transitionStmts
-                              if ts.state.start ]
-            if 0 == len(p.startStates):
-                p.startStates = [ p.transitionStmts[0] ]
-
-        # declare implicit "any", "dead", and "dying" states
-        self.declare(loc=State.ANY.loc,
-                     type=StateType(p.decl.type, State.ANY.name, start=False),
-                     progname=State.ANY.name)
-        self.declare(loc=State.DEAD.loc,
-                     type=StateType(p.decl.type, State.DEAD.name, start=False),
-                     progname=State.DEAD.name)
-        if p.decl.type.hasReentrantDelete:
-            self.declare(loc=State.DYING.loc,
-                         type=StateType(p.decl.type, State.DYING.name, start=False),
-                         progname=State.DYING.name)
-
-        # declare each state before decorating their mention
-        for trans in p.transitionStmts:
-            p.states[trans.state] = trans
-            trans.state.decl = self.declare(
-                loc=trans.state.loc,
-                type=StateType(p.decl.type, trans.state, trans.state.start),
-                progname=trans.state.name)
-
-        for trans in p.transitionStmts:
-            self.seentriggers = set()
-            trans.accept(self)
-
-        if not (p.decl.type.stateless
-                or (p.decl.type.isToplevel()
-                    and None is self.symtab.lookup(_DELETE_MSG))):
-            # add a special state |state DEAD: null goto DEAD;|
-            deadtrans = TransitionStmt.makeNullStmt(State.DEAD)
-            p.states[State.DEAD] = deadtrans
-            if p.decl.type.hasReentrantDelete:
-                dyingtrans = TransitionStmt.makeNullStmt(State.DYING)
-                p.states[State.DYING] = dyingtrans
-
-        # visit the message decls once more and resolve the state names
-        # attached to actor params and returns
-        def resolvestate(loc, actortype):
-            assert actortype.isIPDL() and actortype.isActor()
-
-            # already resolved this guy's state
-            if isinstance(actortype.state, Decl):
-                return
-
-            if actortype.state is None:
-                # we thought this was a C++ type until type checking,
-                # when we realized it was an IPDL actor type.  But
-                # that means that the actor wasn't specified to be in
-                # any particular state
-                actortype.state = State.ANY
-
-            statename = actortype.state.name
-            # FIXME/cjones: this is just wrong.  we need the symbol table
-            # of the protocol this actor refers to.  low priority bug
-            # since nobody's using this feature yet
-            statedecl = self.symtab.lookup(statename)
-            if statedecl is None:
-                self.error(
-                    loc,
-                    "protocol `%s' does not have the state `%s'",
-                    actortype.protocol.name(),
-                    statename)
-            elif not statedecl.type.isState():
-                self.error(
-                    loc,
-                    "tag `%s' is supposed to be of state type, but is instead of type `%s'",
-                    statename,
-                    statedecl.type.typename())
-            else:
-                actortype.state = statedecl.type
-
-        for msg in p.messageDecls:
-            for iparam in msg.inParams:
-                loc = iparam.loc
-                for actortype in iteractortypes(iparam.type):
-                    resolvestate(loc, actortype)
-            for oparam in msg.outParams:
-                loc = oparam.loc
-                for actortype in iteractortypes(oparam.type):
-                    resolvestate(loc, actortype)
-
         # FIXME/cjones declare all the little C++ thingies that will
         # be generated.  they're not relevant to IPDL itself, but
         # those ("invisible") symbols can clash with others in the
         # IPDL spec, and we'd like to catch those before C++ compilers
         # are allowed to obfuscate the error
 
         self.symtab.exitScope(p)
 
@@ -1158,66 +1041,16 @@ class GatherDecls(TcheckVisitor):
         md.decl = self.declare(
             loc=loc,
             type=msgtype,
             progname=msgname)
         md.protocolDecl = self.currentProtocolDecl
         md.decl._md = md
 
 
-    def visitTransitionStmt(self, ts):
-        self.seentriggers = set()
-        TcheckVisitor.visitTransitionStmt(self, ts)
-
-    def visitTransition(self, t):
-        loc = t.loc
-
-        # check the trigger message
-        mname = t.msg
-        if t in self.seentriggers:
-            self.error(loc, "trigger `%s' appears multiple times", t.msg)
-        self.seentriggers.add(t)
-
-        mdecl = self.symtab.lookup(mname)
-        if mdecl is not None and mdecl.type.isIPDL() and mdecl.type.isProtocol():
-            mdecl = self.symtab.lookup(mname +'Constructor')
-
-        if mdecl is None:
-            self.error(loc, "message `%s' has not been declared", mname)
-        elif not mdecl.type.isMessage():
-            self.error(
-                loc,
-                "`%s' should have message type, but instead has type `%s'",
-                mname, mdecl.type.typename())
-        else:
-            t.msg = mdecl
-
-        # check the to-states
-        seenstates = set()
-        for toState in t.toStates:
-            sname = toState.name
-            sdecl = self.symtab.lookup(sname)
-
-            if sname in seenstates:
-                self.error(loc, "to-state `%s' appears multiple times", sname)
-            seenstates.add(sname)
-
-            if sdecl is None:
-                self.error(loc, "state `%s' has not been declared", sname)
-            elif not sdecl.type.isState():
-                self.error(
-                    loc, "`%s' should have state type, but instead has type `%s'",
-                    sname, sdecl.type.typename())
-            else:
-                toState.decl = sdecl
-                toState.start = sdecl.type.start
-
-        t.toStates = set(t.toStates)
-
-
     def _canonicalType(self, itype, typespec):
         loc = typespec.loc
         if itype.isIPDL():
             if itype.isProtocol():
                 itype = ActorType(itype,
                                   nullable=typespec.nullable)
 
         if typespec.nullable and not (itype.isIPDL() and itype.isActor()):
@@ -1517,37 +1350,16 @@ class CheckTypes(TcheckVisitor):
 
         if mtype.isCtor() and not ptype.isManagerOf(mtype.constructedType()):
             self.error(
                 loc,
                 "ctor for protocol `%s', which is not managed by protocol `%s'",
                 mname[:-len('constructor')], pname)
 
 
-    def visitTransition(self, t):
-        _YNC = [ ASYNC, SYNC ]
-
-        loc = t.loc
-        impliedDirection, impliedSems = {
-            SEND: [ OUT, _YNC ], RECV: [ IN, _YNC ],
-            CALL: [ OUT, INTR ],  ANSWER: [ IN, INTR ],
-         } [t.trigger]
-
-        if (OUT is impliedDirection and t.msg.type.isIn()
-            or IN is impliedDirection and t.msg.type.isOut()
-            or _YNC is impliedSems and t.msg.type.isInterrupt()
-            or INTR is impliedSems and (not t.msg.type.isInterrupt())):
-            mtype = t.msg.type
-
-            self.error(
-                loc, "%s %s message `%s' is not `%s'd",
-                mtype.sendSemantics.pretty, mtype.direction.pretty,
-                t.msg.progname,
-                t.trigger.pretty)
-
 ##-----------------------------------------------------------------------------
 
 class Process:
     def __init__(self):
         self.actors = set()         # set(Actor)
         self.edges = { }            # Actor -> [ SpawnsEdge ]
         self.spawn = set()          # set(Actor)
 
@@ -1863,313 +1675,8 @@ class CheckProcessGraph(TcheckVisitor):
             print 'Bridges'
             for bridgeList in ProcessGraph.bridges.itervalues():
                 for bridge in bridgeList:
                     print '  ', bridge
             print 'Opens'
             for opensList in ProcessGraph.opens.itervalues():
                 for opens in opensList:
                     print '  ', opens
-
-##-----------------------------------------------------------------------------
-
-class CheckStateMachine(TcheckVisitor):
-    def __init__(self, errors):
-        # don't need the symbol table, we just want the error reporting
-        TcheckVisitor.__init__(self, None, errors)
-        self.p = None
-
-    def visitProtocol(self, p):
-        self.p = p
-        self.checkReachability(p)
-        for ts in p.transitionStmts:
-            ts.accept(self)
-
-    def visitTransitionStmt(self, ts):
-        # We want to disallow "race conditions" in protocols.  These
-        # can occur when a protocol state machine has a state that
-        # allows triggers of opposite direction.  That declaration
-        # allows the parent to send the child a message at the
-        # exact instance the child sends the parent a message.  One of
-        # those messages would (probably) violate the state machine
-        # and cause the child to be terminated.  It's obviously very
-        # nice if we can forbid this at the level of IPDL state
-        # machines, rather than resorting to static or dynamic
-        # checking of C++ implementation code.
-        #
-        # An easy way to avoid this problem in IPDL is to only allow
-        # "unidirectional" protocol states; that is, from each state,
-        # only send or only recv triggers are allowed.  This approach
-        # is taken by the Singularity project's "contract-based
-        # message channels."  However, this can be something of a
-        # notational burden for stateful protocols.
-        #
-        # If two messages race, the effect is that the parent's and
-        # child's states get temporarily out of sync.  Informally,
-        # IPDL allows this *only if* the state machines get out of
-        # sync for only *one* step (state machine transition), then
-        # sync back up.  This is a design decision: the states could
-        # be allowd to get out of sync for any constant k number of
-        # steps.  (If k is unbounded, there's no point in presenting
-        # the abstraction of parent and child actor states being
-        # "entangled".)  The working hypothesis is that the more steps
-        # the states are allowed to be out of sync, the harder it is
-        # to reason about the protocol.
-        #
-        # Slightly less informally, two messages are allowed to race
-        # only if processing them in either order leaves the protocol
-        # in the same state.  That is, messages A and B are allowed to
-        # race only if processing A then B leaves the protocol in
-        # state S, *and* processing B then A also leaves the protocol
-        # in state S.  Technically, if this holds, then messages A and
-        # B could be called "commutative" wrt to actor state.
-        #
-        # "Formally", state machine definitions must adhere to two
-        # rules.
-        #
-        #   *Rule 1*: from a state S, all sync triggers must be of the same
-        # "direction," i.e. only |send| or only |recv|
-        #
-        # (Pairs of sync messages can't commute, because otherwise
-        # deadlock can occur from simultaneously in-flight sync
-        # requests.)
-        #
-        #   *Rule 2*: the "Diamond Rule".
-        #   from a state S,
-        #     for any pair of triggers t1 and t2,
-        #         where t1 and t2 have opposite direction,
-        #         and t1 transitions to state T1 and t2 to T2,
-        #       then the following must be true:
-        #         (T2 allows the trigger t1, transitioning to state U)
-        #         and
-        #         (T1 allows the trigger t2, transitioning to state U)
-        #         and
-        #         (
-        #           (
-        #             (all of T1's triggers have the same direction as t2)
-        #             and
-        #             (all of T2's triggers have the same direction as t1)
-        #           )
-        #           or
-        #           (T1, T2, and U are the same "terminal state")
-        #         )
-        #
-        # A "terminal state" S is one from which all triggers
-        # transition back to S itself.
-        #
-        # The presence of triggers with multiple out states complicates
-        # this check slightly, but doesn't fundamentally change it.
-        #
-        #   from a state S,
-        #     for any pair of triggers t1 and t2,
-        #         where t1 and t2 have opposite direction,
-        #       for each pair of states (T1, T2) \in t1_out x t2_out,
-        #           where t1_out is the set of outstates from t1
-        #                 t2_out is the set of outstates from t2
-        #                 t1_out x t2_out is their Cartesian product
-        #                 and t1 transitions to state T1 and t2 to T2,
-        #         then the following must be true:
-        #           (T2 allows the trigger t1, with out-state set { U })
-        #           and
-        #           (T1 allows the trigger t2, with out-state set { U })
-        #           and
-        #           (
-        #             (
-        #               (all of T1's triggers have the same direction as t2)
-        #               and
-        #               (all of T2's triggers have the same direction as t1)
-        #             )
-        #             or
-        #             (T1, T2, and U are the same "terminal state")
-        #           )
-
-        # check Rule 1
-        syncdirection = None
-        syncok = True
-        for trans in ts.transitions:
-            if not trans.msg.type.isSync(): continue
-            if syncdirection is None:
-                syncdirection = trans.trigger.direction()
-            elif syncdirection is not trans.trigger.direction():
-                self.error(
-                    trans.loc,
-                    "sync trigger at state `%s' in protocol `%s' has different direction from earlier sync trigger at same state",
-                    ts.state.name, self.p.name)
-                syncok = False
-        # don't check the Diamond Rule if Rule 1 doesn't hold
-        if not syncok:
-            return
-
-        # helper functions
-        def triggerTargets(S, t):
-            '''Return the set of states transitioned to from state |S|
-upon trigger |t|, or { } if |t| is not a trigger in |S|.'''
-            for trans in self.p.states[S].transitions:
-                if t.trigger is trans.trigger and t.msg is trans.msg:
-                    return trans.toStates
-            return set()
-
-        def allTriggersSameDirectionAs(S, t):
-            '''Return true iff all the triggers from state |S| have the same
-direction as trigger |t|'''
-            direction = t.direction()
-            for trans in self.p.states[S].transitions:
-                if direction != trans.trigger.direction():
-                    return False
-            return True
-
-        def terminalState(S):
-            '''Return true iff |S| is a "terminal state".'''
-            for trans in self.p.states[S].transitions:
-                for S_ in trans.toStates:
-                    if S_ != S:  return False
-            return True
-
-        def sameTerminalState(S1, S2, S3):
-            '''Return true iff states |S1|, |S2|, and |S3| are all the same
-"terminal state".'''
-            if isinstance(S3, set):
-                assert len(S3) == 1
-                for S3_ in S3: pass
-                S3 = S3_
-
-            return (S1 == S2 == S3) and terminalState(S1)
-
-        S = ts.state.name
-
-        # check the Diamond Rule
-        for (t1, t2) in unique_pairs(ts.transitions):
-            # if the triggers have the same direction, they can't race,
-            # since only one endpoint can initiate either (and delivery
-            # is in-order)
-            if t1.trigger.direction() == t2.trigger.direction():
-                continue
-
-            loc = t1.loc
-            t1_out = t1.toStates
-            t2_out = t2.toStates
-
-            for (T1, T2) in cartesian_product(t1_out, t2_out):
-                # U1 <- { u | T1 --t2--> u }
-                U1 = triggerTargets(T1, t2)
-                # U2 <- { u | T2 --t1--> u }
-                U2 = triggerTargets(T2, t1)
-
-                # don't report more than one Diamond Rule violation
-                # per state. there may be O(n^4) total, way too many
-                # for a human to parse
-                #
-                # XXX/cjones: could set a limit on #printed and stop
-                # after that limit ...
-                raceError = False
-                errT1 = None
-                errT2 = None
-
-                if 0 == len(U1) or 0 == len(U2):
-                    print "******* case 1"
-                    raceError = True
-                elif 1 < len(U1) or 1 < len(U2):
-                    raceError = True
-                    # there are potentially many unpaired states; just
-                    # pick two
-                    print "******* case 2"
-                    for u1, u2 in cartesian_product(U1, U2):
-                        if u1 != u2:
-                            errT1, errT2 = u1, u2
-                            break
-                elif U1 != U2:
-                    print "******* case 3"
-                    raceError = True
-                    for errT1 in U1: pass
-                    for errT2 in U2: pass
-
-                if raceError:
-                    self.reportRaceError(loc, S,
-                                         [ T1, t1, errT1 ],
-                                         [ T2, t2, errT2 ])
-                    return
-
-                if not ((allTriggersSameDirectionAs(T1, t2.trigger)
-                           and allTriggersSameDirectionAs(T2, t1.trigger))
-                          or sameTerminalState(T1, T2, U1)):
-                    self.reportRunawayError(loc, S, [ T1, t1, None ], [ T2, t2, None ])
-                    return
-
-    def checkReachability(self, p):
-        def explore(ts, visited):
-            if ts.state in visited:
-                return
-            visited.add(ts.state)
-            for outedge in ts.transitions:
-                for toState in outedge.toStates:
-                    explore(p.states[toState], visited)
-
-        checkfordelete = (State.DEAD in p.states)
-
-        allvisited = set()         # set(State)
-        for root in p.startStates:
-            visited = set()
-
-            explore(root, visited)
-            allvisited.update(visited)
-
-            if checkfordelete and State.DEAD not in visited:
-                self.error(
-                    root.loc,
-                    "when starting from state `%s', actors of protocol `%s' cannot be deleted", root.state.name, p.name)
-
-        for ts in p.states.itervalues():
-            if ts.state is not State.DEAD and ts.state not in allvisited:
-                self.error(ts.loc,
-                           "unreachable state `%s' in protocol `%s'",
-                           ts.state.name, p.name)
-
-
-    def _normalizeTransitionSequences(self, t1Seq, t2Seq):
-        T1, M1, U1 = t1Seq
-        T2, M2, U2 = t2Seq
-        assert M1 is not None and M2 is not None
-
-        # make sure that T1/M1/U1 is the parent side of the race
-        if M1.trigger is RECV or M1.trigger is ANSWER:
-            T1, M1, U1, T2, M2, U2 = T2, M2, U2, T1, M1, U1
-
-        def stateName(S):
-            if S: return S.name
-            return '[error]'
-
-        T1 = stateName(T1)
-        T2 = stateName(T2)
-        U1 = stateName(U1)
-        U2 = stateName(U2)
-
-        return T1, M1.msg.progname, U1, T2, M2.msg.progname, U2
-
-
-    def reportRaceError(self, loc, S, t1Seq, t2Seq):
-        T1, M1, U1, T2, M2, U2 = self._normalizeTransitionSequences(t1Seq, t2Seq)
-        self.error(
-            loc,
-"""in protocol `%(P)s', the sequence of events
-     parent:    +--`send %(M1)s'-->( state `%(T1)s' )--`recv %(M2)s'-->( state %(U1)s )
-               /
- ( state `%(S)s' )
-               \\
-      child:    +--`send %(M2)s'-->( state `%(T2)s' )--`recv %(M1)s'-->( state %(U2)s )
-results in error(s) or leaves parent/child state out of sync for more than one step and is thus a race hazard; i.e., triggers `%(M1)s' and `%(M2)s' fail to commute in state `%(S)s'"""% {
-                'P': self.p.name, 'S': S, 'M1': M1, 'M2': M2,
-                'T1': T1, 'T2': T2, 'U1': U1, 'U2': U2
-        })
-
-
-    def reportRunawayError(self, loc, S, t1Seq, t2Seq):
-        T1, M1, _, T2, M2, __ = self._normalizeTransitionSequences(t1Seq, t2Seq)
-        self.error(
-            loc,
-        """in protocol `%(P)s', the sequence of events
-     parent:    +--`send %(M1)s'-->( state `%(T1)s' )
-               /
- ( state `%(S)s' )
-               \\
-      child:    +--`send %(M2)s'-->( state `%(T2)s' )
-lead to parent/child states in which parent/child state can become more than one step out of sync (though this divergence might not lead to error conditions)"""% {
-                'P': self.p.name, 'S': S, 'M1': M1, 'M2': M2, 'T1': T1, 'T2': T2
-        })