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 |