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.h" | 7 #include "src/builtins/builtins-constructor.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 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 Node* const pending_exception = | 441 Node* const pending_exception = |
442 Load(MachineType::AnyTagged(), pending_exception_address); | 442 Load(MachineType::AnyTagged(), pending_exception_address); |
443 | 443 |
444 // If there is no pending exception, a | 444 // If there is no pending exception, a |
445 // stack overflow (on the backtrack stack) was detected in RegExp code. | 445 // stack overflow (on the backtrack stack) was detected in RegExp code. |
446 | 446 |
447 Label stack_overflow(this), rethrow(this); | 447 Label stack_overflow(this), rethrow(this); |
448 Branch(IsTheHole(pending_exception), &stack_overflow, &rethrow); | 448 Branch(IsTheHole(pending_exception), &stack_overflow, &rethrow); |
449 | 449 |
450 Bind(&stack_overflow); | 450 Bind(&stack_overflow); |
451 TailCallRuntime(Runtime::kThrowStackOverflow, context); | 451 CallRuntime(Runtime::kThrowStackOverflow, context); |
| 452 Unreachable(); |
452 | 453 |
453 Bind(&rethrow); | 454 Bind(&rethrow); |
454 TailCallRuntime(Runtime::kRegExpExecReThrow, context); | 455 CallRuntime(Runtime::kRegExpExecReThrow, context); |
| 456 Unreachable(); |
455 } | 457 } |
456 | 458 |
457 Bind(&runtime); | 459 Bind(&runtime); |
458 { | 460 { |
459 Node* const result = CallRuntime(Runtime::kRegExpExec, context, regexp, | 461 Node* const result = CallRuntime(Runtime::kRegExpExec, context, regexp, |
460 string, last_index, match_info); | 462 string, last_index, match_info); |
461 var_result.Bind(result); | 463 var_result.Bind(result); |
462 Goto(&out); | 464 Goto(&out); |
463 } | 465 } |
464 | 466 |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 Label* if_isunmodified, | 721 Label* if_isunmodified, |
720 Label* if_ismodified) { | 722 Label* if_ismodified) { |
721 Node* const native_context = LoadNativeContext(context); | 723 Node* const native_context = LoadNativeContext(context); |
722 Node* const initial_regexp_result_map = | 724 Node* const initial_regexp_result_map = |
723 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 725 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
724 | 726 |
725 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified, | 727 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified, |
726 if_ismodified); | 728 if_ismodified); |
727 } | 729 } |
728 | 730 |
| 731 // Slow path stub for RegExpPrototypeExec to decrease code size. |
| 732 TF_BUILTIN(RegExpPrototypeExecSlow, RegExpBuiltinsAssembler) { |
| 733 typedef RegExpPrototypeExecSlowDescriptor Descriptor; |
| 734 |
| 735 Node* const regexp = Parameter(Descriptor::kReceiver); |
| 736 Node* const string = Parameter(Descriptor::kString); |
| 737 Node* const context = Parameter(Descriptor::kContext); |
| 738 |
| 739 Return(RegExpPrototypeExecBody(context, regexp, string, false)); |
| 740 } |
| 741 |
729 // ES#sec-regexp.prototype.exec | 742 // ES#sec-regexp.prototype.exec |
730 // RegExp.prototype.exec ( string ) | 743 // RegExp.prototype.exec ( string ) |
731 TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { | 744 TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { |
732 Node* const maybe_receiver = Parameter(0); | 745 Node* const maybe_receiver = Parameter(0); |
733 Node* const maybe_string = Parameter(1); | 746 Node* const maybe_string = Parameter(1); |
734 Node* const context = Parameter(4); | 747 Node* const context = Parameter(4); |
735 | 748 |
736 // Ensure {maybe_receiver} is a JSRegExp. | 749 // Ensure {maybe_receiver} is a JSRegExp. |
737 Node* const regexp_map = ThrowIfNotInstanceType( | 750 Node* const regexp_map = ThrowIfNotInstanceType( |
738 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | 751 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); |
739 Node* const receiver = maybe_receiver; | 752 Node* const receiver = maybe_receiver; |
740 | 753 |
741 // Convert {maybe_string} to a String. | 754 // Convert {maybe_string} to a String. |
742 Node* const string = ToString(context, maybe_string); | 755 Node* const string = ToString(context, maybe_string); |
743 | 756 |
744 Label if_isfastpath(this), if_isslowpath(this); | 757 Label if_isfastpath(this), if_isslowpath(this); |
745 Branch(IsInitialRegExpMap(context, regexp_map), &if_isfastpath, | 758 Branch(IsInitialRegExpMap(context, regexp_map), &if_isfastpath, |
746 &if_isslowpath); | 759 &if_isslowpath); |
747 | 760 |
748 Bind(&if_isfastpath); | 761 Bind(&if_isfastpath); |
749 { | 762 { |
750 Node* const result = | 763 Node* const result = |
751 RegExpPrototypeExecBody(context, receiver, string, true); | 764 RegExpPrototypeExecBody(context, receiver, string, true); |
752 Return(result); | 765 Return(result); |
753 } | 766 } |
754 | 767 |
755 Bind(&if_isslowpath); | 768 Bind(&if_isslowpath); |
756 { | 769 { |
757 Node* const result = | 770 Node* const result = CallBuiltin(Builtins::kRegExpPrototypeExecSlow, |
758 RegExpPrototypeExecBody(context, receiver, string, false); | 771 context, receiver, string); |
759 Return(result); | 772 Return(result); |
760 } | 773 } |
761 } | 774 } |
762 | 775 |
763 Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context, | 776 Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context, |
764 Node* const regexp, | 777 Node* const regexp, |
765 bool is_fastpath) { | 778 bool is_fastpath) { |
766 Isolate* isolate = this->isolate(); | 779 Isolate* isolate = this->isolate(); |
767 | 780 |
768 Node* const int_zero = IntPtrConstant(0); | 781 Node* const int_zero = IntPtrConstant(0); |
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1323 | 1336 |
1324 // ES6 21.2.5.15. | 1337 // ES6 21.2.5.15. |
1325 TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) { | 1338 TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) { |
1326 FlagGetter(JSRegExp::kUnicode, v8::Isolate::kRegExpPrototypeUnicodeGetter, | 1339 FlagGetter(JSRegExp::kUnicode, v8::Isolate::kRegExpPrototypeUnicodeGetter, |
1327 "RegExp.prototype.unicode"); | 1340 "RegExp.prototype.unicode"); |
1328 } | 1341 } |
1329 | 1342 |
1330 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1343 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
1331 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, | 1344 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, |
1332 Node* string) { | 1345 Node* string) { |
1333 Isolate* isolate = this->isolate(); | 1346 CSA_ASSERT(this, Word32BinaryNot(IsFastRegExpMap(context, LoadMap(regexp)))); |
1334 | |
1335 Node* const null = NullConstant(); | |
1336 | 1347 |
1337 Variable var_result(this, MachineRepresentation::kTagged); | 1348 Variable var_result(this, MachineRepresentation::kTagged); |
1338 Label out(this), if_isfastpath(this), if_isslowpath(this); | 1349 Label out(this); |
1339 | 1350 |
1340 Node* const map = LoadMap(regexp); | 1351 // Take the slow path of fetching the exec property, calling it, and |
1341 BranchIfFastRegExp(context, map, &if_isfastpath, &if_isslowpath); | 1352 // verifying its return value. |
1342 | 1353 |
1343 Bind(&if_isfastpath); | 1354 // Get the exec property. |
| 1355 Node* const exec = |
| 1356 GetProperty(context, regexp, isolate()->factory()->exec_string()); |
| 1357 |
| 1358 // Is {exec} callable? |
| 1359 Label if_iscallable(this), if_isnotcallable(this); |
| 1360 |
| 1361 GotoIf(TaggedIsSmi(exec), &if_isnotcallable); |
| 1362 |
| 1363 Node* const exec_map = LoadMap(exec); |
| 1364 Branch(IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); |
| 1365 |
| 1366 Bind(&if_iscallable); |
1344 { | 1367 { |
1345 Node* const result = RegExpPrototypeExecBody(context, regexp, string, true); | 1368 Callable call_callable = CodeFactory::Call(isolate()); |
| 1369 Node* const result = CallJS(call_callable, context, exec, regexp, string); |
| 1370 |
| 1371 var_result.Bind(result); |
| 1372 GotoIf(WordEqual(result, NullConstant()), &out); |
| 1373 |
| 1374 ThrowIfNotJSReceiver(context, result, |
| 1375 MessageTemplate::kInvalidRegExpExecResult, "unused"); |
| 1376 |
| 1377 Goto(&out); |
| 1378 } |
| 1379 |
| 1380 Bind(&if_isnotcallable); |
| 1381 { |
| 1382 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
| 1383 "RegExp.prototype.exec"); |
| 1384 |
| 1385 Node* const result = CallBuiltin(Builtins::kRegExpPrototypeExecSlow, |
| 1386 context, regexp, string); |
1346 var_result.Bind(result); | 1387 var_result.Bind(result); |
1347 Goto(&out); | 1388 Goto(&out); |
1348 } | 1389 } |
1349 | 1390 |
1350 Bind(&if_isslowpath); | |
1351 { | |
1352 // Take the slow path of fetching the exec property, calling it, and | |
1353 // verifying its return value. | |
1354 | |
1355 // Get the exec property. | |
1356 Node* const exec = | |
1357 GetProperty(context, regexp, isolate->factory()->exec_string()); | |
1358 | |
1359 // Is {exec} callable? | |
1360 Label if_iscallable(this), if_isnotcallable(this); | |
1361 | |
1362 GotoIf(TaggedIsSmi(exec), &if_isnotcallable); | |
1363 | |
1364 Node* const exec_map = LoadMap(exec); | |
1365 Branch(IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); | |
1366 | |
1367 Bind(&if_iscallable); | |
1368 { | |
1369 Callable call_callable = CodeFactory::Call(isolate); | |
1370 Node* const result = CallJS(call_callable, context, exec, regexp, string); | |
1371 | |
1372 var_result.Bind(result); | |
1373 GotoIf(WordEqual(result, null), &out); | |
1374 | |
1375 ThrowIfNotJSReceiver(context, result, | |
1376 MessageTemplate::kInvalidRegExpExecResult, "unused"); | |
1377 | |
1378 Goto(&out); | |
1379 } | |
1380 | |
1381 Bind(&if_isnotcallable); | |
1382 { | |
1383 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | |
1384 "RegExp.prototype.exec"); | |
1385 | |
1386 Node* const result = | |
1387 RegExpPrototypeExecBody(context, regexp, string, false); | |
1388 var_result.Bind(result); | |
1389 Goto(&out); | |
1390 } | |
1391 } | |
1392 | |
1393 Bind(&out); | 1391 Bind(&out); |
1394 return var_result.value(); | 1392 return var_result.value(); |
1395 } | 1393 } |
1396 | 1394 |
1397 // ES#sec-regexp.prototype.test | 1395 // ES#sec-regexp.prototype.test |
1398 // RegExp.prototype.test ( S ) | 1396 // RegExp.prototype.test ( S ) |
1399 TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { | 1397 TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { |
1400 Node* const maybe_receiver = Parameter(0); | 1398 Node* const maybe_receiver = Parameter(0); |
1401 Node* const maybe_string = Parameter(1); | 1399 Node* const maybe_string = Parameter(1); |
1402 Node* const context = Parameter(4); | 1400 Node* const context = Parameter(4); |
(...skipping 1266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2669 Bind(&if_matched); | 2667 Bind(&if_matched); |
2670 { | 2668 { |
2671 Node* result = | 2669 Node* result = |
2672 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2670 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2673 Return(result); | 2671 Return(result); |
2674 } | 2672 } |
2675 } | 2673 } |
2676 | 2674 |
2677 } // namespace internal | 2675 } // namespace internal |
2678 } // namespace v8 | 2676 } // namespace v8 |
OLD | NEW |