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

Side by Side Diff: src/string.js

Issue 5708006: Optimizing BuildResultFromMatchInfo, StringReplace and StringSplit. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years 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
« no previous file with comments | « src/regexp.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 parts[i + 1] = TO_STRING_INLINE(part); 94 parts[i + 1] = TO_STRING_INLINE(part);
95 } 95 }
96 return %StringBuilderConcat(parts, len + 1, ""); 96 return %StringBuilderConcat(parts, len + 1, "");
97 } 97 }
98 98
99 // Match ES3 and Safari 99 // Match ES3 and Safari
100 %FunctionSetLength(StringConcat, 1); 100 %FunctionSetLength(StringConcat, 1);
101 101
102 102
103 // ECMA-262 section 15.5.4.7 103 // ECMA-262 section 15.5.4.7
104 function StringIndexOf(searchString /* position */) { // length == 1 104 function StringIndexOf(pattern /* position */) { // length == 1
105 var subject_str = TO_STRING_INLINE(this); 105 var subject = TO_STRING_INLINE(this);
106 var pattern_str = TO_STRING_INLINE(searchString); 106 var pattern = TO_STRING_INLINE(pattern);
107 var subject_str_len = subject_str.length; 107 var subject_len = subject.length;
108 var pattern_str_len = pattern_str.length; 108 var pattern_len = pattern.length;
109 var index = 0; 109 var index = 0;
110 if (%_ArgumentsLength() > 1) { 110 if (%_ArgumentsLength() > 1) {
111 var arg1 = %_Arguments(1); // position 111 var arg1 = %_Arguments(1); // position
112 index = TO_INTEGER(arg1); 112 index = TO_INTEGER(arg1);
113 } 113 }
114 if (index < 0) index = 0; 114 if (index < 0) index = 0;
115 if (index > subject_str_len) index = subject_str_len; 115 if (index > subject_len) index = subject_len;
116 if (pattern_str_len + index > subject_str_len) return -1; 116 if (pattern_len + index > subject_len) return -1;
117 return %StringIndexOf(subject_str, pattern_str, index); 117 return %StringIndexOf(subject, pattern, index);
118 } 118 }
119 119
120 120
121 // ECMA-262 section 15.5.4.8 121 // ECMA-262 section 15.5.4.8
122 function StringLastIndexOf(searchString /* position */) { // length == 1 122 function StringLastIndexOf(pat /* position */) { // length == 1
123 var sub = TO_STRING_INLINE(this); 123 var sub = TO_STRING_INLINE(this);
124 var subLength = sub.length; 124 var subLength = sub.length;
125 var pat = TO_STRING_INLINE(searchString); 125 var pat = TO_STRING_INLINE(pat);
126 var patLength = pat.length; 126 var patLength = pat.length;
127 var index = subLength - patLength; 127 var index = subLength - patLength;
128 if (%_ArgumentsLength() > 1) { 128 if (%_ArgumentsLength() > 1) {
129 var position = ToNumber(%_Arguments(1)); 129 var position = ToNumber(%_Arguments(1));
130 if (!$isNaN(position)) { 130 if (!$isNaN(position)) {
131 position = TO_INTEGER(position); 131 position = TO_INTEGER(position);
132 if (position < 0) { 132 if (position < 0) {
133 position = 0; 133 position = 0;
134 } 134 }
135 if (position + patLength < subLength) { 135 if (position + patLength < subLength) {
136 index = position 136 index = position
137 } 137 }
138 } 138 }
139 } 139 }
140 if (index < 0) { 140 if (index < 0) {
141 return -1; 141 return -1;
142 } 142 }
143 return %StringLastIndexOf(sub, pat, index); 143 return %StringLastIndexOf(sub, pat, index);
144 } 144 }
145 145
146 146
147 // ECMA-262 section 15.5.4.9 147 // ECMA-262 section 15.5.4.9
148 // 148 //
149 // This function is implementation specific. For now, we do not 149 // This function is implementation specific. For now, we do not
150 // do anything locale specific. 150 // do anything locale specific.
151 function StringLocaleCompare(other) { 151 function StringLocaleCompare(other) {
152 if (%_ArgumentsLength() === 0) return 0; 152 if (%_ArgumentsLength() === 0) return 0;
153 153 return %StringLocaleCompare(TO_STRING_INLINE(this),
154 var this_str = TO_STRING_INLINE(this); 154 TO_STRING_INLINE(other));
155 var other_str = TO_STRING_INLINE(other);
156 return %StringLocaleCompare(this_str, other_str);
157 } 155 }
158 156
159 157
160 // ECMA-262 section 15.5.4.10 158 // ECMA-262 section 15.5.4.10
161 function StringMatch(regexp) { 159 function StringMatch(regexp) {
162 var subject = TO_STRING_INLINE(this); 160 var subject = TO_STRING_INLINE(this);
163 if (IS_REGEXP(regexp)) { 161 if (IS_REGEXP(regexp)) {
164 if (!regexp.global) return regexp.exec(subject); 162 if (!regexp.global) return regexp.exec(subject);
165 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); 163 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
166 // lastMatchInfo is defined in regexp.js. 164 // lastMatchInfo is defined in regexp.js.
167 return %StringMatch(subject, regexp, lastMatchInfo); 165 return %StringMatch(subject, regexp, lastMatchInfo);
168 } 166 }
169 // Non-regexp argument. 167 // Non-regexp argument.
170 regexp = new $RegExp(regexp); 168 regexp = new $RegExp(regexp);
171 return RegExpExecNoTests(regexp, subject, 0); 169 return RegExpExecNoTests(regexp, subject, 0);
172 } 170 }
173 171
174 172
175 // SubString is an internal function that returns the sub string of 'string'. 173 // SubString is an internal function that returns the sub string of 'string'.
176 // If resulting string is of length 1, we use the one character cache 174 // If resulting string is of length 1, we use the one character cache
177 // otherwise we call the runtime system. 175 // otherwise we call the runtime system.
178 function SubString(string, start, end) { 176 function SubString(string, start, end) {
179 // Use the one character string cache. 177 // Use the one character string cache.
180 if (start + 1 == end) { 178 if (start + 1 == end) return %_StringCharAt(string, start);
181 return %_StringCharAt(string, start);
182 }
183 return %_SubString(string, start, end); 179 return %_SubString(string, start, end);
184 } 180 }
185 181
186 182
187 // This has the same size as the lastMatchInfo array, and can be used for 183 // This has the same size as the lastMatchInfo array, and can be used for
188 // functions that expect that structure to be returned. It is used when the 184 // functions that expect that structure to be returned. It is used when the
189 // needle is a string rather than a regexp. In this case we can't update 185 // needle is a string rather than a regexp. In this case we can't update
190 // lastMatchArray without erroneously affecting the properties on the global 186 // lastMatchArray without erroneously affecting the properties on the global
191 // RegExp object. 187 // RegExp object.
192 var reusableMatchInfo = [2, "", "", -1, -1]; 188 var reusableMatchInfo = [2, "", "", -1, -1];
193 189
194 190
195 // ECMA-262, section 15.5.4.11 191 // ECMA-262, section 15.5.4.11
196 function StringReplace(search, replace) { 192 function StringReplace(search, replace) {
197 var subject = TO_STRING_INLINE(this); 193 var subject = TO_STRING_INLINE(this);
198 194
199 // Delegate to one of the regular expression variants if necessary. 195 // Delegate to one of the regular expression variants if necessary.
200 if (IS_REGEXP(search)) { 196 if (IS_REGEXP(search)) {
201 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); 197 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
202 if (IS_FUNCTION(replace)) { 198 if (IS_FUNCTION(replace)) {
203 if (search.global) { 199 if (search.global) {
204 return StringReplaceGlobalRegExpWithFunction(subject, search, replace); 200 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
205 } else { 201 } else {
206 return StringReplaceNonGlobalRegExpWithFunction(subject, 202 return StringReplaceNonGlobalRegExpWithFunction(subject,
207 search, 203 search,
208 replace); 204 replace);
209 } 205 }
210 } else { 206 } else {
211 return StringReplaceRegExp(subject, search, replace); 207 return %StringReplaceRegExpWithString(subject,
208 search,
209 TO_STRING_INLINE(replace),
210 lastMatchInfo);
212 } 211 }
213 } 212 }
214 213
215 // Convert the search argument to a string and search for it. 214 // Convert the search argument to a string and search for it.
216 search = TO_STRING_INLINE(search); 215 search = TO_STRING_INLINE(search);
217 var start = %StringIndexOf(subject, search, 0); 216 var start = %StringIndexOf(subject, search, 0);
218 if (start < 0) return subject; 217 if (start < 0) return subject;
219 var end = start + search.length; 218 var end = start + search.length;
220 219
221 var builder = new ReplaceResultBuilder(subject); 220 var builder = new ReplaceResultBuilder(subject);
222 // prefix 221 // prefix
223 builder.addSpecialSlice(0, start); 222 builder.addSpecialSlice(0, start);
224 223
225 // Compute the string to replace with. 224 // Compute the string to replace with.
226 if (IS_FUNCTION(replace)) { 225 if (IS_FUNCTION(replace)) {
227 builder.add(replace.call(null, search, start, subject)); 226 builder.add(%_CallFunction(%GetGlobalReceiver(),
227 search,
228 start,
229 subject,
230 replace));
228 } else { 231 } else {
229 reusableMatchInfo[CAPTURE0] = start; 232 reusableMatchInfo[CAPTURE0] = start;
230 reusableMatchInfo[CAPTURE1] = end; 233 reusableMatchInfo[CAPTURE1] = end;
231 replace = TO_STRING_INLINE(replace); 234 replace = TO_STRING_INLINE(replace);
232 ExpandReplacement(replace, subject, reusableMatchInfo, builder); 235 ExpandReplacement(replace, subject, reusableMatchInfo, builder);
233 } 236 }
234 237
235 // suffix 238 // suffix
236 builder.addSpecialSlice(end, subject.length); 239 builder.addSpecialSlice(end, subject.length);
237 240
238 return builder.generate(); 241 return builder.generate();
239 } 242 }
240 243
241 244
242 // Helper function for regular expressions in String.prototype.replace.
243 function StringReplaceRegExp(subject, regexp, replace) {
244 return %StringReplaceRegExpWithString(subject,
245 regexp,
246 TO_STRING_INLINE(replace),
247 lastMatchInfo);
248 }
249
250
251 // Expand the $-expressions in the string and return a new string with 245 // Expand the $-expressions in the string and return a new string with
252 // the result. 246 // the result.
253 function ExpandReplacement(string, subject, matchInfo, builder) { 247 function ExpandReplacement(string, subject, matchInfo, builder) {
254 var next = %StringIndexOf(string, '$', 0); 248 var next = %StringIndexOf(string, '$', 0);
255 if (next < 0) { 249 if (next < 0) {
256 builder.add(string); 250 builder.add(string);
257 return; 251 return;
258 } 252 }
259 253
260 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. 254 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 match_start = (elem >> 11) + (elem & 0x7ff); 395 match_start = (elem >> 11) + (elem & 0x7ff);
402 } else { 396 } else {
403 match_start = res[++i] - elem; 397 match_start = res[++i] - elem;
404 } 398 }
405 } else { 399 } else {
406 override[0] = elem; 400 override[0] = elem;
407 override[1] = match_start; 401 override[1] = match_start;
408 lastMatchInfoOverride = override; 402 lastMatchInfoOverride = override;
409 var func_result = 403 var func_result =
410 %_CallFunction(receiver, elem, match_start, subject, replace); 404 %_CallFunction(receiver, elem, match_start, subject, replace);
411 if (!IS_STRING(func_result)) { 405 func_result = TO_STRING_INLINE(func_result);
412 func_result = NonStringToString(func_result);
413 }
414 res[i] = func_result; 406 res[i] = func_result;
415 match_start += elem.length; 407 match_start += elem.length;
416 } 408 }
417 i++; 409 i++;
418 } 410 }
419 } else { 411 } else {
420 while (i < len) { 412 while (i < len) {
421 var elem = res[i]; 413 var elem = res[i];
422 if (!%_IsSmi(elem)) { 414 if (!%_IsSmi(elem)) {
423 // elem must be an Array. 415 // elem must be an Array.
424 // Use the apply argument as backing for global RegExp properties. 416 // Use the apply argument as backing for global RegExp properties.
425 lastMatchInfoOverride = elem; 417 lastMatchInfoOverride = elem;
426 var func_result = replace.apply(null, elem); 418 var func_result = replace.apply(null, elem);
427 if (!IS_STRING(func_result)) { 419 func_result = TO_STRING_INLINE(func_result);
428 func_result = NonStringToString(func_result);
429 }
430 res[i] = func_result; 420 res[i] = func_result;
431 } 421 }
432 i++; 422 i++;
433 } 423 }
434 } 424 }
435 var resultBuilder = new ReplaceResultBuilder(subject, res); 425 var resultBuilder = new ReplaceResultBuilder(subject, res);
436 var result = resultBuilder.generate(); 426 var result = resultBuilder.generate();
437 resultArray.length = 0; 427 resultArray.length = 0;
438 reusableReplaceArray = resultArray; 428 reusableReplaceArray = resultArray;
439 return result; 429 return result;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 // ECMA-262 section 15.5.4.12 470 // ECMA-262 section 15.5.4.12
481 function StringSearch(re) { 471 function StringSearch(re) {
482 var regexp; 472 var regexp;
483 if (IS_STRING(re)) { 473 if (IS_STRING(re)) {
484 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re); 474 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
485 } else if (IS_REGEXP(re)) { 475 } else if (IS_REGEXP(re)) {
486 regexp = re; 476 regexp = re;
487 } else { 477 } else {
488 regexp = new $RegExp(re); 478 regexp = new $RegExp(re);
489 } 479 }
490 var s = TO_STRING_INLINE(this); 480 var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
491 var match = DoRegExpExec(regexp, s, 0);
492 if (match) { 481 if (match) {
493 return match[CAPTURE0]; 482 return match[CAPTURE0];
494 } 483 }
495 return -1; 484 return -1;
496 } 485 }
497 486
498 487
499 // ECMA-262 section 15.5.4.13 488 // ECMA-262 section 15.5.4.13
500 function StringSlice(start, end) { 489 function StringSlice(start, end) {
501 var s = TO_STRING_INLINE(this); 490 var s = TO_STRING_INLINE(this);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 } 558 }
570 559
571 var currentIndex = 0; 560 var currentIndex = 0;
572 var startIndex = 0; 561 var startIndex = 0;
573 var result = []; 562 var result = [];
574 563
575 outer_loop: 564 outer_loop:
576 while (true) { 565 while (true) {
577 566
578 if (startIndex === length) { 567 if (startIndex === length) {
579 result[result.length] = subject.slice(currentIndex, length); 568 result.push(subject.slice(currentIndex, length));
580 break; 569 break;
581 } 570 }
582 571
583 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); 572 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
584 573
585 if (IS_NULL(matchInfo)) { 574 if (IS_NULL(matchInfo)) {
586 result[result.length] = subject.slice(currentIndex, length); 575 result.push(subject.slice(currentIndex, length));
587 break; 576 break;
588 } 577 }
589 578
590 var endIndex = matchInfo[CAPTURE1]; 579 var endIndex = matchInfo[CAPTURE1];
591 580
592 // We ignore a zero-length match at the currentIndex. 581 // We ignore a zero-length match at the currentIndex.
593 if (startIndex === endIndex && endIndex === currentIndex) { 582 if (startIndex === endIndex && endIndex === currentIndex) {
594 startIndex++; 583 startIndex++;
595 continue; 584 continue;
596 } 585 }
597 586
598 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0] ); 587 result.push(SubString(subject, currentIndex, matchInfo[CAPTURE0]));
599 if (result.length === limit) break; 588 if (result.length === limit) break;
600 589
601 var num_captures = NUMBER_OF_CAPTURES(matchInfo); 590 var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
602 for (var i = 2; i < num_captures; i += 2) { 591 for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
603 var start = matchInfo[CAPTURE(i)]; 592 var start = matchInfo[i++];
604 var end = matchInfo[CAPTURE(i + 1)]; 593 var end = matchInfo[i++];
605 if (start != -1 && end != -1) { 594 if (end != -1) {
606 result[result.length] = SubString(subject, start, end); 595 if (start + 1 == end) {
596 result.push(%_StringCharAt(subject, start));
597 } else {
598 result.push(%_SubString(subject, start, end));
599 }
607 } else { 600 } else {
608 result[result.length] = void 0; 601 result.push(void 0);
609 } 602 }
610 if (result.length === limit) break outer_loop; 603 if (result.length === limit) break outer_loop;
611 } 604 }
612 605
613 startIndex = currentIndex = endIndex; 606 startIndex = currentIndex = endIndex;
614 } 607 }
615 return result; 608 return result;
616 } 609 }
617 610
618 611
(...skipping 30 matching lines...) Expand all
649 } else { 642 } else {
650 if (end_i < 0) end_i = 0; 643 if (end_i < 0) end_i = 0;
651 if (start_i > end_i) { 644 if (start_i > end_i) {
652 var tmp = end_i; 645 var tmp = end_i;
653 end_i = start_i; 646 end_i = start_i;
654 start_i = tmp; 647 start_i = tmp;
655 } 648 }
656 } 649 }
657 } 650 }
658 651
659 return SubString(s, start_i, end_i); 652 return (start_i + 1 == end_i
653 ? %_StringCharAt(s, start_i)
654 : %_SubString(s, start_i, end_i));
660 } 655 }
661 656
662 657
663 // This is not a part of ECMA-262. 658 // This is not a part of ECMA-262.
664 function StringSubstr(start, n) { 659 function StringSubstr(start, n) {
665 var s = TO_STRING_INLINE(this); 660 var s = TO_STRING_INLINE(this);
666 var len; 661 var len;
667 662
668 // Correct n: If not given, set to string length; if explicitly 663 // Correct n: If not given, set to string length; if explicitly
669 // set to undefined, zero, or negative, returns empty string. 664 // set to undefined, zero, or negative, returns empty string.
(...skipping 17 matching lines...) Expand all
687 // use zero. 682 // use zero.
688 if (start < 0) { 683 if (start < 0) {
689 start += s.length; 684 start += s.length;
690 if (start < 0) start = 0; 685 if (start < 0) start = 0;
691 } 686 }
692 } 687 }
693 688
694 var end = start + len; 689 var end = start + len;
695 if (end > s.length) end = s.length; 690 if (end > s.length) end = s.length;
696 691
697 return SubString(s, start, end); 692 return (start + 1 == end
693 ? %_StringCharAt(s, start)
694 : %_SubString(s, start, end));
698 } 695 }
699 696
700 697
701 // ECMA-262, 15.5.4.16 698 // ECMA-262, 15.5.4.16
702 function StringToLowerCase() { 699 function StringToLowerCase() {
703 return %StringToLowerCase(TO_STRING_INLINE(this)); 700 return %StringToLowerCase(TO_STRING_INLINE(this));
704 } 701 }
705 702
706 703
707 // ECMA-262, 15.5.4.17 704 // ECMA-262, 15.5.4.17
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
929 "small", StringSmall, 926 "small", StringSmall,
930 "strike", StringStrike, 927 "strike", StringStrike,
931 "sub", StringSub, 928 "sub", StringSub,
932 "sup", StringSup, 929 "sup", StringSup,
933 "toJSON", StringToJSON 930 "toJSON", StringToJSON
934 )); 931 ));
935 } 932 }
936 933
937 934
938 SetupString(); 935 SetupString();
OLDNEW
« no previous file with comments | « src/regexp.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698