Bug 1255894: Part 9 - Allow returning non-copyable types in async IPDL methods. r?billm draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 27 Aug 2017 18:57:30 -0700
changeset 653837 5063880c34607d9fa6cffce2328e26c5c4501e4f
parent 653836 66b9549a6b8ba80d5411f6622008fc913ec17f38
child 653838 b4996b098f869c3e4e8e3ae70e0caecfe6b4b8b2
push id76425
push usermaglione.k@gmail.com
push dateMon, 28 Aug 2017 04:09:59 +0000
reviewersbillm
bugs1255894
milestone57.0a1
Bug 1255894: Part 9 - Allow returning non-copyable types in async IPDL methods. r?billm Certain types (such as Shmem and Endpoint types) cannot be copied, and need to be moved when passed around. When used with MozPromises, that means that the promise needs to be non-shareable, and the resolve functions need to use the correct ref qualifiers. MozReview-Commit-ID: Kt4WZNsDErK
ipc/ipdl/ipdl/lower.py
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -333,25 +333,29 @@ def _promise(resolvetype, rejecttype, ta
     inner = Type('Private') if resolver else None
     return Type('MozPromise', T=[resolvetype, rejecttype, tail], inner=inner)
 
 def _makePromise(returns, side, resolver=False):
     if len(returns) > 1:
         resolvetype = _tuple([d.bareType(side) for d in returns])
     else:
         resolvetype = returns[0].bareType(side)
+
+    needmove = not all(d.isCopyable() for d in returns)
+
     return _promise(resolvetype,
                     _PromiseRejectReason.Type(),
-                    ExprLiteral.FALSE, resolver=resolver)
+                    ExprLiteral.TRUE if needmove else ExprLiteral.FALSE,
+                    resolver=resolver)
 
 def _makeResolver(returns, side):
     if len(returns) > 1:
-        resolvetype = _tuple([d.bareType(side) for d in returns])
+        resolvetype = _tuple([d.moveType(side) for d in returns])
     else:
-        resolvetype = returns[0].bareType(side)
+        resolvetype = returns[0].moveType(side)
     return TypeFunction([Decl(resolvetype, '')])
 
 def _cxxArrayType(basetype, const=0, ref=0):
     return Type('nsTArray', T=basetype, const=const, ref=ref, hasimplicitcopyctor=False)
 
 def _cxxManagedContainerType(basetype, const=0, ref=0):
     return Type('ManagedContainer', T=basetype,
                 const=const, ref=ref, hasimplicitcopyctor=False)
@@ -581,19 +585,24 @@ def _cxxConstRefType(ipdltype, side):
         return t
     if ipdltype.isIPDL() and ipdltype.isShmem():
         t.ref = 1
         return t
     t.const = 1
     t.ref = 1
     return t
 
+def _cxxTypeNeedsMove(ipdltype):
+    return ipdltype.isIPDL() and (ipdltype.isArray() or
+                                  ipdltype.isShmem() or
+                                  ipdltype.isEndpoint())
+
 def _cxxMoveRefType(ipdltype, side):
     t = _cxxBareType(ipdltype, side)
-    if ipdltype.isIPDL() and (ipdltype.isArray() or ipdltype.isShmem() or ipdltype.isEndpoint()):
+    if _cxxTypeNeedsMove(ipdltype):
         t.ref = 2
         return t
     return _cxxConstRefType(ipdltype, side)
 
 def _cxxPtrToType(ipdltype, side):
     t = _cxxBareType(ipdltype, side)
     if ipdltype.isIPDL() and ipdltype.isActor():
         t.ptr = 0
@@ -626,16 +635,19 @@ def _deallocMethod(ptype, side):
 class _HybridDecl:
     """A hybrid decl stores both an IPDL type and all the C++ type
 info needed by later passes, along with a basic name for the decl."""
     def __init__(self, ipdltype, name):
         self.ipdltype = ipdltype
         self.name = name
         self.idnum = 0
 
+    def isCopyable(self):
+        return not _cxxTypeNeedsMove(self.ipdltype)
+
     def var(self):
         return ExprVar(self.name)
 
     def bareType(self, side):
         """Return this decl's unqualified C++ type."""
         return _cxxBareType(self.ipdltype, side)
 
     def refType(self, side):
@@ -4079,19 +4091,19 @@ class _GenerateProtocolActorCode(ipdl.as
         getpromise = [ Whitespace.NL,
                        StmtDecl(Decl(_refptr(promise), 'promise'),
                                 init=ExprCall(ExprSelect(ExprCall(ExprSelect(self.protocol.callGetChannel(), '->', 'PopPromise'),
                                                                   args=[ self.msgvar ]),
                                                          '.', Type('downcast', T=promise)))),
                        ifnotpromise ]
         if len(md.returns) > 1:
             resolvearg = ExprCall(ExprVar('MakeTuple'),
-                                  args=[p.var() for p in md.returns])
+                                  args=[ExprMove(p.var()) for p in md.returns])
         else:
-            resolvearg = md.returns[0].var()
+            resolvearg = ExprMove(md.returns[0].var())
 
         resolvepromise = [ StmtExpr(ExprCall(ExprSelect(ExprVar('promise'), '->', 'Resolve'),
                                              args=[ resolvearg,
                                                     ExprVar('__func__')])) ]
         rejectpromise = [ StmtExpr(ExprCall(ExprSelect(ExprVar('promise'), '->', 'Reject'),
                                             args=[ reason, ExprVar('__func__') ])) ]
         ifresolve = StmtIf(resolve)
         ifresolve.addifstmts(desstmts)
@@ -4282,23 +4294,23 @@ class _GenerateProtocolActorCode(ipdl.as
                    + [ self.logMessage(md, self.replyvar, 'Sending reply '),
                        StmtDecl(Decl(Type.BOOL, sendok.name),
                                 init=ExprCall(
                                     ExprSelect(self.protocol.callGetChannel(),
                                                '->', 'Send'),
                                     args=[ self.replyvar ])),
                        failifsendok ])
         if len(md.returns) > 1:
-            resolvedecl = Decl(_tuple([p.bareType(self.side) for p in md.returns],
+            resolvedecl = Decl(_tuple([p.moveType(self.side) for p in md.returns],
                                       const=1, ref=1),
                                'aParam')
             destructexpr = ExprCall(ExprVar('Tie'),
                                     args=[ p.var() for p in md.returns ])
         else:
-            resolvedecl = Decl(md.returns[0].bareType(self.side), 'aParam')
+            resolvedecl = Decl(md.returns[0].moveType(self.side), 'aParam')
             destructexpr = md.returns[0].var()
         selfvar = ExprVar('self__')
         ifactorisdead = StmtIf(ExprNot(selfvar))
         ifactorisdead.addifstmts([_printWarningMessage("Not resolving promise because actor is dead."),
                                   StmtReturn()])
         ifactorisdestroyed = StmtIf(ExprBinary(self.protocol.stateVar(), '==',
                                                self.protocol.deadState()))
         ifactorisdestroyed.addifstmts([_printWarningMessage("Not resolving promise because actor is destroyed."),
@@ -4307,17 +4319,17 @@ class _GenerateProtocolActorCode(ipdl.as
                                 ifactorisdestroyed ]
         resolverfn = ExprLambda([ExprVar.THIS, selfvar, routingId, seqno],
                                  [resolvedecl])
         resolverfn.addstmts(returnifactorisdead
                             + [ StmtDecl(Decl(Type.BOOL, resolve.name),
                                          init=ExprLiteral.TRUE) ]
                             + [ StmtDecl(Decl(p.bareType(self.side), p.var().name))
                                for p in md.returns ]
-                            + [ StmtExpr(ExprAssn(destructexpr, ExprVar('aParam'))),
+                            + [ StmtExpr(ExprAssn(destructexpr, ExprMove(ExprVar('aParam')))),
                                 StmtDecl(Decl(Type('IPC::Message', ptr=1), self.replyvar.name),
                                          init=ExprCall(ExprVar(md.pqReplyCtorFunc()),
                                                        args=[ routingId ])) ]
                             + [ self.checkedWrite(None, resolve, self.replyvar,
                                                   sentinelKey=resolve.name) ]
                             + [ self.checkedWrite(r.ipdltype, r.var(), self.replyvar,
                                                   sentinelKey=r.name)
                                  for r in md.returns ])