| 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/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 2310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2321 } | 2321 } |
| 2322 return Field::null(); | 2322 return Field::null(); |
| 2323 } | 2323 } |
| 2324 | 2324 |
| 2325 | 2325 |
| 2326 // Use CHA to determine if the call needs a class check: if the callee's | 2326 // Use CHA to determine if the call needs a class check: if the callee's |
| 2327 // receiver is the same as the caller's receiver and there are no overriden | 2327 // receiver is the same as the caller's receiver and there are no overriden |
| 2328 // callee functions, then no class check is needed. | 2328 // callee functions, then no class check is needed. |
| 2329 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( | 2329 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( |
| 2330 InstanceCallInstr* call, RawFunction::Kind kind) const { | 2330 InstanceCallInstr* call, RawFunction::Kind kind) const { |
| 2331 if (!FLAG_use_cha_deopt) { | 2331 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { |
| 2332 // Even if class or function are private, lazy class finalization | 2332 // Even if class or function are private, lazy class finalization |
| 2333 // may later add overriding methods. | 2333 // may later add overriding methods. |
| 2334 return true; | 2334 return true; |
| 2335 } | 2335 } |
| 2336 Definition* callee_receiver = call->ArgumentAt(0); | 2336 Definition* callee_receiver = call->ArgumentAt(0); |
| 2337 ASSERT(callee_receiver != NULL); | 2337 ASSERT(callee_receiver != NULL); |
| 2338 const Function& function = flow_graph_->function(); | 2338 const Function& function = flow_graph_->function(); |
| 2339 if (function.IsDynamicFunction() && | 2339 if (function.IsDynamicFunction() && |
| 2340 callee_receiver->IsParameter() && | 2340 callee_receiver->IsParameter() && |
| 2341 (callee_receiver->AsParameter()->index() == 0)) { | 2341 (callee_receiver->AsParameter()->index() == 0)) { |
| (...skipping 1694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4036 if (type_class.IsSignatureClass()) return false; | 4036 if (type_class.IsSignatureClass()) return false; |
| 4037 // Could be an interface check? | 4037 // Could be an interface check? |
| 4038 if (CHA::IsImplemented(type_class)) return false; | 4038 if (CHA::IsImplemented(type_class)) return false; |
| 4039 // Check if there are subclasses. | 4039 // Check if there are subclasses. |
| 4040 if (CHA::HasSubclasses(type_class)) { | 4040 if (CHA::HasSubclasses(type_class)) { |
| 4041 return false; | 4041 return false; |
| 4042 } | 4042 } |
| 4043 | 4043 |
| 4044 // Private classes cannot be subclassed by later loaded libs. | 4044 // Private classes cannot be subclassed by later loaded libs. |
| 4045 if (!type_class.IsPrivate()) { | 4045 if (!type_class.IsPrivate()) { |
| 4046 if (FLAG_use_cha_deopt) { | 4046 if (FLAG_use_cha_deopt || isolate()->all_classes_finalized()) { |
| 4047 if (FLAG_trace_cha) { | 4047 if (FLAG_trace_cha) { |
| 4048 THR_Print(" **(CHA) Typecheck as class equality since no " | 4048 THR_Print(" **(CHA) Typecheck as class equality since no " |
| 4049 "subclasses: %s\n", | 4049 "subclasses: %s\n", |
| 4050 type_class.ToCString()); | 4050 type_class.ToCString()); |
| 4051 } | 4051 } |
| 4052 thread()->cha()->AddToLeafClasses(type_class); | 4052 if (FLAG_use_cha_deopt) { |
| 4053 thread()->cha()->AddToLeafClasses(type_class); |
| 4054 } |
| 4053 } else { | 4055 } else { |
| 4054 return false; | 4056 return false; |
| 4055 } | 4057 } |
| 4056 } | 4058 } |
| 4057 const intptr_t num_type_args = type_class.NumTypeArguments(); | 4059 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 4058 if (num_type_args > 0) { | 4060 if (num_type_args > 0) { |
| 4059 // Only raw types can be directly compared, thus disregarding type | 4061 // Only raw types can be directly compared, thus disregarding type |
| 4060 // arguments. | 4062 // arguments. |
| 4061 const intptr_t num_type_params = type_class.NumTypeParameters(); | 4063 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 4062 const intptr_t from_index = num_type_args - num_type_params; | 4064 const intptr_t from_index = num_type_args - num_type_params; |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4301 call->deopt_id()); | 4303 call->deopt_id()); |
| 4302 ReplaceCall(call, assert_as); | 4304 ReplaceCall(call, assert_as); |
| 4303 } | 4305 } |
| 4304 | 4306 |
| 4305 | 4307 |
| 4306 // Special optimizations when running in --noopt mode. | 4308 // Special optimizations when running in --noopt mode. |
| 4307 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { | 4309 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { |
| 4308 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 4310 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 4309 // deoptimize. | 4311 // deoptimize. |
| 4310 const Token::Kind op_kind = instr->token_kind(); | 4312 const Token::Kind op_kind = instr->token_kind(); |
| 4313 if ((op_kind == Token::kGET) && |
| 4314 TryInlineInstanceGetter(instr, false /* no checks allowed */)) { |
| 4315 return; |
| 4316 } |
| 4317 const ICData& unary_checks = |
| 4318 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 4319 if ((instr->ic_data()->NumberOfChecks() > 0) && |
| 4320 (op_kind == Token::kSET) && |
| 4321 TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) { |
| 4322 return; |
| 4323 } |
| 4311 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) { | 4324 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) { |
| 4312 const ICData& unary_checks = | 4325 ASSERT(!FLAG_polymorphic_with_deopt); |
| 4313 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | 4326 // OK to use checks with PolymorphicInstanceCallInstr since no |
| 4314 | 4327 // deoptimization is allowed. |
| 4315 PolymorphicInstanceCallInstr* call = | 4328 PolymorphicInstanceCallInstr* call = |
| 4316 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 4329 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 4317 true /* call_with_checks*/); | 4330 true /* call_with_checks */); |
| 4318 instr->ReplaceWith(call, current_iterator()); | 4331 instr->ReplaceWith(call, current_iterator()); |
| 4319 return; | 4332 return; |
| 4320 } | 4333 } |
| 4321 | 4334 |
| 4322 // Type test is special as it always gets converted into inlined code. | 4335 // Type test is special as it always gets converted into inlined code. |
| 4323 if (Token::IsTypeTestOperator(op_kind)) { | 4336 if (Token::IsTypeTestOperator(op_kind)) { |
| 4324 ReplaceWithInstanceOf(instr); | 4337 ReplaceWithInstanceOf(instr); |
| 4325 return; | 4338 return; |
| 4326 } | 4339 } |
| 4327 if (Token::IsTypeCastOperator(op_kind)) { | 4340 if (Token::IsTypeCastOperator(op_kind)) { |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4685 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 4698 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
| 4686 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 4699 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
| 4687 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 4700 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
| 4688 if (!instr->can_pack_into_smi()) | 4701 if (!instr->can_pack_into_smi()) |
| 4689 instr->set_representation(kUnboxedMint); | 4702 instr->set_representation(kUnboxedMint); |
| 4690 #endif | 4703 #endif |
| 4691 } | 4704 } |
| 4692 | 4705 |
| 4693 | 4706 |
| 4694 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 4707 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
| 4695 const ICData& unary_ic_data) { | 4708 const ICData& unary_ic_data, |
| 4709 bool allow_checks) { |
| 4696 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 4710 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
| 4697 (unary_ic_data.NumArgsTested() == 1)); | 4711 (unary_ic_data.NumArgsTested() == 1)); |
| 4698 if (I->flags().type_checks()) { | 4712 if (I->flags().type_checks()) { |
| 4699 // Checked mode setters are inlined like normal methods by conventional | 4713 // Checked mode setters are inlined like normal methods by conventional |
| 4700 // inlining. | 4714 // inlining. |
| 4701 return false; | 4715 return false; |
| 4702 } | 4716 } |
| 4703 | 4717 |
| 4704 ASSERT(instr->HasICData()); | 4718 ASSERT(instr->HasICData()); |
| 4705 if (unary_ic_data.NumberOfChecks() == 0) { | 4719 if (unary_ic_data.NumberOfChecks() == 0) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4719 return false; | 4733 return false; |
| 4720 } | 4734 } |
| 4721 // Inline implicit instance setter. | 4735 // Inline implicit instance setter. |
| 4722 const String& field_name = | 4736 const String& field_name = |
| 4723 String::Handle(Z, Field::NameFromSetter(instr->function_name())); | 4737 String::Handle(Z, Field::NameFromSetter(instr->function_name())); |
| 4724 const Field& field = | 4738 const Field& field = |
| 4725 Field::ZoneHandle(Z, GetField(class_id, field_name)); | 4739 Field::ZoneHandle(Z, GetField(class_id, field_name)); |
| 4726 ASSERT(!field.IsNull()); | 4740 ASSERT(!field.IsNull()); |
| 4727 | 4741 |
| 4728 if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) { | 4742 if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) { |
| 4743 if (!allow_checks) { |
| 4744 return false; |
| 4745 } |
| 4729 AddReceiverCheck(instr); | 4746 AddReceiverCheck(instr); |
| 4730 } | 4747 } |
| 4731 if (field.guarded_cid() != kDynamicCid) { | 4748 if (field.guarded_cid() != kDynamicCid) { |
| 4749 if (!allow_checks) { |
| 4750 return false; |
| 4751 } |
| 4732 InsertBefore(instr, | 4752 InsertBefore(instr, |
| 4733 new(Z) GuardFieldClassInstr( | 4753 new(Z) GuardFieldClassInstr( |
| 4734 new(Z) Value(instr->ArgumentAt(1)), | 4754 new(Z) Value(instr->ArgumentAt(1)), |
| 4735 field, | 4755 field, |
| 4736 instr->deopt_id()), | 4756 instr->deopt_id()), |
| 4737 instr->env(), | 4757 instr->env(), |
| 4738 FlowGraph::kEffect); | 4758 FlowGraph::kEffect); |
| 4739 } | 4759 } |
| 4740 | 4760 |
| 4741 if (field.needs_length_check()) { | 4761 if (field.needs_length_check()) { |
| 4762 if (!allow_checks) { |
| 4763 return false; |
| 4764 } |
| 4742 InsertBefore(instr, | 4765 InsertBefore(instr, |
| 4743 new(Z) GuardFieldLengthInstr( | 4766 new(Z) GuardFieldLengthInstr( |
| 4744 new(Z) Value(instr->ArgumentAt(1)), | 4767 new(Z) Value(instr->ArgumentAt(1)), |
| 4745 field, | 4768 field, |
| 4746 instr->deopt_id()), | 4769 instr->deopt_id()), |
| 4747 instr->env(), | 4770 instr->env(), |
| 4748 FlowGraph::kEffect); | 4771 FlowGraph::kEffect); |
| 4749 } | 4772 } |
| 4750 | 4773 |
| 4751 // Field guard was detached. | 4774 // Field guard was detached. |
| (...skipping 4040 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8792 | 8815 |
| 8793 // Insert materializations at environment uses. | 8816 // Insert materializations at environment uses. |
| 8794 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 8817 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 8795 CreateMaterializationAt( | 8818 CreateMaterializationAt( |
| 8796 exits_collector_.exits()[i], alloc, *slots); | 8819 exits_collector_.exits()[i], alloc, *slots); |
| 8797 } | 8820 } |
| 8798 } | 8821 } |
| 8799 | 8822 |
| 8800 | 8823 |
| 8801 } // namespace dart | 8824 } // namespace dart |
| OLD | NEW |