| 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 2274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2285 } | 2285 } |
| 2286 // If all of the inputs are known smis or the result of CheckedSmiOp, | 2286 // If all of the inputs are known smis or the result of CheckedSmiOp, |
| 2287 // we guess the operand to be likely smi. | 2287 // we guess the operand to be likely smi. |
| 2288 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { | 2288 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { |
| 2289 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false; | 2289 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false; |
| 2290 } | 2290 } |
| 2291 return true; | 2291 return true; |
| 2292 } | 2292 } |
| 2293 | 2293 |
| 2294 | 2294 |
| 2295 bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) { |
| 2296 const Token::Kind op_kind = call->token_kind(); |
| 2297 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) { |
| 2298 return true; |
| 2299 } |
| 2300 |
| 2301 const ICData& unary_checks = |
| 2302 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 2303 if ((unary_checks.NumberOfChecks() > 0) && |
| 2304 (op_kind == Token::kSET) && |
| 2305 TryInlineInstanceSetter(call, unary_checks)) { |
| 2306 return true; |
| 2307 } |
| 2308 |
| 2309 return false; |
| 2310 } |
| 2311 |
| 2312 |
| 2295 // Tries to optimize instance call by replacing it with a faster instruction | 2313 // Tries to optimize instance call by replacing it with a faster instruction |
| 2296 // (e.g, binary op, field load, ..). | 2314 // (e.g, binary op, field load, ..). |
| 2297 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2315 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2298 ASSERT(FLAG_precompiled_mode); | 2316 ASSERT(FLAG_precompiled_mode); |
| 2299 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 2317 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 2300 // deoptimize. | 2318 // deoptimize. |
| 2301 | 2319 |
| 2302 // Type test is special as it always gets converted into inlined code. | 2320 // Type test is special as it always gets converted into inlined code. |
| 2303 const Token::Kind op_kind = instr->token_kind(); | 2321 const Token::Kind op_kind = instr->token_kind(); |
| 2304 if (Token::IsTypeTestOperator(op_kind)) { | 2322 if (Token::IsTypeTestOperator(op_kind)) { |
| 2305 ReplaceWithInstanceOf(instr); | 2323 ReplaceWithInstanceOf(instr); |
| 2306 return; | 2324 return; |
| 2307 } | 2325 } |
| 2308 if (Token::IsTypeCastOperator(op_kind)) { | 2326 if (Token::IsTypeCastOperator(op_kind)) { |
| 2309 ReplaceWithTypeCast(instr); | 2327 ReplaceWithTypeCast(instr); |
| 2310 return; | 2328 return; |
| 2311 } | 2329 } |
| 2312 | 2330 |
| 2313 if ((op_kind == Token::kGET) && | 2331 if (TryInlineFieldAccess(instr)) { |
| 2314 TryInlineInstanceGetter(instr)) { | |
| 2315 return; | |
| 2316 } | |
| 2317 const ICData& unary_checks = | |
| 2318 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | |
| 2319 if ((unary_checks.NumberOfChecks() > 0) && | |
| 2320 (op_kind == Token::kSET) && | |
| 2321 TryInlineInstanceSetter(instr, unary_checks)) { | |
| 2322 return; | 2332 return; |
| 2323 } | 2333 } |
| 2324 | 2334 |
| 2335 const ICData& unary_checks = |
| 2336 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 2325 if (IsAllowedForInlining(instr->deopt_id()) && | 2337 if (IsAllowedForInlining(instr->deopt_id()) && |
| 2326 (unary_checks.NumberOfChecks() > 0)) { | 2338 (unary_checks.NumberOfChecks() > 0)) { |
| 2327 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | 2339 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2328 return; | 2340 return; |
| 2329 } | 2341 } |
| 2330 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | 2342 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2331 return; | 2343 return; |
| 2332 } | 2344 } |
| 2333 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { | 2345 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { |
| 2334 return; | 2346 return; |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2506 | 2518 |
| 2507 single_target = Function::null(); | 2519 single_target = Function::null(); |
| 2508 } | 2520 } |
| 2509 | 2521 |
| 2510 ASSERT(ic_data.raw() != ICData::null()); | 2522 ASSERT(ic_data.raw() != ICData::null()); |
| 2511 ASSERT(single_target.raw() == Function::null()); | 2523 ASSERT(single_target.raw() == Function::null()); |
| 2512 ic_data.AddReceiverCheck(cid, target); | 2524 ic_data.AddReceiverCheck(cid, target); |
| 2513 } | 2525 } |
| 2514 | 2526 |
| 2515 if (single_target.raw() != Function::null()) { | 2527 if (single_target.raw() != Function::null()) { |
| 2528 // If this is a getter or setter invocation try inlining it right away |
| 2529 // instead of replacing it with a static call. |
| 2530 if ((op_kind == Token::kGET) || (op_kind == Token::kSET)) { |
| 2531 // Create fake IC data with the resolved target. |
| 2532 const ICData& ic_data = ICData::Handle( |
| 2533 ICData::New(flow_graph_->function(), |
| 2534 instr->function_name(), |
| 2535 args_desc_array, |
| 2536 Thread::kNoDeoptId, |
| 2537 /* args_tested = */ 1, |
| 2538 false)); |
| 2539 cls = single_target.Owner(); |
| 2540 ic_data.AddReceiverCheck(cls.id(), single_target); |
| 2541 instr->set_ic_data(&ic_data); |
| 2542 |
| 2543 if (TryInlineFieldAccess(instr)) { |
| 2544 return; |
| 2545 } |
| 2546 } |
| 2547 |
| 2516 // We have computed that there is only a single target for this call | 2548 // We have computed that there is only a single target for this call |
| 2517 // within the whole hierarchy. Replace InstanceCall with StaticCall. | 2549 // within the whole hierarchy. Replace InstanceCall with StaticCall. |
| 2518 ZoneGrowableArray<PushArgumentInstr*>* args = | 2550 ZoneGrowableArray<PushArgumentInstr*>* args = |
| 2519 new (Z) ZoneGrowableArray<PushArgumentInstr*>( | 2551 new (Z) ZoneGrowableArray<PushArgumentInstr*>( |
| 2520 instr->ArgumentCount()); | 2552 instr->ArgumentCount()); |
| 2521 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { | 2553 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { |
| 2522 args->Add(instr->PushArgumentAt(i)); | 2554 args->Add(instr->PushArgumentAt(i)); |
| 2523 } | 2555 } |
| 2524 StaticCallInstr* call = new (Z) StaticCallInstr( | 2556 StaticCallInstr* call = new (Z) StaticCallInstr( |
| 2525 instr->token_pos(), | 2557 instr->token_pos(), |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2778 | 2810 |
| 2779 // Discard the environment from the original instruction because the store | 2811 // Discard the environment from the original instruction because the store |
| 2780 // can't deoptimize. | 2812 // can't deoptimize. |
| 2781 instr->RemoveEnvironment(); | 2813 instr->RemoveEnvironment(); |
| 2782 ReplaceCall(instr, store); | 2814 ReplaceCall(instr, store); |
| 2783 return true; | 2815 return true; |
| 2784 } | 2816 } |
| 2785 | 2817 |
| 2786 | 2818 |
| 2787 } // namespace dart | 2819 } // namespace dart |
| OLD | NEW |