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