diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2010-04-14 10:34:17 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2010-04-14 10:34:27 -0700 |
commit | 41ef1717e096a9e1761efa0df97c395f59c51f16 (patch) | |
tree | 7e854284ef8ce5189a63074857a408b6eea5a9cb /deps/v8/src/string.js | |
parent | 760bba55186eba039ca00e532f7813d2aea450a2 (diff) | |
download | node-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.js | 246 |
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; } |