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/aot_optimizer.h" | 5 #include "vm/aot_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 2447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2458 } | 2458 } |
2459 } | 2459 } |
2460 } | 2460 } |
2461 | 2461 |
2462 Definition* callee_receiver = instr->ArgumentAt(0); | 2462 Definition* callee_receiver = instr->ArgumentAt(0); |
2463 const Function& function = flow_graph_->function(); | 2463 const Function& function = flow_graph_->function(); |
2464 if (function.IsDynamicFunction() && | 2464 if (function.IsDynamicFunction() && |
2465 flow_graph_->IsReceiver(callee_receiver)) { | 2465 flow_graph_->IsReceiver(callee_receiver)) { |
2466 // Call receiver is method receiver. | 2466 // Call receiver is method receiver. |
2467 Class& receiver_class = Class::Handle(Z, function.Owner()); | 2467 Class& receiver_class = Class::Handle(Z, function.Owner()); |
2468 | |
2468 GrowableArray<intptr_t> class_ids(6); | 2469 GrowableArray<intptr_t> class_ids(6); |
2469 if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) { | 2470 if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) { |
2470 if (class_ids.length() <= FLAG_max_exhaustive_polymorphic_checks) { | 2471 // First check if all subclasses end up calling the same method. |
2471 if (FLAG_trace_cha) { | 2472 // If this is the case we will replace instance call with a direct |
2472 THR_Print(" **(CHA) Only %" Pd " concrete subclasses of %s for %s\n", | 2473 // static call. |
2473 class_ids.length(), | 2474 // Otherwise we will try to create ICData that contains all possible |
2474 receiver_class.ToCString(), | 2475 // targets with appropriate checks. |
2475 instr->function_name().ToCString()); | 2476 Function& single_target = Function::Handle(Z); |
2477 ICData& ic_data = ICData::Handle(Z); | |
2478 | |
2479 const Array& args_desc_array = Array::Handle(Z, | |
2480 ArgumentsDescriptor::New(instr->ArgumentCount(), | |
2481 instr->argument_names())); | |
2482 ArgumentsDescriptor args_desc(args_desc_array); | |
2483 | |
2484 Function& target = Function::Handle(Z); | |
2485 Class& cls = Class::Handle(Z); | |
2486 for (intptr_t i = 0; i < class_ids.length(); i++) { | |
2487 const intptr_t cid = class_ids[i]; | |
2488 cls = isolate()->class_table()->At(cid); | |
2489 target = Resolver::ResolveDynamicForReceiverClass( | |
2490 cls, | |
2491 instr->function_name(), | |
2492 args_desc); | |
2493 | |
2494 if (target.IsNull()) { | |
2495 // Can't resolve the target. It might be a noSuchMethod, | |
2496 // call through getter or closurization. | |
2497 single_target = Function::null(); | |
2498 ic_data = ICData::null(); | |
2499 break; | |
2500 } else if (ic_data.IsNull()) { | |
2501 // First we are trying to compute a single target for all subclasses. | |
2502 if (single_target.IsNull()) { | |
2503 ASSERT(i == 0); | |
2504 single_target = target.raw(); | |
2505 continue; | |
2506 } else if (single_target.raw() == target.raw()) { | |
2507 continue; | |
2508 } | |
2509 | |
2510 // The call does not resolve to a single target within the hierarchy. | |
2511 // If we have too many subclasses abort the optimization. | |
2512 if (class_ids.length() > FLAG_max_exhaustive_polymorphic_checks) { | |
2513 single_target = Function::null(); | |
2514 break; | |
2515 } | |
2516 | |
2517 // Create an ICData and map all previously seen classes (< i) to | |
2518 // the computed single_target. | |
2519 ic_data = ICData::New(function, | |
2520 instr->function_name(), | |
2521 args_desc_array, | |
2522 Thread::kNoDeoptId, | |
2523 /* args_tested = */ 1); | |
2524 for (intptr_t j = 0; j < i; j++) { | |
2525 ic_data.AddReceiverCheck(class_ids[j], single_target); | |
2526 } | |
2527 | |
2528 single_target = Function::null(); | |
2476 } | 2529 } |
2477 | 2530 |
2478 const Array& args_desc_array = Array::Handle(Z, | 2531 ASSERT(ic_data.raw() != ICData::null()); |
2479 ArgumentsDescriptor::New(instr->ArgumentCount(), | 2532 ASSERT(single_target.raw() == Function::null()); |
2480 instr->argument_names())); | 2533 ic_data.AddReceiverCheck(cid, target); |
2481 ArgumentsDescriptor args_desc(args_desc_array); | 2534 } |
2482 | 2535 |
2483 const ICData& ic_data = ICData::Handle( | 2536 if (single_target.raw() != Function::null()) { |
2484 ICData::New(function, | 2537 // We have computed that there is only a single target for this call |
2485 instr->function_name(), | 2538 // within the whole hierarchy. Replace InstanceCall with StaticCall. |
2486 args_desc_array, | 2539 ZoneGrowableArray<PushArgumentInstr*>* args = |
2487 Thread::kNoDeoptId, | 2540 new (Z) ZoneGrowableArray<PushArgumentInstr*>( |
2488 /* args_tested = */ 1)); | 2541 instr->ArgumentCount()); |
2489 | 2542 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { |
2490 Function& target = Function::Handle(Z); | 2543 args->Add(instr->PushArgumentAt(i)); |
2491 Class& cls = Class::Handle(Z); | |
2492 bool includes_dispatcher_case = false; | |
2493 for (intptr_t i = 0; i < class_ids.length(); i++) { | |
2494 intptr_t cid = class_ids[i]; | |
2495 cls = isolate()->class_table()->At(cid); | |
2496 target = Resolver::ResolveDynamicForReceiverClass( | |
2497 cls, | |
2498 instr->function_name(), | |
2499 args_desc); | |
2500 if (target.IsNull()) { | |
2501 // noSuchMethod, call through getter or closurization | |
2502 includes_dispatcher_case = true; | |
2503 } else { | |
2504 ic_data.AddReceiverCheck(cid, target); | |
2505 } | |
2506 } | 2544 } |
2507 if (!includes_dispatcher_case && (ic_data.NumberOfChecks() > 0)) { | 2545 StaticCallInstr* call = new (Z) StaticCallInstr( |
Florian Schneider
2016/06/10 15:30:18
Alternatively, maybe you can combine this with the
Vyacheslav Egorov (Google)
2016/06/10 16:05:06
I considered combining it - but then I need to cre
| |
2508 PolymorphicInstanceCallInstr* call = | 2546 instr->token_pos(), |
2509 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | 2547 Function::ZoneHandle(Z, single_target.raw()), |
2510 /* with_checks = */ true, | 2548 instr->argument_names(), |
2511 /* complete = */ true); | 2549 args, |
2512 instr->ReplaceWith(call, current_iterator()); | 2550 instr->deopt_id()); |
2513 return; | 2551 instr->ReplaceWith(call, current_iterator()); |
2514 } | 2552 return; |
2553 } else if ((ic_data.raw() != ICData::null()) && | |
2554 (ic_data.NumberOfChecks() > 0)) { | |
2555 PolymorphicInstanceCallInstr* call = | |
2556 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | |
2557 /* with_checks = */ true, | |
2558 /* complete = */ true); | |
2559 instr->ReplaceWith(call, current_iterator()); | |
2560 return; | |
2515 } | 2561 } |
2516 } | 2562 } |
2517 } | 2563 } |
2518 | 2564 |
2519 // More than one targets. Generate generic polymorphic call without | 2565 // More than one target. Generate generic polymorphic call without |
2520 // deoptimization. | 2566 // deoptimization. |
2521 if (instr->ic_data()->NumberOfUsedChecks() > 0) { | 2567 if (instr->ic_data()->NumberOfUsedChecks() > 0) { |
2522 ASSERT(!FLAG_polymorphic_with_deopt); | 2568 ASSERT(!FLAG_polymorphic_with_deopt); |
2523 // OK to use checks with PolymorphicInstanceCallInstr since no | 2569 // OK to use checks with PolymorphicInstanceCallInstr since no |
2524 // deoptimization is allowed. | 2570 // deoptimization is allowed. |
2525 PolymorphicInstanceCallInstr* call = | 2571 PolymorphicInstanceCallInstr* call = |
2526 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2572 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
2527 /* with_checks = */ true, | 2573 /* with_checks = */ true, |
2528 /* complete = */ false); | 2574 /* complete = */ false); |
2529 instr->ReplaceWith(call, current_iterator()); | 2575 instr->ReplaceWith(call, current_iterator()); |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2753 | 2799 |
2754 // Discard the environment from the original instruction because the store | 2800 // Discard the environment from the original instruction because the store |
2755 // can't deoptimize. | 2801 // can't deoptimize. |
2756 instr->RemoveEnvironment(); | 2802 instr->RemoveEnvironment(); |
2757 ReplaceCall(instr, store); | 2803 ReplaceCall(instr, store); |
2758 return true; | 2804 return true; |
2759 } | 2805 } |
2760 | 2806 |
2761 | 2807 |
2762 } // namespace dart | 2808 } // namespace dart |
OLD | NEW |