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

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

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

Powered by Google App Engine
This is Rietveld 408576698