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:
parent
6b16d0bcae
commit
6c92aba643
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
75
test/mjsunit/regress/regress-2437.js
Normal file
75
test/mjsunit/regress/regress-2437.js
Normal 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);
|
||||
|
52
test/mjsunit/regress/regress-2438.js
Normal file
52
test/mjsunit/regress/regress-2438.js
Normal 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);
|
||||
|
Loading…
Reference in New Issue
Block a user