OLD | NEW |
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/ast/ast.h" | 9 #include "src/ast/ast.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 #undef SIMD128_GEN_ASM | 653 #undef SIMD128_GEN_ASM |
654 | 654 |
655 void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 655 void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
656 compiler::Node* value = assembler->Parameter(0); | 656 compiler::Node* value = assembler->Parameter(0); |
657 compiler::Node* string = assembler->LoadJSValueValue(value); | 657 compiler::Node* string = assembler->LoadJSValueValue(value); |
658 compiler::Node* result = assembler->LoadStringLength(string); | 658 compiler::Node* result = assembler->LoadStringLength(string); |
659 assembler->Return(result); | 659 assembler->Return(result); |
660 } | 660 } |
661 | 661 |
662 // static | 662 // static |
663 compiler::Node* AddStub::Generate(CodeStubAssembler* assembler, | |
664 compiler::Node* left, compiler::Node* right, | |
665 compiler::Node* context) { | |
666 typedef CodeStubAssembler::Label Label; | |
667 typedef compiler::Node Node; | |
668 typedef CodeStubAssembler::Variable Variable; | |
669 | |
670 // Shared entry for floating point addition. | |
671 Label do_fadd(assembler); | |
672 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), | |
673 var_fadd_rhs(assembler, MachineRepresentation::kFloat64); | |
674 | |
675 // We might need to loop several times due to ToPrimitive, ToString and/or | |
676 // ToNumber conversions. | |
677 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
678 var_rhs(assembler, MachineRepresentation::kTagged), | |
679 var_result(assembler, MachineRepresentation::kTagged); | |
680 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
681 Label loop(assembler, 2, loop_vars), end(assembler), | |
682 string_add_convert_left(assembler, Label::kDeferred), | |
683 string_add_convert_right(assembler, Label::kDeferred); | |
684 var_lhs.Bind(left); | |
685 var_rhs.Bind(right); | |
686 assembler->Goto(&loop); | |
687 assembler->Bind(&loop); | |
688 { | |
689 // Load the current {lhs} and {rhs} values. | |
690 Node* lhs = var_lhs.value(); | |
691 Node* rhs = var_rhs.value(); | |
692 | |
693 // Check if the {lhs} is a Smi or a HeapObject. | |
694 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
695 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
696 | |
697 assembler->Bind(&if_lhsissmi); | |
698 { | |
699 // Check if the {rhs} is also a Smi. | |
700 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
701 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
702 &if_rhsisnotsmi); | |
703 | |
704 assembler->Bind(&if_rhsissmi); | |
705 { | |
706 // Try fast Smi addition first. | |
707 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs); | |
708 Node* overflow = assembler->Projection(1, pair); | |
709 | |
710 // Check if the Smi additon overflowed. | |
711 Label if_overflow(assembler), if_notoverflow(assembler); | |
712 assembler->Branch(overflow, &if_overflow, &if_notoverflow); | |
713 | |
714 assembler->Bind(&if_overflow); | |
715 { | |
716 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
717 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
718 assembler->Goto(&do_fadd); | |
719 } | |
720 | |
721 assembler->Bind(&if_notoverflow); | |
722 var_result.Bind(assembler->Projection(0, pair)); | |
723 assembler->Goto(&end); | |
724 } | |
725 | |
726 assembler->Bind(&if_rhsisnotsmi); | |
727 { | |
728 // Load the map of {rhs}. | |
729 Node* rhs_map = assembler->LoadMap(rhs); | |
730 | |
731 // Check if the {rhs} is a HeapNumber. | |
732 Label if_rhsisnumber(assembler), | |
733 if_rhsisnotnumber(assembler, Label::kDeferred); | |
734 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, | |
735 &if_rhsisnotnumber); | |
736 | |
737 assembler->Bind(&if_rhsisnumber); | |
738 { | |
739 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
740 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
741 assembler->Goto(&do_fadd); | |
742 } | |
743 | |
744 assembler->Bind(&if_rhsisnotnumber); | |
745 { | |
746 // Load the instance type of {rhs}. | |
747 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
748 | |
749 // Check if the {rhs} is a String. | |
750 Label if_rhsisstring(assembler, Label::kDeferred), | |
751 if_rhsisnotstring(assembler, Label::kDeferred); | |
752 assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type), | |
753 &if_rhsisstring, &if_rhsisnotstring); | |
754 | |
755 assembler->Bind(&if_rhsisstring); | |
756 { | |
757 var_lhs.Bind(lhs); | |
758 var_rhs.Bind(rhs); | |
759 assembler->Goto(&string_add_convert_left); | |
760 } | |
761 | |
762 assembler->Bind(&if_rhsisnotstring); | |
763 { | |
764 // Check if {rhs} is a JSReceiver. | |
765 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
766 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
767 assembler->Branch( | |
768 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
769 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
770 | |
771 assembler->Bind(&if_rhsisreceiver); | |
772 { | |
773 // Convert {rhs} to a primitive first passing no hint. | |
774 Callable callable = | |
775 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
776 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
777 assembler->Goto(&loop); | |
778 } | |
779 | |
780 assembler->Bind(&if_rhsisnotreceiver); | |
781 { | |
782 // Convert {rhs} to a Number first. | |
783 Callable callable = | |
784 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
785 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
786 assembler->Goto(&loop); | |
787 } | |
788 } | |
789 } | |
790 } | |
791 } | |
792 | |
793 assembler->Bind(&if_lhsisnotsmi); | |
794 { | |
795 // Load the map and instance type of {lhs}. | |
796 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | |
797 | |
798 // Check if {lhs} is a String. | |
799 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); | |
800 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), | |
801 &if_lhsisstring, &if_lhsisnotstring); | |
802 | |
803 assembler->Bind(&if_lhsisstring); | |
804 { | |
805 var_lhs.Bind(lhs); | |
806 var_rhs.Bind(rhs); | |
807 assembler->Goto(&string_add_convert_right); | |
808 } | |
809 | |
810 assembler->Bind(&if_lhsisnotstring); | |
811 { | |
812 // Check if {rhs} is a Smi. | |
813 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
814 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
815 &if_rhsisnotsmi); | |
816 | |
817 assembler->Bind(&if_rhsissmi); | |
818 { | |
819 // Check if {lhs} is a Number. | |
820 Label if_lhsisnumber(assembler), | |
821 if_lhsisnotnumber(assembler, Label::kDeferred); | |
822 assembler->Branch(assembler->Word32Equal( | |
823 lhs_instance_type, | |
824 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
825 &if_lhsisnumber, &if_lhsisnotnumber); | |
826 | |
827 assembler->Bind(&if_lhsisnumber); | |
828 { | |
829 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. | |
830 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
831 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
832 assembler->Goto(&do_fadd); | |
833 } | |
834 | |
835 assembler->Bind(&if_lhsisnotnumber); | |
836 { | |
837 // The {lhs} is neither a Number nor a String, and the {rhs} is a | |
838 // Smi. | |
839 Label if_lhsisreceiver(assembler, Label::kDeferred), | |
840 if_lhsisnotreceiver(assembler, Label::kDeferred); | |
841 assembler->Branch( | |
842 assembler->IsJSReceiverInstanceType(lhs_instance_type), | |
843 &if_lhsisreceiver, &if_lhsisnotreceiver); | |
844 | |
845 assembler->Bind(&if_lhsisreceiver); | |
846 { | |
847 // Convert {lhs} to a primitive first passing no hint. | |
848 Callable callable = | |
849 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
850 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
851 assembler->Goto(&loop); | |
852 } | |
853 | |
854 assembler->Bind(&if_lhsisnotreceiver); | |
855 { | |
856 // Convert {lhs} to a Number first. | |
857 Callable callable = | |
858 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
859 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
860 assembler->Goto(&loop); | |
861 } | |
862 } | |
863 } | |
864 | |
865 assembler->Bind(&if_rhsisnotsmi); | |
866 { | |
867 // Load the instance type of {rhs}. | |
868 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
869 | |
870 // Check if {rhs} is a String. | |
871 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); | |
872 assembler->Branch(assembler->IsStringInstanceType(rhs_instance_type), | |
873 &if_rhsisstring, &if_rhsisnotstring); | |
874 | |
875 assembler->Bind(&if_rhsisstring); | |
876 { | |
877 var_lhs.Bind(lhs); | |
878 var_rhs.Bind(rhs); | |
879 assembler->Goto(&string_add_convert_left); | |
880 } | |
881 | |
882 assembler->Bind(&if_rhsisnotstring); | |
883 { | |
884 // Check if {lhs} is a HeapNumber. | |
885 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
886 assembler->Branch(assembler->Word32Equal( | |
887 lhs_instance_type, | |
888 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
889 &if_lhsisnumber, &if_lhsisnotnumber); | |
890 | |
891 assembler->Bind(&if_lhsisnumber); | |
892 { | |
893 // Check if {rhs} is also a HeapNumber. | |
894 Label if_rhsisnumber(assembler), | |
895 if_rhsisnotnumber(assembler, Label::kDeferred); | |
896 assembler->Branch(assembler->Word32Equal( | |
897 rhs_instance_type, | |
898 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
899 &if_rhsisnumber, &if_rhsisnotnumber); | |
900 | |
901 assembler->Bind(&if_rhsisnumber); | |
902 { | |
903 // Perform a floating point addition. | |
904 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
905 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
906 assembler->Goto(&do_fadd); | |
907 } | |
908 | |
909 assembler->Bind(&if_rhsisnotnumber); | |
910 { | |
911 // Check if {rhs} is a JSReceiver. | |
912 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
913 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
914 assembler->Branch( | |
915 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
916 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
917 | |
918 assembler->Bind(&if_rhsisreceiver); | |
919 { | |
920 // Convert {rhs} to a primitive first passing no hint. | |
921 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
922 assembler->isolate()); | |
923 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
924 assembler->Goto(&loop); | |
925 } | |
926 | |
927 assembler->Bind(&if_rhsisnotreceiver); | |
928 { | |
929 // Convert {rhs} to a Number first. | |
930 Callable callable = | |
931 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
932 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
933 assembler->Goto(&loop); | |
934 } | |
935 } | |
936 } | |
937 | |
938 assembler->Bind(&if_lhsisnotnumber); | |
939 { | |
940 // Check if {lhs} is a JSReceiver. | |
941 Label if_lhsisreceiver(assembler, Label::kDeferred), | |
942 if_lhsisnotreceiver(assembler); | |
943 assembler->Branch( | |
944 assembler->IsJSReceiverInstanceType(lhs_instance_type), | |
945 &if_lhsisreceiver, &if_lhsisnotreceiver); | |
946 | |
947 assembler->Bind(&if_lhsisreceiver); | |
948 { | |
949 // Convert {lhs} to a primitive first passing no hint. | |
950 Callable callable = | |
951 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
952 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
953 assembler->Goto(&loop); | |
954 } | |
955 | |
956 assembler->Bind(&if_lhsisnotreceiver); | |
957 { | |
958 // Check if {rhs} is a JSReceiver. | |
959 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
960 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
961 assembler->Branch( | |
962 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
963 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
964 | |
965 assembler->Bind(&if_rhsisreceiver); | |
966 { | |
967 // Convert {rhs} to a primitive first passing no hint. | |
968 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
969 assembler->isolate()); | |
970 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
971 assembler->Goto(&loop); | |
972 } | |
973 | |
974 assembler->Bind(&if_rhsisnotreceiver); | |
975 { | |
976 // Convert {lhs} to a Number first. | |
977 Callable callable = | |
978 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
979 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
980 assembler->Goto(&loop); | |
981 } | |
982 } | |
983 } | |
984 } | |
985 } | |
986 } | |
987 } | |
988 } | |
989 assembler->Bind(&string_add_convert_left); | |
990 { | |
991 // Convert {lhs}, which is a Smi, to a String and concatenate the | |
992 // resulting string with the String {rhs}. | |
993 Callable callable = CodeFactory::StringAdd( | |
994 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); | |
995 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), | |
996 var_rhs.value())); | |
997 assembler->Goto(&end); | |
998 } | |
999 | |
1000 assembler->Bind(&string_add_convert_right); | |
1001 { | |
1002 // Convert {lhs}, which is a Smi, to a String and concatenate the | |
1003 // resulting string with the String {rhs}. | |
1004 Callable callable = CodeFactory::StringAdd( | |
1005 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); | |
1006 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), | |
1007 var_rhs.value())); | |
1008 assembler->Goto(&end); | |
1009 } | |
1010 | |
1011 assembler->Bind(&do_fadd); | |
1012 { | |
1013 Node* lhs_value = var_fadd_lhs.value(); | |
1014 Node* rhs_value = var_fadd_rhs.value(); | |
1015 Node* value = assembler->Float64Add(lhs_value, rhs_value); | |
1016 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1017 var_result.Bind(result); | |
1018 assembler->Goto(&end); | |
1019 } | |
1020 assembler->Bind(&end); | |
1021 return var_result.value(); | |
1022 } | |
1023 | |
1024 // static | |
1025 compiler::Node* AddWithFeedbackStub::Generate( | 663 compiler::Node* AddWithFeedbackStub::Generate( |
1026 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, | 664 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
1027 compiler::Node* slot_id, compiler::Node* type_feedback_vector, | 665 compiler::Node* slot_id, compiler::Node* type_feedback_vector, |
1028 compiler::Node* context) { | 666 compiler::Node* context) { |
1029 typedef CodeStubAssembler::Label Label; | 667 typedef CodeStubAssembler::Label Label; |
1030 typedef compiler::Node Node; | 668 typedef compiler::Node Node; |
1031 typedef CodeStubAssembler::Variable Variable; | 669 typedef CodeStubAssembler::Variable Variable; |
1032 | 670 |
1033 // Shared entry for floating point addition. | 671 // Shared entry for floating point addition. |
1034 Label do_fadd(assembler), end(assembler), | 672 Label do_fadd(assembler), end(assembler), |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1144 assembler->Goto(&end); | 782 assembler->Goto(&end); |
1145 } | 783 } |
1146 | 784 |
1147 assembler->Bind(&end); | 785 assembler->Bind(&end); |
1148 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 786 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
1149 slot_id); | 787 slot_id); |
1150 return var_result.value(); | 788 return var_result.value(); |
1151 } | 789 } |
1152 | 790 |
1153 // static | 791 // static |
1154 compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler, | |
1155 compiler::Node* left, | |
1156 compiler::Node* right, | |
1157 compiler::Node* context) { | |
1158 typedef CodeStubAssembler::Label Label; | |
1159 typedef compiler::Node Node; | |
1160 typedef CodeStubAssembler::Variable Variable; | |
1161 | |
1162 // Shared entry for floating point subtraction. | |
1163 Label do_fsub(assembler), end(assembler); | |
1164 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), | |
1165 var_fsub_rhs(assembler, MachineRepresentation::kFloat64); | |
1166 | |
1167 // We might need to loop several times due to ToPrimitive and/or ToNumber | |
1168 // conversions. | |
1169 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
1170 var_rhs(assembler, MachineRepresentation::kTagged), | |
1171 var_result(assembler, MachineRepresentation::kTagged); | |
1172 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
1173 Label loop(assembler, 2, loop_vars); | |
1174 var_lhs.Bind(left); | |
1175 var_rhs.Bind(right); | |
1176 assembler->Goto(&loop); | |
1177 assembler->Bind(&loop); | |
1178 { | |
1179 // Load the current {lhs} and {rhs} values. | |
1180 Node* lhs = var_lhs.value(); | |
1181 Node* rhs = var_rhs.value(); | |
1182 | |
1183 // Check if the {lhs} is a Smi or a HeapObject. | |
1184 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
1185 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
1186 | |
1187 assembler->Bind(&if_lhsissmi); | |
1188 { | |
1189 // Check if the {rhs} is also a Smi. | |
1190 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
1191 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
1192 &if_rhsisnotsmi); | |
1193 | |
1194 assembler->Bind(&if_rhsissmi); | |
1195 { | |
1196 // Try a fast Smi subtraction first. | |
1197 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs); | |
1198 Node* overflow = assembler->Projection(1, pair); | |
1199 | |
1200 // Check if the Smi subtraction overflowed. | |
1201 Label if_overflow(assembler), if_notoverflow(assembler); | |
1202 assembler->Branch(overflow, &if_overflow, &if_notoverflow); | |
1203 | |
1204 assembler->Bind(&if_overflow); | |
1205 { | |
1206 // The result doesn't fit into Smi range. | |
1207 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
1208 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
1209 assembler->Goto(&do_fsub); | |
1210 } | |
1211 | |
1212 assembler->Bind(&if_notoverflow); | |
1213 var_result.Bind(assembler->Projection(0, pair)); | |
1214 assembler->Goto(&end); | |
1215 } | |
1216 | |
1217 assembler->Bind(&if_rhsisnotsmi); | |
1218 { | |
1219 // Load the map of the {rhs}. | |
1220 Node* rhs_map = assembler->LoadMap(rhs); | |
1221 | |
1222 // Check if {rhs} is a HeapNumber. | |
1223 Label if_rhsisnumber(assembler), | |
1224 if_rhsisnotnumber(assembler, Label::kDeferred); | |
1225 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, | |
1226 &if_rhsisnotnumber); | |
1227 | |
1228 assembler->Bind(&if_rhsisnumber); | |
1229 { | |
1230 // Perform a floating point subtraction. | |
1231 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
1232 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
1233 assembler->Goto(&do_fsub); | |
1234 } | |
1235 | |
1236 assembler->Bind(&if_rhsisnotnumber); | |
1237 { | |
1238 // Convert the {rhs} to a Number first. | |
1239 Callable callable = | |
1240 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1241 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
1242 assembler->Goto(&loop); | |
1243 } | |
1244 } | |
1245 } | |
1246 | |
1247 assembler->Bind(&if_lhsisnotsmi); | |
1248 { | |
1249 // Load the map of the {lhs}. | |
1250 Node* lhs_map = assembler->LoadMap(lhs); | |
1251 | |
1252 // Check if the {lhs} is a HeapNumber. | |
1253 Label if_lhsisnumber(assembler), | |
1254 if_lhsisnotnumber(assembler, Label::kDeferred); | |
1255 Node* number_map = assembler->HeapNumberMapConstant(); | |
1256 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
1257 &if_lhsisnumber, &if_lhsisnotnumber); | |
1258 | |
1259 assembler->Bind(&if_lhsisnumber); | |
1260 { | |
1261 // Check if the {rhs} is a Smi. | |
1262 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
1263 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
1264 &if_rhsisnotsmi); | |
1265 | |
1266 assembler->Bind(&if_rhsissmi); | |
1267 { | |
1268 // Perform a floating point subtraction. | |
1269 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
1270 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
1271 assembler->Goto(&do_fsub); | |
1272 } | |
1273 | |
1274 assembler->Bind(&if_rhsisnotsmi); | |
1275 { | |
1276 // Load the map of the {rhs}. | |
1277 Node* rhs_map = assembler->LoadMap(rhs); | |
1278 | |
1279 // Check if the {rhs} is a HeapNumber. | |
1280 Label if_rhsisnumber(assembler), | |
1281 if_rhsisnotnumber(assembler, Label::kDeferred); | |
1282 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
1283 &if_rhsisnumber, &if_rhsisnotnumber); | |
1284 | |
1285 assembler->Bind(&if_rhsisnumber); | |
1286 { | |
1287 // Perform a floating point subtraction. | |
1288 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
1289 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
1290 assembler->Goto(&do_fsub); | |
1291 } | |
1292 | |
1293 assembler->Bind(&if_rhsisnotnumber); | |
1294 { | |
1295 // Convert the {rhs} to a Number first. | |
1296 Callable callable = | |
1297 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1298 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
1299 assembler->Goto(&loop); | |
1300 } | |
1301 } | |
1302 } | |
1303 | |
1304 assembler->Bind(&if_lhsisnotnumber); | |
1305 { | |
1306 // Convert the {lhs} to a Number first. | |
1307 Callable callable = | |
1308 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1309 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
1310 assembler->Goto(&loop); | |
1311 } | |
1312 } | |
1313 } | |
1314 | |
1315 assembler->Bind(&do_fsub); | |
1316 { | |
1317 Node* lhs_value = var_fsub_lhs.value(); | |
1318 Node* rhs_value = var_fsub_rhs.value(); | |
1319 Node* value = assembler->Float64Sub(lhs_value, rhs_value); | |
1320 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); | |
1321 assembler->Goto(&end); | |
1322 } | |
1323 assembler->Bind(&end); | |
1324 return var_result.value(); | |
1325 } | |
1326 | |
1327 // static | |
1328 compiler::Node* SubtractWithFeedbackStub::Generate( | 792 compiler::Node* SubtractWithFeedbackStub::Generate( |
1329 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, | 793 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
1330 compiler::Node* slot_id, compiler::Node* type_feedback_vector, | 794 compiler::Node* slot_id, compiler::Node* type_feedback_vector, |
1331 compiler::Node* context) { | 795 compiler::Node* context) { |
1332 typedef CodeStubAssembler::Label Label; | 796 typedef CodeStubAssembler::Label Label; |
1333 typedef compiler::Node Node; | 797 typedef compiler::Node Node; |
1334 typedef CodeStubAssembler::Variable Variable; | 798 typedef CodeStubAssembler::Variable Variable; |
1335 | 799 |
1336 // Shared entry for floating point subtraction. | 800 // Shared entry for floating point subtraction. |
1337 Label do_fsub(assembler), end(assembler), | 801 Label do_fsub(assembler), end(assembler), |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1450 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | 914 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); |
1451 assembler->Goto(&end); | 915 assembler->Goto(&end); |
1452 } | 916 } |
1453 | 917 |
1454 assembler->Bind(&end); | 918 assembler->Bind(&end); |
1455 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 919 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
1456 slot_id); | 920 slot_id); |
1457 return var_result.value(); | 921 return var_result.value(); |
1458 } | 922 } |
1459 | 923 |
1460 // static | |
1461 compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler, | |
1462 compiler::Node* left, | |
1463 compiler::Node* right, | |
1464 compiler::Node* context) { | |
1465 using compiler::Node; | |
1466 typedef CodeStubAssembler::Label Label; | |
1467 typedef CodeStubAssembler::Variable Variable; | |
1468 | |
1469 // Shared entry point for floating point multiplication. | |
1470 Label do_fmul(assembler), return_result(assembler); | |
1471 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), | |
1472 var_rhs_float64(assembler, MachineRepresentation::kFloat64); | |
1473 | |
1474 Node* number_map = assembler->HeapNumberMapConstant(); | |
1475 | |
1476 // We might need to loop one or two times due to ToNumber conversions. | |
1477 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
1478 var_rhs(assembler, MachineRepresentation::kTagged), | |
1479 var_result(assembler, MachineRepresentation::kTagged); | |
1480 Variable* loop_variables[] = {&var_lhs, &var_rhs}; | |
1481 Label loop(assembler, 2, loop_variables); | |
1482 var_lhs.Bind(left); | |
1483 var_rhs.Bind(right); | |
1484 assembler->Goto(&loop); | |
1485 assembler->Bind(&loop); | |
1486 { | |
1487 Node* lhs = var_lhs.value(); | |
1488 Node* rhs = var_rhs.value(); | |
1489 | |
1490 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler); | |
1491 assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); | |
1492 | |
1493 assembler->Bind(&lhs_is_smi); | |
1494 { | |
1495 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); | |
1496 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, | |
1497 &rhs_is_not_smi); | |
1498 | |
1499 assembler->Bind(&rhs_is_smi); | |
1500 { | |
1501 // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, | |
1502 // in case of overflow. | |
1503 var_result.Bind(assembler->SmiMul(lhs, rhs)); | |
1504 assembler->Goto(&return_result); | |
1505 } | |
1506 | |
1507 assembler->Bind(&rhs_is_not_smi); | |
1508 { | |
1509 Node* rhs_map = assembler->LoadMap(rhs); | |
1510 | |
1511 // Check if {rhs} is a HeapNumber. | |
1512 Label rhs_is_number(assembler), | |
1513 rhs_is_not_number(assembler, Label::kDeferred); | |
1514 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
1515 &rhs_is_number, &rhs_is_not_number); | |
1516 | |
1517 assembler->Bind(&rhs_is_number); | |
1518 { | |
1519 // Convert {lhs} to a double and multiply it with the value of {rhs}. | |
1520 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); | |
1521 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); | |
1522 assembler->Goto(&do_fmul); | |
1523 } | |
1524 | |
1525 assembler->Bind(&rhs_is_not_number); | |
1526 { | |
1527 // Multiplication is commutative, swap {lhs} with {rhs} and loop. | |
1528 var_lhs.Bind(rhs); | |
1529 var_rhs.Bind(lhs); | |
1530 assembler->Goto(&loop); | |
1531 } | |
1532 } | |
1533 } | |
1534 | |
1535 assembler->Bind(&lhs_is_not_smi); | |
1536 { | |
1537 Node* lhs_map = assembler->LoadMap(lhs); | |
1538 | |
1539 // Check if {lhs} is a HeapNumber. | |
1540 Label lhs_is_number(assembler), | |
1541 lhs_is_not_number(assembler, Label::kDeferred); | |
1542 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
1543 &lhs_is_number, &lhs_is_not_number); | |
1544 | |
1545 assembler->Bind(&lhs_is_number); | |
1546 { | |
1547 // Check if {rhs} is a Smi. | |
1548 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); | |
1549 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, | |
1550 &rhs_is_not_smi); | |
1551 | |
1552 assembler->Bind(&rhs_is_smi); | |
1553 { | |
1554 // Convert {rhs} to a double and multiply it with the value of {lhs}. | |
1555 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); | |
1556 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs)); | |
1557 assembler->Goto(&do_fmul); | |
1558 } | |
1559 | |
1560 assembler->Bind(&rhs_is_not_smi); | |
1561 { | |
1562 Node* rhs_map = assembler->LoadMap(rhs); | |
1563 | |
1564 // Check if {rhs} is a HeapNumber. | |
1565 Label rhs_is_number(assembler), | |
1566 rhs_is_not_number(assembler, Label::kDeferred); | |
1567 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
1568 &rhs_is_number, &rhs_is_not_number); | |
1569 | |
1570 assembler->Bind(&rhs_is_number); | |
1571 { | |
1572 // Both {lhs} and {rhs} are HeapNumbers. Load their values and | |
1573 // multiply them. | |
1574 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); | |
1575 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); | |
1576 assembler->Goto(&do_fmul); | |
1577 } | |
1578 | |
1579 assembler->Bind(&rhs_is_not_number); | |
1580 { | |
1581 // Multiplication is commutative, swap {lhs} with {rhs} and loop. | |
1582 var_lhs.Bind(rhs); | |
1583 var_rhs.Bind(lhs); | |
1584 assembler->Goto(&loop); | |
1585 } | |
1586 } | |
1587 } | |
1588 | |
1589 assembler->Bind(&lhs_is_not_number); | |
1590 { | |
1591 // Convert {lhs} to a Number and loop. | |
1592 Callable callable = | |
1593 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1594 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
1595 assembler->Goto(&loop); | |
1596 } | |
1597 } | |
1598 } | |
1599 | |
1600 assembler->Bind(&do_fmul); | |
1601 { | |
1602 Node* value = | |
1603 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); | |
1604 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1605 var_result.Bind(result); | |
1606 assembler->Goto(&return_result); | |
1607 } | |
1608 | |
1609 assembler->Bind(&return_result); | |
1610 return var_result.value(); | |
1611 } | |
1612 | 924 |
1613 // static | 925 // static |
1614 compiler::Node* MultiplyWithFeedbackStub::Generate( | 926 compiler::Node* MultiplyWithFeedbackStub::Generate( |
1615 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, | 927 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* rhs, |
1616 compiler::Node* slot_id, compiler::Node* type_feedback_vector, | 928 compiler::Node* slot_id, compiler::Node* type_feedback_vector, |
1617 compiler::Node* context) { | 929 compiler::Node* context) { |
1618 using compiler::Node; | 930 using compiler::Node; |
1619 typedef CodeStubAssembler::Label Label; | 931 typedef CodeStubAssembler::Label Label; |
1620 typedef CodeStubAssembler::Variable Variable; | 932 typedef CodeStubAssembler::Variable Variable; |
1621 | 933 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1720 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | 1032 var_result.Bind(assembler->CallStub(callable, context, lhs, rhs)); |
1721 assembler->Goto(&end); | 1033 assembler->Goto(&end); |
1722 } | 1034 } |
1723 | 1035 |
1724 assembler->Bind(&end); | 1036 assembler->Bind(&end); |
1725 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 1037 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
1726 slot_id); | 1038 slot_id); |
1727 return var_result.value(); | 1039 return var_result.value(); |
1728 } | 1040 } |
1729 | 1041 |
1730 // static | |
1731 compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler, | |
1732 compiler::Node* left, | |
1733 compiler::Node* right, | |
1734 compiler::Node* context) { | |
1735 using compiler::Node; | |
1736 typedef CodeStubAssembler::Label Label; | |
1737 typedef CodeStubAssembler::Variable Variable; | |
1738 | |
1739 // Shared entry point for floating point division. | |
1740 Label do_fdiv(assembler), end(assembler); | |
1741 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), | |
1742 var_divisor_float64(assembler, MachineRepresentation::kFloat64); | |
1743 | |
1744 Node* number_map = assembler->HeapNumberMapConstant(); | |
1745 | |
1746 // We might need to loop one or two times due to ToNumber conversions. | |
1747 Variable var_dividend(assembler, MachineRepresentation::kTagged), | |
1748 var_divisor(assembler, MachineRepresentation::kTagged), | |
1749 var_result(assembler, MachineRepresentation::kTagged); | |
1750 Variable* loop_variables[] = {&var_dividend, &var_divisor}; | |
1751 Label loop(assembler, 2, loop_variables); | |
1752 var_dividend.Bind(left); | |
1753 var_divisor.Bind(right); | |
1754 assembler->Goto(&loop); | |
1755 assembler->Bind(&loop); | |
1756 { | |
1757 Node* dividend = var_dividend.value(); | |
1758 Node* divisor = var_divisor.value(); | |
1759 | |
1760 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); | |
1761 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, | |
1762 ÷nd_is_not_smi); | |
1763 | |
1764 assembler->Bind(÷nd_is_smi); | |
1765 { | |
1766 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
1767 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
1768 &divisor_is_not_smi); | |
1769 | |
1770 assembler->Bind(&divisor_is_smi); | |
1771 { | |
1772 Label bailout(assembler); | |
1773 | |
1774 // Do floating point division if {divisor} is zero. | |
1775 assembler->GotoIf( | |
1776 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)), | |
1777 &bailout); | |
1778 | |
1779 // Do floating point division {dividend} is zero and {divisor} is | |
1780 // negative. | |
1781 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler); | |
1782 assembler->Branch( | |
1783 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)), | |
1784 ÷nd_is_zero, ÷nd_is_not_zero); | |
1785 | |
1786 assembler->Bind(÷nd_is_zero); | |
1787 { | |
1788 assembler->GotoIf( | |
1789 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)), | |
1790 &bailout); | |
1791 assembler->Goto(÷nd_is_not_zero); | |
1792 } | |
1793 assembler->Bind(÷nd_is_not_zero); | |
1794 | |
1795 Node* untagged_divisor = assembler->SmiUntag(divisor); | |
1796 Node* untagged_dividend = assembler->SmiUntag(dividend); | |
1797 | |
1798 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 | |
1799 // if the Smi size is 31) and {divisor} is -1. | |
1800 Label divisor_is_minus_one(assembler), | |
1801 divisor_is_not_minus_one(assembler); | |
1802 assembler->Branch(assembler->Word32Equal(untagged_divisor, | |
1803 assembler->Int32Constant(-1)), | |
1804 &divisor_is_minus_one, &divisor_is_not_minus_one); | |
1805 | |
1806 assembler->Bind(&divisor_is_minus_one); | |
1807 { | |
1808 assembler->GotoIf( | |
1809 assembler->Word32Equal( | |
1810 untagged_dividend, | |
1811 assembler->Int32Constant( | |
1812 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), | |
1813 &bailout); | |
1814 assembler->Goto(&divisor_is_not_minus_one); | |
1815 } | |
1816 assembler->Bind(&divisor_is_not_minus_one); | |
1817 | |
1818 // TODO(epertoso): consider adding a machine instruction that returns | |
1819 // both the result and the remainder. | |
1820 Node* untagged_result = | |
1821 assembler->Int32Div(untagged_dividend, untagged_divisor); | |
1822 Node* truncated = | |
1823 assembler->Int32Mul(untagged_result, untagged_divisor); | |
1824 // Do floating point division if the remainder is not 0. | |
1825 assembler->GotoIf( | |
1826 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout); | |
1827 var_result.Bind(assembler->SmiTag(untagged_result)); | |
1828 assembler->Goto(&end); | |
1829 | |
1830 // Bailout: convert {dividend} and {divisor} to double and do double | |
1831 // division. | |
1832 assembler->Bind(&bailout); | |
1833 { | |
1834 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); | |
1835 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); | |
1836 assembler->Goto(&do_fdiv); | |
1837 } | |
1838 } | |
1839 | |
1840 assembler->Bind(&divisor_is_not_smi); | |
1841 { | |
1842 Node* divisor_map = assembler->LoadMap(divisor); | |
1843 | |
1844 // Check if {divisor} is a HeapNumber. | |
1845 Label divisor_is_number(assembler), | |
1846 divisor_is_not_number(assembler, Label::kDeferred); | |
1847 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
1848 &divisor_is_number, &divisor_is_not_number); | |
1849 | |
1850 assembler->Bind(&divisor_is_number); | |
1851 { | |
1852 // Convert {dividend} to a double and divide it with the value of | |
1853 // {divisor}. | |
1854 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); | |
1855 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
1856 assembler->Goto(&do_fdiv); | |
1857 } | |
1858 | |
1859 assembler->Bind(&divisor_is_not_number); | |
1860 { | |
1861 // Convert {divisor} to a number and loop. | |
1862 Callable callable = | |
1863 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1864 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
1865 assembler->Goto(&loop); | |
1866 } | |
1867 } | |
1868 } | |
1869 | |
1870 assembler->Bind(÷nd_is_not_smi); | |
1871 { | |
1872 Node* dividend_map = assembler->LoadMap(dividend); | |
1873 | |
1874 // Check if {dividend} is a HeapNumber. | |
1875 Label dividend_is_number(assembler), | |
1876 dividend_is_not_number(assembler, Label::kDeferred); | |
1877 assembler->Branch(assembler->WordEqual(dividend_map, number_map), | |
1878 ÷nd_is_number, ÷nd_is_not_number); | |
1879 | |
1880 assembler->Bind(÷nd_is_number); | |
1881 { | |
1882 // Check if {divisor} is a Smi. | |
1883 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
1884 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
1885 &divisor_is_not_smi); | |
1886 | |
1887 assembler->Bind(&divisor_is_smi); | |
1888 { | |
1889 // Convert {divisor} to a double and use it for a floating point | |
1890 // division. | |
1891 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
1892 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); | |
1893 assembler->Goto(&do_fdiv); | |
1894 } | |
1895 | |
1896 assembler->Bind(&divisor_is_not_smi); | |
1897 { | |
1898 Node* divisor_map = assembler->LoadMap(divisor); | |
1899 | |
1900 // Check if {divisor} is a HeapNumber. | |
1901 Label divisor_is_number(assembler), | |
1902 divisor_is_not_number(assembler, Label::kDeferred); | |
1903 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
1904 &divisor_is_number, &divisor_is_not_number); | |
1905 | |
1906 assembler->Bind(&divisor_is_number); | |
1907 { | |
1908 // Both {dividend} and {divisor} are HeapNumbers. Load their values | |
1909 // and divide them. | |
1910 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
1911 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
1912 assembler->Goto(&do_fdiv); | |
1913 } | |
1914 | |
1915 assembler->Bind(&divisor_is_not_number); | |
1916 { | |
1917 // Convert {divisor} to a number and loop. | |
1918 Callable callable = | |
1919 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1920 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
1921 assembler->Goto(&loop); | |
1922 } | |
1923 } | |
1924 } | |
1925 | |
1926 assembler->Bind(÷nd_is_not_number); | |
1927 { | |
1928 // Convert {dividend} to a Number and loop. | |
1929 Callable callable = | |
1930 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1931 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); | |
1932 assembler->Goto(&loop); | |
1933 } | |
1934 } | |
1935 } | |
1936 | |
1937 assembler->Bind(&do_fdiv); | |
1938 { | |
1939 Node* value = assembler->Float64Div(var_dividend_float64.value(), | |
1940 var_divisor_float64.value()); | |
1941 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); | |
1942 assembler->Goto(&end); | |
1943 } | |
1944 assembler->Bind(&end); | |
1945 return var_result.value(); | |
1946 } | |
1947 | 1042 |
1948 // static | 1043 // static |
1949 compiler::Node* DivideWithFeedbackStub::Generate( | 1044 compiler::Node* DivideWithFeedbackStub::Generate( |
1950 CodeStubAssembler* assembler, compiler::Node* dividend, | 1045 CodeStubAssembler* assembler, compiler::Node* dividend, |
1951 compiler::Node* divisor, compiler::Node* slot_id, | 1046 compiler::Node* divisor, compiler::Node* slot_id, |
1952 compiler::Node* type_feedback_vector, compiler::Node* context) { | 1047 compiler::Node* type_feedback_vector, compiler::Node* context) { |
1953 using compiler::Node; | 1048 using compiler::Node; |
1954 typedef CodeStubAssembler::Label Label; | 1049 typedef CodeStubAssembler::Label Label; |
1955 typedef CodeStubAssembler::Variable Variable; | 1050 typedef CodeStubAssembler::Variable Variable; |
1956 | 1051 |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2115 assembler->Goto(&end); | 1210 assembler->Goto(&end); |
2116 } | 1211 } |
2117 | 1212 |
2118 assembler->Bind(&end); | 1213 assembler->Bind(&end); |
2119 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 1214 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
2120 slot_id); | 1215 slot_id); |
2121 return var_result.value(); | 1216 return var_result.value(); |
2122 } | 1217 } |
2123 | 1218 |
2124 // static | 1219 // static |
2125 compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler, | |
2126 compiler::Node* left, | |
2127 compiler::Node* right, | |
2128 compiler::Node* context) { | |
2129 using compiler::Node; | |
2130 typedef CodeStubAssembler::Label Label; | |
2131 typedef CodeStubAssembler::Variable Variable; | |
2132 | |
2133 Variable var_result(assembler, MachineRepresentation::kTagged); | |
2134 Label return_result(assembler, &var_result); | |
2135 | |
2136 // Shared entry point for floating point modulus. | |
2137 Label do_fmod(assembler); | |
2138 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), | |
2139 var_divisor_float64(assembler, MachineRepresentation::kFloat64); | |
2140 | |
2141 Node* number_map = assembler->HeapNumberMapConstant(); | |
2142 | |
2143 // We might need to loop one or two times due to ToNumber conversions. | |
2144 Variable var_dividend(assembler, MachineRepresentation::kTagged), | |
2145 var_divisor(assembler, MachineRepresentation::kTagged); | |
2146 Variable* loop_variables[] = {&var_dividend, &var_divisor}; | |
2147 Label loop(assembler, 2, loop_variables); | |
2148 var_dividend.Bind(left); | |
2149 var_divisor.Bind(right); | |
2150 assembler->Goto(&loop); | |
2151 assembler->Bind(&loop); | |
2152 { | |
2153 Node* dividend = var_dividend.value(); | |
2154 Node* divisor = var_divisor.value(); | |
2155 | |
2156 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); | |
2157 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, | |
2158 ÷nd_is_not_smi); | |
2159 | |
2160 assembler->Bind(÷nd_is_smi); | |
2161 { | |
2162 Label dividend_is_not_zero(assembler); | |
2163 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
2164 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
2165 &divisor_is_not_smi); | |
2166 | |
2167 assembler->Bind(&divisor_is_smi); | |
2168 { | |
2169 // Compute the modulus of two Smis. | |
2170 var_result.Bind(assembler->SmiMod(dividend, divisor)); | |
2171 assembler->Goto(&return_result); | |
2172 } | |
2173 | |
2174 assembler->Bind(&divisor_is_not_smi); | |
2175 { | |
2176 Node* divisor_map = assembler->LoadMap(divisor); | |
2177 | |
2178 // Check if {divisor} is a HeapNumber. | |
2179 Label divisor_is_number(assembler), | |
2180 divisor_is_not_number(assembler, Label::kDeferred); | |
2181 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
2182 &divisor_is_number, &divisor_is_not_number); | |
2183 | |
2184 assembler->Bind(&divisor_is_number); | |
2185 { | |
2186 // Convert {dividend} to a double and compute its modulus with the | |
2187 // value of {dividend}. | |
2188 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); | |
2189 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
2190 assembler->Goto(&do_fmod); | |
2191 } | |
2192 | |
2193 assembler->Bind(&divisor_is_not_number); | |
2194 { | |
2195 // Convert {divisor} to a number and loop. | |
2196 Callable callable = | |
2197 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
2198 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
2199 assembler->Goto(&loop); | |
2200 } | |
2201 } | |
2202 } | |
2203 | |
2204 assembler->Bind(÷nd_is_not_smi); | |
2205 { | |
2206 Node* dividend_map = assembler->LoadMap(dividend); | |
2207 | |
2208 // Check if {dividend} is a HeapNumber. | |
2209 Label dividend_is_number(assembler), | |
2210 dividend_is_not_number(assembler, Label::kDeferred); | |
2211 assembler->Branch(assembler->WordEqual(dividend_map, number_map), | |
2212 ÷nd_is_number, ÷nd_is_not_number); | |
2213 | |
2214 assembler->Bind(÷nd_is_number); | |
2215 { | |
2216 // Check if {divisor} is a Smi. | |
2217 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); | |
2218 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, | |
2219 &divisor_is_not_smi); | |
2220 | |
2221 assembler->Bind(&divisor_is_smi); | |
2222 { | |
2223 // Convert {divisor} to a double and compute {dividend}'s modulus with | |
2224 // it. | |
2225 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
2226 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); | |
2227 assembler->Goto(&do_fmod); | |
2228 } | |
2229 | |
2230 assembler->Bind(&divisor_is_not_smi); | |
2231 { | |
2232 Node* divisor_map = assembler->LoadMap(divisor); | |
2233 | |
2234 // Check if {divisor} is a HeapNumber. | |
2235 Label divisor_is_number(assembler), | |
2236 divisor_is_not_number(assembler, Label::kDeferred); | |
2237 assembler->Branch(assembler->WordEqual(divisor_map, number_map), | |
2238 &divisor_is_number, &divisor_is_not_number); | |
2239 | |
2240 assembler->Bind(&divisor_is_number); | |
2241 { | |
2242 // Both {dividend} and {divisor} are HeapNumbers. Load their values | |
2243 // and compute their modulus. | |
2244 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); | |
2245 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); | |
2246 assembler->Goto(&do_fmod); | |
2247 } | |
2248 | |
2249 assembler->Bind(&divisor_is_not_number); | |
2250 { | |
2251 // Convert {divisor} to a number and loop. | |
2252 Callable callable = | |
2253 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
2254 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); | |
2255 assembler->Goto(&loop); | |
2256 } | |
2257 } | |
2258 } | |
2259 | |
2260 assembler->Bind(÷nd_is_not_number); | |
2261 { | |
2262 // Convert {dividend} to a Number and loop. | |
2263 Callable callable = | |
2264 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
2265 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); | |
2266 assembler->Goto(&loop); | |
2267 } | |
2268 } | |
2269 } | |
2270 | |
2271 assembler->Bind(&do_fmod); | |
2272 { | |
2273 Node* value = assembler->Float64Mod(var_dividend_float64.value(), | |
2274 var_divisor_float64.value()); | |
2275 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); | |
2276 assembler->Goto(&return_result); | |
2277 } | |
2278 | |
2279 assembler->Bind(&return_result); | |
2280 return var_result.value(); | |
2281 } | |
2282 | |
2283 // static | |
2284 compiler::Node* ModulusWithFeedbackStub::Generate( | 1220 compiler::Node* ModulusWithFeedbackStub::Generate( |
2285 CodeStubAssembler* assembler, compiler::Node* dividend, | 1221 CodeStubAssembler* assembler, compiler::Node* dividend, |
2286 compiler::Node* divisor, compiler::Node* slot_id, | 1222 compiler::Node* divisor, compiler::Node* slot_id, |
2287 compiler::Node* type_feedback_vector, compiler::Node* context) { | 1223 compiler::Node* type_feedback_vector, compiler::Node* context) { |
2288 using compiler::Node; | 1224 using compiler::Node; |
2289 typedef CodeStubAssembler::Label Label; | 1225 typedef CodeStubAssembler::Label Label; |
2290 typedef CodeStubAssembler::Variable Variable; | 1226 typedef CodeStubAssembler::Variable Variable; |
2291 | 1227 |
2292 // Shared entry point for floating point division. | 1228 // Shared entry point for floating point division. |
2293 Label do_fmod(assembler), end(assembler), call_modulus_stub(assembler); | 1229 Label do_fmod(assembler), end(assembler), call_modulus_stub(assembler); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2389 Callable callable = CodeFactory::Modulus(assembler->isolate()); | 1325 Callable callable = CodeFactory::Modulus(assembler->isolate()); |
2390 var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); | 1326 var_result.Bind(assembler->CallStub(callable, context, dividend, divisor)); |
2391 assembler->Goto(&end); | 1327 assembler->Goto(&end); |
2392 } | 1328 } |
2393 | 1329 |
2394 assembler->Bind(&end); | 1330 assembler->Bind(&end); |
2395 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, | 1331 assembler->UpdateFeedback(var_type_feedback.value(), type_feedback_vector, |
2396 slot_id); | 1332 slot_id); |
2397 return var_result.value(); | 1333 return var_result.value(); |
2398 } | 1334 } |
2399 // static | |
2400 compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler, | |
2401 compiler::Node* left, | |
2402 compiler::Node* right, | |
2403 compiler::Node* context) { | |
2404 using compiler::Node; | |
2405 | |
2406 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
2407 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
2408 Node* shift_count = | |
2409 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); | |
2410 Node* value = assembler->Word32Shl(lhs_value, shift_count); | |
2411 Node* result = assembler->ChangeInt32ToTagged(value); | |
2412 return result; | |
2413 } | |
2414 | |
2415 // static | |
2416 compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler, | |
2417 compiler::Node* left, | |
2418 compiler::Node* right, | |
2419 compiler::Node* context) { | |
2420 using compiler::Node; | |
2421 | |
2422 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
2423 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
2424 Node* shift_count = | |
2425 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); | |
2426 Node* value = assembler->Word32Sar(lhs_value, shift_count); | |
2427 Node* result = assembler->ChangeInt32ToTagged(value); | |
2428 return result; | |
2429 } | |
2430 | |
2431 // static | |
2432 compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler, | |
2433 compiler::Node* left, | |
2434 compiler::Node* right, | |
2435 compiler::Node* context) { | |
2436 using compiler::Node; | |
2437 | |
2438 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
2439 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
2440 Node* shift_count = | |
2441 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); | |
2442 Node* value = assembler->Word32Shr(lhs_value, shift_count); | |
2443 Node* result = assembler->ChangeUint32ToTagged(value); | |
2444 return result; | |
2445 } | |
2446 | |
2447 // static | |
2448 compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler, | |
2449 compiler::Node* left, | |
2450 compiler::Node* right, | |
2451 compiler::Node* context) { | |
2452 using compiler::Node; | |
2453 | |
2454 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
2455 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
2456 Node* value = assembler->Word32And(lhs_value, rhs_value); | |
2457 Node* result = assembler->ChangeInt32ToTagged(value); | |
2458 return result; | |
2459 } | |
2460 | |
2461 // static | |
2462 compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler, | |
2463 compiler::Node* left, | |
2464 compiler::Node* right, | |
2465 compiler::Node* context) { | |
2466 using compiler::Node; | |
2467 | |
2468 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
2469 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
2470 Node* value = assembler->Word32Or(lhs_value, rhs_value); | |
2471 Node* result = assembler->ChangeInt32ToTagged(value); | |
2472 return result; | |
2473 } | |
2474 | |
2475 // static | |
2476 compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler, | |
2477 compiler::Node* left, | |
2478 compiler::Node* right, | |
2479 compiler::Node* context) { | |
2480 using compiler::Node; | |
2481 | |
2482 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); | |
2483 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); | |
2484 Node* value = assembler->Word32Xor(lhs_value, rhs_value); | |
2485 Node* result = assembler->ChangeInt32ToTagged(value); | |
2486 return result; | |
2487 } | |
2488 | 1335 |
2489 // static | 1336 // static |
2490 compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, | 1337 compiler::Node* IncStub::Generate(CodeStubAssembler* assembler, |
2491 compiler::Node* value, | 1338 compiler::Node* value, |
2492 compiler::Node* context, | 1339 compiler::Node* context, |
2493 compiler::Node* type_feedback_vector, | 1340 compiler::Node* type_feedback_vector, |
2494 compiler::Node* slot_id) { | 1341 compiler::Node* slot_id) { |
2495 typedef CodeStubAssembler::Label Label; | 1342 typedef CodeStubAssembler::Label Label; |
2496 typedef compiler::Node Node; | 1343 typedef compiler::Node Node; |
2497 typedef CodeStubAssembler::Variable Variable; | 1344 typedef CodeStubAssembler::Variable Variable; |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2694 | 1541 |
2695 // ES6 section 21.1.3.19 String.prototype.substring ( start, end ) | 1542 // ES6 section 21.1.3.19 String.prototype.substring ( start, end ) |
2696 compiler::Node* SubStringStub::Generate(CodeStubAssembler* assembler, | 1543 compiler::Node* SubStringStub::Generate(CodeStubAssembler* assembler, |
2697 compiler::Node* string, | 1544 compiler::Node* string, |
2698 compiler::Node* from, | 1545 compiler::Node* from, |
2699 compiler::Node* to, | 1546 compiler::Node* to, |
2700 compiler::Node* context) { | 1547 compiler::Node* context) { |
2701 return assembler->SubString(context, string, from, to); | 1548 return assembler->SubString(context, string, from, to); |
2702 } | 1549 } |
2703 | 1550 |
2704 // ES6 section 7.1.13 ToObject (argument) | |
2705 void ToObjectStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
2706 typedef compiler::Node Node; | |
2707 typedef CodeStubAssembler::Label Label; | |
2708 typedef CodeStubAssembler::Variable Variable; | |
2709 | |
2710 Label if_number(assembler, Label::kDeferred), if_notsmi(assembler), | |
2711 if_jsreceiver(assembler), if_noconstructor(assembler, Label::kDeferred), | |
2712 if_wrapjsvalue(assembler); | |
2713 | |
2714 Node* object = assembler->Parameter(Descriptor::kArgument); | |
2715 Node* context = assembler->Parameter(Descriptor::kContext); | |
2716 | |
2717 Variable constructor_function_index_var(assembler, | |
2718 MachineType::PointerRepresentation()); | |
2719 | |
2720 assembler->Branch(assembler->WordIsSmi(object), &if_number, &if_notsmi); | |
2721 | |
2722 assembler->Bind(&if_notsmi); | |
2723 Node* map = assembler->LoadMap(object); | |
2724 | |
2725 assembler->GotoIf(assembler->IsHeapNumberMap(map), &if_number); | |
2726 | |
2727 Node* instance_type = assembler->LoadMapInstanceType(map); | |
2728 assembler->GotoIf(assembler->IsJSReceiverInstanceType(instance_type), | |
2729 &if_jsreceiver); | |
2730 | |
2731 Node* constructor_function_index = | |
2732 assembler->LoadMapConstructorFunctionIndex(map); | |
2733 assembler->GotoIf(assembler->WordEqual(constructor_function_index, | |
2734 assembler->IntPtrConstant( | |
2735 Map::kNoConstructorFunctionIndex)), | |
2736 &if_noconstructor); | |
2737 constructor_function_index_var.Bind(constructor_function_index); | |
2738 assembler->Goto(&if_wrapjsvalue); | |
2739 | |
2740 assembler->Bind(&if_number); | |
2741 constructor_function_index_var.Bind( | |
2742 assembler->IntPtrConstant(Context::NUMBER_FUNCTION_INDEX)); | |
2743 assembler->Goto(&if_wrapjsvalue); | |
2744 | |
2745 assembler->Bind(&if_wrapjsvalue); | |
2746 Node* native_context = assembler->LoadNativeContext(context); | |
2747 Node* constructor = assembler->LoadFixedArrayElement( | |
2748 native_context, constructor_function_index_var.value(), 0, | |
2749 CodeStubAssembler::INTPTR_PARAMETERS); | |
2750 Node* initial_map = assembler->LoadObjectField( | |
2751 constructor, JSFunction::kPrototypeOrInitialMapOffset); | |
2752 Node* js_value = assembler->Allocate(JSValue::kSize); | |
2753 assembler->StoreMapNoWriteBarrier(js_value, initial_map); | |
2754 assembler->StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset, | |
2755 Heap::kEmptyFixedArrayRootIndex); | |
2756 assembler->StoreObjectFieldRoot(js_value, JSObject::kElementsOffset, | |
2757 Heap::kEmptyFixedArrayRootIndex); | |
2758 assembler->StoreObjectField(js_value, JSValue::kValueOffset, object); | |
2759 assembler->Return(js_value); | |
2760 | |
2761 assembler->Bind(&if_noconstructor); | |
2762 assembler->TailCallRuntime( | |
2763 Runtime::kThrowUndefinedOrNullToObject, context, | |
2764 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | |
2765 "ToObject", TENURED))); | |
2766 | |
2767 assembler->Bind(&if_jsreceiver); | |
2768 assembler->Return(object); | |
2769 } | |
2770 | |
2771 // static | |
2772 // ES6 section 12.5.5 typeof operator | |
2773 compiler::Node* TypeofStub::Generate(CodeStubAssembler* assembler, | |
2774 compiler::Node* value, | |
2775 compiler::Node* context) { | |
2776 typedef compiler::Node Node; | |
2777 typedef CodeStubAssembler::Label Label; | |
2778 typedef CodeStubAssembler::Variable Variable; | |
2779 | |
2780 Variable result_var(assembler, MachineRepresentation::kTagged); | |
2781 | |
2782 Label return_number(assembler, Label::kDeferred), if_oddball(assembler), | |
2783 return_function(assembler), return_undefined(assembler), | |
2784 return_object(assembler), return_string(assembler), | |
2785 return_result(assembler); | |
2786 | |
2787 assembler->GotoIf(assembler->WordIsSmi(value), &return_number); | |
2788 | |
2789 Node* map = assembler->LoadMap(value); | |
2790 | |
2791 assembler->GotoIf(assembler->IsHeapNumberMap(map), &return_number); | |
2792 | |
2793 Node* instance_type = assembler->LoadMapInstanceType(map); | |
2794 | |
2795 assembler->GotoIf(assembler->Word32Equal( | |
2796 instance_type, assembler->Int32Constant(ODDBALL_TYPE)), | |
2797 &if_oddball); | |
2798 | |
2799 Node* callable_or_undetectable_mask = | |
2800 assembler->Word32And(assembler->LoadMapBitField(map), | |
2801 assembler->Int32Constant(1 << Map::kIsCallable | | |
2802 1 << Map::kIsUndetectable)); | |
2803 | |
2804 assembler->GotoIf( | |
2805 assembler->Word32Equal(callable_or_undetectable_mask, | |
2806 assembler->Int32Constant(1 << Map::kIsCallable)), | |
2807 &return_function); | |
2808 | |
2809 assembler->GotoUnless(assembler->Word32Equal(callable_or_undetectable_mask, | |
2810 assembler->Int32Constant(0)), | |
2811 &return_undefined); | |
2812 | |
2813 assembler->GotoIf(assembler->IsJSReceiverInstanceType(instance_type), | |
2814 &return_object); | |
2815 | |
2816 assembler->GotoIf(assembler->IsStringInstanceType(instance_type), | |
2817 &return_string); | |
2818 | |
2819 #define SIMD128_BRANCH(TYPE, Type, type, lane_count, lane_type) \ | |
2820 Label return_##type(assembler); \ | |
2821 Node* type##_map = \ | |
2822 assembler->HeapConstant(assembler->factory()->type##_map()); \ | |
2823 assembler->GotoIf(assembler->WordEqual(map, type##_map), &return_##type); | |
2824 SIMD128_TYPES(SIMD128_BRANCH) | |
2825 #undef SIMD128_BRANCH | |
2826 | |
2827 assembler->Assert(assembler->Word32Equal( | |
2828 instance_type, assembler->Int32Constant(SYMBOL_TYPE))); | |
2829 result_var.Bind(assembler->HeapConstant( | |
2830 assembler->isolate()->factory()->symbol_string())); | |
2831 assembler->Goto(&return_result); | |
2832 | |
2833 assembler->Bind(&return_number); | |
2834 { | |
2835 result_var.Bind(assembler->HeapConstant( | |
2836 assembler->isolate()->factory()->number_string())); | |
2837 assembler->Goto(&return_result); | |
2838 } | |
2839 | |
2840 assembler->Bind(&if_oddball); | |
2841 { | |
2842 Node* type = assembler->LoadObjectField(value, Oddball::kTypeOfOffset); | |
2843 result_var.Bind(type); | |
2844 assembler->Goto(&return_result); | |
2845 } | |
2846 | |
2847 assembler->Bind(&return_function); | |
2848 { | |
2849 result_var.Bind(assembler->HeapConstant( | |
2850 assembler->isolate()->factory()->function_string())); | |
2851 assembler->Goto(&return_result); | |
2852 } | |
2853 | |
2854 assembler->Bind(&return_undefined); | |
2855 { | |
2856 result_var.Bind(assembler->HeapConstant( | |
2857 assembler->isolate()->factory()->undefined_string())); | |
2858 assembler->Goto(&return_result); | |
2859 } | |
2860 | |
2861 assembler->Bind(&return_object); | |
2862 { | |
2863 result_var.Bind(assembler->HeapConstant( | |
2864 assembler->isolate()->factory()->object_string())); | |
2865 assembler->Goto(&return_result); | |
2866 } | |
2867 | |
2868 assembler->Bind(&return_string); | |
2869 { | |
2870 result_var.Bind(assembler->HeapConstant( | |
2871 assembler->isolate()->factory()->string_string())); | |
2872 assembler->Goto(&return_result); | |
2873 } | |
2874 | |
2875 #define SIMD128_BIND_RETURN(TYPE, Type, type, lane_count, lane_type) \ | |
2876 assembler->Bind(&return_##type); \ | |
2877 { \ | |
2878 result_var.Bind(assembler->HeapConstant( \ | |
2879 assembler->isolate()->factory()->type##_string())); \ | |
2880 assembler->Goto(&return_result); \ | |
2881 } | |
2882 SIMD128_TYPES(SIMD128_BIND_RETURN) | |
2883 #undef SIMD128_BIND_RETURN | |
2884 | |
2885 assembler->Bind(&return_result); | |
2886 return result_var.value(); | |
2887 } | |
2888 | |
2889 // static | |
2890 compiler::Node* InstanceOfStub::Generate(CodeStubAssembler* assembler, | |
2891 compiler::Node* object, | |
2892 compiler::Node* callable, | |
2893 compiler::Node* context) { | |
2894 typedef CodeStubAssembler::Label Label; | |
2895 typedef CodeStubAssembler::Variable Variable; | |
2896 | |
2897 Label return_runtime(assembler, Label::kDeferred), end(assembler); | |
2898 Variable result(assembler, MachineRepresentation::kTagged); | |
2899 | |
2900 // Check if no one installed @@hasInstance somewhere. | |
2901 assembler->GotoUnless( | |
2902 assembler->WordEqual( | |
2903 assembler->LoadObjectField( | |
2904 assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex), | |
2905 PropertyCell::kValueOffset), | |
2906 assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), | |
2907 &return_runtime); | |
2908 | |
2909 // Check if {callable} is a valid receiver. | |
2910 assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime); | |
2911 assembler->GotoIf( | |
2912 assembler->Word32Equal( | |
2913 assembler->Word32And( | |
2914 assembler->LoadMapBitField(assembler->LoadMap(callable)), | |
2915 assembler->Int32Constant(1 << Map::kIsCallable)), | |
2916 assembler->Int32Constant(0)), | |
2917 &return_runtime); | |
2918 | |
2919 // Use the inline OrdinaryHasInstance directly. | |
2920 result.Bind(assembler->OrdinaryHasInstance(context, callable, object)); | |
2921 assembler->Goto(&end); | |
2922 | |
2923 // TODO(bmeurer): Use GetPropertyStub here once available. | |
2924 assembler->Bind(&return_runtime); | |
2925 { | |
2926 result.Bind(assembler->CallRuntime(Runtime::kInstanceOf, context, object, | |
2927 callable)); | |
2928 assembler->Goto(&end); | |
2929 } | |
2930 | |
2931 assembler->Bind(&end); | |
2932 return result.value(); | |
2933 } | |
2934 | |
2935 namespace { | |
2936 | |
2937 enum RelationalComparisonMode { | |
2938 kLessThan, | |
2939 kLessThanOrEqual, | |
2940 kGreaterThan, | |
2941 kGreaterThanOrEqual | |
2942 }; | |
2943 | |
2944 compiler::Node* GenerateAbstractRelationalComparison( | |
2945 CodeStubAssembler* assembler, RelationalComparisonMode mode, | |
2946 compiler::Node* lhs, compiler::Node* rhs, compiler::Node* context) { | |
2947 typedef CodeStubAssembler::Label Label; | |
2948 typedef compiler::Node Node; | |
2949 typedef CodeStubAssembler::Variable Variable; | |
2950 | |
2951 Label return_true(assembler), return_false(assembler), end(assembler); | |
2952 Variable result(assembler, MachineRepresentation::kTagged); | |
2953 | |
2954 // Shared entry for floating point comparison. | |
2955 Label do_fcmp(assembler); | |
2956 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), | |
2957 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); | |
2958 | |
2959 // We might need to loop several times due to ToPrimitive and/or ToNumber | |
2960 // conversions. | |
2961 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
2962 var_rhs(assembler, MachineRepresentation::kTagged); | |
2963 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
2964 Label loop(assembler, 2, loop_vars); | |
2965 var_lhs.Bind(lhs); | |
2966 var_rhs.Bind(rhs); | |
2967 assembler->Goto(&loop); | |
2968 assembler->Bind(&loop); | |
2969 { | |
2970 // Load the current {lhs} and {rhs} values. | |
2971 lhs = var_lhs.value(); | |
2972 rhs = var_rhs.value(); | |
2973 | |
2974 // Check if the {lhs} is a Smi or a HeapObject. | |
2975 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
2976 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
2977 | |
2978 assembler->Bind(&if_lhsissmi); | |
2979 { | |
2980 // Check if {rhs} is a Smi or a HeapObject. | |
2981 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
2982 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
2983 &if_rhsisnotsmi); | |
2984 | |
2985 assembler->Bind(&if_rhsissmi); | |
2986 { | |
2987 // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison. | |
2988 switch (mode) { | |
2989 case kLessThan: | |
2990 assembler->BranchIfSmiLessThan(lhs, rhs, &return_true, | |
2991 &return_false); | |
2992 break; | |
2993 case kLessThanOrEqual: | |
2994 assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true, | |
2995 &return_false); | |
2996 break; | |
2997 case kGreaterThan: | |
2998 assembler->BranchIfSmiLessThan(rhs, lhs, &return_true, | |
2999 &return_false); | |
3000 break; | |
3001 case kGreaterThanOrEqual: | |
3002 assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true, | |
3003 &return_false); | |
3004 break; | |
3005 } | |
3006 } | |
3007 | |
3008 assembler->Bind(&if_rhsisnotsmi); | |
3009 { | |
3010 // Load the map of {rhs}. | |
3011 Node* rhs_map = assembler->LoadMap(rhs); | |
3012 | |
3013 // Check if the {rhs} is a HeapNumber. | |
3014 Label if_rhsisnumber(assembler), | |
3015 if_rhsisnotnumber(assembler, Label::kDeferred); | |
3016 assembler->Branch(assembler->IsHeapNumberMap(rhs_map), &if_rhsisnumber, | |
3017 &if_rhsisnotnumber); | |
3018 | |
3019 assembler->Bind(&if_rhsisnumber); | |
3020 { | |
3021 // Convert the {lhs} and {rhs} to floating point values, and | |
3022 // perform a floating point comparison. | |
3023 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
3024 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
3025 assembler->Goto(&do_fcmp); | |
3026 } | |
3027 | |
3028 assembler->Bind(&if_rhsisnotnumber); | |
3029 { | |
3030 // Convert the {rhs} to a Number; we don't need to perform the | |
3031 // dedicated ToPrimitive(rhs, hint Number) operation, as the | |
3032 // ToNumber(rhs) will by itself already invoke ToPrimitive with | |
3033 // a Number hint. | |
3034 Callable callable = | |
3035 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
3036 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3037 assembler->Goto(&loop); | |
3038 } | |
3039 } | |
3040 } | |
3041 | |
3042 assembler->Bind(&if_lhsisnotsmi); | |
3043 { | |
3044 // Load the HeapNumber map for later comparisons. | |
3045 Node* number_map = assembler->HeapNumberMapConstant(); | |
3046 | |
3047 // Load the map of {lhs}. | |
3048 Node* lhs_map = assembler->LoadMap(lhs); | |
3049 | |
3050 // Check if {rhs} is a Smi or a HeapObject. | |
3051 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
3052 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
3053 &if_rhsisnotsmi); | |
3054 | |
3055 assembler->Bind(&if_rhsissmi); | |
3056 { | |
3057 // Check if the {lhs} is a HeapNumber. | |
3058 Label if_lhsisnumber(assembler), | |
3059 if_lhsisnotnumber(assembler, Label::kDeferred); | |
3060 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
3061 &if_lhsisnumber, &if_lhsisnotnumber); | |
3062 | |
3063 assembler->Bind(&if_lhsisnumber); | |
3064 { | |
3065 // Convert the {lhs} and {rhs} to floating point values, and | |
3066 // perform a floating point comparison. | |
3067 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
3068 var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs)); | |
3069 assembler->Goto(&do_fcmp); | |
3070 } | |
3071 | |
3072 assembler->Bind(&if_lhsisnotnumber); | |
3073 { | |
3074 // Convert the {lhs} to a Number; we don't need to perform the | |
3075 // dedicated ToPrimitive(lhs, hint Number) operation, as the | |
3076 // ToNumber(lhs) will by itself already invoke ToPrimitive with | |
3077 // a Number hint. | |
3078 Callable callable = | |
3079 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
3080 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
3081 assembler->Goto(&loop); | |
3082 } | |
3083 } | |
3084 | |
3085 assembler->Bind(&if_rhsisnotsmi); | |
3086 { | |
3087 // Load the map of {rhs}. | |
3088 Node* rhs_map = assembler->LoadMap(rhs); | |
3089 | |
3090 // Check if {lhs} is a HeapNumber. | |
3091 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
3092 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
3093 &if_lhsisnumber, &if_lhsisnotnumber); | |
3094 | |
3095 assembler->Bind(&if_lhsisnumber); | |
3096 { | |
3097 // Check if {rhs} is also a HeapNumber. | |
3098 Label if_rhsisnumber(assembler), | |
3099 if_rhsisnotnumber(assembler, Label::kDeferred); | |
3100 assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), | |
3101 &if_rhsisnumber, &if_rhsisnotnumber); | |
3102 | |
3103 assembler->Bind(&if_rhsisnumber); | |
3104 { | |
3105 // Convert the {lhs} and {rhs} to floating point values, and | |
3106 // perform a floating point comparison. | |
3107 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
3108 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
3109 assembler->Goto(&do_fcmp); | |
3110 } | |
3111 | |
3112 assembler->Bind(&if_rhsisnotnumber); | |
3113 { | |
3114 // Convert the {rhs} to a Number; we don't need to perform | |
3115 // dedicated ToPrimitive(rhs, hint Number) operation, as the | |
3116 // ToNumber(rhs) will by itself already invoke ToPrimitive with | |
3117 // a Number hint. | |
3118 Callable callable = | |
3119 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
3120 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3121 assembler->Goto(&loop); | |
3122 } | |
3123 } | |
3124 | |
3125 assembler->Bind(&if_lhsisnotnumber); | |
3126 { | |
3127 // Load the instance type of {lhs}. | |
3128 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | |
3129 | |
3130 // Check if {lhs} is a String. | |
3131 Label if_lhsisstring(assembler), | |
3132 if_lhsisnotstring(assembler, Label::kDeferred); | |
3133 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), | |
3134 &if_lhsisstring, &if_lhsisnotstring); | |
3135 | |
3136 assembler->Bind(&if_lhsisstring); | |
3137 { | |
3138 // Load the instance type of {rhs}. | |
3139 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
3140 | |
3141 // Check if {rhs} is also a String. | |
3142 Label if_rhsisstring(assembler, Label::kDeferred), | |
3143 if_rhsisnotstring(assembler, Label::kDeferred); | |
3144 assembler->Branch( | |
3145 assembler->IsStringInstanceType(rhs_instance_type), | |
3146 &if_rhsisstring, &if_rhsisnotstring); | |
3147 | |
3148 assembler->Bind(&if_rhsisstring); | |
3149 { | |
3150 // Both {lhs} and {rhs} are strings. | |
3151 switch (mode) { | |
3152 case kLessThan: | |
3153 result.Bind(assembler->CallStub( | |
3154 CodeFactory::StringLessThan(assembler->isolate()), | |
3155 context, lhs, rhs)); | |
3156 assembler->Goto(&end); | |
3157 break; | |
3158 case kLessThanOrEqual: | |
3159 result.Bind(assembler->CallStub( | |
3160 CodeFactory::StringLessThanOrEqual(assembler->isolate()), | |
3161 context, lhs, rhs)); | |
3162 assembler->Goto(&end); | |
3163 break; | |
3164 case kGreaterThan: | |
3165 result.Bind(assembler->CallStub( | |
3166 CodeFactory::StringGreaterThan(assembler->isolate()), | |
3167 context, lhs, rhs)); | |
3168 assembler->Goto(&end); | |
3169 break; | |
3170 case kGreaterThanOrEqual: | |
3171 result.Bind( | |
3172 assembler->CallStub(CodeFactory::StringGreaterThanOrEqual( | |
3173 assembler->isolate()), | |
3174 context, lhs, rhs)); | |
3175 assembler->Goto(&end); | |
3176 break; | |
3177 } | |
3178 } | |
3179 | |
3180 assembler->Bind(&if_rhsisnotstring); | |
3181 { | |
3182 // The {lhs} is a String, while {rhs} is neither a Number nor a | |
3183 // String, so we need to call ToPrimitive(rhs, hint Number) if | |
3184 // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the | |
3185 // other cases. | |
3186 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
3187 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
3188 if_rhsisnotreceiver(assembler, Label::kDeferred); | |
3189 assembler->Branch( | |
3190 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
3191 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
3192 | |
3193 assembler->Bind(&if_rhsisreceiver); | |
3194 { | |
3195 // Convert {rhs} to a primitive first passing Number hint. | |
3196 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
3197 assembler->isolate(), ToPrimitiveHint::kNumber); | |
3198 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3199 assembler->Goto(&loop); | |
3200 } | |
3201 | |
3202 assembler->Bind(&if_rhsisnotreceiver); | |
3203 { | |
3204 // Convert both {lhs} and {rhs} to Number. | |
3205 Callable callable = CodeFactory::ToNumber(assembler->isolate()); | |
3206 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
3207 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3208 assembler->Goto(&loop); | |
3209 } | |
3210 } | |
3211 } | |
3212 | |
3213 assembler->Bind(&if_lhsisnotstring); | |
3214 { | |
3215 // The {lhs} is neither a Number nor a String, so we need to call | |
3216 // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or | |
3217 // ToNumber(lhs) and ToNumber(rhs) in the other cases. | |
3218 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
3219 Label if_lhsisreceiver(assembler, Label::kDeferred), | |
3220 if_lhsisnotreceiver(assembler, Label::kDeferred); | |
3221 assembler->Branch( | |
3222 assembler->IsJSReceiverInstanceType(lhs_instance_type), | |
3223 &if_lhsisreceiver, &if_lhsisnotreceiver); | |
3224 | |
3225 assembler->Bind(&if_lhsisreceiver); | |
3226 { | |
3227 // Convert {lhs} to a primitive first passing Number hint. | |
3228 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
3229 assembler->isolate(), ToPrimitiveHint::kNumber); | |
3230 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
3231 assembler->Goto(&loop); | |
3232 } | |
3233 | |
3234 assembler->Bind(&if_lhsisnotreceiver); | |
3235 { | |
3236 // Convert both {lhs} and {rhs} to Number. | |
3237 Callable callable = CodeFactory::ToNumber(assembler->isolate()); | |
3238 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
3239 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3240 assembler->Goto(&loop); | |
3241 } | |
3242 } | |
3243 } | |
3244 } | |
3245 } | |
3246 } | |
3247 | |
3248 assembler->Bind(&do_fcmp); | |
3249 { | |
3250 // Load the {lhs} and {rhs} floating point values. | |
3251 Node* lhs = var_fcmp_lhs.value(); | |
3252 Node* rhs = var_fcmp_rhs.value(); | |
3253 | |
3254 // Perform a fast floating point comparison. | |
3255 switch (mode) { | |
3256 case kLessThan: | |
3257 assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true, | |
3258 &return_false); | |
3259 break; | |
3260 case kLessThanOrEqual: | |
3261 assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true, | |
3262 &return_false); | |
3263 break; | |
3264 case kGreaterThan: | |
3265 assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true, | |
3266 &return_false); | |
3267 break; | |
3268 case kGreaterThanOrEqual: | |
3269 assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true, | |
3270 &return_false); | |
3271 break; | |
3272 } | |
3273 } | |
3274 | |
3275 assembler->Bind(&return_true); | |
3276 { | |
3277 result.Bind(assembler->BooleanConstant(true)); | |
3278 assembler->Goto(&end); | |
3279 } | |
3280 | |
3281 assembler->Bind(&return_false); | |
3282 { | |
3283 result.Bind(assembler->BooleanConstant(false)); | |
3284 assembler->Goto(&end); | |
3285 } | |
3286 | |
3287 assembler->Bind(&end); | |
3288 return result.value(); | |
3289 } | |
3290 | |
3291 enum ResultMode { kDontNegateResult, kNegateResult }; | |
3292 | |
3293 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value, | |
3294 CodeStubAssembler::Label* if_equal, | |
3295 CodeStubAssembler::Label* if_notequal) { | |
3296 // In case of abstract or strict equality checks, we need additional checks | |
3297 // for NaN values because they are not considered equal, even if both the | |
3298 // left and the right hand side reference exactly the same value. | |
3299 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it | |
3300 // seems to be what is tested in the current SIMD.js testsuite. | |
3301 | |
3302 typedef CodeStubAssembler::Label Label; | |
3303 typedef compiler::Node Node; | |
3304 | |
3305 // Check if {value} is a Smi or a HeapObject. | |
3306 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | |
3307 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, | |
3308 &if_valueisnotsmi); | |
3309 | |
3310 assembler->Bind(&if_valueisnotsmi); | |
3311 { | |
3312 // Load the map of {value}. | |
3313 Node* value_map = assembler->LoadMap(value); | |
3314 | |
3315 // Check if {value} (and therefore {rhs}) is a HeapNumber. | |
3316 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); | |
3317 assembler->Branch(assembler->IsHeapNumberMap(value_map), &if_valueisnumber, | |
3318 &if_valueisnotnumber); | |
3319 | |
3320 assembler->Bind(&if_valueisnumber); | |
3321 { | |
3322 // Convert {value} (and therefore {rhs}) to floating point value. | |
3323 Node* value_value = assembler->LoadHeapNumberValue(value); | |
3324 | |
3325 // Check if the HeapNumber value is a NaN. | |
3326 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); | |
3327 } | |
3328 | |
3329 assembler->Bind(&if_valueisnotnumber); | |
3330 assembler->Goto(if_equal); | |
3331 } | |
3332 | |
3333 assembler->Bind(&if_valueissmi); | |
3334 assembler->Goto(if_equal); | |
3335 } | |
3336 | |
3337 void GenerateEqual_Simd128Value_HeapObject( | |
3338 CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map, | |
3339 compiler::Node* rhs, compiler::Node* rhs_map, | |
3340 CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) { | |
3341 assembler->BranchIfSimd128Equal(lhs, lhs_map, rhs, rhs_map, if_equal, | |
3342 if_notequal); | |
3343 } | |
3344 | |
3345 // ES6 section 7.2.12 Abstract Equality Comparison | |
3346 compiler::Node* GenerateEqual(CodeStubAssembler* assembler, ResultMode mode, | |
3347 compiler::Node* lhs, compiler::Node* rhs, | |
3348 compiler::Node* context) { | |
3349 // This is a slightly optimized version of Object::Equals represented as | |
3350 // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you | |
3351 // change something functionality wise in here, remember to update the | |
3352 // Object::Equals method as well. | |
3353 typedef CodeStubAssembler::Label Label; | |
3354 typedef compiler::Node Node; | |
3355 typedef CodeStubAssembler::Variable Variable; | |
3356 | |
3357 Label if_equal(assembler), if_notequal(assembler), | |
3358 do_rhsstringtonumber(assembler, Label::kDeferred), end(assembler); | |
3359 Variable result(assembler, MachineRepresentation::kTagged); | |
3360 | |
3361 // Shared entry for floating point comparison. | |
3362 Label do_fcmp(assembler); | |
3363 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), | |
3364 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); | |
3365 | |
3366 // We might need to loop several times due to ToPrimitive and/or ToNumber | |
3367 // conversions. | |
3368 Variable var_lhs(assembler, MachineRepresentation::kTagged), | |
3369 var_rhs(assembler, MachineRepresentation::kTagged); | |
3370 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | |
3371 Label loop(assembler, 2, loop_vars); | |
3372 var_lhs.Bind(lhs); | |
3373 var_rhs.Bind(rhs); | |
3374 assembler->Goto(&loop); | |
3375 assembler->Bind(&loop); | |
3376 { | |
3377 // Load the current {lhs} and {rhs} values. | |
3378 lhs = var_lhs.value(); | |
3379 rhs = var_rhs.value(); | |
3380 | |
3381 // Check if {lhs} and {rhs} refer to the same object. | |
3382 Label if_same(assembler), if_notsame(assembler); | |
3383 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
3384 | |
3385 assembler->Bind(&if_same); | |
3386 { | |
3387 // The {lhs} and {rhs} reference the exact same value, yet we need special | |
3388 // treatment for HeapNumber, as NaN is not equal to NaN. | |
3389 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); | |
3390 } | |
3391 | |
3392 assembler->Bind(&if_notsame); | |
3393 { | |
3394 // Check if {lhs} is a Smi or a HeapObject. | |
3395 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
3396 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, | |
3397 &if_lhsisnotsmi); | |
3398 | |
3399 assembler->Bind(&if_lhsissmi); | |
3400 { | |
3401 // Check if {rhs} is a Smi or a HeapObject. | |
3402 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
3403 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
3404 &if_rhsisnotsmi); | |
3405 | |
3406 assembler->Bind(&if_rhsissmi); | |
3407 // We have already checked for {lhs} and {rhs} being the same value, so | |
3408 // if both are Smis when we get here they must not be equal. | |
3409 assembler->Goto(&if_notequal); | |
3410 | |
3411 assembler->Bind(&if_rhsisnotsmi); | |
3412 { | |
3413 // Load the map of {rhs}. | |
3414 Node* rhs_map = assembler->LoadMap(rhs); | |
3415 | |
3416 // Check if {rhs} is a HeapNumber. | |
3417 Node* number_map = assembler->HeapNumberMapConstant(); | |
3418 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
3419 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
3420 &if_rhsisnumber, &if_rhsisnotnumber); | |
3421 | |
3422 assembler->Bind(&if_rhsisnumber); | |
3423 { | |
3424 // Convert {lhs} and {rhs} to floating point values, and | |
3425 // perform a floating point comparison. | |
3426 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); | |
3427 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
3428 assembler->Goto(&do_fcmp); | |
3429 } | |
3430 | |
3431 assembler->Bind(&if_rhsisnotnumber); | |
3432 { | |
3433 // Load the instance type of the {rhs}. | |
3434 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
3435 | |
3436 // Check if the {rhs} is a String. | |
3437 Label if_rhsisstring(assembler, Label::kDeferred), | |
3438 if_rhsisnotstring(assembler); | |
3439 assembler->Branch( | |
3440 assembler->IsStringInstanceType(rhs_instance_type), | |
3441 &if_rhsisstring, &if_rhsisnotstring); | |
3442 | |
3443 assembler->Bind(&if_rhsisstring); | |
3444 { | |
3445 // The {rhs} is a String and the {lhs} is a Smi; we need | |
3446 // to convert the {rhs} to a Number and compare the output to | |
3447 // the Number on the {lhs}. | |
3448 assembler->Goto(&do_rhsstringtonumber); | |
3449 } | |
3450 | |
3451 assembler->Bind(&if_rhsisnotstring); | |
3452 { | |
3453 // Check if the {rhs} is a Boolean. | |
3454 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); | |
3455 assembler->Branch(assembler->IsBooleanMap(rhs_map), | |
3456 &if_rhsisboolean, &if_rhsisnotboolean); | |
3457 | |
3458 assembler->Bind(&if_rhsisboolean); | |
3459 { | |
3460 // The {rhs} is a Boolean, load its number value. | |
3461 var_rhs.Bind( | |
3462 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset)); | |
3463 assembler->Goto(&loop); | |
3464 } | |
3465 | |
3466 assembler->Bind(&if_rhsisnotboolean); | |
3467 { | |
3468 // Check if the {rhs} is a Receiver. | |
3469 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
3470 Label if_rhsisreceiver(assembler, Label::kDeferred), | |
3471 if_rhsisnotreceiver(assembler); | |
3472 assembler->Branch( | |
3473 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
3474 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
3475 | |
3476 assembler->Bind(&if_rhsisreceiver); | |
3477 { | |
3478 // Convert {rhs} to a primitive first (passing no hint). | |
3479 Callable callable = CodeFactory::NonPrimitiveToPrimitive( | |
3480 assembler->isolate()); | |
3481 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3482 assembler->Goto(&loop); | |
3483 } | |
3484 | |
3485 assembler->Bind(&if_rhsisnotreceiver); | |
3486 assembler->Goto(&if_notequal); | |
3487 } | |
3488 } | |
3489 } | |
3490 } | |
3491 } | |
3492 | |
3493 assembler->Bind(&if_lhsisnotsmi); | |
3494 { | |
3495 // Check if {rhs} is a Smi or a HeapObject. | |
3496 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
3497 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
3498 &if_rhsisnotsmi); | |
3499 | |
3500 assembler->Bind(&if_rhsissmi); | |
3501 { | |
3502 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} | |
3503 // and {rhs} is not observable and doesn't matter for the result, so | |
3504 // we can just swap them and use the Smi handling above (for {lhs} | |
3505 // being a Smi). | |
3506 var_lhs.Bind(rhs); | |
3507 var_rhs.Bind(lhs); | |
3508 assembler->Goto(&loop); | |
3509 } | |
3510 | |
3511 assembler->Bind(&if_rhsisnotsmi); | |
3512 { | |
3513 Label if_lhsisstring(assembler), if_lhsisnumber(assembler), | |
3514 if_lhsissymbol(assembler), if_lhsissimd128value(assembler), | |
3515 if_lhsisoddball(assembler), if_lhsisreceiver(assembler); | |
3516 | |
3517 // Both {lhs} and {rhs} are HeapObjects, load their maps | |
3518 // and their instance types. | |
3519 Node* lhs_map = assembler->LoadMap(lhs); | |
3520 Node* rhs_map = assembler->LoadMap(rhs); | |
3521 | |
3522 // Load the instance types of {lhs} and {rhs}. | |
3523 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | |
3524 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); | |
3525 | |
3526 // Dispatch based on the instance type of {lhs}. | |
3527 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; | |
3528 Label* case_labels[kNumCases]; | |
3529 int32_t case_values[kNumCases]; | |
3530 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { | |
3531 case_labels[i] = new Label(assembler); | |
3532 case_values[i] = i; | |
3533 } | |
3534 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; | |
3535 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; | |
3536 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; | |
3537 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; | |
3538 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; | |
3539 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; | |
3540 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; | |
3541 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; | |
3542 assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values, | |
3543 case_labels, arraysize(case_values)); | |
3544 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { | |
3545 assembler->Bind(case_labels[i]); | |
3546 assembler->Goto(&if_lhsisstring); | |
3547 delete case_labels[i]; | |
3548 } | |
3549 | |
3550 assembler->Bind(&if_lhsisstring); | |
3551 { | |
3552 // Check if {rhs} is also a String. | |
3553 Label if_rhsisstring(assembler, Label::kDeferred), | |
3554 if_rhsisnotstring(assembler); | |
3555 assembler->Branch( | |
3556 assembler->IsStringInstanceType(rhs_instance_type), | |
3557 &if_rhsisstring, &if_rhsisnotstring); | |
3558 | |
3559 assembler->Bind(&if_rhsisstring); | |
3560 { | |
3561 // Both {lhs} and {rhs} are of type String, just do the | |
3562 // string comparison then. | |
3563 Callable callable = | |
3564 (mode == kDontNegateResult) | |
3565 ? CodeFactory::StringEqual(assembler->isolate()) | |
3566 : CodeFactory::StringNotEqual(assembler->isolate()); | |
3567 result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | |
3568 assembler->Goto(&end); | |
3569 } | |
3570 | |
3571 assembler->Bind(&if_rhsisnotstring); | |
3572 { | |
3573 // The {lhs} is a String and the {rhs} is some other HeapObject. | |
3574 // Swapping {lhs} and {rhs} is not observable and doesn't matter | |
3575 // for the result, so we can just swap them and use the String | |
3576 // handling below (for {rhs} being a String). | |
3577 var_lhs.Bind(rhs); | |
3578 var_rhs.Bind(lhs); | |
3579 assembler->Goto(&loop); | |
3580 } | |
3581 } | |
3582 | |
3583 assembler->Bind(&if_lhsisnumber); | |
3584 { | |
3585 // Check if {rhs} is also a HeapNumber. | |
3586 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
3587 assembler->Branch( | |
3588 assembler->Word32Equal(lhs_instance_type, rhs_instance_type), | |
3589 &if_rhsisnumber, &if_rhsisnotnumber); | |
3590 | |
3591 assembler->Bind(&if_rhsisnumber); | |
3592 { | |
3593 // Convert {lhs} and {rhs} to floating point values, and | |
3594 // perform a floating point comparison. | |
3595 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); | |
3596 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); | |
3597 assembler->Goto(&do_fcmp); | |
3598 } | |
3599 | |
3600 assembler->Bind(&if_rhsisnotnumber); | |
3601 { | |
3602 // The {lhs} is a Number, the {rhs} is some other HeapObject. | |
3603 Label if_rhsisstring(assembler, Label::kDeferred), | |
3604 if_rhsisnotstring(assembler); | |
3605 assembler->Branch( | |
3606 assembler->IsStringInstanceType(rhs_instance_type), | |
3607 &if_rhsisstring, &if_rhsisnotstring); | |
3608 | |
3609 assembler->Bind(&if_rhsisstring); | |
3610 { | |
3611 // The {rhs} is a String and the {lhs} is a HeapNumber; we need | |
3612 // to convert the {rhs} to a Number and compare the output to | |
3613 // the Number on the {lhs}. | |
3614 assembler->Goto(&do_rhsstringtonumber); | |
3615 } | |
3616 | |
3617 assembler->Bind(&if_rhsisnotstring); | |
3618 { | |
3619 // Check if the {rhs} is a JSReceiver. | |
3620 Label if_rhsisreceiver(assembler), | |
3621 if_rhsisnotreceiver(assembler); | |
3622 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
3623 assembler->Branch( | |
3624 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
3625 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
3626 | |
3627 assembler->Bind(&if_rhsisreceiver); | |
3628 { | |
3629 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. | |
3630 // Swapping {lhs} and {rhs} is not observable and doesn't | |
3631 // matter for the result, so we can just swap them and use | |
3632 // the JSReceiver handling below (for {lhs} being a | |
3633 // JSReceiver). | |
3634 var_lhs.Bind(rhs); | |
3635 var_rhs.Bind(lhs); | |
3636 assembler->Goto(&loop); | |
3637 } | |
3638 | |
3639 assembler->Bind(&if_rhsisnotreceiver); | |
3640 { | |
3641 // Check if {rhs} is a Boolean. | |
3642 Label if_rhsisboolean(assembler), | |
3643 if_rhsisnotboolean(assembler); | |
3644 assembler->Branch(assembler->IsBooleanMap(rhs_map), | |
3645 &if_rhsisboolean, &if_rhsisnotboolean); | |
3646 | |
3647 assembler->Bind(&if_rhsisboolean); | |
3648 { | |
3649 // The {rhs} is a Boolean, convert it to a Smi first. | |
3650 var_rhs.Bind(assembler->LoadObjectField( | |
3651 rhs, Oddball::kToNumberOffset)); | |
3652 assembler->Goto(&loop); | |
3653 } | |
3654 | |
3655 assembler->Bind(&if_rhsisnotboolean); | |
3656 assembler->Goto(&if_notequal); | |
3657 } | |
3658 } | |
3659 } | |
3660 } | |
3661 | |
3662 assembler->Bind(&if_lhsisoddball); | |
3663 { | |
3664 // The {lhs} is an Oddball and {rhs} is some other HeapObject. | |
3665 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler); | |
3666 Node* boolean_map = assembler->BooleanMapConstant(); | |
3667 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map), | |
3668 &if_lhsisboolean, &if_lhsisnotboolean); | |
3669 | |
3670 assembler->Bind(&if_lhsisboolean); | |
3671 { | |
3672 // The {lhs} is a Boolean, check if {rhs} is also a Boolean. | |
3673 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); | |
3674 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), | |
3675 &if_rhsisboolean, &if_rhsisnotboolean); | |
3676 | |
3677 assembler->Bind(&if_rhsisboolean); | |
3678 { | |
3679 // Both {lhs} and {rhs} are distinct Boolean values. | |
3680 assembler->Goto(&if_notequal); | |
3681 } | |
3682 | |
3683 assembler->Bind(&if_rhsisnotboolean); | |
3684 { | |
3685 // Convert the {lhs} to a Number first. | |
3686 var_lhs.Bind( | |
3687 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset)); | |
3688 assembler->Goto(&loop); | |
3689 } | |
3690 } | |
3691 | |
3692 assembler->Bind(&if_lhsisnotboolean); | |
3693 { | |
3694 // The {lhs} is either Null or Undefined; check if the {rhs} is | |
3695 // undetectable (i.e. either also Null or Undefined or some | |
3696 // undetectable JSReceiver). | |
3697 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); | |
3698 assembler->BranchIfWord32Equal( | |
3699 assembler->Word32And( | |
3700 rhs_bitfield, | |
3701 assembler->Int32Constant(1 << Map::kIsUndetectable)), | |
3702 assembler->Int32Constant(0), &if_notequal, &if_equal); | |
3703 } | |
3704 } | |
3705 | |
3706 assembler->Bind(&if_lhsissymbol); | |
3707 { | |
3708 // Check if the {rhs} is a JSReceiver. | |
3709 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); | |
3710 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
3711 assembler->Branch( | |
3712 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
3713 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
3714 | |
3715 assembler->Bind(&if_rhsisreceiver); | |
3716 { | |
3717 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. | |
3718 // Swapping {lhs} and {rhs} is not observable and doesn't | |
3719 // matter for the result, so we can just swap them and use | |
3720 // the JSReceiver handling below (for {lhs} being a JSReceiver). | |
3721 var_lhs.Bind(rhs); | |
3722 var_rhs.Bind(lhs); | |
3723 assembler->Goto(&loop); | |
3724 } | |
3725 | |
3726 assembler->Bind(&if_rhsisnotreceiver); | |
3727 { | |
3728 // The {rhs} is not a JSReceiver and also not the same Symbol | |
3729 // as the {lhs}, so this is equality check is considered false. | |
3730 assembler->Goto(&if_notequal); | |
3731 } | |
3732 } | |
3733 | |
3734 assembler->Bind(&if_lhsissimd128value); | |
3735 { | |
3736 // Check if the {rhs} is also a Simd128Value. | |
3737 Label if_rhsissimd128value(assembler), | |
3738 if_rhsisnotsimd128value(assembler); | |
3739 assembler->Branch( | |
3740 assembler->Word32Equal(lhs_instance_type, rhs_instance_type), | |
3741 &if_rhsissimd128value, &if_rhsisnotsimd128value); | |
3742 | |
3743 assembler->Bind(&if_rhsissimd128value); | |
3744 { | |
3745 // Both {lhs} and {rhs} is a Simd128Value. | |
3746 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, | |
3747 rhs, rhs_map, &if_equal, | |
3748 &if_notequal); | |
3749 } | |
3750 | |
3751 assembler->Bind(&if_rhsisnotsimd128value); | |
3752 { | |
3753 // Check if the {rhs} is a JSReceiver. | |
3754 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); | |
3755 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
3756 assembler->Branch( | |
3757 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
3758 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
3759 | |
3760 assembler->Bind(&if_rhsisreceiver); | |
3761 { | |
3762 // The {lhs} is a Primitive and the {rhs} is a JSReceiver. | |
3763 // Swapping {lhs} and {rhs} is not observable and doesn't | |
3764 // matter for the result, so we can just swap them and use | |
3765 // the JSReceiver handling below (for {lhs} being a JSReceiver). | |
3766 var_lhs.Bind(rhs); | |
3767 var_rhs.Bind(lhs); | |
3768 assembler->Goto(&loop); | |
3769 } | |
3770 | |
3771 assembler->Bind(&if_rhsisnotreceiver); | |
3772 { | |
3773 // The {rhs} is some other Primitive. | |
3774 assembler->Goto(&if_notequal); | |
3775 } | |
3776 } | |
3777 } | |
3778 | |
3779 assembler->Bind(&if_lhsisreceiver); | |
3780 { | |
3781 // Check if the {rhs} is also a JSReceiver. | |
3782 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); | |
3783 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); | |
3784 assembler->Branch( | |
3785 assembler->IsJSReceiverInstanceType(rhs_instance_type), | |
3786 &if_rhsisreceiver, &if_rhsisnotreceiver); | |
3787 | |
3788 assembler->Bind(&if_rhsisreceiver); | |
3789 { | |
3790 // Both {lhs} and {rhs} are different JSReceiver references, so | |
3791 // this cannot be considered equal. | |
3792 assembler->Goto(&if_notequal); | |
3793 } | |
3794 | |
3795 assembler->Bind(&if_rhsisnotreceiver); | |
3796 { | |
3797 // Check if {rhs} is Null or Undefined (an undetectable check | |
3798 // is sufficient here, since we already know that {rhs} is not | |
3799 // a JSReceiver). | |
3800 Label if_rhsisundetectable(assembler), | |
3801 if_rhsisnotundetectable(assembler, Label::kDeferred); | |
3802 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); | |
3803 assembler->BranchIfWord32Equal( | |
3804 assembler->Word32And( | |
3805 rhs_bitfield, | |
3806 assembler->Int32Constant(1 << Map::kIsUndetectable)), | |
3807 assembler->Int32Constant(0), &if_rhsisnotundetectable, | |
3808 &if_rhsisundetectable); | |
3809 | |
3810 assembler->Bind(&if_rhsisundetectable); | |
3811 { | |
3812 // Check if {lhs} is an undetectable JSReceiver. | |
3813 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map); | |
3814 assembler->BranchIfWord32Equal( | |
3815 assembler->Word32And( | |
3816 lhs_bitfield, | |
3817 assembler->Int32Constant(1 << Map::kIsUndetectable)), | |
3818 assembler->Int32Constant(0), &if_notequal, &if_equal); | |
3819 } | |
3820 | |
3821 assembler->Bind(&if_rhsisnotundetectable); | |
3822 { | |
3823 // The {rhs} is some Primitive different from Null and | |
3824 // Undefined, need to convert {lhs} to Primitive first. | |
3825 Callable callable = | |
3826 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); | |
3827 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); | |
3828 assembler->Goto(&loop); | |
3829 } | |
3830 } | |
3831 } | |
3832 } | |
3833 } | |
3834 } | |
3835 | |
3836 assembler->Bind(&do_rhsstringtonumber); | |
3837 { | |
3838 Callable callable = CodeFactory::StringToNumber(assembler->isolate()); | |
3839 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); | |
3840 assembler->Goto(&loop); | |
3841 } | |
3842 } | |
3843 | |
3844 assembler->Bind(&do_fcmp); | |
3845 { | |
3846 // Load the {lhs} and {rhs} floating point values. | |
3847 Node* lhs = var_fcmp_lhs.value(); | |
3848 Node* rhs = var_fcmp_rhs.value(); | |
3849 | |
3850 // Perform a fast floating point comparison. | |
3851 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); | |
3852 } | |
3853 | |
3854 assembler->Bind(&if_equal); | |
3855 { | |
3856 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); | |
3857 assembler->Goto(&end); | |
3858 } | |
3859 | |
3860 assembler->Bind(&if_notequal); | |
3861 { | |
3862 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); | |
3863 assembler->Goto(&end); | |
3864 } | |
3865 | |
3866 assembler->Bind(&end); | |
3867 return result.value(); | |
3868 } | |
3869 | |
3870 compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler, | |
3871 ResultMode mode, compiler::Node* lhs, | |
3872 compiler::Node* rhs, | |
3873 compiler::Node* context) { | |
3874 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | |
3875 // mode; for kNegateResult mode we properly negate the result. | |
3876 // | |
3877 // if (lhs == rhs) { | |
3878 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; | |
3879 // return true; | |
3880 // } | |
3881 // if (!lhs->IsSmi()) { | |
3882 // if (lhs->IsHeapNumber()) { | |
3883 // if (rhs->IsSmi()) { | |
3884 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); | |
3885 // } else if (rhs->IsHeapNumber()) { | |
3886 // return HeapNumber::cast(rhs)->value() == | |
3887 // HeapNumber::cast(lhs)->value(); | |
3888 // } else { | |
3889 // return false; | |
3890 // } | |
3891 // } else { | |
3892 // if (rhs->IsSmi()) { | |
3893 // return false; | |
3894 // } else { | |
3895 // if (lhs->IsString()) { | |
3896 // if (rhs->IsString()) { | |
3897 // return %StringEqual(lhs, rhs); | |
3898 // } else { | |
3899 // return false; | |
3900 // } | |
3901 // } else if (lhs->IsSimd128()) { | |
3902 // if (rhs->IsSimd128()) { | |
3903 // return %StrictEqual(lhs, rhs); | |
3904 // } | |
3905 // } else { | |
3906 // return false; | |
3907 // } | |
3908 // } | |
3909 // } | |
3910 // } else { | |
3911 // if (rhs->IsSmi()) { | |
3912 // return false; | |
3913 // } else { | |
3914 // if (rhs->IsHeapNumber()) { | |
3915 // return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value(); | |
3916 // } else { | |
3917 // return false; | |
3918 // } | |
3919 // } | |
3920 // } | |
3921 | |
3922 typedef CodeStubAssembler::Label Label; | |
3923 typedef CodeStubAssembler::Variable Variable; | |
3924 typedef compiler::Node Node; | |
3925 | |
3926 Label if_equal(assembler), if_notequal(assembler), end(assembler); | |
3927 Variable result(assembler, MachineRepresentation::kTagged); | |
3928 | |
3929 // Check if {lhs} and {rhs} refer to the same object. | |
3930 Label if_same(assembler), if_notsame(assembler); | |
3931 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | |
3932 | |
3933 assembler->Bind(&if_same); | |
3934 { | |
3935 // The {lhs} and {rhs} reference the exact same value, yet we need special | |
3936 // treatment for HeapNumber, as NaN is not equal to NaN. | |
3937 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); | |
3938 } | |
3939 | |
3940 assembler->Bind(&if_notsame); | |
3941 { | |
3942 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, | |
3943 // String and Simd128Value they can still be considered equal. | |
3944 Node* number_map = assembler->HeapNumberMapConstant(); | |
3945 | |
3946 // Check if {lhs} is a Smi or a HeapObject. | |
3947 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
3948 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
3949 | |
3950 assembler->Bind(&if_lhsisnotsmi); | |
3951 { | |
3952 // Load the map of {lhs}. | |
3953 Node* lhs_map = assembler->LoadMap(lhs); | |
3954 | |
3955 // Check if {lhs} is a HeapNumber. | |
3956 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
3957 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
3958 &if_lhsisnumber, &if_lhsisnotnumber); | |
3959 | |
3960 assembler->Bind(&if_lhsisnumber); | |
3961 { | |
3962 // Check if {rhs} is a Smi or a HeapObject. | |
3963 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
3964 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
3965 &if_rhsisnotsmi); | |
3966 | |
3967 assembler->Bind(&if_rhsissmi); | |
3968 { | |
3969 // Convert {lhs} and {rhs} to floating point values. | |
3970 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | |
3971 Node* rhs_value = assembler->SmiToFloat64(rhs); | |
3972 | |
3973 // Perform a floating point comparison of {lhs} and {rhs}. | |
3974 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | |
3975 &if_notequal); | |
3976 } | |
3977 | |
3978 assembler->Bind(&if_rhsisnotsmi); | |
3979 { | |
3980 // Load the map of {rhs}. | |
3981 Node* rhs_map = assembler->LoadMap(rhs); | |
3982 | |
3983 // Check if {rhs} is also a HeapNumber. | |
3984 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
3985 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
3986 &if_rhsisnumber, &if_rhsisnotnumber); | |
3987 | |
3988 assembler->Bind(&if_rhsisnumber); | |
3989 { | |
3990 // Convert {lhs} and {rhs} to floating point values. | |
3991 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | |
3992 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | |
3993 | |
3994 // Perform a floating point comparison of {lhs} and {rhs}. | |
3995 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | |
3996 &if_notequal); | |
3997 } | |
3998 | |
3999 assembler->Bind(&if_rhsisnotnumber); | |
4000 assembler->Goto(&if_notequal); | |
4001 } | |
4002 } | |
4003 | |
4004 assembler->Bind(&if_lhsisnotnumber); | |
4005 { | |
4006 // Check if {rhs} is a Smi or a HeapObject. | |
4007 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
4008 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
4009 &if_rhsisnotsmi); | |
4010 | |
4011 assembler->Bind(&if_rhsissmi); | |
4012 assembler->Goto(&if_notequal); | |
4013 | |
4014 assembler->Bind(&if_rhsisnotsmi); | |
4015 { | |
4016 // Load the instance type of {lhs}. | |
4017 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | |
4018 | |
4019 // Check if {lhs} is a String. | |
4020 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); | |
4021 assembler->Branch(assembler->IsStringInstanceType(lhs_instance_type), | |
4022 &if_lhsisstring, &if_lhsisnotstring); | |
4023 | |
4024 assembler->Bind(&if_lhsisstring); | |
4025 { | |
4026 // Load the instance type of {rhs}. | |
4027 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | |
4028 | |
4029 // Check if {rhs} is also a String. | |
4030 Label if_rhsisstring(assembler, Label::kDeferred), | |
4031 if_rhsisnotstring(assembler); | |
4032 assembler->Branch( | |
4033 assembler->IsStringInstanceType(rhs_instance_type), | |
4034 &if_rhsisstring, &if_rhsisnotstring); | |
4035 | |
4036 assembler->Bind(&if_rhsisstring); | |
4037 { | |
4038 Callable callable = | |
4039 (mode == kDontNegateResult) | |
4040 ? CodeFactory::StringEqual(assembler->isolate()) | |
4041 : CodeFactory::StringNotEqual(assembler->isolate()); | |
4042 result.Bind(assembler->CallStub(callable, context, lhs, rhs)); | |
4043 assembler->Goto(&end); | |
4044 } | |
4045 | |
4046 assembler->Bind(&if_rhsisnotstring); | |
4047 assembler->Goto(&if_notequal); | |
4048 } | |
4049 | |
4050 assembler->Bind(&if_lhsisnotstring); | |
4051 { | |
4052 // Check if {lhs} is a Simd128Value. | |
4053 Label if_lhsissimd128value(assembler), | |
4054 if_lhsisnotsimd128value(assembler); | |
4055 assembler->Branch(assembler->Word32Equal( | |
4056 lhs_instance_type, | |
4057 assembler->Int32Constant(SIMD128_VALUE_TYPE)), | |
4058 &if_lhsissimd128value, &if_lhsisnotsimd128value); | |
4059 | |
4060 assembler->Bind(&if_lhsissimd128value); | |
4061 { | |
4062 // Load the map of {rhs}. | |
4063 Node* rhs_map = assembler->LoadMap(rhs); | |
4064 | |
4065 // Check if {rhs} is also a Simd128Value that is equal to {lhs}. | |
4066 GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map, | |
4067 rhs, rhs_map, &if_equal, | |
4068 &if_notequal); | |
4069 } | |
4070 | |
4071 assembler->Bind(&if_lhsisnotsimd128value); | |
4072 assembler->Goto(&if_notequal); | |
4073 } | |
4074 } | |
4075 } | |
4076 } | |
4077 | |
4078 assembler->Bind(&if_lhsissmi); | |
4079 { | |
4080 // We already know that {lhs} and {rhs} are not reference equal, and {lhs} | |
4081 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a | |
4082 // HeapNumber with an equal floating point value. | |
4083 | |
4084 // Check if {rhs} is a Smi or a HeapObject. | |
4085 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | |
4086 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | |
4087 &if_rhsisnotsmi); | |
4088 | |
4089 assembler->Bind(&if_rhsissmi); | |
4090 assembler->Goto(&if_notequal); | |
4091 | |
4092 assembler->Bind(&if_rhsisnotsmi); | |
4093 { | |
4094 // Load the map of the {rhs}. | |
4095 Node* rhs_map = assembler->LoadMap(rhs); | |
4096 | |
4097 // The {rhs} could be a HeapNumber with the same value as {lhs}. | |
4098 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | |
4099 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | |
4100 &if_rhsisnumber, &if_rhsisnotnumber); | |
4101 | |
4102 assembler->Bind(&if_rhsisnumber); | |
4103 { | |
4104 // Convert {lhs} and {rhs} to floating point values. | |
4105 Node* lhs_value = assembler->SmiToFloat64(lhs); | |
4106 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | |
4107 | |
4108 // Perform a floating point comparison of {lhs} and {rhs}. | |
4109 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, | |
4110 &if_notequal); | |
4111 } | |
4112 | |
4113 assembler->Bind(&if_rhsisnotnumber); | |
4114 assembler->Goto(&if_notequal); | |
4115 } | |
4116 } | |
4117 } | |
4118 | |
4119 assembler->Bind(&if_equal); | |
4120 { | |
4121 result.Bind(assembler->BooleanConstant(mode == kDontNegateResult)); | |
4122 assembler->Goto(&end); | |
4123 } | |
4124 | |
4125 assembler->Bind(&if_notequal); | |
4126 { | |
4127 result.Bind(assembler->BooleanConstant(mode == kNegateResult)); | |
4128 assembler->Goto(&end); | |
4129 } | |
4130 | |
4131 assembler->Bind(&end); | |
4132 return result.value(); | |
4133 } | |
4134 | |
4135 } // namespace | |
4136 | |
4137 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 1551 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
4138 typedef compiler::Node Node; | 1552 typedef compiler::Node Node; |
4139 Node* context = assembler->Parameter(Descriptor::kContext); | 1553 Node* context = assembler->Parameter(Descriptor::kContext); |
4140 Node* receiver = assembler->Parameter(Descriptor::kReceiver); | 1554 Node* receiver = assembler->Parameter(Descriptor::kReceiver); |
4141 // For now we only support receiver_is_holder. | 1555 // For now we only support receiver_is_holder. |
4142 DCHECK(receiver_is_holder()); | 1556 DCHECK(receiver_is_holder()); |
4143 Node* holder = receiver; | 1557 Node* holder = receiver; |
4144 Node* map = assembler->LoadMap(receiver); | 1558 Node* map = assembler->LoadMap(receiver); |
4145 Node* descriptors = assembler->LoadMapDescriptors(map); | 1559 Node* descriptors = assembler->LoadMapDescriptors(map); |
4146 Node* value_index = | 1560 Node* value_index = |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4356 Node* value = assembler->Parameter(Descriptor::kValue); | 1770 Node* value = assembler->Parameter(Descriptor::kValue); |
4357 Node* context = assembler->Parameter(Descriptor::kContext); | 1771 Node* context = assembler->Parameter(Descriptor::kContext); |
4358 | 1772 |
4359 Node* script_context = assembler->LoadScriptContext(context, context_index()); | 1773 Node* script_context = assembler->LoadScriptContext(context, context_index()); |
4360 assembler->StoreFixedArrayElement( | 1774 assembler->StoreFixedArrayElement( |
4361 script_context, assembler->IntPtrConstant(slot_index()), value, | 1775 script_context, assembler->IntPtrConstant(slot_index()), value, |
4362 UPDATE_WRITE_BARRIER, CodeStubAssembler::INTPTR_PARAMETERS); | 1776 UPDATE_WRITE_BARRIER, CodeStubAssembler::INTPTR_PARAMETERS); |
4363 assembler->Return(value); | 1777 assembler->Return(value); |
4364 } | 1778 } |
4365 | 1779 |
4366 // static | |
4367 compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler, | |
4368 compiler::Node* lhs, compiler::Node* rhs, | |
4369 compiler::Node* context) { | |
4370 return GenerateAbstractRelationalComparison(assembler, kLessThan, lhs, rhs, | |
4371 context); | |
4372 } | |
4373 | |
4374 // static | |
4375 compiler::Node* LessThanOrEqualStub::Generate(CodeStubAssembler* assembler, | |
4376 compiler::Node* lhs, | |
4377 compiler::Node* rhs, | |
4378 compiler::Node* context) { | |
4379 return GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual, lhs, | |
4380 rhs, context); | |
4381 } | |
4382 | |
4383 // static | |
4384 compiler::Node* GreaterThanStub::Generate(CodeStubAssembler* assembler, | |
4385 compiler::Node* lhs, | |
4386 compiler::Node* rhs, | |
4387 compiler::Node* context) { | |
4388 return GenerateAbstractRelationalComparison(assembler, kGreaterThan, lhs, rhs, | |
4389 context); | |
4390 } | |
4391 | |
4392 // static | |
4393 compiler::Node* GreaterThanOrEqualStub::Generate(CodeStubAssembler* assembler, | |
4394 compiler::Node* lhs, | |
4395 compiler::Node* rhs, | |
4396 compiler::Node* context) { | |
4397 return GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual, | |
4398 lhs, rhs, context); | |
4399 } | |
4400 | |
4401 // static | |
4402 compiler::Node* EqualStub::Generate(CodeStubAssembler* assembler, | |
4403 compiler::Node* lhs, compiler::Node* rhs, | |
4404 compiler::Node* context) { | |
4405 return GenerateEqual(assembler, kDontNegateResult, lhs, rhs, context); | |
4406 } | |
4407 | |
4408 // static | |
4409 compiler::Node* NotEqualStub::Generate(CodeStubAssembler* assembler, | |
4410 compiler::Node* lhs, compiler::Node* rhs, | |
4411 compiler::Node* context) { | |
4412 return GenerateEqual(assembler, kNegateResult, lhs, rhs, context); | |
4413 } | |
4414 | |
4415 // static | |
4416 compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler, | |
4417 compiler::Node* lhs, | |
4418 compiler::Node* rhs, | |
4419 compiler::Node* context) { | |
4420 return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context); | |
4421 } | |
4422 | |
4423 // static | |
4424 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler, | |
4425 compiler::Node* lhs, | |
4426 compiler::Node* rhs, | |
4427 compiler::Node* context) { | |
4428 return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context); | |
4429 } | |
4430 | |
4431 void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
4432 typedef CodeStubAssembler::Label Label; | |
4433 typedef compiler::Node Node; | |
4434 typedef CodeStubAssembler::Variable Variable; | |
4435 | |
4436 Node* context = assembler->Parameter(1); | |
4437 | |
4438 // We might need to loop once for ToNumber conversion. | |
4439 Variable var_len(assembler, MachineRepresentation::kTagged); | |
4440 Label loop(assembler, &var_len); | |
4441 var_len.Bind(assembler->Parameter(0)); | |
4442 assembler->Goto(&loop); | |
4443 assembler->Bind(&loop); | |
4444 { | |
4445 // Shared entry points. | |
4446 Label return_len(assembler), | |
4447 return_two53minus1(assembler, Label::kDeferred), | |
4448 return_zero(assembler, Label::kDeferred); | |
4449 | |
4450 // Load the current {len} value. | |
4451 Node* len = var_len.value(); | |
4452 | |
4453 // Check if {len} is a positive Smi. | |
4454 assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len); | |
4455 | |
4456 // Check if {len} is a (negative) Smi. | |
4457 assembler->GotoIf(assembler->WordIsSmi(len), &return_zero); | |
4458 | |
4459 // Check if {len} is a HeapNumber. | |
4460 Label if_lenisheapnumber(assembler), | |
4461 if_lenisnotheapnumber(assembler, Label::kDeferred); | |
4462 assembler->Branch(assembler->IsHeapNumberMap(assembler->LoadMap(len)), | |
4463 &if_lenisheapnumber, &if_lenisnotheapnumber); | |
4464 | |
4465 assembler->Bind(&if_lenisheapnumber); | |
4466 { | |
4467 // Load the floating-point value of {len}. | |
4468 Node* len_value = assembler->LoadHeapNumberValue(len); | |
4469 | |
4470 // Check if {len} is not greater than zero. | |
4471 assembler->GotoUnless(assembler->Float64GreaterThan( | |
4472 len_value, assembler->Float64Constant(0.0)), | |
4473 &return_zero); | |
4474 | |
4475 // Check if {len} is greater than or equal to 2^53-1. | |
4476 assembler->GotoIf( | |
4477 assembler->Float64GreaterThanOrEqual( | |
4478 len_value, assembler->Float64Constant(kMaxSafeInteger)), | |
4479 &return_two53minus1); | |
4480 | |
4481 // Round the {len} towards -Infinity. | |
4482 Node* value = assembler->Float64Floor(len_value); | |
4483 Node* result = assembler->ChangeFloat64ToTagged(value); | |
4484 assembler->Return(result); | |
4485 } | |
4486 | |
4487 assembler->Bind(&if_lenisnotheapnumber); | |
4488 { | |
4489 // Need to convert {len} to a Number first. | |
4490 Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate()); | |
4491 var_len.Bind(assembler->CallStub(callable, context, len)); | |
4492 assembler->Goto(&loop); | |
4493 } | |
4494 | |
4495 assembler->Bind(&return_len); | |
4496 assembler->Return(var_len.value()); | |
4497 | |
4498 assembler->Bind(&return_two53minus1); | |
4499 assembler->Return(assembler->NumberConstant(kMaxSafeInteger)); | |
4500 | |
4501 assembler->Bind(&return_zero); | |
4502 assembler->Return(assembler->SmiConstant(Smi::FromInt(0))); | |
4503 } | |
4504 } | |
4505 | |
4506 void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const { | |
4507 typedef compiler::Node Node; | |
4508 | |
4509 Node* input = assembler->Parameter(Descriptor::kArgument); | |
4510 Node* context = assembler->Parameter(Descriptor::kContext); | |
4511 | |
4512 assembler->Return(assembler->ToInteger(context, input)); | |
4513 } | |
4514 | |
4515 void StoreInterceptorStub::GenerateAssembly( | 1780 void StoreInterceptorStub::GenerateAssembly( |
4516 CodeStubAssembler* assembler) const { | 1781 CodeStubAssembler* assembler) const { |
4517 typedef compiler::Node Node; | 1782 typedef compiler::Node Node; |
4518 | 1783 |
4519 Node* receiver = assembler->Parameter(Descriptor::kReceiver); | 1784 Node* receiver = assembler->Parameter(Descriptor::kReceiver); |
4520 Node* name = assembler->Parameter(Descriptor::kName); | 1785 Node* name = assembler->Parameter(Descriptor::kName); |
4521 Node* value = assembler->Parameter(Descriptor::kValue); | 1786 Node* value = assembler->Parameter(Descriptor::kValue); |
4522 Node* context = assembler->Parameter(Descriptor::kContext); | 1787 Node* context = assembler->Parameter(Descriptor::kContext); |
4523 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, | 1788 assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, |
4524 receiver, name, value); | 1789 receiver, name, value); |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4805 descriptor->Initialize( | 2070 descriptor->Initialize( |
4806 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite)); | 2071 FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite)); |
4807 } | 2072 } |
4808 | 2073 |
4809 | 2074 |
4810 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { | 2075 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) { |
4811 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); | 2076 descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry); |
4812 descriptor->SetMissHandler(Runtime::kStringAdd); | 2077 descriptor->SetMissHandler(Runtime::kStringAdd); |
4813 } | 2078 } |
4814 | 2079 |
4815 namespace { | |
4816 | |
4817 compiler::Node* GenerateHasProperty( | |
4818 CodeStubAssembler* assembler, compiler::Node* object, compiler::Node* key, | |
4819 compiler::Node* context, Runtime::FunctionId fallback_runtime_function_id) { | |
4820 typedef compiler::Node Node; | |
4821 typedef CodeStubAssembler::Label Label; | |
4822 typedef CodeStubAssembler::Variable Variable; | |
4823 | |
4824 Label call_runtime(assembler, Label::kDeferred), return_true(assembler), | |
4825 return_false(assembler), end(assembler); | |
4826 | |
4827 CodeStubAssembler::LookupInHolder lookup_property_in_holder = | |
4828 [assembler, &return_true](Node* receiver, Node* holder, Node* holder_map, | |
4829 Node* holder_instance_type, Node* unique_name, | |
4830 Label* next_holder, Label* if_bailout) { | |
4831 assembler->TryHasOwnProperty(holder, holder_map, holder_instance_type, | |
4832 unique_name, &return_true, next_holder, | |
4833 if_bailout); | |
4834 }; | |
4835 | |
4836 CodeStubAssembler::LookupInHolder lookup_element_in_holder = | |
4837 [assembler, &return_true](Node* receiver, Node* holder, Node* holder_map, | |
4838 Node* holder_instance_type, Node* index, | |
4839 Label* next_holder, Label* if_bailout) { | |
4840 assembler->TryLookupElement(holder, holder_map, holder_instance_type, | |
4841 index, &return_true, next_holder, | |
4842 if_bailout); | |
4843 }; | |
4844 | |
4845 assembler->TryPrototypeChainLookup(object, key, lookup_property_in_holder, | |
4846 lookup_element_in_holder, &return_false, | |
4847 &call_runtime); | |
4848 | |
4849 Variable result(assembler, MachineRepresentation::kTagged); | |
4850 assembler->Bind(&return_true); | |
4851 { | |
4852 result.Bind(assembler->BooleanConstant(true)); | |
4853 assembler->Goto(&end); | |
4854 } | |
4855 | |
4856 assembler->Bind(&return_false); | |
4857 { | |
4858 result.Bind(assembler->BooleanConstant(false)); | |
4859 assembler->Goto(&end); | |
4860 } | |
4861 | |
4862 assembler->Bind(&call_runtime); | |
4863 { | |
4864 result.Bind(assembler->CallRuntime(fallback_runtime_function_id, context, | |
4865 object, key)); | |
4866 assembler->Goto(&end); | |
4867 } | |
4868 | |
4869 assembler->Bind(&end); | |
4870 return result.value(); | |
4871 } | |
4872 | |
4873 } // namespace | |
4874 | |
4875 // static | |
4876 compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler, | |
4877 compiler::Node* key, | |
4878 compiler::Node* object, | |
4879 compiler::Node* context) { | |
4880 return GenerateHasProperty(assembler, object, key, context, | |
4881 Runtime::kHasProperty); | |
4882 } | |
4883 | |
4884 // static | |
4885 compiler::Node* ForInFilterStub::Generate(CodeStubAssembler* assembler, | |
4886 compiler::Node* key, | |
4887 compiler::Node* object, | |
4888 compiler::Node* context) { | |
4889 typedef compiler::Node Node; | |
4890 typedef CodeStubAssembler::Label Label; | |
4891 typedef CodeStubAssembler::Variable Variable; | |
4892 | |
4893 Label return_undefined(assembler, Label::kDeferred), | |
4894 return_to_name(assembler), end(assembler); | |
4895 | |
4896 Variable var_result(assembler, MachineRepresentation::kTagged); | |
4897 | |
4898 Node* has_property = GenerateHasProperty(assembler, object, key, context, | |
4899 Runtime::kForInHasProperty); | |
4900 | |
4901 assembler->Branch( | |
4902 assembler->WordEqual(has_property, assembler->BooleanConstant(true)), | |
4903 &return_to_name, &return_undefined); | |
4904 | |
4905 assembler->Bind(&return_to_name); | |
4906 { | |
4907 var_result.Bind(assembler->ToName(context, key)); | |
4908 assembler->Goto(&end); | |
4909 } | |
4910 | |
4911 assembler->Bind(&return_undefined); | |
4912 { | |
4913 var_result.Bind(assembler->UndefinedConstant()); | |
4914 assembler->Goto(&end); | |
4915 } | |
4916 | |
4917 assembler->Bind(&end); | |
4918 return var_result.value(); | |
4919 } | |
4920 | 2080 |
4921 void GetPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const { | 2081 void GetPropertyStub::GenerateAssembly(CodeStubAssembler* assembler) const { |
4922 typedef compiler::Node Node; | 2082 typedef compiler::Node Node; |
4923 typedef CodeStubAssembler::Label Label; | 2083 typedef CodeStubAssembler::Label Label; |
4924 typedef CodeStubAssembler::Variable Variable; | 2084 typedef CodeStubAssembler::Variable Variable; |
4925 | 2085 |
4926 Label call_runtime(assembler, Label::kDeferred), return_undefined(assembler), | 2086 Label call_runtime(assembler, Label::kDeferred), return_undefined(assembler), |
4927 end(assembler); | 2087 end(assembler); |
4928 | 2088 |
4929 Node* object = assembler->Parameter(0); | 2089 Node* object = assembler->Parameter(0); |
(...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5826 | 2986 |
5827 if (type == MachineType::Pointer()) { | 2987 if (type == MachineType::Pointer()) { |
5828 return Representation::External(); | 2988 return Representation::External(); |
5829 } | 2989 } |
5830 | 2990 |
5831 return Representation::Tagged(); | 2991 return Representation::Tagged(); |
5832 } | 2992 } |
5833 | 2993 |
5834 } // namespace internal | 2994 } // namespace internal |
5835 } // namespace v8 | 2995 } // namespace v8 |
OLD | NEW |