Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: runtime/vm/opt_code_generator_ia32.cc

Issue 8945002: Optimize instance setters for non-implicit-setters and for setters with multiple targets. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | tests/language/src/OptimizedSetterTest.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | tests/language/src/OptimizedSetterTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698