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()); |
Vyacheslav Egorov (Google)
2017/05/18 07:03:11
ditto: abstract this pattern into a function
| |
224 const bool complete = false; | 221 const Function& target = targets->FirstTarget(); |
225 PolymorphicInstanceCallInstr* specialized = | 222 ZoneGrowableArray<PushArgumentInstr*>* args = |
226 new (Z) PolymorphicInstanceCallInstr(call->instance_call(), *targets, | 223 new (Z) ZoneGrowableArray<PushArgumentInstr*>( |
227 with_checks, complete); | 224 call->instance_call()->ArgumentCount()); |
225 for (intptr_t i = 0; i < call->instance_call()->ArgumentCount(); i++) { | |
226 args->Add(call->instance_call()->PushArgumentAt(i)); | |
227 } | |
228 StaticCallInstr* specialized = new (Z) StaticCallInstr( | |
229 call->token_pos(), target, call->instance_call()->argument_names(), args, | |
230 call->deopt_id(), call->CallCount()); | |
228 call->ReplaceWith(specialized, current_iterator()); | 231 call->ReplaceWith(specialized, current_iterator()); |
229 } | 232 } |
230 | 233 |
231 | 234 |
232 static bool ClassIdIsOneOf(intptr_t class_id, | 235 static bool ClassIdIsOneOf(intptr_t class_id, |
233 const GrowableArray<intptr_t>& class_ids) { | 236 const GrowableArray<intptr_t>& class_ids) { |
234 for (intptr_t i = 0; i < class_ids.length(); i++) { | 237 for (intptr_t i = 0; i < class_ids.length(); i++) { |
235 ASSERT(class_ids[i] != kIllegalCid); | 238 ASSERT(class_ids[i] != kIllegalCid); |
236 if (class_ids[i] == class_id) { | 239 if (class_ids[i] == class_id) { |
237 return true; | 240 return true; |
(...skipping 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1524 const bool polymorphic_target = | 1527 const bool polymorphic_target = |
1525 MethodRecognizer::PolymorphicTarget(target); | 1528 MethodRecognizer::PolymorphicTarget(target); |
1526 has_one_target = !polymorphic_target; | 1529 has_one_target = !polymorphic_target; |
1527 } | 1530 } |
1528 } | 1531 } |
1529 | 1532 |
1530 if (has_one_target) { | 1533 if (has_one_target) { |
1531 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); | 1534 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
1532 const RawFunction::Kind function_kind = target.kind(); | 1535 const RawFunction::Kind function_kind = target.kind(); |
1533 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { | 1536 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { |
1534 PolymorphicInstanceCallInstr* call = | 1537 ZoneGrowableArray<PushArgumentInstr*>* args = |
Vyacheslav Egorov (Google)
2017/05/18 07:03:11
ditto
| |
1535 new (Z) PolymorphicInstanceCallInstr(instr, *targets, | 1538 new (Z) ZoneGrowableArray<PushArgumentInstr*>(instr->ArgumentCount()); |
1536 /* call_with_checks = */ false, | 1539 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { |
1537 /* complete = */ false); | 1540 args->Add(instr->PushArgumentAt(i)); |
1541 } | |
1542 StaticCallInstr* call = new (Z) | |
1543 StaticCallInstr(instr->token_pos(), target, instr->argument_names(), | |
1544 args, instr->deopt_id(), instr->CallCount()); | |
1538 instr->ReplaceWith(call, current_iterator()); | 1545 instr->ReplaceWith(call, current_iterator()); |
1539 return; | 1546 return; |
1540 } | 1547 } |
1541 } | 1548 } |
1542 | 1549 |
1543 // If there is only one target we can make this into a deopting class check, | 1550 // 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 | 1551 // 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 | 1552 // 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. | 1553 // 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 | 1554 // 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 | 1555 // 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 | 1556 // 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 | 1557 // very polymorphic sites we don't make this optimization, keeping it as a |
1551 // regular checked PolymorphicInstanceCall, which falls back to the slow but | 1558 // regular checked PolymorphicInstanceCall, which falls back to the slow but |
1552 // non-deopting megamorphic call stub when it sees new receiver classes. | 1559 // 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 && | 1560 if (has_one_target && FLAG_polymorphic_with_deopt && |
1555 (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) || | 1561 (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) || |
1556 unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | 1562 unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
1557 // Type propagation has not run yet, we cannot eliminate the check. | 1563 // Type propagation has not run yet, we cannot eliminate the check. |
1558 // TODO(erikcorry): The receiver check should use the off-heap targets | 1564 // TODO(erikcorry): The receiver check should use the off-heap targets |
1559 // array, not the IC array. | 1565 // array, not the IC array. |
1560 AddReceiverCheck(instr); | 1566 AddReceiverCheck(instr); |
1561 // Call can still deoptimize, do not detach environment from instr. | 1567 // Call can still deoptimize, do not detach environment from instr. |
1562 call_with_checks = false; | 1568 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
1569 ZoneGrowableArray<PushArgumentInstr*>* args = | |
Vyacheslav Egorov (Google)
2017/05/18 07:03:11
ditto
| |
1570 new (Z) ZoneGrowableArray<PushArgumentInstr*>(instr->ArgumentCount()); | |
1571 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { | |
1572 args->Add(instr->PushArgumentAt(i)); | |
1573 } | |
1574 StaticCallInstr* call = new (Z) | |
1575 StaticCallInstr(instr->token_pos(), target, instr->argument_names(), | |
1576 args, instr->deopt_id(), instr->CallCount()); | |
1577 instr->ReplaceWith(call, current_iterator()); | |
1563 } else { | 1578 } else { |
1564 call_with_checks = true; | 1579 PolymorphicInstanceCallInstr* call = |
1580 new (Z) PolymorphicInstanceCallInstr(instr, *targets, | |
1581 /* complete = */ false); | |
1582 instr->ReplaceWith(call, current_iterator()); | |
1565 } | 1583 } |
1566 PolymorphicInstanceCallInstr* call = | |
1567 new (Z) PolymorphicInstanceCallInstr(instr, *targets, call_with_checks, | |
1568 /* complete = */ false); | |
1569 instr->ReplaceWith(call, current_iterator()); | |
1570 } | 1584 } |
1571 | 1585 |
1572 | 1586 |
1573 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1587 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
1574 MethodRecognizer::Kind recognized_kind = | 1588 MethodRecognizer::Kind recognized_kind = |
1575 MethodRecognizer::RecognizeKind(call->function()); | 1589 MethodRecognizer::RecognizeKind(call->function()); |
1576 switch (recognized_kind) { | 1590 switch (recognized_kind) { |
1577 case MethodRecognizer::kObjectConstructor: | 1591 case MethodRecognizer::kObjectConstructor: |
1578 case MethodRecognizer::kObjectArrayAllocate: | 1592 case MethodRecognizer::kObjectArrayAllocate: |
1579 case MethodRecognizer::kFloat32x4Zero: | 1593 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 | 1827 // Discard the environment from the original instruction because the store |
1814 // can't deoptimize. | 1828 // can't deoptimize. |
1815 instr->RemoveEnvironment(); | 1829 instr->RemoveEnvironment(); |
1816 ReplaceCall(instr, store); | 1830 ReplaceCall(instr, store); |
1817 return true; | 1831 return true; |
1818 } | 1832 } |
1819 | 1833 |
1820 | 1834 |
1821 } // namespace dart | 1835 } // namespace dart |
1822 #endif // DART_PRECOMPILED_RUNTIME | 1836 #endif // DART_PRECOMPILED_RUNTIME |
OLD | NEW |