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

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

Issue 1761783004: [WIP] EqualStub and NotEqualStub. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@StringRelationalComparison
Patch Set: Updates Created 4 years, 9 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/compiler/code-stub-assembler.h » ('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/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
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
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
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
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
OLDNEW
« no previous file with comments | « src/code-stubs.h ('k') | src/compiler/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698