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

Side by Side Diff: src/code-stubs.cc

Issue 1759133002: [compiler] Initial TurboFan code stubs for abstract relational comparison. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 9 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/code-stubs.h ('k') | src/compiler/code-stub-assembler.h » ('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 #include "src/code-stubs.h" 5 #include "src/code-stubs.h"
6 6
7 #include <sstream> 7 #include <sstream>
8 8
9 #include "src/bootstrapper.h" 9 #include "src/bootstrapper.h"
10 #include "src/code-factory.h" 10 #include "src/code-factory.h"
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 compiler::Node* value = assembler->Parameter(0); 494 compiler::Node* value = assembler->Parameter(0);
495 compiler::Node* string = 495 compiler::Node* string =
496 assembler->LoadObjectField(value, JSValue::kValueOffset); 496 assembler->LoadObjectField(value, JSValue::kValueOffset);
497 compiler::Node* result = 497 compiler::Node* result =
498 assembler->LoadObjectField(string, String::kLengthOffset); 498 assembler->LoadObjectField(string, String::kLengthOffset);
499 assembler->Return(result); 499 assembler->Return(result);
500 } 500 }
501 501
502 namespace { 502 namespace {
503 503
504 enum AbstractRelationalComparisonMode {
505 kLessThan,
506 kLessThanOrEqual,
507 kGreaterThan,
508 kGreaterThanOrEqual
509 };
510
511 void GenerateAbstractRelationalComparison(
512 compiler::CodeStubAssembler* assembler,
513 AbstractRelationalComparisonMode mode) {
514 typedef compiler::CodeStubAssembler::Label Label;
515 typedef compiler::Node Node;
516 typedef compiler::CodeStubAssembler::Variable Variable;
517
518 Node* context = assembler->Parameter(2);
519
520 Label return_true(assembler), return_false(assembler);
521
522 // Shared entry for floating point comparison.
523 Label do_fcmp(assembler);
524 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
525 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
526
527 // We might need to loop several times due to ToPrimitive and/or ToNumber
528 // conversions.
529 Variable var_lhs(assembler, MachineRepresentation::kTagged),
530 var_rhs(assembler, MachineRepresentation::kTagged);
531 Variable* loop_vars[2] = {&var_lhs, &var_rhs};
532 Label loop(assembler, 2, loop_vars);
533 var_lhs.Bind(assembler->Parameter(0));
534 var_rhs.Bind(assembler->Parameter(1));
535 assembler->Goto(&loop);
536 assembler->Bind(&loop);
537 {
538 // Load the current {lhs} and {rhs} values.
539 Node* lhs = var_lhs.value();
540 Node* rhs = var_rhs.value();
541
542 // Check if the {lhs} is a Smi or a HeapObject.
543 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
544 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
545
546 assembler->Bind(&if_lhsissmi);
547 {
548 // Check if {rhs} is a Smi or a HeapObject.
549 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
550 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
551 &if_rhsisnotsmi);
552
553 assembler->Bind(&if_rhsissmi);
554 {
555 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
556 switch (mode) {
557 case kLessThan:
558 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true,
559 &return_false);
560 break;
561 case kLessThanOrEqual:
562 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true,
563 &return_false);
564 break;
565 case kGreaterThan:
566 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true,
567 &return_false);
568 break;
569 case kGreaterThanOrEqual:
570 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true,
571 &return_false);
572 break;
573 }
574 }
575
576 assembler->Bind(&if_rhsisnotsmi);
577 {
578 // Load the map of {rhs}.
579 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
580
581 // Check if the {rhs} is a HeapNumber.
582 Node* number_map = assembler->HeapNumberMapConstant();
583 Label if_rhsisnumber(assembler),
584 if_rhsisnotnumber(assembler, Label::kDeferred);
585 assembler->Branch(assembler->WordEqual(rhs_map, number_map),
586 &if_rhsisnumber, &if_rhsisnotnumber);
587
588 assembler->Bind(&if_rhsisnumber);
589 {
590 // Convert the {lhs} and {rhs} to floating point values, and
591 // perform a floating point comparison.
592 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
593 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
594 assembler->Goto(&do_fcmp);
595 }
596
597 assembler->Bind(&if_rhsisnotnumber);
598 {
599 // Convert the {rhs} to a Number; we don't need to perform the
600 // dedicated ToPrimitive(rhs, hint Number) operation, as the
601 // ToNumber(rhs) will by itself already invoke ToPrimitive with
602 // a Number hint.
603 Callable callable = CodeFactory::ToNumber(assembler->isolate());
604 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
605 assembler->Goto(&loop);
606 }
607 }
608 }
609
610 assembler->Bind(&if_lhsisnotsmi);
611 {
612 // Load the HeapNumber map for later comparisons.
613 Node* number_map = assembler->HeapNumberMapConstant();
614
615 // Load the map of {lhs}.
616 Node* lhs_map = assembler->LoadObjectField(lhs, HeapObject::kMapOffset);
617
618 // Check if {rhs} is a Smi or a HeapObject.
619 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
620 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
621 &if_rhsisnotsmi);
622
623 assembler->Bind(&if_rhsissmi);
624 {
625 // Check if the {lhs} is a HeapNumber.
626 Label if_lhsisnumber(assembler),
627 if_lhsisnotnumber(assembler, Label::kDeferred);
628 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
629 &if_lhsisnumber, &if_lhsisnotnumber);
630
631 assembler->Bind(&if_lhsisnumber);
632 {
633 // Convert the {lhs} and {rhs} to floating point values, and
634 // perform a floating point comparison.
635 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
636 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs));
637 assembler->Goto(&do_fcmp);
638 }
639
640 assembler->Bind(&if_lhsisnotnumber);
641 {
642 // Convert the {lhs} to a Number; we don't need to perform the
643 // dedicated ToPrimitive(lhs, hint Number) operation, as the
644 // ToNumber(lhs) will by itself already invoke ToPrimitive with
645 // a Number hint.
646 Callable callable = CodeFactory::ToNumber(assembler->isolate());
647 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
648 assembler->Goto(&loop);
649 }
650 }
651
652 assembler->Bind(&if_rhsisnotsmi);
653 {
654 // Load the map of {rhs}.
655 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
656
657 // Check if {lhs} is a HeapNumber.
658 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
659 assembler->Branch(assembler->WordEqual(lhs_map, number_map),
660 &if_lhsisnumber, &if_lhsisnotnumber);
661
662 assembler->Bind(&if_lhsisnumber);
663 {
664 // Check if {rhs} is also a HeapNumber.
665 Label if_rhsisnumber(assembler),
666 if_rhsisnotnumber(assembler, Label::kDeferred);
667 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map),
668 &if_rhsisnumber, &if_rhsisnotnumber);
669
670 assembler->Bind(&if_rhsisnumber);
671 {
672 // Convert the {lhs} and {rhs} to floating point values, and
673 // perform a floating point comparison.
674 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
675 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
676 assembler->Goto(&do_fcmp);
677 }
678
679 assembler->Bind(&if_rhsisnotnumber);
680 {
681 // Convert the {rhs} to a Number; we don't need to perform
682 // dedicated ToPrimitive(rhs, hint Number) operation, as the
683 // ToNumber(rhs) will by itself already invoke ToPrimitive with
684 // a Number hint.
685 Callable callable = CodeFactory::ToNumber(assembler->isolate());
686 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
687 assembler->Goto(&loop);
688 }
689 }
690
691 assembler->Bind(&if_lhsisnotnumber);
692 {
693 // Load the instance type of {lhs}.
694 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
695
696 // Check if {lhs} is a String.
697 Label if_lhsisstring(assembler),
698 if_lhsisnotstring(assembler, Label::kDeferred);
699 assembler->Branch(assembler->Int32LessThan(
700 lhs_instance_type,
701 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
702 &if_lhsisstring, &if_lhsisnotstring);
703
704 assembler->Bind(&if_lhsisstring);
705 {
706 // Load the instance type of {rhs}.
707 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
708
709 // Check if {rhs} is also a String.
710 Label if_rhsisstring(assembler),
711 if_rhsisnotstring(assembler, Label::kDeferred);
712 assembler->Branch(assembler->Int32LessThan(
713 rhs_instance_type, assembler->Int32Constant(
714 FIRST_NONSTRING_TYPE)),
715 &if_rhsisstring, &if_rhsisnotstring);
716
717 assembler->Bind(&if_rhsisstring);
718 {
719 // Both {lhs} and {rhs} are strings.
720 // TODO(bmeurer): Hook up String<Compare>Stub once we have it.
721 switch (mode) {
722 case kLessThan:
723 assembler->TailCallRuntime(Runtime::kStringLessThan, context,
724 lhs, rhs);
725 break;
726 case kLessThanOrEqual:
727 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual,
728 context, lhs, rhs);
729 break;
730 case kGreaterThan:
731 assembler->TailCallRuntime(Runtime::kStringGreaterThan,
732 context, lhs, rhs);
733 break;
734 case kGreaterThanOrEqual:
735 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
736 context, lhs, rhs);
737 break;
738 }
739 }
740
741 assembler->Bind(&if_rhsisnotstring);
742 {
743 // The {lhs} is a String, while {rhs} is neither a Number nor a
744 // String, so we need to call ToPrimitive(rhs, hint Number) if
745 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
746 // other cases.
747 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
748 Label if_rhsisreceiver(assembler, Label::kDeferred),
749 if_rhsisnotreceiver(assembler, Label::kDeferred);
750 assembler->Branch(
751 assembler->Int32LessThanOrEqual(
752 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
753 rhs_instance_type),
754 &if_rhsisreceiver, &if_rhsisnotreceiver);
755
756 assembler->Bind(&if_rhsisreceiver);
757 {
758 // Convert {rhs} to a primitive first passing Number hint.
759 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
760 var_rhs.Bind(assembler->CallRuntime(
761 Runtime::kToPrimitive_Number, context, rhs));
762 assembler->Goto(&loop);
763 }
764
765 assembler->Bind(&if_rhsisnotreceiver);
766 {
767 // Convert both {lhs} and {rhs} to Number.
768 Callable callable = CodeFactory::ToNumber(assembler->isolate());
769 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
770 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
771 assembler->Goto(&loop);
772 }
773 }
774 }
775
776 assembler->Bind(&if_lhsisnotstring);
777 {
778 // The {lhs} is neither a Number nor a String, so we need to call
779 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
780 // ToNumber(lhs) and ToNumber(rhs) in the other cases.
781 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
782 Label if_lhsisreceiver(assembler, Label::kDeferred),
783 if_lhsisnotreceiver(assembler, Label::kDeferred);
784 assembler->Branch(
785 assembler->Int32LessThanOrEqual(
786 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
787 lhs_instance_type),
788 &if_lhsisreceiver, &if_lhsisnotreceiver);
789
790 assembler->Bind(&if_lhsisreceiver);
791 {
792 // Convert {lhs} to a primitive first passing Number hint.
793 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
794 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number,
795 context, lhs));
796 assembler->Goto(&loop);
797 }
798
799 assembler->Bind(&if_lhsisnotreceiver);
800 {
801 // Convert both {lhs} and {rhs} to Number.
802 Callable callable = CodeFactory::ToNumber(assembler->isolate());
803 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
804 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
805 assembler->Goto(&loop);
806 }
807 }
808 }
809 }
810 }
811 }
812
813 assembler->Bind(&do_fcmp);
814 {
815 // Load the {lhs} and {rhs} floating point values.
816 Node* lhs = var_fcmp_lhs.value();
817 Node* rhs = var_fcmp_rhs.value();
818
819 // Perform a fast floating point comparison.
820 switch (mode) {
821 case kLessThan:
822 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true,
823 &return_false);
824 break;
825 case kLessThanOrEqual:
826 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true,
827 &return_false);
828 break;
829 case kGreaterThan:
830 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true,
831 &return_false);
832 break;
833 case kGreaterThanOrEqual:
834 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true,
835 &return_false);
836 break;
837 }
838 }
839
840 assembler->Bind(&return_true);
841 assembler->Return(assembler->BooleanConstant(true));
842
843 assembler->Bind(&return_false);
844 assembler->Return(assembler->BooleanConstant(false));
845 }
846
504 enum ResultMode { kDontNegateResult, kNegateResult }; 847 enum ResultMode { kDontNegateResult, kNegateResult };
505 848
506 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, 849 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler,
507 Isolate* isolate, ResultMode mode) { 850 ResultMode mode) {
508 // Here's pseudo-code for the algorithm below in case of kDontNegateResult 851 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
509 // mode; for kNegateResult mode we properly negate the result. 852 // mode; for kNegateResult mode we properly negate the result.
510 // 853 //
511 // if (lhs == rhs) { 854 // if (lhs == rhs) {
512 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; 855 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
513 // return true; 856 // return true;
514 // } 857 // }
515 // if (!lhs->IsSmi()) { 858 // if (!lhs->IsSmi()) {
516 // if (lhs->IsHeapNumber()) { 859 // if (lhs->IsHeapNumber()) {
517 // if (rhs->IsSmi()) { 860 // if (rhs->IsSmi()) {
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 1042
700 // Check if {rhs} is also a String. 1043 // Check if {rhs} is also a String.
701 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); 1044 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
702 assembler->Branch(assembler->Int32LessThan( 1045 assembler->Branch(assembler->Int32LessThan(
703 rhs_instance_type, assembler->Int32Constant( 1046 rhs_instance_type, assembler->Int32Constant(
704 FIRST_NONSTRING_TYPE)), 1047 FIRST_NONSTRING_TYPE)),
705 &if_rhsisstring, &if_rhsisnotstring); 1048 &if_rhsisstring, &if_rhsisnotstring);
706 1049
707 assembler->Bind(&if_rhsisstring); 1050 assembler->Bind(&if_rhsisstring);
708 { 1051 {
709 Callable callable = (mode == kDontNegateResult) 1052 Callable callable =
710 ? CodeFactory::StringEqual(isolate) 1053 (mode == kDontNegateResult)
711 : CodeFactory::StringNotEqual(isolate); 1054 ? CodeFactory::StringEqual(assembler->isolate())
1055 : CodeFactory::StringNotEqual(assembler->isolate());
712 assembler->TailCallStub(callable, context, lhs, rhs); 1056 assembler->TailCallStub(callable, context, lhs, rhs);
713 } 1057 }
714 1058
715 assembler->Bind(&if_rhsisnotstring); 1059 assembler->Bind(&if_rhsisnotstring);
716 assembler->Goto(&if_notequal); 1060 assembler->Goto(&if_notequal);
717 } 1061 }
718 1062
719 assembler->Bind(&if_lhsisnotstring); 1063 assembler->Bind(&if_lhsisnotstring);
720 { 1064 {
721 // Check if {lhs} is a Simd128Value. 1065 // Check if {lhs} is a Simd128Value.
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 1306
963 assembler->Bind(&if_equal); 1307 assembler->Bind(&if_equal);
964 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); 1308 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
965 1309
966 assembler->Bind(&if_notequal); 1310 assembler->Bind(&if_notequal);
967 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); 1311 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
968 } 1312 }
969 1313
970 } // namespace 1314 } // namespace
971 1315
1316 void LessThanStub::GenerateAssembly(
1317 compiler::CodeStubAssembler* assembler) const {
1318 GenerateAbstractRelationalComparison(assembler, kLessThan);
1319 }
1320
1321 void LessThanOrEqualStub::GenerateAssembly(
1322 compiler::CodeStubAssembler* assembler) const {
1323 GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual);
1324 }
1325
1326 void GreaterThanStub::GenerateAssembly(
1327 compiler::CodeStubAssembler* assembler) const {
1328 GenerateAbstractRelationalComparison(assembler, kGreaterThan);
1329 }
1330
1331 void GreaterThanOrEqualStub::GenerateAssembly(
1332 compiler::CodeStubAssembler* assembler) const {
1333 GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual);
1334 }
1335
972 void StrictEqualStub::GenerateAssembly( 1336 void StrictEqualStub::GenerateAssembly(
973 compiler::CodeStubAssembler* assembler) const { 1337 compiler::CodeStubAssembler* assembler) const {
974 GenerateStrictEqual(assembler, isolate(), kDontNegateResult); 1338 GenerateStrictEqual(assembler, kDontNegateResult);
975 } 1339 }
976 1340
977 void StrictNotEqualStub::GenerateAssembly( 1341 void StrictNotEqualStub::GenerateAssembly(
978 compiler::CodeStubAssembler* assembler) const { 1342 compiler::CodeStubAssembler* assembler) const {
979 GenerateStrictEqual(assembler, isolate(), kNegateResult); 1343 GenerateStrictEqual(assembler, kNegateResult);
980 } 1344 }
981 1345
982 void StringEqualStub::GenerateAssembly( 1346 void StringEqualStub::GenerateAssembly(
983 compiler::CodeStubAssembler* assembler) const { 1347 compiler::CodeStubAssembler* assembler) const {
984 GenerateStringEqual(assembler, kDontNegateResult); 1348 GenerateStringEqual(assembler, kDontNegateResult);
985 } 1349 }
986 1350
987 void StringNotEqualStub::GenerateAssembly( 1351 void StringNotEqualStub::GenerateAssembly(
988 compiler::CodeStubAssembler* assembler) const { 1352 compiler::CodeStubAssembler* assembler) const {
989 GenerateStringEqual(assembler, kNegateResult); 1353 GenerateStringEqual(assembler, kNegateResult);
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 if (type->Is(Type::UntaggedPointer())) { 1921 if (type->Is(Type::UntaggedPointer())) {
1558 return Representation::External(); 1922 return Representation::External();
1559 } 1923 }
1560 1924
1561 DCHECK(!type->Is(Type::Untagged())); 1925 DCHECK(!type->Is(Type::Untagged()));
1562 return Representation::Tagged(); 1926 return Representation::Tagged();
1563 } 1927 }
1564 1928
1565 } // namespace internal 1929 } // namespace internal
1566 } // namespace v8 1930 } // namespace v8
OLDNEW
« no previous file with comments | « src/code-stubs.h ('k') | src/compiler/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698