summaryrefslogtreecommitdiff
path: root/deps/v8/src/string.js
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-04-14 10:34:17 -0700
committerRyan Dahl <ry@tinyclouds.org>2010-04-14 10:34:27 -0700
commit41ef1717e096a9e1761efa0df97c395f59c51f16 (patch)
tree7e854284ef8ce5189a63074857a408b6eea5a9cb /deps/v8/src/string.js
parent760bba55186eba039ca00e532f7813d2aea450a2 (diff)
downloadnode-new-41ef1717e096a9e1761efa0df97c395f59c51f16.tar.gz
Upgrade V8 to 2.2.3.1
Diffstat (limited to 'deps/v8/src/string.js')
-rw-r--r--deps/v8/src/string.js246
1 files changed, 130 insertions, 116 deletions
diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js
index ca438fdde5..7ddc467fc0 100644
--- a/deps/v8/src/string.js
+++ b/deps/v8/src/string.js
@@ -149,6 +149,16 @@ function StringLastIndexOf(searchString /* position */) { // length == 1
}
+function CloneDenseArray(array) {
+ if (array === null) return null;
+ var clone = new $Array(array.length);
+ for (var i = 0; i < array.length; i++) {
+ clone[i] = array[i];
+ }
+ return clone;
+}
+
+
// ECMA-262 section 15.5.4.9
//
// This function is implementation specific. For now, we do not
@@ -164,36 +174,37 @@ function StringLocaleCompare(other) {
// ECMA-262 section 15.5.4.10
function StringMatch(regexp) {
- if (!IS_REGEXP(regexp)) regexp = new $RegExp(regexp);
var subject = TO_STRING_INLINE(this);
-
- if (!regexp.global) return regexp.exec(subject);
-
- var cache = regExpCache;
-
- if (%_ObjectEquals(cache.type, 'match') &&
- %_ObjectEquals(cache.regExp, regexp) &&
- %_ObjectEquals(cache.subject, subject)) {
- var last = cache.answer;
- if (last == null) {
- return last;
- } else {
- return CloneRegexpAnswer(last);
+ if (IS_REGEXP(regexp)) {
+ if (!regexp.global) return regexp.exec(subject);
+
+ var cache = regExpCache;
+ var saveAnswer = false;
+
+ if (%_ObjectEquals(cache.type, 'match') &&
+ %_ObjectEquals(cache.regExp, regexp) &&
+ %_ObjectEquals(cache.subject, subject)) {
+ if (cache.answerSaved) {
+ return CloneDenseArray(cache.answer);
+ } else {
+ saveAnswer = true;
+ }
}
- }
-
- %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
- // lastMatchInfo is defined in regexp.js.
- var result = %StringMatch(subject, regexp, lastMatchInfo);
- cache.type = 'match';
- cache.regExp = regexp;
- cache.subject = subject;
- cache.answer = result;
- if (result == null) {
+ %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
+ // lastMatchInfo is defined in regexp.js.
+ var result = %StringMatch(subject, regexp, lastMatchInfo);
+ cache.type = 'match';
+ cache.regExp = regexp;
+ cache.subject = subject;
+ if (saveAnswer) cache.answer = CloneDenseArray(result);
+ cache.answerSaved = saveAnswer;
return result;
- } else {
- return CloneRegexpAnswer(result);
}
+ // Non-regexp argument.
+ regexp = new $RegExp(regexp);
+ // Don't check regexp exec cache, since the regexp is new.
+ // TODO(lrn): Change this if we start caching regexps here.
+ return RegExpExecNoTests(regexp, subject, 0);
}
@@ -405,97 +416,95 @@ function addCaptureString(builder, matchInfo, index) {
builder.addSpecialSlice(start, end);
};
+// TODO(lrn): This array will survive indefinitely if replace is never
+// called again. However, it will be empty, since the contents are cleared
+// in the finally block.
+var reusableReplaceArray = $Array(16);
// Helper function for replacing regular expressions with the result of a
-// function application in String.prototype.replace. The function application
-// must be interleaved with the regexp matching (contrary to ECMA-262
-// 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses
-// the static properties of the RegExp constructor. Example:
-// 'abcd'.replace(/(.)/g, function() { return RegExp.$1; }
-// should be 'abcd' and not 'dddd' (or anything else).
+// function application in String.prototype.replace.
function StringReplaceRegExpWithFunction(subject, regexp, replace) {
- var matchInfo = DoRegExpExec(regexp, subject, 0);
- if (IS_NULL(matchInfo)) return subject;
-
- var result = new ReplaceResultBuilder(subject);
- // There's at least one match. If the regexp is global, we have to loop
- // over all matches. The loop is not in C++ code here like the one in
- // RegExp.prototype.exec, because of the interleaved function application.
- // Unfortunately, that means this code is nearly duplicated, here and in
- // jsregexp.cc.
if (regexp.global) {
- var previous = 0;
- var startOfMatch;
- if (NUMBER_OF_CAPTURES(matchInfo) == 2) {
- // Both branches contain essentially the same loop except for the call
- // to the replace function. The branch is put outside of the loop for
- // speed
- do {
- startOfMatch = matchInfo[CAPTURE0];
- result.addSpecialSlice(previous, startOfMatch);
- previous = matchInfo[CAPTURE1];
- var match = SubString(subject, startOfMatch, previous);
- // Don't call directly to avoid exposing the built-in global object.
- result.add(replace.call(null, match, startOfMatch, subject));
- // Can't use matchInfo any more from here, since the function could
- // overwrite it.
- // Continue with the next match.
- // Increment previous if we matched an empty string, as per ECMA-262
- // 15.5.4.10.
- if (previous == startOfMatch) {
- // Add the skipped character to the output, if any.
- if (previous < subject.length) {
- result.addSpecialSlice(previous, previous + 1);
- }
- previous++;
- // Per ECMA-262 15.10.6.2, if the previous index is greater than the
- // string length, there is no match
- if (previous > subject.length) {
- return result.generate();
- }
- }
- matchInfo = DoRegExpExec(regexp, subject, previous);
- } while (!IS_NULL(matchInfo));
+ var resultArray = reusableReplaceArray;
+ if (resultArray) {
+ reusableReplaceArray = null;
} else {
- do {
- startOfMatch = matchInfo[CAPTURE0];
- result.addSpecialSlice(previous, startOfMatch);
- previous = matchInfo[CAPTURE1];
- result.add(ApplyReplacementFunction(replace, matchInfo, subject));
- // Can't use matchInfo any more from here, since the function could
- // overwrite it.
- // Continue with the next match.
- // Increment previous if we matched an empty string, as per ECMA-262
- // 15.5.4.10.
- if (previous == startOfMatch) {
- // Add the skipped character to the output, if any.
- if (previous < subject.length) {
- result.addSpecialSlice(previous, previous + 1);
+ // Inside a nested replace (replace called from the replacement function
+ // of another replace) or we have failed to set the reusable array
+ // back due to an exception in a replacement function. Create a new
+ // array to use in the future, or until the original is written back.
+ resultArray = $Array(16);
+ }
+ try {
+ // Must handle exceptions thrown by the replace functions correctly,
+ // including unregistering global regexps.
+ var res = %RegExpExecMultiple(regexp,
+ subject,
+ lastMatchInfo,
+ resultArray);
+ regexp.lastIndex = 0;
+ if (IS_NULL(res)) {
+ // No matches at all.
+ return subject;
+ }
+ var len = res.length;
+ var i = 0;
+ if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
+ var match_start = 0;
+ while (i < len) {
+ var elem = res[i];
+ if (%_IsSmi(elem)) {
+ if (elem > 0) {
+ match_start = (elem >> 11) + (elem & 0x7ff);
+ } else {
+ match_start = res[++i] - elem;
+ }
+ } else {
+ var func_result = replace.call(null, elem, match_start, subject);
+ if (!IS_STRING(func_result)) {
+ func_result = NonStringToString(func_result);
+ }
+ res[i] = func_result;
+ match_start += elem.length;
}
- previous++;
- // Per ECMA-262 15.10.6.2, if the previous index is greater than the
- // string length, there is no match
- if (previous > subject.length) {
- return result.generate();
+ i++;
+ }
+ } else {
+ while (i < len) {
+ var elem = res[i];
+ if (!%_IsSmi(elem)) {
+ // elem must be an Array.
+ // Use the apply argument as backing for global RegExp properties.
+ lastMatchInfoOverride = elem;
+ var func_result = replace.apply(null, elem);
+ if (!IS_STRING(func_result)) {
+ func_result = NonStringToString(func_result);
+ }
+ res[i] = func_result;
}
+ i++;
}
- matchInfo = DoRegExpExec(regexp, subject, previous);
- } while (!IS_NULL(matchInfo));
+ }
+ var result = new ReplaceResultBuilder(subject, res);
+ return result.generate();
+ } finally {
+ lastMatchInfoOverride = null;
+ resultArray.length = 0;
+ reusableReplaceArray = resultArray;
}
-
- // Tack on the final right substring after the last match.
- result.addSpecialSlice(previous, subject.length);
-
} else { // Not a global regexp, no need to loop.
+ var matchInfo = DoRegExpExec(regexp, subject, 0);
+ if (IS_NULL(matchInfo)) return subject;
+
+ var result = new ReplaceResultBuilder(subject);
result.addSpecialSlice(0, matchInfo[CAPTURE0]);
var endOfMatch = matchInfo[CAPTURE1];
result.add(ApplyReplacementFunction(replace, matchInfo, subject));
// Can't use matchInfo any more from here, since the function could
// overwrite it.
result.addSpecialSlice(endOfMatch, subject.length);
+ return result.generate();
}
-
- return result.generate();
}
@@ -522,7 +531,7 @@ function ApplyReplacementFunction(replace, matchInfo, subject) {
// ECMA-262 section 15.5.4.12
-function StringSearch(re) {
+function StringSearch(re) {
var regexp = new $RegExp(re);
var s = TO_STRING_INLINE(this);
var match = DoRegExpExec(regexp, s, 0);
@@ -598,11 +607,16 @@ function StringSplit(separator, limit) {
}
var cache = regExpCache;
+ var saveAnswer = false;
if (%_ObjectEquals(cache.type, 'split') &&
%_ObjectEquals(cache.regExp, separator) &&
%_ObjectEquals(cache.subject, subject)) {
- return CloneRegexpAnswer(cache.answer);
+ if (cache.answerSaved) {
+ return CloneDenseArray(cache.answer);
+ } else {
+ saveAnswer = true;
+ }
}
cache.type = 'split';
@@ -612,6 +626,7 @@ function StringSplit(separator, limit) {
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
if (length === 0) {
+ cache.answerSaved = true;
if (splitMatch(separator, subject, 0, 0) != null) {
cache.answer = [];
return [];
@@ -624,20 +639,19 @@ function StringSplit(separator, limit) {
var startIndex = 0;
var result = [];
+ outer_loop:
while (true) {
if (startIndex === length) {
result[result.length] = subject.slice(currentIndex, length);
- cache.answer = result;
- return CloneRegexpAnswer(result);
+ break;
}
var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
if (IS_NULL(matchInfo)) {
result[result.length] = subject.slice(currentIndex, length);
- cache.answer = result;
- return CloneRegexpAnswer(result);
+ break;
}
var endIndex = matchInfo[CAPTURE1];
@@ -649,10 +663,7 @@ function StringSplit(separator, limit) {
}
result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
- if (result.length === limit) {
- cache.answer = result;
- return CloneRegexpAnswer(result);
- }
+ if (result.length === limit) break;
var num_captures = NUMBER_OF_CAPTURES(matchInfo);
for (var i = 2; i < num_captures; i += 2) {
@@ -663,14 +674,14 @@ function StringSplit(separator, limit) {
} else {
result[result.length] = void 0;
}
- if (result.length === limit) {
- cache.answer = result;
- return CloneRegexpAnswer(result);
- }
+ if (result.length === limit) break outer_loop;
}
startIndex = currentIndex = endIndex;
}
+ if (saveAnswer) cache.answer = CloneDenseArray(result);
+ cache.answerSaved = saveAnswer;
+ return result;
}
@@ -894,8 +905,11 @@ function StringSup() {
// ReplaceResultBuilder support.
function ReplaceResultBuilder(str) {
- this.__proto__ = void 0;
- this.elements = new $Array();
+ if (%_ArgumentsLength() > 1) {
+ this.elements = %_Arguments(1);
+ } else {
+ this.elements = new $Array();
+ }
this.special_string = str;
}