Bug 1255894: Part 9 - Allow returning non-copyable types in async IPDL methods. r=kanru
authorKris Maglione <maglione.k@gmail.com>
Sun, 27 Aug 2017 18:57:30 -0700
changeset 428221 96b6a3d0231b93016f6d35a55b8f5ed98a6a8712
parent 428220 15097fdfa8e972216cb71cfd98c95591cf857e55
child 428222 3b975fe2591bc3a6954b036790b9ec169adfeb44
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskanru
bugs1255894
milestone57.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 1255894: Part 9 - Allow returning non-copyable types in async IPDL methods. r=kanru 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 ])