Bug 868715 part 8. Add tracing to WebIDL sequence return values. r=peterv, a=lsblakk
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 20 May 2013 23:54:29 -0400
changeset 142687 41e2ba420e4450c9b9fcf015a4529b4c7f8d05cd
parent 142686 c5f2a5abe3c3a80d460268c3ede0be605c8693d1
child 142688 6f0feec7b0b7b2831e1b64342d0474fe149c260c
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, lsblakk
bugs868715
milestone23.0a2
Bug 868715 part 8. Add tracing to WebIDL sequence return values. r=peterv, a=lsblakk
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1566,16 +1566,18 @@ public:
     }
     void Destroy() {
       storage.addr()->~T();
     }
 };
 
 template<typename T>
 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
+template<typename T>
+void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
 
 // Class for simple sequence arguments, only used internally by codegen.
 template<typename T>
 class AutoSequence : public AutoFallibleTArray<T, 16>
 {
 public:
   AutoSequence() : AutoFallibleTArray<T, 16>()
   {}
@@ -1631,16 +1633,30 @@ class SequenceTracer<Sequence<T>, false>
 public:
   static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
     for ( ; seqp != end; ++seqp) {
       DoTraceSequence(trc, *seqp);
     }
   }
 };
 
+// sequence<sequence<T>> as return value
+template<typename T>
+class SequenceTracer<nsTArray<T>, false>
+{
+  explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
+
+public:
+  static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
+    for ( ; seqp != end; ++seqp) {
+      DoTraceSequence(trc, *seqp);
+    }
+  }
+};
+
 // sequence<someDictionary>
 template<typename T>
 class SequenceTracer<T, true>
 {
   explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
 
 public:
   static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
@@ -1699,35 +1715,47 @@ public:
   }
 
   void SetSequence(InfallibleTArray<T>* aSequence)
   {
     mInfallibleArray = aSequence;
     mSequenceType = eInfallibleArray;
   }
 
