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

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

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

Powered by Google App Engine
This is Rietveld 408576698