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