| 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 |