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

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

Issue 10837165: Lattice-based representation inference, powered by left/right specific type feedback for BinaryOps … (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: HConstants, HSimulates, stub fixes Created 8 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 979 matching lines...) Expand 10 before | Expand all | Expand 10 after
990 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 990 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
991 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 991 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
992 } 992 }
993 stream->Add("UnaryOpStub_%s_%s_%s", 993 stream->Add("UnaryOpStub_%s_%s_%s",
994 op_name, 994 op_name,
995 overwrite_name, 995 overwrite_name,
996 UnaryOpIC::GetName(operand_type_)); 996 UnaryOpIC::GetName(operand_type_));
997 } 997 }
998 998
999 999
1000 void BinaryOpStub::Initialize() {}
1001
1002
1000 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 1003 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
1001 __ pop(rcx); // Save return address. 1004 __ pop(rcx); // Save return address.
1002 __ push(rdx); 1005 __ push(rdx);
1003 __ push(rax); 1006 __ push(rax);
1004 // Left and right arguments are now on top. 1007 // Left and right arguments are now on top.
1005 // Push this stub's key. Although the operation and the type info are
1006 // encoded into the key, the encoding is opaque, so push them too.
1007 __ Push(Smi::FromInt(MinorKey())); 1008 __ Push(Smi::FromInt(MinorKey()));
1008 __ Push(Smi::FromInt(op_));
1009 __ Push(Smi::FromInt(operands_type_));
1010 1009
1011 __ push(rcx); // Push return address. 1010 __ push(rcx); // Push return address.
1012 1011
1013 // Patch the caller to an appropriate specialized stub and return the 1012 // Patch the caller to an appropriate specialized stub and return the
1014 // operation result to the caller of the stub. 1013 // operation result to the caller of the stub.
1015 __ TailCallExternalReference( 1014 __ TailCallExternalReference(
1016 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 1015 ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
1017 masm->isolate()), 1016 masm->isolate()),
1018 5, 1017 3,
1019 1); 1018 1);
1020 } 1019 }
1021 1020
1022 1021
1023 void BinaryOpStub::Generate(MacroAssembler* masm) { 1022 static void BinaryOpStub_GenerateSmiCode(
1024 // Explicitly allow generation of nested stubs. It is safe here because
1025 // generation code does not use any raw pointers.
1026 AllowStubCallsScope allow_stub_calls(masm, true);
1027
1028 switch (operands_type_) {
1029 case BinaryOpIC::UNINITIALIZED:
1030 GenerateTypeTransition(masm);
1031 break;
1032 case BinaryOpIC::SMI:
1033 GenerateSmiStub(masm);
1034 break;
1035 case BinaryOpIC::INT32:
1036 UNREACHABLE();
1037 // The int32 case is identical to the Smi case. We avoid creating this
1038 // ic state on x64.
1039 break;
1040 case BinaryOpIC::HEAP_NUMBER:
1041 GenerateHeapNumberStub(masm);
1042 break;
1043 case BinaryOpIC::ODDBALL:
1044 GenerateOddballStub(masm);
1045 break;
1046 case BinaryOpIC::BOTH_STRING:
1047 GenerateBothStringStub(masm);
1048 break;
1049 case BinaryOpIC::STRING:
1050 GenerateStringStub(masm);
1051 break;
1052 case BinaryOpIC::GENERIC:
1053 GenerateGeneric(masm);
1054 break;
1055 default:
1056 UNREACHABLE();
1057 }
1058 }
1059
1060
1061 void BinaryOpStub::PrintName(StringStream* stream) {
1062 const char* op_name = Token::Name(op_);
1063 const char* overwrite_name;
1064 switch (mode_) {
1065 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
1066 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
1067 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
1068 default: overwrite_name = "UnknownOverwrite"; break;
1069 }
1070 stream->Add("BinaryOpStub_%s_%s_%s",
1071 op_name,
1072 overwrite_name,
1073 BinaryOpIC::GetName(operands_type_));
1074 }
1075
1076
1077 void BinaryOpStub::GenerateSmiCode(
1078 MacroAssembler* masm, 1023 MacroAssembler* masm,
1079 Label* slow, 1024 Label* slow,
1080 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 1025 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
1026 Token::Value op) {
1081 1027
1082 // Arguments to BinaryOpStub are in rdx and rax. 1028 // Arguments to BinaryOpStub are in rdx and rax.
1083 const Register left = rdx; 1029 const Register left = rdx;
1084 const Register right = rax; 1030 const Register right = rax;
1085 1031
1086 // We only generate heapnumber answers for overflowing calculations 1032 // We only generate heapnumber answers for overflowing calculations
1087 // for the four basic arithmetic operations and logical right shift by 0. 1033 // for the four basic arithmetic operations and logical right shift by 0.
1088 bool generate_inline_heapnumber_results = 1034 bool generate_inline_heapnumber_results =
1089 (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) && 1035 (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) &&
1090 (op_ == Token::ADD || op_ == Token::SUB || 1036 (op == Token::ADD || op == Token::SUB ||
1091 op_ == Token::MUL || op_ == Token::DIV || op_ == Token::SHR); 1037 op == Token::MUL || op == Token::DIV || op == Token::SHR);
1092 1038
1093 // Smi check of both operands. If op is BIT_OR, the check is delayed 1039 // Smi check of both operands. If op is BIT_OR, the check is delayed
1094 // until after the OR operation. 1040 // until after the OR operation.
1095 Label not_smis; 1041 Label not_smis;
1096 Label use_fp_on_smis; 1042 Label use_fp_on_smis;
1097 Label fail; 1043 Label fail;
1098 1044
1099 if (op_ != Token::BIT_OR) { 1045 if (op != Token::BIT_OR) {
1100 Comment smi_check_comment(masm, "-- Smi check arguments"); 1046 Comment smi_check_comment(masm, "-- Smi check arguments");
1101 __ JumpIfNotBothSmi(left, right, &not_smis); 1047 __ JumpIfNotBothSmi(left, right, &not_smis);
1102 } 1048 }
1103 1049
1104 Label smi_values; 1050 Label smi_values;
1105 __ bind(&smi_values); 1051 __ bind(&smi_values);
1106 // Perform the operation. 1052 // Perform the operation.
1107 Comment perform_smi(masm, "-- Perform smi operation"); 1053 Comment perform_smi(masm, "-- Perform smi operation");
1108 switch (op_) { 1054 switch (op) {
1109 case Token::ADD: 1055 case Token::ADD:
1110 ASSERT(right.is(rax)); 1056 ASSERT(right.is(rax));
1111 __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative. 1057 __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative.
1112 break; 1058 break;
1113 1059
1114 case Token::SUB: 1060 case Token::SUB:
1115 __ SmiSub(left, left, right, &use_fp_on_smis); 1061 __ SmiSub(left, left, right, &use_fp_on_smis);
1116 __ movq(rax, left); 1062 __ movq(rax, left);
1117 break; 1063 break;
1118 1064
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1170 } 1116 }
1171 1117
1172 // 5. Emit return of result in rax. Some operations have registers pushed. 1118 // 5. Emit return of result in rax. Some operations have registers pushed.
1173 __ ret(0); 1119 __ ret(0);
1174 1120
1175 if (use_fp_on_smis.is_linked()) { 1121 if (use_fp_on_smis.is_linked()) {
1176 // 6. For some operations emit inline code to perform floating point 1122 // 6. For some operations emit inline code to perform floating point
1177 // operations on known smis (e.g., if the result of the operation 1123 // operations on known smis (e.g., if the result of the operation
1178 // overflowed the smi range). 1124 // overflowed the smi range).
1179 __ bind(&use_fp_on_smis); 1125 __ bind(&use_fp_on_smis);
1180 if (op_ == Token::DIV || op_ == Token::MOD) { 1126 if (op == Token::DIV || op == Token::MOD) {
1181 // Restore left and right to rdx and rax. 1127 // Restore left and right to rdx and rax.
1182 __ movq(rdx, rcx); 1128 __ movq(rdx, rcx);
1183 __ movq(rax, rbx); 1129 __ movq(rax, rbx);
1184 } 1130 }
1185 1131
1186 if (generate_inline_heapnumber_results) { 1132 if (generate_inline_heapnumber_results) {
1187 __ AllocateHeapNumber(rcx, rbx, slow); 1133 __ AllocateHeapNumber(rcx, rbx, slow);
1188 Comment perform_float(masm, "-- Perform float operation on smis"); 1134 Comment perform_float(masm, "-- Perform float operation on smis");
1189 if (op_ == Token::SHR) { 1135 if (op == Token::SHR) {
1190 __ SmiToInteger32(left, left); 1136 __ SmiToInteger32(left, left);
1191 __ cvtqsi2sd(xmm0, left); 1137 __ cvtqsi2sd(xmm0, left);
1192 } else { 1138 } else {
1193 FloatingPointHelper::LoadSSE2SmiOperands(masm); 1139 FloatingPointHelper::LoadSSE2SmiOperands(masm);
1194 switch (op_) { 1140 switch (op) {
1195 case Token::ADD: __ addsd(xmm0, xmm1); break; 1141 case Token::ADD: __ addsd(xmm0, xmm1); break;
1196 case Token::SUB: __ subsd(xmm0, xmm1); break; 1142 case Token::SUB: __ subsd(xmm0, xmm1); break;
1197 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1143 case Token::MUL: __ mulsd(xmm0, xmm1); break;
1198 case Token::DIV: __ divsd(xmm0, xmm1); break; 1144 case Token::DIV: __ divsd(xmm0, xmm1); break;
1199 default: UNREACHABLE(); 1145 default: UNREACHABLE();
1200 } 1146 }
1201 } 1147 }
1202 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); 1148 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
1203 __ movq(rax, rcx); 1149 __ movq(rax, rcx);
1204 __ ret(0); 1150 __ ret(0);
1205 } else { 1151 } else {
1206 __ jmp(&fail); 1152 __ jmp(&fail);
1207 } 1153 }
1208 } 1154 }
1209 1155
1210 // 7. Non-smi operands reach the end of the code generated by 1156 // 7. Non-smi operands reach the end of the code generated by
1211 // GenerateSmiCode, and fall through to subsequent code, 1157 // GenerateSmiCode, and fall through to subsequent code,
1212 // with the operands in rdx and rax. 1158 // with the operands in rdx and rax.
1213 // But first we check if non-smi values are HeapNumbers holding 1159 // But first we check if non-smi values are HeapNumbers holding
1214 // values that could be smi. 1160 // values that could be smi.
1215 __ bind(&not_smis); 1161 __ bind(&not_smis);
1216 Comment done_comment(masm, "-- Enter non-smi code"); 1162 Comment done_comment(masm, "-- Enter non-smi code");
1217 FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx, 1163 FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx,
1218 &smi_values, &fail); 1164 &smi_values, &fail);
1219 __ jmp(&smi_values); 1165 __ jmp(&smi_values);
1220 __ bind(&fail); 1166 __ bind(&fail);
1221 } 1167 }
1222 1168
1223 1169
1224 void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, 1170 static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
1225 Label* allocation_failure, 1171 Label* alloc_failure,
1226 Label* non_numeric_failure) { 1172 OverwriteMode mode);
1227 switch (op_) { 1173
1174
1175 static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm,
1176 Label* allocation_failure,
1177 Label* non_numeric_failure,
1178 Token::Value op,
1179 OverwriteMode mode) {
1180 switch (op) {
1228 case Token::ADD: 1181 case Token::ADD:
1229 case Token::SUB: 1182 case Token::SUB:
1230 case Token::MUL: 1183 case Token::MUL:
1231 case Token::DIV: { 1184 case Token::DIV: {
1232 FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure); 1185 FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure);
1233 1186
1234 switch (op_) { 1187 switch (op) {
1235 case Token::ADD: __ addsd(xmm0, xmm1); break; 1188 case Token::ADD: __ addsd(xmm0, xmm1); break;
1236 case Token::SUB: __ subsd(xmm0, xmm1); break; 1189 case Token::SUB: __ subsd(xmm0, xmm1); break;
1237 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1190 case Token::MUL: __ mulsd(xmm0, xmm1); break;
1238 case Token::DIV: __ divsd(xmm0, xmm1); break; 1191 case Token::DIV: __ divsd(xmm0, xmm1); break;
1239 default: UNREACHABLE(); 1192 default: UNREACHABLE();
1240 } 1193 }
1241 GenerateHeapResultAllocation(masm, allocation_failure); 1194 BinaryOpStub_GenerateHeapResultAllocation(
1195 masm, allocation_failure, mode);
1242 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); 1196 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
1243 __ ret(0); 1197 __ ret(0);
1244 break; 1198 break;
1245 } 1199 }
1246 case Token::MOD: { 1200 case Token::MOD: {
1247 // For MOD we jump to the allocation_failure label, to call runtime. 1201 // For MOD we jump to the allocation_failure label, to call runtime.
1248 __ jmp(allocation_failure); 1202 __ jmp(allocation_failure);
1249 break; 1203 break;
1250 } 1204 }
1251 case Token::BIT_OR: 1205 case Token::BIT_OR:
1252 case Token::BIT_AND: 1206 case Token::BIT_AND:
1253 case Token::BIT_XOR: 1207 case Token::BIT_XOR:
1254 case Token::SAR: 1208 case Token::SAR:
1255 case Token::SHL: 1209 case Token::SHL:
1256 case Token::SHR: { 1210 case Token::SHR: {
1257 Label non_smi_shr_result; 1211 Label non_smi_shr_result;
1258 Register heap_number_map = r9; 1212 Register heap_number_map = r9;
1259 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 1213 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
1260 FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure, 1214 FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure,
1261 heap_number_map); 1215 heap_number_map);
1262 switch (op_) { 1216 switch (op) {
1263 case Token::BIT_OR: __ orl(rax, rcx); break; 1217 case Token::BIT_OR: __ orl(rax, rcx); break;
1264 case Token::BIT_AND: __ andl(rax, rcx); break; 1218 case Token::BIT_AND: __ andl(rax, rcx); break;
1265 case Token::BIT_XOR: __ xorl(rax, rcx); break; 1219 case Token::BIT_XOR: __ xorl(rax, rcx); break;
1266 case Token::SAR: __ sarl_cl(rax); break; 1220 case Token::SAR: __ sarl_cl(rax); break;
1267 case Token::SHL: __ shll_cl(rax); break; 1221 case Token::SHL: __ shll_cl(rax); break;
1268 case Token::SHR: { 1222 case Token::SHR: {
1269 __ shrl_cl(rax); 1223 __ shrl_cl(rax);
1270 // Check if result is negative. This can only happen for a shift 1224 // Check if result is negative. This can only happen for a shift
1271 // by zero. 1225 // by zero.
1272 __ testl(rax, rax); 1226 __ testl(rax, rax);
1273 __ j(negative, &non_smi_shr_result); 1227 __ j(negative, &non_smi_shr_result);
1274 break; 1228 break;
1275 } 1229 }
1276 default: UNREACHABLE(); 1230 default: UNREACHABLE();
1277 } 1231 }
1278 STATIC_ASSERT(kSmiValueSize == 32); 1232 STATIC_ASSERT(kSmiValueSize == 32);
1279 // Tag smi result and return. 1233 // Tag smi result and return.
1280 __ Integer32ToSmi(rax, rax); 1234 __ Integer32ToSmi(rax, rax);
1281 __ Ret(); 1235 __ Ret();
1282 1236
1283 // Logical shift right can produce an unsigned int32 that is not 1237 // Logical shift right can produce an unsigned int32 that is not
1284 // an int32, and so is not in the smi range. Allocate a heap number 1238 // an int32, and so is not in the smi range. Allocate a heap number
1285 // in that case. 1239 // in that case.
1286 if (op_ == Token::SHR) { 1240 if (op == Token::SHR) {
1287 __ bind(&non_smi_shr_result); 1241 __ bind(&non_smi_shr_result);
1288 Label allocation_failed; 1242 Label allocation_failed;
1289 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). 1243 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64).
1290 // Allocate heap number in new space. 1244 // Allocate heap number in new space.
1291 // Not using AllocateHeapNumber macro in order to reuse 1245 // Not using AllocateHeapNumber macro in order to reuse
1292 // already loaded heap_number_map. 1246 // already loaded heap_number_map.
1293 __ AllocateInNewSpace(HeapNumber::kSize, 1247 __ AllocateInNewSpace(HeapNumber::kSize,
1294 rax, 1248 rax,
1295 rdx, 1249 rdx,
1296 no_reg, 1250 no_reg,
(...skipping 16 matching lines...) Expand all
1313 __ Integer32ToSmi(rdx, rbx); 1267 __ Integer32ToSmi(rdx, rbx);
1314 __ jmp(allocation_failure); 1268 __ jmp(allocation_failure);
1315 } 1269 }
1316 break; 1270 break;
1317 } 1271 }
1318 default: UNREACHABLE(); break; 1272 default: UNREACHABLE(); break;
1319 } 1273 }
1320 // No fall-through from this generated code. 1274 // No fall-through from this generated code.
1321 if (FLAG_debug_code) { 1275 if (FLAG_debug_code) {
1322 __ Abort("Unexpected fall-through in " 1276 __ Abort("Unexpected fall-through in "
1323 "BinaryStub::GenerateFloatingPointCode."); 1277 "BinaryStub_GenerateFloatingPointCode.");
1324 } 1278 }
1325 } 1279 }
1326 1280
1327 1281
1328 void BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { 1282 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
1329 ASSERT(op_ == Token::ADD); 1283 ASSERT(op_ == Token::ADD);
1330 Label left_not_string, call_runtime; 1284 Label left_not_string, call_runtime;
1331 1285
1332 // Registers containing left and right operands respectively. 1286 // Registers containing left and right operands respectively.
1333 Register left = rdx; 1287 Register left = rdx;
1334 Register right = rax; 1288 Register right = rax;
1335 1289
1336 // Test if left operand is a string. 1290 // Test if left operand is a string.
1337 __ JumpIfSmi(left, &left_not_string, Label::kNear); 1291 __ JumpIfSmi(left, &left_not_string, Label::kNear);
1338 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); 1292 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
(...skipping 10 matching lines...) Expand all
1349 1303
1350 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 1304 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
1351 GenerateRegisterArgsPush(masm); 1305 GenerateRegisterArgsPush(masm);
1352 __ TailCallStub(&string_add_right_stub); 1306 __ TailCallStub(&string_add_right_stub);
1353 1307
1354 // Neither argument is a string. 1308 // Neither argument is a string.
1355 __ bind(&call_runtime); 1309 __ bind(&call_runtime);
1356 } 1310 }
1357 1311
1358 1312
1359 void BinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) {
1360 GenerateRegisterArgsPush(masm);
1361 switch (op_) {
1362 case Token::ADD:
1363 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1364 break;
1365 case Token::SUB:
1366 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
1367 break;
1368 case Token::MUL:
1369 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
1370 break;
1371 case Token::DIV:
1372 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
1373 break;
1374 case Token::MOD:
1375 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
1376 break;
1377 case Token::BIT_OR:
1378 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
1379 break;
1380 case Token::BIT_AND:
1381 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
1382 break;
1383 case Token::BIT_XOR:
1384 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
1385 break;
1386 case Token::SAR:
1387 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
1388 break;
1389 case Token::SHL:
1390 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
1391 break;
1392 case Token::SHR:
1393 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
1394 break;
1395 default:
1396 UNREACHABLE();
1397 }
1398 }
1399
1400
1401 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 1313 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
1402 Label call_runtime; 1314 Label call_runtime;
1403 if (result_type_ == BinaryOpIC::UNINITIALIZED || 1315 if (result_type_ == BinaryOpIC::UNINITIALIZED ||
1404 result_type_ == BinaryOpIC::SMI) { 1316 result_type_ == BinaryOpIC::SMI) {
1405 // Only allow smi results. 1317 // Only allow smi results.
1406 GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS); 1318 BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_);
1407 } else { 1319 } else {
1408 // Allow heap number result and don't make a transition if a heap number 1320 // Allow heap number result and don't make a transition if a heap number
1409 // cannot be allocated. 1321 // cannot be allocated.
1410 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1322 BinaryOpStub_GenerateSmiCode(
1323 masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
1411 } 1324 }
1412 1325
1413 // Code falls through if the result is not returned as either a smi or heap 1326 // Code falls through if the result is not returned as either a smi or heap
1414 // number. 1327 // number.
1415 GenerateTypeTransition(masm); 1328 GenerateTypeTransition(masm);
1416 1329
1417 if (call_runtime.is_linked()) { 1330 if (call_runtime.is_linked()) {
1418 __ bind(&call_runtime); 1331 __ bind(&call_runtime);
1419 GenerateCallRuntimeCode(masm); 1332 GenerateRegisterArgsPush(masm);
1333 GenerateCallRuntime(masm);
1420 } 1334 }
1421 } 1335 }
1422 1336
1423 1337
1424 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1338 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
1425 ASSERT(operands_type_ == BinaryOpIC::STRING); 1339 // The int32 case is identical to the Smi case. We avoid creating this
1426 ASSERT(op_ == Token::ADD); 1340 // ic state on x64.
1427 GenerateStringAddCode(masm); 1341 UNREACHABLE();
1428 // Try to add arguments as strings, otherwise, transition to the generic
1429 // BinaryOpIC type.
1430 GenerateTypeTransition(masm);
1431 } 1342 }
1432 1343
1433 1344
1434 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 1345 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
1435 Label call_runtime; 1346 Label call_runtime;
1436 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 1347 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
1437 ASSERT(op_ == Token::ADD); 1348 ASSERT(op_ == Token::ADD);
1438 // If both arguments are strings, call the string add stub. 1349 // If both arguments are strings, call the string add stub.
1439 // Otherwise, do a transition. 1350 // Otherwise, do a transition.
1440 1351
1441 // Registers containing left and right operands respectively. 1352 // Registers containing left and right operands respectively.
1442 Register left = rdx; 1353 Register left = rdx;
1443 Register right = rax; 1354 Register right = rax;
1444 1355
1445 // Test if left operand is a string. 1356 // Test if left operand is a string.
1446 __ JumpIfSmi(left, &call_runtime); 1357 __ JumpIfSmi(left, &call_runtime);
(...skipping 13 matching lines...) Expand all
1460 GenerateTypeTransition(masm); 1371 GenerateTypeTransition(masm);
1461 } 1372 }
1462 1373
1463 1374
1464 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 1375 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
1465 Label call_runtime; 1376 Label call_runtime;
1466 1377
1467 if (op_ == Token::ADD) { 1378 if (op_ == Token::ADD) {
1468 // Handle string addition here, because it is the only operation 1379 // Handle string addition here, because it is the only operation
1469 // that does not do a ToNumber conversion on the operands. 1380 // that does not do a ToNumber conversion on the operands.
1470 GenerateStringAddCode(masm); 1381 GenerateAddStrings(masm);
1471 } 1382 }
1472 1383
1473 // Convert oddball arguments to numbers. 1384 // Convert oddball arguments to numbers.
1474 Label check, done; 1385 Label check, done;
1475 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 1386 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
1476 __ j(not_equal, &check, Label::kNear); 1387 __ j(not_equal, &check, Label::kNear);
1477 if (Token::IsBitOp(op_)) { 1388 if (Token::IsBitOp(op_)) {
1478 __ xor_(rdx, rdx); 1389 __ xor_(rdx, rdx);
1479 } else { 1390 } else {
1480 __ LoadRoot(rdx, Heap::kNanValueRootIndex); 1391 __ LoadRoot(rdx, Heap::kNanValueRootIndex);
1481 } 1392 }
1482 __ jmp(&done, Label::kNear); 1393 __ jmp(&done, Label::kNear);
1483 __ bind(&check); 1394 __ bind(&check);
1484 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 1395 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
1485 __ j(not_equal, &done, Label::kNear); 1396 __ j(not_equal, &done, Label::kNear);
1486 if (Token::IsBitOp(op_)) { 1397 if (Token::IsBitOp(op_)) {
1487 __ xor_(rax, rax); 1398 __ xor_(rax, rax);
1488 } else { 1399 } else {
1489 __ LoadRoot(rax, Heap::kNanValueRootIndex); 1400 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1490 } 1401 }
1491 __ bind(&done); 1402 __ bind(&done);
1492 1403
1493 GenerateHeapNumberStub(masm); 1404 GenerateHeapNumberStub(masm);
1494 } 1405 }
1495 1406
1496 1407
1408 static void BinaryOpStub_CheckSmiInput(MacroAssembler* masm,
1409 Register input,
1410 Label* fail) {
1411 Label ok;
1412 __ JumpIfSmi(input, &ok, Label::kNear);
1413 Register heap_number_map = r8;
1414 Register scratch1 = r9;
1415 Register scratch2 = r10;
1416 // HeapNumbers containing 32bit integer values are also allowed.
1417 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
1418 __ cmpq(FieldOperand(input, HeapObject::kMapOffset), heap_number_map);
1419 __ j(not_equal, fail);
1420 __ movsd(xmm0, FieldOperand(input, HeapNumber::kValueOffset));
1421 // Convert, convert back, and compare the two doubles' bits.
1422 __ cvttsd2siq(scratch2, xmm0);
1423 __ cvtlsi2sd(xmm1, scratch2);
1424 __ movq(scratch1, xmm0);
1425 __ movq(scratch2, xmm1);
1426 __ cmpq(scratch1, scratch2);
1427 __ j(not_equal, fail);
1428 __ bind(&ok);
1429 }
1430
1431
1497 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1432 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
1498 Label gc_required, not_number; 1433 Label gc_required, not_number;
1499 GenerateFloatingPointCode(masm, &gc_required, &not_number); 1434
1435 // It could be that only SMIs have been seen at either the left
1436 // or the right operand. For precise type feedback, patch the IC
1437 // again if this changes.
1438 if (left_type_ == BinaryOpIC::SMI) {
1439 BinaryOpStub_CheckSmiInput(masm, rdx, &not_number);
1440 }
1441 if (right_type_ == BinaryOpIC::SMI) {
1442 BinaryOpStub_CheckSmiInput(masm, rax, &not_number);
1443 }
1444
1445 BinaryOpStub_GenerateFloatingPointCode(
1446 masm, &gc_required, &not_number, op_, mode_);
1500 1447
1501 __ bind(&not_number); 1448 __ bind(&not_number);
1502 GenerateTypeTransition(masm); 1449 GenerateTypeTransition(masm);
1503 1450
1504 __ bind(&gc_required); 1451 __ bind(&gc_required);
1505 GenerateCallRuntimeCode(masm); 1452 GenerateRegisterArgsPush(masm);
1453 GenerateCallRuntime(masm);
1506 } 1454 }
1507 1455
1508 1456
1509 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 1457 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
1510 Label call_runtime, call_string_add_or_runtime; 1458 Label call_runtime, call_string_add_or_runtime;
1511 1459
1512 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1460 BinaryOpStub_GenerateSmiCode(
1461 masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_);
1513 1462
1514 GenerateFloatingPointCode(masm, &call_runtime, &call_string_add_or_runtime); 1463 BinaryOpStub_GenerateFloatingPointCode(
1464 masm, &call_runtime, &call_string_add_or_runtime, op_, mode_);
1515 1465
1516 __ bind(&call_string_add_or_runtime); 1466 __ bind(&call_string_add_or_runtime);
1517 if (op_ == Token::ADD) { 1467 if (op_ == Token::ADD) {
1518 GenerateStringAddCode(masm); 1468 GenerateAddStrings(masm);
1519 } 1469 }
1520 1470
1521 __ bind(&call_runtime); 1471 __ bind(&call_runtime);
1522 GenerateCallRuntimeCode(masm); 1472 GenerateRegisterArgsPush(masm);
1473 GenerateCallRuntime(masm);
1523 } 1474 }
1524 1475
1525 1476
1526 void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, 1477 static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
1527 Label* alloc_failure) { 1478 Label* alloc_failure,
1479 OverwriteMode mode) {
1528 Label skip_allocation; 1480 Label skip_allocation;
1529 OverwriteMode mode = mode_;
1530 switch (mode) { 1481 switch (mode) {
1531 case OVERWRITE_LEFT: { 1482 case OVERWRITE_LEFT: {
1532 // If the argument in rdx is already an object, we skip the 1483 // If the argument in rdx is already an object, we skip the
1533 // allocation of a heap number. 1484 // allocation of a heap number.
1534 __ JumpIfNotSmi(rdx, &skip_allocation); 1485 __ JumpIfNotSmi(rdx, &skip_allocation);
1535 // Allocate a heap number for the result. Keep eax and edx intact 1486 // Allocate a heap number for the result. Keep eax and edx intact
1536 // for the possible runtime call. 1487 // for the possible runtime call.
1537 __ AllocateHeapNumber(rbx, rcx, alloc_failure); 1488 __ AllocateHeapNumber(rbx, rcx, alloc_failure);
1538 // Now rdx can be overwritten losing one of the arguments as we are 1489 // Now rdx can be overwritten losing one of the arguments as we are
1539 // now done and will not need it any more. 1490 // now done and will not need it any more.
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after
2018 void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, 1969 void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm,
2019 Register first, 1970 Register first,
2020 Register second, 1971 Register second,
2021 Register scratch1, 1972 Register scratch1,
2022 Register scratch2, 1973 Register scratch2,
2023 Register scratch3, 1974 Register scratch3,
2024 Label* on_success, 1975 Label* on_success,
2025 Label* on_not_smis) { 1976 Label* on_not_smis) {
2026 Register heap_number_map = scratch3; 1977 Register heap_number_map = scratch3;
2027 Register smi_result = scratch1; 1978 Register smi_result = scratch1;
2028 Label done; 1979 Label done, maybe_undefined_first, maybe_undefined_second, first_done;
2029 1980
2030 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 1981 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2031 1982
2032 Label first_smi; 1983 Label first_smi;
2033 __ JumpIfSmi(first, &first_smi, Label::kNear); 1984 __ JumpIfSmi(first, &first_smi, Label::kNear);
2034 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); 1985 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map);
2035 __ j(not_equal, on_not_smis); 1986 __ j(not_equal, &maybe_undefined_first);
2036 // Convert HeapNumber to smi if possible. 1987 // Convert HeapNumber to smi if possible.
2037 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); 1988 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset));
2038 __ movq(scratch2, xmm0); 1989 __ movq(scratch2, xmm0);
2039 __ cvttsd2siq(smi_result, xmm0); 1990 __ cvttsd2siq(smi_result, xmm0);
2040 // Check if conversion was successful by converting back and 1991 // Check if conversion was successful by converting back and
2041 // comparing to the original double's bits. 1992 // comparing to the original double's bits.
2042 __ cvtlsi2sd(xmm1, smi_result); 1993 __ cvtlsi2sd(xmm1, smi_result);
2043 __ movq(kScratchRegister, xmm1); 1994 __ movq(kScratchRegister, xmm1);
2044 __ cmpq(scratch2, kScratchRegister); 1995 __ cmpq(scratch2, kScratchRegister);
2045 __ j(not_equal, on_not_smis); 1996 __ j(not_equal, on_not_smis);
2046 __ Integer32ToSmi(first, smi_result); 1997 __ Integer32ToSmi(first, smi_result);
2047 1998
1999 __ bind(&first_done);
2048 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); 2000 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done);
2049 __ bind(&first_smi); 2001 __ bind(&first_smi);
2050 __ AssertNotSmi(second); 2002 __ AssertNotSmi(second);
2051 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); 2003 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map);
2052 __ j(not_equal, on_not_smis); 2004 __ j(not_equal, &maybe_undefined_second);
2053 // Convert second to smi, if possible. 2005 // Convert second to smi, if possible.
2054 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); 2006 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset));
2055 __ movq(scratch2, xmm0); 2007 __ movq(scratch2, xmm0);
2056 __ cvttsd2siq(smi_result, xmm0); 2008 __ cvttsd2siq(smi_result, xmm0);
2057 __ cvtlsi2sd(xmm1, smi_result); 2009 __ cvtlsi2sd(xmm1, smi_result);
2058 __ movq(kScratchRegister, xmm1); 2010 __ movq(kScratchRegister, xmm1);
2059 __ cmpq(scratch2, kScratchRegister); 2011 __ cmpq(scratch2, kScratchRegister);
2060 __ j(not_equal, on_not_smis); 2012 __ j(not_equal, on_not_smis);
2061 __ Integer32ToSmi(second, smi_result); 2013 __ Integer32ToSmi(second, smi_result);
2062 if (on_success != NULL) { 2014 if (on_success != NULL) {
2063 __ jmp(on_success); 2015 __ jmp(on_success);
2064 } else { 2016 } else {
2065 __ bind(&done); 2017 __ jmp(&done);
2066 } 2018 }
2019
2020 __ bind(&maybe_undefined_first);
2021 __ CompareRoot(first, Heap::kUndefinedValueRootIndex);
2022 __ j(not_equal, on_not_smis);
2023 __ xor_(first, first);
2024 __ jmp(&first_done);
2025
2026 __ bind(&maybe_undefined_second);
2027 __ CompareRoot(second, Heap::kUndefinedValueRootIndex);
2028 __ j(not_equal, on_not_smis);
2029 __ xor_(second, second);
2030 if (on_success != NULL) {
2031 __ jmp(on_success);
2032 }
2033 // Else: fall through.
2034
2035 __ bind(&done);
2067 } 2036 }
2068 2037
2069 2038
2070 void MathPowStub::Generate(MacroAssembler* masm) { 2039 void MathPowStub::Generate(MacroAssembler* masm) {
2071 // Choose register conforming to calling convention (when bailing out). 2040 // Choose register conforming to calling convention (when bailing out).
2072 #ifdef _WIN64 2041 #ifdef _WIN64
2073 const Register exponent = rdx; 2042 const Register exponent = rdx;
2074 #else 2043 #else
2075 const Register exponent = rdi; 2044 const Register exponent = rdi;
2076 #endif 2045 #endif
(...skipping 1294 matching lines...) Expand 10 before | Expand all | Expand 10 after
3371 3340
3372 3341
3373 static int NegativeComparisonResult(Condition cc) { 3342 static int NegativeComparisonResult(Condition cc) {
3374 ASSERT(cc != equal); 3343 ASSERT(cc != equal);
3375 ASSERT((cc == less) || (cc == less_equal) 3344 ASSERT((cc == less) || (cc == less_equal)
3376 || (cc == greater) || (cc == greater_equal)); 3345 || (cc == greater) || (cc == greater_equal));
3377 return (cc == greater || cc == greater_equal) ? LESS : GREATER; 3346 return (cc == greater || cc == greater_equal) ? LESS : GREATER;
3378 } 3347 }
3379 3348
3380 3349
3381 void CompareStub::Generate(MacroAssembler* masm) { 3350 static void CheckInputType(MacroAssembler* masm,
3382 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 3351 Register input,
3352 CompareIC::State expected,
3353 Label* fail) {
3354 Label ok;
3355 if (expected == CompareIC::SMI) {
3356 __ JumpIfNotSmi(input, fail);
3357 } else if (expected == CompareIC::HEAP_NUMBER) {
3358 __ JumpIfSmi(input, &ok);
3359 __ CompareMap(input, masm->isolate()->factory()->heap_number_map(), NULL);
3360 __ j(not_equal, fail);
3361 }
3362 // We could be strict about symbol/string here, but as long as
3363 // hydrogen doesn't care, the stub doesn't have to care either.
3364 __ bind(&ok);
3365 }
3383 3366
3367
3368 static void BranchIfNonSymbol(MacroAssembler* masm,
3369 Label* label,
3370 Register object,
3371 Register scratch) {
3372 __ JumpIfSmi(object, label);
3373 __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
3374 __ movzxbq(scratch,
3375 FieldOperand(scratch, Map::kInstanceTypeOffset));
3376 // Ensure that no non-strings have the symbol bit set.
3377 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
3378 STATIC_ASSERT(kSymbolTag != 0);
3379 __ testb(scratch, Immediate(kIsSymbolMask));
3380 __ j(zero, label);
3381 }
3382
3383
3384 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
3384 Label check_unequal_objects, done; 3385 Label check_unequal_objects, done;
3386 Condition cc = GetCondition();
3385 Factory* factory = masm->isolate()->factory(); 3387 Factory* factory = masm->isolate()->factory();
3386 3388
3387 // Compare two smis if required. 3389 Label miss;
3388 if (include_smi_compare_) { 3390 CheckInputType(masm, rdx, left_, &miss);
3389 Label non_smi, smi_done; 3391 CheckInputType(masm, rax, right_, &miss);
3390 __ JumpIfNotBothSmi(rax, rdx, &non_smi); 3392
3391 __ subq(rdx, rax); 3393 // Compare two smis.
3392 __ j(no_overflow, &smi_done); 3394 Label non_smi, smi_done;
3393 __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. 3395 __ JumpIfNotBothSmi(rax, rdx, &non_smi);
3394 __ bind(&smi_done); 3396 __ subq(rdx, rax);
3395 __ movq(rax, rdx); 3397 __ j(no_overflow, &smi_done);
3396 __ ret(0); 3398 __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here.
3397 __ bind(&non_smi); 3399 __ bind(&smi_done);
3398 } else if (FLAG_debug_code) { 3400 __ movq(rax, rdx);
3399 Label ok; 3401 __ ret(0);
3400 __ JumpIfNotSmi(rdx, &ok); 3402 __ bind(&non_smi);
3401 __ JumpIfNotSmi(rax, &ok);
3402 __ Abort("CompareStub: smi operands");
3403 __ bind(&ok);
3404 }
3405 3403
3406 // The compare stub returns a positive, negative, or zero 64-bit integer 3404 // The compare stub returns a positive, negative, or zero 64-bit integer
3407 // value in rax, corresponding to result of comparing the two inputs. 3405 // value in rax, corresponding to result of comparing the two inputs.
3408 // NOTICE! This code is only reached after a smi-fast-case check, so 3406 // NOTICE! This code is only reached after a smi-fast-case check, so
3409 // it is certain that at least one operand isn't a smi. 3407 // it is certain that at least one operand isn't a smi.
3410 3408
3411 // Two identical objects are equal unless they are both NaN or undefined. 3409 // Two identical objects are equal unless they are both NaN or undefined.
3412 { 3410 {
3413 Label not_identical; 3411 Label not_identical;
3414 __ cmpq(rax, rdx); 3412 __ cmpq(rax, rdx);
3415 __ j(not_equal, &not_identical, Label::kNear); 3413 __ j(not_equal, &not_identical, Label::kNear);
3416 3414
3417 if (cc_ != equal) { 3415 if (cc != equal) {
3418 // Check for undefined. undefined OP undefined is false even though 3416 // Check for undefined. undefined OP undefined is false even though
3419 // undefined == undefined. 3417 // undefined == undefined.
3420 Label check_for_nan; 3418 Label check_for_nan;
3421 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 3419 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
3422 __ j(not_equal, &check_for_nan, Label::kNear); 3420 __ j(not_equal, &check_for_nan, Label::kNear);
3423 __ Set(rax, NegativeComparisonResult(cc_)); 3421 __ Set(rax, NegativeComparisonResult(cc));
3424 __ ret(0); 3422 __ ret(0);
3425 __ bind(&check_for_nan); 3423 __ bind(&check_for_nan);
3426 } 3424 }
3427 3425
3428 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), 3426 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
3429 // so we do the second best thing - test it ourselves. 3427 // so we do the second best thing - test it ourselves.
3430 // Note: if cc_ != equal, never_nan_nan_ is not used. 3428 Label heap_number;
3431 // We cannot set rax to EQUAL until just before return because 3429 // If it's not a heap number, then return equal for (in)equality operator.
3432 // rax must be unchanged on jump to not_identical. 3430 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
3433 if (never_nan_nan_ && (cc_ == equal)) { 3431 factory->heap_number_map());
3434 __ Set(rax, EQUAL); 3432 __ j(equal, &heap_number, Label::kNear);
3435 __ ret(0); 3433 if (cc != equal) {
3436 } else { 3434 // Call runtime on identical objects. Otherwise return equal.
3437 Label heap_number; 3435 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
3438 // If it's not a heap number, then return equal for (in)equality operator. 3436 __ j(above_equal, &not_identical, Label::kNear);
3439 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), 3437 }
3440 factory->heap_number_map()); 3438 __ Set(rax, EQUAL);
3441 __ j(equal, &heap_number, Label::kNear); 3439 __ ret(0);
3442 if (cc_ != equal) {
3443 // Call runtime on identical objects. Otherwise return equal.
3444 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
3445 __ j(above_equal, &not_identical, Label::kNear);
3446 }
3447 __ Set(rax, EQUAL);
3448 __ ret(0);
3449 3440
3450 __ bind(&heap_number); 3441 __ bind(&heap_number);
3451 // It is a heap number, so return equal if it's not NaN. 3442 // It is a heap number, so return equal if it's not NaN.
3452 // For NaN, return 1 for every condition except greater and 3443 // For NaN, return 1 for every condition except greater and
3453 // greater-equal. Return -1 for them, so the comparison yields 3444 // greater-equal. Return -1 for them, so the comparison yields
3454 // false for all conditions except not-equal. 3445 // false for all conditions except not-equal.
3455 __ Set(rax, EQUAL); 3446 __ Set(rax, EQUAL);
3456 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 3447 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
3457 __ ucomisd(xmm0, xmm0); 3448 __ ucomisd(xmm0, xmm0);
3458 __ setcc(parity_even, rax); 3449 __ setcc(parity_even, rax);
3459 // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs. 3450 // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs.
3460 if (cc_ == greater_equal || cc_ == greater) { 3451 if (cc == greater_equal || cc == greater) {
3461 __ neg(rax); 3452 __ neg(rax);
3462 }
3463 __ ret(0);
3464 } 3453 }
3454 __ ret(0);
3465 3455
3466 __ bind(&not_identical); 3456 __ bind(&not_identical);
3467 } 3457 }
3468 3458
3469 if (cc_ == equal) { // Both strict and non-strict. 3459 if (cc == equal) { // Both strict and non-strict.
3470 Label slow; // Fallthrough label. 3460 Label slow; // Fallthrough label.
3471 3461
3472 // If we're doing a strict equality comparison, we don't have to do 3462 // If we're doing a strict equality comparison, we don't have to do
3473 // type conversion, so we generate code to do fast comparison for objects 3463 // type conversion, so we generate code to do fast comparison for objects
3474 // and oddballs. Non-smi numbers and strings still go through the usual 3464 // and oddballs. Non-smi numbers and strings still go through the usual
3475 // slow-case code. 3465 // slow-case code.
3476 if (strict_) { 3466 if (strict()) {
3477 // If either is a Smi (we know that not both are), then they can only 3467 // If either is a Smi (we know that not both are), then they can only
3478 // be equal if the other is a HeapNumber. If so, use the slow case. 3468 // be equal if the other is a HeapNumber. If so, use the slow case.
3479 { 3469 {
3480 Label not_smis; 3470 Label not_smis;
3481 __ SelectNonSmi(rbx, rax, rdx, &not_smis); 3471 __ SelectNonSmi(rbx, rax, rdx, &not_smis);
3482 3472
3483 // Check if the non-smi operand is a heap number. 3473 // Check if the non-smi operand is a heap number.
3484 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), 3474 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
3485 factory->heap_number_map()); 3475 factory->heap_number_map());
3486 // If heap number, handle it in the slow case. 3476 // If heap number, handle it in the slow case.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
3518 // Check for oddballs: true, false, null, undefined. 3508 // Check for oddballs: true, false, null, undefined.
3519 __ CmpInstanceType(rcx, ODDBALL_TYPE); 3509 __ CmpInstanceType(rcx, ODDBALL_TYPE);
3520 __ j(equal, &return_not_equal); 3510 __ j(equal, &return_not_equal);
3521 3511
3522 // Fall through to the general case. 3512 // Fall through to the general case.
3523 } 3513 }
3524 __ bind(&slow); 3514 __ bind(&slow);
3525 } 3515 }
3526 3516
3527 // Generate the number comparison code. 3517 // Generate the number comparison code.
3528 if (include_number_compare_) { 3518 Label non_number_comparison;
3529 Label non_number_comparison; 3519 Label unordered;
3530 Label unordered; 3520 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
3531 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); 3521 __ xorl(rax, rax);
3532 __ xorl(rax, rax); 3522 __ xorl(rcx, rcx);
3533 __ xorl(rcx, rcx); 3523 __ ucomisd(xmm0, xmm1);
3534 __ ucomisd(xmm0, xmm1);
3535 3524
3536 // Don't base result on EFLAGS when a NaN is involved. 3525 // Don't base result on EFLAGS when a NaN is involved.
3537 __ j(parity_even, &unordered, Label::kNear); 3526 __ j(parity_even, &unordered, Label::kNear);
3538 // Return a result of -1, 0, or 1, based on EFLAGS. 3527 // Return a result of -1, 0, or 1, based on EFLAGS.
3539 __ setcc(above, rax); 3528 __ setcc(above, rax);
3540 __ setcc(below, rcx); 3529 __ setcc(below, rcx);
3541 __ subq(rax, rcx); 3530 __ subq(rax, rcx);
3542 __ ret(0); 3531 __ ret(0);
3543 3532
3544 // If one of the numbers was NaN, then the result is always false. 3533 // If one of the numbers was NaN, then the result is always false.
3545 // The cc is never not-equal. 3534 // The cc is never not-equal.
3546 __ bind(&unordered); 3535 __ bind(&unordered);
3547 ASSERT(cc_ != not_equal); 3536 ASSERT(cc != not_equal);
3548 if (cc_ == less || cc_ == less_equal) { 3537 if (cc == less || cc == less_equal) {
3549 __ Set(rax, 1); 3538 __ Set(rax, 1);
3550 } else { 3539 } else {
3551 __ Set(rax, -1); 3540 __ Set(rax, -1);
3552 } 3541 }
3553 __ ret(0); 3542 __ ret(0);
3554 3543
3555 // The number comparison code did not provide a valid result. 3544 // The number comparison code did not provide a valid result.
3556 __ bind(&non_number_comparison); 3545 __ bind(&non_number_comparison);
3557 }
3558 3546
3559 // Fast negative check for symbol-to-symbol equality. 3547 // Fast negative check for symbol-to-symbol equality.
3560 Label check_for_strings; 3548 Label check_for_strings;
3561 if (cc_ == equal) { 3549 if (cc == equal) {
3562 BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister); 3550 BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
3563 BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister); 3551 BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
3564 3552
3565 // We've already checked for object identity, so if both operands 3553 // We've already checked for object identity, so if both operands
3566 // are symbols they aren't equal. Register eax (not rax) already holds a 3554 // are symbols they aren't equal. Register eax (not rax) already holds a
3567 // non-zero value, which indicates not equal, so just return. 3555 // non-zero value, which indicates not equal, so just return.
3568 __ ret(0); 3556 __ ret(0);
3569 } 3557 }
3570 3558
3571 __ bind(&check_for_strings); 3559 __ bind(&check_for_strings);
3572 3560
3573 __ JumpIfNotBothSequentialAsciiStrings( 3561 __ JumpIfNotBothSequentialAsciiStrings(
3574 rdx, rax, rcx, rbx, &check_unequal_objects); 3562 rdx, rax, rcx, rbx, &check_unequal_objects);
3575 3563
3576 // Inline comparison of ASCII strings. 3564 // Inline comparison of ASCII strings.
3577 if (cc_ == equal) { 3565 if (cc == equal) {
3578 StringCompareStub::GenerateFlatAsciiStringEquals(masm, 3566 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
3579 rdx, 3567 rdx,
3580 rax, 3568 rax,
3581 rcx, 3569 rcx,
3582 rbx); 3570 rbx);
3583 } else { 3571 } else {
3584 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 3572 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
3585 rdx, 3573 rdx,
3586 rax, 3574 rax,
3587 rcx, 3575 rcx,
3588 rbx, 3576 rbx,
3589 rdi, 3577 rdi,
3590 r8); 3578 r8);
3591 } 3579 }
3592 3580
3593 #ifdef DEBUG 3581 #ifdef DEBUG
3594 __ Abort("Unexpected fall-through from string comparison"); 3582 __ Abort("Unexpected fall-through from string comparison");
3595 #endif 3583 #endif
3596 3584
3597 __ bind(&check_unequal_objects); 3585 __ bind(&check_unequal_objects);
3598 if (cc_ == equal && !strict_) { 3586 if (cc == equal && !strict()) {
3599 // Not strict equality. Objects are unequal if 3587 // Not strict equality. Objects are unequal if
3600 // they are both JSObjects and not undetectable, 3588 // they are both JSObjects and not undetectable,
3601 // and their pointers are different. 3589 // and their pointers are different.
3602 Label not_both_objects, return_unequal; 3590 Label not_both_objects, return_unequal;
3603 // At most one is a smi, so we can test for smi by adding the two. 3591 // At most one is a smi, so we can test for smi by adding the two.
3604 // A smi plus a heap object has the low bit set, a heap object plus 3592 // A smi plus a heap object has the low bit set, a heap object plus
3605 // a heap object has the low bit clear. 3593 // a heap object has the low bit clear.
3606 STATIC_ASSERT(kSmiTag == 0); 3594 STATIC_ASSERT(kSmiTag == 0);
3607 STATIC_ASSERT(kSmiTagMask == 1); 3595 STATIC_ASSERT(kSmiTagMask == 1);
3608 __ lea(rcx, Operand(rax, rdx, times_1, 0)); 3596 __ lea(rcx, Operand(rax, rdx, times_1, 0));
(...skipping 19 matching lines...) Expand all
3628 __ bind(&not_both_objects); 3616 __ bind(&not_both_objects);
3629 } 3617 }
3630 3618
3631 // Push arguments below the return address to prepare jump to builtin. 3619 // Push arguments below the return address to prepare jump to builtin.
3632 __ pop(rcx); 3620 __ pop(rcx);
3633 __ push(rdx); 3621 __ push(rdx);
3634 __ push(rax); 3622 __ push(rax);
3635 3623
3636 // Figure out which native to call and setup the arguments. 3624 // Figure out which native to call and setup the arguments.
3637 Builtins::JavaScript builtin; 3625 Builtins::JavaScript builtin;
3638 if (cc_ == equal) { 3626 if (cc == equal) {
3639 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 3627 builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
3640 } else { 3628 } else {
3641 builtin = Builtins::COMPARE; 3629 builtin = Builtins::COMPARE;
3642 __ Push(Smi::FromInt(NegativeComparisonResult(cc_))); 3630 __ Push(Smi::FromInt(NegativeComparisonResult(cc)));
3643 } 3631 }
3644 3632
3645 // Restore return address on the stack. 3633 // Restore return address on the stack.
3646 __ push(rcx); 3634 __ push(rcx);
3647 3635
3648 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 3636 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
3649 // tagged as a small integer. 3637 // tagged as a small integer.
3650 __ InvokeBuiltin(builtin, JUMP_FUNCTION); 3638 __ InvokeBuiltin(builtin, JUMP_FUNCTION);
3639
3640 __ bind(&miss);
3641 GenerateMiss(masm);
3651 } 3642 }
3652 3643
3653 3644
3654 void CompareStub::BranchIfNonSymbol(MacroAssembler* masm,
3655 Label* label,
3656 Register object,
3657 Register scratch) {
3658 __ JumpIfSmi(object, label);
3659 __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
3660 __ movzxbq(scratch,
3661 FieldOperand(scratch, Map::kInstanceTypeOffset));
3662 // Ensure that no non-strings have the symbol bit set.
3663 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
3664 STATIC_ASSERT(kSymbolTag != 0);
3665 __ testb(scratch, Immediate(kIsSymbolMask));
3666 __ j(zero, label);
3667 }
3668
3669
3670 void StackCheckStub::Generate(MacroAssembler* masm) { 3645 void StackCheckStub::Generate(MacroAssembler* masm) {
3671 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 3646 __ TailCallRuntime(Runtime::kStackGuard, 0, 1);
3672 } 3647 }
3673 3648
3674 3649
3675 void InterruptStub::Generate(MacroAssembler* masm) { 3650 void InterruptStub::Generate(MacroAssembler* masm) {
3676 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); 3651 __ TailCallRuntime(Runtime::kInterrupt, 0, 1);
3677 } 3652 }
3678 3653
3679 3654
(...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after
4414 } 4389 }
4415 4390
4416 4391
4417 // Passing arguments in registers is not supported. 4392 // Passing arguments in registers is not supported.
4418 Register InstanceofStub::left() { return no_reg; } 4393 Register InstanceofStub::left() { return no_reg; }
4419 4394
4420 4395
4421 Register InstanceofStub::right() { return no_reg; } 4396 Register InstanceofStub::right() { return no_reg; }
4422 4397
4423 4398
4424 int CompareStub::MinorKey() {
4425 // Encode the three parameters in a unique 16 bit value. To avoid duplicate
4426 // stubs the never NaN NaN condition is only taken into account if the
4427 // condition is equals.
4428 ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
4429 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
4430 return ConditionField::encode(static_cast<unsigned>(cc_))
4431 | RegisterField::encode(false) // lhs_ and rhs_ are not used
4432 | StrictField::encode(strict_)
4433 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false)
4434 | IncludeNumberCompareField::encode(include_number_compare_)
4435 | IncludeSmiCompareField::encode(include_smi_compare_);
4436 }
4437
4438
4439 // Unfortunately you have to run without snapshots to see most of these
4440 // names in the profile since most compare stubs end up in the snapshot.
4441 void CompareStub::PrintName(StringStream* stream) {
4442 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
4443 const char* cc_name;
4444 switch (cc_) {
4445 case less: cc_name = "LT"; break;
4446 case greater: cc_name = "GT"; break;
4447 case less_equal: cc_name = "LE"; break;
4448 case greater_equal: cc_name = "GE"; break;
4449 case equal: cc_name = "EQ"; break;
4450 case not_equal: cc_name = "NE"; break;
4451 default: cc_name = "UnknownCondition"; break;
4452 }
4453 bool is_equality = cc_ == equal || cc_ == not_equal;
4454 stream->Add("CompareStub_%s", cc_name);
4455 if (strict_ && is_equality) stream->Add("_STRICT");
4456 if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
4457 if (!include_number_compare_) stream->Add("_NO_NUMBER");
4458 if (!include_smi_compare_) stream->Add("_NO_SMI");
4459 }
4460
4461
4462 // ------------------------------------------------------------------------- 4399 // -------------------------------------------------------------------------
4463 // StringCharCodeAtGenerator 4400 // StringCharCodeAtGenerator
4464 4401
4465 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 4402 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
4466 Label flat_string; 4403 Label flat_string;
4467 Label ascii_string; 4404 Label ascii_string;
4468 Label got_char_code; 4405 Label got_char_code;
4469 Label sliced_string; 4406 Label sliced_string;
4470 4407
4471 // If the receiver is a smi trigger the non-string case. 4408 // If the receiver is a smi trigger the non-string case.
(...skipping 1089 matching lines...) Expand 10 before | Expand all | Expand 10 after
5561 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); 5498 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
5562 5499
5563 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 5500 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
5564 // tagged as a small integer. 5501 // tagged as a small integer.
5565 __ bind(&runtime); 5502 __ bind(&runtime);
5566 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 5503 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
5567 } 5504 }
5568 5505
5569 5506
5570 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { 5507 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
5571 ASSERT(state_ == CompareIC::SMIS); 5508 ASSERT(state_ == CompareIC::SMI);
5572 Label miss; 5509 Label miss;
5573 __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear); 5510 __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear);
5574 5511
5575 if (GetCondition() == equal) { 5512 if (GetCondition() == equal) {
5576 // For equality we do not care about the sign of the result. 5513 // For equality we do not care about the sign of the result.
5577 __ subq(rax, rdx); 5514 __ subq(rax, rdx);
5578 } else { 5515 } else {
5579 Label done; 5516 Label done;
5580 __ subq(rdx, rax); 5517 __ subq(rdx, rax);
5581 __ j(no_overflow, &done, Label::kNear); 5518 __ j(no_overflow, &done, Label::kNear);
5582 // Correct sign of result in case of overflow. 5519 // Correct sign of result in case of overflow.
5583 __ SmiNot(rdx, rdx); 5520 __ SmiNot(rdx, rdx);
5584 __ bind(&done); 5521 __ bind(&done);
5585 __ movq(rax, rdx); 5522 __ movq(rax, rdx);
5586 } 5523 }
5587 __ ret(0); 5524 __ ret(0);
5588 5525
5589 __ bind(&miss); 5526 __ bind(&miss);
5590 GenerateMiss(masm); 5527 GenerateMiss(masm);
5591 } 5528 }
5592 5529
5593 5530
5594 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 5531 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
5595 ASSERT(state_ == CompareIC::HEAP_NUMBERS); 5532 ASSERT(state_ == CompareIC::HEAP_NUMBER);
5596 5533
5597 Label generic_stub; 5534 Label generic_stub;
5598 Label unordered, maybe_undefined1, maybe_undefined2; 5535 Label unordered, maybe_undefined1, maybe_undefined2;
5599 Label miss; 5536 Label miss;
5600 Condition either_smi = masm->CheckEitherSmi(rax, rdx);
5601 __ j(either_smi, &generic_stub, Label::kNear);
5602 5537
5603 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); 5538 if (left_ == CompareIC::SMI) {
5539 __ JumpIfNotSmi(rdx, &miss);
5540 }
5541 if (right_ == CompareIC::SMI) {
5542 __ JumpIfNotSmi(rax, &miss);
5543 }
5544
5545 // Load left and right operand.
5546 Label done, left, left_smi, right_smi;
5547 __ JumpIfSmi(rax, &right_smi, Label::kNear);
5548 __ CompareMap(rax, masm->isolate()->factory()->heap_number_map(), NULL);
5604 __ j(not_equal, &maybe_undefined1, Label::kNear); 5549 __ j(not_equal, &maybe_undefined1, Label::kNear);
5605 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); 5550 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
5551 __ jmp(&left, Label::kNear);
5552 __ bind(&right_smi);
5553 __ SmiToInteger32(rcx, rax); // Can't clobber rax yet.
5554 __ cvtlsi2sd(xmm1, rcx);
5555
5556 __ bind(&left);
5557 __ JumpIfSmi(rdx, &left_smi, Label::kNear);
5558 __ CompareMap(rdx, masm->isolate()->factory()->heap_number_map(), NULL);
5606 __ j(not_equal, &maybe_undefined2, Label::kNear); 5559 __ j(not_equal, &maybe_undefined2, Label::kNear);
5560 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
5561 __ jmp(&done);
5562 __ bind(&left_smi);
5563 __ SmiToInteger32(rcx, rdx); // Can't clobber rdx yet.
5564 __ cvtlsi2sd(xmm0, rcx);
5607 5565
5608 // Load left and right operand 5566 __ bind(&done);
5609 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
5610 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
5611
5612 // Compare operands 5567 // Compare operands
5613 __ ucomisd(xmm0, xmm1); 5568 __ ucomisd(xmm0, xmm1);
5614 5569
5615 // Don't base result on EFLAGS when a NaN is involved. 5570 // Don't base result on EFLAGS when a NaN is involved.
5616 __ j(parity_even, &unordered, Label::kNear); 5571 __ j(parity_even, &unordered, Label::kNear);
5617 5572
5618 // Return a result of -1, 0, or 1, based on EFLAGS. 5573 // Return a result of -1, 0, or 1, based on EFLAGS.
5619 // Performing mov, because xor would destroy the flag register. 5574 // Performing mov, because xor would destroy the flag register.
5620 __ movl(rax, Immediate(0)); 5575 __ movl(rax, Immediate(0));
5621 __ movl(rcx, Immediate(0)); 5576 __ movl(rcx, Immediate(0));
5622 __ setcc(above, rax); // Add one to zero if carry clear and not equal. 5577 __ setcc(above, rax); // Add one to zero if carry clear and not equal.
5623 __ sbbq(rax, rcx); // Subtract one if below (aka. carry set). 5578 __ sbbq(rax, rcx); // Subtract one if below (aka. carry set).
5624 __ ret(0); 5579 __ ret(0);
5625 5580
5626 __ bind(&unordered); 5581 __ bind(&unordered);
5627 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
5628 __ bind(&generic_stub); 5582 __ bind(&generic_stub);
5583 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
5584 CompareIC::GENERIC);
5629 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 5585 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
5630 5586
5631 __ bind(&maybe_undefined1); 5587 __ bind(&maybe_undefined1);
5632 if (Token::IsOrderedRelationalCompareOp(op_)) { 5588 if (Token::IsOrderedRelationalCompareOp(op_)) {
5633 __ Cmp(rax, masm->isolate()->factory()->undefined_value()); 5589 __ Cmp(rax, masm->isolate()->factory()->undefined_value());
5634 __ j(not_equal, &miss); 5590 __ j(not_equal, &miss);
5591 __ JumpIfSmi(rdx, &unordered);
5635 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); 5592 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
5636 __ j(not_equal, &maybe_undefined2, Label::kNear); 5593 __ j(not_equal, &maybe_undefined2, Label::kNear);
5637 __ jmp(&unordered); 5594 __ jmp(&unordered);
5638 } 5595 }
5639 5596
5640 __ bind(&maybe_undefined2); 5597 __ bind(&maybe_undefined2);
5641 if (Token::IsOrderedRelationalCompareOp(op_)) { 5598 if (Token::IsOrderedRelationalCompareOp(op_)) {
5642 __ Cmp(rdx, masm->isolate()->factory()->undefined_value()); 5599 __ Cmp(rdx, masm->isolate()->factory()->undefined_value());
5643 __ j(equal, &unordered); 5600 __ j(equal, &unordered);
5644 } 5601 }
5645 5602
5646 __ bind(&miss); 5603 __ bind(&miss);
5647 GenerateMiss(masm); 5604 GenerateMiss(masm);
5648 } 5605 }
5649 5606
5650 5607
5651 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 5608 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
5652 ASSERT(state_ == CompareIC::SYMBOLS); 5609 ASSERT(state_ == CompareIC::SYMBOL);
5653 ASSERT(GetCondition() == equal); 5610 ASSERT(GetCondition() == equal);
5654 5611
5655 // Registers containing left and right operands respectively. 5612 // Registers containing left and right operands respectively.
5656 Register left = rdx; 5613 Register left = rdx;
5657 Register right = rax; 5614 Register right = rax;
5658 Register tmp1 = rcx; 5615 Register tmp1 = rcx;
5659 Register tmp2 = rbx; 5616 Register tmp2 = rbx;
5660 5617
5661 // Check that both operands are heap objects. 5618 // Check that both operands are heap objects.
5662 Label miss; 5619 Label miss;
(...skipping 22 matching lines...) Expand all
5685 __ Move(rax, Smi::FromInt(EQUAL)); 5642 __ Move(rax, Smi::FromInt(EQUAL));
5686 __ bind(&done); 5643 __ bind(&done);
5687 __ ret(0); 5644 __ ret(0);
5688 5645
5689 __ bind(&miss); 5646 __ bind(&miss);
5690 GenerateMiss(masm); 5647 GenerateMiss(masm);
5691 } 5648 }
5692 5649
5693 5650
5694 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { 5651 void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
5695 ASSERT(state_ == CompareIC::STRINGS); 5652 ASSERT(state_ == CompareIC::STRING);
5696 Label miss; 5653 Label miss;
5697 5654
5698 bool equality = Token::IsEqualityOp(op_); 5655 bool equality = Token::IsEqualityOp(op_);
5699 5656
5700 // Registers containing left and right operands respectively. 5657 // Registers containing left and right operands respectively.
5701 Register left = rdx; 5658 Register left = rdx;
5702 Register right = rax; 5659 Register right = rax;
5703 Register tmp1 = rcx; 5660 Register tmp1 = rcx;
5704 Register tmp2 = rbx; 5661 Register tmp2 = rbx;
5705 Register tmp3 = rdi; 5662 Register tmp3 = rdi;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
5771 } else { 5728 } else {
5772 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 5729 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
5773 } 5730 }
5774 5731
5775 __ bind(&miss); 5732 __ bind(&miss);
5776 GenerateMiss(masm); 5733 GenerateMiss(masm);
5777 } 5734 }
5778 5735
5779 5736
5780 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { 5737 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
5781 ASSERT(state_ == CompareIC::OBJECTS); 5738 ASSERT(state_ == CompareIC::OBJECT);
5782 Label miss; 5739 Label miss;
5783 Condition either_smi = masm->CheckEitherSmi(rdx, rax); 5740 Condition either_smi = masm->CheckEitherSmi(rdx, rax);
5784 __ j(either_smi, &miss, Label::kNear); 5741 __ j(either_smi, &miss, Label::kNear);
5785 5742
5786 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); 5743 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
5787 __ j(not_equal, &miss, Label::kNear); 5744 __ j(not_equal, &miss, Label::kNear);
5788 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); 5745 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
5789 __ j(not_equal, &miss, Label::kNear); 5746 __ j(not_equal, &miss, Label::kNear);
5790 5747
5791 ASSERT(GetCondition() == equal); 5748 ASSERT(GetCondition() == equal);
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after
6499 #endif 6456 #endif
6500 6457
6501 __ Ret(); 6458 __ Ret();
6502 } 6459 }
6503 6460
6504 #undef __ 6461 #undef __
6505 6462
6506 } } // namespace v8::internal 6463 } } // namespace v8::internal
6507 6464
6508 #endif // V8_TARGET_ARCH_X64 6465 #endif // V8_TARGET_ARCH_X64
OLDNEW
« src/objects-inl.h ('K') | « src/x64/code-stubs-x64.h ('k') | src/x64/full-codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698