Commit f6df3267 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Add 1-element caches to RegExp.exec and String.replace. We

probably want to remove this again if and when Dromaeo is
fixed so this strategy doesn't pay off.
Review URL: http://codereview.chromium.org/817001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4083 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9e2c15e4
......@@ -95,6 +95,16 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
%IgnoreAttributesAndSetProperty(object, 'ignoreCase', ignoreCase);
%IgnoreAttributesAndSetProperty(object, 'multiline', multiline);
%IgnoreAttributesAndSetProperty(object, 'lastIndex', 0);
// Clear the regexp result cache.
cachedRegexp = 0;
cachedSubject = 0;
cachedLastIndex = 0;
cachedAnswer = 0;
// These are from string.js.
cachedReplaceSubject = 0;
cachedReplaceRegexp = 0;
cachedReplaceReplacement = 0;
cachedReplaceAnswer = 0;
}
// Call internal function to compile the pattern.
......@@ -140,7 +150,36 @@ function DoRegExpExec(regexp, string, index) {
}
var cachedRegexp;
var cachedSubject;
var cachedLastIndex;
var cachedAnswer;
function CloneRegexpAnswer(array) {
var len = array.length;
var answer = new $Array(len);
for (var i = 0; i < len; i++) {
answer[i] = array[i];
}
answer.index = array.index;
answer.input = array.input;
return answer;
}
function RegExpExec(string) {
if (%_ObjectEquals(cachedLastIndex, this.lastIndex) &&
%_ObjectEquals(cachedRegexp, this) &&
%_ObjectEquals(cachedSubject, string)) {
var last = cachedAnswer;
if (last == null) {
return last;
} else {
return CloneRegexpAnswer(last);
}
}
if (!IS_REGEXP(this)) {
throw MakeTypeError('incompatible_method_receiver',
['RegExp.prototype.exec', this]);
......@@ -159,6 +198,7 @@ function RegExpExec(string) {
s = ToString(string);
}
var lastIndex = this.lastIndex;
var i = this.global ? TO_INTEGER(lastIndex) : 0;
if (i < 0 || i > s.length) {
......@@ -172,7 +212,11 @@ function RegExpExec(string) {
if (matchIndices == null) {
if (this.global) this.lastIndex = 0;
return matchIndices; // no match
cachedLastIndex = lastIndex;
cachedRegexp = this;
cachedSubject = s;
cachedAnswer = matchIndices; // Null.
return matchIndices; // No match.
}
var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
......@@ -196,11 +240,18 @@ function RegExpExec(string) {
}
}
if (this.global)
this.lastIndex = lastMatchInfo[CAPTURE1];
result.index = lastMatchInfo[CAPTURE0];
result.input = s;
return result;
if (this.global) {
this.lastIndex = lastMatchInfo[CAPTURE1];
return result;
} else {
cachedRegexp = this;
cachedSubject = s;
cachedLastIndex = lastIndex;
cachedAnswer = result;
return CloneRegexpAnswer(result);
}
}
......
......@@ -239,14 +239,29 @@ function StringReplace(search, replace) {
}
var cachedReplaceSubject;
var cachedReplaceRegexp;
var cachedReplaceReplacement;
var cachedReplaceAnswer;
// Helper function for regular expressions in String.prototype.replace.
function StringReplaceRegExp(subject, regexp, replace) {
if (%_ObjectEquals(replace, cachedReplaceReplacement) &&
%_ObjectEquals(subject, cachedReplaceSubject) &&
%_ObjectEquals(regexp, cachedReplaceRegexp)) {
return cachedReplaceAnswer;
}
replace = TO_STRING_INLINE(replace);
return %StringReplaceRegExpWithString(subject,
regexp,
replace,
lastMatchInfo);
};
var answer = %StringReplaceRegExpWithString(subject,
regexp,
replace,
lastMatchInfo);
cachedReplaceSubject = subject;
cachedReplaceRegexp = regexp;
cachedReplaceReplacement = replace;
cachedReplaceAnswer = answer;
return answer;
}
// Expand the $-expressions in the string and return a new string with
......
// Copyright 2008 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 that we don't cache the result of a regexp match across a
// compile event.
var re = /x/;
assertEquals("a.yb", "axyb".replace(re, "."));
re.compile("y")
assertEquals("ax.b", "axyb".replace(re, "."));
re.compile("(x)");
assertEquals("x,x", re.exec("axyb"));
re.compile("(y)");
assertEquals("y,y", re.exec("axyb"));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment