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 |