OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 | 841 |
842 assembler->Bind(&return_true); | 842 assembler->Bind(&return_true); |
843 assembler->Return(assembler->BooleanConstant(true)); | 843 assembler->Return(assembler->BooleanConstant(true)); |
844 | 844 |
845 assembler->Bind(&return_false); | 845 assembler->Bind(&return_false); |
846 assembler->Return(assembler->BooleanConstant(false)); | 846 assembler->Return(assembler->BooleanConstant(false)); |
847 } | 847 } |
848 | 848 |
849 enum ResultMode { kDontNegateResult, kNegateResult }; | 849 enum ResultMode { kDontNegateResult, kNegateResult }; |
850 | 850 |
| 851 void GenerateEqual_Same(compiler::CodeStubAssembler* assembler, |
| 852 compiler::Node* value, |
| 853 compiler::CodeStubAssembler::Label* if_equal, |
| 854 compiler::CodeStubAssembler::Label* if_notequal) { |
| 855 // In case of abstract or strict equality checks, we need additional checks |
| 856 // for NaN values because they are not considered equal, even if both the |
| 857 // left and the right hand side reference exactly the same value. |
| 858 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it |
| 859 // seems to be what is tested in the current SIMD.js testsuite. |
| 860 |
| 861 typedef compiler::CodeStubAssembler::Label Label; |
| 862 typedef compiler::Node Node; |
| 863 |
| 864 // Check if {value} is a Smi or a HeapObject. |
| 865 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
| 866 assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi, |
| 867 &if_valueisnotsmi); |
| 868 |
| 869 assembler->Bind(&if_valueisnotsmi); |
| 870 { |
| 871 // Load the map of {value}. |
| 872 Node* value_map = assembler->LoadObjectField(value, HeapObject::kMapOffset); |
| 873 |
| 874 // Check if {value} (and therefore {rhs}) is a HeapNumber. |
| 875 Node* number_map = assembler->HeapNumberMapConstant(); |
| 876 Label if_valueisnumber(assembler), if_valueisnotnumber(assembler); |
| 877 assembler->Branch(assembler->WordEqual(value_map, number_map), |
| 878 &if_valueisnumber, &if_valueisnotnumber); |
| 879 |
| 880 assembler->Bind(&if_valueisnumber); |
| 881 { |
| 882 // Convert {value} (and therefore {rhs}) to floating point value. |
| 883 Node* value_value = assembler->LoadHeapNumberValue(value); |
| 884 |
| 885 // Check if the HeapNumber value is a NaN. |
| 886 assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal); |
| 887 } |
| 888 |
| 889 assembler->Bind(&if_valueisnotnumber); |
| 890 assembler->Goto(if_equal); |
| 891 } |
| 892 |
| 893 assembler->Bind(&if_valueissmi); |
| 894 assembler->Goto(if_equal); |
| 895 } |
| 896 |
| 897 void GenerateEqual(compiler::CodeStubAssembler* assembler, ResultMode mode) { |
| 898 typedef compiler::CodeStubAssembler::Label Label; |
| 899 typedef compiler::Node Node; |
| 900 typedef compiler::CodeStubAssembler::Variable Variable; |
| 901 |
| 902 Node* context = assembler->Parameter(2); |
| 903 |
| 904 Label if_equal(assembler), if_notequal(assembler); |
| 905 |
| 906 // Shared entry for floating point comparison. |
| 907 Label do_fcmp(assembler); |
| 908 Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64), |
| 909 var_fcmp_rhs(assembler, MachineRepresentation::kFloat64); |
| 910 |
| 911 // Shared entry for runtime comparison. |
| 912 Label do_rcmp(assembler); |
| 913 Variable var_rcmp_lhs(assembler, MachineRepresentation::kTagged), |
| 914 var_rcmp_rhs(assembler, MachineRepresentation::kTagged); |
| 915 |
| 916 // We might need to loop several times due to ToPrimitive and/or ToNumber |
| 917 // conversions. |
| 918 Variable var_lhs(assembler, MachineRepresentation::kTagged), |
| 919 var_rhs(assembler, MachineRepresentation::kTagged); |
| 920 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
| 921 Label loop(assembler, 2, loop_vars); |
| 922 var_lhs.Bind(assembler->Parameter(0)); |
| 923 var_rhs.Bind(assembler->Parameter(1)); |
| 924 assembler->Goto(&loop); |
| 925 assembler->Bind(&loop); |
| 926 { |
| 927 // Load the current {lhs} and {rhs} values. |
| 928 Node* lhs = var_lhs.value(); |
| 929 Node* rhs = var_rhs.value(); |
| 930 |
| 931 // Check if {lhs} and {rhs} refer to the same object. |
| 932 Label if_same(assembler), if_notsame(assembler); |
| 933 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
| 934 |
| 935 assembler->Bind(&if_same); |
| 936 { |
| 937 // The {lhs} and {rhs} reference the exact same value, yet we need special |
| 938 // treatment for HeapNumber, as NaN is not equal to NaN. |
| 939 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); |
| 940 } |
| 941 |
| 942 assembler->Bind(&if_notsame); |
| 943 { |
| 944 // Check if {lhs} is a Smi or a HeapObject. |
| 945 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
| 946 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, |
| 947 &if_lhsisnotsmi); |
| 948 |
| 949 assembler->Bind(&if_lhsissmi); |
| 950 { |
| 951 // Check if {rhs} is a Smi or a HeapObject. |
| 952 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
| 953 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
| 954 &if_rhsisnotsmi); |
| 955 |
| 956 assembler->Bind(&if_rhsissmi); |
| 957 assembler->Goto(&if_notequal); |
| 958 |
| 959 assembler->Bind(&if_rhsisnotsmi); |
| 960 { |
| 961 // Load the map of {rhs}. |
| 962 Node* rhs_map = |
| 963 assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
| 964 |
| 965 // Check if {rhs} is a HeapNumber. |
| 966 Node* number_map = assembler->HeapNumberMapConstant(); |
| 967 Label if_rhsisnumber(assembler), |
| 968 if_rhsisnotnumber(assembler, Label::kDeferred); |
| 969 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 970 &if_rhsisnumber, &if_rhsisnotnumber); |
| 971 |
| 972 assembler->Bind(&if_rhsisnumber); |
| 973 { |
| 974 // Convert {lhs} and {rhs} to floating point values, and |
| 975 // perform a floating point comparison. |
| 976 var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs)); |
| 977 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 978 assembler->Goto(&do_fcmp); |
| 979 } |
| 980 |
| 981 assembler->Bind(&if_rhsisnotnumber); |
| 982 { |
| 983 // Load the instance type of the {rhs}. |
| 984 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); |
| 985 |
| 986 // Check if the {rhs} is a String. |
| 987 Label if_rhsisstring(assembler, Label::kDeferred), |
| 988 if_rhsisnotstring(assembler, Label::kDeferred); |
| 989 assembler->Branch(assembler->Int32LessThan( |
| 990 rhs_instance_type, assembler->Int32Constant( |
| 991 FIRST_NONSTRING_TYPE)), |
| 992 &if_rhsisstring, &if_rhsisnotstring); |
| 993 |
| 994 assembler->Bind(&if_rhsisstring); |
| 995 { |
| 996 // Convert the {rhs} to a Number. |
| 997 Callable callable = CodeFactory::ToNumber(assembler->isolate()); |
| 998 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 999 assembler->Goto(&loop); |
| 1000 } |
| 1001 |
| 1002 assembler->Bind(&if_rhsisnotstring); |
| 1003 { |
| 1004 // Check if the {rhs} is a Boolean. |
| 1005 Node* boolean_map = assembler->BooleanMapConstant(); |
| 1006 Label if_rhsisboolean(assembler, Label::kDeferred), |
| 1007 if_rhsisnotboolean(assembler, Label::kDeferred); |
| 1008 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), |
| 1009 &if_rhsisboolean, &if_rhsisnotboolean); |
| 1010 |
| 1011 assembler->Bind(&if_rhsisboolean); |
| 1012 { |
| 1013 // The {rhs} is a Boolean, load its number value. |
| 1014 var_rhs.Bind( |
| 1015 assembler->LoadObjectField(rhs, Oddball::kToNumberOffset)); |
| 1016 assembler->Goto(&loop); |
| 1017 } |
| 1018 |
| 1019 assembler->Bind(&if_rhsisnotboolean); |
| 1020 { |
| 1021 // Check if the {rhs} is a Receiver. |
| 1022 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 1023 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 1024 if_rhsisnotreceiver(assembler, Label::kDeferred); |
| 1025 assembler->Branch( |
| 1026 assembler->Int32LessThanOrEqual( |
| 1027 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 1028 rhs_instance_type), |
| 1029 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 1030 |
| 1031 assembler->Bind(&if_rhsisreceiver); |
| 1032 { |
| 1033 // Convert {rhs} to a primitive first (passing no hint). |
| 1034 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. |
| 1035 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, |
| 1036 context, rhs)); |
| 1037 assembler->Goto(&loop); |
| 1038 } |
| 1039 |
| 1040 assembler->Bind(&if_rhsisnotreceiver); |
| 1041 assembler->Goto(&if_notequal); |
| 1042 } |
| 1043 } |
| 1044 } |
| 1045 } |
| 1046 } |
| 1047 |
| 1048 assembler->Bind(&if_lhsisnotsmi); |
| 1049 { |
| 1050 // Check if {rhs} is a Smi or a HeapObject. |
| 1051 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
| 1052 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
| 1053 &if_rhsisnotsmi); |
| 1054 |
| 1055 assembler->Bind(&if_rhsissmi); |
| 1056 { |
| 1057 // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs} |
| 1058 // and {rhs} is not observable and doesn't matter for the result, so |
| 1059 // we can just swap them and use the Smi handling above (for {lhs} |
| 1060 // being a Smi). |
| 1061 var_lhs.Bind(rhs); |
| 1062 var_rhs.Bind(lhs); |
| 1063 assembler->Goto(&loop); |
| 1064 } |
| 1065 |
| 1066 assembler->Bind(&if_rhsisnotsmi); |
| 1067 { |
| 1068 Label if_lhsisstring(assembler), if_lhsisnumber(assembler), |
| 1069 if_lhsissymbol(assembler), if_lhsissimd128value(assembler), |
| 1070 if_lhsisoddball(assembler), if_lhsisreceiver(assembler); |
| 1071 |
| 1072 // Both {lhs} and {rhs} are HeapObjects, load their maps |
| 1073 // and their instance types. |
| 1074 Node* lhs_map = |
| 1075 assembler->LoadObjectField(lhs, HeapObject::kMapOffset); |
| 1076 Node* rhs_map = |
| 1077 assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
| 1078 |
| 1079 // Load the instance types of {lhs} and {rhs}. |
| 1080 Node* lhs_instancetype = assembler->LoadMapInstanceType(lhs_map); |
| 1081 Node* rhs_instancetype = assembler->LoadMapInstanceType(rhs_map); |
| 1082 |
| 1083 // Dispatch based on the instance type of {lhs}. |
| 1084 size_t const kNumCases = FIRST_NONSTRING_TYPE + 4; |
| 1085 Label* case_labels[kNumCases]; |
| 1086 int32_t case_values[kNumCases]; |
| 1087 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
| 1088 case_labels[i] = new Label(assembler); |
| 1089 case_values[i] = i; |
| 1090 } |
| 1091 case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber; |
| 1092 case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE; |
| 1093 case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol; |
| 1094 case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE; |
| 1095 case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value; |
| 1096 case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE; |
| 1097 case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball; |
| 1098 case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE; |
| 1099 assembler->Switch(lhs_instancetype, &if_lhsisreceiver, case_values, |
| 1100 case_labels, arraysize(case_values)); |
| 1101 for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) { |
| 1102 assembler->Bind(case_labels[i]); |
| 1103 assembler->Goto(&if_lhsisstring); |
| 1104 delete case_labels[i]; |
| 1105 } |
| 1106 |
| 1107 assembler->Bind(&if_lhsisstring); |
| 1108 { |
| 1109 // Check if {rhs} is also a String. |
| 1110 Label if_rhsisstring(assembler), |
| 1111 if_rhsisnotstring(assembler, Label::kDeferred); |
| 1112 assembler->Branch(assembler->Int32LessThan( |
| 1113 rhs_instancetype, assembler->Int32Constant( |
| 1114 FIRST_NONSTRING_TYPE)), |
| 1115 &if_rhsisstring, &if_rhsisnotstring); |
| 1116 |
| 1117 assembler->Bind(&if_rhsisstring); |
| 1118 { |
| 1119 // Both {lhs} and {rhs} are of type String, just do the |
| 1120 // string comparison then. |
| 1121 Callable callable = |
| 1122 (mode == kDontNegateResult) |
| 1123 ? CodeFactory::StringEqual(assembler->isolate()) |
| 1124 : CodeFactory::StringNotEqual(assembler->isolate()); |
| 1125 assembler->TailCallStub(callable, context, lhs, rhs); |
| 1126 } |
| 1127 |
| 1128 assembler->Bind(&if_rhsisnotstring); |
| 1129 { |
| 1130 // Check if {rhs} is a HeapNumber. |
| 1131 Label if_rhsisnumber(assembler, Label::kDeferred), |
| 1132 if_rhsisnotnumber(assembler); |
| 1133 assembler->Branch(assembler->Word32Equal( |
| 1134 rhs_instancetype, |
| 1135 assembler->Int32Constant(HEAP_NUMBER_TYPE)), |
| 1136 &if_rhsisnumber, &if_rhsisnotnumber); |
| 1137 |
| 1138 assembler->Bind(&if_rhsisnumber); |
| 1139 { |
| 1140 // The {lhs} is a String and the {rhs} is a HeapNumber; we need |
| 1141 // to convert the {lhs} to a Number and compare the output to |
| 1142 // the Number on the {rhs}. |
| 1143 Callable callable = CodeFactory::ToNumber(assembler->isolate()); |
| 1144 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 1145 assembler->Goto(&loop); |
| 1146 } |
| 1147 |
| 1148 assembler->Bind(&if_rhsisnotnumber); |
| 1149 { |
| 1150 // The {lhs} is a String, but the {rhs} is neither a String nor |
| 1151 // a Number. Check if {rhs} is a Boolean. |
| 1152 Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler); |
| 1153 Node* boolean_map = assembler->BooleanMapConstant(); |
| 1154 assembler->Branch(assembler->WordEqual(rhs_map, boolean_map), |
| 1155 &if_rhsisboolean, &if_rhsisnotboolean); |
| 1156 |
| 1157 assembler->Bind(&if_rhsisboolean); |
| 1158 { |
| 1159 // The {rhs} is a Boolean, convert it to Number first. |
| 1160 var_rhs.Bind(assembler->LoadObjectField( |
| 1161 rhs, Oddball::kToNumberOffset)); |
| 1162 assembler->Goto(&loop); |
| 1163 } |
| 1164 |
| 1165 assembler->Bind(&if_rhsisnotboolean); |
| 1166 { |
| 1167 // The {lhs} is a String, but the {rhs} is none of String, |
| 1168 // Number or Boolean. Check if {rhs} is a JSReceiver. |
| 1169 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 1170 if_rhsisnotreceiver(assembler); |
| 1171 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 1172 assembler->Branch( |
| 1173 assembler->Int32LessThanOrEqual( |
| 1174 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 1175 rhs_instancetype), |
| 1176 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 1177 |
| 1178 assembler->Bind(&if_rhsisreceiver); |
| 1179 { |
| 1180 // Convert {rhs} to a primitive first (passing no hint). |
| 1181 // TODO(bmeurer): Hook up ToPrimitiveStub here. |
| 1182 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, |
| 1183 context, rhs)); |
| 1184 assembler->Goto(&loop); |
| 1185 } |
| 1186 |
| 1187 assembler->Bind(&if_rhsisnotreceiver); |
| 1188 { |
| 1189 // The {lhs} is a String, but the {rhs} is neither a String, |
| 1190 // nor Number, nor Boolean, nor JSReceiver, so the two |
| 1191 // values cannot be considered equal. |
| 1192 assembler->Goto(&if_notequal); |
| 1193 } |
| 1194 } |
| 1195 } |
| 1196 } |
| 1197 } |
| 1198 |
| 1199 assembler->Bind(&if_lhsisnumber); |
| 1200 { |
| 1201 // Check if {rhs} is also a HeapNumber. |
| 1202 Label if_rhsisnumber(assembler), |
| 1203 if_rhsisnotnumber(assembler, Label::kDeferred); |
| 1204 assembler->Branch( |
| 1205 assembler->Word32Equal(lhs_instancetype, rhs_instancetype), |
| 1206 &if_rhsisnumber, &if_rhsisnotnumber); |
| 1207 |
| 1208 assembler->Bind(&if_rhsisnumber); |
| 1209 { |
| 1210 // Convert {lhs} and {rhs} to floating point values, and |
| 1211 // perform a floating point comparison. |
| 1212 var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 1213 var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 1214 assembler->Goto(&do_fcmp); |
| 1215 } |
| 1216 |
| 1217 assembler->Bind(&if_rhsisnotnumber); |
| 1218 { |
| 1219 // The {lhs} is a Number, the {rhs} is some other HeapObject. |
| 1220 // TODO(bmeurer): Make this fast! |
| 1221 var_rcmp_lhs.Bind(lhs); |
| 1222 var_rcmp_rhs.Bind(rhs); |
| 1223 assembler->Goto(&do_rcmp); |
| 1224 } |
| 1225 } |
| 1226 |
| 1227 assembler->Bind(&if_lhsisoddball); |
| 1228 { |
| 1229 // The {lhs} is an Oddball and {rhs} is some other HeapObject. |
| 1230 Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler); |
| 1231 Node* boolean_map = assembler->BooleanMapConstant(); |
| 1232 assembler->Branch(assembler->WordEqual(lhs_map, boolean_map), |
| 1233 &if_lhsisboolean, &if_lhsisnotboolean); |
| 1234 |
| 1235 assembler->Bind(&if_lhsisboolean); |
| 1236 { |
| 1237 // The {lhs} is a Boolean, convert it to a Number first. |
| 1238 var_lhs.Bind( |
| 1239 assembler->LoadObjectField(lhs, Oddball::kToNumberOffset)); |
| 1240 assembler->Goto(&loop); |
| 1241 } |
| 1242 |
| 1243 assembler->Bind(&if_lhsisnotboolean); |
| 1244 { |
| 1245 // The {lhs} is either Null or Undefined; check if the {rhs} is |
| 1246 // undetectable (i.e. either also Null or Undefined or some |
| 1247 // undetectable JSReceiver). |
| 1248 Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map); |
| 1249 assembler->BranchIfWord32Equal( |
| 1250 assembler->Word32And( |
| 1251 rhs_bitfield, |
| 1252 assembler->Int32Constant(1 << Map::kIsUndetectable)), |
| 1253 assembler->Int32Constant(0), &if_notequal, &if_equal); |
| 1254 } |
| 1255 } |
| 1256 |
| 1257 assembler->Bind(&if_lhsissymbol); |
| 1258 { |
| 1259 // Check if the {rhs} is a JSReceiver. |
| 1260 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 1261 if_rhsisnotreceiver(assembler); |
| 1262 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 1263 assembler->Branch( |
| 1264 assembler->Int32LessThanOrEqual( |
| 1265 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 1266 rhs_instancetype), |
| 1267 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 1268 |
| 1269 assembler->Bind(&if_rhsisreceiver); |
| 1270 { |
| 1271 // Convert {rhs} to a primitive first (passing no hint). |
| 1272 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. |
| 1273 var_rhs.Bind( |
| 1274 assembler->CallRuntime(Runtime::kToPrimitive, context, rhs)); |
| 1275 assembler->Goto(&loop); |
| 1276 } |
| 1277 |
| 1278 assembler->Bind(&if_rhsisnotreceiver); |
| 1279 { |
| 1280 // The {rhs} is not a JSReceiver and also not the same Symbol |
| 1281 // as the {lhs}, so this is equality check is considered false. |
| 1282 assembler->Goto(&if_notequal); |
| 1283 } |
| 1284 } |
| 1285 |
| 1286 assembler->Bind(&if_lhsissimd128value); |
| 1287 { |
| 1288 // Check if the {rhs} is also a Simd128Value. |
| 1289 Label if_rhsissimd128value(assembler), |
| 1290 if_rhsisnotsimd128value(assembler); |
| 1291 assembler->Branch( |
| 1292 assembler->Word32Equal(lhs_instancetype, rhs_instancetype), |
| 1293 &if_rhsissimd128value, &if_rhsisnotsimd128value); |
| 1294 |
| 1295 assembler->Bind(&if_rhsissimd128value); |
| 1296 { |
| 1297 // The {lhs} is a Simd128Value. |
| 1298 // TODO(bmeurer): Make this fast! |
| 1299 var_rcmp_lhs.Bind(lhs); |
| 1300 var_rcmp_rhs.Bind(rhs); |
| 1301 assembler->Goto(&do_rcmp); |
| 1302 } |
| 1303 |
| 1304 assembler->Bind(&if_rhsisnotsimd128value); |
| 1305 { |
| 1306 // Check if the {rhs} is a JSReceiver. |
| 1307 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 1308 if_rhsisnotreceiver(assembler); |
| 1309 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 1310 assembler->Branch( |
| 1311 assembler->Int32LessThanOrEqual( |
| 1312 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 1313 rhs_instancetype), |
| 1314 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 1315 |
| 1316 assembler->Bind(&if_rhsisreceiver); |
| 1317 { |
| 1318 // Convert {rhs} to a primitive first (passing no hint). |
| 1319 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists. |
| 1320 var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive, |
| 1321 context, rhs)); |
| 1322 assembler->Goto(&loop); |
| 1323 } |
| 1324 |
| 1325 assembler->Bind(&if_rhsisnotreceiver); |
| 1326 { |
| 1327 // The {rhs} is some other Primitive. |
| 1328 assembler->Goto(&if_notequal); |
| 1329 } |
| 1330 } |
| 1331 } |
| 1332 |
| 1333 assembler->Bind(&if_lhsisreceiver); |
| 1334 { |
| 1335 // Check if the {rhs} is also a JSReceiver. |
| 1336 Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler); |
| 1337 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 1338 assembler->Branch( |
| 1339 assembler->Int32LessThanOrEqual( |
| 1340 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 1341 rhs_instancetype), |
| 1342 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 1343 |
| 1344 assembler->Bind(&if_rhsisreceiver); |
| 1345 { |
| 1346 // Both {lhs} and {rhs} are different JSReceiver references, so |
| 1347 // this cannot be considered equal. |
| 1348 assembler->Goto(&if_notequal); |
| 1349 } |
| 1350 |
| 1351 assembler->Bind(&if_rhsisnotreceiver); |
| 1352 { |
| 1353 // The {lhs} is a JSReceiver and the {rhs} is a Primitive. |
| 1354 // Swapping {lhs} and {rhs} is not observable and doesn't |
| 1355 // matter for the result, so we can just swap them and use |
| 1356 // the Primitive handling above (for {lhs} being a Primitive). |
| 1357 var_lhs.Bind(rhs); |
| 1358 var_rhs.Bind(lhs); |
| 1359 assembler->Goto(&loop); |
| 1360 } |
| 1361 } |
| 1362 } |
| 1363 } |
| 1364 } |
| 1365 } |
| 1366 |
| 1367 assembler->Bind(&do_fcmp); |
| 1368 { |
| 1369 // Load the {lhs} and {rhs} floating point values. |
| 1370 Node* lhs = var_fcmp_lhs.value(); |
| 1371 Node* rhs = var_fcmp_rhs.value(); |
| 1372 |
| 1373 // Perform a fast floating point comparison. |
| 1374 assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal); |
| 1375 } |
| 1376 |
| 1377 assembler->Bind(&do_rcmp); |
| 1378 { |
| 1379 // Load the {lhs} and {rhs} floating point values. |
| 1380 Node* lhs = var_rcmp_lhs.value(); |
| 1381 Node* rhs = var_rcmp_rhs.value(); |
| 1382 |
| 1383 // Perform a slow runtime comparison. |
| 1384 switch (mode) { |
| 1385 case kDontNegateResult: |
| 1386 assembler->TailCallRuntime(Runtime::kEqual, context, lhs, rhs); |
| 1387 break; |
| 1388 case kNegateResult: |
| 1389 assembler->TailCallRuntime(Runtime::kNotEqual, context, lhs, rhs); |
| 1390 break; |
| 1391 } |
| 1392 } |
| 1393 |
| 1394 assembler->Bind(&if_equal); |
| 1395 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); |
| 1396 |
| 1397 assembler->Bind(&if_notequal); |
| 1398 assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); |
| 1399 } |
| 1400 |
851 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, | 1401 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, |
852 ResultMode mode) { | 1402 ResultMode mode) { |
853 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | 1403 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
854 // mode; for kNegateResult mode we properly negate the result. | 1404 // mode; for kNegateResult mode we properly negate the result. |
855 // | 1405 // |
856 // if (lhs == rhs) { | 1406 // if (lhs == rhs) { |
857 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; | 1407 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; |
858 // return true; | 1408 // return true; |
859 // } | 1409 // } |
860 // if (!lhs->IsSmi()) { | 1410 // if (!lhs->IsSmi()) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 Label if_equal(assembler), if_notequal(assembler); | 1458 Label if_equal(assembler), if_notequal(assembler); |
909 | 1459 |
910 // Check if {lhs} and {rhs} refer to the same object. | 1460 // Check if {lhs} and {rhs} refer to the same object. |
911 Label if_same(assembler), if_notsame(assembler); | 1461 Label if_same(assembler), if_notsame(assembler); |
912 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | 1462 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
913 | 1463 |
914 assembler->Bind(&if_same); | 1464 assembler->Bind(&if_same); |
915 { | 1465 { |
916 // The {lhs} and {rhs} reference the exact same value, yet we need special | 1466 // The {lhs} and {rhs} reference the exact same value, yet we need special |
917 // treatment for HeapNumber, as NaN is not equal to NaN. | 1467 // treatment for HeapNumber, as NaN is not equal to NaN. |
918 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it | 1468 GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal); |
919 // seems to be what is tested in the current SIMD.js testsuite. | |
920 | |
921 // Check if {lhs} (and therefore {rhs}) is a Smi or a HeapObject. | |
922 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | |
923 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | |
924 | |
925 assembler->Bind(&if_lhsisnotsmi); | |
926 { | |
927 // Load the map of {lhs}. | |
928 Node* lhs_map = assembler->LoadObjectField(lhs, HeapObject::kMapOffset); | |
929 | |
930 // Check if {lhs} (and therefore {rhs}) is a HeapNumber. | |
931 Node* number_map = assembler->HeapNumberMapConstant(); | |
932 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | |
933 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | |
934 &if_lhsisnumber, &if_lhsisnotnumber); | |
935 | |
936 assembler->Bind(&if_lhsisnumber); | |
937 { | |
938 // Convert {lhs} (and therefore {rhs}) to floating point value. | |
939 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | |
940 | |
941 // Check if the HeapNumber value is a NaN. | |
942 assembler->BranchIfFloat64IsNaN(lhs_value, &if_notequal, &if_equal); | |
943 } | |
944 | |
945 assembler->Bind(&if_lhsisnotnumber); | |
946 assembler->Goto(&if_equal); | |
947 } | |
948 | |
949 assembler->Bind(&if_lhsissmi); | |
950 assembler->Goto(&if_equal); | |
951 } | 1469 } |
952 | 1470 |
953 assembler->Bind(&if_notsame); | 1471 assembler->Bind(&if_notsame); |
954 { | 1472 { |
955 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, | 1473 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, |
956 // String and Simd128Value they can still be considered equal. | 1474 // String and Simd128Value they can still be considered equal. |
957 Node* number_map = assembler->HeapNumberMapConstant(); | 1475 Node* number_map = assembler->HeapNumberMapConstant(); |
958 | 1476 |
959 // Check if {lhs} is a Smi or a HeapObject. | 1477 // Check if {lhs} is a Smi or a HeapObject. |
960 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | 1478 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1511 void GreaterThanStub::GenerateAssembly( | 2029 void GreaterThanStub::GenerateAssembly( |
1512 compiler::CodeStubAssembler* assembler) const { | 2030 compiler::CodeStubAssembler* assembler) const { |
1513 GenerateAbstractRelationalComparison(assembler, kGreaterThan); | 2031 GenerateAbstractRelationalComparison(assembler, kGreaterThan); |
1514 } | 2032 } |
1515 | 2033 |
1516 void GreaterThanOrEqualStub::GenerateAssembly( | 2034 void GreaterThanOrEqualStub::GenerateAssembly( |
1517 compiler::CodeStubAssembler* assembler) const { | 2035 compiler::CodeStubAssembler* assembler) const { |
1518 GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual); | 2036 GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual); |
1519 } | 2037 } |
1520 | 2038 |
| 2039 void EqualStub::GenerateAssembly(compiler::CodeStubAssembler* assembler) const { |
| 2040 GenerateEqual(assembler, kDontNegateResult); |
| 2041 } |
| 2042 |
| 2043 void NotEqualStub::GenerateAssembly( |
| 2044 compiler::CodeStubAssembler* assembler) const { |
| 2045 GenerateEqual(assembler, kNegateResult); |
| 2046 } |
| 2047 |
1521 void StrictEqualStub::GenerateAssembly( | 2048 void StrictEqualStub::GenerateAssembly( |
1522 compiler::CodeStubAssembler* assembler) const { | 2049 compiler::CodeStubAssembler* assembler) const { |
1523 GenerateStrictEqual(assembler, kDontNegateResult); | 2050 GenerateStrictEqual(assembler, kDontNegateResult); |
1524 } | 2051 } |
1525 | 2052 |
1526 void StrictNotEqualStub::GenerateAssembly( | 2053 void StrictNotEqualStub::GenerateAssembly( |
1527 compiler::CodeStubAssembler* assembler) const { | 2054 compiler::CodeStubAssembler* assembler) const { |
1528 GenerateStrictEqual(assembler, kNegateResult); | 2055 GenerateStrictEqual(assembler, kNegateResult); |
1529 } | 2056 } |
1530 | 2057 |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2126 if (type->Is(Type::UntaggedPointer())) { | 2653 if (type->Is(Type::UntaggedPointer())) { |
2127 return Representation::External(); | 2654 return Representation::External(); |
2128 } | 2655 } |
2129 | 2656 |
2130 DCHECK(!type->Is(Type::Untagged())); | 2657 DCHECK(!type->Is(Type::Untagged())); |
2131 return Representation::Tagged(); | 2658 return Representation::Tagged(); |
2132 } | 2659 } |
2133 | 2660 |
2134 } // namespace internal | 2661 } // namespace internal |
2135 } // namespace v8 | 2662 } // namespace v8 |
OLD | NEW |