| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/opt_code_generator.h" | 8 #include "vm/opt_code_generator.h" |
| 9 | 9 |
| 10 #include "vm/assembler_macros.h" | 10 #include "vm/assembler_macros.h" |
| (...skipping 1406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1417 __ j(condition, nInfo.true_label()); | 1417 __ j(condition, nInfo.true_label()); |
| 1418 __ jmp(nInfo.false_label()); | 1418 __ jmp(nInfo.false_label()); |
| 1419 } else if (nInfo.fallthrough_label() == nInfo.false_label()) { | 1419 } else if (nInfo.fallthrough_label() == nInfo.false_label()) { |
| 1420 __ j(condition, nInfo.true_label()); | 1420 __ j(condition, nInfo.true_label()); |
| 1421 } else if (nInfo.fallthrough_label() == nInfo.true_label()) { | 1421 } else if (nInfo.fallthrough_label() == nInfo.true_label()) { |
| 1422 __ j(NegateCondition(condition), nInfo.false_label()); | 1422 __ j(NegateCondition(condition), nInfo.false_label()); |
| 1423 } | 1423 } |
| 1424 } | 1424 } |
| 1425 | 1425 |
| 1426 | 1426 |
| 1427 // Return false if the code cannot be generated. | 1427 // Generate code under assumption that it is common that a Smi |
| 1428 // is compared with null. |
| 1429 // Left argument can be Smi or null, otherwise deoptimize and collect more |
| 1430 // type information. |
| 1431 // Right operand can be Smi or null, otherwise call operator on Smi (e.g, |
| 1432 // when compared with double). |
| 1433 // This code will be more optimized once we collect types for two arguments. |
| 1434 void OptimizingCodeGenerator::GenerateSmiEquality(ComparisonNode* node) { |
| 1435 ASSERT((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)); |
| 1436 CodeGenInfo left_info(node->left()); |
| 1437 CodeGenInfo right_info(node->right()); |
| 1438 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1439 if (!CodeGenerator::IsResultNeeded(node)) { |
| 1440 return; |
| 1441 } |
| 1442 const Immediate raw_null = |
| 1443 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1444 Label evaluate_comparison; |
| 1445 if (!left_info.IsClass(smi_class_)) { |
| 1446 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); |
| 1447 Label left_not_null; |
| 1448 __ cmpl(EAX, raw_null); |
| 1449 __ j(NOT_EQUAL, &left_not_null, Assembler::kNearJump); |
| 1450 |
| 1451 // Left is null, strict compare. |
| 1452 __ cmpl(EAX, EDX); |
| 1453 __ jmp(&evaluate_comparison, Assembler::kNearJump); |
| 1454 |
| 1455 // Deoptimize if left is not Smi. |
| 1456 __ Bind(&left_not_null); |
| 1457 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1458 __ j(NOT_ZERO, deopt_blob->label()); |
| 1459 } |
| 1460 Label done; |
| 1461 if (right_info.IsClass(smi_class_)) { |
| 1462 __ cmpl(EAX, EDX); |
| 1463 // Fall through to evaluate comparison. |
| 1464 } else { |
| 1465 Label call_operator, inlined_compare; |
| 1466 // Test right for being Smi. |
| 1467 __ testl(EDX, Immediate(kSmiTagMask)); |
| 1468 __ j(ZERO, &inlined_compare, Assembler::kNearJump); |
| 1469 // Right is not Smi, test it for being null; if so result is false which |
| 1470 // is generated by comparing it to left. If right is not null call operator |
| 1471 // (could be double). |
| 1472 __ cmpl(EDX, raw_null); |
| 1473 __ j(NOT_EQUAL, &call_operator, Assembler::kNearJump); |
| 1474 |
| 1475 __ Bind(&inlined_compare); |
| 1476 // Left is Smi, right is Smi or Null. |
| 1477 __ cmpl(EAX, EDX); |
| 1478 __ jmp(&evaluate_comparison); |
| 1479 |
| 1480 __ Bind(&call_operator); |
| 1481 // Left is Smi. |
| 1482 const int kNumberOfArguments = 2; |
| 1483 const Array& kNoArgumentNames = Array::Handle(); |
| 1484 __ pushl(EAX); |
| 1485 __ pushl(EDX); |
| 1486 GenerateCheckedInstanceCalls(node, |
| 1487 node->left(), |
| 1488 node->id(), |
| 1489 node->token_index(), |
| 1490 kNumberOfArguments, |
| 1491 kNoArgumentNames); |
| 1492 __ pushl(EAX); |
| 1493 __ jmp(&done, Assembler::kNearJump); |
| 1494 } |
| 1495 __ Bind(&evaluate_comparison); |
| 1496 // Condition is set by a previous comparison operation. |
| 1497 Condition condition = OVERFLOW; // Initialize to something. |
| 1498 bool ok = SupportedTokenKindToSmiCondition(node->kind(), &condition); |
| 1499 ASSERT(ok); |
| 1500 if (NodeInfoHasLabels(node)) { |
| 1501 GenerateConditionalJumps(*(node->info()), condition); |
| 1502 node->info()->set_labels_used(true); |
| 1503 } else { |
| 1504 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1505 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1506 Label true_label; |
| 1507 __ j(condition, &true_label, Assembler::kNearJump); |
| 1508 __ PushObject(bool_false); |
| 1509 __ jmp(&done, Assembler::kNearJump); |
| 1510 __ Bind(&true_label); |
| 1511 __ PushObject(bool_true); |
| 1512 } |
| 1513 __ Bind(&done); |
| 1514 } |
| 1515 |
| 1516 |
| 1517 // Return false if the code cannot be generated. It is expected that |
| 1518 // node->left() is Smi (or null for equality comparison). |
| 1428 bool OptimizingCodeGenerator::GenerateSmiComparison(ComparisonNode* node) { | 1519 bool OptimizingCodeGenerator::GenerateSmiComparison(ComparisonNode* node) { |
| 1520 if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
| 1521 GenerateSmiEquality(node); |
| 1522 return true; |
| 1523 } |
| 1429 Condition condition; | 1524 Condition condition; |
| 1430 if (!SupportedTokenKindToSmiCondition(node->kind(), &condition)) { | 1525 if (!SupportedTokenKindToSmiCondition(node->kind(), &condition)) { |
| 1431 return false; | 1526 return false; |
| 1432 } | 1527 } |
| 1433 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1528 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1434 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1529 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1435 CodeGenInfo left_info(node->left()); | 1530 CodeGenInfo left_info(node->left()); |
| 1436 CodeGenInfo right_info(node->right()); | 1531 CodeGenInfo right_info(node->right()); |
| 1437 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1532 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1438 if (!CodeGenerator::IsResultNeeded(node)) { | 1533 if (!CodeGenerator::IsResultNeeded(node)) { |
| 1439 return true; | 1534 return true; |
| 1440 } | 1535 } |
| 1441 Label two_smis; | |
| 1442 if (left_info.IsClass(smi_class_) && right_info.IsClass(smi_class_)) { | 1536 if (left_info.IsClass(smi_class_) && right_info.IsClass(smi_class_)) { |
| 1443 __ cmpl(EAX, EDX); | 1537 __ cmpl(EAX, EDX); |
| 1444 } else if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { | 1538 } else if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { |
| 1445 // One is Smi. | 1539 // One is Smi. |
| 1446 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | 1540 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); |
| 1447 Register reg_to_test = left_info.IsClass(smi_class_) ? EDX : EAX; | 1541 Register reg_to_test = left_info.IsClass(smi_class_) ? EDX : EAX; |
| 1448 __ testl(reg_to_test, Immediate(kSmiTagMask)); | 1542 __ testl(reg_to_test, Immediate(kSmiTagMask)); |
| 1449 __ j(NOT_ZERO, deopt_blob->label()); | 1543 __ j(NOT_ZERO, deopt_blob->label()); |
| 1450 __ cmpl(EAX, EDX); | 1544 __ cmpl(EAX, EDX); |
| 1451 } else { | 1545 } else { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1492 return true; | 1586 return true; |
| 1493 default: | 1587 default: |
| 1494 return false; | 1588 return false; |
| 1495 } | 1589 } |
| 1496 } | 1590 } |
| 1497 | 1591 |
| 1498 | 1592 |
| 1499 // Checks if an inlined equality/non-equality operation can be emitted: | 1593 // Checks if an inlined equality/non-equality operation can be emitted: |
| 1500 // - type feedback must exist. | 1594 // - type feedback must exist. |
| 1501 // - no class in type feedback list overrides '=='. | 1595 // - no class in type feedback list overrides '=='. |
| 1502 // - no Smi class in type feedback class list. | 1596 // - no Smi class in type feedback class list (Smi overrides equality operator). |
| 1503 bool OptimizingCodeGenerator::GenerateEqualityComparison(ComparisonNode* node) { | 1597 bool OptimizingCodeGenerator::GenerateEqualityComparison(ComparisonNode* node) { |
| 1504 ASSERT((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)); | 1598 ASSERT((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)); |
| 1505 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1599 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1506 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1600 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1507 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 1601 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 1508 if (classes == NULL) { | 1602 if (classes == NULL) { |
| 1509 return false; | 1603 return false; |
| 1510 } | 1604 } |
| 1511 const int num_classes = classes->length(); | 1605 const int num_classes = classes->length(); |
| 1512 // 'num_classes' can be 0 if the receiver was always null. | 1606 // 'num_classes' can be 0 if the receiver was always null. |
| (...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2177 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2271 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2178 // Result is in EAX. | 2272 // Result is in EAX. |
| 2179 if (IsResultNeeded(node)) { | 2273 if (IsResultNeeded(node)) { |
| 2180 __ pushl(EAX); | 2274 __ pushl(EAX); |
| 2181 } | 2275 } |
| 2182 } | 2276 } |
| 2183 | 2277 |
| 2184 } // namespace dart | 2278 } // namespace dart |
| 2185 | 2279 |
| 2186 #endif // defined TARGET_ARCH_IA32 | 2280 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |