Bug 796850 - Implement Code Generation for Bytestring in WebIDL bindings r=bz
authorJames Kitchener <jkitch.bug@gmail.com>
Thu, 13 Jun 2013 01:18:35 -0400
changeset 134907 2cb618e6b57c7cf8cf559f1641b41b17069ebcd4
parent 134906 864acd590539268af53937b95943def6efcf903c
child 134908 708f6cd81acbc9f88bd7e30553fa8555c33b33e5
push id29438
push userbzbarsky@mozilla.com
push dateThu, 13 Jun 2013 05:21:13 +0000
treeherdermozilla-inbound@708f6cd81acb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs796850
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 796850 - Implement Code Generation for Bytestring in WebIDL bindings r=bz
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/Errors.msg
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/bindings/test/TestExampleGen.webidl
dom/bindings/test/TestJSImplGen.webidl
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2,18 +2,20 @@
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <algorithm>
 #include <stdarg.h>
 
+#include "prprf.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
+#include "mozilla/Assertions.h"
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
 #include "nsContentUtils.h"
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsIXPConnect.h"
@@ -1894,10 +1896,88 @@ ConstructJSImplementation(JSContext* aCx
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
   }
 
   return window.forget();
 }
 
+bool
+NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
+                         JS::MutableHandle<JS::Value> rval)
+{
+    if (str.IsEmpty()) {
+        rval.set(JS_GetEmptyStringValue(cx));
+        return true;
+    }
+
+    // ByteStrings are not UTF-8 encoded.
+    JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length());
+
+    if (!jsStr)
+        return false;
+
+    rval.setString(jsStr);
+    return true;
+}
+
+bool
+ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
+                           JS::MutableHandle<JS::Value> pval, bool nullable,
+                           nsACString& result)
+{
+  JSString *s;
+  if (v.isString()) {
+    s = v.toString();
+  } else {
+
+    if (nullable && v.isNullOrUndefined()) {
+      result.SetIsVoid(true);
+      return true;
+    }
+
+    s = JS_ValueToString(cx, v);
+    if (!s) {
+      return false;
+    }
+    pval.set(JS::StringValue(s));  // Root the new string.
+  }
+
+  size_t length;
+  const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &length);
+  if (!chars) {
+    return false;
+  }
+
+  // Conversion from Javascript string to ByteString is only valid if all
+  // characters < 256.
+  for (size_t i = 0; i < length; i++) {
+    if (chars[i] > 255) {
+      // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has
+      // 20 digits, plus one more for the null terminator.
+      char index[21];
+      MOZ_STATIC_ASSERT(sizeof(size_t) <= 8, "index array too small");
+      PR_snprintf(index, sizeof(index), "%d", i);
+      // A jschar is 16 bits long.  The biggest unsigned 16 bit
+      // number (65,535) has 5 digits, plus one more for the null
+      // terminator.
+      char badChar[6];
+      MOZ_STATIC_ASSERT(sizeof(jschar) <= 2, "badChar array too small");
+      PR_snprintf(badChar, sizeof(badChar), "%d", chars[i]);
+      ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badChar);
+      return false;
+    }
+  }
+
+  if (length >= UINT32_MAX) {
+    return false;
+  }
+  result.SetCapacity(length+1);
+  JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length);
+  result.BeginWriting()[length] = '\0';
+  result.SetLength(length);
+
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1577,16 +1577,21 @@ ConvertJSValueToString(JSContext* cx, JS
   if (!chars) {
     return false;
   }
 
   result.SetData(chars, len);
   return true;
 }
 
