Bug 903391: Evaluate both arguments in String.prototype.lastIndexOf. r=till
authorAndré Bargull <andre.bargull@gmail.com>
Tue, 18 Oct 2016 11:44:11 -0700
changeset 318737 6f0a1da93428b08df5aabe05f1ae0776564753b5
parent 318736 75faf4827dcf906c0e6573affa6ce1689fd79ea8
child 318738 c9ddce297cab3e3cb400057122d9946493e38c3f
push id20727
push usercbook@mozilla.com
push dateThu, 20 Oct 2016 14:51:54 +0000
treeherderfx-team@11ae641575dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs903391
milestone52.0a1
Bug 903391: Evaluate both arguments in String.prototype.lastIndexOf. r=till
js/src/jsstr.cpp
js/src/tests/ecma/String/lastIndexOf-ToNumber-when-searchStr-larger-than-string.js
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1695,36 +1695,41 @@ LastIndexOfImpl(const TextChar* text, si
             return static_cast<int32_t>(t - text);
         }
       break_continue:;
     }
 
     return -1;
 }
 
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 21.1.3.9 String.prototype.lastIndexOf ( searchString [ , position ] )
 bool
 js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedString textstr(cx, ToStringForStringFunction(cx, args.thisv()));
-    if (!textstr)
+
+    // Steps 1-2.
+    RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
+    if (!str)
         return false;
 
-    RootedLinearString pat(cx, ArgToRootedString(cx, args, 0));
-    if (!pat)
+    // Step 3.
+    RootedLinearString searchStr(cx, ArgToRootedString(cx, args, 0));
+    if (!searchStr)
         return false;
 
-    size_t textLen = textstr->length();
-    size_t patLen = pat->length();
-    int start = textLen - patLen; // Start searching here
-    if (start < 0) {
-        args.rval().setInt32(-1);
-        return true;
-    }
-
+    // Step 6.
+    size_t len = str->length();
+
+    // Step 8.
+    size_t searchLen = searchStr->length();
+
+    // Steps 4-5, 7.
+    int start = len - searchLen; // Start searching here
     if (args.hasDefined(1)) {
         if (args[1].isInt32()) {
             int i = args[1].toInt32();
             if (i <= 0)
                 start = 0;
             else if (i < start)
                 start = i;
         } else {
@@ -1736,39 +1741,46 @@ js::str_lastIndexOf(JSContext* cx, unsig
                 if (d <= 0)
                     start = 0;
                 else if (d < start)
                     start = int(d);
             }
         }
     }
 
-    if (patLen == 0) {
+    if (searchLen > len) {
+        args.rval().setInt32(-1);
+        return true;
+    }
+
+    if (searchLen == 0) {
         args.rval().setInt32(start);
         return true;
     }
-
-    JSLinearString* text = textstr->ensureLinear(cx);
+    MOZ_ASSERT(0 <= start && size_t(start) < len);
+
+    JSLinearString* text = str->ensureLinear(cx);
     if (!text)
         return false;
 
+    // Step 9.
     int32_t res;
     AutoCheckCannotGC nogc;
     if (text->hasLatin1Chars()) {
         const Latin1Char* textChars = text->latin1Chars(nogc);
-        if (pat->hasLatin1Chars())
-            res = LastIndexOfImpl(textChars, textLen, pat->latin1Chars(nogc), patLen, start);
+        if (searchStr->hasLatin1Chars())
+            res = LastIndexOfImpl(textChars, len, searchStr->latin1Chars(nogc), searchLen, start);
         else
-            res = LastIndexOfImpl(textChars, textLen, pat->twoByteChars(nogc), patLen, start);
+            res = LastIndexOfImpl(textChars, len, searchStr->twoByteChars(nogc), searchLen, start);
     } else {
         const char16_t* textChars = text->twoByteChars(nogc);
-        if (pat->hasLatin1Chars())
-            res = LastIndexOfImpl(textChars, textLen, pat->latin1Chars(nogc), patLen, start);
+        if (searchStr->hasLatin1Chars())
+            res = LastIndexOfImpl(textChars, len, searchStr->latin1Chars(nogc), searchLen, start);
         else
-            res = LastIndexOfImpl(textChars, textLen, pat->twoByteChars(nogc), patLen, start);
+            res = LastIndexOfImpl(textChars, len, searchStr->twoByteChars(nogc), searchLen, start);
     }
 
     args.rval().setInt32(res);
     return true;
 }
 
 bool
 js::HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma/String/lastIndexOf-ToNumber-when-searchStr-larger-than-string.js
@@ -0,0 +1,22 @@
+/* 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/. */
+
+var str = "a";
+var searchStr = "abc";
+
+var position = new Object();
+var valueOfCalled = false;
+function positionValueOf() {
+    assertEq(valueOfCalled, false);
+    valueOfCalled = true;
+    return 0;
+}
+position.valueOf = positionValueOf;
+
+var result = str.lastIndexOf(searchStr, position);
+assertEq(result, -1);
+assertEq(valueOfCalled, true);
+
+if (typeof reportCompare == "function")
+    reportCompare(0, 0);