| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 x >>= 4; | 1001 x >>= 4; |
| 1002 } | 1002 } |
| 1003 while ((x & 1) == 0) { | 1003 while ((x & 1) == 0) { |
| 1004 bit_posn++; | 1004 bit_posn++; |
| 1005 x >>= 1; | 1005 x >>= 1; |
| 1006 } | 1006 } |
| 1007 return bit_posn; | 1007 return bit_posn; |
| 1008 } | 1008 } |
| 1009 | 1009 |
| 1010 | 1010 |
| 1011 void CodeGenerator::VirtualFrameSmiOperation(Token::Value op, | 1011 void CodeGenerator::SmiOperation(Token::Value op, |
| 1012 Handle<Object> value, | 1012 Handle<Object> value, |
| 1013 bool reversed, | 1013 bool reversed, |
| 1014 OverwriteMode mode) { | 1014 OverwriteMode mode) { |
| 1015 int int_value = Smi::cast(*value)->value(); | 1015 int int_value = Smi::cast(*value)->value(); |
| 1016 | 1016 |
| 1017 bool something_to_inline; | 1017 bool something_to_inline; |
| 1018 switch (op) { | 1018 switch (op) { |
| 1019 case Token::ADD: | 1019 case Token::ADD: |
| 1020 case Token::SUB: | 1020 case Token::SUB: |
| 1021 case Token::BIT_AND: | 1021 case Token::BIT_AND: |
| 1022 case Token::BIT_OR: | 1022 case Token::BIT_OR: |
| 1023 case Token::BIT_XOR: { | 1023 case Token::BIT_XOR: { |
| 1024 something_to_inline = true; | 1024 something_to_inline = true; |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1225 break; | 1225 break; |
| 1226 } | 1226 } |
| 1227 | 1227 |
| 1228 default: | 1228 default: |
| 1229 UNREACHABLE(); | 1229 UNREACHABLE(); |
| 1230 break; | 1230 break; |
| 1231 } | 1231 } |
| 1232 } | 1232 } |
| 1233 | 1233 |
| 1234 | 1234 |
| 1235 void CodeGenerator::SmiOperation(Token::Value op, | |
| 1236 Handle<Object> value, | |
| 1237 bool reversed, | |
| 1238 OverwriteMode mode) { | |
| 1239 VirtualFrame::SpilledScope spilled_scope(frame_); | |
| 1240 // NOTE: This is an attempt to inline (a bit) more of the code for | |
| 1241 // some possible smi operations (like + and -) when (at least) one | |
| 1242 // of the operands is a literal smi. With this optimization, the | |
| 1243 // performance of the system is increased by ~15%, and the generated | |
| 1244 // code size is increased by ~1% (measured on a combination of | |
| 1245 // different benchmarks). | |
| 1246 | |
| 1247 // sp[0] : operand | |
| 1248 | |
| 1249 int int_value = Smi::cast(*value)->value(); | |
| 1250 | |
| 1251 JumpTarget exit; | |
| 1252 frame_->EmitPop(r0); | |
| 1253 | |
| 1254 bool something_to_inline = true; | |
| 1255 switch (op) { | |
| 1256 case Token::ADD: { | |
| 1257 DeferredCode* deferred = | |
| 1258 new DeferredInlineSmiOperation(op, int_value, reversed, mode, r0); | |
| 1259 | |
| 1260 __ add(r0, r0, Operand(value), SetCC); | |
| 1261 deferred->Branch(vs); | |
| 1262 __ tst(r0, Operand(kSmiTagMask)); | |
| 1263 deferred->Branch(ne); | |
| 1264 deferred->BindExit(); | |
| 1265 break; | |
| 1266 } | |
| 1267 | |
| 1268 case Token::SUB: { | |
| 1269 DeferredCode* deferred = | |
| 1270 new DeferredInlineSmiOperation(op, int_value, reversed, mode, r0); | |
| 1271 | |
| 1272 if (reversed) { | |
| 1273 __ rsb(r0, r0, Operand(value), SetCC); | |
| 1274 } else { | |
| 1275 __ sub(r0, r0, Operand(value), SetCC); | |
| 1276 } | |
| 1277 deferred->Branch(vs); | |
| 1278 __ tst(r0, Operand(kSmiTagMask)); | |
| 1279 deferred->Branch(ne); | |
| 1280 deferred->BindExit(); | |
| 1281 break; | |
| 1282 } | |
| 1283 | |
| 1284 | |
| 1285 case Token::BIT_OR: | |
| 1286 case Token::BIT_XOR: | |
| 1287 case Token::BIT_AND: { | |
| 1288 DeferredCode* deferred = | |
| 1289 new DeferredInlineSmiOperation(op, int_value, reversed, mode, r0); | |
| 1290 __ tst(r0, Operand(kSmiTagMask)); | |
| 1291 deferred->Branch(ne); | |
| 1292 switch (op) { | |
| 1293 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break; | |
| 1294 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break; | |
| 1295 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break; | |
| 1296 default: UNREACHABLE(); | |
| 1297 } | |
| 1298 deferred->BindExit(); | |
| 1299 break; | |
| 1300 } | |
| 1301 | |
| 1302 case Token::SHL: | |
| 1303 case Token::SHR: | |
| 1304 case Token::SAR: { | |
| 1305 if (reversed) { | |
| 1306 something_to_inline = false; | |
| 1307 break; | |
| 1308 } | |
| 1309 int shift_value = int_value & 0x1f; // least significant 5 bits | |
| 1310 DeferredCode* deferred = | |
| 1311 new DeferredInlineSmiOperation(op, shift_value, false, mode, r0); | |
| 1312 __ tst(r0, Operand(kSmiTagMask)); | |
| 1313 deferred->Branch(ne); | |
| 1314 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags | |
| 1315 switch (op) { | |
| 1316 case Token::SHL: { | |
| 1317 if (shift_value != 0) { | |
| 1318 __ mov(r2, Operand(r2, LSL, shift_value)); | |
| 1319 } | |
| 1320 // check that the *unsigned* result fits in a smi | |
| 1321 __ add(r3, r2, Operand(0x40000000), SetCC); | |
| 1322 deferred->Branch(mi); | |
| 1323 break; | |
| 1324 } | |
| 1325 case Token::SHR: { | |
| 1326 // LSR by immediate 0 means shifting 32 bits. | |
| 1327 if (shift_value != 0) { | |
| 1328 __ mov(r2, Operand(r2, LSR, shift_value)); | |
| 1329 } | |
| 1330 // check that the *unsigned* result fits in a smi | |
| 1331 // neither of the two high-order bits can be set: | |
| 1332 // - 0x80000000: high bit would be lost when smi tagging | |
| 1333 // - 0x40000000: this number would convert to negative when | |
| 1334 // smi tagging these two cases can only happen with shifts | |
| 1335 // by 0 or 1 when handed a valid smi | |
| 1336 __ and_(r3, r2, Operand(0xc0000000), SetCC); | |
| 1337 deferred->Branch(ne); | |
| 1338 break; | |
| 1339 } | |
| 1340 case Token::SAR: { | |
| 1341 if (shift_value != 0) { | |
| 1342 // ASR by immediate 0 means shifting 32 bits. | |
| 1343 __ mov(r2, Operand(r2, ASR, shift_value)); | |
| 1344 } | |
| 1345 break; | |
| 1346 } | |
| 1347 default: UNREACHABLE(); | |
| 1348 } | |
| 1349 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); | |
| 1350 deferred->BindExit(); | |
| 1351 break; | |
| 1352 } | |
| 1353 | |
| 1354 case Token::MOD: { | |
| 1355 if (reversed || int_value < 2 || !IsPowerOf2(int_value)) { | |
| 1356 something_to_inline = false; | |
| 1357 break; | |
| 1358 } | |
| 1359 DeferredCode* deferred = | |
| 1360 new DeferredInlineSmiOperation(op, int_value, reversed, mode, r0); | |
| 1361 unsigned mask = (0x80000000u | kSmiTagMask); | |
| 1362 __ tst(r0, Operand(mask)); | |
| 1363 deferred->Branch(ne); // Go to deferred code on non-Smis and negative. | |
| 1364 mask = (int_value << kSmiTagSize) - 1; | |
| 1365 __ and_(r0, r0, Operand(mask)); | |
| 1366 deferred->BindExit(); | |
| 1367 break; | |
| 1368 } | |
| 1369 | |
| 1370 case Token::MUL: { | |
| 1371 if (!IsEasyToMultiplyBy(int_value)) { | |
| 1372 something_to_inline = false; | |
| 1373 break; | |
| 1374 } | |
| 1375 DeferredCode* deferred = | |
| 1376 new DeferredInlineSmiOperation(op, int_value, reversed, mode, r0); | |
| 1377 unsigned max_smi_that_wont_overflow = Smi::kMaxValue / int_value; | |
| 1378 max_smi_that_wont_overflow <<= kSmiTagSize; | |
| 1379 unsigned mask = 0x80000000u; | |
| 1380 while ((mask & max_smi_that_wont_overflow) == 0) { | |
| 1381 mask |= mask >> 1; | |
| 1382 } | |
| 1383 mask |= kSmiTagMask; | |
| 1384 // This does a single mask that checks for a too high value in a | |
| 1385 // conservative way and for a non-Smi. It also filters out negative | |
| 1386 // numbers, unfortunately, but since this code is inline we prefer | |
| 1387 // brevity to comprehensiveness. | |
| 1388 __ tst(r0, Operand(mask)); | |
| 1389 deferred->Branch(ne); | |
| 1390 MultiplyByKnownInt(masm_, r0, r0, int_value); | |
| 1391 deferred->BindExit(); | |
| 1392 break; | |
| 1393 } | |
| 1394 | |
| 1395 default: | |
| 1396 something_to_inline = false; | |
| 1397 break; | |
| 1398 } | |
| 1399 | |
| 1400 if (!something_to_inline) { | |
| 1401 if (!reversed) { | |
| 1402 frame_->EmitPush(r0); | |
| 1403 __ mov(r0, Operand(value)); | |
| 1404 frame_->EmitPush(r0); | |
| 1405 GenericBinaryOperation(op, mode, int_value); | |
| 1406 } else { | |
| 1407 __ mov(ip, Operand(value)); | |
| 1408 frame_->EmitPush(ip); | |
| 1409 frame_->EmitPush(r0); | |
| 1410 GenericBinaryOperation(op, mode, kUnknownIntValue); | |
| 1411 } | |
| 1412 } | |
| 1413 | |
| 1414 exit.Bind(); | |
| 1415 } | |
| 1416 | |
| 1417 | |
| 1418 void CodeGenerator::Comparison(Condition cc, | 1235 void CodeGenerator::Comparison(Condition cc, |
| 1419 Expression* left, | 1236 Expression* left, |
| 1420 Expression* right, | 1237 Expression* right, |
| 1421 bool strict) { | 1238 bool strict) { |
| 1422 VirtualFrame::RegisterAllocationScope scope(this); | 1239 VirtualFrame::RegisterAllocationScope scope(this); |
| 1423 | 1240 |
| 1424 if (left != NULL) Load(left); | 1241 if (left != NULL) Load(left); |
| 1425 if (right != NULL) Load(right); | 1242 if (right != NULL) Load(right); |
| 1426 | 1243 |
| 1427 // sp[0] : y | 1244 // sp[0] : y |
| (...skipping 2046 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3474 Load(node->value()); | 3291 Load(node->value()); |
| 3475 | 3292 |
| 3476 } else { // Assignment is a compound assignment. | 3293 } else { // Assignment is a compound assignment. |
| 3477 // Get the old value of the lhs. | 3294 // Get the old value of the lhs. |
| 3478 target.GetValue(); | 3295 target.GetValue(); |
| 3479 Literal* literal = node->value()->AsLiteral(); | 3296 Literal* literal = node->value()->AsLiteral(); |
| 3480 bool overwrite = | 3297 bool overwrite = |
| 3481 (node->value()->AsBinaryOperation() != NULL && | 3298 (node->value()->AsBinaryOperation() != NULL && |
| 3482 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3299 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 3483 if (literal != NULL && literal->handle()->IsSmi()) { | 3300 if (literal != NULL && literal->handle()->IsSmi()) { |
| 3484 VirtualFrameSmiOperation(node->binary_op(), | 3301 SmiOperation(node->binary_op(), |
| 3485 literal->handle(), | 3302 literal->handle(), |
| 3486 false, | 3303 false, |
| 3487 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3304 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 3488 } else { | 3305 } else { |
| 3489 Load(node->value()); | 3306 Load(node->value()); |
| 3490 VirtualFrameBinaryOperation(node->binary_op(), | 3307 VirtualFrameBinaryOperation(node->binary_op(), |
| 3491 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3308 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 3492 } | 3309 } |
| 3493 } | 3310 } |
| 3494 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 3311 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 3495 if (var != NULL && | 3312 if (var != NULL && |
| 3496 (var->mode() == Variable::CONST) && | 3313 (var->mode() == Variable::CONST) && |
| 3497 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 3314 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| (...skipping 1463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4961 bool overwrite_left = | 4778 bool overwrite_left = |
| 4962 (node->left()->AsBinaryOperation() != NULL && | 4779 (node->left()->AsBinaryOperation() != NULL && |
| 4963 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); | 4780 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 4964 bool overwrite_right = | 4781 bool overwrite_right = |
| 4965 (node->right()->AsBinaryOperation() != NULL && | 4782 (node->right()->AsBinaryOperation() != NULL && |
| 4966 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); | 4783 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 4967 | 4784 |
| 4968 if (rliteral != NULL && rliteral->handle()->IsSmi()) { | 4785 if (rliteral != NULL && rliteral->handle()->IsSmi()) { |
| 4969 VirtualFrame::RegisterAllocationScope scope(this); | 4786 VirtualFrame::RegisterAllocationScope scope(this); |
| 4970 Load(node->left()); | 4787 Load(node->left()); |
| 4971 VirtualFrameSmiOperation( | 4788 SmiOperation(node->op(), |
| 4972 node->op(), | 4789 rliteral->handle(), |
| 4973 rliteral->handle(), | 4790 false, |
| 4974 false, | 4791 overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); |
| 4975 overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); | |
| 4976 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { | 4792 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { |
| 4977 VirtualFrame::RegisterAllocationScope scope(this); | 4793 VirtualFrame::RegisterAllocationScope scope(this); |
| 4978 Load(node->right()); | 4794 Load(node->right()); |
| 4979 VirtualFrameSmiOperation(node->op(), | 4795 SmiOperation(node->op(), |
| 4980 lliteral->handle(), | 4796 lliteral->handle(), |
| 4981 true, | 4797 true, |
| 4982 overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); | 4798 overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); |
| 4983 } else { | 4799 } else { |
| 4984 VirtualFrame::RegisterAllocationScope scope(this); | 4800 VirtualFrame::RegisterAllocationScope scope(this); |
| 4985 OverwriteMode overwrite_mode = NO_OVERWRITE; | 4801 OverwriteMode overwrite_mode = NO_OVERWRITE; |
| 4986 if (overwrite_left) { | 4802 if (overwrite_left) { |
| 4987 overwrite_mode = OVERWRITE_LEFT; | 4803 overwrite_mode = OVERWRITE_LEFT; |
| 4988 } else if (overwrite_right) { | 4804 } else if (overwrite_right) { |
| 4989 overwrite_mode = OVERWRITE_RIGHT; | 4805 overwrite_mode = OVERWRITE_RIGHT; |
| 4990 } | 4806 } |
| 4991 Load(node->left()); | 4807 Load(node->left()); |
| 4992 Load(node->right()); | 4808 Load(node->right()); |
| (...skipping 4630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9623 | 9439 |
| 9624 // Just jump to runtime to add the two strings. | 9440 // Just jump to runtime to add the two strings. |
| 9625 __ bind(&string_add_runtime); | 9441 __ bind(&string_add_runtime); |
| 9626 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 9442 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 9627 } | 9443 } |
| 9628 | 9444 |
| 9629 | 9445 |
| 9630 #undef __ | 9446 #undef __ |
| 9631 | 9447 |
| 9632 } } // namespace v8::internal | 9448 } } // namespace v8::internal |
| OLD | NEW |