+bool
+ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
+                           JS::MutableHandle<JS::Value> pval, bool nullable,
+                           nsACString& result);
+
 // Class for holding the type of members of a union. The union type has an enum
 // to keep track of which of its UnionMembers has been constructed.
 template<class T>
 class UnionMember {
     AlignedStorage2<T> storage;
 
 public:
     T& SetValue() {
@@ -2052,12 +2057,30 @@ ConstructJSImplementation(JSContext* aCx
                           const GlobalObject& aGlobal,
                           JS::MutableHandle<JSObject*> aObject,
                           ErrorResult& aRv);
 
 bool
 RegisterForDeferredFinalization(DeferredFinalizeStartFunction start,
                                 DeferredFinalizeFunction run);
 
+/**
+ * Convert an nsCString to jsval, returning true on success.
+ * These functions are intended for ByteString implementations.
+ * As such, the string is not UTF-8 encoded.  Any UTF8 strings passed to these
+ * methods will be mangled.
+ */
+bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
+                              JS::MutableHandle<JS::Value> rval);
+inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
+                              JS::MutableHandle<JS::Value> rval)
+{
+    if (str.IsVoid()) {
+        rval.setNull();
+        return true;
+    }
+    return NonVoidByteStringToJsval(cx, str, rval);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3208,17 +3208,17 @@ for (uint32_t i = 0; i < length; ++i) {
 
         if holderType is not None:
             holderType = CGGeneric(holderType)
         # We handle all the optional stuff ourselves; no need for caller to do it.
         return JSToNativeConversionInfo(template,
                                         declType=CGGeneric(declType),
                                         holderType=holderType)
 
-    if type.isString():
+    if type.isDOMString():
         assert not isEnforceRange and not isClamp
 
         treatAs = {
             "Default": "eStringify",
             "EmptyString": "eEmpty",
             "Null": "eNull",
             # For Missing it doesn't matter what we use here, since we'll never
             # call ConvertJSValueToString on undefined in that case.
@@ -3274,16 +3274,34 @@ for (uint32_t i = 0; i < length; ++i) {
         # No need to deal with optional here; we handled it already
         return JSToNativeConversionInfo(
             "%s\n"
             "${declName} = &${holderName};" %
             getConversionCode("${holderName}"),
             declType=CGGeneric(declType),
             holderType=CGGeneric("FakeDependentString"))
 
+    if type.isByteString():
+        assert not isEnforceRange and not isClamp
+
+        nullable = toStringBool(type.nullable())
+
+        conversionCode = (
+            "if (!ConvertJSValueToByteString(cx, ${val}, ${mutableVal},"
+            " %s, ${declName})) {\n"
+            "%s\n"
+            "}" % (nullable, exceptionCodeIndented.define()))
+        # ByteString arguments cannot have a default value.
+        assert defaultValue is None
+
+        return JSToNativeConversionInfo(
+            conversionCode,
+            declType=CGGeneric("nsCString"),
+            dealWithOptional=isOptional)
+
     if type.isEnum():
         assert not isEnforceRange and not isClamp
 
         enumName = type.unroll().inner.identifier.name
         declType = CGGeneric(enumName)
         if type.nullable():
             declType = CGTemplatedType("Nullable", declType)
             declType = declType.define()
@@ -3977,22 +3995,28 @@ if (!returnArray) {
             else:
                 getIID = ""
             wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalHandle})" % (result, getIID)
             failed = None
 
         wrappingCode += wrapAndSetPtr(wrap, failed)
         return (wrappingCode, False)
 
-    if type.isString():
+    if type.isDOMString():
         if type.nullable():
             return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalRef}.address())" % result), False)
         else:
             return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalRef}.address())" % result), False)
 
