Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/jit_optimizer.h" | 5 #include "vm/jit_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 2650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2661 new(Z) AssertAssignableInstr(call->token_pos(), | 2661 new(Z) AssertAssignableInstr(call->token_pos(), |
| 2662 new(Z) Value(left), | 2662 new(Z) Value(left), |
| 2663 new(Z) Value(type_args), | 2663 new(Z) Value(type_args), |
| 2664 type, | 2664 type, |
| 2665 Symbols::InTypeCast(), | 2665 Symbols::InTypeCast(), |
| 2666 call->deopt_id()); | 2666 call->deopt_id()); |
| 2667 ReplaceCall(call, assert_as); | 2667 ReplaceCall(call, assert_as); |
| 2668 } | 2668 } |
| 2669 | 2669 |
| 2670 | 2670 |
| 2671 static bool IsDenseCidRange(const ICData& unary_checks) { | |
|
Vyacheslav Egorov (Google)
2016/04/01 10:53:59
I am a bit concerned that we have two functions th
Florian Schneider
2016/04/01 15:58:43
Changed to use a single function CheckClassInstr::
| |
| 2672 if (unary_checks.GetReceiverClassIdAt(0) == kSmiCid) return false; | |
| 2673 intptr_t max = 0; | |
| 2674 intptr_t min = kIntptrMax; | |
| 2675 for (intptr_t i = 0; i < unary_checks.NumberOfChecks(); ++i) { | |
| 2676 intptr_t cid = unary_checks.GetCidAt(i); | |
| 2677 if (cid < min) min = cid; | |
| 2678 if (cid > max) max = cid; | |
| 2679 } | |
| 2680 return (max - min) < kBitsPerWord; | |
| 2681 } | |
| 2682 | |
| 2683 | |
| 2671 // Tries to optimize instance call by replacing it with a faster instruction | 2684 // Tries to optimize instance call by replacing it with a faster instruction |
| 2672 // (e.g, binary op, field load, ..). | 2685 // (e.g, binary op, field load, ..). |
| 2673 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2686 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2674 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | 2687 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { |
| 2675 return; | 2688 return; |
| 2676 } | 2689 } |
| 2677 const Token::Kind op_kind = instr->token_kind(); | 2690 const Token::Kind op_kind = instr->token_kind(); |
| 2678 | 2691 |
| 2679 // Type test is special as it always gets converted into inlined code. | 2692 // Type test is special as it always gets converted into inlined code. |
| 2680 if (Token::IsTypeTestOperator(op_kind)) { | 2693 if (Token::IsTypeTestOperator(op_kind)) { |
| 2681 ReplaceWithInstanceOf(instr); | 2694 ReplaceWithInstanceOf(instr); |
| 2682 return; | 2695 return; |
| 2683 } | 2696 } |
| 2684 | 2697 |
| 2685 if (Token::IsTypeCastOperator(op_kind)) { | 2698 if (Token::IsTypeCastOperator(op_kind)) { |
| 2686 ReplaceWithTypeCast(instr); | 2699 ReplaceWithTypeCast(instr); |
| 2687 return; | 2700 return; |
| 2688 } | 2701 } |
| 2689 | 2702 |
| 2690 const ICData& unary_checks = | 2703 const ICData& unary_checks = |
| 2691 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | 2704 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 2692 | 2705 |
| 2706 const bool is_dense = IsDenseCidRange(unary_checks); | |
| 2693 const intptr_t max_checks = (op_kind == Token::kEQ) | 2707 const intptr_t max_checks = (op_kind == Token::kEQ) |
| 2694 ? FLAG_max_equality_polymorphic_checks | 2708 ? FLAG_max_equality_polymorphic_checks |
| 2695 : FLAG_max_polymorphic_checks; | 2709 : FLAG_max_polymorphic_checks; |
| 2696 if ((unary_checks.NumberOfChecks() > max_checks) && | 2710 if ((unary_checks.NumberOfChecks() > max_checks) && |
| 2711 !is_dense && | |
| 2697 flow_graph()->InstanceCallNeedsClassCheck( | 2712 flow_graph()->InstanceCallNeedsClassCheck( |
| 2698 instr, RawFunction::kRegularFunction)) { | 2713 instr, RawFunction::kRegularFunction)) { |
| 2699 // Too many checks, it will be megamorphic which needs unary checks. | 2714 // Too many checks, it will be megamorphic which needs unary checks. |
| 2700 instr->set_ic_data(&unary_checks); | 2715 instr->set_ic_data(&unary_checks); |
| 2701 return; | 2716 return; |
| 2702 } | 2717 } |
| 2703 | 2718 |
| 2704 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | 2719 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2705 return; | 2720 return; |
| 2706 } | 2721 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2752 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); | 2767 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); |
| 2753 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { | 2768 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { |
| 2754 PolymorphicInstanceCallInstr* call = | 2769 PolymorphicInstanceCallInstr* call = |
| 2755 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2770 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 2756 /* call_with_checks = */ false); | 2771 /* call_with_checks = */ false); |
| 2757 instr->ReplaceWith(call, current_iterator()); | 2772 instr->ReplaceWith(call, current_iterator()); |
| 2758 return; | 2773 return; |
| 2759 } | 2774 } |
| 2760 } | 2775 } |
| 2761 | 2776 |
| 2762 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 2777 if ((unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) || |
| 2778 (has_one_target && is_dense)) { | |
| 2763 bool call_with_checks; | 2779 bool call_with_checks; |
| 2764 if (has_one_target && FLAG_polymorphic_with_deopt) { | 2780 if (has_one_target && FLAG_polymorphic_with_deopt) { |
| 2765 // Type propagation has not run yet, we cannot eliminate the check. | 2781 // Type propagation has not run yet, we cannot eliminate the check. |
| 2766 AddReceiverCheck(instr); | 2782 AddReceiverCheck(instr); |
| 2767 // Call can still deoptimize, do not detach environment from instr. | 2783 // Call can still deoptimize, do not detach environment from instr. |
| 2768 call_with_checks = false; | 2784 call_with_checks = false; |
| 2769 } else { | 2785 } else { |
| 2770 call_with_checks = true; | 2786 call_with_checks = true; |
| 2771 } | 2787 } |
| 2772 PolymorphicInstanceCallInstr* call = | 2788 PolymorphicInstanceCallInstr* call = |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3122 | 3138 |
| 3123 // Discard the environment from the original instruction because the store | 3139 // Discard the environment from the original instruction because the store |
| 3124 // can't deoptimize. | 3140 // can't deoptimize. |
| 3125 instr->RemoveEnvironment(); | 3141 instr->RemoveEnvironment(); |
| 3126 ReplaceCall(instr, store); | 3142 ReplaceCall(instr, store); |
| 3127 return true; | 3143 return true; |
| 3128 } | 3144 } |
| 3129 | 3145 |
| 3130 | 3146 |
| 3131 } // namespace dart | 3147 } // namespace dart |
| OLD | NEW |