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

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

Issue 2372113004: [turbofan] JSGenericLowering mostly uses builtins instead of code stubs now (Closed)
Patch Set: removed TFSC macro Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/code-stubs.h" 5 #include "src/code-stubs.h"
6 6
7 #include <sstream> 7 #include <sstream>
8 8
9 #include "src/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
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
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
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
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), &dividend_is_smi,
1787 &dividend_is_not_smi);
1788
1789 assembler->Bind(&dividend_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 &dividend_is_zero, &dividend_is_not_zero);
1810
1811 assembler->Bind(&dividend_is_zero);
1812 {
1813 assembler->GotoIf(
1814 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)),
1815 &bailout);
1816 assembler->Goto(&dividend_is_not_zero);
1817 }
1818 assembler->Bind(&dividend_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(&dividend_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 &dividend_is_number, &dividend_is_not_number);
1904
1905 assembler->Bind(&dividend_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(&dividend_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
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), &dividend_is_smi,
2183 &dividend_is_not_smi);
2184
2185 assembler->Bind(&dividend_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(&dividend_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 &dividend_is_number, &dividend_is_not_number);
2238
2239 assembler->Bind(&dividend_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(&dividend_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
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
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
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
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
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
OLDNEW
« src/builtins/builtins.cc ('K') | « src/code-stubs.h ('k') | src/crankshaft/hydrogen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698