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 |