| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 895 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 906 OverwriteMode overwrite_mode) { | 906 OverwriteMode overwrite_mode) { |
| 907 Comment cmnt(masm_, "[ BinaryOperation"); | 907 Comment cmnt(masm_, "[ BinaryOperation"); |
| 908 Comment cmnt_token(masm_, Token::String(op)); | 908 Comment cmnt_token(masm_, Token::String(op)); |
| 909 | 909 |
| 910 if (op == Token::COMMA) { | 910 if (op == Token::COMMA) { |
| 911 // Simply discard left value. | 911 // Simply discard left value. |
| 912 frame_->Nip(1); | 912 frame_->Nip(1); |
| 913 return; | 913 return; |
| 914 } | 914 } |
| 915 | 915 |
| 916 // Set the flags based on the operation, type and loop nesting level. | |
| 917 GenericBinaryFlags flags; | |
| 918 switch (op) { | |
| 919 case Token::BIT_OR: | |
| 920 case Token::BIT_AND: | |
| 921 case Token::BIT_XOR: | |
| 922 case Token::SHL: | |
| 923 case Token::SHR: | |
| 924 case Token::SAR: | |
| 925 // Bit operations always assume they likely operate on Smis. Still only | |
| 926 // generate the inline Smi check code if this operation is part of a loop. | |
| 927 flags = (loop_nesting() > 0) | |
| 928 ? NO_SMI_CODE_IN_STUB | |
| 929 : NO_GENERIC_BINARY_FLAGS; | |
| 930 break; | |
| 931 | |
| 932 default: | |
| 933 // By default only inline the Smi check code for likely smis if this | |
| 934 // operation is part of a loop. | |
| 935 flags = ((loop_nesting() > 0) && type->IsLikelySmi()) | |
| 936 ? NO_SMI_CODE_IN_STUB | |
| 937 : NO_GENERIC_BINARY_FLAGS; | |
| 938 break; | |
| 939 } | |
| 940 | |
| 941 Result right = frame_->Pop(); | 916 Result right = frame_->Pop(); |
| 942 Result left = frame_->Pop(); | 917 Result left = frame_->Pop(); |
| 943 | 918 |
| 944 if (op == Token::ADD) { | 919 if (op == Token::ADD) { |
| 945 bool left_is_string = left.is_constant() && left.handle()->IsString(); | 920 bool left_is_string = left.is_constant() && left.handle()->IsString(); |
| 946 bool right_is_string = right.is_constant() && right.handle()->IsString(); | 921 bool right_is_string = right.is_constant() && right.handle()->IsString(); |
| 947 if (left_is_string || right_is_string) { | 922 if (left_is_string || right_is_string) { |
| 948 frame_->Push(&left); | 923 frame_->Push(&left); |
| 949 frame_->Push(&right); | 924 frame_->Push(&right); |
| 950 Result answer; | 925 Result answer; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 964 frame_->Push(&answer); | 939 frame_->Push(&answer); |
| 965 return; | 940 return; |
| 966 } | 941 } |
| 967 // Neither operand is known to be a string. | 942 // Neither operand is known to be a string. |
| 968 } | 943 } |
| 969 | 944 |
| 970 bool left_is_smi = left.is_constant() && left.handle()->IsSmi(); | 945 bool left_is_smi = left.is_constant() && left.handle()->IsSmi(); |
| 971 bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi(); | 946 bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi(); |
| 972 bool right_is_smi = right.is_constant() && right.handle()->IsSmi(); | 947 bool right_is_smi = right.is_constant() && right.handle()->IsSmi(); |
| 973 bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi(); | 948 bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi(); |
| 974 bool generate_no_smi_code = false; // No smi code at all, inline or in stub. | |
| 975 | 949 |
| 976 if (left_is_smi && right_is_smi) { | 950 if (left_is_smi && right_is_smi) { |
| 977 // Compute the constant result at compile time, and leave it on the frame. | 951 // Compute the constant result at compile time, and leave it on the frame. |
| 978 int left_int = Smi::cast(*left.handle())->value(); | 952 int left_int = Smi::cast(*left.handle())->value(); |
| 979 int right_int = Smi::cast(*right.handle())->value(); | 953 int right_int = Smi::cast(*right.handle())->value(); |
| 980 if (FoldConstantSmis(op, left_int, right_int)) return; | 954 if (FoldConstantSmis(op, left_int, right_int)) return; |
| 981 } | 955 } |
| 982 | 956 |
| 957 Result answer; |
| 983 if (left_is_non_smi || right_is_non_smi) { | 958 if (left_is_non_smi || right_is_non_smi) { |
| 984 // Set flag so that we go straight to the slow case, with no smi code. | 959 // Go straight to the slow case, with no smi code. |
| 985 generate_no_smi_code = true; | |
| 986 } else if (right_is_smi) { | |
| 987 ConstantSmiBinaryOperation(op, &left, right.handle(), | |
| 988 type, false, overwrite_mode); | |
| 989 return; | |
| 990 } else if (left_is_smi) { | |
| 991 ConstantSmiBinaryOperation(op, &right, left.handle(), | |
| 992 type, true, overwrite_mode); | |
| 993 return; | |
| 994 } | |
| 995 | |
| 996 if (((flags & NO_SMI_CODE_IN_STUB) != 0) && !generate_no_smi_code) { | |
| 997 LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | |
| 998 } else { | |
| 999 frame_->Push(&left); | 960 frame_->Push(&left); |
| 1000 frame_->Push(&right); | 961 frame_->Push(&right); |
| 1001 // If we know the arguments aren't smis, use the binary operation stub | 962 GenericBinaryOpStub stub(op, overwrite_mode, NO_SMI_CODE_IN_STUB); |
| 1002 // that does not check for the fast smi case. | 963 answer = frame_->CallStub(&stub, 2); |
| 1003 if (generate_no_smi_code) { | 964 } else if (right_is_smi) { |
| 1004 flags = NO_SMI_CODE_IN_STUB; | 965 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
| 966 type, false, overwrite_mode); |
| 967 } else if (left_is_smi) { |
| 968 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
| 969 type, true, overwrite_mode); |
| 970 } else { |
| 971 // Set the flags based on the operation, type and loop nesting level. |
| 972 // Bit operations always assume they likely operate on Smis. Still only |
| 973 // generate the inline Smi check code if this operation is part of a loop. |
| 974 // For all other operations only inline the Smi check code for likely smis |
| 975 // if the operation is part of a loop. |
| 976 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { |
| 977 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
| 978 } else { |
| 979 frame_->Push(&left); |
| 980 frame_->Push(&right); |
| 981 GenericBinaryOpStub stub(op, overwrite_mode, NO_GENERIC_BINARY_FLAGS); |
| 982 answer = frame_->CallStub(&stub, 2); |
| 1005 } | 983 } |
| 1006 GenericBinaryOpStub stub(op, overwrite_mode, flags); | |
| 1007 Result answer = frame_->CallStub(&stub, 2); | |
| 1008 frame_->Push(&answer); | |
| 1009 } | 984 } |
| 985 frame_->Push(&answer); |
| 1010 } | 986 } |
| 1011 | 987 |
| 1012 | 988 |
| 1013 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 989 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
| 1014 Object* answer_object = Heap::undefined_value(); | 990 Object* answer_object = Heap::undefined_value(); |
| 1015 switch (op) { | 991 switch (op) { |
| 1016 case Token::ADD: | 992 case Token::ADD: |
| 1017 if (Smi::IsValid(left + right)) { | 993 if (Smi::IsValid(left + right)) { |
| 1018 answer_object = Smi::FromInt(left + right); | 994 answer_object = Smi::FromInt(left + right); |
| 1019 } | 995 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1086 if (answer_object == Heap::undefined_value()) { | 1062 if (answer_object == Heap::undefined_value()) { |
| 1087 return false; | 1063 return false; |
| 1088 } | 1064 } |
| 1089 frame_->Push(Handle<Object>(answer_object)); | 1065 frame_->Push(Handle<Object>(answer_object)); |
| 1090 return true; | 1066 return true; |
| 1091 } | 1067 } |
| 1092 | 1068 |
| 1093 | 1069 |
| 1094 // Implements a binary operation using a deferred code object and some | 1070 // Implements a binary operation using a deferred code object and some |
| 1095 // inline code to operate on smis quickly. | 1071 // inline code to operate on smis quickly. |
| 1096 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 1072 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| 1097 Result* left, | 1073 Result* left, |
| 1098 Result* right, | 1074 Result* right, |
| 1099 OverwriteMode overwrite_mode) { | 1075 OverwriteMode overwrite_mode) { |
| 1076 Result answer; |
| 1100 // Special handling of div and mod because they use fixed registers. | 1077 // Special handling of div and mod because they use fixed registers. |
| 1101 if (op == Token::DIV || op == Token::MOD) { | 1078 if (op == Token::DIV || op == Token::MOD) { |
| 1102 // We need eax as the quotient register, edx as the remainder | 1079 // We need eax as the quotient register, edx as the remainder |
| 1103 // register, neither left nor right in eax or edx, and left copied | 1080 // register, neither left nor right in eax or edx, and left copied |
| 1104 // to eax. | 1081 // to eax. |
| 1105 Result quotient; | 1082 Result quotient; |
| 1106 Result remainder; | 1083 Result remainder; |
| 1107 bool left_is_in_eax = false; | 1084 bool left_is_in_eax = false; |
| 1108 // Step 1: get eax for quotient. | 1085 // Step 1: get eax for quotient. |
| 1109 if ((left->is_register() && left->reg().is(eax)) || | 1086 if ((left->is_register() && left->reg().is(eax)) || |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 __ cmp(eax, 0x40000000); | 1188 __ cmp(eax, 0x40000000); |
| 1212 deferred->Branch(equal); | 1189 deferred->Branch(equal); |
| 1213 // Check that the remainder is zero. | 1190 // Check that the remainder is zero. |
| 1214 __ test(edx, Operand(edx)); | 1191 __ test(edx, Operand(edx)); |
| 1215 deferred->Branch(not_zero); | 1192 deferred->Branch(not_zero); |
| 1216 // Tag the result and store it in the quotient register. | 1193 // Tag the result and store it in the quotient register. |
| 1217 __ SmiTag(eax); | 1194 __ SmiTag(eax); |
| 1218 deferred->BindExit(); | 1195 deferred->BindExit(); |
| 1219 left->Unuse(); | 1196 left->Unuse(); |
| 1220 right->Unuse(); | 1197 right->Unuse(); |
| 1221 frame_->Push("ient); | 1198 answer = quotient; |
| 1222 } else { | 1199 } else { |
| 1223 ASSERT(op == Token::MOD); | 1200 ASSERT(op == Token::MOD); |
| 1224 // Check for a negative zero result. If the result is zero, and | 1201 // Check for a negative zero result. If the result is zero, and |
| 1225 // the dividend is negative, return a floating point negative | 1202 // the dividend is negative, return a floating point negative |
| 1226 // zero. The frame is unchanged in this block, so local control | 1203 // zero. The frame is unchanged in this block, so local control |
| 1227 // flow can use a Label rather than a JumpTarget. | 1204 // flow can use a Label rather than a JumpTarget. |
| 1228 Label non_zero_result; | 1205 Label non_zero_result; |
| 1229 __ test(edx, Operand(edx)); | 1206 __ test(edx, Operand(edx)); |
| 1230 __ j(not_zero, &non_zero_result, taken); | 1207 __ j(not_zero, &non_zero_result, taken); |
| 1231 __ test(left->reg(), Operand(left->reg())); | 1208 __ test(left->reg(), Operand(left->reg())); |
| 1232 deferred->Branch(negative); | 1209 deferred->Branch(negative); |
| 1233 __ bind(&non_zero_result); | 1210 __ bind(&non_zero_result); |
| 1234 deferred->BindExit(); | 1211 deferred->BindExit(); |
| 1235 left->Unuse(); | 1212 left->Unuse(); |
| 1236 right->Unuse(); | 1213 right->Unuse(); |
| 1237 frame_->Push(&remainder); | 1214 answer = remainder; |
| 1238 } | 1215 } |
| 1239 return; | 1216 ASSERT(answer.is_valid()); |
| 1217 return answer; |
| 1240 } | 1218 } |
| 1241 | 1219 |
| 1242 // Special handling of shift operations because they use fixed | 1220 // Special handling of shift operations because they use fixed |
| 1243 // registers. | 1221 // registers. |
| 1244 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { | 1222 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { |
| 1245 // Move left out of ecx if necessary. | 1223 // Move left out of ecx if necessary. |
| 1246 if (left->is_register() && left->reg().is(ecx)) { | 1224 if (left->is_register() && left->reg().is(ecx)) { |
| 1247 *left = allocator_->Allocate(); | 1225 *left = allocator_->Allocate(); |
| 1248 ASSERT(left->is_valid()); | 1226 ASSERT(left->is_valid()); |
| 1249 __ mov(left->reg(), ecx); | 1227 __ mov(left->reg(), ecx); |
| 1250 } | 1228 } |
| 1251 right->ToRegister(ecx); | 1229 right->ToRegister(ecx); |
| 1252 left->ToRegister(); | 1230 left->ToRegister(); |
| 1253 ASSERT(left->is_register() && !left->reg().is(ecx)); | 1231 ASSERT(left->is_register() && !left->reg().is(ecx)); |
| 1254 ASSERT(right->is_register() && right->reg().is(ecx)); | 1232 ASSERT(right->is_register() && right->reg().is(ecx)); |
| 1255 | 1233 |
| 1256 // We will modify right, it must be spilled. | 1234 // We will modify right, it must be spilled. |
| 1257 frame_->Spill(ecx); | 1235 frame_->Spill(ecx); |
| 1258 | 1236 |
| 1259 // Use a fresh answer register to avoid spilling the left operand. | 1237 // Use a fresh answer register to avoid spilling the left operand. |
| 1260 Result answer = allocator_->Allocate(); | 1238 answer = allocator_->Allocate(); |
| 1261 ASSERT(answer.is_valid()); | 1239 ASSERT(answer.is_valid()); |
| 1262 // Check that both operands are smis using the answer register as a | 1240 // Check that both operands are smis using the answer register as a |
| 1263 // temporary. | 1241 // temporary. |
| 1264 DeferredInlineBinaryOperation* deferred = | 1242 DeferredInlineBinaryOperation* deferred = |
| 1265 new DeferredInlineBinaryOperation(op, | 1243 new DeferredInlineBinaryOperation(op, |
| 1266 answer.reg(), | 1244 answer.reg(), |
| 1267 left->reg(), | 1245 left->reg(), |
| 1268 ecx, | 1246 ecx, |
| 1269 overwrite_mode); | 1247 overwrite_mode); |
| 1270 __ mov(answer.reg(), left->reg()); | 1248 __ mov(answer.reg(), left->reg()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 break; | 1292 break; |
| 1315 } | 1293 } |
| 1316 default: | 1294 default: |
| 1317 UNREACHABLE(); | 1295 UNREACHABLE(); |
| 1318 } | 1296 } |
| 1319 // Smi-tag the result in answer. | 1297 // Smi-tag the result in answer. |
| 1320 __ SmiTag(answer.reg()); | 1298 __ SmiTag(answer.reg()); |
| 1321 deferred->BindExit(); | 1299 deferred->BindExit(); |
| 1322 left->Unuse(); | 1300 left->Unuse(); |
| 1323 right->Unuse(); | 1301 right->Unuse(); |
| 1324 frame_->Push(&answer); | 1302 ASSERT(answer.is_valid()); |
| 1325 return; | 1303 return answer; |
| 1326 } | 1304 } |
| 1327 | 1305 |
| 1328 // Handle the other binary operations. | 1306 // Handle the other binary operations. |
| 1329 left->ToRegister(); | 1307 left->ToRegister(); |
| 1330 right->ToRegister(); | 1308 right->ToRegister(); |
| 1331 // A newly allocated register answer is used to hold the answer. The | 1309 // A newly allocated register answer is used to hold the answer. The |
| 1332 // registers containing left and right are not modified so they don't | 1310 // registers containing left and right are not modified so they don't |
| 1333 // need to be spilled in the fast case. | 1311 // need to be spilled in the fast case. |
| 1334 Result answer = allocator_->Allocate(); | 1312 answer = allocator_->Allocate(); |
| 1335 ASSERT(answer.is_valid()); | 1313 ASSERT(answer.is_valid()); |
| 1336 | 1314 |
| 1337 // Perform the smi tag check. | 1315 // Perform the smi tag check. |
| 1338 DeferredInlineBinaryOperation* deferred = | 1316 DeferredInlineBinaryOperation* deferred = |
| 1339 new DeferredInlineBinaryOperation(op, | 1317 new DeferredInlineBinaryOperation(op, |
| 1340 answer.reg(), | 1318 answer.reg(), |
| 1341 left->reg(), | 1319 left->reg(), |
| 1342 right->reg(), | 1320 right->reg(), |
| 1343 overwrite_mode); | 1321 overwrite_mode); |
| 1344 if (left->reg().is(right->reg())) { | 1322 if (left->reg().is(right->reg())) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1399 __ xor_(answer.reg(), Operand(right->reg())); | 1377 __ xor_(answer.reg(), Operand(right->reg())); |
| 1400 break; | 1378 break; |
| 1401 | 1379 |
| 1402 default: | 1380 default: |
| 1403 UNREACHABLE(); | 1381 UNREACHABLE(); |
| 1404 break; | 1382 break; |
| 1405 } | 1383 } |
| 1406 deferred->BindExit(); | 1384 deferred->BindExit(); |
| 1407 left->Unuse(); | 1385 left->Unuse(); |
| 1408 right->Unuse(); | 1386 right->Unuse(); |
| 1409 frame_->Push(&answer); | 1387 ASSERT(answer.is_valid()); |
| 1388 return answer; |
| 1410 } | 1389 } |
| 1411 | 1390 |
| 1412 | 1391 |
| 1413 // Call the appropriate binary operation stub to compute src op value | 1392 // Call the appropriate binary operation stub to compute src op value |
| 1414 // and leave the result in dst. | 1393 // and leave the result in dst. |
| 1415 class DeferredInlineSmiOperation: public DeferredCode { | 1394 class DeferredInlineSmiOperation: public DeferredCode { |
| 1416 public: | 1395 public: |
| 1417 DeferredInlineSmiOperation(Token::Value op, | 1396 DeferredInlineSmiOperation(Token::Value op, |
| 1418 Register dst, | 1397 Register dst, |
| 1419 Register src, | 1398 Register src, |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 | 1547 |
| 1569 void DeferredInlineSmiSub::Generate() { | 1548 void DeferredInlineSmiSub::Generate() { |
| 1570 // Undo the optimistic sub operation and call the shared stub. | 1549 // Undo the optimistic sub operation and call the shared stub. |
| 1571 __ add(Operand(dst_), Immediate(value_)); | 1550 __ add(Operand(dst_), Immediate(value_)); |
| 1572 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1551 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); |
| 1573 igostub.GenerateCall(masm_, dst_, value_); | 1552 igostub.GenerateCall(masm_, dst_, value_); |
| 1574 if (!dst_.is(eax)) __ mov(dst_, eax); | 1553 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1575 } | 1554 } |
| 1576 | 1555 |
| 1577 | 1556 |
| 1578 void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 1557 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| 1579 Result* operand, | 1558 Result* operand, |
| 1580 Handle<Object> value, | 1559 Handle<Object> value, |
| 1581 StaticType* type, | 1560 StaticType* type, |
| 1582 bool reversed, | 1561 bool reversed, |
| 1583 OverwriteMode overwrite_mode) { | 1562 OverwriteMode overwrite_mode) { |
| 1584 // NOTE: This is an attempt to inline (a bit) more of the code for | 1563 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 1585 // some possible smi operations (like + and -) when (at least) one | 1564 // some possible smi operations (like + and -) when (at least) one |
| 1586 // of the operands is a constant smi. | 1565 // of the operands is a constant smi. |
| 1587 // Consumes the argument "operand". | 1566 // Consumes the argument "operand". |
| 1588 | |
| 1589 // TODO(199): Optimize some special cases of operations involving a | 1567 // TODO(199): Optimize some special cases of operations involving a |
| 1590 // smi literal (multiply by 2, shift by 0, etc.). | 1568 // smi literal (multiply by 2, shift by 0, etc.). |
| 1591 if (IsUnsafeSmi(value)) { | 1569 if (IsUnsafeSmi(value)) { |
| 1592 Result unsafe_operand(value); | 1570 Result unsafe_operand(value); |
| 1593 if (reversed) { | 1571 if (reversed) { |
| 1594 LikelySmiBinaryOperation(op, &unsafe_operand, operand, | 1572 return LikelySmiBinaryOperation(op, &unsafe_operand, operand, |
| 1595 overwrite_mode); | 1573 overwrite_mode); |
| 1596 } else { | 1574 } else { |
| 1597 LikelySmiBinaryOperation(op, operand, &unsafe_operand, | 1575 return LikelySmiBinaryOperation(op, operand, &unsafe_operand, |
| 1598 overwrite_mode); | 1576 overwrite_mode); |
| 1599 } | 1577 } |
| 1600 ASSERT(!operand->is_valid()); | |
| 1601 return; | |
| 1602 } | 1578 } |
| 1603 | 1579 |
| 1604 // Get the literal value. | 1580 // Get the literal value. |
| 1605 Smi* smi_value = Smi::cast(*value); | 1581 Smi* smi_value = Smi::cast(*value); |
| 1606 int int_value = smi_value->value(); | 1582 int int_value = smi_value->value(); |
| 1607 | 1583 |
| 1584 Result answer; |
| 1608 switch (op) { | 1585 switch (op) { |
| 1609 case Token::ADD: { | 1586 case Token::ADD: { |
| 1610 operand->ToRegister(); | 1587 operand->ToRegister(); |
| 1611 frame_->Spill(operand->reg()); | 1588 frame_->Spill(operand->reg()); |
| 1612 | 1589 |
| 1613 // Optimistically add. Call the specialized add stub if the | 1590 // Optimistically add. Call the specialized add stub if the |
| 1614 // result is not a smi or overflows. | 1591 // result is not a smi or overflows. |
| 1615 DeferredCode* deferred = NULL; | 1592 DeferredCode* deferred = NULL; |
| 1616 if (reversed) { | 1593 if (reversed) { |
| 1617 deferred = new DeferredInlineSmiAddReversed(operand->reg(), | 1594 deferred = new DeferredInlineSmiAddReversed(operand->reg(), |
| 1618 smi_value, | 1595 smi_value, |
| 1619 overwrite_mode); | 1596 overwrite_mode); |
| 1620 } else { | 1597 } else { |
| 1621 deferred = new DeferredInlineSmiAdd(operand->reg(), | 1598 deferred = new DeferredInlineSmiAdd(operand->reg(), |
| 1622 smi_value, | 1599 smi_value, |
| 1623 overwrite_mode); | 1600 overwrite_mode); |
| 1624 } | 1601 } |
| 1625 __ add(Operand(operand->reg()), Immediate(value)); | 1602 __ add(Operand(operand->reg()), Immediate(value)); |
| 1626 deferred->Branch(overflow); | 1603 deferred->Branch(overflow); |
| 1627 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1604 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1628 deferred->Branch(not_zero); | 1605 deferred->Branch(not_zero); |
| 1629 deferred->BindExit(); | 1606 deferred->BindExit(); |
| 1630 frame_->Push(operand); | 1607 answer = *operand; |
| 1631 break; | 1608 break; |
| 1632 } | 1609 } |
| 1633 | 1610 |
| 1634 case Token::SUB: { | 1611 case Token::SUB: { |
| 1635 DeferredCode* deferred = NULL; | 1612 DeferredCode* deferred = NULL; |
| 1636 Result answer; // Only allocate a new register if reversed. | |
| 1637 if (reversed) { | 1613 if (reversed) { |
| 1638 // The reversed case is only hit when the right operand is not a | 1614 // The reversed case is only hit when the right operand is not a |
| 1639 // constant. | 1615 // constant. |
| 1640 ASSERT(operand->is_register()); | 1616 ASSERT(operand->is_register()); |
| 1641 answer = allocator()->Allocate(); | 1617 answer = allocator()->Allocate(); |
| 1642 ASSERT(answer.is_valid()); | 1618 ASSERT(answer.is_valid()); |
| 1643 __ Set(answer.reg(), Immediate(value)); | 1619 __ Set(answer.reg(), Immediate(value)); |
| 1644 deferred = new DeferredInlineSmiOperationReversed(op, | 1620 deferred = new DeferredInlineSmiOperationReversed(op, |
| 1645 answer.reg(), | 1621 answer.reg(), |
| 1646 smi_value, | 1622 smi_value, |
| 1647 operand->reg(), | 1623 operand->reg(), |
| 1648 overwrite_mode); | 1624 overwrite_mode); |
| 1649 __ sub(answer.reg(), Operand(operand->reg())); | 1625 __ sub(answer.reg(), Operand(operand->reg())); |
| 1650 } else { | 1626 } else { |
| 1651 operand->ToRegister(); | 1627 operand->ToRegister(); |
| 1652 frame_->Spill(operand->reg()); | 1628 frame_->Spill(operand->reg()); |
| 1653 answer = *operand; | 1629 answer = *operand; |
| 1654 deferred = new DeferredInlineSmiSub(operand->reg(), | 1630 deferred = new DeferredInlineSmiSub(operand->reg(), |
| 1655 smi_value, | 1631 smi_value, |
| 1656 overwrite_mode); | 1632 overwrite_mode); |
| 1657 __ sub(Operand(operand->reg()), Immediate(value)); | 1633 __ sub(Operand(operand->reg()), Immediate(value)); |
| 1658 } | 1634 } |
| 1659 deferred->Branch(overflow); | 1635 deferred->Branch(overflow); |
| 1660 __ test(answer.reg(), Immediate(kSmiTagMask)); | 1636 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 1661 deferred->Branch(not_zero); | 1637 deferred->Branch(not_zero); |
| 1662 deferred->BindExit(); | 1638 deferred->BindExit(); |
| 1663 operand->Unuse(); | 1639 operand->Unuse(); |
| 1664 frame_->Push(&answer); | |
| 1665 break; | 1640 break; |
| 1666 } | 1641 } |
| 1667 | 1642 |
| 1668 case Token::SAR: | 1643 case Token::SAR: |
| 1669 if (reversed) { | 1644 if (reversed) { |
| 1670 Result constant_operand(value); | 1645 Result constant_operand(value); |
| 1671 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1646 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1672 overwrite_mode); | 1647 overwrite_mode); |
| 1673 } else { | 1648 } else { |
| 1674 // Only the least significant 5 bits of the shift value are used. | 1649 // Only the least significant 5 bits of the shift value are used. |
| 1675 // In the slow case, this masking is done inside the runtime call. | 1650 // In the slow case, this masking is done inside the runtime call. |
| 1676 int shift_value = int_value & 0x1f; | 1651 int shift_value = int_value & 0x1f; |
| 1677 operand->ToRegister(); | 1652 operand->ToRegister(); |
| 1678 frame_->Spill(operand->reg()); | 1653 frame_->Spill(operand->reg()); |
| 1679 DeferredInlineSmiOperation* deferred = | 1654 DeferredInlineSmiOperation* deferred = |
| 1680 new DeferredInlineSmiOperation(op, | 1655 new DeferredInlineSmiOperation(op, |
| 1681 operand->reg(), | 1656 operand->reg(), |
| 1682 operand->reg(), | 1657 operand->reg(), |
| 1683 smi_value, | 1658 smi_value, |
| 1684 overwrite_mode); | 1659 overwrite_mode); |
| 1685 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1660 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1686 deferred->Branch(not_zero); | 1661 deferred->Branch(not_zero); |
| 1687 if (shift_value > 0) { | 1662 if (shift_value > 0) { |
| 1688 __ sar(operand->reg(), shift_value); | 1663 __ sar(operand->reg(), shift_value); |
| 1689 __ and_(operand->reg(), ~kSmiTagMask); | 1664 __ and_(operand->reg(), ~kSmiTagMask); |
| 1690 } | 1665 } |
| 1691 deferred->BindExit(); | 1666 deferred->BindExit(); |
| 1692 frame_->Push(operand); | 1667 answer = *operand; |
| 1693 } | 1668 } |
| 1694 break; | 1669 break; |
| 1695 | 1670 |
| 1696 case Token::SHR: | 1671 case Token::SHR: |
| 1697 if (reversed) { | 1672 if (reversed) { |
| 1698 Result constant_operand(value); | 1673 Result constant_operand(value); |
| 1699 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1674 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1700 overwrite_mode); | 1675 overwrite_mode); |
| 1701 } else { | 1676 } else { |
| 1702 // Only the least significant 5 bits of the shift value are used. | 1677 // Only the least significant 5 bits of the shift value are used. |
| 1703 // In the slow case, this masking is done inside the runtime call. | 1678 // In the slow case, this masking is done inside the runtime call. |
| 1704 int shift_value = int_value & 0x1f; | 1679 int shift_value = int_value & 0x1f; |
| 1705 operand->ToRegister(); | 1680 operand->ToRegister(); |
| 1706 Result answer = allocator()->Allocate(); | 1681 answer = allocator()->Allocate(); |
| 1707 ASSERT(answer.is_valid()); | 1682 ASSERT(answer.is_valid()); |
| 1708 DeferredInlineSmiOperation* deferred = | 1683 DeferredInlineSmiOperation* deferred = |
| 1709 new DeferredInlineSmiOperation(op, | 1684 new DeferredInlineSmiOperation(op, |
| 1710 answer.reg(), | 1685 answer.reg(), |
| 1711 operand->reg(), | 1686 operand->reg(), |
| 1712 smi_value, | 1687 smi_value, |
| 1713 overwrite_mode); | 1688 overwrite_mode); |
| 1714 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1689 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1715 deferred->Branch(not_zero); | 1690 deferred->Branch(not_zero); |
| 1716 __ mov(answer.reg(), operand->reg()); | 1691 __ mov(answer.reg(), operand->reg()); |
| 1717 __ SmiUntag(answer.reg()); | 1692 __ SmiUntag(answer.reg()); |
| 1718 __ shr(answer.reg(), shift_value); | 1693 __ shr(answer.reg(), shift_value); |
| 1719 // A negative Smi shifted right two is in the positive Smi range. | 1694 // A negative Smi shifted right two is in the positive Smi range. |
| 1720 if (shift_value < 2) { | 1695 if (shift_value < 2) { |
| 1721 __ test(answer.reg(), Immediate(0xc0000000)); | 1696 __ test(answer.reg(), Immediate(0xc0000000)); |
| 1722 deferred->Branch(not_zero); | 1697 deferred->Branch(not_zero); |
| 1723 } | 1698 } |
| 1724 operand->Unuse(); | 1699 operand->Unuse(); |
| 1725 __ SmiTag(answer.reg()); | 1700 __ SmiTag(answer.reg()); |
| 1726 deferred->BindExit(); | 1701 deferred->BindExit(); |
| 1727 frame_->Push(&answer); | |
| 1728 } | 1702 } |
| 1729 break; | 1703 break; |
| 1730 | 1704 |
| 1731 case Token::SHL: | 1705 case Token::SHL: |
| 1732 if (reversed) { | 1706 if (reversed) { |
| 1733 Result right; | 1707 Result right; |
| 1734 Result right_copy_in_ecx; | 1708 Result right_copy_in_ecx; |
| 1735 | 1709 |
| 1736 // Make sure to get a copy of the right operand into ecx. This | 1710 // Make sure to get a copy of the right operand into ecx. This |
| 1737 // allows us to modify it without having to restore it in the | 1711 // allows us to modify it without having to restore it in the |
| 1738 // deferred code. | 1712 // deferred code. |
| 1739 operand->ToRegister(); | 1713 operand->ToRegister(); |
| 1740 if (operand->reg().is(ecx)) { | 1714 if (operand->reg().is(ecx)) { |
| 1741 right = allocator()->Allocate(); | 1715 right = allocator()->Allocate(); |
| 1742 __ mov(right.reg(), ecx); | 1716 __ mov(right.reg(), ecx); |
| 1743 frame_->Spill(ecx); | 1717 frame_->Spill(ecx); |
| 1744 right_copy_in_ecx = *operand; | 1718 right_copy_in_ecx = *operand; |
| 1745 } else { | 1719 } else { |
| 1746 right_copy_in_ecx = allocator()->Allocate(ecx); | 1720 right_copy_in_ecx = allocator()->Allocate(ecx); |
| 1747 __ mov(ecx, operand->reg()); | 1721 __ mov(ecx, operand->reg()); |
| 1748 right = *operand; | 1722 right = *operand; |
| 1749 } | 1723 } |
| 1750 operand->Unuse(); | 1724 operand->Unuse(); |
| 1751 | 1725 |
| 1752 Result answer = allocator()->Allocate(); | 1726 answer = allocator()->Allocate(); |
| 1753 DeferredInlineSmiOperationReversed* deferred = | 1727 DeferredInlineSmiOperationReversed* deferred = |
| 1754 new DeferredInlineSmiOperationReversed(op, | 1728 new DeferredInlineSmiOperationReversed(op, |
| 1755 answer.reg(), | 1729 answer.reg(), |
| 1756 smi_value, | 1730 smi_value, |
| 1757 right.reg(), | 1731 right.reg(), |
| 1758 overwrite_mode); | 1732 overwrite_mode); |
| 1759 __ mov(answer.reg(), Immediate(int_value)); | 1733 __ mov(answer.reg(), Immediate(int_value)); |
| 1760 __ sar(ecx, kSmiTagSize); | 1734 __ sar(ecx, kSmiTagSize); |
| 1761 deferred->Branch(carry); | 1735 deferred->Branch(carry); |
| 1762 __ shl_cl(answer.reg()); | 1736 __ shl_cl(answer.reg()); |
| 1763 __ cmp(answer.reg(), 0xc0000000); | 1737 __ cmp(answer.reg(), 0xc0000000); |
| 1764 deferred->Branch(sign); | 1738 deferred->Branch(sign); |
| 1765 __ SmiTag(answer.reg()); | 1739 __ SmiTag(answer.reg()); |
| 1766 | 1740 |
| 1767 deferred->BindExit(); | 1741 deferred->BindExit(); |
| 1768 frame_->Push(&answer); | |
| 1769 } else { | 1742 } else { |
| 1770 // Only the least significant 5 bits of the shift value are used. | 1743 // Only the least significant 5 bits of the shift value are used. |
| 1771 // In the slow case, this masking is done inside the runtime call. | 1744 // In the slow case, this masking is done inside the runtime call. |
| 1772 int shift_value = int_value & 0x1f; | 1745 int shift_value = int_value & 0x1f; |
| 1773 operand->ToRegister(); | 1746 operand->ToRegister(); |
| 1774 if (shift_value == 0) { | 1747 if (shift_value == 0) { |
| 1775 // Spill operand so it can be overwritten in the slow case. | 1748 // Spill operand so it can be overwritten in the slow case. |
| 1776 frame_->Spill(operand->reg()); | 1749 frame_->Spill(operand->reg()); |
| 1777 DeferredInlineSmiOperation* deferred = | 1750 DeferredInlineSmiOperation* deferred = |
| 1778 new DeferredInlineSmiOperation(op, | 1751 new DeferredInlineSmiOperation(op, |
| 1779 operand->reg(), | 1752 operand->reg(), |
| 1780 operand->reg(), | 1753 operand->reg(), |
| 1781 smi_value, | 1754 smi_value, |
| 1782 overwrite_mode); | 1755 overwrite_mode); |
| 1783 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1756 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1784 deferred->Branch(not_zero); | 1757 deferred->Branch(not_zero); |
| 1785 deferred->BindExit(); | 1758 deferred->BindExit(); |
| 1786 frame_->Push(operand); | 1759 answer = *operand; |
| 1787 } else { | 1760 } else { |
| 1788 // Use a fresh temporary for nonzero shift values. | 1761 // Use a fresh temporary for nonzero shift values. |
| 1789 Result answer = allocator()->Allocate(); | 1762 answer = allocator()->Allocate(); |
| 1790 ASSERT(answer.is_valid()); | 1763 ASSERT(answer.is_valid()); |
| 1791 DeferredInlineSmiOperation* deferred = | 1764 DeferredInlineSmiOperation* deferred = |
| 1792 new DeferredInlineSmiOperation(op, | 1765 new DeferredInlineSmiOperation(op, |
| 1793 answer.reg(), | 1766 answer.reg(), |
| 1794 operand->reg(), | 1767 operand->reg(), |
| 1795 smi_value, | 1768 smi_value, |
| 1796 overwrite_mode); | 1769 overwrite_mode); |
| 1797 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1770 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1798 deferred->Branch(not_zero); | 1771 deferred->Branch(not_zero); |
| 1799 __ mov(answer.reg(), operand->reg()); | 1772 __ mov(answer.reg(), operand->reg()); |
| 1800 ASSERT(kSmiTag == 0); // adjust code if not the case | 1773 ASSERT(kSmiTag == 0); // adjust code if not the case |
| 1801 // We do no shifts, only the Smi conversion, if shift_value is 1. | 1774 // We do no shifts, only the Smi conversion, if shift_value is 1. |
| 1802 if (shift_value > 1) { | 1775 if (shift_value > 1) { |
| 1803 __ shl(answer.reg(), shift_value - 1); | 1776 __ shl(answer.reg(), shift_value - 1); |
| 1804 } | 1777 } |
| 1805 // Convert int result to Smi, checking that it is in int range. | 1778 // Convert int result to Smi, checking that it is in int range. |
| 1806 ASSERT(kSmiTagSize == 1); // adjust code if not the case | 1779 ASSERT(kSmiTagSize == 1); // adjust code if not the case |
| 1807 __ add(answer.reg(), Operand(answer.reg())); | 1780 __ add(answer.reg(), Operand(answer.reg())); |
| 1808 deferred->Branch(overflow); | 1781 deferred->Branch(overflow); |
| 1809 deferred->BindExit(); | 1782 deferred->BindExit(); |
| 1810 operand->Unuse(); | 1783 operand->Unuse(); |
| 1811 frame_->Push(&answer); | |
| 1812 } | 1784 } |
| 1813 } | 1785 } |
| 1814 break; | 1786 break; |
| 1815 | 1787 |
| 1816 case Token::BIT_OR: | 1788 case Token::BIT_OR: |
| 1817 case Token::BIT_XOR: | 1789 case Token::BIT_XOR: |
| 1818 case Token::BIT_AND: { | 1790 case Token::BIT_AND: { |
| 1819 operand->ToRegister(); | 1791 operand->ToRegister(); |
| 1820 frame_->Spill(operand->reg()); | 1792 frame_->Spill(operand->reg()); |
| 1821 DeferredCode* deferred = NULL; | 1793 DeferredCode* deferred = NULL; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1840 if (int_value != 0) { | 1812 if (int_value != 0) { |
| 1841 __ xor_(Operand(operand->reg()), Immediate(value)); | 1813 __ xor_(Operand(operand->reg()), Immediate(value)); |
| 1842 } | 1814 } |
| 1843 } else { | 1815 } else { |
| 1844 ASSERT(op == Token::BIT_OR); | 1816 ASSERT(op == Token::BIT_OR); |
| 1845 if (int_value != 0) { | 1817 if (int_value != 0) { |
| 1846 __ or_(Operand(operand->reg()), Immediate(value)); | 1818 __ or_(Operand(operand->reg()), Immediate(value)); |
| 1847 } | 1819 } |
| 1848 } | 1820 } |
| 1849 deferred->BindExit(); | 1821 deferred->BindExit(); |
| 1850 frame_->Push(operand); | 1822 answer = *operand; |
| 1851 break; | 1823 break; |
| 1852 } | 1824 } |
| 1853 | 1825 |
| 1854 // Generate inline code for mod of powers of 2 and negative powers of 2. | 1826 // Generate inline code for mod of powers of 2 and negative powers of 2. |
| 1855 case Token::MOD: | 1827 case Token::MOD: |
| 1856 if (!reversed && | 1828 if (!reversed && |
| 1857 int_value != 0 && | 1829 int_value != 0 && |
| 1858 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { | 1830 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { |
| 1859 operand->ToRegister(); | 1831 operand->ToRegister(); |
| 1860 frame_->Spill(operand->reg()); | 1832 frame_->Spill(operand->reg()); |
| 1861 DeferredCode* deferred = new DeferredInlineSmiOperation(op, | 1833 DeferredCode* deferred = new DeferredInlineSmiOperation(op, |
| 1862 operand->reg(), | 1834 operand->reg(), |
| 1863 operand->reg(), | 1835 operand->reg(), |
| 1864 smi_value, | 1836 smi_value, |
| 1865 overwrite_mode); | 1837 overwrite_mode); |
| 1866 // Check for negative or non-Smi left hand side. | 1838 // Check for negative or non-Smi left hand side. |
| 1867 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); | 1839 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 1868 deferred->Branch(not_zero); | 1840 deferred->Branch(not_zero); |
| 1869 if (int_value < 0) int_value = -int_value; | 1841 if (int_value < 0) int_value = -int_value; |
| 1870 if (int_value == 1) { | 1842 if (int_value == 1) { |
| 1871 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); | 1843 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); |
| 1872 } else { | 1844 } else { |
| 1873 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); | 1845 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); |
| 1874 } | 1846 } |
| 1875 deferred->BindExit(); | 1847 deferred->BindExit(); |
| 1876 frame_->Push(operand); | 1848 answer = *operand; |
| 1877 break; | 1849 break; |
| 1878 } | 1850 } |
| 1879 // Fall through if we did not find a power of 2 on the right hand side! | 1851 // Fall through if we did not find a power of 2 on the right hand side! |
| 1880 | 1852 |
| 1881 default: { | 1853 default: { |
| 1882 Result constant_operand(value); | 1854 Result constant_operand(value); |
| 1883 if (reversed) { | 1855 if (reversed) { |
| 1884 LikelySmiBinaryOperation(op, &constant_operand, operand, | 1856 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1885 overwrite_mode); | 1857 overwrite_mode); |
| 1886 } else { | 1858 } else { |
| 1887 LikelySmiBinaryOperation(op, operand, &constant_operand, | 1859 answer = LikelySmiBinaryOperation(op, operand, &constant_operand, |
| 1888 overwrite_mode); | 1860 overwrite_mode); |
| 1889 } | 1861 } |
| 1890 break; | 1862 break; |
| 1891 } | 1863 } |
| 1892 } | 1864 } |
| 1893 ASSERT(!operand->is_valid()); | 1865 ASSERT(answer.is_valid()); |
| 1866 return answer; |
| 1894 } | 1867 } |
| 1895 | 1868 |
| 1896 | 1869 |
| 1897 static bool CouldBeNaN(const Result& result) { | 1870 static bool CouldBeNaN(const Result& result) { |
| 1898 if (!result.is_constant()) return true; | 1871 if (!result.is_constant()) return true; |
| 1899 if (!result.handle()->IsHeapNumber()) return false; | 1872 if (!result.handle()->IsHeapNumber()) return false; |
| 1900 return isnan(HeapNumber::cast(*result.handle())->value()); | 1873 return isnan(HeapNumber::cast(*result.handle())->value()); |
| 1901 } | 1874 } |
| 1902 | 1875 |
| 1903 | 1876 |
| (...skipping 7905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9809 | 9782 |
| 9810 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 9783 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 9811 // tagged as a small integer. | 9784 // tagged as a small integer. |
| 9812 __ bind(&runtime); | 9785 __ bind(&runtime); |
| 9813 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 9786 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
| 9814 } | 9787 } |
| 9815 | 9788 |
| 9816 #undef __ | 9789 #undef __ |
| 9817 | 9790 |
| 9818 } } // namespace v8::internal | 9791 } } // namespace v8::internal |
| OLD | NEW |