Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(671)

Side by Side Diff: runtime/vm/aot_optimizer.cc

Issue 1824023002: VM: Fix a couple of issues in the AOT optimizer, add fast path smi multiply. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698