| 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. | |
| 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 // Phis with at least one known smi are // guessed to be likely smi as well. |
| 2384 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { |
| 2385 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); |
| 2386 if (phi != NULL) { |
| 2387 for (intptr_t j = 0; j < phi->InputCount(); ++j) { |
| 2388 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; |
| 2389 } |
| 2390 } |
| 2391 } |
| 2392 // If all of the inputs are known smis or the result of CheckedSmiOp, |
| 2393 // we guess the operand to be likely smi. |
| 2394 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { |
| 2395 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false; |
| 2396 } |
| 2397 return true; |
| 2398 } |
| 2399 |
| 2400 |
| 2408 // Tries to optimize instance call by replacing it with a faster instruction | 2401 // Tries to optimize instance call by replacing it with a faster instruction |
| 2409 // (e.g, binary op, field load, ..). | 2402 // (e.g, binary op, field load, ..). |
| 2410 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2403 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2411 ASSERT(FLAG_precompiled_mode); | 2404 ASSERT(FLAG_precompiled_mode); |
| 2412 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 2405 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 2413 // deoptimize. | 2406 // deoptimize. |
| 2414 | 2407 |
| 2415 // Type test is special as it always gets converted into inlined code. | 2408 // Type test is special as it always gets converted into inlined code. |
| 2416 const Token::Kind op_kind = instr->token_kind(); | 2409 const Token::Kind op_kind = instr->token_kind(); |
| 2417 if (Token::IsTypeTestOperator(op_kind)) { | 2410 if (Token::IsTypeTestOperator(op_kind)) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2488 switch (instr->token_kind()) { | 2481 switch (instr->token_kind()) { |
| 2489 case Token::kEQ: | 2482 case Token::kEQ: |
| 2490 case Token::kLT: | 2483 case Token::kLT: |
| 2491 case Token::kLTE: | 2484 case Token::kLTE: |
| 2492 case Token::kGT: | 2485 case Token::kGT: |
| 2493 case Token::kGTE: | 2486 case Token::kGTE: |
| 2494 case Token::kBIT_OR: | 2487 case Token::kBIT_OR: |
| 2495 case Token::kBIT_XOR: | 2488 case Token::kBIT_XOR: |
| 2496 case Token::kBIT_AND: | 2489 case Token::kBIT_AND: |
| 2497 case Token::kADD: | 2490 case Token::kADD: |
| 2498 case Token::kSUB: { | 2491 case Token::kSUB: |
| 2499 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid)) { | 2492 case Token::kMUL: { |
| 2493 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) || |
| 2494 HasLikelySmiOperand(instr)) { |
| 2500 Definition* left = instr->ArgumentAt(0); | 2495 Definition* left = instr->ArgumentAt(0); |
| 2501 Definition* right = instr->ArgumentAt(1); | 2496 Definition* right = instr->ArgumentAt(1); |
| 2502 CheckedSmiOpInstr* smi_op = | 2497 CheckedSmiOpInstr* smi_op = |
| 2503 new(Z) CheckedSmiOpInstr(instr->token_kind(), | 2498 new(Z) CheckedSmiOpInstr(instr->token_kind(), |
| 2504 new(Z) Value(left), | 2499 new(Z) Value(left), |
| 2505 new(Z) Value(right), | 2500 new(Z) Value(right), |
| 2506 instr); | 2501 instr); |
| 2507 | 2502 |
| 2508 ReplaceCall(instr, smi_op); | 2503 ReplaceCall(instr, smi_op); |
| 2509 return; | 2504 return; |
| 2510 } | 2505 } |
| 2506 break; |
| 2511 } | 2507 } |
| 2512 default: | 2508 default: |
| 2513 break; | 2509 break; |
| 2514 } | 2510 } |
| 2515 | 2511 |
| 2512 // No IC data checks. Try resolve target using the propagated type. |
| 2513 // If the propagated type has a method with the target name and there are |
| 2514 // no overrides with that name according to CHA, call the method directly. |
| 2515 const intptr_t receiver_cid = |
| 2516 instr->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 2517 if (receiver_cid != kDynamicCid) { |
| 2518 const Class& receiver_class = Class::Handle(Z, |
| 2519 isolate()->class_table()->At(receiver_cid)); |
| 2520 |
| 2521 const Array& args_desc_array = Array::Handle(Z, |
| 2522 ArgumentsDescriptor::New(instr->ArgumentCount(), |
| 2523 instr->argument_names())); |
| 2524 ArgumentsDescriptor args_desc(args_desc_array); |
| 2525 const Function& function = Function::Handle(Z, |
| 2526 Resolver::ResolveDynamicForReceiverClass( |
| 2527 receiver_class, |
| 2528 instr->function_name(), |
| 2529 args_desc)); |
| 2530 if (!function.IsNull()) { |
| 2531 if (!thread()->cha()->HasOverride(receiver_class, |
| 2532 instr->function_name())) { |
| 2533 if (FLAG_trace_cha) { |
| 2534 THR_Print(" **(CHA) Instance call needs no check, " |
| 2535 "no overrides of '%s' '%s'\n", |
| 2536 instr->function_name().ToCString(), receiver_class.ToCString()); |
| 2537 } |
| 2538 |
| 2539 // Create fake IC data with the resolved target. |
| 2540 const ICData& ic_data = ICData::Handle( |
| 2541 ICData::New(flow_graph_->function(), |
| 2542 instr->function_name(), |
| 2543 args_desc_array, |
| 2544 Thread::kNoDeoptId, |
| 2545 /* args_tested = */ 1)); |
| 2546 ic_data.AddReceiverCheck(receiver_class.id(), function); |
| 2547 PolymorphicInstanceCallInstr* call = |
| 2548 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, |
| 2549 /* with_checks = */ false); |
| 2550 instr->ReplaceWith(call, current_iterator()); |
| 2551 return; |
| 2552 } |
| 2553 } |
| 2554 } |
| 2555 |
| 2516 // More than one targets. Generate generic polymorphic call without | 2556 // More than one targets. Generate generic polymorphic call without |
| 2517 // deoptimization. | 2557 // deoptimization. |
| 2518 if (instr->ic_data()->NumberOfUsedChecks() > 0) { | 2558 if (instr->ic_data()->NumberOfUsedChecks() > 0) { |
| 2519 ASSERT(!FLAG_polymorphic_with_deopt); | 2559 ASSERT(!FLAG_polymorphic_with_deopt); |
| 2520 // OK to use checks with PolymorphicInstanceCallInstr since no | 2560 // OK to use checks with PolymorphicInstanceCallInstr since no |
| 2521 // deoptimization is allowed. | 2561 // deoptimization is allowed. |
| 2522 PolymorphicInstanceCallInstr* call = | 2562 PolymorphicInstanceCallInstr* call = |
| 2523 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2563 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 2524 /* with_checks = */ true); | 2564 /* with_checks = */ true); |
| 2525 instr->ReplaceWith(call, current_iterator()); | 2565 instr->ReplaceWith(call, current_iterator()); |
| 2526 return; | 2566 return; |
| 2527 } | 2567 } |
| 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 } | 2568 } |
| 2572 | 2569 |
| 2573 | 2570 |
| 2574 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2571 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 2575 if (!CanUnboxDouble()) { | 2572 if (!CanUnboxDouble()) { |
| 2576 return; | 2573 return; |
| 2577 } | 2574 } |
| 2578 MethodRecognizer::Kind recognized_kind = | 2575 MethodRecognizer::Kind recognized_kind = |
| 2579 MethodRecognizer::RecognizeKind(call->function()); | 2576 MethodRecognizer::RecognizeKind(call->function()); |
| 2580 MathUnaryInstr::MathUnaryKind unary_kind; | 2577 MathUnaryInstr::MathUnaryKind unary_kind; |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2791 | 2788 |
| 2792 // Discard the environment from the original instruction because the store | 2789 // Discard the environment from the original instruction because the store |
| 2793 // can't deoptimize. | 2790 // can't deoptimize. |
| 2794 instr->RemoveEnvironment(); | 2791 instr->RemoveEnvironment(); |
| 2795 ReplaceCall(instr, store); | 2792 ReplaceCall(instr, store); |
| 2796 return true; | 2793 return true; |
| 2797 } | 2794 } |
| 2798 | 2795 |
| 2799 | 2796 |
| 2800 } // namespace dart | 2797 } // namespace dart |
| OLD | NEW |