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

Side by Side Diff: src/js/regexp.js

Issue 1836123002: Add fast paths for native RegExps in ES2015 subclass-aware code (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Less zealous inlining Created 4 years, 8 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
« no previous file with comments | « src/js/harmony-unicode-regexps.js ('k') | test/test262/test262.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 (function(global, utils) { 5 (function(global, utils) {
6 6
7 'use strict'; 7 'use strict';
8 8
9 %CheckIsBootstrapping(); 9 %CheckIsBootstrapping();
10 10
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 260
261 // Successful match. 261 // Successful match.
262 if (updateLastIndex) { 262 if (updateLastIndex) {
263 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; 263 this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
264 } 264 }
265 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); 265 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
266 } 266 }
267 267
268 268
269 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) 269 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
270 function RegExpSubclassExec(regexp, string) { 270 // Also takes an optional exec method in case our caller
271 var exec = regexp.exec; 271 // has already fetched exec.
272 function RegExpSubclassExec(regexp, string, exec) {
273 if (IS_UNDEFINED(exec)) {
274 exec = regexp.exec;
275 }
272 if (IS_CALLABLE(exec)) { 276 if (IS_CALLABLE(exec)) {
273 var result = %_Call(exec, regexp, string); 277 var result = %_Call(exec, regexp, string);
274 if (!IS_RECEIVER(result) && !IS_NULL(result)) { 278 if (!IS_RECEIVER(result) && !IS_NULL(result)) {
275 throw MakeTypeError(kInvalidRegExpExecResult); 279 throw MakeTypeError(kInvalidRegExpExecResult);
276 } 280 }
277 return result; 281 return result;
278 } 282 }
279 return %_Call(RegExpExecJS, regexp, string); 283 return %_Call(RegExpExecJS, regexp, string);
280 } 284 }
285 %SetForceInlineFlag(RegExpSubclassExec);
281 286
282 287
283 // One-element cache for the simplified test regexp. 288 // One-element cache for the simplified test regexp.
284 var regexp_key; 289 var regexp_key;
285 var regexp_val; 290 var regexp_val;
286 291
287 // Legacy implementation of RegExp.prototype.test 292 // Legacy implementation of RegExp.prototype.test
288 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be 293 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
289 // that test is defined in terms of String.prototype.exec. However, it probably 294 // that test is defined in terms of String.prototype.exec. However, it probably
290 // means the original value of String.prototype.exec, which is what everybody 295 // means the original value of String.prototype.exec, which is what everybody
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 // ES#sec-regexp.prototype-@@split 481 // ES#sec-regexp.prototype-@@split
477 // RegExp.prototype [ @@split ] ( string, limit ) 482 // RegExp.prototype [ @@split ] ( string, limit )
478 function RegExpSubclassSplit(string, limit) { 483 function RegExpSubclassSplit(string, limit) {
479 if (!IS_RECEIVER(this)) { 484 if (!IS_RECEIVER(this)) {
480 throw MakeTypeError(kIncompatibleMethodReceiver, 485 throw MakeTypeError(kIncompatibleMethodReceiver,
481 "RegExp.prototype.@@split", this); 486 "RegExp.prototype.@@split", this);
482 } 487 }
483 string = TO_STRING(string); 488 string = TO_STRING(string);
484 var constructor = SpeciesConstructor(this, GlobalRegExp); 489 var constructor = SpeciesConstructor(this, GlobalRegExp);
485 var flags = TO_STRING(this.flags); 490 var flags = TO_STRING(this.flags);
491
492 // TODO(adamk): this fast path is wrong with respect to this.global
493 // and this.sticky, but hopefully the spec will remove those gets
494 // and thus make the assumption of 'exec' having no side-effects
495 // more correct. Also, we doesn't ensure that 'exec' is actually
496 // a data property on RegExp.prototype.
497 var exec;
498 if (IS_REGEXP(this) && constructor === GlobalRegExp) {
499 exec = this.exec;
500 if (exec === RegExpSubclassExecJS) {
501 return %_Call(RegExpSplit, this, string, limit);
502 }
503 }
504
486 var unicode = %StringIndexOf(flags, 'u', 0) >= 0; 505 var unicode = %StringIndexOf(flags, 'u', 0) >= 0;
487 var sticky = %StringIndexOf(flags, 'y', 0) >= 0; 506 var sticky = %StringIndexOf(flags, 'y', 0) >= 0;
488 var newFlags = sticky ? flags : flags + "y"; 507 var newFlags = sticky ? flags : flags + "y";
489 var splitter = new constructor(this, newFlags); 508 var splitter = new constructor(this, newFlags);
490 var array = new GlobalArray(); 509 var array = new GlobalArray();
491 var arrayIndex = 0; 510 var arrayIndex = 0;
492 var lim = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit); 511 var lim = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
493 var size = string.length; 512 var size = string.length;
494 var prevStringIndex = 0; 513 var prevStringIndex = 0;
495 if (lim === 0) return array; 514 if (lim === 0) return array;
496 var result; 515 var result;
497 if (size === 0) { 516 if (size === 0) {
498 result = RegExpSubclassExec(splitter, string); 517 result = RegExpSubclassExec(splitter, string);
499 if (IS_NULL(result)) AddIndexedProperty(array, 0, string); 518 if (IS_NULL(result)) AddIndexedProperty(array, 0, string);
500 return array; 519 return array;
501 } 520 }
502 var stringIndex = prevStringIndex; 521 var stringIndex = prevStringIndex;
503 while (stringIndex < size) { 522 while (stringIndex < size) {
504 splitter.lastIndex = stringIndex; 523 splitter.lastIndex = stringIndex;
505 result = RegExpSubclassExec(splitter, string); 524 result = RegExpSubclassExec(splitter, string, exec);
525 // Ensure exec will be read again on the next loop through.
526 exec = UNDEFINED;
506 if (IS_NULL(result)) { 527 if (IS_NULL(result)) {
507 stringIndex += AdvanceStringIndex(string, stringIndex, unicode); 528 stringIndex += AdvanceStringIndex(string, stringIndex, unicode);
508 } else { 529 } else {
509 var end = MinSimple(TO_LENGTH(splitter.lastIndex), size); 530 var end = MinSimple(TO_LENGTH(splitter.lastIndex), size);
510 if (end === stringIndex) { 531 if (end === stringIndex) {
511 stringIndex += AdvanceStringIndex(string, stringIndex, unicode); 532 stringIndex += AdvanceStringIndex(string, stringIndex, unicode);
512 } else { 533 } else {
513 AddIndexedProperty( 534 AddIndexedProperty(
514 array, arrayIndex, 535 array, arrayIndex,
515 %_SubString(string, prevStringIndex, stringIndex)); 536 %_SubString(string, prevStringIndex, stringIndex));
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 function RegExpSubclassMatch(string) { 575 function RegExpSubclassMatch(string) {
555 if (!IS_RECEIVER(this)) { 576 if (!IS_RECEIVER(this)) {
556 throw MakeTypeError(kIncompatibleMethodReceiver, 577 throw MakeTypeError(kIncompatibleMethodReceiver,
557 "RegExp.prototype.@@match", this); 578 "RegExp.prototype.@@match", this);
558 } 579 }
559 string = TO_STRING(string); 580 string = TO_STRING(string);
560 var global = this.global; 581 var global = this.global;
561 if (!global) return RegExpSubclassExec(this, string); 582 if (!global) return RegExpSubclassExec(this, string);
562 var unicode = this.unicode; 583 var unicode = this.unicode;
563 this.lastIndex = 0; 584 this.lastIndex = 0;
564 var array = []; 585 var array = new InternalArray();
565 var n = 0; 586 var n = 0;
566 var result; 587 var result;
567 while (true) { 588 while (true) {
568 result = RegExpSubclassExec(this, string); 589 result = RegExpSubclassExec(this, string);
569 if (IS_NULL(result)) { 590 if (IS_NULL(result)) {
570 if (n === 0) return null; 591 if (n === 0) return null;
571 return array; 592 break;
572 } 593 }
573 var matchStr = TO_STRING(result[0]); 594 var matchStr = TO_STRING(result[0]);
574 %AddElement(array, n, matchStr); 595 array[n] = matchStr;
575 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); 596 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode);
576 n++; 597 n++;
577 } 598 }
599 var resultArray = [];
600 %MoveArrayContents(array, resultArray);
601 return resultArray;
578 } 602 }
579 %FunctionRemovePrototype(RegExpSubclassMatch); 603 %FunctionRemovePrototype(RegExpSubclassMatch);
580 604
581 605
582 // Legacy implementation of RegExp.prototype[Symbol.replace] which 606 // Legacy implementation of RegExp.prototype[Symbol.replace] which
583 // doesn't properly call the underlying exec method. 607 // doesn't properly call the underlying exec method.
584 608
585 // TODO(lrn): This array will survive indefinitely if replace is never 609 // TODO(lrn): This array will survive indefinitely if replace is never
586 // called again. However, it will be empty, since the contents are cleared 610 // called again. However, it will be empty, since the contents are cleared
587 // in the finally block. 611 // in the finally block.
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
864 // RegExp.prototype [ @@replace ] ( string, replaceValue ) 888 // RegExp.prototype [ @@replace ] ( string, replaceValue )
865 function RegExpSubclassReplace(string, replace) { 889 function RegExpSubclassReplace(string, replace) {
866 if (!IS_RECEIVER(this)) { 890 if (!IS_RECEIVER(this)) {
867 throw MakeTypeError(kIncompatibleMethodReceiver, 891 throw MakeTypeError(kIncompatibleMethodReceiver,
868 "RegExp.prototype.@@replace", this); 892 "RegExp.prototype.@@replace", this);
869 } 893 }
870 string = TO_STRING(string); 894 string = TO_STRING(string);
871 var length = string.length; 895 var length = string.length;
872 var functionalReplace = IS_CALLABLE(replace); 896 var functionalReplace = IS_CALLABLE(replace);
873 if (!functionalReplace) replace = TO_STRING(replace); 897 if (!functionalReplace) replace = TO_STRING(replace);
874 var global = this.global; 898 var global = TO_BOOLEAN(this.global);
875 if (global) { 899 if (global) {
876 var unicode = this.unicode; 900 var unicode = TO_BOOLEAN(this.unicode);
877 this.lastIndex = 0; 901 this.lastIndex = 0;
878 } 902 }
903
904 // TODO(adamk): this fast path is wrong with respect to this.global
905 // and this.sticky, but hopefully the spec will remove those gets
906 // and thus make the assumption of 'exec' having no side-effects
907 // more correct. Also, we doesn't ensure that 'exec' is actually
908 // a data property on RegExp.prototype, nor does the fast path
909 // correctly handle lastIndex setting.
910 var exec;
911 if (IS_REGEXP(this)) {
912 exec = this.exec;
913 if (exec === RegExpSubclassExecJS) {
914 return %_Call(RegExpReplace, this, string, replace);
915 }
916 }
917
879 var results = new InternalArray(); 918 var results = new InternalArray();
880 var result, replacement; 919 var result, replacement;
881 while (true) { 920 while (true) {
882 result = RegExpSubclassExec(this, string); 921 result = RegExpSubclassExec(this, string, exec);
922 // Ensure exec will be read again on the next loop through.
923 exec = UNDEFINED;
883 if (IS_NULL(result)) { 924 if (IS_NULL(result)) {
884 break; 925 break;
885 } else { 926 } else {
886 results.push(result); 927 results.push(result);
887 if (!global) break; 928 if (!global) break;
888 var matchStr = TO_STRING(result[0]); 929 var matchStr = TO_STRING(result[0]);
889 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); 930 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode);
890 } 931 }
891 } 932 }
892 var accumulatedResult = ""; 933 var accumulatedResult = "";
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 // ES6 21.2.5.4. 1080 // ES6 21.2.5.4.
1040 function RegExpGetGlobal() { 1081 function RegExpGetGlobal() {
1041 if (!IS_REGEXP(this)) { 1082 if (!IS_REGEXP(this)) {
1042 // TODO(littledan): Remove this RegExp compat workaround 1083 // TODO(littledan): Remove this RegExp compat workaround
1043 if (this === GlobalRegExpPrototype) { 1084 if (this === GlobalRegExpPrototype) {
1044 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); 1085 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
1045 return UNDEFINED; 1086 return UNDEFINED;
1046 } 1087 }
1047 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global"); 1088 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global");
1048 } 1089 }
1049 return !!REGEXP_GLOBAL(this); 1090 return TO_BOOLEAN(REGEXP_GLOBAL(this));
1050 } 1091 }
1092 %SetForceInlineFlag(RegExpGetGlobal);
1051 1093
1052 1094
1053 // ES6 21.2.5.5. 1095 // ES6 21.2.5.5.
1054 function RegExpGetIgnoreCase() { 1096 function RegExpGetIgnoreCase() {
1055 if (!IS_REGEXP(this)) { 1097 if (!IS_REGEXP(this)) {
1056 // TODO(littledan): Remove this RegExp compat workaround 1098 // TODO(littledan): Remove this RegExp compat workaround
1057 if (this === GlobalRegExpPrototype) { 1099 if (this === GlobalRegExpPrototype) {
1058 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); 1100 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
1059 return UNDEFINED; 1101 return UNDEFINED;
1060 } 1102 }
1061 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); 1103 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase");
1062 } 1104 }
1063 return !!REGEXP_IGNORE_CASE(this); 1105 return TO_BOOLEAN(REGEXP_IGNORE_CASE(this));
1064 } 1106 }
1065 1107
1066 1108
1067 // ES6 21.2.5.7. 1109 // ES6 21.2.5.7.
1068 function RegExpGetMultiline() { 1110 function RegExpGetMultiline() {
1069 if (!IS_REGEXP(this)) { 1111 if (!IS_REGEXP(this)) {
1070 // TODO(littledan): Remove this RegExp compat workaround 1112 // TODO(littledan): Remove this RegExp compat workaround
1071 if (this === GlobalRegExpPrototype) { 1113 if (this === GlobalRegExpPrototype) {
1072 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); 1114 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
1073 return UNDEFINED; 1115 return UNDEFINED;
1074 } 1116 }
1075 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline"); 1117 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline");
1076 } 1118 }
1077 return !!REGEXP_MULTILINE(this); 1119 return TO_BOOLEAN(REGEXP_MULTILINE(this));
1078 } 1120 }
1079 1121
1080 1122
1081 // ES6 21.2.5.10. 1123 // ES6 21.2.5.10.
1082 function RegExpGetSource() { 1124 function RegExpGetSource() {
1083 if (!IS_REGEXP(this)) { 1125 if (!IS_REGEXP(this)) {
1084 // TODO(littledan): Remove this RegExp compat workaround 1126 // TODO(littledan): Remove this RegExp compat workaround
1085 if (this === GlobalRegExpPrototype) { 1127 if (this === GlobalRegExpPrototype) {
1086 %IncrementUseCounter(kRegExpPrototypeSourceGetter); 1128 %IncrementUseCounter(kRegExpPrototypeSourceGetter);
1087 return UNDEFINED; 1129 return UNDEFINED;
1088 } 1130 }
1089 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source"); 1131 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source");
1090 } 1132 }
1091 return REGEXP_SOURCE(this); 1133 return REGEXP_SOURCE(this);
1092 } 1134 }
1093 1135
1094 1136
1095 // ES6 21.2.5.12. 1137 // ES6 21.2.5.12.
1096 function RegExpGetSticky() { 1138 function RegExpGetSticky() {
1097 if (!IS_REGEXP(this)) { 1139 if (!IS_REGEXP(this)) {
1098 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it 1140 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
1099 // TODO(littledan): Remove this workaround or standardize it 1141 // TODO(littledan): Remove this workaround or standardize it
1100 if (this === GlobalRegExpPrototype) { 1142 if (this === GlobalRegExpPrototype) {
1101 %IncrementUseCounter(kRegExpPrototypeStickyGetter); 1143 %IncrementUseCounter(kRegExpPrototypeStickyGetter);
1102 return UNDEFINED; 1144 return UNDEFINED;
1103 } 1145 }
1104 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky"); 1146 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky");
1105 } 1147 }
1106 return !!REGEXP_STICKY(this); 1148 return TO_BOOLEAN(REGEXP_STICKY(this));
1107 } 1149 }
1150 %SetForceInlineFlag(RegExpGetSticky);
1108 1151
1109 // ------------------------------------------------------------------- 1152 // -------------------------------------------------------------------
1110 1153
1111 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); 1154 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
1112 GlobalRegExpPrototype = new GlobalObject(); 1155 GlobalRegExpPrototype = new GlobalObject();
1113 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype); 1156 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype);
1114 %AddNamedProperty( 1157 %AddNamedProperty(
1115 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); 1158 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
1116 %SetCode(GlobalRegExp, RegExpConstructor); 1159 %SetCode(GlobalRegExp, RegExpConstructor);
1117 1160
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1188 to.RegExpSubclassMatch = RegExpSubclassMatch; 1231 to.RegExpSubclassMatch = RegExpSubclassMatch;
1189 to.RegExpSubclassReplace = RegExpSubclassReplace; 1232 to.RegExpSubclassReplace = RegExpSubclassReplace;
1190 to.RegExpSubclassSearch = RegExpSubclassSearch; 1233 to.RegExpSubclassSearch = RegExpSubclassSearch;
1191 to.RegExpSubclassSplit = RegExpSubclassSplit; 1234 to.RegExpSubclassSplit = RegExpSubclassSplit;
1192 to.RegExpSubclassTest = RegExpSubclassTest; 1235 to.RegExpSubclassTest = RegExpSubclassTest;
1193 to.RegExpTest = RegExpTest; 1236 to.RegExpTest = RegExpTest;
1194 to.IsRegExp = IsRegExp; 1237 to.IsRegExp = IsRegExp;
1195 }); 1238 });
1196 1239
1197 }) 1240 })
OLDNEW
« no previous file with comments | « src/js/harmony-unicode-regexps.js ('k') | test/test262/test262.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698