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