Revision: 13581
Author:   [email protected]
Date:     Mon Feb  4 02:20:26 2013
Log:      Merged r13471, r13504 into 3.15 branch.

Correctly reset lastIndex in an RegExp object.

Fix additional spec violations wrt RegExp.lastIndex.

BUG=170856,v8:2437

[email protected]

Review URL: https://chromiumcodereview.appspot.com/12186012
http://code.google.com/p/v8/source/detail?r=13581

Added:
 /branches/3.15/test/mjsunit/regress/regress-crbug-170856.js
Modified:
 /branches/3.15/src/objects-inl.h
 /branches/3.15/src/objects.h
 /branches/3.15/src/runtime.cc
 /branches/3.15/src/string.js
 /branches/3.15/src/version.cc
 /branches/3.15/test/mjsunit/regress/regress-2437.js

=======================================
--- /dev/null
+++ /branches/3.15/test/mjsunit/regress/regress-crbug-170856.js Mon Feb 4 02:20:26 2013
@@ -0,0 +1,33 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+r = new RegExp("a");
+for (var i = 0; i < 100; i++) {
+  r["abc" + i] = i;
+}
+"zzzz".replace(r, "");
+assertEquals(0, r.lastIndex);
=======================================
--- /branches/3.15/src/objects-inl.h    Wed Jan 30 05:57:19 2013
+++ /branches/3.15/src/objects-inl.h    Mon Feb  4 02:20:26 2013
@@ -4966,13 +4966,6 @@
     fa->set_unchecked(heap, index, value, SKIP_WRITE_BARRIER);
   }
 }
-
-
-void JSRegExp::ResetLastIndex() {
-  InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
-                        Smi::FromInt(0),
-                        SKIP_WRITE_BARRIER);  // It's a Smi.
-}


 ElementsKind JSObject::GetElementsKind() {
=======================================
--- /branches/3.15/src/objects.h        Wed Jan 30 05:57:19 2013
+++ /branches/3.15/src/objects.h        Mon Feb  4 02:20:26 2013
@@ -6649,7 +6649,6 @@
   inline Object* DataAtUnchecked(int index);
   inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
   inline Type TypeTagUnchecked();
-  inline void ResetLastIndex();

   static int code_index(bool is_ascii) {
     if (is_ascii) {
=======================================
--- /branches/3.15/src/runtime.cc       Wed Jan 30 05:57:19 2013
+++ /branches/3.15/src/runtime.cc       Mon Feb  4 02:20:26 2013
@@ -1791,7 +1791,8 @@
         JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
     regexp->InObjectPropertyAtPut(
         JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
-    regexp->ResetLastIndex();
+    regexp->InObjectPropertyAtPut(
+ JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
     return regexp;
   }

@@ -2904,8 +2905,7 @@

   int matches = indices.length();
   if (matches == 0) {
-    pattern_regexp->ResetLastIndex();
-    return *subject;
+    return isolate->heap()->undefined_value();
   }

   // Detect integer overflow.
@@ -3006,8 +3006,7 @@
   int32_t* current_match = global_cache.FetchNext();
   if (current_match == NULL) {
     if (global_cache.HasException()) return Failure::Exception();
-    regexp->ResetLastIndex();
-    return *subject;
+    return isolate->heap()->undefined_value();
   }

   // Guessing the number of parts that the final result string is built
@@ -3105,8 +3104,7 @@
   int32_t* current_match = global_cache.FetchNext();
   if (current_match == NULL) {
     if (global_cache.HasException()) return Failure::Exception();
-    regexp->ResetLastIndex();
-    return *subject;
+    return isolate->heap()->undefined_value();
   }

   int start = current_match[0];
=======================================
--- /branches/3.15/src/string.js        Thu Jan 10 23:27:44 2013
+++ /branches/3.15/src/string.js        Mon Feb  4 02:20:26 2013
@@ -194,6 +194,7 @@
     // lastMatchInfo is defined in regexp.js.
     var result = %StringMatch(subject, regexp, lastMatchInfo);
     if (result !== null) lastMatchInfoOverride = null;
+    regexp.lastIndex = 0;
     return result;
   }
   // Non-regexp argument.
@@ -244,10 +245,16 @@
       }
     } else {
       if (lastMatchInfoOverride == null) {
-        return %StringReplaceRegExpWithString(subject,
-                                              search,
-                                              TO_STRING_INLINE(replace),
-                                              lastMatchInfo);
+        var answer = %StringReplaceRegExpWithString(subject,
+                                                    search,
+ TO_STRING_INLINE(replace),
+                                                    lastMatchInfo);
+        if (IS_UNDEFINED(answer)) {  // No match.  Return subject string.
+          search.lastIndex = 0;
+          return subject;
+        }
+        if (search.global) search.lastIndex = 0;
+        return answer;
       } else {
         // We use this hack to detect whether StringReplaceRegExpWithString
         // found at least one hit.  In that case we need to remove any
@@ -258,11 +265,17 @@
                                                     search,
TO_STRING_INLINE(replace),
                                                     lastMatchInfo);
+        if (IS_UNDEFINED(answer)) {  // No match.  Return subject string.
+          search.lastIndex = 0;
+          lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
+          return subject;
+        }
         if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
           lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
         } else {
           lastMatchInfoOverride = null;
         }
+        if (search.global) search.lastIndex = 0;
         return answer;
       }
     }