+    if type.isByteString():
+        if type.nullable():
+            return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
+        else:
+            return (wrapAndSetPtr("NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
+
     if type.isEnum():
         if type.nullable():
             resultLoc = "%s.Value()" % result
         else:
             resultLoc = result
         conversion = ("""{
   // Scope for resultStr
   MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
@@ -4198,20 +4222,22 @@ def getRetvalDeclarationForType(returnTy
     if returnType is None or returnType.isVoid():
         # Nothing to declare
         return None, False, None, None
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, False, None, None
-    if returnType.isString():
+    if returnType.isDOMString():
         if isMember:
             return CGGeneric("nsString"), True, None, None
         return CGGeneric("DOMString"), True, None, None
+    if returnType.isByteString():
+        return CGGeneric("nsCString"), True, None, None
     if returnType.isEnum():
         result = CGGeneric(returnType.unroll().inner.identifier.name)
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, False, None, None
     if returnType.isGeckoInterface():
         result = CGGeneric(descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeType)
@@ -5674,19 +5700,22 @@ def getUnionAccessorSignatureType(type, 
     if type.isSpiderMonkeyInterface():
         typeName = CGGeneric(type.name)
         if type.nullable():
             typeName = CGWrapper(typeName, post="*")
         else:
             typeName = CGWrapper(typeName, post="&")
         return typeName
 
-    if type.isString():
+    if type.isDOMString():
         return CGGeneric("const nsAString&")
 
+    if type.isByteString():
+        return CGGeneric("const nsCString&")
+
     if type.isEnum():
         if type.nullable():
             raise TypeError("We don't support nullable enumerated arguments or "
                             "union members yet")
         return CGGeneric(type.inner.identifier.name)
 
     if type.isCallback():
         if descriptorProvider.workers:
@@ -8478,22 +8507,28 @@ class CGNativeMember(ClassMethod):
             result = CGGeneric(builtinNames[type.tag()])
             defaultReturnArg = "0"
             if type.nullable():
                 result = CGTemplatedType("Nullable", result)
                 defaultReturnArg = ""
             return (result.define(),
                     "%s(%s)" % (result.define(), defaultReturnArg),
                     "return ${declName};")
-        if type.isString():
+        if type.isDOMString():
             if isMember:
                 # No need for a third element in the isMember case
                 return "nsString", None, None
             # Outparam
             return "void", "", "retval = ${declName};"
+        if type.isByteString():
+            if isMember:
+                # No need for a third element in the isMember case
+                return "nsCString", None, None
+            # Outparam
+            return "void", "", "retval = ${declName};"
         if type.isEnum():
             enumName = type.unroll().inner.identifier.name
             if type.nullable():
                 enumName = CGTemplatedType("Nullable",
                                            CGGeneric(enumName)).define()
                 defaultValue = "%s()" % enumName
             else:
                 defaultValue = "%s(0)" % enumName
@@ -8562,18 +8597,20 @@ class CGNativeMember(ClassMethod):
             return (result.define(), "%s()" % result.define(),
                     "return ${declName};")
         raise TypeError("Don't know how to declare return value for %s" %
                         type)
 
     def getArgs(self, returnType, argList):
         args = [self.getArg(arg) for arg in argList]
         # Now the outparams
-        if returnType.isString():
+        if returnType.isDOMString():
             args.append(Argument("nsString&", "retval"))
+        if returnType.isByteString():
+            args.append(Argument("nsCString&", "retval"))
         elif returnType.isSequence():
             nullable = returnType.nullable()
             if nullable:
                 returnType = returnType.inner
             # And now the actual underlying type
             elementDecl = self.getReturnType(returnType.inner, True)
             type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
             if nullable:
@@ -8657,23 +8694,27 @@ class CGNativeMember(ClassMethod):
                     typeDecl = "%s*"
                 else:
                     typeDecl = "%s"
                     if not optional:
                         typeDecl += "&"
                 typeDecl = typeDecl % type.name
             return typeDecl, False, False
 
-        if type.isString():
+        if type.isDOMString():
             if isMember:
                 declType = "nsString"
             else:
                 declType = "nsAString"
             return declType, True, False
 
+        if type.isByteString():
+            declType = "nsCString"
+            return declType, True, False
+
         if type.isEnum():
             return type.unroll().inner.identifier.name, False, True
 
         if type.isCallback() or type.isCallbackInterface():
             forceOwningType = optional or isMember
             if type.nullable():
                 if forceOwningType:
                     declType = "nsRefPtr<%s>"
@@ -9530,17 +9571,17 @@ class CallbackMember(CGNativeMember):
 
         if arg.variadic:
             argval = argval + "[idx]"
             jsvalIndex = "%d + idx" % i
         else:
             jsvalIndex = "%d" % i
             if arg.optional and not arg.defaultValue:
                 argval += ".Value()"
-        if arg.type.isString():
+        if arg.type.isDOMString():
             # XPConnect string-to-JS conversion wants to mutate the string.  So
             # let's give it a string it can mutate
             # XXXbz if we try to do a sequence of strings, this will kinda fail.
             result = "mutableStr"
             prepend = "nsString mutableStr(%s);\n" % argval
         else:
             result = argval
             prepend = ""
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -32,9 +32,11 @@ MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 
 MSG_DEF(MSG_NOT_SEQUENCE, 0, "Value can not be converted to a sequence.")
 MSG_DEF(MSG_NOT_DICTIONARY, 0, "Value can not be converted to a dictionary.")
 MSG_DEF(MSG_INVALID_ARG, 2, "Argument {0} is not valid for any of the {1}-argument overloads.")
 MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "Global is not a native object.")
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
 MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")
 MSG_DEF(MSG_NOT_FINITE, 0, "Floating-point value is not finite.")
 MSG_DEF(MSG_INVALID_VERSION, 0, "0 (Zero) is not a valid database version.")
+MSG_DEF(MSG_INVALID_BYTESTRING, 2, "Cannot convert string to ByteString because the character"
+        " at index {0} has value {1} which is greater than 255.")
 MSG_DEF(MSG_NOT_DATE, 0, "Value is not a date.")
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -132,16 +132,20 @@ public:
   */
 
   static
   already_AddRefed<TestInterface> Test(const GlobalObject&, ErrorResult&);
   static
   already_AddRefed<TestInterface> Test(const GlobalObject&, const nsAString&,
                                        ErrorResult&);
   static
+  already_AddRefed<TestInterface> Test(const GlobalObject&, const nsACString&,
+                                       ErrorResult&);
+
+  static
   already_AddRefed<TestInterface> Test2(const GlobalObject&,
                                         JSContext*,
                                         const DictForConstructor&,
                                         JS::Value,
                                         JS::Handle<JSObject*>,
                                         JS::Handle<JSObject*>,
                                         const Sequence<Dict>&,
                                         const Optional<JS::Handle<JS::Value> >&,
@@ -365,16 +369,19 @@ public:
   void PassOptionalNullableSequenceWithDefaultValue(const Nullable< Sequence<int32_t> >&);
   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 ReceiveByteStringSequence(nsTArray<nsCString>&);
+  void PassByteStringSequence(const Sequence<nsCString>&);
+
   void ReceiveAnySequence(JSContext*, 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> >&);
@@ -393,27 +400,34 @@ public:
   void PassUint8Array(Uint8Array&);
   void PassUint16Array(Uint16Array&);
   void PassUint32Array(Uint32Array&);
   void PassUint8ClampedArray(Uint8ClampedArray&);
   void PassFloat32Array(Float32Array&);
   void PassFloat64Array(Float64Array&);
   JSObject* ReceiveUint8Array(JSContext*);
 
-  // String types
+  // DOMString types
   void PassString(const nsAString&);
   void PassNullableString(const nsAString&);
   void PassOptionalString(const Optional<nsAString>&);
   void PassOptionalUndefinedMissingString(const Optional<nsAString>&);
   void PassOptionalStringWithDefaultValue(const nsAString&);
   void PassOptionalUndefinedMissingStringWithDefaultValue(const nsAString&);
   void PassOptionalNullableString(const Optional<nsAString>&);
   void PassOptionalNullableStringWithDefaultValue(const nsAString&);
   void PassVariadicString(const Sequence<nsString>&);
 
+  // ByteString types
+  void PassByteString(const nsCString&);
+  void PassNullableByteString(const nsCString&);
+  void PassOptionalByteString(const Optional<nsCString>&);
+  void PassOptionalNullableByteString(const Optional<nsCString>&);
+  void PassVariadicByteString(const Sequence<nsCString>&);
+
   // Enumerated types
   void PassEnum(TestEnum);
   void PassNullableEnum(const Nullable<TestEnum>&);
   void PassOptionalEnum(const Optional<TestEnum>&);
   void PassEnumWithDefault(TestEnum);
   void PassOptionalNullableEnum(const Optional<Nullable<TestEnum> >&);
   void PassOptionalNullableEnumWithDefaultValue(const Nullable<TestEnum>&);
   void PassOptionalNullableEnumWithDefaultValue2(const Nullable<TestEnum>&);
@@ -748,16 +762,23 @@ private:
   void PassString(nsAString&) MOZ_DELETE;
   void PassNullableString(nsAString&) MOZ_DELETE;
   void PassOptionalString(Optional<nsAString>&) MOZ_DELETE;
   void PassOptionalStringWithDefaultValue(nsAString&) MOZ_DELETE;
   void PassOptionalNullableString(Optional<nsAString>&) MOZ_DELETE;
   void PassOptionalNullableStringWithDefaultValue(nsAString&) MOZ_DELETE;
   void PassVariadicString(Sequence<nsString>&) MOZ_DELETE;
 
+  // cstrings should be const as well
+  void PassByteString(nsCString&) MOZ_DELETE;
+  void PassNullableByteString(nsCString&) MOZ_DELETE;
+  void PassOptionalByteString(Optional<nsCString>&) MOZ_DELETE;
+  void PassOptionalNullableByteString(Optional<nsCString>&) MOZ_DELETE;
+  void PassVariadicByteString(Sequence<nsCString>&) MOZ_DELETE;
+
   // Make sure dictionary arguments are always const
   void PassDictionary(JSContext*, Dict&) MOZ_DELETE;
   void PassOtherDictionary(GrandparentDict&) MOZ_DELETE;
   void PassSequenceOfDictionaries(JSContext*, Sequence<Dict>&) MOZ_DELETE;
   void PassDictionaryOrLong(JSContext*, Dict&) MOZ_DELETE;
   void PassDictContainingDict(JSContext*, DictContainingDict&) MOZ_DELETE;
   void PassDictContainingSequence(DictContainingSequence&) MOZ_DELETE;
 
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -333,16 +333,19 @@ interface TestInterface {
   void passOptionalNullableSequenceWithDefaultValue(optional sequence<long>? arg = null);
   void passOptionalObjectSequence(optional sequence<TestInterface> arg);
   void passExternalInterfaceSequence(sequence<TestExternalInterface> arg);
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   void passStringSequence(sequence<DOMString> arg);
 
+  sequence<ByteString> receiveByteStringSequence();
+  void passByteStringSequence(sequence<ByteString> arg);
+
   sequence<any> receiveAnySequence();
   sequence<any>? receiveNullableAnySequence();
   sequence<sequence<any>> receiveAnySequenceSequence();
 
   sequence<object> receiveObjectSequence();
   sequence<object?> receiveNullableObjectSequence();
 
   void passSequenceOfSequences(sequence<sequence<long>> arg);
@@ -361,27 +364,34 @@ interface TestInterface {
   void passUint8Array(Uint8Array arg);
   void passUint16Array(Uint16Array arg);
   void passUint32Array(Uint32Array arg);
   void passUint8ClampedArray(Uint8ClampedArray arg);
   void passFloat32Array(Float32Array arg);
   void passFloat64Array(Float64Array arg);
   Uint8Array receiveUint8Array();
 
-  // String types
+  // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
   void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
   void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
+  // ByteString types
+  void passByteString(ByteString arg);
+  void passNullableByteString(ByteString? arg);
+  void passOptionalByteString(optional ByteString arg);
+  void passOptionalNullableByteString(optional ByteString? arg);
+  void passVariadicByteString(ByteString... arg);
+
   // Enumerated types
   void passEnum(TestEnum arg);
   void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   void passEnumWithDefault(optional TestEnum arg = "a");
   void passOptionalNullableEnum(optional TestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
   void passOptionalNullableEnumWithDefaultValue2(optional TestEnum? arg = "a");
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -229,16 +229,19 @@ interface TestExampleInterface {
   void passOptionalNullableSequenceWithDefaultValue(optional sequence<long>? arg = null);
   void passOptionalObjectSequence(optional sequence<TestInterface> arg);
   void passExternalInterfaceSequence(sequence<TestExternalInterface> arg);
   void passNullableExternalInterfaceSequence(sequence<TestExternalInterface?> arg);
 
   sequence<DOMString> receiveStringSequence();
   void passStringSequence(sequence<DOMString> arg);
 
+  sequence<ByteString> receiveByteStringSequence();
+  void passByteStringSequence(sequence<ByteString> 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();
 
@@ -259,27 +262,34 @@ interface TestExampleInterface {
   void passUint8Array(Uint8Array arg);
   void passUint16Array(Uint16Array arg);
   void passUint32Array(Uint32Array arg);
   void passUint8ClampedArray(Uint8ClampedArray arg);
   void passFloat32Array(Float32Array arg);
   void passFloat64Array(Float64Array arg);
   Uint8Array receiveUint8Array();
 
-  // String types
+  // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
   void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
   void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
+  // ByteString types
+  void passByteString(ByteString arg);
+  void passNullableByteString(ByteString? arg);
+  void passOptionalByteString(optional ByteString arg);
+  void passOptionalNullableByteString(optional ByteString? arg);
+  void passVariadicByteString(ByteString... arg);
+
   // Enumerated types
   void passEnum(TestEnum arg);
   void passNullableEnum(TestEnum? arg);
   void passOptionalEnum(optional TestEnum arg);
   void passEnumWithDefault(optional TestEnum arg = "a");
   void passOptionalNullableEnum(optional TestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null);
   void passOptionalNullableEnumWithDefaultValue2(optional TestEnum? arg = "a");
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -247,16 +247,17 @@ interface TestJSImplInterface {
   void passOptionalSequence(optional sequence<long> arg);
   void passOptionalNullableSequence(optional sequence<long>? arg);
   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();
+  sequence<ByteString> receiveByteStringSequence();
   // Callback interface problem.  See bug 843261.
   //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();
@@ -282,27 +283,34 @@ interface TestJSImplInterface {
   //void passUint8Array(Uint8Array arg);
   //void passUint16Array(Uint16Array arg);
   //void passUint32Array(Uint32Array arg);
   //void passUint8ClampedArray(Uint8ClampedArray arg);
   //void passFloat32Array(Float32Array arg);
   //void passFloat64Array(Float64Array arg);
   //Uint8Array receiveUint8Array();
 
-  // String types
+  // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
   void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
   void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
+  // ByteString types
+  void passByteString(ByteString arg);
+  void passNullableByteString(ByteString? arg);
+  void passOptionalByteString(optional ByteString arg);
+  void passOptionalNullableByteString(optional ByteString? arg);
+  void passVariadicByteString(ByteString... arg);
+
   // Enumerated types
   void passEnum(MyTestEnum arg);
   void passNullableEnum(MyTestEnum? arg);
   void passOptionalEnum(optional MyTestEnum arg);
   void passEnumWithDefault(optional MyTestEnum arg = "a");
   void passOptionalNullableEnum(optional MyTestEnum? arg);
   void passOptionalNullableEnumWithDefaultValue(optional MyTestEnum? arg = null);
   void passOptionalNullableEnumWithDefaultValue2(optional MyTestEnum? arg = "a");