| 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 1265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1276 } else { | 1276 } else { |
| 1277 return field.raw(); | 1277 return field.raw(); |
| 1278 } | 1278 } |
| 1279 } | 1279 } |
| 1280 cls = cls.SuperClass(); | 1280 cls = cls.SuperClass(); |
| 1281 } | 1281 } |
| 1282 return Field::null(); | 1282 return Field::null(); |
| 1283 } | 1283 } |
| 1284 | 1284 |
| 1285 | 1285 |
| 1286 // Use CHA to determine if the call needs a class check: if the callee's | |
| 1287 // receiver is the same as the caller's receiver and there are no overriden | |
| 1288 // callee functions, then no class check is needed. | |
| 1289 bool JitOptimizer::InstanceCallNeedsClassCheck( | |
| 1290 InstanceCallInstr* call, RawFunction::Kind kind) const { | |
| 1291 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { | |
| 1292 // Even if class or function are private, lazy class finalization | |
| 1293 // may later add overriding methods. | |
| 1294 return true; | |
| 1295 } | |
| 1296 Definition* callee_receiver = call->ArgumentAt(0); | |
| 1297 ASSERT(callee_receiver != NULL); | |
| 1298 const Function& function = flow_graph_->function(); | |
| 1299 if (function.IsDynamicFunction() && | |
| 1300 callee_receiver->IsParameter() && | |
| 1301 (callee_receiver->AsParameter()->index() == 0)) { | |
| 1302 const String& name = (kind == RawFunction::kMethodExtractor) | |
| 1303 ? String::Handle(Z, Field::NameFromGetter(call->function_name())) | |
| 1304 : call->function_name(); | |
| 1305 const Class& cls = Class::Handle(Z, function.Owner()); | |
| 1306 if (!thread()->cha()->HasOverride(cls, name)) { | |
| 1307 if (FLAG_trace_cha) { | |
| 1308 THR_Print(" **(CHA) Instance call needs no check, " | |
| 1309 "no overrides of '%s' '%s'\n", | |
| 1310 name.ToCString(), cls.ToCString()); | |
| 1311 } | |
| 1312 thread()->cha()->AddToLeafClasses(cls); | |
| 1313 return false; | |
| 1314 } | |
| 1315 } | |
| 1316 return true; | |
| 1317 } | |
| 1318 | |
| 1319 | |
| 1320 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 1286 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
| 1321 ASSERT(call->HasICData()); | 1287 ASSERT(call->HasICData()); |
| 1322 const ICData& ic_data = *call->ic_data(); | 1288 const ICData& ic_data = *call->ic_data(); |
| 1323 ASSERT(ic_data.HasOneTarget()); | 1289 ASSERT(ic_data.HasOneTarget()); |
| 1324 GrowableArray<intptr_t> class_ids; | 1290 GrowableArray<intptr_t> class_ids; |
| 1325 ic_data.GetClassIdsAt(0, &class_ids); | 1291 ic_data.GetClassIdsAt(0, &class_ids); |
| 1326 ASSERT(class_ids.length() == 1); | 1292 ASSERT(class_ids.length() == 1); |
| 1327 // Inline implicit instance getter. | 1293 // Inline implicit instance getter. |
| 1328 const String& field_name = | 1294 const String& field_name = |
| 1329 String::Handle(Z, Field::NameFromGetter(call->function_name())); | 1295 String::Handle(Z, Field::NameFromGetter(call->function_name())); |
| 1330 const Field& field = | 1296 const Field& field = |
| 1331 Field::ZoneHandle(Z, GetField(class_ids[0], field_name)); | 1297 Field::ZoneHandle(Z, GetField(class_ids[0], field_name)); |
| 1332 ASSERT(!field.IsNull()); | 1298 ASSERT(!field.IsNull()); |
| 1333 | 1299 |
| 1334 if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) { | 1300 if (flow_graph()->InstanceCallNeedsClassCheck( |
| 1301 call, RawFunction::kImplicitGetter)) { |
| 1335 AddReceiverCheck(call); | 1302 AddReceiverCheck(call); |
| 1336 } | 1303 } |
| 1337 LoadFieldInstr* load = new(Z) LoadFieldInstr( | 1304 LoadFieldInstr* load = new(Z) LoadFieldInstr( |
| 1338 new(Z) Value(call->ArgumentAt(0)), | 1305 new(Z) Value(call->ArgumentAt(0)), |
| 1339 &field, | 1306 &field, |
| 1340 AbstractType::ZoneHandle(Z, field.type()), | 1307 AbstractType::ZoneHandle(Z, field.type()), |
| 1341 call->token_pos()); | 1308 call->token_pos()); |
| 1342 load->set_is_immutable(field.is_final()); | 1309 load->set_is_immutable(field.is_final()); |
| 1343 if (field.guarded_cid() != kIllegalCid) { | 1310 if (field.guarded_cid() != kIllegalCid) { |
| 1344 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) { | 1311 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) { |
| (...skipping 1375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2720 return; | 2687 return; |
| 2721 } | 2688 } |
| 2722 | 2689 |
| 2723 const ICData& unary_checks = | 2690 const ICData& unary_checks = |
| 2724 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | 2691 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 2725 | 2692 |
| 2726 const intptr_t max_checks = (op_kind == Token::kEQ) | 2693 const intptr_t max_checks = (op_kind == Token::kEQ) |
| 2727 ? FLAG_max_equality_polymorphic_checks | 2694 ? FLAG_max_equality_polymorphic_checks |
| 2728 : FLAG_max_polymorphic_checks; | 2695 : FLAG_max_polymorphic_checks; |
| 2729 if ((unary_checks.NumberOfChecks() > max_checks) && | 2696 if ((unary_checks.NumberOfChecks() > max_checks) && |
| 2730 InstanceCallNeedsClassCheck(instr, RawFunction::kRegularFunction)) { | 2697 flow_graph()->InstanceCallNeedsClassCheck( |
| 2698 instr, RawFunction::kRegularFunction)) { |
| 2731 // Too many checks, it will be megamorphic which needs unary checks. | 2699 // Too many checks, it will be megamorphic which needs unary checks. |
| 2732 instr->set_ic_data(&unary_checks); | 2700 instr->set_ic_data(&unary_checks); |
| 2733 return; | 2701 return; |
| 2734 } | 2702 } |
| 2735 | 2703 |
| 2736 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | 2704 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2737 return; | 2705 return; |
| 2738 } | 2706 } |
| 2739 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | 2707 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2740 return; | 2708 return; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2775 // we don't have one target. | 2743 // we don't have one target. |
| 2776 const Function& target = | 2744 const Function& target = |
| 2777 Function::Handle(Z, unary_checks.GetTargetAt(0)); | 2745 Function::Handle(Z, unary_checks.GetTargetAt(0)); |
| 2778 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); | 2746 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); |
| 2779 has_one_target = !polymorphic_target; | 2747 has_one_target = !polymorphic_target; |
| 2780 } | 2748 } |
| 2781 | 2749 |
| 2782 if (has_one_target) { | 2750 if (has_one_target) { |
| 2783 RawFunction::Kind function_kind = | 2751 RawFunction::Kind function_kind = |
| 2784 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); | 2752 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); |
| 2785 if (!InstanceCallNeedsClassCheck(instr, function_kind)) { | 2753 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { |
| 2786 PolymorphicInstanceCallInstr* call = | 2754 PolymorphicInstanceCallInstr* call = |
| 2787 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2755 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 2788 /* call_with_checks = */ false); | 2756 /* call_with_checks = */ false); |
| 2789 instr->ReplaceWith(call, current_iterator()); | 2757 instr->ReplaceWith(call, current_iterator()); |
| 2790 return; | 2758 return; |
| 2791 } | 2759 } |
| 2792 } | 2760 } |
| 2793 | 2761 |
| 2794 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 2762 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 2795 bool call_with_checks; | 2763 bool call_with_checks; |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3107 // Non-implicit setter are inlined like normal method calls. | 3075 // Non-implicit setter are inlined like normal method calls. |
| 3108 return false; | 3076 return false; |
| 3109 } | 3077 } |
| 3110 // Inline implicit instance setter. | 3078 // Inline implicit instance setter. |
| 3111 const String& field_name = | 3079 const String& field_name = |
| 3112 String::Handle(Z, Field::NameFromSetter(instr->function_name())); | 3080 String::Handle(Z, Field::NameFromSetter(instr->function_name())); |
| 3113 const Field& field = | 3081 const Field& field = |
| 3114 Field::ZoneHandle(Z, GetField(class_id, field_name)); | 3082 Field::ZoneHandle(Z, GetField(class_id, field_name)); |
| 3115 ASSERT(!field.IsNull()); | 3083 ASSERT(!field.IsNull()); |
| 3116 | 3084 |
| 3117 if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) { | 3085 if (flow_graph()->InstanceCallNeedsClassCheck( |
| 3086 instr, RawFunction::kImplicitSetter)) { |
| 3118 AddReceiverCheck(instr); | 3087 AddReceiverCheck(instr); |
| 3119 } | 3088 } |
| 3120 if (field.guarded_cid() != kDynamicCid) { | 3089 if (field.guarded_cid() != kDynamicCid) { |
| 3121 InsertBefore(instr, | 3090 InsertBefore(instr, |
| 3122 new(Z) GuardFieldClassInstr( | 3091 new(Z) GuardFieldClassInstr( |
| 3123 new(Z) Value(instr->ArgumentAt(1)), | 3092 new(Z) Value(instr->ArgumentAt(1)), |
| 3124 field, | 3093 field, |
| 3125 instr->deopt_id()), | 3094 instr->deopt_id()), |
| 3126 instr->env(), | 3095 instr->env(), |
| 3127 FlowGraph::kEffect); | 3096 FlowGraph::kEffect); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3151 | 3120 |
| 3152 // Discard the environment from the original instruction because the store | 3121 // Discard the environment from the original instruction because the store |
| 3153 // can't deoptimize. | 3122 // can't deoptimize. |
| 3154 instr->RemoveEnvironment(); | 3123 instr->RemoveEnvironment(); |
| 3155 ReplaceCall(instr, store); | 3124 ReplaceCall(instr, store); |
| 3156 return true; | 3125 return true; |
| 3157 } | 3126 } |
| 3158 | 3127 |
| 3159 | 3128 |
| 3160 } // namespace dart | 3129 } // namespace dart |
| OLD | NEW |