Fix spec violations related to regexp.lastIndex

BUG=v8:2437, v8:2438

Review URL: https://chromiumcodereview.appspot.com/11451005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13143 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2012-12-05 12:32:25 +00:00
parent 6b16d0bcae
commit 6c92aba643
7 changed files with 158 additions and 7 deletions

View File

@ -4743,6 +4743,13 @@ void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) {
}
void JSRegExp::ResetLastIndex() {
InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
Smi::FromInt(0),
SKIP_WRITE_BARRIER); // It's a Smi.
}
ElementsKind JSObject::GetElementsKind() {
ElementsKind kind = map()->elements_kind();
#if DEBUG

View File

@ -6651,6 +6651,7 @@ class JSRegExp: public JSObject {
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) {

View File

@ -161,6 +161,7 @@ function RegExpExecNoTests(regexp, string, start) {
lastMatchInfoOverride = null;
return BuildResultFromMatchInfo(matchInfo, string);
}
regexp.lastIndex = 0;
return null;
}
@ -193,7 +194,7 @@ function RegExpExec(string) {
var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
if (matchIndices === null) {
if (global) this.lastIndex = 0;
this.lastIndex = 0;
return null;
}
@ -256,7 +257,10 @@ function RegExpTest(string) {
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [regexp, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(regexp, string, 0, lastMatchInfo);
if (matchIndices === null) return false;
if (matchIndices === null) {
this.lastIndex = 0;
return false;
}
lastMatchInfoOverride = null;
return true;
}

View File

@ -1790,9 +1790,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
regexp->InObjectPropertyAtPut(
JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
Smi::FromInt(0),
SKIP_WRITE_BARRIER); // It's a Smi.
regexp->ResetLastIndex();
return regexp;
}
@ -2904,7 +2902,10 @@ MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString(
isolate, *subject, pattern, &indices, 0xffffffff, zone);
int matches = indices.length();
if (matches == 0) return *subject;
if (matches == 0) {
pattern_regexp->ResetLastIndex();
return *subject;
}
// Detect integer overflow.
int64_t result_len_64 =
@ -3004,6 +3005,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return Failure::Exception();
regexp->ResetLastIndex();
return *subject;
}
@ -3102,6 +3104,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
int32_t* current_match = global_cache.FetchNext();
if (current_match == NULL) {
if (global_cache.HasException()) return Failure::Exception();
regexp->ResetLastIndex();
return *subject;
}

View File

@ -186,6 +186,9 @@ function StringMatch(regexp) {
}
var subject = TO_STRING_INLINE(this);
if (IS_REGEXP(regexp)) {
// Emulate RegExp.prototype.exec's side effect in step 5, even though
// value is discarded.
ToInteger(regexp.lastIndex);
if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
// lastMatchInfo is defined in regexp.js.
@ -227,6 +230,9 @@ function StringReplace(search, replace) {
// Delegate to one of the regular expression variants if necessary.
if (IS_REGEXP(search)) {
// Emulate RegExp.prototype.exec's side effect in step 5, even though
// value is discarded.
ToInteger(search.lastIndex);
%_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
if (IS_SPEC_FUNCTION(replace)) {
if (search.global) {
@ -451,7 +457,10 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
var matchInfo = DoRegExpExec(regexp, subject, 0);
if (IS_NULL(matchInfo)) return subject;
if (IS_NULL(matchInfo)) {
regexp.lastIndex = 0;
return subject;
}
var index = matchInfo[CAPTURE0];
var result = SubString(subject, 0, index);
var endOfMatch = matchInfo[CAPTURE1];

View File

@ -0,0 +1,75 @@
// Copyright 2012 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.
// Test Regexp.prototype.exec
r = /a/;
r.lastIndex = 1;
r.exec("zzzz");
assertEquals(0, r.lastIndex);
// Test Regexp.prototype.test
r = /a/;
r.lastIndex = 1;
r.test("zzzz");
assertEquals(0, r.lastIndex);
// Test String.prototype.match
r = /a/;
r.lastIndex = 1;
"zzzz".match(r);
assertEquals(0, r.lastIndex);
// Test String.prototype.replace with atomic regexp and empty string.
r = /a/;
r.lastIndex = 1;
"zzzz".replace(r, "");
assertEquals(0, r.lastIndex);
// Test String.prototype.replace with non-atomic regexp and empty string.
r = /\d/;
r.lastIndex = 1;
"zzzz".replace(r, "");
assertEquals(0, r.lastIndex);
// Test String.prototype.replace with atomic regexp and non-empty string.
r = /a/;
r.lastIndex = 1;
"zzzz".replace(r, "a");
assertEquals(0, r.lastIndex);
// Test String.prototype.replace with non-atomic regexp and non-empty string.
r = /\d/;
r.lastIndex = 1;
"zzzz".replace(r, "a");
assertEquals(0, r.lastIndex);
// Test String.prototype.replace with replacement function
r = /a/;
r.lastIndex = 1;
"zzzz".replace(r, function() { return ""; });
assertEquals(0, r.lastIndex);

View File

@ -0,0 +1,52 @@
// Copyright 2012 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.
function testSideEffects(subject, re) {
var counter = 0;
var side_effect_object = { valueOf: function() { return counter++; } };
re.lastIndex = side_effect_object;
re.exec(subject);
assertEquals(1, counter);
re.lastIndex = side_effect_object;
re.test(subject);
assertEquals(2, counter);
re.lastIndex = side_effect_object;
subject.match(re);
assertEquals(3, counter);
re.lastIndex = side_effect_object;
subject.replace(re, "");
assertEquals(4, counter);
}
testSideEffects("zzzz", /a/);
testSideEffects("zzzz", /a/g);
testSideEffects("xaxa", /a/);
testSideEffects("xaxa", /a/g);