-private:
+  void SetSequence(Nullable<nsTArray<T>>* aSequence)
+  {
+    mNullableArray = aSequence;
+    mSequenceType = eNullableArray;
+  }
+
+ private:
   enum SequenceType {
     eNone,
     eInfallibleArray,
-    eFallibleArray
+    eFallibleArray,
+    eNullableArray
   };
 
   virtual void trace(JSTracer *trc) MOZ_OVERRIDE
   {
     if (mSequenceType == eFallibleArray) {
       DoTraceSequence(trc, *mFallibleArray);
     } else if (mSequenceType == eInfallibleArray) {
       DoTraceSequence(trc, *mInfallibleArray);
+    } else if (mSequenceType == eNullableArray) {
+      if (!mNullableArray->IsNull()) {
+        DoTraceSequence(trc, mNullableArray->Value());
+      }
     }
   }
 
   union {
     InfallibleTArray<T>* mInfallibleArray;
     FallibleTArray<T>* mFallibleArray;
+    Nullable<nsTArray<T> >* mNullableArray;
   };
 
   SequenceType mSequenceType;
 };
 
 template<typename T>
 class MOZ_STACK_CLASS DictionaryRooter : JS::CustomAutoRooter
 {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4084,92 +4084,107 @@ def typeNeedsCx(type, descriptorProvider
     if type.isCallback():
         return descriptorProvider.workers
     return type.isAny() or type.isObject()
 
 def dictionaryNeedsCx(dictionary, descriptorProvider):
     return (any(typeNeedsCx(m.type, descriptorProvider) for m in dictionary.members) or
         (dictionary.parent and dictionaryNeedsCx(dictionary.parent, descriptorProvider)))
 
-# Returns a tuple consisting of a CGThing containing the type of the return
-# value, or None if there is no need for a return value, and a boolean signaling
-# whether the return value is passed in an out parameter.
-#
 # Whenever this is modified, please update CGNativeMember.getRetvalInfo as
 # needed to keep the types compatible.
 def getRetvalDeclarationForType(returnType, descriptorProvider,
                                 resultAlreadyAddRefed,
                                 isMember=False):
+    """
+    Returns a tuple containing three things:
+
+    1) A CGThing for the type of the return value, or None if there is no need
+       for a return value.
+
+    2) A boolean indicating whether the return value is passed as an out
+       parameter.
+
+    3) A CGThing for a tracer for the return value, or None if no tracing is
+       needed.
+    """
     if returnType is None or returnType.isVoid():
         # Nothing to declare
-        return None, False
+        return None, False, None
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
-        return result, False
+        return result, False, None
     if returnType.isString():
         if isMember:
-            return CGGeneric("nsString"), True
-        return CGGeneric("DOMString"), True
+            return CGGeneric("nsString"), True, None
+        return CGGeneric("DOMString"), True, None
     if returnType.isEnum():
         result = CGGeneric(returnType.unroll().inner.identifier.name)
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
-        return result, False
+        return result, False, None
     if returnType.isGeckoInterface():
         result = CGGeneric(descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeType)
         if resultAlreadyAddRefed:
             result = CGTemplatedType("nsRefPtr", result)
         elif descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeOwnership == 'owned':
             result = CGTemplatedType("nsAutoPtr", result)
         else:
             result = CGWrapper(result, post="*")
-        return result, False
+        return result, False, None
     if returnType.isCallback():
         name = returnType.unroll().identifier.name
         if descriptorProvider.workers:
-            return CGGeneric("JSObject*"), False
-        return CGGeneric("nsRefPtr<%s>" % name), False
+            return CGGeneric("JSObject*"), False, None
+        return CGGeneric("nsRefPtr<%s>" % name), False, None
     if returnType.isAny():
-        return CGGeneric("JS::Value"), False
+        return CGGeneric("JS::Value"), False, None
     if returnType.isObject() or returnType.isSpiderMonkeyInterface():
-        return CGGeneric("JSObject*"), False
+        return CGGeneric("JSObject*"), False, None
     if returnType.isSequence():
         nullable = returnType.nullable()
         if nullable:
             returnType = returnType.inner
         # If our result is already addrefed, use the right type in the
         # sequence argument here.
-        (result, _) = getRetvalDeclarationForType(returnType.inner,
-                                                  descriptorProvider,
-                                                  resultAlreadyAddRefed,
-                                                  isMember="Sequence")
+        (result, _, _) = getRetvalDeclarationForType(returnType.inner,
+                                                     descriptorProvider,
+                                                     resultAlreadyAddRefed,
+                                                     isMember="Sequence")
+        # While we have our inner type, set up our rooter, if needed
+        if not isMember and typeNeedsCx(returnType, descriptorProvider):
+            rooter = CGGeneric("SequenceRooter<%s > resultRooter(cx);\n"
+                               "resultRooter.SetSequence(&result);" %
+                               result.define())
+        else:
+            rooter = None
         result = CGTemplatedType("nsTArray", result)
         if nullable:
             result = CGTemplatedType("Nullable", result)
-        return result, True
+        return result, True, rooter
     if returnType.isDictionary():
         nullable = returnType.nullable()
         result = CGGeneric(
             CGDictionary.makeDictionaryName(returnType.unroll().inner,
                                             descriptorProvider.workers) +
             "Initializer")
         if nullable:
             result = CGTemplatedType("Nullable", result)
-        return result, True
+        return result, True, None
     if returnType.isUnion():
         raise TypeError("Need to sort out ownership model for union retvals");
     if returnType.isDate():
         result = CGGeneric("Date")
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
-        return result, False
+        return result, False, None
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
 def needCx(returnType, arguments, extendedAttributes, descriptorProvider,
@@ -4193,19 +4208,18 @@ class CGCallGenerator(CGThing):
         CGThing.__init__(self)
 
         assert errorReport is None or isinstance(errorReport, CGThing)
 
         isFallible = errorReport is not None
 
         resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
                                                         extendedAttributes)
-        (result, resultOutParam) = getRetvalDeclarationForType(returnType,
-                                                               descriptorProvider,
-                                                               resultAlreadyAddRefed)
+        (result, resultOutParam, resultRooter) = getRetvalDeclarationForType(
+            returnType, descriptorProvider, resultAlreadyAddRefed)
 
         args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
         for (a, name) in arguments:
             arg = CGGeneric(name)
             # Now constify the things that need it
             def needsConst(a):
                 if a.type.isDictionary():
                     return True
@@ -4241,16 +4255,18 @@ class CGCallGenerator(CGThing):
         # Build up our actual call
         self.cgRoot = CGList([], "\n")
 
         call = CGGeneric(nativeMethodName)
         if not static:
             call = CGWrapper(call, pre="%s->" % object)
         call = CGList([call, CGWrapper(args, pre="(", post=");")])
         if result is not None:
+            if resultRooter is not None:
+                self.cgRoot.prepend(resultRooter)
             result = CGWrapper(result, post=" result;")
             self.cgRoot.prepend(result)
             if not resultOutParam:
                 call = CGWrapper(call, pre="result = ")
 
         call = CGWrapper(call)
         self.cgRoot.append(call)
 
@@ -5163,18 +5179,19 @@ class CGSpecializedGetter(CGAbstractStat
         return CGIndenter(CGGetterCall(self.attr.type, nativeName,
                                        self.descriptor, self.attr)).define()
 
     @staticmethod
     def makeNativeName(descriptor, attr):
         name = attr.identifier.name
         nativeName = MakeNativeName(descriptor.binaryNames.get(name, name))
         # resultOutParam does not depend on whether resultAlreadyAddRefed is set
-        (_, resultOutParam) = getRetvalDeclarationForType(attr.type, descriptor,
-                                                          False)
+        (_, resultOutParam, _) = getRetvalDeclarationForType(attr.type,
+                                                             descriptor,
+                                                             False)
         infallible = ('infallible' in
                       descriptor.getExtendedAttributes(attr, getter=True))
         if resultOutParam or attr.type.nullable() or not infallible:
             nativeName = "Get" + nativeName
         return nativeName
 
 class CGStaticGetter(CGAbstractStaticBindingMethod):
     """