| 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 1519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1530 | 1530 |
| 1531 | 1531 |
| 1532 // Return true if all targets in 'ic_data' point to same | 1532 // Return true if all targets in 'ic_data' point to same |
| 1533 // inlineable getter target. | 1533 // inlineable getter target. |
| 1534 static bool ICDataToSameInlineableInstanceGetter(const ICData& ic_data) { | 1534 static bool ICDataToSameInlineableInstanceGetter(const ICData& ic_data) { |
| 1535 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); | 1535 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); |
| 1536 return !target.IsNull() && IsInlineableInstanceGetter(target); | 1536 return !target.IsNull() && IsInlineableInstanceGetter(target); |
| 1537 } | 1537 } |
| 1538 | 1538 |
| 1539 | 1539 |
| 1540 // Return true if all targets in 'ic_data' point to same | |
| 1541 // inlineable getter target. | |
| 1542 static bool ICDataToSameInlineableInstanceSetter(const ICData& ic_data) { | |
| 1543 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); | |
| 1544 return !target.IsNull() && (target.kind() == RawFunction::kImplicitSetter); | |
| 1545 } | |
| 1546 | |
| 1547 | |
| 1548 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, | 1540 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, |
| 1549 intptr_t id, | 1541 intptr_t id, |
| 1550 AstNode* receiver, | 1542 AstNode* receiver, |
| 1551 const String& field_name, | 1543 const String& field_name, |
| 1552 Register recv_reg) { | 1544 Register recv_reg) { |
| 1553 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { | 1545 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { |
| 1554 InlineInstanceGettersWithSameTarget(node, | 1546 InlineInstanceGettersWithSameTarget(node, |
| 1555 id, | 1547 id, |
| 1556 receiver, | 1548 receiver, |
| 1557 field_name, | 1549 field_name, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1591 node->receiver(), | 1583 node->receiver(), |
| 1592 node->field_name(), | 1584 node->field_name(), |
| 1593 EBX); | 1585 EBX); |
| 1594 // Result is in EAX. | 1586 // Result is in EAX. |
| 1595 if (CodeGenerator::IsResultNeeded(node)) { | 1587 if (CodeGenerator::IsResultNeeded(node)) { |
| 1596 __ pushl(EAX); | 1588 __ pushl(EAX); |
| 1597 } | 1589 } |
| 1598 } | 1590 } |
| 1599 | 1591 |
| 1600 | 1592 |
| 1601 // Clobber EBX leave 'value_reg' untouched. | 1593 // Helper struct to pass arguments to 'GenerateInstanceSetter'. |
| 1602 void OptimizingCodeGenerator::InlineInstanceSettersWithSameTarget( | 1594 struct InstanceSetterArgs { |
| 1603 AstNode* node, | 1595 const Class* cls; |
| 1604 intptr_t id, | 1596 const Function* target; |
| 1605 AstNode* receiver, | 1597 const String* field_name; |
| 1606 const String& field_name, | 1598 Register recv_reg; |
| 1607 Register recv_reg, | 1599 Register value_reg; |
| 1608 Register value_reg) { | 1600 intptr_t id; |
| 1609 ASSERT((recv_reg != EBX) && (value_reg != EBX)); | 1601 intptr_t token_index; |
| 1610 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob( | 1602 }; |
| 1611 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); | 1603 |
| 1612 if (NodeMayBeSmi(receiver)) { | 1604 |
| 1613 __ testl(recv_reg, Immediate(kSmiTagMask)); | 1605 // Preserves 'args.value_reg'. Either stores instance field directly or |
| 1614 __ j(ZERO, deopt_blob->label()); | 1606 // calls the setter method. |
| 1607 void OptimizingCodeGenerator::GenerateInstanceSetter( |
| 1608 const InstanceSetterArgs& args) { |
| 1609 if (args.target->kind() == RawFunction::kImplicitSetter) { |
| 1610 intptr_t field_offset = GetFieldOffset(*(args.cls), *(args.field_name)); |
| 1611 ASSERT(field_offset >= 0); |
| 1612 __ StoreIntoObject(args.recv_reg, |
| 1613 FieldAddress(args.recv_reg, field_offset), args.value_reg); |
| 1614 } else { |
| 1615 __ pushl(args.value_reg); |
| 1616 __ pushl(args.recv_reg); |
| 1617 __ pushl(args.value_reg); |
| 1618 const Array& no_optional_argument_names = Array::Handle(); |
| 1619 GenerateDirectCall(args.id, |
| 1620 args.token_index, |
| 1621 *(args.target), |
| 1622 2, |
| 1623 no_optional_argument_names); |
| 1624 __ popl(args.value_reg); |
| 1615 } | 1625 } |
| 1616 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); | |
| 1617 const ICData& ic_data = node->ICDataAtId(id); | |
| 1618 Function& target = Function::Handle(); | |
| 1619 Label store_field; | |
| 1620 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 1621 Class& cls = Class::ZoneHandle(); | |
| 1622 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 1623 __ CompareObject(EBX, cls); | |
| 1624 if (i == (ic_data.NumberOfChecks() - 1)) { | |
| 1625 __ j(NOT_EQUAL, deopt_blob->label()); | |
| 1626 } else { | |
| 1627 __ j(EQUAL, &store_field); | |
| 1628 } | |
| 1629 } | |
| 1630 Class& cls = Class::Handle(); | |
| 1631 ic_data.GetOneClassCheckAt(0, &cls, &target); | |
| 1632 | |
| 1633 __ Bind(&store_field); | |
| 1634 ASSERT(target.kind() == RawFunction::kImplicitSetter); | |
| 1635 intptr_t field_offset = GetFieldOffset(cls, field_name); | |
| 1636 ASSERT(field_offset >= 0); | |
| 1637 __ StoreIntoObject(recv_reg, FieldAddress(recv_reg, field_offset), value_reg); | |
| 1638 } | 1626 } |
| 1639 | 1627 |
| 1640 | 1628 |
| 1641 // Returns value in 'value_reg'. | 1629 // Returns value in 'value_reg', clobbers EBX. |
| 1642 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, | 1630 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, |
| 1643 intptr_t id, | 1631 intptr_t id, |
| 1644 AstNode* receiver, | 1632 AstNode* receiver, |
| 1645 const String& field_name, | 1633 const String& field_name, |
| 1646 Register recv_reg, | 1634 Register recv_reg, |
| 1647 Register value_reg) { | 1635 Register value_reg) { |
| 1648 if (ICDataToSameInlineableInstanceSetter(node->ICDataAtId(id))) { | 1636 // EBX is used as temporary register for class. |
| 1649 InlineInstanceSettersWithSameTarget(node, | 1637 ASSERT((recv_reg != EBX) && (value_reg != EBX)); |
| 1650 id, | 1638 GrowableArray<Class*> classes; |
| 1651 receiver, | 1639 GrowableArray<Function*> targets; |
| 1652 field_name, | 1640 bool unique_target = true; |
| 1653 recv_reg, | 1641 { |
| 1654 value_reg); | 1642 const ICData& ic_data = node->ICDataAtId(id); |
| 1655 } else { | 1643 ASSERT(ic_data.NumberOfChecks() > 0); |
| 1656 UNIMPLEMENTED(); | 1644 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 1645 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1646 Class& cls = Class::ZoneHandle(); |
| 1647 Function& target = Function::ZoneHandle(); |
| 1648 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1649 classes.Add(&cls); |
| 1650 targets.Add(&target); |
| 1651 } |
| 1652 for (intptr_t i = 1; i < targets.length(); i++) { |
| 1653 if (targets[i - 1]->raw() != targets[i]->raw()) { |
| 1654 unique_target = false; |
| 1655 break; |
| 1656 } |
| 1657 } |
| 1657 } | 1658 } |
| 1659 // TODO(srdjan): sort classes/target by their invocation count. |
| 1660 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob( |
| 1661 node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget); |
| 1662 // Deoptimize if Smi, since they do not have setters. |
| 1663 if (NodeMayBeSmi(receiver)) { |
| 1664 __ testl(recv_reg, Immediate(kSmiTagMask)); |
| 1665 __ j(ZERO, deopt_blob->label()); |
| 1666 } |
| 1667 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); |
| 1668 // Initialize setter arguments, but leave the class and target fields NULL. |
| 1669 InstanceSetterArgs setter_args = |
| 1670 {NULL, NULL, &field_name, recv_reg, value_reg, id, node->token_index()}; |
| 1671 |
| 1672 if (unique_target) { |
| 1673 Label store_field; |
| 1674 for (intptr_t i = 0; i < classes.length(); i++) { |
| 1675 __ CompareObject(EBX, *classes[i]); |
| 1676 if (i == (classes.length() - 1)) { |
| 1677 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1678 } else { |
| 1679 __ j(EQUAL, &store_field); |
| 1680 } |
| 1681 } |
| 1682 __ Bind(&store_field); |
| 1683 setter_args.cls = classes[0]; |
| 1684 setter_args.target = targets[0]; |
| 1685 GenerateInstanceSetter(setter_args); |
| 1686 return; |
| 1687 } |
| 1688 // Targets are different. |
| 1689 Label done; |
| 1690 for (intptr_t i = 0; i < classes.length(); i++) { |
| 1691 setter_args.cls = classes[i]; |
| 1692 setter_args.target = targets[i]; |
| 1693 __ CompareObject(EBX, *classes[i]); |
| 1694 if (i == (classes.length() - 1)) { |
| 1695 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1696 GenerateInstanceSetter(setter_args); |
| 1697 } else { |
| 1698 Label next_check; |
| 1699 __ j(NOT_EQUAL, &next_check); |
| 1700 GenerateInstanceSetter(setter_args); |
| 1701 __ jmp(&done); |
| 1702 __ Bind(&next_check); |
| 1703 } |
| 1704 } |
| 1705 __ Bind(&done); |
| 1658 } | 1706 } |
| 1659 | 1707 |
| 1660 | 1708 |
| 1661 // The call to the instance setter implements the assignment to a field. | 1709 // The call to the instance setter implements the assignment to a field. |
| 1662 // The result of the assignment to a field is the value being stored. | 1710 // The result of the assignment to a field is the value being stored. |
| 1663 void OptimizingCodeGenerator::VisitInstanceSetterNode( | 1711 void OptimizingCodeGenerator::VisitInstanceSetterNode( |
| 1664 InstanceSetterNode* node) { | 1712 InstanceSetterNode* node) { |
| 1665 // TODO(srdjan): inline setters to different targets as well. | 1713 // TODO(srdjan): inline setters to different targets as well. |
| 1666 if (FLAG_enable_type_checks || | 1714 if (FLAG_enable_type_checks) { |
| 1667 !ICDataToSameInlineableInstanceSetter(node->ICDataAtId(node->id()))) { | |
| 1668 CodeGenerator::VisitInstanceSetterNode(node); | 1715 CodeGenerator::VisitInstanceSetterNode(node); |
| 1669 return; | 1716 return; |
| 1670 } | 1717 } |
| 1671 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); | 1718 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); |
| 1672 const ICData& ic_data = node->ICDataAtId(node->id()); | 1719 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1673 if (ic_data.NumberOfChecks() == 0) { | 1720 if (ic_data.NumberOfChecks() == 0) { |
| 1674 DeoptimizationBlob* deopt_blob = | 1721 DeoptimizationBlob* deopt_blob = |
| 1675 AddDeoptimizationBlob(node, EDX, EAX, kDeoptInstanceSetter); | 1722 AddDeoptimizationBlob(node, EDX, EAX, kDeoptInstanceSetter); |
| 1676 __ jmp(deopt_blob->label()); | 1723 __ jmp(deopt_blob->label()); |
| 1677 return; | 1724 return; |
| (...skipping 1065 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2743 void OptimizingCodeGenerator::VisitTryCatchNode(TryCatchNode* node) { | 2790 void OptimizingCodeGenerator::VisitTryCatchNode(TryCatchNode* node) { |
| 2744 // TODO(srdjan): Set classes for locals. | 2791 // TODO(srdjan): Set classes for locals. |
| 2745 classes_for_locals_->Clear(); | 2792 classes_for_locals_->Clear(); |
| 2746 CodeGenerator::VisitTryCatchNode(node); | 2793 CodeGenerator::VisitTryCatchNode(node); |
| 2747 } | 2794 } |
| 2748 | 2795 |
| 2749 | 2796 |
| 2750 } // namespace dart | 2797 } // namespace dart |
| 2751 | 2798 |
| 2752 #endif // defined TARGET_ARCH_IA32 | 2799 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |