Chromium Code Reviews| 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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 &error_message)) { | 220 &error_message)) { |
| 221 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); | 221 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); |
| 222 const ICData& ic_data = ICData::ZoneHandle(Z, | 222 const ICData& ic_data = ICData::ZoneHandle(Z, |
| 223 ICData::NewFrom(*call->ic_data(), 1)); | 223 ICData::NewFrom(*call->ic_data(), 1)); |
| 224 ic_data.AddReceiverCheck(cid, target_function); | 224 ic_data.AddReceiverCheck(cid, target_function); |
| 225 call->set_ic_data(&ic_data); | 225 call->set_ic_data(&ic_data); |
| 226 return true; | 226 return true; |
| 227 } | 227 } |
| 228 } | 228 } |
| 229 | 229 |
| 230 // Check if getter or setter in function's class and class is currently leaf. | |
|
srdjan
2016/03/22 16:37:22
Removing this guessing will have a considerable ne
Florian Schneider
2016/03/22 16:51:03
One question: Is this only meant for getter/setter
| |
| 231 if (FLAG_guess_icdata_cid && | |
| 232 ((call->token_kind() == Token::kGET) || | |
| 233 (call->token_kind() == Token::kSET))) { | |
| 234 const Class& owner_class = Class::Handle(Z, function().Owner()); | |
| 235 if (!owner_class.is_abstract() && | |
| 236 !CHA::HasSubclasses(owner_class) && | |
| 237 !CHA::IsImplemented(owner_class)) { | |
| 238 const Array& args_desc_array = Array::Handle(Z, | |
| 239 ArgumentsDescriptor::New(call->ArgumentCount(), | |
| 240 call->argument_names())); | |
| 241 ArgumentsDescriptor args_desc(args_desc_array); | |
| 242 const Function& function = Function::Handle(Z, | |
| 243 Resolver::ResolveDynamicForReceiverClass(owner_class, | |
| 244 call->function_name(), | |
| 245 args_desc)); | |
| 246 if (!function.IsNull()) { | |
| 247 const ICData& ic_data = ICData::ZoneHandle(Z, | |
| 248 ICData::NewFrom(*call->ic_data(), class_ids.length())); | |
| 249 ic_data.AddReceiverCheck(owner_class.id(), function); | |
| 250 call->set_ic_data(&ic_data); | |
| 251 return true; | |
| 252 } | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 return false; | 230 return false; |
| 257 } | 231 } |
| 258 | 232 |
| 259 | 233 |
| 260 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, | 234 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, |
| 261 intptr_t cid) { | 235 intptr_t cid) { |
| 262 ASSERT(ic_data.NumArgsTested() == 1); | 236 ASSERT(ic_data.NumArgsTested() == 1); |
| 263 | 237 |
| 264 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 238 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { |
| 265 return ic_data; // Nothing to do | 239 return ic_data; // Nothing to do |
| (...skipping 2132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2398 | 2372 |
| 2399 | 2373 |
| 2400 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { | 2374 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { |
| 2401 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { | 2375 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { |
| 2402 if ((*inlining_black_list_)[i] == call_deopt_id) return true; | 2376 if ((*inlining_black_list_)[i] == call_deopt_id) return true; |
| 2403 } | 2377 } |
| 2404 return false; | 2378 return false; |
| 2405 } | 2379 } |
| 2406 | 2380 |
| 2407 | 2381 |
| 2382 static bool HasLikelySmiOperand(InstanceCallInstr* instr) { | |
| 2383 // If one of the inputs is the result of another CheckedSmiOp, we guess | |
| 2384 // the operand to be likely smi. Phis with at least one known smi are | |
| 2385 // guessed to be likely smi as well. | |
| 2386 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { | |
| 2387 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); | |
| 2388 if (phi != NULL) { | |
| 2389 for (intptr_t j = 0; j < phi->InputCount(); ++j) { | |
| 2390 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; | |
| 2391 } | |
| 2392 continue; | |
| 2393 } | |
| 2394 if (instr->ArgumentAt(i)->IsCheckedSmiOp()) return true; | |
| 2395 } | |
| 2396 return false; | |
| 2397 } | |
| 2398 | |
| 2408 // Tries to optimize instance call by replacing it with a faster instruction | 2399 // Tries to optimize instance call by replacing it with a faster instruction |
| 2409 // (e.g, binary op, field load, ..). | 2400 // (e.g, binary op, field load, ..). |
| 2410 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2401 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2411 ASSERT(FLAG_precompiled_mode); | 2402 ASSERT(FLAG_precompiled_mode); |
| 2412 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 2403 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 2413 // deoptimize. | 2404 // deoptimize. |
| 2414 | 2405 |
| 2415 // Type test is special as it always gets converted into inlined code. | 2406 // Type test is special as it always gets converted into inlined code. |
| 2416 const Token::Kind op_kind = instr->token_kind(); | 2407 const Token::Kind op_kind = instr->token_kind(); |
| 2417 if (Token::IsTypeTestOperator(op_kind)) { | 2408 if (Token::IsTypeTestOperator(op_kind)) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2488 switch (instr->token_kind()) { | 2479 switch (instr->token_kind()) { |
| 2489 case Token::kEQ: | 2480 case Token::kEQ: |
| 2490 case Token::kLT: | 2481 case Token::kLT: |
| 2491 case Token::kLTE: | 2482 case Token::kLTE: |
| 2492 case Token::kGT: | 2483 case Token::kGT: |
| 2493 case Token::kGTE: | 2484 case Token::kGTE: |
| 2494 case Token::kBIT_OR: | 2485 case Token::kBIT_OR: |
| 2495 case Token::kBIT_XOR: | 2486 case Token::kBIT_XOR: |
| 2496 case Token::kBIT_AND: | 2487 case Token::kBIT_AND: |
| 2497 case Token::kADD: | 2488 case Token::kADD: |
| 2498 case Token::kSUB: { | 2489 case Token::kSUB: |
| 2499 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid)) { | 2490 case Token::kMUL: { |
| 2491 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) || | |
| 2492 HasLikelySmiOperand(instr)) { | |
| 2500 Definition* left = instr->ArgumentAt(0); | 2493 Definition* left = instr->ArgumentAt(0); |
| 2501 Definition* right = instr->ArgumentAt(1); | 2494 Definition* right = instr->ArgumentAt(1); |
| 2502 CheckedSmiOpInstr* smi_op = | 2495 CheckedSmiOpInstr* smi_op = |
| 2503 new(Z) CheckedSmiOpInstr(instr->token_kind(), | 2496 new(Z) CheckedSmiOpInstr(instr->token_kind(), |
| 2504 new(Z) Value(left), | 2497 new(Z) Value(left), |
| 2505 new(Z) Value(right), | 2498 new(Z) Value(right), |
| 2506 instr); | 2499 instr); |
| 2507 | 2500 |
| 2508 ReplaceCall(instr, smi_op); | 2501 ReplaceCall(instr, smi_op); |
| 2509 return; | 2502 return; |
| 2510 } | 2503 } |
| 2504 break; | |
| 2511 } | 2505 } |
| 2512 default: | 2506 default: |
| 2513 break; | 2507 break; |
| 2514 } | 2508 } |
| 2515 | 2509 |
| 2510 // No IC data checks. Try resolve target using the propagated type. | |
| 2511 // If the propagated type has a method with the target name and there are | |
| 2512 // no overrides with that name according to CHA, call the method directly. | |
| 2513 const intptr_t receiver_cid = | |
| 2514 instr->PushArgumentAt(0)->value()->Type()->ToCid(); | |
| 2515 if (receiver_cid != kDynamicCid) { | |
| 2516 const Class& receiver_class = Class::Handle(Z, | |
| 2517 isolate()->class_table()->At(receiver_cid)); | |
| 2518 | |
| 2519 const Array& args_desc_array = Array::Handle(Z, | |
| 2520 ArgumentsDescriptor::New(instr->ArgumentCount(), | |
| 2521 instr->argument_names())); | |
| 2522 ArgumentsDescriptor args_desc(args_desc_array); | |
| 2523 const Function& function = Function::Handle(Z, | |
| 2524 Resolver::ResolveDynamicForReceiverClass( | |
| 2525 receiver_class, | |
| 2526 instr->function_name(), | |
| 2527 args_desc)); | |
| 2528 if (!function.IsNull()) { | |
| 2529 if (!thread()->cha()->HasOverride(receiver_class, | |
| 2530 instr->function_name())) { | |
| 2531 if (FLAG_trace_cha) { | |
| 2532 THR_Print(" **(CHA) Instance call needs no check, " | |
| 2533 "no overrides of '%s' '%s'\n", | |
| 2534 instr->function_name().ToCString(), receiver_class.ToCString()); | |
| 2535 } | |
| 2536 thread()->cha()->AddToLeafClasses(receiver_class); | |
|
srdjan
2016/03/22 16:37:22
AddToLeafClasses is I think only needed when deopt
Florian Schneider
2016/03/22 16:51:03
Done.
| |
| 2537 | |
| 2538 // Create fake IC data with the resolved target. | |
| 2539 const ICData& ic_data = ICData::Handle( | |
| 2540 ICData::New(flow_graph_->function(), | |
| 2541 instr->function_name(), | |
| 2542 args_desc_array, | |
| 2543 Thread::kNoDeoptId, | |
| 2544 /* args_tested = */ 1)); | |
| 2545 ic_data.AddReceiverCheck(receiver_class.id(), function); | |
| 2546 PolymorphicInstanceCallInstr* call = | |
| 2547 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | |
| 2548 /* with_checks = */ false); | |
| 2549 instr->ReplaceWith(call, current_iterator()); | |
| 2550 return; | |
| 2551 } | |
| 2552 } | |
| 2553 } | |
| 2554 | |
| 2516 // More than one targets. Generate generic polymorphic call without | 2555 // More than one targets. Generate generic polymorphic call without |
| 2517 // deoptimization. | 2556 // deoptimization. |
| 2518 if (instr->ic_data()->NumberOfUsedChecks() > 0) { | 2557 if (instr->ic_data()->NumberOfUsedChecks() > 0) { |
| 2519 ASSERT(!FLAG_polymorphic_with_deopt); | 2558 ASSERT(!FLAG_polymorphic_with_deopt); |
| 2520 // OK to use checks with PolymorphicInstanceCallInstr since no | 2559 // OK to use checks with PolymorphicInstanceCallInstr since no |
| 2521 // deoptimization is allowed. | 2560 // deoptimization is allowed. |
| 2522 PolymorphicInstanceCallInstr* call = | 2561 PolymorphicInstanceCallInstr* call = |
| 2523 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2562 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 2524 /* with_checks = */ true); | 2563 /* with_checks = */ true); |
| 2525 instr->ReplaceWith(call, current_iterator()); | 2564 instr->ReplaceWith(call, current_iterator()); |
| 2526 return; | 2565 return; |
| 2527 } | 2566 } |
| 2528 | |
| 2529 // No IC data checks. Try resolve target using the propagated type. | |
| 2530 // If the propagated type has a method with the target name and there are | |
| 2531 // no overrides with that name according to CHA, call the method directly. | |
| 2532 const intptr_t receiver_cid = | |
| 2533 instr->PushArgumentAt(0)->value()->Type()->ToCid(); | |
| 2534 if (receiver_cid == kDynamicCid) return; | |
| 2535 const Class& receiver_class = Class::Handle(Z, | |
| 2536 isolate()->class_table()->At(receiver_cid)); | |
| 2537 | |
| 2538 const Array& args_desc_array = Array::Handle(Z, | |
| 2539 ArgumentsDescriptor::New(instr->ArgumentCount(), | |
| 2540 instr->argument_names())); | |
| 2541 ArgumentsDescriptor args_desc(args_desc_array); | |
| 2542 const Function& function = Function::Handle(Z, | |
| 2543 Resolver::ResolveDynamicForReceiverClass( | |
| 2544 receiver_class, | |
| 2545 instr->function_name(), | |
| 2546 args_desc)); | |
| 2547 if (function.IsNull()) { | |
| 2548 return; | |
| 2549 } | |
| 2550 if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) { | |
| 2551 if (FLAG_trace_cha) { | |
| 2552 THR_Print(" **(CHA) Instance call needs no check, " | |
| 2553 "no overrides of '%s' '%s'\n", | |
| 2554 instr->function_name().ToCString(), receiver_class.ToCString()); | |
| 2555 } | |
| 2556 thread()->cha()->AddToLeafClasses(receiver_class); | |
| 2557 | |
| 2558 // Create fake IC data with the resolved target. | |
| 2559 const ICData& ic_data = ICData::Handle( | |
| 2560 ICData::New(flow_graph_->function(), | |
| 2561 instr->function_name(), | |
| 2562 args_desc_array, | |
| 2563 Thread::kNoDeoptId, | |
| 2564 /* args_tested = */ 1)); | |
| 2565 ic_data.AddReceiverCheck(receiver_class.id(), function); | |
| 2566 PolymorphicInstanceCallInstr* call = | |
| 2567 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | |
| 2568 /* with_checks = */ false); | |
| 2569 instr->ReplaceWith(call, current_iterator()); | |
| 2570 } | |
| 2571 } | 2567 } |
| 2572 | 2568 |
| 2573 | 2569 |
| 2574 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2570 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 2575 if (!CanUnboxDouble()) { | 2571 if (!CanUnboxDouble()) { |
| 2576 return; | 2572 return; |
| 2577 } | 2573 } |
| 2578 MethodRecognizer::Kind recognized_kind = | 2574 MethodRecognizer::Kind recognized_kind = |
| 2579 MethodRecognizer::RecognizeKind(call->function()); | 2575 MethodRecognizer::RecognizeKind(call->function()); |
| 2580 MathUnaryInstr::MathUnaryKind unary_kind; | 2576 MathUnaryInstr::MathUnaryKind unary_kind; |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2791 | 2787 |
| 2792 // Discard the environment from the original instruction because the store | 2788 // Discard the environment from the original instruction because the store |
| 2793 // can't deoptimize. | 2789 // can't deoptimize. |
| 2794 instr->RemoveEnvironment(); | 2790 instr->RemoveEnvironment(); |
| 2795 ReplaceCall(instr, store); | 2791 ReplaceCall(instr, store); |
| 2796 return true; | 2792 return true; |
| 2797 } | 2793 } |
| 2798 | 2794 |
| 2799 | 2795 |
| 2800 } // namespace dart | 2796 } // namespace dart |
| OLD | NEW |