Bug 868715 part 6. Add the ability to trace sequence arguments. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 16 May 2013 12:36:55 -0400
changeset 143620 e0e9c5f02a56550593e510a8e056f1ce6694b625
parent 143619 e3ef4876a29f52f145170f302d2853eec41cb094
child 143621 4ca5f545698727fbb12b90f4d58ad880fd692d17
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs868715
milestone24.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 868715 part 6. Add the ability to trace sequence arguments. r=peterv
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/bindings/test/TestExampleGen.webidl
dom/bindings/test/TestJSImplGen.webidl
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1573,30 +1573,175 @@ public:
     const T& Value() const {
       return *storage.addr();
     }
     void Destroy() {
       storage.addr()->~T();
     }
 };
 
+template<typename T>
+void DoTraceSequence(JSTracer* trc, FallibleTArray<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>()
   {}
 
   // Allow converting to const sequences as needed
   operator const Sequence<T>&() const {
     return *reinterpret_cast<const Sequence<T>*>(this);
   }
 };
 
+// Class used to trace sequences, with specializations for various
+// sequence types.
+template<typename T, bool isDictionary=IsBaseOf<DictionaryBase, T>::value>
+class SequenceTracer
+{
+  explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
+};
+
+// sequence<object> or sequence<object?>
+template<>
+class SequenceTracer<JSObject*, false>
+{
+  explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
+
+public:
+  static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
+    for ( ; objp != end; ++objp) {
+      JS_CallObjectTracer(trc, objp, "sequence<object>");
+    }
+  }
+};
+
+// sequence<any>
+template<>
+class SequenceTracer<JS::Value, false>
+{
+  explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
+
+public:
+  static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
+    for ( ; valp != end; ++valp) {
+      JS_CallValueTracer(trc, valp, "sequence<any>");
+    }
+  }
+};
+
+// sequence<sequence<T>>
+template<typename T>
+class SequenceTracer<Sequence<T>, false>
+{
+  explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
+
+public:
+  static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<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) {
+    for ( ; dictp != end; ++dictp) {
+      dictp->TraceDictionary(trc);
+    }
+  }
+};
+
+// sequence<sequence<T>?>
+template<typename T>
+class SequenceTracer<Nullable<Sequence<T> >, false>
+{
+  explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
+
+public:
+  static void TraceSequence(JSTracer* trc, Nullable<Sequence<T> >* seqp,
+                            Nullable<Sequence<T> >* end) {
+    for ( ; seqp != end; ++seqp) {
+      if (!seqp->IsNull()) {
+        DoTraceSequence(trc, seqp->Value());
+      }
+    }
+  }
+};
+
+template<typename T>
+void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
+{
+  SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
+                                   seq.Elements() + seq.Length());
+}
+
+template<typename T>
+void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
+{
+  SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
+                                   seq.Elements() + seq.Length());
+}
+
+// Rooter class for sequences; this is what we mostly use in the codegen
+template<typename T>
+class MOZ_STACK_CLASS SequenceRooter : private JS::CustomAutoRooter
+{
+public:
+  explicit SequenceRooter(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+    : JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
+      mSequenceType(eNone)
+  {
+  }
+
+  void SetSequence(FallibleTArray<T>* aSequence)
+  {
+    mFallibleArray = aSequence;
+    mSequenceType = eFallibleArray;
+  }
+
+  void SetSequence(InfallibleTArray<T>* aSequence)
+  {
+    mInfallibleArray = aSequence;
+    mSequenceType = eInfallibleArray;
+  }
+
+private:
+  enum SequenceType {
+    eNone,
+    eInfallibleArray,
+    eFallibleArray
+  };
+
+  virtual void trace(JSTracer *trc) MOZ_OVERRIDE
+  {
+    if (mSequenceType == eFallibleArray) {
+      DoTraceSequence(trc, *mFallibleArray);
+    } else if (mSequenceType == eInfallibleArray) {
+      DoTraceSequence(trc, *mInfallibleArray);
+    }
+  }
+
+  union {
+    InfallibleTArray<T>* mInfallibleArray;
+    FallibleTArray<T>* mFallibleArray;
+  };
+
+  SequenceType mSequenceType;
+};
+
 inline bool
 IdEquals(jsid id, const char* string)
 {
   return JSID_IS_STRING(id) &&
          JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
 }
 
 inline bool
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2613,50 +2613,53 @@ def getJSToNativeConversionInfo(type, de
                 templateBody = handleDefaultNull(templateBody, codeToSetNull)
             else:
                 assert(defaultValue is None)
 
         return templateBody
 
     # A helper function for converting things that look like a JSObject*.
     def handleJSObjectType(type, isMember, failureCode):
-        if not isMember:
-            declType = CGGeneric("JS::Rooted<JSObject*>")
-            templateBody = "${declName} = &${valHandle}.toObject();"
-            setToNullCode = "${declName} = nullptr;"
-            template = wrapObjectTemplate(templateBody, type, setToNullCode,
-                                          failureCode)
-            return JSToNativeConversionInfo(template, declType=declType,
-                                            dealWithOptional=isOptional,
-                                            declArgs="cx")
-
-        if type.nullable():
-            declType = CGGeneric("LazyRootedObject")
-        else:
-            declType = CGGeneric("NonNullLazyRootedObject")
-
-        # If cx is null then LazyRootedObject will not be
-        # constructed and behave as nullptr.
-        templateBody = "${declName}.construct(cx, &${val}.toObject());"
-
-        # Cast of nullptr to (JSObject*) is required for template deduction.
-        setToNullCode = "${declName}.construct(cx, static_cast<JSObject*>(nullptr));"
-
         if isMember == "Dictionary":
+            if type.nullable():
+                declType = CGGeneric("LazyRootedObject")
+            else:
+                declType = CGGeneric("NonNullLazyRootedObject")
+
+            # If cx is null then LazyRootedObject will not be
+            # constructed and behave as nullptr.
+            templateBody = "${declName}.construct(cx, &${val}.toObject());"
+
+            # Cast of nullptr to (JSObject*) is required for template deduction.
+            setToNullCode = "${declName}.construct(cx, static_cast<JSObject*>(nullptr));"
+
             # If cx is null then LazyRootedObject will not be
             # constructed and behave as nullptr.
             templateBody = CGIfWrapper(CGGeneric(templateBody), "cx").define()
             setToNullCode = CGIfWrapper(CGGeneric(setToNullCode), "cx").define()
 
+            template = wrapObjectTemplate(templateBody, type, setToNullCode,
+                                          failureCode)
+
+            return JSToNativeConversionInfo(template, declType=declType,
+                                            dealWithOptional=isOptional)
+
+        if not isMember:
+            declType = CGGeneric("JS::Rooted<JSObject*>")
+        else:
+            assert isMember == "Sequence" or isMember == "Variadic"
+            # We'll get traced by the sequence tracer
+            declType = CGGeneric("JSObject*")
+        templateBody = "${declName} = &${valHandle}.toObject();"
+        setToNullCode = "${declName} = nullptr;"
         template = wrapObjectTemplate(templateBody, type, setToNullCode,
                                       failureCode)
-
         return JSToNativeConversionInfo(template, declType=declType,
-                                        dealWithOptional=isOptional)
-
+                                        dealWithOptional=isOptional,
+                                        declArgs="cx")
 
     assert not (isEnforceRange and isClamp) # These are mutually exclusive
 
     if type.isArray():
         raise TypeError("Can't handle array arguments yet")
 
     if type.isSequence():
         assert not isEnforceRange and not isClamp
@@ -2752,18 +2755,31 @@ for (uint32_t i = 0; i < length; ++i) {
                         # conversion even when forceOwningType ends up true.
                         "holderName": "tempHolder",
                         }
                     ))).define()
 
         templateBody += "\n}"
         templateBody = wrapObjectTemplate(templateBody, type,
                                           "${declName}.SetNull()")
