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/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 "Print constant propagation and useless code elimination."); | 34 "Print constant propagation and useless code elimination."); |
35 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 35 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
36 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 36 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
37 DEFINE_FLAG(bool, truncating_left_shift, true, | 37 DEFINE_FLAG(bool, truncating_left_shift, true, |
38 "Optimize left shift to truncate if possible"); | 38 "Optimize left shift to truncate if possible"); |
39 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 39 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
40 DEFINE_FLAG(bool, trace_load_optimization, false, | 40 DEFINE_FLAG(bool, trace_load_optimization, false, |
41 "Print live sets for load optimization pass."); | 41 "Print live sets for load optimization pass."); |
42 DEFINE_FLAG(bool, enable_simd_inline, true, | 42 DEFINE_FLAG(bool, enable_simd_inline, true, |
43 "Enable inlining of SIMD related method calls."); | 43 "Enable inlining of SIMD related method calls."); |
| 44 DEFINE_FLAG(int, getter_setter_ratio, 10, |
| 45 "Ratio of getter/setter usage used for double field unboxing heuristics"); |
44 DECLARE_FLAG(bool, eliminate_type_checks); | 46 DECLARE_FLAG(bool, eliminate_type_checks); |
45 DECLARE_FLAG(bool, enable_type_checks); | 47 DECLARE_FLAG(bool, enable_type_checks); |
46 DECLARE_FLAG(bool, trace_type_check_elimination); | 48 DECLARE_FLAG(bool, trace_type_check_elimination); |
47 | 49 |
48 | 50 |
49 static bool ShouldInlineSimd() { | 51 static bool ShouldInlineSimd() { |
50 #if defined(TARGET_ARCH_MIPS) | 52 #if defined(TARGET_ARCH_MIPS) |
51 return false; | 53 return false; |
52 #elif defined(TARGET_ARCH_ARM) | 54 #elif defined(TARGET_ARCH_ARM) |
53 return CPUFeatures::neon_supported() && FLAG_enable_simd_inline; | 55 return CPUFeatures::neon_supported() && FLAG_enable_simd_inline; |
(...skipping 3470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3524 ASSERT((cid == kOneByteStringCid) || (cid == kTwoByteStringCid) || | 3526 ASSERT((cid == kOneByteStringCid) || (cid == kTwoByteStringCid) || |
3525 (cid == kExternalOneByteStringCid) || | 3527 (cid == kExternalOneByteStringCid) || |
3526 (cid == kGrowableObjectArrayCid) || | 3528 (cid == kGrowableObjectArrayCid) || |
3527 (cid == kImmutableArrayCid) || (cid == kArrayCid)); | 3529 (cid == kImmutableArrayCid) || (cid == kArrayCid)); |
3528 ConstantInstr* cid_instr = new ConstantInstr(Smi::Handle(Smi::New(cid))); | 3530 ConstantInstr* cid_instr = new ConstantInstr(Smi::Handle(Smi::New(cid))); |
3529 ReplaceCall(call, cid_instr); | 3531 ReplaceCall(call, cid_instr); |
3530 } | 3532 } |
3531 } | 3533 } |
3532 | 3534 |
3533 | 3535 |
| 3536 void FlowGraphOptimizer::VisitStoreInstanceField( |
| 3537 StoreInstanceFieldInstr* instr) { |
| 3538 if (instr->IsUnboxedStore()) { |
| 3539 ASSERT(instr->is_initialization_); |
| 3540 // Determine if this field should be unboxed based on the usage of getter |
| 3541 // and setter functions: The heuristic requires that the setter has a |
| 3542 // usage count of at least 1/kGetterSetterRatio of the getter usage count. |
| 3543 // This is to avoid unboxing fields where the setter is never or rarely |
| 3544 // executed. |
| 3545 const Field& field = Field::ZoneHandle(instr->field().raw()); |
| 3546 const String& field_name = String::Handle(field.name()); |
| 3547 class Class& owner = Class::Handle(field.owner()); |
| 3548 const Function& getter = |
| 3549 Function::Handle(owner.LookupGetterFunction(field_name)); |
| 3550 const Function& setter = |
| 3551 Function::Handle(owner.LookupSetterFunction(field_name)); |
| 3552 bool result = !getter.IsNull() |
| 3553 && !setter.IsNull() |
| 3554 && (setter.usage_counter() > 0) |
| 3555 && (FLAG_getter_setter_ratio * setter.usage_counter() > |
| 3556 getter.usage_counter()); |
| 3557 if (!result) { |
| 3558 field.set_is_unboxing_candidate(false); |
| 3559 field.DeoptimizeDependentCode(); |
| 3560 } else { |
| 3561 FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field); |
| 3562 } |
| 3563 } |
| 3564 } |
| 3565 |
| 3566 |
3534 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 3567 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
3535 const ICData& unary_ic_data) { | 3568 const ICData& unary_ic_data) { |
3536 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 3569 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
3537 (unary_ic_data.num_args_tested() == 1)); | 3570 (unary_ic_data.num_args_tested() == 1)); |
3538 if (FLAG_enable_type_checks) { | 3571 if (FLAG_enable_type_checks) { |
3539 // Checked mode setters are inlined like normal methods by conventional | 3572 // Checked mode setters are inlined like normal methods by conventional |
3540 // inlining. | 3573 // inlining. |
3541 return false; | 3574 return false; |
3542 } | 3575 } |
3543 | 3576 |
(...skipping 10 matching lines...) Expand all Loading... |
3554 Function& target = Function::Handle(); | 3587 Function& target = Function::Handle(); |
3555 intptr_t class_id; | 3588 intptr_t class_id; |
3556 unary_ic_data.GetOneClassCheckAt(0, &class_id, &target); | 3589 unary_ic_data.GetOneClassCheckAt(0, &class_id, &target); |
3557 if (target.kind() != RawFunction::kImplicitSetter) { | 3590 if (target.kind() != RawFunction::kImplicitSetter) { |
3558 // Non-implicit setter are inlined like normal method calls. | 3591 // Non-implicit setter are inlined like normal method calls. |
3559 return false; | 3592 return false; |
3560 } | 3593 } |
3561 // Inline implicit instance setter. | 3594 // Inline implicit instance setter. |
3562 const String& field_name = | 3595 const String& field_name = |
3563 String::Handle(Field::NameFromSetter(instr->function_name())); | 3596 String::Handle(Field::NameFromSetter(instr->function_name())); |
3564 const Field& field = Field::Handle(GetField(class_id, field_name)); | 3597 const Field& field = Field::ZoneHandle(GetField(class_id, field_name)); |
3565 ASSERT(!field.IsNull()); | 3598 ASSERT(!field.IsNull()); |
3566 | 3599 |
3567 if (InstanceCallNeedsClassCheck(instr)) { | 3600 if (InstanceCallNeedsClassCheck(instr)) { |
3568 AddReceiverCheck(instr); | 3601 AddReceiverCheck(instr); |
3569 } | 3602 } |
3570 StoreBarrierType needs_store_barrier = kEmitStoreBarrier; | 3603 StoreBarrierType needs_store_barrier = kEmitStoreBarrier; |
3571 if (ArgIsAlways(kSmiCid, *instr->ic_data(), 1)) { | 3604 if (ArgIsAlways(kSmiCid, *instr->ic_data(), 1)) { |
3572 InsertBefore(instr, | 3605 InsertBefore(instr, |
3573 new CheckSmiInstr(new Value(instr->ArgumentAt(1)), | 3606 new CheckSmiInstr(new Value(instr->ArgumentAt(1)), |
3574 instr->deopt_id()), | 3607 instr->deopt_id()), |
(...skipping 10 matching lines...) Expand all Loading... |
3585 instr->env(), | 3618 instr->env(), |
3586 Definition::kEffect); | 3619 Definition::kEffect); |
3587 } | 3620 } |
3588 | 3621 |
3589 // Field guard was detached. | 3622 // Field guard was detached. |
3590 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( | 3623 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( |
3591 field, | 3624 field, |
3592 new Value(instr->ArgumentAt(0)), | 3625 new Value(instr->ArgumentAt(0)), |
3593 new Value(instr->ArgumentAt(1)), | 3626 new Value(instr->ArgumentAt(1)), |
3594 needs_store_barrier); | 3627 needs_store_barrier); |
| 3628 |
| 3629 if (store->IsUnboxedStore()) { |
| 3630 FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field); |
| 3631 } |
| 3632 |
3595 // Discard the environment from the original instruction because the store | 3633 // Discard the environment from the original instruction because the store |
3596 // can't deoptimize. | 3634 // can't deoptimize. |
3597 instr->RemoveEnvironment(); | 3635 instr->RemoveEnvironment(); |
3598 ReplaceCall(instr, store); | 3636 ReplaceCall(instr, store); |
3599 return true; | 3637 return true; |
3600 } | 3638 } |
3601 | 3639 |
3602 | 3640 |
3603 // Range analysis for smi values. | 3641 // Range analysis for smi values. |
3604 class RangeAnalysis : public ValueObject { | 3642 class RangeAnalysis : public ValueObject { |
(...skipping 4470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8075 } | 8113 } |
8076 | 8114 |
8077 // Insert materializations at environment uses. | 8115 // Insert materializations at environment uses. |
8078 for (intptr_t i = 0; i < exits.length(); i++) { | 8116 for (intptr_t i = 0; i < exits.length(); i++) { |
8079 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8117 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
8080 } | 8118 } |
8081 } | 8119 } |
8082 | 8120 |
8083 | 8121 |
8084 } // namespace dart | 8122 } // namespace dart |
OLD | NEW |