| 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 #ifndef DART_PRECOMPILED_RUNTIME | 4 #ifndef DART_PRECOMPILED_RUNTIME |
| 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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 return false; | 192 return false; |
| 193 } | 193 } |
| 194 | 194 |
| 195 | 195 |
| 196 void JitOptimizer::SpecializePolymorphicInstanceCall( | 196 void JitOptimizer::SpecializePolymorphicInstanceCall( |
| 197 PolymorphicInstanceCallInstr* call) { | 197 PolymorphicInstanceCallInstr* call) { |
| 198 if (!FLAG_polymorphic_with_deopt) { | 198 if (!FLAG_polymorphic_with_deopt) { |
| 199 // Specialization adds receiver checks which can lead to deoptimization. | 199 // Specialization adds receiver checks which can lead to deoptimization. |
| 200 return; | 200 return; |
| 201 } | 201 } |
| 202 if (!call->with_checks()) { | |
| 203 return; // Already specialized. | |
| 204 } | |
| 205 | 202 |
| 206 const intptr_t receiver_cid = | 203 const intptr_t receiver_cid = |
| 207 call->PushArgumentAt(0)->value()->Type()->ToCid(); | 204 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 208 if (receiver_cid == kDynamicCid) { | 205 if (receiver_cid == kDynamicCid) { |
| 209 return; // No information about receiver was infered. | 206 return; // No information about receiver was infered. |
| 210 } | 207 } |
| 211 | 208 |
| 212 const ICData& ic_data = *call->instance_call()->ic_data(); | 209 const ICData& ic_data = *call->instance_call()->ic_data(); |
| 213 | 210 |
| 214 const CallTargets* targets = | 211 const CallTargets* targets = |
| 215 FlowGraphCompiler::ResolveCallTargetsForReceiverCid( | 212 FlowGraphCompiler::ResolveCallTargetsForReceiverCid( |
| 216 receiver_cid, String::Handle(zone(), ic_data.target_name()), | 213 receiver_cid, String::Handle(zone(), ic_data.target_name()), |
| 217 Array::Handle(zone(), ic_data.arguments_descriptor())); | 214 Array::Handle(zone(), ic_data.arguments_descriptor())); |
| 218 if (targets == NULL) { | 215 if (targets == NULL) { |
| 219 // No specialization. | 216 // No specialization. |
| 220 return; | 217 return; |
| 221 } | 218 } |
| 222 | 219 |
| 223 const bool with_checks = false; | 220 ASSERT(targets->HasSingleTarget()); |
| 224 const bool complete = false; | 221 const Function& target = targets->FirstTarget(); |
| 225 PolymorphicInstanceCallInstr* specialized = | 222 StaticCallInstr* specialized = StaticCallInstr::FromCall(Z, call, target); |
| 226 new (Z) PolymorphicInstanceCallInstr(call->instance_call(), *targets, | |
| 227 with_checks, complete); | |
| 228 call->ReplaceWith(specialized, current_iterator()); | 223 call->ReplaceWith(specialized, current_iterator()); |
| 229 } | 224 } |
| 230 | 225 |
| 231 | 226 |
| 232 static bool ClassIdIsOneOf(intptr_t class_id, | 227 static bool ClassIdIsOneOf(intptr_t class_id, |
| 233 const GrowableArray<intptr_t>& class_ids) { | 228 const GrowableArray<intptr_t>& class_ids) { |
| 234 for (intptr_t i = 0; i < class_ids.length(); i++) { | 229 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 235 ASSERT(class_ids[i] != kIllegalCid); | 230 ASSERT(class_ids[i] != kIllegalCid); |
| 236 if (class_ids[i] == class_id) { | 231 if (class_ids[i] == class_id) { |
| 237 return true; | 232 return true; |
| (...skipping 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1524 const bool polymorphic_target = | 1519 const bool polymorphic_target = |
| 1525 MethodRecognizer::PolymorphicTarget(target); | 1520 MethodRecognizer::PolymorphicTarget(target); |
| 1526 has_one_target = !polymorphic_target; | 1521 has_one_target = !polymorphic_target; |
| 1527 } | 1522 } |
| 1528 } | 1523 } |
| 1529 | 1524 |
| 1530 if (has_one_target) { | 1525 if (has_one_target) { |
| 1531 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); | 1526 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
| 1532 const RawFunction::Kind function_kind = target.kind(); | 1527 const RawFunction::Kind function_kind = target.kind(); |
| 1533 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { | 1528 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { |
| 1534 PolymorphicInstanceCallInstr* call = | 1529 StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target); |
| 1535 new (Z) PolymorphicInstanceCallInstr(instr, *targets, | |
| 1536 /* call_with_checks = */ false, | |
| 1537 /* complete = */ false); | |
| 1538 instr->ReplaceWith(call, current_iterator()); | 1530 instr->ReplaceWith(call, current_iterator()); |
| 1539 return; | 1531 return; |
| 1540 } | 1532 } |
| 1541 } | 1533 } |
| 1542 | 1534 |
| 1543 // If there is only one target we can make this into a deopting class check, | 1535 // If there is only one target we can make this into a deopting class check, |
| 1544 // followed by a call instruction that does not check the class of the | 1536 // followed by a call instruction that does not check the class of the |
| 1545 // receiver. This enables a lot of optimizations because after the class | 1537 // receiver. This enables a lot of optimizations because after the class |
| 1546 // check we can probably inline the call and not worry about side effects. | 1538 // check we can probably inline the call and not worry about side effects. |
| 1547 // However, this can fall down if new receiver classes arrive at this call | 1539 // However, this can fall down if new receiver classes arrive at this call |
| 1548 // site after we generated optimized code. This causes a deopt, and after a | 1540 // site after we generated optimized code. This causes a deopt, and after a |
| 1549 // few deopts we won't optimize this function any more at all. Therefore for | 1541 // few deopts we won't optimize this function any more at all. Therefore for |
| 1550 // very polymorphic sites we don't make this optimization, keeping it as a | 1542 // very polymorphic sites we don't make this optimization, keeping it as a |
| 1551 // regular checked PolymorphicInstanceCall, which falls back to the slow but | 1543 // regular checked PolymorphicInstanceCall, which falls back to the slow but |
| 1552 // non-deopting megamorphic call stub when it sees new receiver classes. | 1544 // non-deopting megamorphic call stub when it sees new receiver classes. |
| 1553 bool call_with_checks; | |
| 1554 if (has_one_target && FLAG_polymorphic_with_deopt && | 1545 if (has_one_target && FLAG_polymorphic_with_deopt && |
| 1555 (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) || | 1546 (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) || |
| 1556 unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | 1547 unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
| 1557 // Type propagation has not run yet, we cannot eliminate the check. | 1548 // Type propagation has not run yet, we cannot eliminate the check. |
| 1558 // TODO(erikcorry): The receiver check should use the off-heap targets | 1549 // TODO(erikcorry): The receiver check should use the off-heap targets |
| 1559 // array, not the IC array. | 1550 // array, not the IC array. |
| 1560 AddReceiverCheck(instr); | 1551 AddReceiverCheck(instr); |
| 1561 // Call can still deoptimize, do not detach environment from instr. | 1552 // Call can still deoptimize, do not detach environment from instr. |
| 1562 call_with_checks = false; | 1553 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
| 1554 StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target); |
| 1555 instr->ReplaceWith(call, current_iterator()); |
| 1563 } else { | 1556 } else { |
| 1564 call_with_checks = true; | 1557 PolymorphicInstanceCallInstr* call = |
| 1558 new (Z) PolymorphicInstanceCallInstr(instr, *targets, |
| 1559 /* complete = */ false); |
| 1560 instr->ReplaceWith(call, current_iterator()); |
| 1565 } | 1561 } |
| 1566 PolymorphicInstanceCallInstr* call = | |
| 1567 new (Z) PolymorphicInstanceCallInstr(instr, *targets, call_with_checks, | |
| 1568 /* complete = */ false); | |
| 1569 instr->ReplaceWith(call, current_iterator()); | |
| 1570 } | 1562 } |
| 1571 | 1563 |
| 1572 | 1564 |
| 1573 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1565 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 1574 MethodRecognizer::Kind recognized_kind = | 1566 MethodRecognizer::Kind recognized_kind = |
| 1575 MethodRecognizer::RecognizeKind(call->function()); | 1567 MethodRecognizer::RecognizeKind(call->function()); |
| 1576 switch (recognized_kind) { | 1568 switch (recognized_kind) { |
| 1577 case MethodRecognizer::kObjectConstructor: | 1569 case MethodRecognizer::kObjectConstructor: |
| 1578 case MethodRecognizer::kObjectArrayAllocate: | 1570 case MethodRecognizer::kObjectArrayAllocate: |
| 1579 case MethodRecognizer::kFloat32x4Zero: | 1571 case MethodRecognizer::kFloat32x4Zero: |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1813 // Discard the environment from the original instruction because the store | 1805 // Discard the environment from the original instruction because the store |
| 1814 // can't deoptimize. | 1806 // can't deoptimize. |
| 1815 instr->RemoveEnvironment(); | 1807 instr->RemoveEnvironment(); |
| 1816 ReplaceCall(instr, store); | 1808 ReplaceCall(instr, store); |
| 1817 return true; | 1809 return true; |
| 1818 } | 1810 } |
| 1819 | 1811 |
| 1820 | 1812 |
| 1821 } // namespace dart | 1813 } // namespace dart |
| 1822 #endif // DART_PRECOMPILED_RUNTIME | 1814 #endif // DART_PRECOMPILED_RUNTIME |
| OLD | NEW |