+        # Sequence arguments that might contain traceable things need
+        # to get traced
+        if not isMember and typeNeedsCx(elementType, descriptorProvider):
+            holderType = CGTemplatedType("SequenceRooter", elementInfo.declType)
+            templateBody = (("${holderName}.SetSequence(&%s);\n" % arrayRef) +
+                            templateBody)
+            holderArgs = "cx"
+        else:
+            holderType = None
+            holderArgs = None
+
         return JSToNativeConversionInfo(templateBody, declType=typeName,
-                                        dealWithOptional=isOptional)
+                                        holderType=holderType,
+                                        dealWithOptional=isOptional,
+                                        holderArgs=holderArgs)
 
     if type.isUnion():
         if isMember:
             raise TypeError("Can't handle unions as members, we have a "
                             "holderType")
         nullable = type.nullable();
         if nullable:
             type = type.inner
@@ -3328,22 +3344,19 @@ for (uint32_t i = 0; i < length; ++i) {
     if type.isAny():
         assert not isEnforceRange and not isClamp
 
         declArgs = None
         if isMember == "Dictionary":
             declType = "LazyRootedValue"
             templateBody = "${declName}.construct(cx, ${val});"
             nullHandling = "${declName}.construct(cx, JS::NullValue());"
-        elif isMember == "Sequence":
-            raise TypeError("Can't handle sequence member 'any'; need to sort "
-                            "out rooting issues")
-        else:
-            if isMember == "Variadic":
-                # Variadic arguments are rooted by being in argv
+        else:
+            if isMember == "Variadic" or isMember == "Sequence":
+                # Rooting is handled by the sequence tracer.
                 declType = "JS::Value"
             else:
                 assert not isMember
                 declType = "JS::Rooted<JS::Value>"
                 declArgs = "cx"
 
             templateBody = "${declName} = ${val};"
             nullHandling = "${declName} = JS::NullValue()"
@@ -3695,21 +3708,28 @@ class CGArgumentConverter(CGThing):
         if typeConversion.dealWithOptional:
             raise TypeError("Shouldn't have optional things in variadics")
         if typeConversion.holderType is not None:
             raise TypeError("Shouldn't need holders for variadics")
 
         replacer = dict(self.argcAndIndex, **self.replacementVariables)
         replacer["seqType"] = CGTemplatedType("AutoSequence",
                                               typeConversion.declType).define()
+        if typeNeedsCx(self.argument.type, self.descriptorProvider):
+            rooterDecl = ("SequenceRooter<%s> ${holderName}(cx);\n"
+                          "${holderName}.SetSequence(&${declName});\n" %
+                          typeConversion.declType.define())
+        else:
+            rooterDecl = ""
         replacer["elemType"] = typeConversion.declType.define()
 
         # NOTE: Keep this in sync with sequence conversions as needed
-        variadicConversion = string.Template("""${seqType} ${declName};
-if (${argc} > ${index}) {
+        variadicConversion = string.Template("${seqType} ${declName};\n" +
+                                             rooterDecl +
+                                             """if (${argc} > ${index}) {
   if (!${declName}.SetCapacity(${argc} - ${index})) {
     JS_ReportOutOfMemory(cx);
     return false;
   }
   for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
     ${elemType}& slot = *${declName}.AppendElement();
 """).substitute(replacer)
 
@@ -4071,19 +4091,19 @@ def infallibleForMember(member, type, de
     """
     return getWrapTemplateForType(type, descriptorProvider, 'result', None,\
                                   memberIsCreator(member), "return false;")[1]
 
 def typeNeedsCx(type, descriptorProvider, retVal=False):
     if type is None:
         return False
     if type.nullable():
-        type = type.inner
+        return typeNeedsCx(type.inner, descriptorProvider, retVal)
     if type.isSequence() or type.isArray():
-        type = type.inner
+        return typeNeedsCx(type.inner, descriptorProvider, retVal)
     if type.isUnion():
         return any(typeNeedsCx(t, descriptorProvider) for t in
                    type.unroll().flatMemberTypes)
     if type.isDictionary():
         return dictionaryNeedsCx(type.inner, descriptorProvider)
     if retVal and type.isSpiderMonkeyInterface():
         return True
     if type.isCallback():
@@ -7470,16 +7490,17 @@ class CGDictionary(CGThing):
                        for m in self.memberInfo]
 
         return (string.Template(
                 "struct ${selfName} : public ${inheritance} {\n"
                 "  ${selfName}() {}\n"
                 "  bool Init(JSContext* cx, JS::Handle<JS::Value> val);\n" +
                 ("  bool Init(const nsAString& aJSON);\n" if not self.workers else "") +
                 "  bool ToObject(JSContext* cx, JS::Handle<JSObject*> parentObject, JS::Value *vp) const;\n"
+                "  void TraceDictionary(JSTracer* trc);\n"
                 "\n" +
                 "\n".join(memberDecls) + "\n"
                 "private:\n"
                 "  // Disallow copy-construction\n"
                 "  ${selfName}(const ${selfName}&) MOZ_DELETE;\n" +
                 # NOTE: jsids are per-runtime, so don't use them in workers
                 ("  static bool InitIds(JSContext* cx);\n"
                  "  static bool initedIds;\n" if self.needToInitIds else "") +
@@ -7587,16 +7608,22 @@ class CGDictionary(CGThing):
              "    return false;\n"
              "  }\n" if self.needToInitIds else "") +
             "${toObjectParent}"
             "${ensureObject}"
             "\n"
             "${defineMembers}\n"
             "\n"
             "  return true;\n"
+            "}\n"
+            "\n"
+            "void\n"
+            "${selfName}::TraceDictionary(JSTracer* trc)\n"
+            "{\n"
+            "  // XXXbz Need an implementation\n"
             "}").substitute({
                 "selfName": self.makeClassName(d),
                 "initParent": CGIndenter(CGGeneric(initParent)).define(),
                 "initMembers": "\n\n".join(memberInits),
                 "idInit": CGIndenter(idinit).define(),
                 "isMainThread": toStringBool(not self.workers),
                 "toObjectParent": CGIndenter(CGGeneric(toObjectParent)).define(),
                 "ensureObject": CGIndenter(CGGeneric(ensureObject)).define(),
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -360,17 +360,21 @@ public:
   void PassOptionalObjectSequence(const Optional<Sequence<OwningNonNull<TestInterface> > >&);
   void PassExternalInterfaceSequence(const Sequence<nsRefPtr<TestExternalInterface> >&);
   void PassNullableExternalInterfaceSequence(const Sequence<nsRefPtr<TestExternalInterface> >&);
 
   void ReceiveStringSequence(nsTArray<nsString>&);
   void PassStringSequence(const Sequence<nsString>&);
 
   void ReceiveAnySequence(JSContext*, nsTArray<JS::Value>&);
-  void ReceiveNullableAnySequence(JSContext*, Nullable<nsTArray<JS::Value> >);
+  void ReceiveNullableAnySequence(JSContext*, Nullable<nsTArray<JS::Value> >&);
+  void ReceiveAnySequenceSequence(JSContext*, nsTArray<nsTArray<JS::Value> >&);
+
+  void ReceiveObjectSequence(JSContext*, nsTArray<JSObject*>&);
+  void ReceiveNullableObjectSequence(JSContext*, nsTArray<JSObject*>&);
 
   void PassSequenceOfSequences(const Sequence< Sequence<int32_t> >&);
   void ReceiveSequenceOfSequences(nsTArray< nsTArray<int32_t> >&);
 
   // Typed array types
   void PassArrayBuffer(ArrayBuffer&);
   void PassNullableArrayBuffer(ArrayBuffer*);
   void PassOptionalArrayBuffer(const Optional<ArrayBuffer>&);
@@ -424,26 +428,42 @@ public:
   void PassOptionalNullableTreatAsNullCallbackWithDefaultValue(TestTreatAsNullCallback*);
   void SetTreatAsNullCallback(TestTreatAsNullCallback&);
   already_AddRefed<TestTreatAsNullCallback> TreatAsNullCallback();
   void SetNullableTreatAsNullCallback(TestTreatAsNullCallback*);
   already_AddRefed<TestTreatAsNullCallback> GetNullableTreatAsNullCallback();
 
   // Any types
   void PassAny(JSContext*, JS::Handle<JS::Value>);
+  void PassVariadicAny(JSContext*, const Sequence<JS::Value>&);
   void PassOptionalAny(JSContext*, const Optional<JS::Rooted<JS::Value> >&);
   void PassAnyDefaultNull(JSContext*, JS::Handle<JS::Value>);
+  void PassSequenceOfAny(JSContext*, const Sequence<JS::Value>&);
+  void PassNullableSequenceOfAny(JSContext*, const Nullable<Sequence<JS::Value> >&);
+  void PassOptionalSequenceOfAny(JSContext*, const Optional<Sequence<JS::Value> >&);
+  void PassOptionalNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<JS::Value> > >&);
+  void PassOptionalSequenceOfAnyWithDefaultValue(JSContext*, const Nullable<Sequence<JS::Value> >&);
+  void PassSequenceOfSequenceOfAny(JSContext*, const Sequence<Sequence<JS::Value> >&);
+  void PassSequenceOfNullableSequenceOfAny(JSContext*, const Sequence<Nullable<Sequence<JS::Value> > >&);
+  void PassNullableSequenceOfNullableSequenceOfAny(JSContext*, const Nullable<Sequence<Nullable<Sequence<JS::Value> > > >&);
+  void PassOptionalNullableSequenceOfNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JS::Value> > > > >&);
   JS::Value ReceiveAny(JSContext*);
 
   // object types
   void PassObject(JSContext*, JS::Handle<JSObject*>);
+  void PassVariadicObject(JSContext*, const Sequence<JSObject*>&);
   void PassNullableObject(JSContext*, JS::Handle<JSObject*>);
+  void PassVariadicNullableObject(JSContext*, const Sequence<JSObject*>&);
   void PassOptionalObject(JSContext*, const Optional<JS::Rooted<JSObject*> >&);
   void PassOptionalNullableObject(JSContext*, const Optional<JS::Rooted<JSObject*> >&);
   void PassOptionalNullableObjectWithDefaultValue(JSContext*, JS::Handle<JSObject*>);
+  void PassSequenceOfObject(JSContext*, const Sequence<JSObject*>&);
+  void PassSequenceOfNullableObject(JSContext*, const Sequence<JSObject*>&);
+  void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
+  void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
   JSObject* ReceiveObject(JSContext*);
   JSObject* ReceiveNullableObject(JSContext*);
 
   // Union types
   void PassUnion(JSContext*, const ObjectOrLong& arg);
   void PassUnionWithNullable(JSContext* cx, const ObjectOrNullOrLong& arg)
   {
     ObjectOrLong returnValue;
@@ -490,18 +510,18 @@ public:
   // Dictionary tests
   void PassDictionary(JSContext*, const Dict&);
   void ReceiveDictionary(JSContext*, Dict&);
   void PassOtherDictionary(const GrandparentDict&);
   void PassSequenceOfDictionaries(JSContext*, const Sequence<Dict>&);
   void PassDictionaryOrLong(JSContext*, const Dict&);
   void PassDictionaryOrLong(int32_t);
   void PassDictContainingDict(JSContext*, const DictContainingDict&);
-  void PassDictContainingSequence(const DictContainingSequence&);
-  void ReceiveDictContainingSequence(DictContainingSequence&);
+  void PassDictContainingSequence(JSContext*, const DictContainingSequence&);
+  void ReceiveDictContainingSequence(JSContext*, DictContainingSequence&);
 
   // Typedefs
   void ExerciseTypedefInterfaces1(TestInterface&);
   already_AddRefed<TestInterface> ExerciseTypedefInterfaces2(TestInterface*);
   void ExerciseTypedefInterfaces3(TestInterface&);
 
   // Static methods and attributes
   static void StaticMethod(const GlobalObject&, bool);
@@ -670,16 +690,29 @@ private:
   void PassOptionalUnsignedLongLong(const Optional<T>&) MOZ_DELETE;
   template<typename T>
   void PassOptionalUnsignedLongLongWithDefault(T) MOZ_DELETE;
 
   // Enforce that only const things are passed for sequences
   void PassSequence(Sequence<int32_t> &) MOZ_DELETE;
   void PassNullableSequence(Nullable< Sequence<int32_t> >&) MOZ_DELETE;
   void PassOptionalNullableSequenceWithDefaultValue(Nullable< Sequence<int32_t> >&) MOZ_DELETE;
+  void PassSequenceOfAny(JSContext*, Sequence<JS::Value>&) MOZ_DELETE;
+  void PassNullableSequenceOfAny(JSContext*, Nullable<Sequence<JS::Value> >&) MOZ_DELETE;
+  void PassOptionalSequenceOfAny(JSContext*, Optional<Sequence<JS::Value> >&) MOZ_DELETE;
+  void PassOptionalNullableSequenceOfAny(JSContext*, Optional<Nullable<Sequence<JS::Value> > >&) MOZ_DELETE;
+  void PassOptionalSequenceOfAnyWithDefaultValue(JSContext*, Nullable<Sequence<JS::Value> >&) MOZ_DELETE;
+  void PassSequenceOfSequenceOfAny(JSContext*, Sequence<Sequence<JS::Value> >&) MOZ_DELETE;
+  void PassSequenceOfNullableSequenceOfAny(JSContext*, Sequence<Nullable<Sequence<JS::Value> > >&) MOZ_DELETE;
+  void PassNullableSequenceOfNullableSequenceOfAny(JSContext*, Nullable<Sequence<Nullable<Sequence<JS::Value> > > >&) MOZ_DELETE;
+  void PassOptionalNullableSequenceOfNullableSequenceOfAny(JSContext*, Optional<Nullable<Sequence<Nullable<Sequence<JS::Value> > > > >&) MOZ_DELETE;
+  void PassSequenceOfObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
+  void PassSequenceOfNullableObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
+  void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&) MOZ_DELETE;
+  void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&) MOZ_DELETE;
 
   // Enforce that only const things are passed for optional
   void PassOptionalByte(Optional<int8_t>&) MOZ_DELETE;
   void PassOptionalNullableByte(Optional<Nullable<int8_t> >&) MOZ_DELETE;
   void PassOptionalShort(Optional<int16_t>&) MOZ_DELETE;
   void PassOptionalLong(Optional<int32_t>&) MOZ_DELETE;
   void PassOptionalLongLong(Optional<int64_t>&) MOZ_DELETE;
   void PassOptionalOctet(Optional<uint8_t>&) MOZ_DELETE;
@@ -732,16 +765,21 @@ private:
 
   // Make sure various date stuff is const as needed
   void PassNullableDate(Nullable<Date>&) MOZ_DELETE;
   void PassOptionalDate(Optional<Date>&) MOZ_DELETE;
   void PassOptionalNullableDate(Optional<Nullable<Date> >&) MOZ_DELETE;
   void PassOptionalNullableDateWithDefaultValue(Nullable<Date>&) MOZ_DELETE;
   void PassDateSequence(Sequence<Date>&) MOZ_DELETE;
   void PassNullableDateSequence(Sequence<Nullable<Date> >&) MOZ_DELETE;
+
+  // Make sure variadics are const as needed
+  void PassVariadicAny(JSContext*, Sequence<JS::Value>&) MOZ_DELETE;
+  void PassVariadicObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
+  void PassVariadicNullableObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
 };
 
 class TestIndexedGetterInterface : public nsISupports,
                                    public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -331,16 +331,20 @@ interface TestInterface {
   void passExternalInterfaceSequence(sequence<TestExternalInterface> arg);
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   void passStringSequence(sequence<DOMString> arg);
 
   sequence<any> receiveAnySequence();
   sequence<any>? receiveNullableAnySequence();
+  sequence<sequence<any>> receiveAnySequenceSequence();
+
+  sequence<object> receiveObjectSequence();
+  sequence<object?> receiveNullableObjectSequence();
 
   void passSequenceOfSequences(sequence<sequence<long>> arg);
   sequence<sequence<long>> receiveSequenceOfSequences();
 
   // Typed array types
   void passArrayBuffer(ArrayBuffer arg);
   void passNullableArrayBuffer(ArrayBuffer? arg);
   void passOptionalArrayBuffer(optional ArrayBuffer arg);
@@ -391,26 +395,42 @@ interface TestInterface {
   void passNullableTreatAsNullCallback(TestTreatAsNullCallback? arg);
   void passOptionalNullableTreatAsNullCallback(optional TestTreatAsNullCallback? arg);
   void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
   attribute TestTreatAsNullCallback treatAsNullCallback;
   attribute TestTreatAsNullCallback? nullableTreatAsNullCallback;
 
   // Any types
   void passAny(any arg);
+  void passVariadicAny(any... arg);
   void passOptionalAny(optional any arg);
   void passAnyDefaultNull(optional any arg = null);
+  void passSequenceOfAny(sequence<any> arg);
+  void passNullableSequenceOfAny(sequence<any>? arg);
+  void passOptionalSequenceOfAny(optional sequence<any> arg);
+  void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
+  void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
+  void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
+  void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
+  void passNullableSequenceOfNullableSequenceOfAny(sequence<sequence<any>?>? arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence<sequence<any>?>? arg);
   any receiveAny();
 
   // object types
   void passObject(object arg);
+  void passVariadicObject(object... arg);
   void passNullableObject(object? arg);
+  void passVariadicNullableObject(object... arg);
   void passOptionalObject(optional object arg);
   void passOptionalNullableObject(optional object? arg);
   void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
+  void passSequenceOfObject(sequence<object> arg);
+  void passSequenceOfNullableObject(sequence<object?> arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence<sequence<object>?>? arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence<sequence<object?>?>? arg);
   object receiveObject();
   object? receiveNullableObject();
 
   // Union types
   void passUnion((object or long) arg);
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
@@ -444,16 +464,18 @@ interface TestInterface {
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   Dict receiveDictionary();
   void passOtherDictionary(optional GrandparentDict x);
   void passSequenceOfDictionaries(sequence<Dict> x);
+  // No support for nullable dictionaries inside a sequence (nor should there be)
+  //  void passSequenceOfNullableDictionaries(sequence<Dict?> x);
   void passDictionaryOrLong(optional Dict x);
   void passDictionaryOrLong(long x);
 
   void passDictContainingDict(optional DictContainingDict arg);
   void passDictContainingSequence(optional DictContainingSequence arg);
   DictContainingSequence receiveDictContainingSequence();
 
   // EnforceRange/Clamp tests
@@ -652,25 +674,32 @@ dictionary ParentDict : GrandparentDict 
 
 dictionary DictContainingDict {
   Dict memberDict;
 };
 
 dictionary DictContainingSequence {
   sequence<long> ourSequence;
   sequence<TestInterface> ourSequence2;
+  sequence<any> ourSequence3;
+  // XXXbz we can't make up our minds about how to represent 'object';
+  // will be fixed once we trace dictionaries.
+  //sequence<object> ourSequence4;
+  sequence<object?> ourSequence5;
 };
 
 dictionary DictForConstructor {
   Dict dict;
   DictContainingDict dict2;
   sequence<Dict> seq1;
   sequence<sequence<Dict>>? seq2;
   sequence<sequence<Dict>?> seq3;
-  // No support for sequences of "any" or "object" as return values yet.
+  sequence<any> seq4;
+  sequence<any> seq5;
+  sequence<DictContainingSequence> seq6;
   object obj1;
   object? obj2;
   any any1 = null;
 };
 
 interface TestIndexedGetterInterface {
   getter long item(unsigned long idx);
   readonly attribute unsigned long length;
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -229,16 +229,21 @@ interface TestExampleInterface {
   void passExternalInterfaceSequence(sequence<TestExternalInterface> arg);
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   void passStringSequence(sequence<DOMString> arg);
 
   sequence<any> receiveAnySequence();
   sequence<any>? receiveNullableAnySequence();
+  //XXXbz No support for sequence of sequence return values yet.
+  //sequence<sequence<any>> receiveAnySequenceSequence();
+
+  sequence<object> receiveObjectSequence();
+  sequence<object?> receiveNullableObjectSequence();
 
   void passSequenceOfSequences(sequence<sequence<long>> arg);
   //XXXbz No support for sequence of sequence return values yet.
   //sequence<sequence<long>> receiveSequenceOfSequences();
 
   // Typed array types
   void passArrayBuffer(ArrayBuffer arg);
   void passNullableArrayBuffer(ArrayBuffer? arg);
@@ -288,26 +293,42 @@ interface TestExampleInterface {
   TestCallback receiveCallback();
   TestCallback? receiveNullableCallback();
   void passNullableTreatAsNullCallback(TestTreatAsNullCallback? arg);
   void passOptionalNullableTreatAsNullCallback(optional TestTreatAsNullCallback? arg);
   void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
 
   // Any types
   void passAny(any arg);
+  void passVariadicAny(any... arg);
   void passOptionalAny(optional any arg);
   void passAnyDefaultNull(optional any arg = null);
+  void passSequenceOfAny(sequence<any> arg);
+  void passNullableSequenceOfAny(sequence<any>? arg);
+  void passOptionalSequenceOfAny(optional sequence<any> arg);
+  void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
+  void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
+  void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
+  void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
+  void passNullableSequenceOfNullableSequenceOfAny(sequence<sequence<any>?>? arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence<sequence<any>?>? arg);
   any receiveAny();
 
   // object types
   void passObject(object arg);
+  void passVariadicObject(object... arg);
   void passNullableObject(object? arg);
+  void passVariadicNullableObject(object... arg);
   void passOptionalObject(optional object arg);
   void passOptionalNullableObject(optional object? arg);
   void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
+  void passSequenceOfObject(sequence<object> arg);
+  void passSequenceOfNullableObject(sequence<object?> arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence<sequence<object>?>? arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence<sequence<object?>?>? arg);
   object receiveObject();
   object? receiveNullableObject();
 
   // Union types
   void passUnion((object or long) arg);
   void passUnionWithNullable((object? or long) arg);
   void passNullableUnion((object or long)? arg);
   void passOptionalUnion(optional (object or long) arg);
@@ -341,16 +362,18 @@ interface TestExampleInterface {
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   //UNSUPPORTED  Dict receiveDictionary();
   void passOtherDictionary(optional GrandparentDict x);
   void passSequenceOfDictionaries(sequence<Dict> x);
+  // No support for nullable dictionaries inside a sequence (nor should there be)
+  //  void passSequenceOfNullableDictionaries(sequence<Dict?> x);
   void passDictionaryOrLong(optional Dict x);
   void passDictionaryOrLong(long x);
 
   void passDictContainingDict(optional DictContainingDict arg);
   void passDictContainingSequence(optional DictContainingSequence arg);
   //UNSUPPORTED DictContainingSequence receiveDictContainingSequence();
 
   // EnforceRange/Clamp tests
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -247,19 +247,23 @@ interface TestJSImplInterface {
   void passOptionalNullableSequenceWithDefaultValue(optional sequence<long>? arg = null);
   void passOptionalObjectSequence(optional sequence<TestJSImplInterface> arg);
   void passExternalInterfaceSequence(sequence<TestExternalInterface> arg);
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   // Callback interface problem.  See bug 843261.
   //void passStringSequence(sequence<DOMString> arg);
-  // "Can't handle sequence member 'any'; need to sort out rooting issues"
-  //sequence<any> receiveAnySequence();
-  //sequence<any>? receiveNullableAnySequence();
+  sequence<any> receiveAnySequence();
+  sequence<any>? receiveNullableAnySequence();
+  //XXXbz No support for sequence of sequence return values yet.
+  //sequence<sequence<any>> receiveAnySequenceSequence();
+
+  sequence<object> receiveObjectSequence();
+  sequence<object?> receiveNullableObjectSequence();
 
   void passSequenceOfSequences(sequence<sequence<long>> arg);
   //sequence<sequence<long>> receiveSequenceOfSequences();
 
   // ArrayBuffer is handled differently in callback interfaces and the example generator.
   // Need to figure out what should be done there.  Seems like other typed array stuff is
   // similarly not working in the JS implemented generator.  Probably some other issues
   // here as well.
@@ -313,25 +317,41 @@ interface TestJSImplInterface {
   MyTestCallback? receiveNullableCallback();
   // Hmm. These two don't work, I think because I need a locally modified version of TestTreatAsNullCallback.
   //void passNullableTreatAsNullCallback(TestTreatAsNullCallback? arg);
   //void passOptionalNullableTreatAsNullCallback(optional TestTreatAsNullCallback? arg);
   void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
 
   // Any types
   void passAny(any arg);
+  void passVariadicAny(any... arg);
   void passOptionalAny(optional any arg);
   void passAnyDefaultNull(optional any arg = null);
+  void passSequenceOfAny(sequence<any> arg);
+  void passNullableSequenceOfAny(sequence<any>? arg);
+  void passOptionalSequenceOfAny(optional sequence<any> arg);
+  void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
+  void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
+  void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
+  void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
+  void passNullableSequenceOfNullableSequenceOfAny(sequence<sequence<any>?>? arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence<sequence<any>?>? arg);
   any receiveAny();
 
   void passObject(object arg);
+  void passVariadicObject(object... arg);
   void passNullableObject(object? arg);
+  void passVariadicNullableObject(object... arg);
   void passOptionalObject(optional object arg);
   void passOptionalNullableObject(optional object? arg);
   void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
+  void passSequenceOfObject(sequence<object> arg);
+  void passSequenceOfNullableObject(sequence<object?> arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence<sequence<object>?>? arg);
+  void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence<sequence<object?>?>? arg);
   object receiveObject();
   object? receiveNullableObject();
 
   // Union types
   void passUnion((object or long) arg);
   void passUnionWithNullable((object? or long) arg);
   // FIXME: Bug 863948 Nullable unions not supported yet
   //   void passNullableUnion((object or long)? arg);
@@ -368,16 +388,18 @@ interface TestJSImplInterface {
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   // FIXME: Bug 863949 no dictionary return values
   //   Dict receiveDictionary();
   void passOtherDictionary(optional GrandparentDict x);
   void passSequenceOfDictionaries(sequence<Dict> x);
+  // No support for nullable dictionaries inside a sequence (nor should there be)
+  //  void passSequenceOfNullableDictionaries(sequence<Dict?> x);
   void passDictionaryOrLong(optional Dict x);
   void passDictionaryOrLong(long x);
 
   void passDictContainingDict(optional DictContainingDict arg);
   void passDictContainingSequence(optional DictContainingSequence arg);
   // FIXME: Bug 863949 no dictionary return values
   //   DictContainingSequence receiveDictContainingSequence();