Commit f7615c8e authored by Chris Jones's avatar Chris Jones
Browse files

Bug 613442, part 1: Frontend support for IPDL |opens|. r=bent

parent 3ee40a33
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@ class Visitor:
            spawns.accept(self)
        for bridges in p.bridgesStmts:
            bridges.accept(self)
        for opens in p.opensStmts:
            opens.accept(self)
        for mgr in p.managers:
            mgr.accept(self)
        for managed in p.managesStmts:
@@ -95,6 +97,9 @@ class Visitor:
    def visitBridgesStmt(self, bridges):
        pass

    def visitOpensStmt(self, opens):
        pass

    def visitManager(self, mgr):
        pass

@@ -269,6 +274,7 @@ class Protocol(NamespacedNode):
        self.sendSemantics = ASYNC
        self.spawnsStmts = [ ]
        self.bridgesStmts = [ ]
        self.opensStmts = [ ]
        self.managers = [ ]
        self.managesStmts = [ ]
        self.messageDecls = [ ]
@@ -304,6 +310,12 @@ class BridgesStmt(Node):
        self.parentSide = parentSide
        self.childSide = childSide

class OpensStmt(Node):
    def __init__(self, loc, side, proto):
        Node.__init__(self, loc)
        self.side = side
        self.proto = proto

class Manager(Node):
    def __init__(self, loc, managerName):
        Node.__init__(self, loc)
+17 −2
Original line number Diff line number Diff line
@@ -155,6 +155,7 @@ reserved = set((
        'manages',
        'namespace',
        'nullable',
        'opens',
        'or',
        'parent',
        'protocol',
@@ -343,7 +344,7 @@ def p_ProtocolBody(p):
    p[0] = p[1]

##--------------------
## spawns/bridges stmts
## spawns/bridges/opens stmts

def p_SpawnsStmtsOpt(p):
    """SpawnsStmtsOpt : SpawnsStmt SpawnsStmtsOpt
@@ -370,7 +371,7 @@ def p_AsOpt(p):

def p_BridgesStmtsOpt(p):
    """BridgesStmtsOpt : BridgesStmt BridgesStmtsOpt
                       | ManagersStmtOpt"""
                       | OpensStmtsOpt"""
    if 2 == len(p):
        p[0] = p[1]
    else:
@@ -381,6 +382,20 @@ def p_BridgesStmt(p):
    """BridgesStmt : BRIDGES ID ',' ID ';'"""
    p[0] = BridgesStmt(locFromTok(p, 1), p[2], p[4])

def p_OpensStmtsOpt(p):
    """OpensStmtsOpt : OpensStmt OpensStmtsOpt
                     | ManagersStmtOpt"""
    if 2 == len(p):
        p[0] = p[1]
    else:
        p[2].opensStmts.insert(0, p[1])
        p[0] = p[2]

def p_OpensStmt(p):
    """OpensStmt : PARENT OPENS ID ';'
                 | CHILD OPENS ID ';'"""
    p[0] = OpensStmt(locFromTok(p, 1), p[1], p[3])

##--------------------
## manager/manages stmts

+105 −0
Original line number Diff line number Diff line
@@ -294,6 +294,7 @@ class ProtocolType(IPDLType):
        self.qname = qname
        self.sendSemantics = sendSemantics
        self.spawns = set()             # ProtocolType
        self.opens = set()              # ProtocolType
        self.managers = set()           # ProtocolType
        self.manages = [ ]
        self.stateless = stateless
@@ -313,6 +314,10 @@ class ProtocolType(IPDLType):
        assert self.isToplevel() and  ptype.isToplevel()
        self.spawns.add(ptype)

    def addOpen(self, ptype):
        assert self.isToplevel() and  ptype.isToplevel()
        self.opens.add(ptype)

    def managedBy(self, mgr):
        self.managers = mgr

@@ -773,6 +778,9 @@ class GatherDecls(TcheckVisitor):
        for bridges in p.bridgesStmts:
            bridges.accept(self)

        for opens in p.opensStmts:
            opens.accept(self)

        seenmgrs = set()
        for mgr in p.managers:
            if mgr.name in seenmgrs:
@@ -923,6 +931,14 @@ class GatherDecls(TcheckVisitor):
        bridges.parentSide = lookup(bridges.parentSide)
        bridges.childSide = lookup(bridges.childSide)

    def visitOpensStmt(self, opens):
        pname = opens.proto
        opens.proto = self.symtab.lookup(pname)
        if opens.proto is None:
            self.error(opens.loc,
                       "opened protocol `%s' has not been declared",
                       pname)


    def visitManager(self, mgr):
        mgrdecl = self.symtab.lookup(mgr.name)
@@ -1230,6 +1246,11 @@ class CheckTypes(TcheckVisitor):
                       "protocol `%s' is not top-level and so cannot declare |bridges|",
                       pname)

        if len(p.opensStmts) and not ptype.isToplevel():
            self.error(p.decl.loc,
                       "protocol `%s' is not top-level and so cannot declare |opens|",
                       pname)

        for mgrtype in ptype.managers:
            if mgrtype is not None and ptype.needsMoreJuiceThan(mgrtype):
                self.error(
@@ -1298,6 +1319,23 @@ class CheckTypes(TcheckVisitor):
                       parentType.name(), childType.name())


    def visitOpensStmt(self, opens):
        if not self.ptype.isToplevel():
            self.error(opens.loc,
                       "only top-level protocols can have |opens| statements; `%s' cannot",
                       self.ptype.name())
            return

        openedType = opens.proto.type
        if not (openedType.isIPDL() and openedType.isProtocol()
                and openedType.isToplevel()):
            self.error(opens.loc,
                       "cannot open non-top-level-protocol `%s'",
                       openedType.name())
        else:
            self.ptype.addOpen(openedType)


    def visitManagesStmt(self, mgs):
        pdecl = mgs.manager.decl
        ptype, pname = pdecl.type, pdecl.shortname
@@ -1467,11 +1505,20 @@ class BridgeEdge:
            self.parent, self.bridgeProto.name(), self.child)
    def __str__(self):  return repr(self)

