| 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 |