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

Side by Side Diff: src/string.js

Issue 995005: Fix a bug in the regexp caching. Also add a few more places to... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
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 ORIGINAL_REGEXP(regexp); 167 if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_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-delay.js. 186 // lastMatchInfo is defined in regexp-delay.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 13 matching lines...) Expand all
232 ExpandReplacement(replace, subject, reusableMatchInfo, builder); 256 ExpandReplacement(replace, subject, reusableMatchInfo, builder);
233 } 257 }
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 var cachedReplaceSubject;
243 var cachedReplaceRegexp;
244 var cachedReplaceReplacement;
245 var cachedReplaceAnswer;
246
247 // Helper function for regular expressions in String.prototype.replace. 266 // Helper function for regular expressions in String.prototype.replace.
248 function StringReplaceRegExp(subject, regexp, replace) { 267 function StringReplaceRegExp(subject, regexp, replace) {
249 if (%_ObjectEquals(replace, cachedReplaceReplacement) && 268 var cache = regExpCache;
250 %_ObjectEquals(subject, cachedReplaceSubject) && 269 if (%_ObjectEquals(cache.regExp, regexp) &&
251 %_ObjectEquals(regexp, cachedReplaceRegexp)) { 270 %_ObjectEquals(cache.type, 'replace') &&
252 return cachedReplaceAnswer; 271 %_ObjectEquals(cache.replaceString, replace) &&
272 %_ObjectEquals(cache.subject, subject)) {
273 return cache.answer;
253 } 274 }
254 replace = TO_STRING_INLINE(replace); 275 replace = TO_STRING_INLINE(replace);
255 var answer = %StringReplaceRegExpWithString(subject, 276 var answer = %StringReplaceRegExpWithString(subject,
256 regexp, 277 regexp,
257 replace, 278 replace,
258 lastMatchInfo); 279 lastMatchInfo);
259 cachedReplaceSubject = subject; 280 cache.subject = subject;
260 cachedReplaceRegexp = regexp; 281 cache.regExp = regexp;
261 cachedReplaceReplacement = replace; 282 cache.replaceString = replace;
262 cachedReplaceAnswer = answer; 283 cache.answer = answer;
284 cache.type = 'replace';
263 return answer; 285 return answer;
264 } 286 }
265 287
266 288
267 // 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
268 // the result. 290 // the result.
269 function ExpandReplacement(string, subject, matchInfo, builder) { 291 function ExpandReplacement(string, subject, matchInfo, builder) {
270 var next = %StringIndexOf(string, '$', 0); 292 var next = %StringIndexOf(string, '$', 0);
271 if (next < 0) { 293 if (next < 0) {
272 builder.add(string); 294 builder.add(string);
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 var separator_length = separator.length; 592 var separator_length = separator.length;
571 593
572 // 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.
573 if (separator_length === 0) return %StringToArray(subject); 595 if (separator_length === 0) return %StringToArray(subject);
574 596
575 var result = %StringSplit(subject, separator, limit); 597 var result = %StringSplit(subject, separator, limit);
576 598
577 return result; 599 return result;
578 } 600 }
579 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
580 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); 614 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
581 615
582 if (length === 0) { 616 if (length === 0) {
583 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];
584 return [subject]; 622 return [subject];
585 } 623 }
586 624
587 var currentIndex = 0; 625 var currentIndex = 0;
588 var startIndex = 0; 626 var startIndex = 0;
589 var result = []; 627 var result = [];
590 628
591 while (true) { 629 while (true) {
592 630
593 if (startIndex === length) { 631 if (startIndex === length) {
594 result[result.length] = subject.slice(currentIndex, length); 632 result[result.length] = subject.slice(currentIndex, length);
595 return result; 633 cache.answer = result;
634 return CloneRegexpAnswer(result);
596 } 635 }
597 636
598 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); 637 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
599 638
600 if (IS_NULL(matchInfo)) { 639 if (IS_NULL(matchInfo)) {
601 result[result.length] = subject.slice(currentIndex, length); 640 result[result.length] = subject.slice(currentIndex, length);
602 return result; 641 cache.answer = result;
642 return CloneRegexpAnswer(result);
603 } 643 }
604 644
605 var endIndex = matchInfo[CAPTURE1]; 645 var endIndex = matchInfo[CAPTURE1];
606 646
607 // We ignore a zero-length match at the currentIndex. 647 // We ignore a zero-length match at the currentIndex.
608 if (startIndex === endIndex && endIndex === currentIndex) { 648 if (startIndex === endIndex && endIndex === currentIndex) {
609 startIndex++; 649 startIndex++;
610 continue; 650 continue;
611 } 651 }
612 652
613 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0] ); 653 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0] );
614 if (result.length === limit) return result; 654 if (result.length === limit) {
655 cache.answer = result;
656 return CloneRegexpAnswer(result);
657 }
615 658
616 var num_captures = NUMBER_OF_CAPTURES(matchInfo); 659 var num_captures = NUMBER_OF_CAPTURES(matchInfo);
617 for (var i = 2; i < num_captures; i += 2) { 660 for (var i = 2; i < num_captures; i += 2) {
618 var start = matchInfo[CAPTURE(i)]; 661 var start = matchInfo[CAPTURE(i)];
619 var end = matchInfo[CAPTURE(i + 1)]; 662 var end = matchInfo[CAPTURE(i + 1)];
620 if (start != -1 && end != -1) { 663 if (start != -1 && end != -1) {
621 result[result.length] = SubString(subject, start, end); 664 result[result.length] = SubString(subject, start, end);
622 } else { 665 } else {
623 result[result.length] = void 0; 666 result[result.length] = void 0;
624 } 667 }
625 if (result.length === limit) return result; 668 if (result.length === limit) {
669 cache.answer = result;
670 return CloneRegexpAnswer(result);
671 }
626 } 672 }
627 673
628 startIndex = currentIndex = endIndex; 674 startIndex = currentIndex = endIndex;
629 } 675 }
630 } 676 }
631 677
632 678
633 // ECMA-262 section 15.5.4.14 679 // ECMA-262 section 15.5.4.14
634 // Helper function used by split. This version returns the matchInfo 680 // Helper function used by split. This version returns the matchInfo
635 // instead of allocating a new array with basically the same information. 681 // instead of allocating a new array with basically the same information.
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 "small", StringSmall, 985 "small", StringSmall,
940 "strike", StringStrike, 986 "strike", StringStrike,
941 "sub", StringSub, 987 "sub", StringSub,
942 "sup", StringSup, 988 "sup", StringSup,
943 "toJSON", StringToJSON 989 "toJSON", StringToJSON
944 )); 990 ));
945 } 991 }
946 992
947 993
948 SetupString(); 994 SetupString();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698