Revision: 13504
Author: [email protected]
Date: Fri Jan 25 02:53:26 2013
Log: Fix additional spec violations wrt RegExp.lastIndex.
[email protected]
BUG=v8:2437
Review URL: https://chromiumcodereview.appspot.com/12033099
http://code.google.com/p/v8/source/detail?r=13504
Modified:
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/string.js
/branches/bleeding_edge/test/mjsunit/regress/regress-2437.js
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Thu Jan 24 03:55:05 2013
+++ /branches/bleeding_edge/src/objects-inl.h Fri Jan 25 02:53:26 2013
@@ -5073,17 +5073,6 @@
fa->set_unchecked(heap, index, value, SKIP_WRITE_BARRIER);
}
}
-
-
-void JSRegExp::ResetLastIndex(Isolate* isolate,
- Handle<JSRegExp> regexp) {
- // Reset lastIndex property to 0.
- SetProperty(regexp,
- isolate->factory()->last_index_symbol(),
- Handle<Smi>(Smi::FromInt(0)),
- ::NONE,
- kNonStrictMode);
-}
ElementsKind JSObject::GetElementsKind() {
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Jan 24 03:55:05 2013
+++ /branches/bleeding_edge/src/objects.h Fri Jan 25 02:53:26 2013
@@ -6622,8 +6622,6 @@
inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
inline Type TypeTagUnchecked();
- static inline void ResetLastIndex(Isolate* isolate, Handle<JSRegExp>
regexp);
-
static int code_index(bool is_ascii) {
if (is_ascii) {
return kIrregexpASCIICodeIndex;
=======================================
--- /branches/bleeding_edge/src/runtime.cc Wed Jan 23 04:28:16 2013
+++ /branches/bleeding_edge/src/runtime.cc Fri Jan 25 02:53:26 2013
@@ -2912,8 +2912,7 @@
int matches = indices.length();
if (matches == 0) {
- JSRegExp::ResetLastIndex(isolate, pattern_regexp);
- return *subject;
+ return isolate->heap()->undefined_value();
}
// Detect integer overflow.
@@ -3015,8 +3014,7 @@
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return Failure::Exception();
- JSRegExp::ResetLastIndex(isolate, regexp);
- return *subject;
+ return isolate->heap()->undefined_value();
}
// Guessing the number of parts that the final result string is built
@@ -3114,8 +3112,7 @@
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return Failure::Exception();
- JSRegExp::ResetLastIndex(isolate, regexp);
- return *subject;
+ return isolate->heap()->undefined_value();
}
int start = current_match[0];
=======================================
--- /branches/bleeding_edge/src/string.js Wed Jan 9 02:30:54 2013
+++ /branches/bleeding_edge/src/string.js Fri Jan 25 02:53: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,13 +245,19 @@
}
} 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
+ // found at least one hit. In that case we need to remove any
// override.
var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX];
lastMatchInfo[LAST_SUBJECT_INDEX] = 0;
@@ -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/bleeding_edge/test/mjsunit/regress/regress-2437.js Wed Dec 5
04:32:25 2012
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-2437.js Fri Jan 25
02:53: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