=======================================
--- /branches/3.15/src/version.cc       Wed Jan 30 05:57:19 2013
+++ /branches/3.15/src/version.cc       Mon Feb  4 02:20:26 2013
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     15
 #define BUILD_NUMBER      11
-#define PATCH_LEVEL       14
+#define PATCH_LEVEL       15
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
=======================================
--- /branches/3.15/test/mjsunit/regress/regress-2437.js Thu Dec 6 09:32:37 2012 +++ /branches/3.15/test/mjsunit/regress/regress-2437.js Mon Feb 4 02:20:26 2013
@@ -25,6 +25,14 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+// Summary of the spec: lastIndex is reset to 0 if
+// - a regexp fails to match, regardless of global or non-global.
+// - a global regexp is used in a function that returns multiple results,
+//   such as String.prototype.replace or String.prototype.match, since it
+//   repeats the regexp until it fails to match.
+// Otherwise lastIndex is only set when a global regexp matches, to the index
+// after the match.
+
 // Test Regexp.prototype.exec
 r = /a/;
 r.lastIndex = 1;
@@ -73,3 +81,76 @@
 "zzzz".replace(r, function() { return ""; });
 assertEquals(0, r.lastIndex);

+// Regexp functions that returns multiple results:
+// A global regexp always resets lastIndex regardless of whether it matches.
+r = /a/g;
+r.lastIndex = -1;
+"0123abcd".replace(r, "x");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".replace(r, "x");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"0123abcd".match(r);
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".match(r);
+assertEquals(0, r.lastIndex);
+
+// A non-global regexp resets lastIndex iff it does not match.
+r = /a/;
+r.lastIndex = -1;
+"0123abcd".replace(r, "x");
+assertEquals(-1, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".replace(r, "x");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = -1;
+"0123abcd".match(r);
+assertEquals(-1, r.lastIndex);
+
+r.lastIndex = -1;
+"01234567".match(r);
+assertEquals(0, r.lastIndex);
+
+// Also test RegExp.prototype.exec and RegExp.prototype.test
+r = /a/g;
+r.lastIndex = 1;
+r.exec("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.exec("0123abcd");
+assertEquals(5, r.lastIndex);
+
+r = /a/;
+r.lastIndex = 1;
+r.exec("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.exec("0123abcd");
+assertEquals(1, r.lastIndex);
+
+r = /a/g;
+r.lastIndex = 1;
+r.test("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.test("0123abcd");
+assertEquals(5, r.lastIndex);
+
+r = /a/;
+r.lastIndex = 1;
+r.test("01234567");
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 1;
+r.test("0123abcd");
+assertEquals(1, r.lastIndex);

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to