Bug 910795 part 2. Use the new Rebind() setup to avoid creating string copies for variadic string arguments. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 04 Sep 2013 16:43:12 -0400
changeset 145497 3e07ffec398e5116c080b48ac819f03f637d6b81
parent 145496 d42f8528d09f8b41bd8b15efe878eed35694a201
child 145498 8790cc20505b55680fb9de88a20019eedd6cbe1f
push id33298
push userbzbarsky@mozilla.com
push dateWed, 04 Sep 2013 20:43:35 +0000
treeherdermozilla-inbound@8790cc20505b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs910795
milestone26.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 910795 part 2. Use the new Rebind() setup to avoid creating string copies for variadic string arguments. r=smaug
content/base/src/nsDOMTokenList.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -135,17 +135,16 @@ nsDOMTokenList::AddInternal(const nsAttr
   nsAutoString resultStr;
 
   if (aAttr) {
     aAttr->ToString(resultStr);
   }
 
   bool oneWasAdded = false;
   nsAutoTArray<nsString, 10> addedClasses;
-  addedClasses.SetCapacity(aTokens.Length());
 
   for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
     const nsString& aToken = aTokens[i];
 
     if ((aAttr && aAttr->Contains(aToken)) ||
         addedClasses.Contains(aToken)) {
       continue;
     }
@@ -175,19 +174,19 @@ nsDOMTokenList::Add(const nsTArray<nsStr
 
   const nsAttrValue* attr = GetParsedAttr();
   AddInternal(attr, aTokens);
 }
 
 void
 nsDOMTokenList::Add(const nsAString& aToken, mozilla::ErrorResult& aError)
 {
-  nsAutoTArray<nsString, 1> aTokens;
-  aTokens.AppendElement(aToken);
-  Add(aTokens, aError);
+  nsAutoTArray<nsString, 1> tokens;
+  tokens.AppendElement(aToken);
+  Add(tokens, aError);
 }
 
 void
 nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
                                const nsTArray<nsString>& aTokens)
 {
   NS_ABORT_IF_FALSE(aAttr, "Need an attribute");
 
@@ -261,19 +260,19 @@ nsDOMTokenList::Remove(const nsTArray<ns
   }
 
   RemoveInternal(attr, aTokens);
 }
 
 void
 nsDOMTokenList::Remove(const nsAString& aToken, mozilla::ErrorResult& aError)
 {
-  nsAutoTArray<nsString, 1> aTokens;
-  aTokens.AppendElement(aToken);
-  Remove(aTokens, aError);
+  nsAutoTArray<nsString, 1> tokens;
+  tokens.AppendElement(aToken);
+  Remove(tokens, aError);
 }
 
 bool
 nsDOMTokenList::Toggle(const nsAString& aToken,
                        const Optional<bool>& aForce,
                        ErrorResult& aError)
 {
   aError = CheckToken(aToken);
@@ -281,27 +280,27 @@ nsDOMTokenList::Toggle(const nsAString& 
     return false;
   }
 
   const nsAttrValue* attr = GetParsedAttr();
   const bool forceOn = aForce.WasPassed() && aForce.Value();
   const bool forceOff = aForce.WasPassed() && !aForce.Value();
 
   bool isPresent = attr && attr->Contains(aToken);
-  nsAutoTArray<nsString, 1> aTokens;
-  aTokens.AppendElement(aToken);
+  nsAutoTArray<nsString, 1> tokens;
+  (*tokens.AppendElement()).Rebind(aToken.Data(), aToken.Length());
 
   if (isPresent) {
     if (!forceOn) {
-      RemoveInternal(attr, aTokens);
+      RemoveInternal(attr, tokens);
       isPresent = false;
     }
   } else {
     if (!forceOff) {
-      AddInternal(attr, aTokens);
+      AddInternal(attr, tokens);
       isPresent = true;
     }
   }
 
   return isPresent;
 }
 
 void
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1508,16 +1508,26 @@ struct FakeDependentString {
     mLength = 0;
   }
 
   void SetNull() {
     Truncate();
     mFlags |= nsDependentString::F_VOIDED;
   }
 
+  const nsDependentString::char_type* Data() const
+  {
+    return mData;
+  }
+
+  nsDependentString::size_type Length() const
+  {
+    return mLength;
+  }
+
   // If this ever changes, change the corresponding code in the
   // Optional<nsAString> specialization as well.
   const nsAString* ToAStringPtr() const {
     return reinterpret_cast<const nsDependentString*>(this);
   }
 
   nsAString* ToAStringPtr() {
     return reinterpret_cast<nsDependentString*>(this);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3391,25 +3391,33 @@ for (uint32_t i = 0; i < length; ++i) {
                 assert(type.nullable())
                 defaultCode = "%s.SetNull()" % varName
             else:
                 defaultCode = handleDefaultStringValue(defaultValue,
                                                        "%s.SetData" % varName)
             return handleDefault(conversionCode, defaultCode)
 
         if isMember:
-            # We have to make a copy, because our jsval may well not
-            # live as long as our string needs to.
+            # We have to make a copy, except in the variadic case, because our
+            # jsval may well not live as long as our string needs to.
             declType = CGGeneric("nsString")
+            if isMember == "Variadic":
+                # The string is kept alive by the argument, so we can just
+                # depend on it.
+                assignString = "${declName}.Rebind(str.Data(), str.Length())"
+            else:
+                assignString = "${declName} = str"
             return JSToNativeConversionInfo(
                 "{\n"
                 "  FakeDependentString str;\n"
                 "%s\n"
-                "  ${declName} = str;\n"
-                "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(),
+                "  %s;\n"
+                "}\n" % (
+                    CGIndenter(CGGeneric(getConversionCode("str"))).define(),
+                    assignString),
                 declType=declType, dealWithOptional=isOptional)
 
         if isOptional:
             declType = "Optional<nsAString>"
         elif isInUnionReturnValue:
             declType = "nsString"
         else:
             declType = "NonNull<nsAString>"