bug 523272: allow protocols to reference great*grandchild actors
authorChris Jones <jones.chris.g@gmail.com>
Mon, 19 Oct 2009 21:12:25 -0500
changeset 35998 3e15f80f0498186d7b17e3a8dca0dfdba6fd8005
parent 35997 04684b0cd85477432c085ad4c8659d656f299e60
child 35999 f3175b1461360373451987db30e9e060bbeec09c
push idunknown
push userunknown
push dateunknown
bugs523272
milestone1.9.3a1pre
bug 523272: allow protocols to reference great*grandchild actors
ipc/ipdl/ipdl/ast.py
ipc/ipdl/ipdl/lower.py
ipc/ipdl/ipdl/type.py
ipc/ipdl/test/cxx/Makefile.in
ipc/ipdl/test/cxx/PTestDesc.ipdl
ipc/ipdl/test/cxx/PTestDescSub.ipdl
ipc/ipdl/test/cxx/PTestDescSubsub.ipdl
ipc/ipdl/test/cxx/TestDesc.cpp
ipc/ipdl/test/cxx/TestDesc.h
ipc/ipdl/test/cxx/TestLatency.cpp
ipc/ipdl/test/cxx/ipdl.mk
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -91,17 +91,18 @@ class Visitor:
             outParam.accept(self)
 
     def visitTransitionStmt(self, ts):
         ts.state.accept(self)
         for trans in ts.transitions:
             trans.accept(self)
 
     def visitTransition(self, t):
