OLD | NEW |
1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 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 #include "src/builtins/builtins-regexp-gen.h" | 5 #include "src/builtins/builtins-regexp-gen.h" |
6 | 6 |
7 #include "src/builtins/builtins-constructor-gen.h" | 7 #include "src/builtins/builtins-constructor-gen.h" |
8 #include "src/builtins/builtins-utils-gen.h" | 8 #include "src/builtins/builtins-utils-gen.h" |
9 #include "src/builtins/builtins.h" | 9 #include "src/builtins/builtins.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context, | 774 Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context, |
775 Node* const regexp, | 775 Node* const regexp, |
776 bool is_fastpath) { | 776 bool is_fastpath) { |
777 Isolate* isolate = this->isolate(); | 777 Isolate* isolate = this->isolate(); |
778 | 778 |
779 Node* const int_zero = IntPtrConstant(0); | 779 Node* const int_zero = IntPtrConstant(0); |
780 Node* const int_one = IntPtrConstant(1); | 780 Node* const int_one = IntPtrConstant(1); |
781 Variable var_length(this, MachineType::PointerRepresentation(), int_zero); | 781 Variable var_length(this, MachineType::PointerRepresentation(), int_zero); |
782 Variable var_flags(this, MachineType::PointerRepresentation()); | 782 Variable var_flags(this, MachineType::PointerRepresentation()); |
783 | 783 |
| 784 Node* const is_dotall_enabled = IsDotAllEnabled(isolate); |
| 785 |
784 // First, count the number of characters we will need and check which flags | 786 // First, count the number of characters we will need and check which flags |
785 // are set. | 787 // are set. |
786 | 788 |
787 if (is_fastpath) { | 789 if (is_fastpath) { |
788 // Refer to JSRegExp's flag property on the fast-path. | 790 // Refer to JSRegExp's flag property on the fast-path. |
789 Node* const flags_smi = LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 791 Node* const flags_smi = LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
790 Node* const flags_intptr = SmiUntag(flags_smi); | 792 Node* const flags_intptr = SmiUntag(flags_smi); |
791 var_flags.Bind(flags_intptr); | 793 var_flags.Bind(flags_intptr); |
792 | 794 |
793 #define CASE_FOR_FLAG(FLAG) \ | 795 #define CASE_FOR_FLAG(FLAG) \ |
794 do { \ | 796 do { \ |
795 Label next(this); \ | 797 Label next(this); \ |
796 GotoIfNot(IsSetWord(flags_intptr, FLAG), &next); \ | 798 GotoIfNot(IsSetWord(flags_intptr, FLAG), &next); \ |
797 var_length.Bind(IntPtrAdd(var_length.value(), int_one)); \ | 799 var_length.Bind(IntPtrAdd(var_length.value(), int_one)); \ |
798 Goto(&next); \ | 800 Goto(&next); \ |
799 Bind(&next); \ | 801 Bind(&next); \ |
800 } while (false) | 802 } while (false) |
801 | 803 |
802 CASE_FOR_FLAG(JSRegExp::kGlobal); | 804 CASE_FOR_FLAG(JSRegExp::kGlobal); |
803 CASE_FOR_FLAG(JSRegExp::kIgnoreCase); | 805 CASE_FOR_FLAG(JSRegExp::kIgnoreCase); |
804 CASE_FOR_FLAG(JSRegExp::kMultiline); | 806 CASE_FOR_FLAG(JSRegExp::kMultiline); |
| 807 { |
| 808 Label next(this); |
| 809 GotoIfNot(is_dotall_enabled, &next); |
| 810 CASE_FOR_FLAG(JSRegExp::kDotAll); |
| 811 Goto(&next); |
| 812 Bind(&next); |
| 813 } |
805 CASE_FOR_FLAG(JSRegExp::kUnicode); | 814 CASE_FOR_FLAG(JSRegExp::kUnicode); |
806 CASE_FOR_FLAG(JSRegExp::kSticky); | 815 CASE_FOR_FLAG(JSRegExp::kSticky); |
807 #undef CASE_FOR_FLAG | 816 #undef CASE_FOR_FLAG |
808 } else { | 817 } else { |
809 DCHECK(!is_fastpath); | 818 DCHECK(!is_fastpath); |
810 | 819 |
811 // Fall back to GetProperty stub on the slow-path. | 820 // Fall back to GetProperty stub on the slow-path. |
812 var_flags.Bind(int_zero); | 821 var_flags.Bind(int_zero); |
813 | 822 |
814 #define CASE_FOR_FLAG(NAME, FLAG) \ | 823 #define CASE_FOR_FLAG(NAME, FLAG) \ |
815 do { \ | 824 do { \ |
816 Label next(this); \ | 825 Label next(this); \ |
817 Node* const flag = GetProperty( \ | 826 Node* const flag = GetProperty( \ |
818 context, regexp, isolate->factory()->InternalizeUtf8String(NAME)); \ | 827 context, regexp, isolate->factory()->InternalizeUtf8String(NAME)); \ |
819 Label if_isflagset(this); \ | 828 Label if_isflagset(this); \ |
820 BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \ | 829 BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \ |
821 Bind(&if_isflagset); \ | 830 Bind(&if_isflagset); \ |
822 var_length.Bind(IntPtrAdd(var_length.value(), int_one)); \ | 831 var_length.Bind(IntPtrAdd(var_length.value(), int_one)); \ |
823 var_flags.Bind(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \ | 832 var_flags.Bind(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \ |
824 Goto(&next); \ | 833 Goto(&next); \ |
825 Bind(&next); \ | 834 Bind(&next); \ |
826 } while (false) | 835 } while (false) |
827 | 836 |
828 CASE_FOR_FLAG("global", JSRegExp::kGlobal); | 837 CASE_FOR_FLAG("global", JSRegExp::kGlobal); |
829 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase); | 838 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase); |
830 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline); | 839 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline); |
| 840 { |
| 841 Label next(this); |
| 842 GotoIfNot(is_dotall_enabled, &next); |
| 843 CASE_FOR_FLAG("dotAll", JSRegExp::kDotAll); |
| 844 Goto(&next); |
| 845 Bind(&next); |
| 846 } |
831 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode); | 847 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode); |
832 CASE_FOR_FLAG("sticky", JSRegExp::kSticky); | 848 CASE_FOR_FLAG("sticky", JSRegExp::kSticky); |
833 #undef CASE_FOR_FLAG | 849 #undef CASE_FOR_FLAG |
834 } | 850 } |
835 | 851 |
836 // Allocate a string of the required length and fill it with the corresponding | 852 // Allocate a string of the required length and fill it with the corresponding |
837 // char for each set flag. | 853 // char for each set flag. |
838 | 854 |
839 { | 855 { |
840 Node* const result = AllocateSeqOneByteString(context, var_length.value()); | 856 Node* const result = AllocateSeqOneByteString(context, var_length.value()); |
(...skipping 11 matching lines...) Expand all Loading... |
852 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ | 868 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ |
853 var_offset.value(), value); \ | 869 var_offset.value(), value); \ |
854 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \ | 870 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \ |
855 Goto(&next); \ | 871 Goto(&next); \ |
856 Bind(&next); \ | 872 Bind(&next); \ |
857 } while (false) | 873 } while (false) |
858 | 874 |
859 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g'); | 875 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g'); |
860 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i'); | 876 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i'); |
861 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm'); | 877 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm'); |
| 878 { |
| 879 Label next(this); |
| 880 GotoIfNot(is_dotall_enabled, &next); |
| 881 CASE_FOR_FLAG(JSRegExp::kDotAll, 's'); |
| 882 Goto(&next); |
| 883 Bind(&next); |
| 884 } |
862 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u'); | 885 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u'); |
863 CASE_FOR_FLAG(JSRegExp::kSticky, 'y'); | 886 CASE_FOR_FLAG(JSRegExp::kSticky, 'y'); |
864 #undef CASE_FOR_FLAG | 887 #undef CASE_FOR_FLAG |
865 | 888 |
866 return result; | 889 return result; |
867 } | 890 } |
868 } | 891 } |
869 | 892 |
870 // ES#sec-isregexp IsRegExp ( argument ) | 893 // ES#sec-isregexp IsRegExp ( argument ) |
871 Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context, | 894 Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context, |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1204 switch (flag) { | 1227 switch (flag) { |
1205 case JSRegExp::kGlobal: | 1228 case JSRegExp::kGlobal: |
1206 name = factory->global_string(); | 1229 name = factory->global_string(); |
1207 break; | 1230 break; |
1208 case JSRegExp::kIgnoreCase: | 1231 case JSRegExp::kIgnoreCase: |
1209 name = factory->ignoreCase_string(); | 1232 name = factory->ignoreCase_string(); |
1210 break; | 1233 break; |
1211 case JSRegExp::kMultiline: | 1234 case JSRegExp::kMultiline: |
1212 name = factory->multiline_string(); | 1235 name = factory->multiline_string(); |
1213 break; | 1236 break; |
| 1237 case JSRegExp::kDotAll: |
| 1238 UNREACHABLE(); // Never called for dotAll. |
| 1239 break; |
1214 case JSRegExp::kSticky: | 1240 case JSRegExp::kSticky: |
1215 name = factory->sticky_string(); | 1241 name = factory->sticky_string(); |
1216 break; | 1242 break; |
1217 case JSRegExp::kUnicode: | 1243 case JSRegExp::kUnicode: |
1218 name = factory->unicode_string(); | 1244 name = factory->unicode_string(); |
1219 break; | 1245 break; |
1220 default: | 1246 default: |
1221 UNREACHABLE(); | 1247 UNREACHABLE(); |
1222 } | 1248 } |
1223 | 1249 |
(...skipping 20 matching lines...) Expand all Loading... |
1244 | 1270 |
1245 Node* RegExpBuiltinsAssembler::FlagGetter(Node* const context, | 1271 Node* RegExpBuiltinsAssembler::FlagGetter(Node* const context, |
1246 Node* const regexp, | 1272 Node* const regexp, |
1247 JSRegExp::Flag flag, | 1273 JSRegExp::Flag flag, |
1248 bool is_fastpath) { | 1274 bool is_fastpath) { |
1249 return is_fastpath ? FastFlagGetter(regexp, flag) | 1275 return is_fastpath ? FastFlagGetter(regexp, flag) |
1250 : SlowFlagGetter(context, regexp, flag); | 1276 : SlowFlagGetter(context, regexp, flag); |
1251 } | 1277 } |
1252 | 1278 |
1253 void RegExpBuiltinsAssembler::FlagGetter(Node* context, Node* receiver, | 1279 void RegExpBuiltinsAssembler::FlagGetter(Node* context, Node* receiver, |
1254 JSRegExp::Flag flag, | 1280 JSRegExp::Flag flag, int counter, |
1255 v8::Isolate::UseCounterFeature counter, | |
1256 const char* method_name) { | 1281 const char* method_name) { |
1257 Isolate* isolate = this->isolate(); | 1282 Isolate* isolate = this->isolate(); |
1258 | 1283 |
1259 // Check whether we have an unmodified regexp instance. | 1284 // Check whether we have an unmodified regexp instance. |
1260 Label if_isunmodifiedjsregexp(this), | 1285 Label if_isunmodifiedjsregexp(this), |
1261 if_isnotunmodifiedjsregexp(this, Label::kDeferred); | 1286 if_isnotunmodifiedjsregexp(this, Label::kDeferred); |
1262 | 1287 |
1263 GotoIf(TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); | 1288 GotoIf(TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); |
1264 | 1289 |
1265 Node* const receiver_map = LoadMap(receiver); | 1290 Node* const receiver_map = LoadMap(receiver); |
(...skipping 17 matching lines...) Expand all Loading... |
1283 Node* const initial_map = | 1308 Node* const initial_map = |
1284 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 1309 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
1285 Node* const initial_prototype = LoadMapPrototype(initial_map); | 1310 Node* const initial_prototype = LoadMapPrototype(initial_map); |
1286 | 1311 |
1287 Label if_isprototype(this), if_isnotprototype(this); | 1312 Label if_isprototype(this), if_isnotprototype(this); |
1288 Branch(WordEqual(receiver, initial_prototype), &if_isprototype, | 1313 Branch(WordEqual(receiver, initial_prototype), &if_isprototype, |
1289 &if_isnotprototype); | 1314 &if_isnotprototype); |
1290 | 1315 |
1291 Bind(&if_isprototype); | 1316 Bind(&if_isprototype); |
1292 { | 1317 { |
1293 Node* const counter_smi = SmiConstant(Smi::FromInt(counter)); | 1318 if (counter != -1) { |
1294 CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); | 1319 Node* const counter_smi = SmiConstant(Smi::FromInt(counter)); |
| 1320 CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); |
| 1321 } |
1295 Return(UndefinedConstant()); | 1322 Return(UndefinedConstant()); |
1296 } | 1323 } |
1297 | 1324 |
1298 Bind(&if_isnotprototype); | 1325 Bind(&if_isnotprototype); |
1299 { | 1326 { |
1300 Node* const message_id = | 1327 Node* const message_id = |
1301 SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); | 1328 SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); |
1302 Node* const method_name_str = HeapConstant( | 1329 Node* const method_name_str = HeapConstant( |
1303 isolate->factory()->NewStringFromAsciiChecked(method_name)); | 1330 isolate->factory()->NewStringFromAsciiChecked(method_name)); |
1304 CallRuntime(Runtime::kThrowTypeError, context, message_id, | 1331 CallRuntime(Runtime::kThrowTypeError, context, message_id, |
(...skipping 26 matching lines...) Expand all Loading... |
1331 // ES6 21.2.5.7. | 1358 // ES6 21.2.5.7. |
1332 // ES #sec-get-regexp.prototype.multiline | 1359 // ES #sec-get-regexp.prototype.multiline |
1333 TF_BUILTIN(RegExpPrototypeMultilineGetter, RegExpBuiltinsAssembler) { | 1360 TF_BUILTIN(RegExpPrototypeMultilineGetter, RegExpBuiltinsAssembler) { |
1334 Node* context = Parameter(Descriptor::kContext); | 1361 Node* context = Parameter(Descriptor::kContext); |
1335 Node* receiver = Parameter(Descriptor::kReceiver); | 1362 Node* receiver = Parameter(Descriptor::kReceiver); |
1336 FlagGetter(context, receiver, JSRegExp::kMultiline, | 1363 FlagGetter(context, receiver, JSRegExp::kMultiline, |
1337 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 1364 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
1338 "RegExp.prototype.multiline"); | 1365 "RegExp.prototype.multiline"); |
1339 } | 1366 } |
1340 | 1367 |
| 1368 Node* RegExpBuiltinsAssembler::IsDotAllEnabled(Isolate* isolate) { |
| 1369 Node* flag_ptr = ExternalConstant( |
| 1370 ExternalReference::address_of_regexp_dotall_flag(isolate)); |
| 1371 Node* flag_value = Load(MachineType::IntPtr(), flag_ptr); |
| 1372 return WordNotEqual(flag_value, IntPtrConstant(0)); |
| 1373 } |
| 1374 |
| 1375 // ES #sec-get-regexp.prototype.dotAll |
| 1376 TF_BUILTIN(RegExpPrototypeDotAllGetter, RegExpBuiltinsAssembler) { |
| 1377 Node* context = Parameter(Descriptor::kContext); |
| 1378 Node* receiver = Parameter(Descriptor::kReceiver); |
| 1379 static const int kNoCounter = -1; |
| 1380 CSA_ASSERT(this, IsDotAllEnabled(isolate())); |
| 1381 FlagGetter(context, receiver, JSRegExp::kDotAll, kNoCounter, |
| 1382 "RegExp.prototype.dotAll"); |
| 1383 } |
| 1384 |
1341 // ES6 21.2.5.12. | 1385 // ES6 21.2.5.12. |
1342 // ES #sec-get-regexp.prototype.sticky | 1386 // ES #sec-get-regexp.prototype.sticky |
1343 TF_BUILTIN(RegExpPrototypeStickyGetter, RegExpBuiltinsAssembler) { | 1387 TF_BUILTIN(RegExpPrototypeStickyGetter, RegExpBuiltinsAssembler) { |
1344 Node* context = Parameter(Descriptor::kContext); | 1388 Node* context = Parameter(Descriptor::kContext); |
1345 Node* receiver = Parameter(Descriptor::kReceiver); | 1389 Node* receiver = Parameter(Descriptor::kReceiver); |
1346 FlagGetter(context, receiver, JSRegExp::kSticky, | 1390 FlagGetter(context, receiver, JSRegExp::kSticky, |
1347 v8::Isolate::kRegExpPrototypeStickyGetter, | 1391 v8::Isolate::kRegExpPrototypeStickyGetter, |
1348 "RegExp.prototype.sticky"); | 1392 "RegExp.prototype.sticky"); |
1349 } | 1393 } |
1350 | 1394 |
(...skipping 1330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2681 Bind(&if_matched); | 2725 Bind(&if_matched); |
2682 { | 2726 { |
2683 Node* result = | 2727 Node* result = |
2684 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2728 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2685 Return(result); | 2729 Return(result); |
2686 } | 2730 } |
2687 } | 2731 } |
2688 | 2732 |
2689 } // namespace internal | 2733 } // namespace internal |
2690 } // namespace v8 | 2734 } // namespace v8 |
OLD | NEW |