Bug 1269719 - Check hasTwoByteChars for all strings used in replace operation. r=h4writer
authorTooru Fujisawa <arai_a@mac.com>
Thu, 05 May 2016 06:00:48 +0900
changeset 296141 5fa2e1397aca364125bb7859414a7af2244d4f30
parent 296140 7db4faf3e32b32c9862c92d895ac5a014b29738f
child 296142 b9482cba39f34ac1fb886a3e73c9b2f991645620
push id76217
push userarai_a@mac.com
push dateWed, 04 May 2016 21:48:42 +0000
treeherdermozilla-inbound@5fa2e1397aca [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1269719
milestone49.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 1269719 - Check hasTwoByteChars for all strings used in replace operation. r=h4writer
js/src/builtin/RegExp.cpp
js/src/tests/ecma_6/RegExp/replace-twoBytes.js
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1350,16 +1350,38 @@ DoReplace(HandleLinearString matched, Ha
             currentDollar++;
         }
 
         currentDollar = js_strchr_limit(currentDollar, '$', replacementEnd);
     } while (currentDollar);
     sb.infallibleAppend(currentChar, replacement->length() - (currentChar - replacementBegin));
 }
 
+static bool
+NeedTwoBytes(HandleLinearString string, HandleLinearString replacement,
+             HandleLinearString matched, Handle<GCVector<Value>> captures)
+{
+    if (string->hasTwoByteChars())
+        return true;
+    if (replacement->hasTwoByteChars())
+        return true;
+    if (matched->hasTwoByteChars())
+        return true;
+
+    for (size_t i = 0, len = captures.length(); i < len; i++) {
+        Value capture = captures[i];
+        if (capture.isUndefined())
+            continue;
+        if (capture.toString()->hasTwoByteChars())
+            return true;
+    }
+
+    return false;
+}
+
 /* ES 2016 draft Mar 25, 2016 21.1.3.14.1. */
 bool
 js::RegExpGetSubstitution(JSContext* cx, HandleLinearString matched, HandleLinearString string,
                           size_t position, HandleObject capturesObj, HandleLinearString replacement,
                           size_t firstDollarIndex, MutableHandleValue rval)
 {
     MOZ_ASSERT(firstDollarIndex < replacement->length());
 
@@ -1416,17 +1438,17 @@ js::RegExpGetSubstitution(JSContext* cx,
     size_t reserveLength;
     if (!FindReplaceLength(cx, matched, string, position, tailPos, &captures, replacement,
                            firstDollarIndex, &reserveLength))
     {
         return false;
     }
 
     StringBuffer result(cx);
-    if (string->hasTwoByteChars() || replacement->hasTwoByteChars()) {
+    if (NeedTwoBytes(string, replacement, matched, captures)) {
         if (!result.ensureTwoByteChars())
             return false;
     }
 
     if (!result.reserve(reserveLength))
         return false;
 
     if (replacement->hasLatin1Chars()) {
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/replace-twoBytes.js
@@ -0,0 +1,44 @@
+var BUGNUMBER = 1269719;
+var summary = "RegExp.prototype[@@replace] should check latin1/twoBytes for all strings used in relate operation.";
+
+print(BUGNUMBER + ": " + summary);
+
+var ans = [
+  "[AB$2$3$]",
+  "[AB$2$3$]\u3048",
+  "[AB$2$3$]",
+  "[AB$2$3$]\u3048",
+  "[A\u3044$2$3$]",
+  "[A\u3044$2$3$]\u3048",
+  "[A\u3044$2$3$]",
+  "[A\u3044$2$3$]\u3048",
+  "[\u3042B$2$3$]",
+  "[\u3042B$2$3$]\u3048",
+  "[\u3042B$2$3$]",
+  "[\u3042B$2$3$]\u3048",
+  "[\u3042\u3044$2$3$]",
+  "[\u3042\u3044$2$3$]\u3048",
+  "[\u3042\u3044$2$3$]",
+  "[\u3042\u3044$2$3$]\u3048",
+];
+var i = 0;
+for (var matched of ["A", "\u3042"]) {
+  for (var group1 of ["B", "\u3044"]) {
+    for (var string of ["C", "\u3046"]) {
+      for (var replacement of ["[$&$`$'$1$2$3$]", "[$&$`$'$1$2$3$]\u3048"]) {
+        var myRegExp = {
+          get exec() {
+            return function() {
+              return [matched, group1];
+            };
+          }
+        };
+        assertEq(RegExp.prototype[Symbol.replace].call(myRegExp, string, replacement), ans[i]);
+        i++;
+      }
+    }
+  }
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);