-        t.toState.accept(self)
+        for toState in t.toStates:
+            toState.accept(self)
 
     def visitState(self, s):
         pass
 
     def visitParam(self, decl):
         pass
 
     def visitTypeSpec(self, ts):
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1926,16 +1926,68 @@ def _generateCxxUnionStuff(ud):
 """),
             _putInNamespaces(pickle, [ Namespace('IPC') ]),
             Whitespace.NL
         ])
 
 
 ##-----------------------------------------------------------------------------
 
+class _FindFriends(ipdl.ast.Visitor):
+    def __init__(self):
+        self.mytype = None              # ProtocolType
+        self.vtype = None               # ProtocolType
+        self.friends = set()            # set<ProtocolType>
+        self.visited = set()            # set<ProtocolType>
+
+    def findFriends(self, ptype):
+        self.mytype = ptype
+        self.walkUpTheProtocolTree(ptype)
+        self.walkDownTheProtocolTree(ptype)
+        return self.friends
+
+    # TODO could make this into a _iterProtocolTreeHelper ...
+    def walkUpTheProtocolTree(self, ptype):
+        if not ptype.isManaged():
+            return
+        mtype = ptype.manager
+        self.visit(mtype)
+        self.walkUpTheProtocolTree(mtype)
+
+    def walkDownTheProtocolTree(self, ptype):
+        if not ptype.isManager():
+            return
+        for mtype in ptype.manages:
+            self.visit(mtype)
+            self.walkDownTheProtocolTree(mtype)
+
+    def visit(self, ptype):
+        if ptype in self.visited:
+            return
+        self.visited.add(ptype)
+
+        savedptype = self.vtype
+        self.vtype = ptype
+        ptype._p.accept(self)
+        self.vtype = savedptype
+
+    def visitMessageDecl(self, md):
+        for it in self.iterActorParams(md):
+            if it.protocol == self.mytype:
+                self.friends.add(self.vtype)
+
+    def iterActorParams(self, md):
+        for param in md.inParams:
+            for actor in ipdl.type.iteractortypes(param.type):
+                yield actor
+        for ret in md.outParams:
+            for actor in ipdl.type.iteractortypes(ret.type):
+                yield actor
+
+
 class _Result:
     Type = Type('Result')
 
     Processed = ExprVar('MsgProcessed')
     NotKnown = ExprVar('MsgNotKnown')
     NotAllowed = ExprVar('MsgNotAllowed')
     PayloadError = ExprVar('MsgPayloadError')
     RouteError = ExprVar('MsgRouteError')
@@ -2028,24 +2080,28 @@ class _GenerateProtocolActorHeader(ipdl.
             self.file.addthing(outerns)
         self.ns.addstmts([ Whitespace.NL, Whitespace.NL ])
 
         inherits = [ Inherit(Type(p.fqListenerName())) ]
         if p.decl.type.isManager():
             inherits.append(Inherit(p.managerCxxType()))
         self.cls = Class(self.clsname, inherits=inherits, abstract=True)
 
+        friends = _FindFriends().findFriends(p.decl.type)
         if p.decl.type.isManaged():
+            friends.add(p.decl.type.manager)
+
+        for friend in friends:
             self.file.addthings([
                 Whitespace.NL,
-                _makeForwardDecl(p.decl.type.manager, self.prettyside),
+                _makeForwardDecl(friend, self.prettyside),
                 Whitespace.NL
             ])
             self.cls.addstmts([
-                FriendClassDecl(_actorName(p.decl.type.manager.fullname(),
+                FriendClassDecl(_actorName(friend.fullname(),
                                            self.prettyside)),
                 Whitespace.NL ])
 
         self.cls.addstmt(Label.PROTECTED)
         for typedef in p.cxxTypedefs():
             self.cls.addstmt(typedef)
         for typedef in self.includedActorTypedefs:
             self.cls.addstmt(typedef)
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -494,16 +494,20 @@ class GatherDecls(TcheckVisitor):
         else:
             fullname = str(qname)
         p.decl = self.declare(
             loc=p.loc,
             type=ProtocolType(qname, p.sendSemantics),
             shortname=p.name,
             fullname=fullname)
 
+        # XXX ugh, this sucks.  but we need this information to compute
+        # what friend decls we need in generated C++
+        p.decl.type._p = p
+
         # make sure we have decls for all dependent protocols
         for pinc in tu.protocolIncludes:
             pinc.accept(self)
 
         # declare imported (and builtin) C++ types
         for using in tu.using:
             using.accept(self)
 
--- a/ipc/ipdl/test/cxx/Makefile.in
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -56,16 +56,17 @@ LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 
 # Please keep these organized in the order "easy"-to-"hard"
 IPDLTESTS = \
   TestSanity  \
   TestLatency \
   TestManyChildAllocs  \
+  TestDesc \
   TestArrays \
   $(NULL)
 
 IPDLTESTSRCS = $(addsuffix .cpp,$(IPDLTESTS))
 IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
 
 TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
 GENTESTER := $(srcdir)/genIPDLUnitTests.py
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDesc.ipdl
@@ -0,0 +1,28 @@
+include protocol "PTestDescSub.ipdl";
+include protocol "PTestDescSubsub.ipdl";
+
+namespace mozilla {
+namespace _ipdltest {
+
+protocol PTestDesc {
+    manages PTestDescSub; 
+child:
+    PTestDescSub();
+    ~PTestDescSub();
+
+    Test(PTestDescSubsub a);
+
+parent:
+    Ok(PTestDescSubsub a);
+
+
+state START:
+    send Test goto ACK;
+
+state ACK:
+    recv Ok goto ACK;
+    // delete
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDescSub.ipdl
@@ -0,0 +1,17 @@
+include protocol "PTestDesc.ipdl";
+include protocol "PTestDescSubsub.ipdl";
+
+namespace mozilla {
+namespace _ipdltest {
+
+protocol PTestDescSub {
+    manager PTestDesc;
+    manages PTestDescSubsub;
+
+child:
+    PTestDescSubsub();
+    ~PTestDescSubsub();
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl
@@ -0,0 +1,13 @@
+include protocol "PTestDescSub.ipdl";
+
+namespace mozilla {
+namespace _ipdltest {
+
+protocol PTestDescSubsub {
+    manager PTestDescSub;
+
+    // empty
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDesc.cpp
@@ -0,0 +1,108 @@
+#include "TestDesc.h"
+
+#include "nsIAppShell.h"
+
+#include "nsCOMPtr.h"
+#include "nsServiceManagerUtils.h" // do_GetService()
+#include "nsWidgetsCID.h"       // NS_APPSHELL_CID
+
+#include "IPDLUnitTests.h"      // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+void
+TestDescParent::Main()
+{
+    PTestDescSubParent* p = SendPTestDescSubConstructor();
+    if (!p)
+        fail("can't allocate Sub");
+
+    PTestDescSubsubParent* pp = p->SendPTestDescSubsubConstructor();
+    if (!pp)
+        fail("can't allocate Subsub");
+
+    if (!SendTest(pp))
+        fail("can't send Subsub");
+}
+
+bool
+TestDescParent::RecvOk(PTestDescSubsubParent* a)
+{
+    if (!a)
+        fail("didn't receive Subsub");
+
+    passed("ok");
+
+    static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
+    nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
+    appShell->Exit();
+
+    return true;
+}
+
+
+PTestDescSubParent*
+TestDescParent::AllocPTestDescSub() {
+    return new TestDescSubParent();
+}
+bool
+TestDescParent::DeallocPTestDescSub(PTestDescSubParent* actor)
+{
+    delete actor;
+    return true;
+}
+
+PTestDescSubsubParent*
+TestDescSubParent::AllocPTestDescSubsub()
+{
+    return new TestDescSubsubParent();
+}
+bool
+TestDescSubParent::DeallocPTestDescSubsub(PTestDescSubsubParent* actor)
+{
+    delete actor;
+    return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// child
+
+bool
+TestDescChild::RecvTest(PTestDescSubsubChild* a)
+{
+    if (!a)
+        fail("didn't receive Subsub");
+    if (!SendOk(a))
+        fail("couldn't send Ok()");
+    return true;
+}
+
+PTestDescSubChild*
+TestDescChild::AllocPTestDescSub() {
+    return new TestDescSubChild();
+}
+bool
+TestDescChild::DeallocPTestDescSub(PTestDescSubChild* actor)
+{
+    delete actor;
+    return true;
+}
+
+PTestDescSubsubChild*
+TestDescSubChild::AllocPTestDescSubsub()
+{
+    return new TestDescSubsubChild();
+}
+bool
+TestDescSubChild::DeallocPTestDescSubsub(PTestDescSubsubChild* actor)
+{
+    delete actor;
+    return true;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDesc.h
@@ -0,0 +1,102 @@
+#ifndef mozilla_ipdltest_TestDesc_h
+#define mozilla_ipdltest_TestDesc_h
+
+#include "mozilla/_ipdltest/PTestDescParent.h"
+#include "mozilla/_ipdltest/PTestDescChild.h"
+
+#include "mozilla/_ipdltest/PTestDescSubParent.h"
+#include "mozilla/_ipdltest/PTestDescSubChild.h"
+
+#include "mozilla/_ipdltest/PTestDescSubsubParent.h"
+#include "mozilla/_ipdltest/PTestDescSubsubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Top-level
+//
+class TestDescParent :
+    public PTestDescParent
+{
+public:
+    TestDescParent() { }
+    virtual ~TestDescParent() { }
+
+    void Main();
+
+    virtual bool RecvOk(PTestDescSubsubParent* a);
+
+protected:
+    virtual PTestDescSubParent* AllocPTestDescSub();
+    virtual bool DeallocPTestDescSub(PTestDescSubParent* actor);
+};
+
+
+class TestDescChild :
+    public PTestDescChild
+{
+public:
+    TestDescChild() { }
+    virtual ~TestDescChild() { }
+
+protected:
+    virtual PTestDescSubChild* AllocPTestDescSub();
+    virtual bool DeallocPTestDescSub(PTestDescSubChild* actor);
+    virtual bool RecvTest(PTestDescSubsubChild* a);
+};
+
+
+//-----------------------------------------------------------------------------
+// First descendent
+//
+class TestDescSubParent :
+    public PTestDescSubParent
+{
+public:
+    TestDescSubParent() { }
+    virtual ~TestDescSubParent() { }
+
+protected:
+    virtual PTestDescSubsubParent* AllocPTestDescSubsub();
+    virtual bool DeallocPTestDescSubsub(PTestDescSubsubParent* actor);
+};
+
+
+class TestDescSubChild :
+    public PTestDescSubChild
+{
+public:
+    TestDescSubChild() { }
+    virtual ~TestDescSubChild() { }
+
+protected:
+    virtual PTestDescSubsubChild* AllocPTestDescSubsub();
+    virtual bool DeallocPTestDescSubsub(PTestDescSubsubChild* actor);
+};
+
+
+//-----------------------------------------------------------------------------
+// Grand-descendent
+//
+class TestDescSubsubParent :
+    public PTestDescSubsubParent
+{
+public:
+    TestDescSubsubParent() { }
+    virtual ~TestDescSubsubParent() { }
+};
+
+class TestDescSubsubChild :
+    public PTestDescSubsubChild
+{
+public:
+    TestDescSubsubChild() { }
+    virtual ~TestDescSubsubChild() { }
+};
+
+
+}
+}
+
+#endif // ifndef mozilla_ipdltest_TestDesc_h
--- a/ipc/ipdl/test/cxx/TestLatency.cpp
+++ b/ipc/ipdl/test/cxx/TestLatency.cpp
@@ -4,17 +4,17 @@
 
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h" // do_GetService()
 #include "nsWidgetsCID.h"       // NS_APPSHELL_CID
 
 #include "IPDLUnitTests.h"      // fail etc.
 
 
-#define NR_TRIALS 100000
+#define NR_TRIALS 10000
 
 namespace mozilla {
 namespace _ipdltest {
 
 //-----------------------------------------------------------------------------
 // parent
 
 TestLatencyParent::TestLatencyParent() :
--- a/ipc/ipdl/test/cxx/ipdl.mk
+++ b/ipc/ipdl/test/cxx/ipdl.mk
@@ -1,8 +1,11 @@
 IPDLSRCS =					\
   PTestArrays.ipdl				\
   PTestArraysSub.ipdl				\
+  PTestDesc.ipdl				\
+  PTestDescSub.ipdl				\
+  PTestDescSubsub.ipdl				\
   PTestLatency.ipdl				\
   PTestManyChildAllocs.ipdl			\
   PTestManyChildAllocsSub.ipdl			\
   PTestSanity.ipdl				\
   $(NULL)