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

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: Added TO_BOOLEAN and more comments 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 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
844 var first = %_StringCharCodeAt(string, index); 868 var first = %_StringCharCodeAt(string, index);
845 if (first >= 0xD800 && first <= 0xDBFF && string.length > index + 1) { 869 if (first >= 0xD800 && first <= 0xDBFF && string.length > index + 1) {
846 var second = %_StringCharCodeAt(string, index + 1); 870 var second = %_StringCharCodeAt(string, index + 1);
847 if (second >= 0xDC00 && second <= 0xDFFF) { 871 if (second >= 0xDC00 && second <= 0xDFFF) {
848 increment = 2; 872 increment = 2;
849 } 873 }
850 } 874 }
851 } 875 }
852 return increment; 876 return increment;
853 } 877 }
878 %SetForceInlineFlag(AdvanceStringIndex);
854 879
855 880
856 function SetAdvancedStringIndex(regexp, string, unicode) { 881 function SetAdvancedStringIndex(regexp, string, unicode) {
857 var lastIndex = regexp.lastIndex; 882 var lastIndex = regexp.lastIndex;
858 regexp.lastIndex = lastIndex + 883 regexp.lastIndex = lastIndex +
859 AdvanceStringIndex(string, lastIndex, unicode); 884 AdvanceStringIndex(string, lastIndex, unicode);
860 } 885 }
886 %SetForceInlineFlag(SetAdvancedStringIndex);
Yang 2016/03/29 12:19:04 I see this is only used as a helper. Can we write
adamk 2016/03/29 20:19:20 For this patch, it turns out we don't need this st
861 887
862 888
863 // ES#sec-regexp.prototype-@@replace 889 // ES#sec-regexp.prototype-@@replace
864 // RegExp.prototype [ @@replace ] ( string, replaceValue ) 890 // RegExp.prototype [ @@replace ] ( string, replaceValue )
865 function RegExpSubclassReplace(string, replace) { 891 function RegExpSubclassReplace(string, replace) {
866 if (!IS_RECEIVER(this)) { 892 if (!IS_RECEIVER(this)) {
867 throw MakeTypeError(kIncompatibleMethodReceiver, 893 throw MakeTypeError(kIncompatibleMethodReceiver,
868 "RegExp.prototype.@@replace", this); 894 "RegExp.prototype.@@replace", this);
869 } 895 }
870 string = TO_STRING(string); 896 string = TO_STRING(string);
871 var length = string.length; 897 var length = string.length;
872 var functionalReplace = IS_CALLABLE(replace); 898 var functionalReplace = IS_CALLABLE(replace);
873 if (!functionalReplace) replace = TO_STRING(replace); 899 if (!functionalReplace) replace = TO_STRING(replace);
874 var global = this.global; 900 var global = TO_BOOLEAN(this.global);
875 if (global) { 901 if (global) {
876 var unicode = this.unicode; 902 var unicode = TO_BOOLEAN(this.unicode);
877 this.lastIndex = 0; 903 this.lastIndex = 0;
878 } 904 }
905
906 // TODO(adamk): this fast path is wrong with respect to this.global
907 // and this.sticky, but hopefully the spec will remove those gets
908 // and thus make the assumption of 'exec' having no side-effects
909 // more correct. Also, we doesn't ensure that 'exec' is actually
910 // a data property on RegExp.prototype, nor does the fast path
911 // correctly handle lastIndex setting.
912 var exec;
913 if (IS_REGEXP(this)) {
914 exec = this.exec;
915 if (exec === RegExpSubclassExecJS) {
916 return %_Call(RegExpReplace, this, string, replace);
917 }
918 }
919
879 var results = new InternalArray(); 920 var results = new InternalArray();
880 var result, replacement; 921 var result, replacement;
881 while (true) { 922 while (true) {
882 result = RegExpSubclassExec(this, string); 923 result = RegExpSubclassExec(this, string, exec);
924 // Ensure exec will be read again on the next loop through.
925 exec = UNDEFINED;
883 if (IS_NULL(result)) { 926 if (IS_NULL(result)) {
884 break; 927 break;
885 } else { 928 } else {
886 results.push(result); 929 results.push(result);
887 if (!global) break; 930 if (!global) break;
888 var matchStr = TO_STRING(result[0]); 931 var matchStr = TO_STRING(result[0]);
889 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); 932 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode);
890 } 933 }
891 } 934 }
892 var accumulatedResult = ""; 935 var accumulatedResult = "";
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1027 kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this)); 1070 kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this));
1028 } 1071 }
1029 var result = ''; 1072 var result = '';
1030 if (this.global) result += 'g'; 1073 if (this.global) result += 'g';
1031 if (this.ignoreCase) result += 'i'; 1074 if (this.ignoreCase) result += 'i';
1032 if (this.multiline) result += 'm'; 1075 if (this.multiline) result += 'm';
1033 if (this.unicode) result += 'u'; 1076 if (this.unicode) result += 'u';
1034 if (this.sticky) result += 'y'; 1077 if (this.sticky) result += 'y';
1035 return result; 1078 return result;
1036 } 1079 }
1080 %SetForceInlineFlag(RegExpGetFlags);
Yang 2016/03/29 12:19:04 I can see the need for individual flag getters bel
adamk 2016/03/29 20:19:20 No, flags barely shows up on the profile, these go
1037 1081
1038 1082
1039 // ES6 21.2.5.4. 1083 // ES6 21.2.5.4.
1040 function RegExpGetGlobal() { 1084 function RegExpGetGlobal() {
1041 if (!IS_REGEXP(this)) { 1085 if (!IS_REGEXP(this)) {
1042 // TODO(littledan): Remove this RegExp compat workaround 1086 // TODO(littledan): Remove this RegExp compat workaround
1043 if (this === GlobalRegExpPrototype) { 1087 if (this === GlobalRegExpPrototype) {
1044 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); 1088 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
1045 return UNDEFINED; 1089 return UNDEFINED;
1046 } 1090 }
1047 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global"); 1091 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global");
1048 } 1092 }
1049 return !!REGEXP_GLOBAL(this); 1093 return TO_BOOLEAN(REGEXP_GLOBAL(this));
1050 } 1094 }
1095 %SetForceInlineFlag(RegExpGetGlobal);
1051 1096
1052 1097
1053 // ES6 21.2.5.5. 1098 // ES6 21.2.5.5.
1054 function RegExpGetIgnoreCase() { 1099 function RegExpGetIgnoreCase() {
1055 if (!IS_REGEXP(this)) { 1100 if (!IS_REGEXP(this)) {
1056 // TODO(littledan): Remove this RegExp compat workaround 1101 // TODO(littledan): Remove this RegExp compat workaround
1057 if (this === GlobalRegExpPrototype) { 1102 if (this === GlobalRegExpPrototype) {
1058 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); 1103 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
1059 return UNDEFINED; 1104 return UNDEFINED;
1060 } 1105 }
1061 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); 1106 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase");
1062 } 1107 }
1063 return !!REGEXP_IGNORE_CASE(this); 1108 return TO_BOOLEAN(REGEXP_IGNORE_CASE(this));
1064 } 1109 }
1110 %SetForceInlineFlag(RegExpGetIgnoreCase);
1065 1111
1066 1112
1067 // ES6 21.2.5.7. 1113 // ES6 21.2.5.7.
1068 function RegExpGetMultiline() { 1114 function RegExpGetMultiline() {
1069 if (!IS_REGEXP(this)) { 1115 if (!IS_REGEXP(this)) {
1070 // TODO(littledan): Remove this RegExp compat workaround 1116 // TODO(littledan): Remove this RegExp compat workaround
1071 if (this === GlobalRegExpPrototype) { 1117 if (this === GlobalRegExpPrototype) {
1072 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); 1118 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
1073 return UNDEFINED; 1119 return UNDEFINED;
1074 } 1120 }
1075 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline"); 1121 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline");
1076 } 1122 }
1077 return !!REGEXP_MULTILINE(this); 1123 return TO_BOOLEAN(REGEXP_MULTILINE(this));
1078 } 1124 }
1125 %SetForceInlineFlag(RegExpGetMultiline);
Yang 2016/03/29 12:19:04 Is this only for symmetry? I don't think any of th
adamk 2016/03/29 20:19:20 Removed, as noted. The only getters that still hav
1079 1126
1080 1127
1081 // ES6 21.2.5.10. 1128 // ES6 21.2.5.10.
1082 function RegExpGetSource() { 1129 function RegExpGetSource() {
1083 if (!IS_REGEXP(this)) { 1130 if (!IS_REGEXP(this)) {
1084 // TODO(littledan): Remove this RegExp compat workaround 1131 // TODO(littledan): Remove this RegExp compat workaround
1085 if (this === GlobalRegExpPrototype) { 1132 if (this === GlobalRegExpPrototype) {
1086 %IncrementUseCounter(kRegExpPrototypeSourceGetter); 1133 %IncrementUseCounter(kRegExpPrototypeSourceGetter);
1087 return UNDEFINED; 1134 return UNDEFINED;
1088 } 1135 }
1089 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source"); 1136 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source");
1090 } 1137 }
1091 return REGEXP_SOURCE(this); 1138 return REGEXP_SOURCE(this);
1092 } 1139 }
1093 1140
1094 1141
1095 // ES6 21.2.5.12. 1142 // ES6 21.2.5.12.
1096 function RegExpGetSticky() { 1143 function RegExpGetSticky() {
1097 if (!IS_REGEXP(this)) { 1144 if (!IS_REGEXP(this)) {
1098 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it 1145 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
1099 // TODO(littledan): Remove this workaround or standardize it 1146 // TODO(littledan): Remove this workaround or standardize it
1100 if (this === GlobalRegExpPrototype) { 1147 if (this === GlobalRegExpPrototype) {
1101 %IncrementUseCounter(kRegExpPrototypeStickyGetter); 1148 %IncrementUseCounter(kRegExpPrototypeStickyGetter);
1102 return UNDEFINED; 1149 return UNDEFINED;
1103 } 1150 }
1104 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky"); 1151 throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky");
1105 } 1152 }
1106 return !!REGEXP_STICKY(this); 1153 return TO_BOOLEAN(REGEXP_STICKY(this));
1107 } 1154 }
1155 %SetForceInlineFlag(RegExpGetSticky);
1108 1156
1109 // ------------------------------------------------------------------- 1157 // -------------------------------------------------------------------
1110 1158
1111 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); 1159 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp');
1112 GlobalRegExpPrototype = new GlobalObject(); 1160 GlobalRegExpPrototype = new GlobalObject();
1113 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype); 1161 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype);
1114 %AddNamedProperty( 1162 %AddNamedProperty(
1115 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); 1163 GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM);
1116 %SetCode(GlobalRegExp, RegExpConstructor); 1164 %SetCode(GlobalRegExp, RegExpConstructor);
1117 1165
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1188 to.RegExpSubclassMatch = RegExpSubclassMatch; 1236 to.RegExpSubclassMatch = RegExpSubclassMatch;
1189 to.RegExpSubclassReplace = RegExpSubclassReplace; 1237 to.RegExpSubclassReplace = RegExpSubclassReplace;
1190 to.RegExpSubclassSearch = RegExpSubclassSearch; 1238 to.RegExpSubclassSearch = RegExpSubclassSearch;
1191 to.RegExpSubclassSplit = RegExpSubclassSplit; 1239 to.RegExpSubclassSplit = RegExpSubclassSplit;
1192 to.RegExpSubclassTest = RegExpSubclassTest; 1240 to.RegExpSubclassTest = RegExpSubclassTest;
1193 to.RegExpTest = RegExpTest; 1241 to.RegExpTest = RegExpTest;
1194 to.IsRegExp = IsRegExp; 1242 to.IsRegExp = IsRegExp;
1195 }); 1243 });
1196 1244
1197 }) 1245 })
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