Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/string.js

Issue 1148007: Merge bleeding_edge from version 2.1.3 up to revision 4205... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 return %StringLocaleCompare(this_str, other_str); 161 return %StringLocaleCompare(this_str, other_str);
162 } 162 }
163 163
164 164
165 // ECMA-262 section 15.5.4.10 165 // ECMA-262 section 15.5.4.10
166 function StringMatch(regexp) { 166 function StringMatch(regexp) {
167 if (!IS_REGEXP(regexp)) regexp = new $RegExp(regexp); 167 if (!IS_REGEXP(regexp)) regexp = new $RegExp(regexp);
168 var subject = TO_STRING_INLINE(this); 168 var subject = TO_STRING_INLINE(this);
169 169
170 if (!regexp.global) return regexp.exec(subject); 170 if (!regexp.global) return regexp.exec(subject);
171
172 var cache = regExpCache;
173
174 if (%_ObjectEquals(cache.type, 'match') &&
175 %_ObjectEquals(cache.regExp, regexp) &&
176 %_ObjectEquals(cache.subject, subject)) {
177 var last = cache.answer;
178 if (last == null) {
179 return last;
180 } else {
181 return CloneRegexpAnswer(last);
182 }
183 }
184
171 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); 185 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
172 // lastMatchInfo is defined in regexp.js. 186 // lastMatchInfo is defined in regexp.js.
173 return %StringMatch(subject, regexp, lastMatchInfo); 187 var result = %StringMatch(subject, regexp, lastMatchInfo);
188 cache.type = 'match';
189 cache.regExp = regexp;
190 cache.subject = subject;
191 cache.answer = result;
192 if (result == null) {
193 return result;
194 } else {
195 return CloneRegexpAnswer(result);
196 }
174 } 197 }
175 198
176 199
177 // SubString is an internal function that returns the sub string of 'string'. 200 // SubString is an internal function that returns the sub string of 'string'.
178 // If resulting string is of length 1, we use the one character cache 201 // If resulting string is of length 1, we use the one character cache
179 // otherwise we call the runtime system. 202 // otherwise we call the runtime system.
180 function SubString(string, start, end) { 203 function SubString(string, start, end) {
181 // Use the one character string cache. 204 // Use the one character string cache.
182 if (start + 1 == end) { 205 if (start + 1 == end) {
183 var char_code = %_FastCharCodeAt(string, start); 206 var char_code = %_FastCharCodeAt(string, start);
(...skipping 15 matching lines...) Expand all
199 222
200 223
201 // ECMA-262, section 15.5.4.11 224 // ECMA-262, section 15.5.4.11
202 function StringReplace(search, replace) { 225 function StringReplace(search, replace) {
203 var subject = TO_STRING_INLINE(this); 226 var subject = TO_STRING_INLINE(this);
204 227
205 // Delegate to one of the regular expression variants if necessary. 228 // Delegate to one of the regular expression variants if necessary.
206 if (IS_REGEXP(search)) { 229 if (IS_REGEXP(search)) {
207 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); 230 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
208 if (IS_FUNCTION(replace)) { 231 if (IS_FUNCTION(replace)) {
232 regExpCache.type = 'none';
209 return StringReplaceRegExpWithFunction(subject, search, replace); 233 return StringReplaceRegExpWithFunction(subject, search, replace);
210 } else { 234 } else {
211 return StringReplaceRegExp(subject, search, replace); 235 return StringReplaceRegExp(subject, search, replace);
212 } 236 }
213 } 237 }
214 238
215 // Convert the search argument to a string and search for it. 239 // Convert the search argument to a string and search for it.
216 search = TO_STRING_INLINE(search); 240 search = TO_STRING_INLINE(search);
217 var start = %StringIndexOf(subject, search, 0); 241 var start = %StringIndexOf(subject, search, 0);
218 if (start < 0) return subject; 242 if (start < 0) return subject;
(...skipping 15 matching lines...) Expand all
234 258
235 // suffix 259 // suffix
236 builder.addSpecialSlice(end, subject.length); 260 builder.addSpecialSlice(end, subject.length);
237 261
238 return builder.generate(); 262 return builder.generate();
239 } 263 }
240 264
241 265
242 // Helper function for regular expressions in String.prototype.replace. 266 // Helper function for regular expressions in String.prototype.replace.
243 function StringReplaceRegExp(subject, regexp, replace) { 267 function StringReplaceRegExp(subject, regexp, replace) {
268 var cache = regExpCache;
269 if (%_ObjectEquals(cache.regExp, regexp) &&
270 %_ObjectEquals(cache.type, 'replace') &&
271 %_ObjectEquals(cache.replaceString, replace) &&
272 %_ObjectEquals(cache.subject, subject)) {
273 return cache.answer;
274 }
244 replace = TO_STRING_INLINE(replace); 275 replace = TO_STRING_INLINE(replace);
245 return %StringReplaceRegExpWithString(subject, 276 var answer = %StringReplaceRegExpWithString(subject,
246 regexp, 277 regexp,
247 replace, 278 replace,
248 lastMatchInfo); 279 lastMatchInfo);
249 }; 280 cache.subject = subject;
281 cache.regExp = regexp;
282 cache.replaceString = replace;
283 cache.answer = answer;
284 cache.type = 'replace';
285 return answer;
286 }
250 287
251 288
252 // Expand the $-expressions in the string and return a new string with 289 // Expand the $-expressions in the string and return a new string with
253 // the result. 290 // the result.
254 function ExpandReplacement(string, subject, matchInfo, builder) { 291 function ExpandReplacement(string, subject, matchInfo, builder) {
255 var next = %StringIndexOf(string, '$', 0); 292 var next = %StringIndexOf(string, '$', 0);
256 if (next < 0) { 293 if (next < 0) {
257 builder.add(string); 294 builder.add(string);
258 return; 295 return;
259 } 296 }
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 var matchInfo = DoRegExpExec(regexp, subject, 0); 417 var matchInfo = DoRegExpExec(regexp, subject, 0);
381 if (IS_NULL(matchInfo)) return subject; 418 if (IS_NULL(matchInfo)) return subject;
382 419
383 var result = new ReplaceResultBuilder(subject); 420 var result = new ReplaceResultBuilder(subject);
384 // There's at least one match. If the regexp is global, we have to loop 421 // There's at least one match. If the regexp is global, we have to loop
385 // over all matches. The loop is not in C++ code here like the one in 422 // over all matches. The loop is not in C++ code here like the one in
386 // RegExp.prototype.exec, because of the interleaved function application. 423 // RegExp.prototype.exec, because of the interleaved function application.
387 // Unfortunately, that means this code is nearly duplicated, here and in 424 // Unfortunately, that means this code is nearly duplicated, here and in
388 // jsregexp.cc. 425 // jsregexp.cc.
389 if (regexp.global) { 426 if (regexp.global) {
390 var numberOfCaptures = NUMBER_OF_CAPTURES(matchInfo) >> 1;
391 var previous = 0; 427 var previous = 0;
392 do { 428 var startOfMatch;
393 var startOfMatch = matchInfo[CAPTURE0]; 429 if (NUMBER_OF_CAPTURES(matchInfo) == 2) {
394 result.addSpecialSlice(previous, startOfMatch); 430 // Both branches contain essentially the same loop except for the call
395 previous = matchInfo[CAPTURE1]; 431 // to the replace function. The branch is put outside of the loop for
396 if (numberOfCaptures == 1) { 432 // speed
433 do {
434 startOfMatch = matchInfo[CAPTURE0];
435 result.addSpecialSlice(previous, startOfMatch);
436 previous = matchInfo[CAPTURE1];
397 var match = SubString(subject, startOfMatch, previous); 437 var match = SubString(subject, startOfMatch, previous);
398 // Don't call directly to avoid exposing the built-in global object. 438 // Don't call directly to avoid exposing the built-in global object.
399 result.add(replace.call(null, match, startOfMatch, subject)); 439 result.add(replace.call(null, match, startOfMatch, subject));
400 } else { 440 // Can't use matchInfo any more from here, since the function could
441 // overwrite it.
442 // Continue with the next match.
443 // Increment previous if we matched an empty string, as per ECMA-262
444 // 15.5.4.10.
445 if (previous == startOfMatch) {
446 // Add the skipped character to the output, if any.
447 if (previous < subject.length) {
448 result.addSpecialSlice(previous, previous + 1);
449 }
450 previous++;
451 // Per ECMA-262 15.10.6.2, if the previous index is greater than the
452 // string length, there is no match
453 if (previous > subject.length) {
454 return result.generate();
455 }
456 }
457 matchInfo = DoRegExpExec(regexp, subject, previous);
458 } while (!IS_NULL(matchInfo));
459 } else {
460 do {
461 startOfMatch = matchInfo[CAPTURE0];
462 result.addSpecialSlice(previous, startOfMatch);
463 previous = matchInfo[CAPTURE1];
401 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); 464 result.add(ApplyReplacementFunction(replace, matchInfo, subject));
402 } 465 // Can't use matchInfo any more from here, since the function could
403 // Can't use matchInfo any more from here, since the function could 466 // overwrite it.
404 // overwrite it. 467 // Continue with the next match.
405 // Continue with the next match. 468 // Increment previous if we matched an empty string, as per ECMA-262
406 // Increment previous if we matched an empty string, as per ECMA-262 469 // 15.5.4.10.
407 // 15.5.4.10. 470 if (previous == startOfMatch) {
408 if (previous == startOfMatch) { 471 // Add the skipped character to the output, if any.
409 // Add the skipped character to the output, if any. 472 if (previous < subject.length) {
410 if (previous < subject.length) { 473 result.addSpecialSlice(previous, previous + 1);
411 result.addSpecialSlice(previous, previous + 1); 474 }
475 previous++;
476 // Per ECMA-262 15.10.6.2, if the previous index is greater than the
477 // string length, there is no match
478 if (previous > subject.length) {
479 return result.generate();
480 }
412 } 481 }
413 previous++; 482 matchInfo = DoRegExpExec(regexp, subject, previous);
414 } 483 } while (!IS_NULL(matchInfo));
484 }
415 485
416 // Per ECMA-262 15.10.6.2, if the previous index is greater than the 486 // Tack on the final right substring after the last match.
417 // string length, there is no match 487 result.addSpecialSlice(previous, subject.length);
418 matchInfo = (previous > subject.length)
419 ? null
420 : DoRegExpExec(regexp, subject, previous);
421 } while (!IS_NULL(matchInfo));
422 488
423 // Tack on the final right substring after the last match, if necessary.
424 if (previous < subject.length) {
425 result.addSpecialSlice(previous, subject.length);
426 }
427 } else { // Not a global regexp, no need to loop. 489 } else { // Not a global regexp, no need to loop.
428 result.addSpecialSlice(0, matchInfo[CAPTURE0]); 490 result.addSpecialSlice(0, matchInfo[CAPTURE0]);
429 var endOfMatch = matchInfo[CAPTURE1]; 491 var endOfMatch = matchInfo[CAPTURE1];
430 result.add(ApplyReplacementFunction(replace, matchInfo, subject)); 492 result.add(ApplyReplacementFunction(replace, matchInfo, subject));
431 // Can't use matchInfo any more from here, since the function could 493 // Can't use matchInfo any more from here, since the function could
432 // overwrite it. 494 // overwrite it.
433 result.addSpecialSlice(endOfMatch, subject.length); 495 result.addSpecialSlice(endOfMatch, subject.length);
434 } 496 }
435 497
436 return result.generate(); 498 return result.generate();
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 572
511 573
512 // ECMA-262 section 15.5.4.14 574 // ECMA-262 section 15.5.4.14
513 function StringSplit(separator, limit) { 575 function StringSplit(separator, limit) {
514 var subject = TO_STRING_INLINE(this); 576 var subject = TO_STRING_INLINE(this);
515 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); 577 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
516 if (limit === 0) return []; 578 if (limit === 0) return [];
517 579
518 // ECMA-262 says that if separator is undefined, the result should 580 // ECMA-262 says that if separator is undefined, the result should
519 // be an array of size 1 containing the entire string. SpiderMonkey 581 // be an array of size 1 containing the entire string. SpiderMonkey
520 // and KJS have this behaviour only when no separator is given. If 582 // and KJS have this behavior only when no separator is given. If
521 // undefined is explicitly given, they convert it to a string and 583 // undefined is explicitly given, they convert it to a string and
522 // use that. We do as SpiderMonkey and KJS. 584 // use that. We do as SpiderMonkey and KJS.
523 if (%_ArgumentsLength() === 0) { 585 if (%_ArgumentsLength() === 0) {
524 return [subject]; 586 return [subject];
525 } 587 }
526 588
527 var length = subject.length; 589 var length = subject.length;
528 if (!IS_REGEXP(separator)) { 590 if (!IS_REGEXP(separator)) {
529 separator = TO_STRING_INLINE(separator); 591 separator = TO_STRING_INLINE(separator);
530 var separator_length = separator.length; 592 var separator_length = separator.length;
531 593
532 // If the separator string is empty then return the elements in the subject. 594 // If the separator string is empty then return the elements in the subject.
533 if (separator_length === 0) return %StringToArray(subject); 595 if (separator_length === 0) return %StringToArray(subject);
534 596
535 var result = []; 597 var result = %StringSplit(subject, separator, limit);
536 var start_index = 0;
537 var index;
538 while (true) {
539 if (start_index + separator_length > length ||
540 (index = %StringIndexOf(subject, separator, start_index)) === -1) {
541 result.push(SubString(subject, start_index, length));
542 break;
543 }
544 if (result.push(SubString(subject, start_index, index)) === limit) break;
545 start_index = index + separator_length;
546 }
547 598
548 return result; 599 return result;
549 } 600 }
550 601
602 var cache = regExpCache;
603
604 if (%_ObjectEquals(cache.type, 'split') &&
605 %_ObjectEquals(cache.regExp, separator) &&
606 %_ObjectEquals(cache.subject, subject)) {
607 return CloneRegexpAnswer(cache.answer);
608 }
609
610 cache.type = 'split';
611 cache.regExp = separator;
612 cache.subject = subject;
613
551 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); 614 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
552 615
553 if (length === 0) { 616 if (length === 0) {
554 if (splitMatch(separator, subject, 0, 0) != null) return []; 617 if (splitMatch(separator, subject, 0, 0) != null) {
618 cache.answer = [];
619 return [];
620 }
621 cache.answer = [subject];
555 return [subject]; 622 return [subject];
556 } 623 }
557 624
558 var currentIndex = 0; 625 var currentIndex = 0;
559 var startIndex = 0; 626 var startIndex = 0;
560 var result = []; 627 var result = [];
561 628
562 while (true) { 629 while (true) {
563 630
564 if (startIndex === length) { 631 if (startIndex === length) {
565 result[result.length] = subject.slice(currentIndex, length); 632 result[result.length] = subject.slice(currentIndex, length);
566 return result; 633 cache.answer = result;
634 return CloneRegexpAnswer(result);
567 } 635 }
568 636
569 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); 637 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
570 638
571 if (IS_NULL(matchInfo)) { 639 if (IS_NULL(matchInfo)) {
572 result[result.length] = subject.slice(currentIndex, length); 640 result[result.length] = subject.slice(currentIndex, length);
573 return result; 641 cache.answer = result;
642 return CloneRegexpAnswer(result);
574 } 643 }
575 644
576 var endIndex = matchInfo[CAPTURE1]; 645 var endIndex = matchInfo[CAPTURE1];
577 646
578 // We ignore a zero-length match at the currentIndex. 647 // We ignore a zero-length match at the currentIndex.
579 if (startIndex === endIndex && endIndex === currentIndex) { 648 if (startIndex === endIndex && endIndex === currentIndex) {
580 startIndex++; 649 startIndex++;
581 continue; 650 continue;
582 } 651 }
583 652
584 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0] ); 653 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0] );
585 if (result.length === limit) return result; 654 if (result.length === limit) {
655 cache.answer = result;
656 return CloneRegexpAnswer(result);
657 }
586 658
587 var num_captures = NUMBER_OF_CAPTURES(matchInfo); 659 var num_captures = NUMBER_OF_CAPTURES(matchInfo);
588 for (var i = 2; i < num_captures; i += 2) { 660 for (var i = 2; i < num_captures; i += 2) {
589 var start = matchInfo[CAPTURE(i)]; 661 var start = matchInfo[CAPTURE(i)];
590 var end = matchInfo[CAPTURE(i + 1)]; 662 var end = matchInfo[CAPTURE(i + 1)];
591 if (start != -1 && end != -1) { 663 if (start != -1 && end != -1) {
592 result[result.length] = SubString(subject, start, end); 664 result[result.length] = SubString(subject, start, end);
593 } else { 665 } else {
594 result[result.length] = void 0; 666 result[result.length] = void 0;
595 } 667 }
596 if (result.length === limit) return result; 668 if (result.length === limit) {
669 cache.answer = result;
670 return CloneRegexpAnswer(result);
671 }
597 } 672 }
598 673
599 startIndex = currentIndex = endIndex; 674 startIndex = currentIndex = endIndex;
600 } 675 }
601 } 676 }
602 677
603 678
604 // ECMA-262 section 15.5.4.14 679 // ECMA-262 section 15.5.4.14
605 // Helper function used by split. This version returns the matchInfo 680 // Helper function used by split. This version returns the matchInfo
606 // instead of allocating a new array with basically the same information. 681 // instead of allocating a new array with basically the same information.
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 } 787 }
713 788
714 function StringTrimLeft() { 789 function StringTrimLeft() {
715 return %StringTrim(TO_STRING_INLINE(this), true, false); 790 return %StringTrim(TO_STRING_INLINE(this), true, false);
716 } 791 }
717 792
718 function StringTrimRight() { 793 function StringTrimRight() {
719 return %StringTrim(TO_STRING_INLINE(this), false, true); 794 return %StringTrim(TO_STRING_INLINE(this), false, true);
720 } 795 }
721 796
797 var static_charcode_array = new $Array(4);
798
722 // ECMA-262, section 15.5.3.2 799 // ECMA-262, section 15.5.3.2
723 function StringFromCharCode(code) { 800 function StringFromCharCode(code) {
724 var n = %_ArgumentsLength(); 801 var n = %_ArgumentsLength();
725 if (n == 1) return %_CharFromCode(ToNumber(code) & 0xffff) 802 if (n == 1) {
803 if (!%_IsSmi(code)) code = ToNumber(code);
804 return %_CharFromCode(code & 0xffff);
805 }
726 806
727 // NOTE: This is not super-efficient, but it is necessary because we 807 // NOTE: This is not super-efficient, but it is necessary because we
728 // want to avoid converting to numbers from within the virtual 808 // want to avoid converting to numbers from within the virtual
729 // machine. Maybe we can find another way of doing this? 809 // machine. Maybe we can find another way of doing this?
730 var codes = new $Array(n); 810 var codes = static_charcode_array;
731 for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); 811 for (var i = 0; i < n; i++) {
812 var code = %_Arguments(i);
813 if (!%_IsSmi(code)) code = ToNumber(code);
814 codes[i] = code;
815 }
816 codes.length = n;
732 return %StringFromCharCodeArray(codes); 817 return %StringFromCharCodeArray(codes);
733 } 818 }
734 819
735 820
736 // Helper function for very basic XSS protection. 821 // Helper function for very basic XSS protection.
737 function HtmlEscape(str) { 822 function HtmlEscape(str) {
738 return TO_STRING_INLINE(str).replace(/</g, "&lt;") 823 return TO_STRING_INLINE(str).replace(/</g, "&lt;")
739 .replace(/>/g, "&gt;") 824 .replace(/>/g, "&gt;")
740 .replace(/"/g, "&quot;") 825 .replace(/"/g, "&quot;")
741 .replace(/'/g, "&#039;"); 826 .replace(/'/g, "&#039;");
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 "small", StringSmall, 986 "small", StringSmall,
902 "strike", StringStrike, 987 "strike", StringStrike,
903 "sub", StringSub, 988 "sub", StringSub,
904 "sup", StringSup, 989 "sup", StringSup,
905 "toJSON", StringToJSON 990 "toJSON", StringToJSON
906 )); 991 ));
907 } 992 }
908 993
909 994
910 SetupString(); 995 SetupString();
OLDNEW
« src/runtime.cc ('K') | « src/splay-tree-inl.h ('k') | src/stub-cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698