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.