From 425a221b02306cb43b4aae64d7d2f2734958a376 Mon Sep 17 00:00:00 2001 From: "sandholm@chromium.org" Date: Mon, 13 Dec 2010 12:19:10 +0000 Subject: [PATCH] Optimizing BuildResultFromMatchInfo, StringReplace and StringSplit. Review URL: http://codereview.chromium.org/5708006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5982 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/regexp.js | 66 +++++++++++++++++------------------- src/string.js | 93 +++++++++++++++++++++++++-------------------------- 2 files changed, 76 insertions(+), 83 deletions(-) diff --git a/src/regexp.js b/src/regexp.js index d01d04f2e..dd27266a9 100644 --- a/src/regexp.js +++ b/src/regexp.js @@ -120,22 +120,28 @@ function DoRegExpExec(regexp, string, index) { function BuildResultFromMatchInfo(lastMatchInfo, s) { var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1; - var result = %_RegExpConstructResult(numResults, lastMatchInfo[CAPTURE0], s); - if (numResults === 1) { - var matchStart = lastMatchInfo[CAPTURE(0)]; - var matchEnd = lastMatchInfo[CAPTURE(1)]; - result[0] = SubString(s, matchStart, matchEnd); + var start = lastMatchInfo[CAPTURE0]; + var end = lastMatchInfo[CAPTURE1]; + var result = %_RegExpConstructResult(numResults, start, s); + if (start + 1 == end) { + result[0] = %_StringCharAt(s, start); } else { - for (var i = 0; i < numResults; i++) { - var matchStart = lastMatchInfo[CAPTURE(i << 1)]; - var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)]; - if (matchStart != -1 && matchEnd != -1) { - result[i] = SubString(s, matchStart, matchEnd); + result[0] = %_SubString(s, start, end); + } + var j = REGEXP_FIRST_CAPTURE + 2; + for (var i = 1; i < numResults; i++) { + start = lastMatchInfo[j++]; + end = lastMatchInfo[j++]; + if (end != -1) { + if (start + 1 == end) { + result[i] = %_StringCharAt(s, start); } else { - // Make sure the element is present. Avoid reading the undefined - // property from the global object since this may change. - result[i] = void 0; + result[i] = %_SubString(s, start, end); } + } else { + // Make sure the element is present. Avoid reading the undefined + // property from the global object since this may change. + result[i] = void 0; } } return result; @@ -166,12 +172,7 @@ function RegExpExec(string) { } string = regExpInput; } - var s; - if (IS_STRING(string)) { - s = string; - } else { - s = ToString(string); - } + string = TO_STRING_INLINE(string); var lastIndex = this.lastIndex; // Conversion is required by the ES5 specification (RegExp.prototype.exec @@ -180,7 +181,7 @@ function RegExpExec(string) { var global = this.global; if (global) { - if (i < 0 || i > s.length) { + if (i < 0 || i > string.length) { this.lastIndex = 0; return null; } @@ -188,9 +189,9 @@ function RegExpExec(string) { i = 0; } - %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); + %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]); // matchIndices is either null or the lastMatchInfo array. - var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); + var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo); if (matchIndices === null) { if (global) this.lastIndex = 0; @@ -202,7 +203,7 @@ function RegExpExec(string) { if (global) { this.lastIndex = lastMatchInfo[CAPTURE1]; } - return BuildResultFromMatchInfo(matchIndices, s); + return BuildResultFromMatchInfo(matchIndices, string); } @@ -227,12 +228,7 @@ function RegExpTest(string) { string = regExpInput; } - var s; - if (IS_STRING(string)) { - s = string; - } else { - s = ToString(string); - } + string = TO_STRING_INLINE(string); var lastIndex = this.lastIndex; @@ -241,13 +237,13 @@ function RegExpTest(string) { var i = TO_INTEGER(lastIndex); if (this.global) { - if (i < 0 || i > s.length) { + if (i < 0 || i > string.length) { this.lastIndex = 0; return false; } - %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); + %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]); // matchIndices is either null or the lastMatchInfo array. - var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); + var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo); if (matchIndices === null) { this.lastIndex = 0; return false; @@ -269,11 +265,11 @@ function RegExpTest(string) { (this.ignoreCase ? 'i' : '') + (this.multiline ? 'm' : '')); } - if (!regexp_val.test(s)) return false; + if (!regexp_val.test(string)) return false; } - %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); + %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]); // matchIndices is either null or the lastMatchInfo array. - var matchIndices = %_RegExpExec(this, s, 0, lastMatchInfo); + var matchIndices = %_RegExpExec(this, string, 0, lastMatchInfo); if (matchIndices === null) return false; lastMatchInfoOverride = null; return true; diff --git a/src/string.js b/src/string.js index 3b3c82bb7..576ffc85d 100644 --- a/src/string.js +++ b/src/string.js @@ -101,28 +101,28 @@ function StringConcat() { // ECMA-262 section 15.5.4.7 -function StringIndexOf(searchString /* position */) { // length == 1 - var subject_str = TO_STRING_INLINE(this); - var pattern_str = TO_STRING_INLINE(searchString); - var subject_str_len = subject_str.length; - var pattern_str_len = pattern_str.length; +function StringIndexOf(pattern /* position */) { // length == 1 + var subject = TO_STRING_INLINE(this); + var pattern = TO_STRING_INLINE(pattern); + var subject_len = subject.length; + var pattern_len = pattern.length; var index = 0; if (%_ArgumentsLength() > 1) { var arg1 = %_Arguments(1); // position index = TO_INTEGER(arg1); } if (index < 0) index = 0; - if (index > subject_str_len) index = subject_str_len; - if (pattern_str_len + index > subject_str_len) return -1; - return %StringIndexOf(subject_str, pattern_str, index); + if (index > subject_len) index = subject_len; + if (pattern_len + index > subject_len) return -1; + return %StringIndexOf(subject, pattern, index); } // ECMA-262 section 15.5.4.8 -function StringLastIndexOf(searchString /* position */) { // length == 1 +function StringLastIndexOf(pat /* position */) { // length == 1 var sub = TO_STRING_INLINE(this); var subLength = sub.length; - var pat = TO_STRING_INLINE(searchString); + var pat = TO_STRING_INLINE(pat); var patLength = pat.length; var index = subLength - patLength; if (%_ArgumentsLength() > 1) { @@ -150,10 +150,8 @@ function StringLastIndexOf(searchString /* position */) { // length == 1 // do anything locale specific. function StringLocaleCompare(other) { if (%_ArgumentsLength() === 0) return 0; - - var this_str = TO_STRING_INLINE(this); - var other_str = TO_STRING_INLINE(other); - return %StringLocaleCompare(this_str, other_str); + return %StringLocaleCompare(TO_STRING_INLINE(this), + TO_STRING_INLINE(other)); } @@ -177,9 +175,7 @@ function StringMatch(regexp) { // otherwise we call the runtime system. function SubString(string, start, end) { // Use the one character string cache. - if (start + 1 == end) { - return %_StringCharAt(string, start); - } + if (start + 1 == end) return %_StringCharAt(string, start); return %_SubString(string, start, end); } @@ -208,7 +204,10 @@ function StringReplace(search, replace) { replace); } } else { - return StringReplaceRegExp(subject, search, replace); + return %StringReplaceRegExpWithString(subject, + search, + TO_STRING_INLINE(replace), + lastMatchInfo); } } @@ -224,7 +223,11 @@ function StringReplace(search, replace) { // Compute the string to replace with. if (IS_FUNCTION(replace)) { - builder.add(replace.call(null, search, start, subject)); + builder.add(%_CallFunction(%GetGlobalReceiver(), + search, + start, + subject, + replace)); } else { reusableMatchInfo[CAPTURE0] = start; reusableMatchInfo[CAPTURE1] = end; @@ -239,15 +242,6 @@ function StringReplace(search, replace) { } -// Helper function for regular expressions in String.prototype.replace. -function StringReplaceRegExp(subject, regexp, replace) { - return %StringReplaceRegExpWithString(subject, - regexp, - TO_STRING_INLINE(replace), - lastMatchInfo); -} - - // Expand the $-expressions in the string and return a new string with // the result. function ExpandReplacement(string, subject, matchInfo, builder) { @@ -408,9 +402,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { lastMatchInfoOverride = override; var func_result = %_CallFunction(receiver, elem, match_start, subject, replace); - if (!IS_STRING(func_result)) { - func_result = NonStringToString(func_result); - } + func_result = TO_STRING_INLINE(func_result); res[i] = func_result; match_start += elem.length; } @@ -424,9 +416,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { // 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); - } + func_result = TO_STRING_INLINE(func_result); res[i] = func_result; } i++; @@ -487,8 +477,7 @@ function StringSearch(re) { } else { regexp = new $RegExp(re); } - var s = TO_STRING_INLINE(this); - var match = DoRegExpExec(regexp, s, 0); + var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0); if (match) { return match[CAPTURE0]; } @@ -576,14 +565,14 @@ function StringSplit(separator, limit) { while (true) { if (startIndex === length) { - result[result.length] = subject.slice(currentIndex, length); + result.push(subject.slice(currentIndex, length)); break; } var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); if (IS_NULL(matchInfo)) { - result[result.length] = subject.slice(currentIndex, length); + result.push(subject.slice(currentIndex, length)); break; } @@ -595,17 +584,21 @@ function StringSplit(separator, limit) { continue; } - result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]); + result.push(SubString(subject, currentIndex, matchInfo[CAPTURE0])); if (result.length === limit) break; - var num_captures = NUMBER_OF_CAPTURES(matchInfo); - for (var i = 2; i < num_captures; i += 2) { - var start = matchInfo[CAPTURE(i)]; - var end = matchInfo[CAPTURE(i + 1)]; - if (start != -1 && end != -1) { - result[result.length] = SubString(subject, start, end); + var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE; + for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) { + var start = matchInfo[i++]; + var end = matchInfo[i++]; + if (end != -1) { + if (start + 1 == end) { + result.push(%_StringCharAt(subject, start)); + } else { + result.push(%_SubString(subject, start, end)); + } } else { - result[result.length] = void 0; + result.push(void 0); } if (result.length === limit) break outer_loop; } @@ -656,7 +649,9 @@ function StringSubstring(start, end) { } } - return SubString(s, start_i, end_i); + return (start_i + 1 == end_i + ? %_StringCharAt(s, start_i) + : %_SubString(s, start_i, end_i)); } @@ -694,7 +689,9 @@ function StringSubstr(start, n) { var end = start + len; if (end > s.length) end = s.length; - return SubString(s, start, end); + return (start + 1 == end + ? %_StringCharAt(s, start) + : %_SubString(s, start, end)); } -- 2.34.1