class OpensEdge:
    def __init__(self, opener, openedProto):
        self.opener = opener            # Actor
        self.openedProto = openedProto  # ProtocolType
    def __repr__(self):
        return '(%r)--opens-->(%s)'% (self.opener, self.openedProto.name())
    def __str__(self):  return repr(self)

# "singleton" class with state that persists across type checking of
# all protocols
class ProcessGraph:
    processes = set()                   # set(Process)
    bridges = { }                       # ProtocolType -> [ BridgeEdge ]
    opens = { }                         # ProtocolType -> [ OpensEdge ]
    actorToProcess = { }                # Actor -> Process
    visitedSpawns = set()               # set(ActorType)
    visitedBridges = set()              # set(ActorType)
@@ -1510,6 +1557,27 @@ class ProcessGraph:
            for bridge in edges:
                yield bridge

    @classmethod
    def opensOf(cls, openedP):
        return cls.opens.get(openedP, [])

    @classmethod
    def opensEndpointsOf(cls, ptype, side):
        actor = Actor(ptype, side)
        endpoints = []
        for o in cls.iteropens():
            if actor == o.opener:
                endpoints.append(Actor(o.openedProto, o.opener.side))
            elif actor == o.opener.other():
                endpoints.append(Actor(o.openedProto, o.opener.other().side))
        return endpoints

    @classmethod
    def iteropens(cls):
        for edges in cls.opens.itervalues():
            for opens in edges:
                yield opens

    @classmethod
    def spawn(cls, spawner, remoteSpawn):
        localSpawn = remoteSpawn.other()
@@ -1519,10 +1587,27 @@ class ProcessGraph:

    @classmethod
    def bridge(cls, parent, child, bridgeP):
        bridgeParent = Actor(bridgeP, 'parent')
        parentProcess = ProcessGraph.getProcess(parent)
        parentProcess.merge(ProcessGraph.getProcess(bridgeParent))
        bridgeChild = Actor(bridgeP, 'child')
        childProcess = ProcessGraph.getProcess(child)
        childProcess.merge(ProcessGraph.getProcess(bridgeChild))
        if bridgeP not in cls.bridges:
            cls.bridges[bridgeP] = [ ]
        cls.bridges[bridgeP].append(BridgeEdge(bridgeP, parent, child))

    @classmethod
    def open(cls, opener, opened, openedP):
        remoteOpener, remoteOpened, = opener.other(), opened.other()
        openerProcess = ProcessGraph.getProcess(opener)
        openerProcess.merge(ProcessGraph.getProcess(opened))
        remoteOpenerProcess = ProcessGraph.getProcess(remoteOpener)
        remoteOpenerProcess.merge(ProcessGraph.getProcess(remoteOpened))
        if openedP not in cls.opens:
            cls.opens[openedP] = [ ]
        cls.opens[openedP].append(OpensEdge(opener, openedP))


class BuildProcessGraph(TcheckVisitor):
    class findSpawns(TcheckVisitor):
@@ -1629,6 +1714,22 @@ class BuildProcessGraph(TcheckVisitor):

        ProcessGraph.bridge(parentSideActor, childSideActor, bridgeProto)

    def visitOpensStmt(self, opens):
        openedP = opens.proto.type
        opener = Actor(self.visiting, opens.side)
        opened = Actor(openedP, opens.side)

        # The picture here is:
        #  [ opener       | opened ]   (process 1)
        #      |               |
        #      |               |
        #  [ remoteOpener | remoteOpened ]  (process 2)
        #
        # An opens stmt tells us that the pairs |opener|/|opened|
        # and |remoteOpener|/|remoteOpened| are each in the same
        # process.
        ProcessGraph.open(opener, opened, openedP)


class CheckProcessGraph(TcheckVisitor):
    def __init__(self, errors):
@@ -1647,6 +1748,10 @@ class CheckProcessGraph(TcheckVisitor):
            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

##-----------------------------------------------------------------------------