| 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/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 | 42 |
| 43 // Attempts to convert an instance call (IC call) using propagated class-ids, | 43 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 44 // e.g., receiver class id. | 44 // e.g., receiver class id. |
| 45 void FlowGraphOptimizer::ApplyClassIds() { | 45 void FlowGraphOptimizer::ApplyClassIds() { |
| 46 ASSERT(current_iterator_ == NULL); | 46 ASSERT(current_iterator_ == NULL); |
| 47 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 47 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 48 BlockEntryInstr* entry = block_order_[i]; | 48 BlockEntryInstr* entry = block_order_[i]; |
| 49 ForwardInstructionIterator it(entry); | 49 ForwardInstructionIterator it(entry); |
| 50 current_iterator_ = ⁢ | 50 current_iterator_ = ⁢ |
| 51 for (; !it.Done(); it.Advance()) { | 51 for (; !it.Done(); it.Advance()) { |
| 52 if (it.Current()->IsInstanceCall()) { | 52 Instruction* instr = it.Current(); |
| 53 InstanceCallInstr* call = it.Current()->AsInstanceCall(); | 53 if (instr->IsInstanceCall()) { |
| 54 InstanceCallInstr* call = instr->AsInstanceCall(); |
| 54 if (call->HasICData()) { | 55 if (call->HasICData()) { |
| 55 if (TryCreateICData(call)) { | 56 if (TryCreateICData(call)) { |
| 56 VisitInstanceCall(call); | 57 VisitInstanceCall(call); |
| 57 } | 58 } |
| 58 } | 59 } |
| 59 } else if (it.Current()->IsPolymorphicInstanceCall()) { | 60 } else if (instr->IsPolymorphicInstanceCall()) { |
| 60 SpecializePolymorphicInstanceCall( | 61 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); |
| 61 it.Current()->AsPolymorphicInstanceCall()); | 62 } else if (instr->IsStrictCompare()) { |
| 62 } else if (it.Current()->IsStrictCompare()) { | 63 VisitStrictCompare(instr->AsStrictCompare()); |
| 63 VisitStrictCompare(it.Current()->AsStrictCompare()); | 64 } else if (instr->IsBranch()) { |
| 64 } else if (it.Current()->IsBranch()) { | 65 ComparisonInstr* compare = instr->AsBranch()->comparison(); |
| 65 ComparisonInstr* compare = it.Current()->AsBranch()->comparison(); | |
| 66 if (compare->IsStrictCompare()) { | 66 if (compare->IsStrictCompare()) { |
| 67 VisitStrictCompare(compare->AsStrictCompare()); | 67 VisitStrictCompare(compare->AsStrictCompare()); |
| 68 } | 68 } |
| 69 } | 69 } |
| 70 } | 70 } |
| 71 current_iterator_ = NULL; | 71 current_iterator_ = NULL; |
| 72 } | 72 } |
| 73 } | 73 } |
| 74 | 74 |
| 75 | 75 |
| 76 // Attempt to build ICData for call using propagated class-ids. | 76 // Attempt to build ICData for call using propagated class-ids. |
| 77 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 77 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| 78 ASSERT(call->HasICData()); | 78 ASSERT(call->HasICData()); |
| 79 if (call->ic_data()->NumberOfChecks() > 0) { | 79 if (call->ic_data()->NumberOfChecks() > 0) { |
| 80 // This occurs when an instance call has too many checks. | 80 // This occurs when an instance call has too many checks. |
| 81 // TODO(srdjan): Replace IC call with megamorphic call. | 81 // TODO(srdjan): Replace IC call with megamorphic call. |
| 82 return false; | 82 return false; |
| 83 } | 83 } |
| 84 GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested()); | 84 GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested()); |
| 85 ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount()); | 85 ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount()); |
| 86 for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) { | 86 for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) { |
| 87 intptr_t cid = call->ArgumentAt(i)->value()->Type()->ToCid(); | 87 intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid(); |
| 88 class_ids.Add(cid); | 88 class_ids.Add(cid); |
| 89 } | 89 } |
| 90 // TODO(srdjan): Test for other class_ids > 1. | 90 // TODO(srdjan): Test for other class_ids > 1. |
| 91 if (class_ids.length() != 1) return false; | 91 if (class_ids.length() != 1) return false; |
| 92 if (class_ids[0] != kDynamicCid) { | 92 if (class_ids[0] != kDynamicCid) { |
| 93 const intptr_t num_named_arguments = call->argument_names().IsNull() ? | 93 const intptr_t num_named_arguments = call->argument_names().IsNull() ? |
| 94 0 : call->argument_names().Length(); | 94 0 : call->argument_names().Length(); |
| 95 const Class& receiver_class = Class::Handle( | 95 const Class& receiver_class = Class::Handle( |
| 96 Isolate::Current()->class_table()->At(class_ids[0])); | 96 Isolate::Current()->class_table()->At(class_ids[0])); |
| 97 Function& function = Function::Handle(); | 97 Function& function = Function::Handle(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 return new_ic_data; | 143 return new_ic_data; |
| 144 } | 144 } |
| 145 | 145 |
| 146 | 146 |
| 147 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 147 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( |
| 148 PolymorphicInstanceCallInstr* call) { | 148 PolymorphicInstanceCallInstr* call) { |
| 149 if (!call->with_checks()) { | 149 if (!call->with_checks()) { |
| 150 return; // Already specialized. | 150 return; // Already specialized. |
| 151 } | 151 } |
| 152 | 152 |
| 153 const intptr_t receiver_cid = call->ArgumentAt(0)->value()->Type()->ToCid(); | 153 const intptr_t receiver_cid = |
| 154 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 154 if (receiver_cid == kDynamicCid) { | 155 if (receiver_cid == kDynamicCid) { |
| 155 return; // No information about receiver was infered. | 156 return; // No information about receiver was infered. |
| 156 } | 157 } |
| 157 | 158 |
| 158 const ICData& ic_data = SpecializeICData(call->ic_data(), receiver_cid); | 159 const ICData& ic_data = SpecializeICData(call->ic_data(), receiver_cid); |
| 159 | 160 |
| 160 const bool with_checks = false; | 161 const bool with_checks = false; |
| 161 PolymorphicInstanceCallInstr* specialized = | 162 PolymorphicInstanceCallInstr* specialized = |
| 162 new PolymorphicInstanceCallInstr(call->instance_call(), | 163 new PolymorphicInstanceCallInstr(call->instance_call(), |
| 163 ic_data, | 164 ic_data, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 Representation to, | 228 Representation to, |
| 228 Value* use, | 229 Value* use, |
| 229 Instruction* insert_before, | 230 Instruction* insert_before, |
| 230 Instruction* deopt_target) { | 231 Instruction* deopt_target) { |
| 231 Definition* converted = NULL; | 232 Definition* converted = NULL; |
| 232 if ((from == kTagged) && (to == kUnboxedMint)) { | 233 if ((from == kTagged) && (to == kUnboxedMint)) { |
| 233 ASSERT((deopt_target != NULL) || | 234 ASSERT((deopt_target != NULL) || |
| 234 (use->Type()->ToCid() == kDoubleCid)); | 235 (use->Type()->ToCid() == kDoubleCid)); |
| 235 const intptr_t deopt_id = (deopt_target != NULL) ? | 236 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 236 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 237 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 237 converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id); | 238 converted = new UnboxIntegerInstr(use->Copy(), deopt_id); |
| 239 |
| 238 } else if ((from == kUnboxedMint) && (to == kTagged)) { | 240 } else if ((from == kUnboxedMint) && (to == kTagged)) { |
| 239 converted = new BoxIntegerInstr(new Value(use->definition())); | 241 converted = new BoxIntegerInstr(use->Copy()); |
| 242 |
| 240 } else if (from == kUnboxedMint && to == kUnboxedDouble) { | 243 } else if (from == kUnboxedMint && to == kUnboxedDouble) { |
| 241 // Convert by boxing/unboxing. | 244 // Convert by boxing/unboxing. |
| 242 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. | 245 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. |
| 243 BoxIntegerInstr* boxed = new BoxIntegerInstr(new Value(use->definition())); | 246 BoxIntegerInstr* boxed = new BoxIntegerInstr(use->Copy()); |
| 247 use->RemoveFromUseList(); |
| 248 use->set_definition(boxed); |
| 249 boxed->AddInputUse(use); |
| 244 InsertBefore(insert_before, boxed, NULL, Definition::kValue); | 250 InsertBefore(insert_before, boxed, NULL, Definition::kValue); |
| 251 |
| 245 const intptr_t deopt_id = (deopt_target != NULL) ? | 252 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 246 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 253 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 247 converted = new UnboxDoubleInstr(new Value(boxed), deopt_id); | 254 converted = new UnboxDoubleInstr(new Value(boxed), deopt_id); |
| 255 |
| 248 } else if ((from == kUnboxedDouble) && (to == kTagged)) { | 256 } else if ((from == kUnboxedDouble) && (to == kTagged)) { |
| 249 converted = new BoxDoubleInstr(new Value(use->definition()), NULL); | 257 converted = new BoxDoubleInstr(use->Copy(), NULL); |
| 258 |
| 250 } else if ((from == kTagged) && (to == kUnboxedDouble)) { | 259 } else if ((from == kTagged) && (to == kUnboxedDouble)) { |
| 260 ASSERT((deopt_target != NULL) || |
| 261 (use->Type()->ToCid() == kDoubleCid)); |
| 251 const intptr_t deopt_id = (deopt_target != NULL) ? | 262 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 252 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 263 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 253 ASSERT((deopt_target != NULL) || | |
| 254 (use->Type()->ToCid() == kDoubleCid)); | |
| 255 ConstantInstr* constant = use->definition()->AsConstant(); | 264 ConstantInstr* constant = use->definition()->AsConstant(); |
| 256 if ((constant != NULL) && constant->value().IsSmi()) { | 265 if ((constant != NULL) && constant->value().IsSmi()) { |
| 257 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); | 266 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); |
| 258 const Double& dbl_obj = | 267 const Double& dbl_obj = |
| 259 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); | 268 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); |
| 260 ConstantInstr* double_const = new ConstantInstr(dbl_obj); | 269 ConstantInstr* double_const = new ConstantInstr(dbl_obj); |
| 261 InsertBefore(insert_before, double_const, NULL, Definition::kValue); | 270 InsertBefore(insert_before, double_const, NULL, Definition::kValue); |
| 262 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); | 271 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); |
| 263 } else { | 272 } else { |
| 264 converted = new UnboxDoubleInstr(new Value(use->definition()), deopt_id); | 273 converted = new UnboxDoubleInstr(use->Copy(), deopt_id); |
| 265 } | 274 } |
| 266 } | 275 } |
| 267 ASSERT(converted != NULL); | 276 ASSERT(converted != NULL); |
| 277 use->RemoveFromUseList(); |
| 278 use->set_definition(converted); |
| 279 converted->AddInputUse(use); |
| 268 InsertBefore(insert_before, converted, use->instruction()->env(), | 280 InsertBefore(insert_before, converted, use->instruction()->env(), |
| 269 Definition::kValue); | 281 Definition::kValue); |
| 270 use->set_definition(converted); | |
| 271 } | 282 } |
| 272 | 283 |
| 273 | 284 |
| 274 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { | 285 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
| 275 const Representation from_rep = def->representation(); | 286 const Representation from_rep = def->representation(); |
| 276 | 287 |
| 277 for (Value::Iterator it(def->input_use_list()); | 288 for (Value::Iterator it(def->input_use_list()); |
| 278 !it.Done(); | 289 !it.Done(); |
| 279 it.Advance()) { | 290 it.Advance()) { |
| 280 Value* use = it.Current(); | 291 Value* use = it.Current(); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 } | 463 } |
| 453 | 464 |
| 454 // Check that it have seen only smis and doubles. | 465 // Check that it have seen only smis and doubles. |
| 455 GrowableArray<intptr_t> class_ids(2); | 466 GrowableArray<intptr_t> class_ids(2); |
| 456 class_ids.Add(kSmiCid); | 467 class_ids.Add(kSmiCid); |
| 457 class_ids.Add(kDoubleCid); | 468 class_ids.Add(kDoubleCid); |
| 458 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); | 469 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 459 } | 470 } |
| 460 | 471 |
| 461 | 472 |
| 462 static void RemovePushArguments(InstanceCallInstr* call) { | 473 void FlowGraphOptimizer::ReplaceCall(Definition* call, |
| 463 // Remove original push arguments. | 474 Definition* replacement) { |
| 475 // Remove the original push arguments. |
| 464 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 476 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 465 PushArgumentInstr* push = call->ArgumentAt(i); | 477 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 466 push->ReplaceUsesWith(push->value()->definition()); | 478 push->ReplaceUsesWith(push->value()->definition()); |
| 479 push->UnuseAllInputs(); |
| 467 push->RemoveFromGraph(); | 480 push->RemoveFromGraph(); |
| 468 } | 481 } |
| 482 call->ReplaceWith(replacement, current_iterator()); |
| 469 } | 483 } |
| 470 | 484 |
| 471 | 485 |
| 472 static void RemovePushArguments(StaticCallInstr* call) { | |
| 473 // Remove original push arguments. | |
| 474 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 475 PushArgumentInstr* push = call->ArgumentAt(i); | |
| 476 push->ReplaceUsesWith(push->value()->definition()); | |
| 477 push->RemoveFromGraph(); | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 | |
| 482 static intptr_t ReceiverClassId(InstanceCallInstr* call) { | 486 static intptr_t ReceiverClassId(InstanceCallInstr* call) { |
| 483 if (!call->HasICData()) return kIllegalCid; | 487 if (!call->HasICData()) return kIllegalCid; |
| 484 | 488 |
| 485 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); | 489 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); |
| 486 | 490 |
| 487 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; | 491 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; |
| 488 // TODO(vegorov): Add multiple receiver type support. | 492 // TODO(vegorov): Add multiple receiver type support. |
| 489 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; | 493 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; |
| 490 ASSERT(ic_data.HasOneTarget()); | 494 ASSERT(ic_data.HasOneTarget()); |
| 491 | 495 |
| 492 Function& target = Function::Handle(); | 496 Function& target = Function::Handle(); |
| 493 intptr_t class_id; | 497 intptr_t class_id; |
| 494 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 498 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 495 return class_id; | 499 return class_id; |
| 496 } | 500 } |
| 497 | 501 |
| 498 | 502 |
| 499 void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call, | 503 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, |
| 500 Value* value) { | 504 const ICData& unary_checks, |
| 505 intptr_t deopt_id, |
| 506 Environment* deopt_environment, |
| 507 Instruction* insert_before) { |
| 501 // Type propagation has not run yet, we cannot eliminate the check. | 508 // Type propagation has not run yet, we cannot eliminate the check. |
| 502 const ICData& unary_checks = | |
| 503 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | |
| 504 Instruction* check = NULL; | 509 Instruction* check = NULL; |
| 505 if ((unary_checks.NumberOfChecks() == 1) && | 510 if ((unary_checks.NumberOfChecks() == 1) && |
| 506 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { | 511 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { |
| 507 check = new CheckSmiInstr(value, call->deopt_id()); | 512 check = new CheckSmiInstr(new Value(to_check), deopt_id); |
| 508 } else { | 513 } else { |
| 509 check = new CheckClassInstr(value, call->deopt_id(), unary_checks); | 514 check = new CheckClassInstr(new Value(to_check), deopt_id, unary_checks); |
| 510 } | 515 } |
| 511 InsertBefore(call, check, call->env(), Definition::kEffect); | 516 InsertBefore(insert_before, check, deopt_environment, Definition::kEffect); |
| 512 } | 517 } |
| 513 | 518 |
| 514 | 519 |
| 520 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { |
| 521 AddCheckClass(call->ArgumentAt(0), |
| 522 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()), |
| 523 call->deopt_id(), |
| 524 call->env(), |
| 525 call); |
| 526 } |
| 527 |
| 528 |
| 515 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { | 529 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { |
| 516 ASSERT(ic_data.num_args_tested() > arg_n); | 530 ASSERT(ic_data.num_args_tested() > arg_n); |
| 517 if (ic_data.NumberOfChecks() == 0) return false; | 531 if (ic_data.NumberOfChecks() == 0) return false; |
| 518 GrowableArray<intptr_t> class_ids; | 532 GrowableArray<intptr_t> class_ids; |
| 519 Function& target = Function::Handle(); | 533 Function& target = Function::Handle(); |
| 520 const intptr_t len = ic_data.NumberOfChecks(); | 534 const intptr_t len = ic_data.NumberOfChecks(); |
| 521 for (intptr_t i = 0; i < len; i++) { | 535 for (intptr_t i = 0; i < len; i++) { |
| 522 ic_data.GetCheckAt(i, &class_ids, &target); | 536 ic_data.GetCheckAt(i, &class_ids, &target); |
| 523 if (class_ids[arg_n] != kSmiCid) return false; | 537 if (class_ids[arg_n] != kSmiCid) return false; |
| 524 } | 538 } |
| 525 return true; | 539 return true; |
| 526 } | 540 } |
| 527 | 541 |
| 528 | 542 |
| 529 // Returns array classid to load from, array and index value | 543 // Returns array classid to load from, array and index value |
| 530 | 544 |
| 531 intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call, | 545 intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call, |
| 532 intptr_t class_id, | 546 intptr_t class_id, |
| 533 Value** array, | 547 Definition** array, |
| 534 Value** index) { | 548 Definition** index) { |
| 535 *array = call->ArgumentAt(0)->value(); | |
| 536 *index = call->ArgumentAt(1)->value(); | |
| 537 // Insert class check and index smi checks and attach a copy of the | 549 // Insert class check and index smi checks and attach a copy of the |
| 538 // original environment because the operation can still deoptimize. | 550 // original environment because the operation can still deoptimize. |
| 539 AddCheckClass(call, (*array)->Copy()); | 551 AddReceiverCheck(call); |
| 540 InsertBefore(call, | 552 InsertBefore(call, |
| 541 new CheckSmiInstr((*index)->Copy(), call->deopt_id()), | 553 new CheckSmiInstr(new Value(*index), call->deopt_id()), |
| 542 call->env(), | 554 call->env(), |
| 543 Definition::kEffect); | 555 Definition::kEffect); |
| 556 |
| 544 // If both index and array are constants, then do a compile-time check. | 557 // If both index and array are constants, then do a compile-time check. |
| 545 // TODO(srdjan): Remove once constant propagation handles bounds checks. | 558 // TODO(srdjan): Remove once constant propagation handles bounds checks. |
| 546 bool skip_check = false; | 559 bool skip_check = false; |
| 547 if ((*array)->BindsToConstant() && (*index)->BindsToConstant()) { | 560 if ((*array)->IsConstant() && (*index)->IsConstant()) { |
| 548 ConstantInstr* array_def = (*array)->definition()->AsConstant(); | |
| 549 const ImmutableArray& constant_array = | 561 const ImmutableArray& constant_array = |
| 550 ImmutableArray::Cast(array_def->value()); | 562 ImmutableArray::Cast((*array)->AsConstant()->value()); |
| 551 ConstantInstr* index_def = (*index)->definition()->AsConstant(); | 563 const Object& constant_index = (*index)->AsConstant()->value(); |
| 552 if (index_def->value().IsSmi()) { | 564 skip_check = constant_index.IsSmi() && |
| 553 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); | 565 (Smi::Cast(constant_index).Value() < constant_array.Length()); |
| 554 skip_check = (constant_index < constant_array.Length()); | |
| 555 } | |
| 556 } | 566 } |
| 557 if (!skip_check) { | 567 if (!skip_check) { |
| 558 // Insert array length load and bounds check. | 568 // Insert array length load and bounds check. |
| 559 const bool is_immutable = | 569 const bool is_immutable = |
| 560 CheckArrayBoundInstr::IsFixedLengthArrayType(class_id); | 570 CheckArrayBoundInstr::IsFixedLengthArrayType(class_id); |
| 561 LoadFieldInstr* length = new LoadFieldInstr( | 571 LoadFieldInstr* length = |
| 562 (*array)->Copy(), | 572 new LoadFieldInstr(new Value(*array), |
| 563 CheckArrayBoundInstr::LengthOffsetFor(class_id), | 573 CheckArrayBoundInstr::LengthOffsetFor(class_id), |
| 564 Type::ZoneHandle(Type::SmiType()), | 574 Type::ZoneHandle(Type::SmiType()), |
| 565 is_immutable); | 575 is_immutable); |
| 566 length->set_result_cid(kSmiCid); | 576 length->set_result_cid(kSmiCid); |
| 567 length->set_recognized_kind( | 577 length->set_recognized_kind( |
| 568 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); | 578 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); |
| 569 InsertBefore(call, length, NULL, Definition::kValue); | 579 InsertBefore(call, length, NULL, Definition::kValue); |
| 580 |
| 570 InsertBefore(call, | 581 InsertBefore(call, |
| 571 new CheckArrayBoundInstr(new Value(length), | 582 new CheckArrayBoundInstr(new Value(length), |
| 572 (*index)->Copy(), | 583 new Value(*index), |
| 573 class_id, | 584 class_id, |
| 574 call), | 585 call), |
| 575 call->env(), | 586 call->env(), |
| 576 Definition::kEffect); | 587 Definition::kEffect); |
| 577 } | 588 } |
| 578 if (class_id == kGrowableObjectArrayCid) { | 589 if (class_id == kGrowableObjectArrayCid) { |
| 579 // Insert data elements load. | 590 // Insert data elements load. |
| 580 LoadFieldInstr* elements = | 591 LoadFieldInstr* elements = |
| 581 new LoadFieldInstr((*array)->Copy(), | 592 new LoadFieldInstr(new Value(*array), |
| 582 GrowableObjectArray::data_offset(), | 593 GrowableObjectArray::data_offset(), |
| 583 Type::ZoneHandle(Type::DynamicType())); | 594 Type::ZoneHandle(Type::DynamicType())); |
| 584 elements->set_result_cid(kArrayCid); | 595 elements->set_result_cid(kArrayCid); |
| 585 InsertBefore(call, elements, NULL, Definition::kValue); | 596 InsertBefore(call, elements, NULL, Definition::kValue); |
| 586 *array = new Value(elements); | 597 *array = elements; |
| 587 return kArrayCid; | 598 return kArrayCid; |
| 588 } | 599 } |
| 589 return class_id; | 600 return class_id; |
| 590 } | 601 } |
| 591 | 602 |
| 592 | 603 |
| 593 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { | 604 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
| 594 const intptr_t class_id = ReceiverClassId(call); | 605 const intptr_t class_id = ReceiverClassId(call); |
| 595 ICData& value_check = ICData::ZoneHandle(); | 606 ICData& value_check = ICData::ZoneHandle(); |
| 596 switch (class_id) { | 607 switch (class_id) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { | 655 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { |
| 645 return false; | 656 return false; |
| 646 } | 657 } |
| 647 break; | 658 break; |
| 648 } | 659 } |
| 649 default: | 660 default: |
| 650 // TODO(fschneider): Add support for other array types. | 661 // TODO(fschneider): Add support for other array types. |
| 651 return false; | 662 return false; |
| 652 } | 663 } |
| 653 | 664 |
| 665 Definition* array = call->ArgumentAt(0); |
| 666 Definition* index = call->ArgumentAt(1); |
| 667 Definition* stored_value = call->ArgumentAt(2); |
| 654 if (FLAG_enable_type_checks) { | 668 if (FLAG_enable_type_checks) { |
| 655 Value* array = call->ArgumentAt(0)->value(); | |
| 656 Value* value = call->ArgumentAt(2)->value(); | |
| 657 // Only type check for the value. A type check for the index is not | 669 // Only type check for the value. A type check for the index is not |
| 658 // needed here because we insert a deoptimizing smi-check for the case | 670 // needed here because we insert a deoptimizing smi-check for the case |
| 659 // the index is not a smi. | 671 // the index is not a smi. |
| 660 const Function& target = | 672 const Function& target = |
| 661 Function::ZoneHandle(call->ic_data()->GetTargetAt(0)); | 673 Function::ZoneHandle(call->ic_data()->GetTargetAt(0)); |
| 662 const AbstractType& value_type = | 674 const AbstractType& value_type = |
| 663 AbstractType::ZoneHandle(target.ParameterTypeAt(2)); | 675 AbstractType::ZoneHandle(target.ParameterTypeAt(2)); |
| 664 Value* instantiator = NULL; | 676 Definition* instantiator = NULL; |
| 665 Value* type_args = NULL; | 677 Definition* type_args = NULL; |
| 666 switch (class_id) { | 678 switch (class_id) { |
| 667 case kArrayCid: | 679 case kArrayCid: |
| 668 case kGrowableObjectArrayCid: { | 680 case kGrowableObjectArrayCid: { |
| 669 const Class& instantiator_class = Class::Handle(target.Owner()); | 681 const Class& instantiator_class = Class::Handle(target.Owner()); |
| 670 intptr_t type_arguments_field_offset = | 682 intptr_t type_arguments_field_offset = |
| 671 instantiator_class.type_arguments_field_offset(); | 683 instantiator_class.type_arguments_field_offset(); |
| 672 LoadFieldInstr* load_type_args = | 684 LoadFieldInstr* load_type_args = |
| 673 new LoadFieldInstr(array->Copy(), | 685 new LoadFieldInstr(new Value(array), |
| 674 type_arguments_field_offset, | 686 type_arguments_field_offset, |
| 675 Type::ZoneHandle()); // No type. | 687 Type::ZoneHandle()); // No type. |
| 676 InsertBefore(call, load_type_args, NULL, Definition::kValue); | 688 InsertBefore(call, load_type_args, NULL, Definition::kValue); |
| 677 instantiator = array->Copy(); | 689 instantiator = array; |
| 678 type_args = new Value(load_type_args); | 690 type_args = load_type_args; |
| 679 break; | 691 break; |
| 680 } | 692 } |
| 681 case kInt8ArrayCid: | 693 case kInt8ArrayCid: |
| 682 case kUint8ArrayCid: | 694 case kUint8ArrayCid: |
| 683 case kUint8ClampedArrayCid: | 695 case kUint8ClampedArrayCid: |
| 684 case kExternalUint8ArrayCid: | 696 case kExternalUint8ArrayCid: |
| 685 case kExternalUint8ClampedArrayCid: | 697 case kExternalUint8ClampedArrayCid: |
| 686 case kInt16ArrayCid: | 698 case kInt16ArrayCid: |
| 687 case kUint16ArrayCid: | 699 case kUint16ArrayCid: |
| 688 case kInt32ArrayCid: | 700 case kInt32ArrayCid: |
| 689 case kUint32ArrayCid: | 701 case kUint32ArrayCid: |
| 690 ASSERT(value_type.IsIntType()); | 702 ASSERT(value_type.IsIntType()); |
| 691 // Fall through. | 703 // Fall through. |
| 692 case kFloat32ArrayCid: | 704 case kFloat32ArrayCid: |
| 693 case kFloat64ArrayCid: { | 705 case kFloat64ArrayCid: { |
| 694 instantiator = new Value(flow_graph_->constant_null()); | 706 type_args = instantiator = flow_graph_->constant_null(); |
| 695 type_args = new Value(flow_graph_->constant_null()); | |
| 696 ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || | 707 ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || |
| 697 value_type.IsDoubleType()); | 708 value_type.IsDoubleType()); |
| 698 ASSERT(value_type.IsInstantiated()); | 709 ASSERT(value_type.IsInstantiated()); |
| 699 break; | 710 break; |
| 700 } | 711 } |
| 701 default: | 712 default: |
| 702 // TODO(fschneider): Add support for other array types. | 713 // TODO(fschneider): Add support for other array types. |
| 703 UNREACHABLE(); | 714 UNREACHABLE(); |
| 704 } | 715 } |
| 705 AssertAssignableInstr* assert_value = | 716 AssertAssignableInstr* assert_value = |
| 706 new AssertAssignableInstr(call->token_pos(), | 717 new AssertAssignableInstr(call->token_pos(), |
| 707 value->Copy(), | 718 new Value(stored_value), |
| 708 instantiator, | 719 new Value(instantiator), |
| 709 type_args, | 720 new Value(type_args), |
| 710 value_type, | 721 value_type, |
| 711 Symbols::Value()); | 722 Symbols::Value()); |
| 712 // Newly inserted instructions that can deoptimize or throw an exception | 723 // Newly inserted instructions that can deoptimize or throw an exception |
| 713 // must have a deoptimization id that is valid for lookup in the unoptimized | 724 // must have a deoptimization id that is valid for lookup in the unoptimized |
| 714 // code. | 725 // code. |
| 715 assert_value->deopt_id_ = call->deopt_id(); | 726 assert_value->deopt_id_ = call->deopt_id(); |
| 716 InsertBefore(call, assert_value, call->env(), Definition::kValue); | 727 InsertBefore(call, assert_value, call->env(), Definition::kValue); |
| 717 } | 728 } |
| 718 | 729 |
| 719 Value* array = NULL; | |
| 720 Value* index = NULL; | |
| 721 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 730 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| 722 Value* value = call->ArgumentAt(2)->value(); | |
| 723 // Check if store barrier is needed. | 731 // Check if store barrier is needed. |
| 724 bool needs_store_barrier = true; | 732 bool needs_store_barrier = true; |
| 725 if (!value_check.IsNull()) { | 733 if (!value_check.IsNull()) { |
| 726 needs_store_barrier = false; | 734 needs_store_barrier = false; |
| 727 if (value_check.NumberOfChecks() == 1 && | 735 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), |
| 728 value_check.GetReceiverClassIdAt(0) == kSmiCid) { | 736 call); |
| 729 InsertBefore(call, | |
| 730 new CheckSmiInstr(value->Copy(), call->deopt_id()), | |
| 731 call->env(), | |
| 732 Definition::kEffect); | |
| 733 } else { | |
| 734 InsertBefore(call, | |
| 735 new CheckClassInstr(value->Copy(), | |
| 736 call->deopt_id(), | |
| 737 value_check), | |
| 738 call->env(), | |
| 739 Definition::kEffect); | |
| 740 } | |
| 741 } | 737 } |
| 742 | 738 |
| 743 Definition* array_op = | 739 Definition* array_op = new StoreIndexedInstr(new Value(array), |
| 744 new StoreIndexedInstr(array, index, value, | 740 new Value(index), |
| 745 needs_store_barrier, array_cid, call->deopt_id()); | 741 new Value(stored_value), |
| 746 call->ReplaceWith(array_op, current_iterator()); | 742 needs_store_barrier, |
| 747 RemovePushArguments(call); | 743 array_cid, |
| 744 call->deopt_id()); |
| 745 ReplaceCall(call, array_op); |
| 748 return true; | 746 return true; |
| 749 } | 747 } |
| 750 | 748 |
| 751 | 749 |
| 752 | 750 |
| 753 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 751 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 754 const intptr_t class_id = ReceiverClassId(call); | 752 const intptr_t class_id = ReceiverClassId(call); |
| 755 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. | 753 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. |
| 756 intptr_t deopt_id = Isolate::kNoDeoptId; | 754 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 757 switch (class_id) { | 755 switch (class_id) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 780 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 778 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| 781 ASSERT(call->HasICData()); | 779 ASSERT(call->HasICData()); |
| 782 const ICData& ic_data = *call->ic_data(); | 780 const ICData& ic_data = *call->ic_data(); |
| 783 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 781 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| 784 call->deopt_id() : Isolate::kNoDeoptId; | 782 call->deopt_id() : Isolate::kNoDeoptId; |
| 785 } | 783 } |
| 786 break; | 784 break; |
| 787 default: | 785 default: |
| 788 return false; | 786 return false; |
| 789 } | 787 } |
| 790 Value* array = NULL; | 788 Definition* array = call->ArgumentAt(0); |
| 791 Value* index = NULL; | 789 Definition* index = call->ArgumentAt(1); |
| 792 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 790 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| 793 Definition* array_op = | 791 Definition* array_op = |
| 794 new LoadIndexedInstr(array, | 792 new LoadIndexedInstr(new Value(array), |
| 795 index, | 793 new Value(index), |
| 796 FlowGraphCompiler::ElementSizeFor(array_cid), | 794 FlowGraphCompiler::ElementSizeFor(array_cid), |
| 797 array_cid, | 795 array_cid, |
| 798 deopt_id); | 796 deopt_id); |
| 799 call->ReplaceWith(array_op, current_iterator()); | 797 ReplaceCall(call, array_op); |
| 800 RemovePushArguments(call); | |
| 801 return true; | 798 return true; |
| 802 } | 799 } |
| 803 | 800 |
| 804 | 801 |
| 805 void FlowGraphOptimizer::InsertBefore(Instruction* next, | |
| 806 Instruction* instr, | |
| 807 Environment* env, | |
| 808 Definition::UseKind use_kind) { | |
| 809 if (env != NULL) env->DeepCopyTo(instr); | |
| 810 if (use_kind == Definition::kValue) { | |
| 811 ASSERT(instr->IsDefinition()); | |
| 812 instr->AsDefinition()->set_ssa_temp_index( | |
| 813 flow_graph_->alloc_ssa_temp_index()); | |
| 814 } | |
| 815 instr->InsertBefore(next); | |
| 816 } | |
| 817 | |
| 818 | |
| 819 void FlowGraphOptimizer::InsertAfter(Instruction* prev, | |
| 820 Instruction* instr, | |
| 821 Environment* env, | |
| 822 Definition::UseKind use_kind) { | |
| 823 if (env != NULL) env->DeepCopyTo(instr); | |
| 824 if (use_kind == Definition::kValue) { | |
| 825 ASSERT(instr->IsDefinition()); | |
| 826 instr->AsDefinition()->set_ssa_temp_index( | |
| 827 flow_graph_->alloc_ssa_temp_index()); | |
| 828 } | |
| 829 instr->InsertAfter(prev); | |
| 830 } | |
| 831 | |
| 832 | |
| 833 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 802 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 834 Token::Kind op_kind) { | 803 Token::Kind op_kind) { |
| 835 intptr_t operands_type = kIllegalCid; | 804 intptr_t operands_type = kIllegalCid; |
| 836 ASSERT(call->HasICData()); | 805 ASSERT(call->HasICData()); |
| 837 const ICData& ic_data = *call->ic_data(); | 806 const ICData& ic_data = *call->ic_data(); |
| 838 switch (op_kind) { | 807 switch (op_kind) { |
| 839 case Token::kADD: | 808 case Token::kADD: |
| 840 case Token::kSUB: | 809 case Token::kSUB: |
| 841 if (HasOnlyTwoSmis(ic_data)) { | 810 if (HasOnlyTwoSmis(ic_data)) { |
| 842 // Don't generate smi code if the IC data is marked because | 811 // Don't generate smi code if the IC data is marked because |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 case Token::kTRUNCDIV: | 888 case Token::kTRUNCDIV: |
| 920 if (HasOnlyTwoSmis(ic_data)) { | 889 if (HasOnlyTwoSmis(ic_data)) { |
| 921 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; | 890 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; |
| 922 operands_type = kSmiCid; | 891 operands_type = kSmiCid; |
| 923 } else { | 892 } else { |
| 924 return false; | 893 return false; |
| 925 } | 894 } |
| 926 break; | 895 break; |
| 927 default: | 896 default: |
| 928 UNREACHABLE(); | 897 UNREACHABLE(); |
| 929 }; | 898 } |
| 930 | 899 |
| 931 ASSERT(call->ArgumentCount() == 2); | 900 ASSERT(call->ArgumentCount() == 2); |
| 901 Definition* left = call->ArgumentAt(0); |
| 902 Definition* right = call->ArgumentAt(1); |
| 932 if (operands_type == kDoubleCid) { | 903 if (operands_type == kDoubleCid) { |
| 933 Value* left = call->ArgumentAt(0)->value(); | |
| 934 Value* right = call->ArgumentAt(1)->value(); | |
| 935 | |
| 936 // Check that either left or right are not a smi. Result or a | 904 // Check that either left or right are not a smi. Result or a |
| 937 // binary operation with two smis is a smi not a double. | 905 // binary operation with two smis is a smi not a double. |
| 938 InsertBefore(call, | 906 InsertBefore(call, |
| 939 new CheckEitherNonSmiInstr(left->Copy(), | 907 new CheckEitherNonSmiInstr(new Value(left), |
| 940 right->Copy(), | 908 new Value(right), |
| 941 call), | 909 call), |
| 942 call->env(), | 910 call->env(), |
| 943 Definition::kEffect); | 911 Definition::kEffect); |
| 944 | 912 |
| 945 BinaryDoubleOpInstr* double_bin_op = | 913 BinaryDoubleOpInstr* double_bin_op = |
| 946 new BinaryDoubleOpInstr(op_kind, left->Copy(), right->Copy(), call); | 914 new BinaryDoubleOpInstr(op_kind, new Value(left), new Value(right), |
| 947 call->ReplaceWith(double_bin_op, current_iterator()); | 915 call); |
| 948 RemovePushArguments(call); | 916 ReplaceCall(call, double_bin_op); |
| 949 } else if (operands_type == kMintCid) { | 917 } else if (operands_type == kMintCid) { |
| 950 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; | 918 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; |
| 951 Value* left = call->ArgumentAt(0)->value(); | |
| 952 Value* right = call->ArgumentAt(1)->value(); | |
| 953 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | 919 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { |
| 954 ShiftMintOpInstr* shift_op = | 920 ShiftMintOpInstr* shift_op = |
| 955 new ShiftMintOpInstr(op_kind, left, right, call); | 921 new ShiftMintOpInstr(op_kind, new Value(left), new Value(right), |
| 956 call->ReplaceWith(shift_op, current_iterator()); | 922 call); |
| 923 ReplaceCall(call, shift_op); |
| 957 } else { | 924 } else { |
| 958 BinaryMintOpInstr* bin_op = | 925 BinaryMintOpInstr* bin_op = |
| 959 new BinaryMintOpInstr(op_kind, left, right, call); | 926 new BinaryMintOpInstr(op_kind, new Value(left), new Value(right), |
| 960 call->ReplaceWith(bin_op, current_iterator()); | 927 call); |
| 928 ReplaceCall(call, bin_op); |
| 961 } | 929 } |
| 962 RemovePushArguments(call); | |
| 963 } else if (op_kind == Token::kMOD) { | 930 } else if (op_kind == Token::kMOD) { |
| 964 // TODO(vegorov): implement fast path code for modulo. | 931 // TODO(vegorov): implement fast path code for modulo. |
| 965 ASSERT(operands_type == kSmiCid); | 932 ASSERT(operands_type == kSmiCid); |
| 966 if (!call->ArgumentAt(1)->value()->BindsToConstant()) return false; | 933 if (!right->IsConstant()) return false; |
| 967 const Object& obj = call->ArgumentAt(1)->value()->BoundConstant(); | 934 const Object& obj = right->AsConstant()->value(); |
| 968 if (!obj.IsSmi()) return false; | 935 if (!obj.IsSmi()) return false; |
| 969 const intptr_t value = Smi::Cast(obj).Value(); | 936 const intptr_t value = Smi::Cast(obj).Value(); |
| 970 if ((value > 0) && Utils::IsPowerOfTwo(value)) { | 937 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; |
| 971 Value* left = call->ArgumentAt(0)->value(); | 938 |
| 972 // Insert smi check and attach a copy of the original | 939 // Insert smi check and attach a copy of the original environment |
| 973 // environment because the smi operation can still deoptimize. | 940 // because the smi operation can still deoptimize. |
| 974 InsertBefore(call, | 941 InsertBefore(call, |
| 975 new CheckSmiInstr(left->Copy(), call->deopt_id()), | 942 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 976 call->env(), | 943 call->env(), |
| 977 Definition::kEffect); | 944 Definition::kEffect); |
| 978 ConstantInstr* c = new ConstantInstr(Smi::Handle(Smi::New(value - 1))); | 945 ConstantInstr* constant = |
| 979 InsertBefore(call, c, NULL, Definition::kValue); | 946 new ConstantInstr(Smi::Handle(Smi::New(value - 1))); |
| 980 BinarySmiOpInstr* bin_op = | 947 InsertBefore(call, constant, NULL, Definition::kValue); |
| 981 new BinarySmiOpInstr(Token::kBIT_AND, call, left, new Value(c)); | 948 BinarySmiOpInstr* bin_op = |
| 982 call->ReplaceWith(bin_op, current_iterator()); | 949 new BinarySmiOpInstr(Token::kBIT_AND, call, |
| 983 RemovePushArguments(call); | 950 new Value(left), |
| 984 } else { | 951 new Value(constant)); |
| 985 // Did not replace. | 952 ReplaceCall(call, bin_op); |
| 986 return false; | |
| 987 } | |
| 988 } else { | 953 } else { |
| 989 ASSERT(operands_type == kSmiCid); | 954 ASSERT(operands_type == kSmiCid); |
| 990 Value* left = call->ArgumentAt(0)->value(); | |
| 991 Value* right = call->ArgumentAt(1)->value(); | |
| 992 // Insert two smi checks and attach a copy of the original | 955 // Insert two smi checks and attach a copy of the original |
| 993 // environment because the smi operation can still deoptimize. | 956 // environment because the smi operation can still deoptimize. |
| 994 InsertBefore(call, | 957 InsertBefore(call, |
| 995 new CheckSmiInstr(left->Copy(), call->deopt_id()), | 958 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 996 call->env(), | 959 call->env(), |
| 997 Definition::kEffect); | 960 Definition::kEffect); |
| 998 InsertBefore(call, | 961 InsertBefore(call, |
| 999 new CheckSmiInstr(right->Copy(), call->deopt_id()), | 962 new CheckSmiInstr(new Value(right), call->deopt_id()), |
| 1000 call->env(), | 963 call->env(), |
| 1001 Definition::kEffect); | 964 Definition::kEffect); |
| 1002 if (left->BindsToConstant() && | 965 if (left->IsConstant() && |
| 1003 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { | 966 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { |
| 1004 // Constant should be on the right side. | 967 // Constant should be on the right side. |
| 1005 Value* temp = left; | 968 Definition* temp = left; |
| 1006 left = right; | 969 left = right; |
| 1007 right = temp; | 970 right = temp; |
| 1008 } | 971 } |
| 1009 BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right); | 972 BinarySmiOpInstr* bin_op = |
| 1010 call->ReplaceWith(bin_op, current_iterator()); | 973 new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right)); |
| 1011 RemovePushArguments(call); | 974 ReplaceCall(call, bin_op); |
| 1012 } | 975 } |
| 1013 return true; | 976 return true; |
| 1014 } | 977 } |
| 1015 | 978 |
| 1016 | 979 |
| 1017 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 980 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| 1018 Token::Kind op_kind) { | 981 Token::Kind op_kind) { |
| 1019 ASSERT(call->ArgumentCount() == 1); | 982 ASSERT(call->ArgumentCount() == 1); |
| 983 Definition* input = call->ArgumentAt(0); |
| 1020 Definition* unary_op = NULL; | 984 Definition* unary_op = NULL; |
| 1021 if (HasOnlyOneSmi(*call->ic_data())) { | 985 if (HasOnlyOneSmi(*call->ic_data())) { |
| 1022 Value* value = call->ArgumentAt(0)->value(); | |
| 1023 InsertBefore(call, | 986 InsertBefore(call, |
| 1024 new CheckSmiInstr(value->Copy(), call->deopt_id()), | 987 new CheckSmiInstr(new Value(input), call->deopt_id()), |
| 1025 call->env(), | 988 call->env(), |
| 1026 Definition::kEffect); | 989 Definition::kEffect); |
| 1027 unary_op = new UnarySmiOpInstr(op_kind, call, value); | 990 unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input)); |
| 1028 } else if ((op_kind == Token::kBIT_NOT) && | 991 } else if ((op_kind == Token::kBIT_NOT) && |
| 1029 HasOnlySmiOrMint(*call->ic_data()) && | 992 HasOnlySmiOrMint(*call->ic_data()) && |
| 1030 FlowGraphCompiler::SupportsUnboxedMints()) { | 993 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1031 Value* value = call->ArgumentAt(0)->value(); | 994 unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call); |
| 1032 unary_op = new UnaryMintOpInstr(op_kind, value, call); | |
| 1033 } else if (HasOnlyOneDouble(*call->ic_data()) && | 995 } else if (HasOnlyOneDouble(*call->ic_data()) && |
| 1034 (op_kind == Token::kNEGATE)) { | 996 (op_kind == Token::kNEGATE)) { |
| 1035 Value* value = call->ArgumentAt(0)->value(); | 997 AddReceiverCheck(call); |
| 1036 AddCheckClass(call, value->Copy()); | |
| 1037 ConstantInstr* minus_one = | 998 ConstantInstr* minus_one = |
| 1038 new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1))); | 999 new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1))); |
| 1039 InsertBefore(call, minus_one, NULL, Definition::kValue); | 1000 InsertBefore(call, minus_one, NULL, Definition::kValue); |
| 1040 unary_op = new BinaryDoubleOpInstr(Token::kMUL, | 1001 unary_op = new BinaryDoubleOpInstr(Token::kMUL, |
| 1041 value, | 1002 new Value(input), |
| 1042 new Value(minus_one), | 1003 new Value(minus_one), |
| 1043 call); | 1004 call); |
| 1044 } | 1005 } |
| 1045 if (unary_op == NULL) return false; | 1006 if (unary_op == NULL) return false; |
| 1046 | 1007 |
| 1047 call->ReplaceWith(unary_op, current_iterator()); | 1008 ReplaceCall(call, unary_op); |
| 1048 RemovePushArguments(call); | |
| 1049 return true; | 1009 return true; |
| 1050 } | 1010 } |
| 1051 | 1011 |
| 1052 | 1012 |
| 1053 // Using field class | 1013 // Using field class |
| 1054 static RawField* GetField(intptr_t class_id, const String& field_name) { | 1014 static RawField* GetField(intptr_t class_id, const String& field_name) { |
| 1055 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); | 1015 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); |
| 1056 Field& field = Field::Handle(); | 1016 Field& field = Field::Handle(); |
| 1057 while (!cls.IsNull()) { | 1017 while (!cls.IsNull()) { |
| 1058 field = cls.LookupInstanceField(field_name); | 1018 field = cls.LookupInstanceField(field_name); |
| 1059 if (!field.IsNull()) { | 1019 if (!field.IsNull()) { |
| 1060 return field.raw(); | 1020 return field.raw(); |
| 1061 } | 1021 } |
| 1062 cls = cls.SuperClass(); | 1022 cls = cls.SuperClass(); |
| 1063 } | 1023 } |
| 1064 return Field::null(); | 1024 return Field::null(); |
| 1065 } | 1025 } |
| 1066 | 1026 |
| 1067 | 1027 |
| 1068 // Use CHA to determine if the call needs a class check: if the callee's | 1028 // Use CHA to determine if the call needs a class check: if the callee's |
| 1069 // receiver is the same as the caller's receiver and there are no overriden | 1029 // receiver is the same as the caller's receiver and there are no overriden |
| 1070 // callee functions, then no class check is needed. | 1030 // callee functions, then no class check is needed. |
| 1071 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( | 1031 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( |
| 1072 InstanceCallInstr* call) const { | 1032 InstanceCallInstr* call) const { |
| 1073 if (!FLAG_use_cha) return true; | 1033 if (!FLAG_use_cha) return true; |
| 1074 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); | 1034 Definition* callee_receiver = call->ArgumentAt(0); |
| 1075 ASSERT(callee_receiver != NULL); | 1035 ASSERT(callee_receiver != NULL); |
| 1076 const Function& function = flow_graph_->parsed_function().function(); | 1036 const Function& function = flow_graph_->parsed_function().function(); |
| 1077 if (function.IsDynamicFunction() && | 1037 if (function.IsDynamicFunction() && |
| 1078 callee_receiver->IsParameter() && | 1038 callee_receiver->IsParameter() && |
| 1079 (callee_receiver->AsParameter()->index() == 0)) { | 1039 (callee_receiver->AsParameter()->index() == 0)) { |
| 1080 return CHA::HasOverride(Class::Handle(function.Owner()), | 1040 return CHA::HasOverride(Class::Handle(function.Owner()), |
| 1081 call->function_name()); | 1041 call->function_name()); |
| 1082 } | 1042 } |
| 1083 return true; | 1043 return true; |
| 1084 } | 1044 } |
| 1085 | 1045 |
| 1086 | 1046 |
| 1087 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( | 1047 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( |
| 1088 InstanceCallInstr* call) const { | 1048 InstanceCallInstr* call) const { |
| 1089 if (!FLAG_use_cha) return true; | 1049 if (!FLAG_use_cha) return true; |
| 1090 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); | 1050 Definition* callee_receiver = call->ArgumentAt(0); |
| 1091 ASSERT(callee_receiver != NULL); | 1051 ASSERT(callee_receiver != NULL); |
| 1092 const Function& function = flow_graph_->parsed_function().function(); | 1052 const Function& function = flow_graph_->parsed_function().function(); |
| 1093 if (function.IsDynamicFunction() && | 1053 if (function.IsDynamicFunction() && |
| 1094 callee_receiver->IsParameter() && | 1054 callee_receiver->IsParameter() && |
| 1095 (callee_receiver->AsParameter()->index() == 0)) { | 1055 (callee_receiver->AsParameter()->index() == 0)) { |
| 1096 const String& field_name = | 1056 const String& field_name = |
| 1097 String::Handle(Field::NameFromGetter(call->function_name())); | 1057 String::Handle(Field::NameFromGetter(call->function_name())); |
| 1098 return CHA::HasOverride(Class::Handle(function.Owner()), field_name); | 1058 return CHA::HasOverride(Class::Handle(function.Owner()), field_name); |
| 1099 } | 1059 } |
| 1100 return true; | 1060 return true; |
| 1101 } | 1061 } |
| 1102 | 1062 |
| 1103 | 1063 |
| 1104 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 1064 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
| 1105 ASSERT(call->HasICData()); | 1065 ASSERT(call->HasICData()); |
| 1106 const ICData& ic_data = *call->ic_data(); | 1066 const ICData& ic_data = *call->ic_data(); |
| 1107 Function& target = Function::Handle(); | 1067 Function& target = Function::Handle(); |
| 1108 GrowableArray<intptr_t> class_ids; | 1068 GrowableArray<intptr_t> class_ids; |
| 1109 ic_data.GetCheckAt(0, &class_ids, &target); | 1069 ic_data.GetCheckAt(0, &class_ids, &target); |
| 1110 ASSERT(class_ids.length() == 1); | 1070 ASSERT(class_ids.length() == 1); |
| 1111 // Inline implicit instance getter. | 1071 // Inline implicit instance getter. |
| 1112 const String& field_name = | 1072 const String& field_name = |
| 1113 String::Handle(Field::NameFromGetter(call->function_name())); | 1073 String::Handle(Field::NameFromGetter(call->function_name())); |
| 1114 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 1074 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 1115 ASSERT(!field.IsNull()); | 1075 ASSERT(!field.IsNull()); |
| 1116 | 1076 |
| 1117 if (InstanceCallNeedsClassCheck(call)) { | 1077 if (InstanceCallNeedsClassCheck(call)) { |
| 1118 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1078 AddReceiverCheck(call); |
| 1119 } | 1079 } |
| 1120 // Detach environment from the original instruction because it can't | |
| 1121 // deoptimize. | |
| 1122 call->set_env(NULL); | |
| 1123 LoadFieldInstr* load = new LoadFieldInstr( | 1080 LoadFieldInstr* load = new LoadFieldInstr( |
| 1124 call->ArgumentAt(0)->value(), | 1081 new Value(call->ArgumentAt(0)), |
| 1125 field.Offset(), | 1082 field.Offset(), |
| 1126 AbstractType::ZoneHandle(field.type()), | 1083 AbstractType::ZoneHandle(field.type()), |
| 1127 field.is_final()); | 1084 field.is_final()); |
| 1128 call->ReplaceWith(load, current_iterator()); | 1085 // Detach environment from the original instruction because it can't |
| 1129 RemovePushArguments(call); | 1086 // deoptimize. |
| 1087 for (Environment::DeepIterator it(call->env()); !it.Done(); it.Advance()) { |
| 1088 it.CurrentValue()->RemoveFromUseList(); |
| 1089 } |
| 1090 call->set_env(NULL); |
| 1091 ReplaceCall(call, load); |
| 1130 } | 1092 } |
| 1131 | 1093 |
| 1132 | 1094 |
| 1133 void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call, | 1095 void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call, |
| 1134 intptr_t length_offset, | 1096 intptr_t length_offset, |
| 1135 bool is_immutable, | 1097 bool is_immutable, |
| 1136 MethodRecognizer::Kind kind) { | 1098 MethodRecognizer::Kind kind) { |
| 1137 // Check receiver class. | 1099 AddReceiverCheck(call); |
| 1138 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1139 | 1100 |
| 1140 LoadFieldInstr* load = new LoadFieldInstr( | 1101 LoadFieldInstr* load = new LoadFieldInstr( |
| 1141 call->ArgumentAt(0)->value(), | 1102 new Value(call->ArgumentAt(0)), |
| 1142 length_offset, | 1103 length_offset, |
| 1143 Type::ZoneHandle(Type::SmiType()), | 1104 Type::ZoneHandle(Type::SmiType()), |
| 1144 is_immutable); | 1105 is_immutable); |
| 1145 load->set_result_cid(kSmiCid); | 1106 load->set_result_cid(kSmiCid); |
| 1146 load->set_recognized_kind(kind); | 1107 load->set_recognized_kind(kind); |
| 1147 call->ReplaceWith(load, current_iterator()); | 1108 ReplaceCall(call, load); |
| 1148 RemovePushArguments(call); | |
| 1149 } | 1109 } |
| 1150 | 1110 |
| 1151 | 1111 |
| 1152 void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter( | 1112 void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter( |
| 1153 InstanceCallInstr* call) { | 1113 InstanceCallInstr* call) { |
| 1154 // Check receiver class. | 1114 AddReceiverCheck(call); |
| 1155 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1156 | 1115 |
| 1157 // TODO(srdjan): type of load should be GrowableObjectArrayType. | 1116 // TODO(srdjan): type of load should be GrowableObjectArrayType. |
| 1158 LoadFieldInstr* data_load = new LoadFieldInstr( | 1117 LoadFieldInstr* data_load = new LoadFieldInstr( |
| 1159 call->ArgumentAt(0)->value(), | 1118 new Value(call->ArgumentAt(0)), |
| 1160 Array::data_offset(), | 1119 Array::data_offset(), |
| 1161 Type::ZoneHandle(Type::DynamicType())); | 1120 Type::ZoneHandle(Type::DynamicType())); |
| 1162 data_load->set_result_cid(kArrayCid); | 1121 data_load->set_result_cid(kArrayCid); |
| 1163 InsertBefore(call, data_load, NULL, Definition::kValue); | 1122 InsertBefore(call, data_load, NULL, Definition::kValue); |
| 1164 | 1123 |
| 1165 LoadFieldInstr* length_load = new LoadFieldInstr( | 1124 LoadFieldInstr* length_load = new LoadFieldInstr( |
| 1166 new Value(data_load), | 1125 new Value(data_load), |
| 1167 Array::length_offset(), | 1126 Array::length_offset(), |
| 1168 Type::ZoneHandle(Type::SmiType())); | 1127 Type::ZoneHandle(Type::SmiType())); |
| 1169 length_load->set_result_cid(kSmiCid); | 1128 length_load->set_result_cid(kSmiCid); |
| 1170 length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength); | 1129 length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength); |
| 1171 | 1130 |
| 1172 call->ReplaceWith(length_load, current_iterator()); | 1131 ReplaceCall(call, length_load); |
| 1173 RemovePushArguments(call); | |
| 1174 } | 1132 } |
| 1175 | 1133 |
| 1176 | 1134 |
| 1177 static LoadFieldInstr* BuildLoadStringLength(Value* str) { | 1135 static LoadFieldInstr* BuildLoadStringLength(Definition* str) { |
| 1178 // Treat length loads as mutable (i.e. affected by side effects) to avoid | 1136 // Treat length loads as mutable (i.e. affected by side effects) to avoid |
| 1179 // hoisting them since we can't hoist the preceding class-check. This | 1137 // hoisting them since we can't hoist the preceding class-check. This |
| 1180 // is because of externalization of strings that affects their class-id. | 1138 // is because of externalization of strings that affects their class-id. |
| 1181 const bool is_immutable = false; | 1139 const bool is_immutable = false; |
| 1182 LoadFieldInstr* load = new LoadFieldInstr( | 1140 LoadFieldInstr* load = new LoadFieldInstr( |
| 1183 str, | 1141 new Value(str), |
| 1184 String::length_offset(), | 1142 String::length_offset(), |
| 1185 Type::ZoneHandle(Type::SmiType()), | 1143 Type::ZoneHandle(Type::SmiType()), |
| 1186 is_immutable); | 1144 is_immutable); |
| 1187 load->set_result_cid(kSmiCid); | 1145 load->set_result_cid(kSmiCid); |
| 1188 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); | 1146 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); |
| 1189 return load; | 1147 return load; |
| 1190 } | 1148 } |
| 1191 | 1149 |
| 1192 | 1150 |
| 1193 void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) { | 1151 void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) { |
| 1194 // Check receiver class. | 1152 AddReceiverCheck(call); |
| 1195 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1153 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)); |
| 1196 | 1154 ReplaceCall(call, load); |
| 1197 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value()); | |
| 1198 call->ReplaceWith(load, current_iterator()); | |
| 1199 RemovePushArguments(call); | |
| 1200 } | 1155 } |
| 1201 | 1156 |
| 1202 | 1157 |
| 1203 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { | 1158 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { |
| 1204 // Check receiver class. | 1159 AddReceiverCheck(call); |
| 1205 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1206 | 1160 |
| 1207 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value()); | 1161 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)); |
| 1208 InsertBefore(call, load, NULL, Definition::kValue); | 1162 InsertBefore(call, load, NULL, Definition::kValue); |
| 1209 | 1163 |
| 1210 ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0))); | 1164 ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0))); |
| 1211 InsertBefore(call, zero, NULL, Definition::kValue); | 1165 InsertBefore(call, zero, NULL, Definition::kValue); |
| 1212 | 1166 |
| 1213 StrictCompareInstr* compare = | 1167 StrictCompareInstr* compare = |
| 1214 new StrictCompareInstr(Token::kEQ_STRICT, | 1168 new StrictCompareInstr(Token::kEQ_STRICT, |
| 1215 new Value(load), | 1169 new Value(load), |
| 1216 new Value(zero)); | 1170 new Value(zero)); |
| 1217 call->ReplaceWith(compare, current_iterator()); | 1171 ReplaceCall(call, compare); |
| 1218 RemovePushArguments(call); | |
| 1219 } | 1172 } |
| 1220 | 1173 |
| 1221 | 1174 |
| 1222 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { | 1175 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { |
| 1223 switch (kind) { | 1176 switch (kind) { |
| 1224 case MethodRecognizer::kObjectArrayLength: | 1177 case MethodRecognizer::kObjectArrayLength: |
| 1225 case MethodRecognizer::kImmutableArrayLength: | 1178 case MethodRecognizer::kImmutableArrayLength: |
| 1226 return Array::length_offset(); | 1179 return Array::length_offset(); |
| 1227 case MethodRecognizer::kByteArrayBaseLength: | 1180 case MethodRecognizer::kByteArrayBaseLength: |
| 1228 return ByteArray::length_offset(); | 1181 return ByteArray::length_offset(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1299 default: | 1252 default: |
| 1300 ASSERT(recognized_kind == MethodRecognizer::kUnknown); | 1253 ASSERT(recognized_kind == MethodRecognizer::kUnknown); |
| 1301 } | 1254 } |
| 1302 return false; | 1255 return false; |
| 1303 } | 1256 } |
| 1304 | 1257 |
| 1305 | 1258 |
| 1306 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt( | 1259 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt( |
| 1307 InstanceCallInstr* call, | 1260 InstanceCallInstr* call, |
| 1308 intptr_t cid) { | 1261 intptr_t cid) { |
| 1309 Value* str = call->ArgumentAt(0)->value(); | 1262 Definition* str = call->ArgumentAt(0); |
| 1310 Value* index = call->ArgumentAt(1)->value(); | 1263 Definition* index = call->ArgumentAt(1); |
| 1311 AddCheckClass(call, str->Copy()); | 1264 AddReceiverCheck(call); |
| 1312 InsertBefore(call, | 1265 InsertBefore(call, |
| 1313 new CheckSmiInstr(index->Copy(), call->deopt_id()), | 1266 new CheckSmiInstr(new Value(index), call->deopt_id()), |
| 1314 call->env(), | 1267 call->env(), |
| 1315 Definition::kEffect); | 1268 Definition::kEffect); |
| 1316 // If both index and string are constants, then do a compile-time check. | 1269 // If both index and string are constants, then do a compile-time check. |
| 1317 // TODO(srdjan): Remove once constant propagation handles bounds checks. | 1270 // TODO(srdjan): Remove once constant propagation handles bounds checks. |
| 1318 bool skip_check = false; | 1271 bool skip_check = false; |
| 1319 if (str->BindsToConstant() && index->BindsToConstant()) { | 1272 if (str->IsConstant() && index->IsConstant()) { |
| 1320 ConstantInstr* string_def = str->definition()->AsConstant(); | |
| 1321 const String& constant_string = | 1273 const String& constant_string = |
| 1322 String::Cast(string_def->value()); | 1274 String::Cast(str->AsConstant()->value()); |
| 1323 ConstantInstr* index_def = index->definition()->AsConstant(); | 1275 const Object& constant_index = index->AsConstant()->value(); |
| 1324 if (index_def->value().IsSmi()) { | 1276 skip_check = constant_index.IsSmi() && |
| 1325 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); | 1277 (Smi::Cast(constant_index).Value() < constant_string.Length()); |
| 1326 skip_check = (constant_index < constant_string.Length()); | |
| 1327 } | |
| 1328 } | 1278 } |
| 1329 if (!skip_check) { | 1279 if (!skip_check) { |
| 1330 // Insert bounds check. | 1280 // Insert bounds check. |
| 1331 LoadFieldInstr* length = BuildLoadStringLength(str->Copy()); | 1281 LoadFieldInstr* length = BuildLoadStringLength(str); |
| 1332 InsertBefore(call, length, NULL, Definition::kValue); | 1282 InsertBefore(call, length, NULL, Definition::kValue); |
| 1333 InsertBefore(call, | 1283 InsertBefore(call, |
| 1334 new CheckArrayBoundInstr(new Value(length), | 1284 new CheckArrayBoundInstr(new Value(length), |
| 1335 index->Copy(), | 1285 new Value(index), |
| 1336 cid, | 1286 cid, |
| 1337 call), | 1287 call), |
| 1338 call->env(), | 1288 call->env(), |
| 1339 Definition::kEffect); | 1289 Definition::kEffect); |
| 1340 } | 1290 } |
| 1341 return new LoadIndexedInstr(str, | 1291 return new LoadIndexedInstr(new Value(str), |
| 1342 index, | 1292 new Value(index), |
| 1343 FlowGraphCompiler::ElementSizeFor(cid), | 1293 FlowGraphCompiler::ElementSizeFor(cid), |
| 1344 cid, | 1294 cid, |
| 1345 Isolate::kNoDeoptId); // Can't deoptimize. | 1295 Isolate::kNoDeoptId); // Can't deoptimize. |
| 1346 } | 1296 } |
| 1347 | 1297 |
| 1348 | 1298 |
| 1349 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 1299 void FlowGraphOptimizer::ReplaceWithMathCFunction( |
| 1350 InstanceCallInstr* call, | 1300 InstanceCallInstr* call, |
| 1351 MethodRecognizer::Kind recognized_kind) { | 1301 MethodRecognizer::Kind recognized_kind) { |
| 1352 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1302 AddReceiverCheck(call); |
| 1353 ZoneGrowableArray<Value*>* args = | 1303 ZoneGrowableArray<Value*>* args = |
| 1354 new ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1304 new ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1355 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1305 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1356 args->Add(call->ArgumentAt(i)->value()); | 1306 args->Add(new Value(call->ArgumentAt(i))); |
| 1357 } | 1307 } |
| 1358 InvokeMathCFunctionInstr* invoke = | 1308 InvokeMathCFunctionInstr* invoke = |
| 1359 new InvokeMathCFunctionInstr(args, call, recognized_kind); | 1309 new InvokeMathCFunctionInstr(args, call, recognized_kind); |
| 1360 call->ReplaceWith(invoke, current_iterator()); | 1310 ReplaceCall(call, invoke); |
| 1361 RemovePushArguments(call); | |
| 1362 } | 1311 } |
| 1363 | 1312 |
| 1364 | 1313 |
| 1365 static bool IsSupportedByteArrayCid(intptr_t cid) { | 1314 static bool IsSupportedByteArrayCid(intptr_t cid) { |
| 1366 switch (cid) { | 1315 switch (cid) { |
| 1367 case kInt8ArrayCid: | 1316 case kInt8ArrayCid: |
| 1368 case kUint8ArrayCid: | 1317 case kUint8ArrayCid: |
| 1369 case kUint8ClampedArrayCid: | 1318 case kUint8ClampedArrayCid: |
| 1370 case kExternalUint8ArrayCid: | 1319 case kExternalUint8ArrayCid: |
| 1371 case kExternalUint8ClampedArrayCid: | 1320 case kExternalUint8ClampedArrayCid: |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1413 return TryReplaceWithLoadIndexed(call); | 1362 return TryReplaceWithLoadIndexed(call); |
| 1414 default: | 1363 default: |
| 1415 break; | 1364 break; |
| 1416 } | 1365 } |
| 1417 | 1366 |
| 1418 if ((recognized_kind == MethodRecognizer::kStringBaseCharCodeAt) && | 1367 if ((recognized_kind == MethodRecognizer::kStringBaseCharCodeAt) && |
| 1419 (ic_data.NumberOfChecks() == 1) && | 1368 (ic_data.NumberOfChecks() == 1) && |
| 1420 ((class_ids[0] == kOneByteStringCid) || | 1369 ((class_ids[0] == kOneByteStringCid) || |
| 1421 (class_ids[0] == kTwoByteStringCid))) { | 1370 (class_ids[0] == kTwoByteStringCid))) { |
| 1422 LoadIndexedInstr* instr = BuildStringCharCodeAt(call, class_ids[0]); | 1371 LoadIndexedInstr* instr = BuildStringCharCodeAt(call, class_ids[0]); |
| 1423 call->ReplaceWith(instr, current_iterator()); | 1372 ReplaceCall(call, instr); |
| 1424 RemovePushArguments(call); | |
| 1425 return true; | 1373 return true; |
| 1426 } | 1374 } |
| 1427 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && | 1375 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && |
| 1428 (ic_data.NumberOfChecks() == 1) && | 1376 (ic_data.NumberOfChecks() == 1) && |
| 1429 (class_ids[0] == kOneByteStringCid)) { | 1377 (class_ids[0] == kOneByteStringCid)) { |
| 1430 // TODO(fschneider): Handle TwoByteString. | 1378 // TODO(fschneider): Handle TwoByteString. |
| 1431 LoadIndexedInstr* load_char_code = | 1379 LoadIndexedInstr* load_char_code = |
| 1432 BuildStringCharCodeAt(call, class_ids[0]); | 1380 BuildStringCharCodeAt(call, class_ids[0]); |
| 1433 InsertBefore(call, load_char_code, NULL, Definition::kValue); | 1381 InsertBefore(call, load_char_code, NULL, Definition::kValue); |
| 1434 StringFromCharCodeInstr* char_at = | 1382 StringFromCharCodeInstr* char_at = |
| 1435 new StringFromCharCodeInstr(new Value(load_char_code), | 1383 new StringFromCharCodeInstr(new Value(load_char_code), |
| 1436 kOneByteStringCid); | 1384 kOneByteStringCid); |
| 1437 call->ReplaceWith(char_at, current_iterator()); | 1385 ReplaceCall(call, char_at); |
| 1438 RemovePushArguments(call); | |
| 1439 return true; | 1386 return true; |
| 1440 } | 1387 } |
| 1441 | 1388 |
| 1442 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && | 1389 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && |
| 1443 (class_ids[0] == kSmiCid)) { | 1390 (class_ids[0] == kSmiCid)) { |
| 1444 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); | 1391 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); |
| 1445 call->ReplaceWith(s2d_instr, current_iterator()); | 1392 call->ReplaceWith(s2d_instr, current_iterator()); |
| 1446 // Pushed arguments are not removed because SmiToDouble is implemented | 1393 // Pushed arguments are not removed because SmiToDouble is implemented |
| 1447 // as a call. | 1394 // as a call. |
| 1448 return true; | 1395 return true; |
| 1449 } | 1396 } |
| 1450 | 1397 |
| 1451 if (class_ids[0] == kDoubleCid) { | 1398 if (class_ids[0] == kDoubleCid) { |
| 1452 switch (recognized_kind) { | 1399 switch (recognized_kind) { |
| 1453 case MethodRecognizer::kDoubleToInteger: { | 1400 case MethodRecognizer::kDoubleToInteger: { |
| 1454 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1401 AddReceiverCheck(call); |
| 1455 ASSERT(call->HasICData()); | 1402 ASSERT(call->HasICData()); |
| 1456 const ICData& ic_data = *call->ic_data(); | 1403 const ICData& ic_data = *call->ic_data(); |
| 1404 Definition* input = call->ArgumentAt(0); |
| 1457 Definition* d2i_instr = NULL; | 1405 Definition* d2i_instr = NULL; |
| 1458 if (ic_data.deopt_reason() == kDeoptDoubleToSmi) { | 1406 if (ic_data.deopt_reason() == kDeoptDoubleToSmi) { |
| 1459 // Do not repeatedly deoptimize because result didn't fit into Smi. | 1407 // Do not repeatedly deoptimize because result didn't fit into Smi. |
| 1460 d2i_instr = new DoubleToIntegerInstr(call->ArgumentAt(0)->value(), | 1408 d2i_instr = new DoubleToIntegerInstr(new Value(input), call); |
| 1461 call); | |
| 1462 } else { | 1409 } else { |
| 1463 // Optimistically assume result fits into Smi. | 1410 // Optimistically assume result fits into Smi. |
| 1464 d2i_instr = new DoubleToSmiInstr(call->ArgumentAt(0)->value(), call); | 1411 d2i_instr = new DoubleToSmiInstr(new Value(input), call); |
| 1465 } | 1412 } |
| 1466 call->ReplaceWith(d2i_instr, current_iterator()); | 1413 ReplaceCall(call, d2i_instr); |
| 1467 RemovePushArguments(call); | |
| 1468 return true; | 1414 return true; |
| 1469 } | 1415 } |
| 1470 case MethodRecognizer::kDoubleMod: | 1416 case MethodRecognizer::kDoubleMod: |
| 1471 case MethodRecognizer::kDoublePow: | 1417 case MethodRecognizer::kDoublePow: |
| 1472 ReplaceWithMathCFunction(call, recognized_kind); | 1418 ReplaceWithMathCFunction(call, recognized_kind); |
| 1473 return true; | 1419 return true; |
| 1474 case MethodRecognizer::kDoubleTruncate: | 1420 case MethodRecognizer::kDoubleTruncate: |
| 1475 case MethodRecognizer::kDoubleRound: | 1421 case MethodRecognizer::kDoubleRound: |
| 1476 case MethodRecognizer::kDoubleFloor: | 1422 case MethodRecognizer::kDoubleFloor: |
| 1477 case MethodRecognizer::kDoubleCeil: | 1423 case MethodRecognizer::kDoubleCeil: |
| 1478 if (!CPUFeatures::double_truncate_round_supported()) { | 1424 if (!CPUFeatures::double_truncate_round_supported()) { |
| 1479 ReplaceWithMathCFunction(call, recognized_kind); | 1425 ReplaceWithMathCFunction(call, recognized_kind); |
| 1480 } else { | 1426 } else { |
| 1481 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1427 AddReceiverCheck(call); |
| 1482 DoubleToDoubleInstr* d2d_instr = | 1428 DoubleToDoubleInstr* d2d_instr = |
| 1483 new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), | 1429 new DoubleToDoubleInstr(new Value(call->ArgumentAt(0)), |
| 1484 call, | 1430 call, |
| 1485 recognized_kind); | 1431 recognized_kind); |
| 1486 call->ReplaceWith(d2d_instr, current_iterator()); | 1432 ReplaceCall(call, d2d_instr); |
| 1487 RemovePushArguments(call); | |
| 1488 } | 1433 } |
| 1489 return true; | 1434 return true; |
| 1490 default: | 1435 default: |
| 1491 // Unsupported method. | 1436 // Unsupported method. |
| 1492 return false; | 1437 return false; |
| 1493 } | 1438 } |
| 1494 } | 1439 } |
| 1495 | 1440 |
| 1496 if (IsSupportedByteArrayCid(class_ids[0]) && | 1441 if (IsSupportedByteArrayCid(class_ids[0]) && |
| 1497 (ic_data.NumberOfChecks() == 1)) { | 1442 (ic_data.NumberOfChecks() == 1)) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1519 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); | 1464 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); |
| 1520 break; | 1465 break; |
| 1521 case MethodRecognizer::kByteArrayBaseGetFloat64: | 1466 case MethodRecognizer::kByteArrayBaseGetFloat64: |
| 1522 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); | 1467 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); |
| 1523 break; | 1468 break; |
| 1524 default: | 1469 default: |
| 1525 // Unsupported method. | 1470 // Unsupported method. |
| 1526 return false; | 1471 return false; |
| 1527 } | 1472 } |
| 1528 ASSERT(array_op != NULL); | 1473 ASSERT(array_op != NULL); |
| 1529 call->ReplaceWith(array_op, current_iterator()); | 1474 ReplaceCall(call, array_op); |
| 1530 RemovePushArguments(call); | |
| 1531 return true; | 1475 return true; |
| 1532 } | 1476 } |
| 1533 return false; | 1477 return false; |
| 1534 } | 1478 } |
| 1535 | 1479 |
| 1536 | 1480 |
| 1537 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( | 1481 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( |
| 1538 InstanceCallInstr* call, | 1482 InstanceCallInstr* call, |
| 1539 intptr_t receiver_cid, | 1483 intptr_t receiver_cid, |
| 1540 intptr_t view_cid) { | 1484 intptr_t view_cid) { |
| 1541 Value* array = call->ArgumentAt(0)->value(); | 1485 Definition* array = call->ArgumentAt(0); |
| 1542 Value* byte_index = call->ArgumentAt(1)->value(); | 1486 Definition* byte_index = call->ArgumentAt(1); |
| 1543 | 1487 |
| 1544 AddCheckClass(call, array->Copy()); | 1488 AddReceiverCheck(call); |
| 1545 const bool is_immutable = true; | 1489 const bool is_immutable = true; |
| 1546 LoadFieldInstr* length = new LoadFieldInstr( | 1490 LoadFieldInstr* length = new LoadFieldInstr( |
| 1547 array->Copy(), | 1491 new Value(array), |
| 1548 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), | 1492 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), |
| 1549 Type::ZoneHandle(Type::SmiType()), | 1493 Type::ZoneHandle(Type::SmiType()), |
| 1550 is_immutable); | 1494 is_immutable); |
| 1551 length->set_result_cid(kSmiCid); | 1495 length->set_result_cid(kSmiCid); |
| 1552 length->set_recognized_kind( | 1496 length->set_recognized_kind( |
| 1553 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); | 1497 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); |
| 1554 InsertBefore(call, length, NULL, Definition::kValue); | 1498 InsertBefore(call, length, NULL, Definition::kValue); |
| 1555 | 1499 |
| 1556 // len_in_bytes = length * kBytesPerElement(receiver) | 1500 // len_in_bytes = length * kBytesPerElement(receiver) |
| 1557 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | 1501 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); |
| 1558 ConstantInstr* bytes_per_element = | 1502 ConstantInstr* bytes_per_element = |
| 1559 new ConstantInstr(Smi::Handle(Smi::New(element_size))); | 1503 new ConstantInstr(Smi::Handle(Smi::New(element_size))); |
| 1560 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); | 1504 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); |
| 1561 BinarySmiOpInstr* len_in_bytes = | 1505 BinarySmiOpInstr* len_in_bytes = |
| 1562 new BinarySmiOpInstr(Token::kMUL, | 1506 new BinarySmiOpInstr(Token::kMUL, |
| 1563 call, | 1507 call, |
| 1564 new Value(length), | 1508 new Value(length), |
| 1565 new Value(bytes_per_element)); | 1509 new Value(bytes_per_element)); |
| 1566 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | 1510 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); |
| 1567 | 1511 |
| 1568 // Check byte_index < len_in_bytes. | 1512 // Check byte_index < len_in_bytes. |
| 1569 InsertBefore(call, | 1513 InsertBefore(call, |
| 1570 new CheckArrayBoundInstr(new Value(len_in_bytes), | 1514 new CheckArrayBoundInstr(new Value(len_in_bytes), |
| 1571 byte_index->Copy(), | 1515 new Value(byte_index), |
| 1572 receiver_cid, | 1516 receiver_cid, |
| 1573 call), | 1517 call), |
| 1574 call->env(), | 1518 call->env(), |
| 1575 Definition::kEffect); | 1519 Definition::kEffect); |
| 1576 | 1520 |
| 1577 // TODO(fschneider): Optimistically build smi load for Int32 and Uint32 | 1521 // TODO(fschneider): Optimistically build smi load for Int32 and Uint32 |
| 1578 // loads on ia32 like we do for normal array loads, and only revert to | 1522 // loads on ia32 like we do for normal array loads, and only revert to |
| 1579 // mint case after deoptimizing here. | 1523 // mint case after deoptimizing here. |
| 1580 return new LoadIndexedInstr(array, | 1524 return new LoadIndexedInstr(new Value(array), |
| 1581 byte_index, | 1525 new Value(byte_index), |
| 1582 1, // Index scale. | 1526 1, // Index scale. |
| 1583 view_cid, | 1527 view_cid, |
| 1584 Isolate::kNoDeoptId); // Can't deoptimize. | 1528 Isolate::kNoDeoptId); // Can't deoptimize. |
| 1585 } | 1529 } |
| 1586 | 1530 |
| 1587 | 1531 |
| 1588 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 1532 // Returns a Boolean constant if all classes in ic_data yield the same type-test |
| 1589 // result and the type tests do not depend on type arguments. Otherwise return | 1533 // result and the type tests do not depend on type arguments. Otherwise return |
| 1590 // Bool::null(). | 1534 // Bool::null(). |
| 1591 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 1535 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, |
| 1592 const AbstractType& type) const { | 1536 const AbstractType& type) const { |
| 1593 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 1537 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 1594 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); | 1538 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1610 if (is_subtype != prev.value()) return Bool::null(); | 1554 if (is_subtype != prev.value()) return Bool::null(); |
| 1611 } | 1555 } |
| 1612 } | 1556 } |
| 1613 return prev.raw(); | 1557 return prev.raw(); |
| 1614 } | 1558 } |
| 1615 | 1559 |
| 1616 | 1560 |
| 1617 // TODO(srdjan): Use ICData to check if always true or false. | 1561 // TODO(srdjan): Use ICData to check if always true or false. |
| 1618 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 1562 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 1619 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 1563 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 1620 Value* left_val = call->ArgumentAt(0)->value(); | 1564 Definition* left = call->ArgumentAt(0); |
| 1621 Value* instantiator_val = call->ArgumentAt(1)->value(); | 1565 Definition* instantiator = call->ArgumentAt(1); |
| 1622 Value* type_args_val = call->ArgumentAt(2)->value(); | 1566 Definition* type_args = call->ArgumentAt(2); |
| 1623 const AbstractType& type = | 1567 const AbstractType& type = |
| 1624 AbstractType::Cast(call->ArgumentAt(3)->value()->BoundConstant()); | 1568 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 1625 const bool negate = | 1569 const bool negate = |
| 1626 Bool::Cast(call->ArgumentAt(4)->value()->BoundConstant()).value(); | 1570 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); |
| 1627 const ICData& unary_checks = | 1571 const ICData& unary_checks = |
| 1628 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 1572 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 1629 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 1573 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 1630 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 1574 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); |
| 1631 if (!as_bool.IsNull()) { | 1575 if (!as_bool.IsNull()) { |
| 1632 AddCheckClass(call, left_val->Copy()); | 1576 AddReceiverCheck(call); |
| 1633 if (negate) { | 1577 if (negate) { |
| 1634 as_bool = as_bool.value() ? Bool::False().raw() : Bool::True().raw(); | 1578 as_bool = Bool::Get(!as_bool.value()); |
| 1635 } | 1579 } |
| 1636 ConstantInstr* bool_const = new ConstantInstr(as_bool); | 1580 ConstantInstr* bool_const = new ConstantInstr(as_bool); |
| 1637 call->ReplaceWith(bool_const, current_iterator()); | 1581 ReplaceCall(call, bool_const); |
| 1638 RemovePushArguments(call); | |
| 1639 return; | 1582 return; |
| 1640 } | 1583 } |
| 1641 } | 1584 } |
| 1642 InstanceOfInstr* instance_of = | 1585 InstanceOfInstr* instance_of = |
| 1643 new InstanceOfInstr(call->token_pos(), | 1586 new InstanceOfInstr(call->token_pos(), |
| 1644 left_val, | 1587 new Value(left), |
| 1645 instantiator_val, | 1588 new Value(instantiator), |
| 1646 type_args_val, | 1589 new Value(type_args), |
| 1647 type, | 1590 type, |
| 1648 negate); | 1591 negate); |
| 1649 call->ReplaceWith(instance_of, current_iterator()); | 1592 ReplaceCall(call, instance_of); |
| 1650 RemovePushArguments(call); | |
| 1651 } | 1593 } |
| 1652 | 1594 |
| 1653 | 1595 |
| 1654 // Tries to optimize instance call by replacing it with a faster instruction | 1596 // Tries to optimize instance call by replacing it with a faster instruction |
| 1655 // (e.g, binary op, field load, ..). | 1597 // (e.g, binary op, field load, ..). |
| 1656 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 1598 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 1657 if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) { | 1599 if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) { |
| 1658 // An instance call without ICData will trigger deoptimization. | |
| 1659 return; | 1600 return; |
| 1660 } | 1601 } |
| 1661 | 1602 |
| 1662 const Token::Kind op_kind = instr->token_kind(); | 1603 const Token::Kind op_kind = instr->token_kind(); |
| 1663 // Type test is special as it always gets converted into inlined code. | 1604 // Type test is special as it always gets converted into inlined code. |
| 1664 if (Token::IsTypeTestOperator(op_kind)) { | 1605 if (Token::IsTypeTestOperator(op_kind)) { |
| 1665 ReplaceWithInstanceOf(instr); | 1606 ReplaceWithInstanceOf(instr); |
| 1666 return; | 1607 return; |
| 1667 } | 1608 } |
| 1668 | 1609 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1716 call_with_checks); | 1657 call_with_checks); |
| 1717 instr->ReplaceWith(call, current_iterator()); | 1658 instr->ReplaceWith(call, current_iterator()); |
| 1718 return; | 1659 return; |
| 1719 } | 1660 } |
| 1720 } | 1661 } |
| 1721 | 1662 |
| 1722 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 1663 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 1723 bool call_with_checks; | 1664 bool call_with_checks; |
| 1724 if (has_one_target) { | 1665 if (has_one_target) { |
| 1725 // Type propagation has not run yet, we cannot eliminate the check. | 1666 // Type propagation has not run yet, we cannot eliminate the check. |
| 1726 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1667 AddReceiverCheck(instr); |
| 1727 // Call can still deoptimize, do not detach environment from instr. | 1668 // Call can still deoptimize, do not detach environment from instr. |
| 1728 call_with_checks = false; | 1669 call_with_checks = false; |
| 1729 } else { | 1670 } else { |
| 1730 call_with_checks = true; | 1671 call_with_checks = true; |
| 1731 } | 1672 } |
| 1732 PolymorphicInstanceCallInstr* call = | 1673 PolymorphicInstanceCallInstr* call = |
| 1733 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1674 new PolymorphicInstanceCallInstr(instr, unary_checks, |
| 1734 call_with_checks); | 1675 call_with_checks); |
| 1735 instr->ReplaceWith(call, current_iterator()); | 1676 instr->ReplaceWith(call, current_iterator()); |
| 1736 } | 1677 } |
| 1737 } | 1678 } |
| 1738 | 1679 |
| 1739 | 1680 |
| 1740 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1681 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 1741 MethodRecognizer::Kind recognized_kind = | 1682 MethodRecognizer::Kind recognized_kind = |
| 1742 MethodRecognizer::RecognizeKind(call->function()); | 1683 MethodRecognizer::RecognizeKind(call->function()); |
| 1743 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 1684 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 1744 MathSqrtInstr* sqrt = new MathSqrtInstr(call->ArgumentAt(0)->value(), call); | 1685 MathSqrtInstr* sqrt = |
| 1745 call->ReplaceWith(sqrt, current_iterator()); | 1686 new MathSqrtInstr(new Value(call->ArgumentAt(0)), call); |
| 1746 RemovePushArguments(call); | 1687 ReplaceCall(call, sqrt); |
| 1747 } | 1688 } |
| 1748 } | 1689 } |
| 1749 | 1690 |
| 1750 | 1691 |
| 1751 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 1692 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
| 1752 const ICData& unary_ic_data) { | 1693 const ICData& unary_ic_data) { |
| 1753 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 1694 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
| 1754 (unary_ic_data.num_args_tested() == 1)); | 1695 (unary_ic_data.num_args_tested() == 1)); |
| 1755 if (FLAG_enable_type_checks) { | 1696 if (FLAG_enable_type_checks) { |
| 1756 // TODO(srdjan): Add assignable check node if --enable_type_checks. | 1697 // TODO(srdjan): Add assignable check node if --enable_type_checks. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1774 // TODO(srdjan): Inline special setters. | 1715 // TODO(srdjan): Inline special setters. |
| 1775 return false; | 1716 return false; |
| 1776 } | 1717 } |
| 1777 // Inline implicit instance setter. | 1718 // Inline implicit instance setter. |
| 1778 const String& field_name = | 1719 const String& field_name = |
| 1779 String::Handle(Field::NameFromSetter(instr->function_name())); | 1720 String::Handle(Field::NameFromSetter(instr->function_name())); |
| 1780 const Field& field = Field::Handle(GetField(class_id, field_name)); | 1721 const Field& field = Field::Handle(GetField(class_id, field_name)); |
| 1781 ASSERT(!field.IsNull()); | 1722 ASSERT(!field.IsNull()); |
| 1782 | 1723 |
| 1783 if (InstanceCallNeedsClassCheck(instr)) { | 1724 if (InstanceCallNeedsClassCheck(instr)) { |
| 1784 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1725 AddReceiverCheck(instr); |
| 1785 } | 1726 } |
| 1786 bool needs_store_barrier = true; | 1727 bool needs_store_barrier = true; |
| 1787 if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) { | 1728 if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) { |
| 1788 InsertBefore(instr, | 1729 InsertBefore(instr, |
| 1789 new CheckSmiInstr(instr->ArgumentAt(1)->value()->Copy(), | 1730 new CheckSmiInstr(new Value(instr->ArgumentAt(1)), |
| 1790 instr->deopt_id()), | 1731 instr->deopt_id()), |
| 1791 instr->env(), | 1732 instr->env(), |
| 1792 Definition::kEffect); | 1733 Definition::kEffect); |
| 1793 needs_store_barrier = false; | 1734 needs_store_barrier = false; |
| 1794 } | 1735 } |
| 1736 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( |
| 1737 field, |
| 1738 new Value(instr->ArgumentAt(0)), |
| 1739 new Value(instr->ArgumentAt(1)), |
| 1740 needs_store_barrier); |
| 1795 // Detach environment from the original instruction because it can't | 1741 // Detach environment from the original instruction because it can't |
| 1796 // deoptimize. | 1742 // deoptimize. |
| 1743 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
| 1744 it.CurrentValue()->RemoveFromUseList(); |
| 1745 } |
| 1797 instr->set_env(NULL); | 1746 instr->set_env(NULL); |
| 1798 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( | 1747 ReplaceCall(instr, store); |
| 1799 field, | |
| 1800 instr->ArgumentAt(0)->value(), | |
| 1801 instr->ArgumentAt(1)->value(), | |
| 1802 needs_store_barrier); | |
| 1803 instr->ReplaceWith(store, current_iterator()); | |
| 1804 RemovePushArguments(instr); | |
| 1805 return true; | 1748 return true; |
| 1806 } | 1749 } |
| 1807 | 1750 |
| 1808 | 1751 |
| 1809 static void HandleRelationalOp(FlowGraphOptimizer* optimizer, | 1752 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { |
| 1810 RelationalOpInstr* comp, | |
| 1811 Instruction* instr) { | |
| 1812 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 1753 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 1813 return; | 1754 return; |
| 1814 } | 1755 } |
| 1815 const ICData& ic_data = *comp->ic_data(); | 1756 const ICData& ic_data = *comp->ic_data(); |
| 1757 Instruction* instr = current_iterator()->Current(); |
| 1816 if (ic_data.NumberOfChecks() == 1) { | 1758 if (ic_data.NumberOfChecks() == 1) { |
| 1817 ASSERT(ic_data.HasOneTarget()); | 1759 ASSERT(ic_data.HasOneTarget()); |
| 1818 if (HasOnlyTwoSmis(ic_data)) { | 1760 if (HasOnlyTwoSmis(ic_data)) { |
| 1819 optimizer->InsertBefore( | 1761 InsertBefore(instr, |
| 1820 instr, | 1762 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| 1821 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 1763 instr->env(), |
| 1822 instr->env(), | 1764 Definition::kEffect); |
| 1823 Definition::kEffect); | 1765 InsertBefore(instr, |
| 1824 optimizer->InsertBefore( | 1766 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| 1825 instr, | 1767 instr->env(), |
| 1826 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 1768 Definition::kEffect); |
| 1827 instr->env(), | |
| 1828 Definition::kEffect); | |
| 1829 comp->set_operands_class_id(kSmiCid); | 1769 comp->set_operands_class_id(kSmiCid); |
| 1830 } else if (ShouldSpecializeForDouble(ic_data)) { | 1770 } else if (ShouldSpecializeForDouble(ic_data)) { |
| 1831 comp->set_operands_class_id(kDoubleCid); | 1771 comp->set_operands_class_id(kDoubleCid); |
| 1832 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1772 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1833 FlowGraphCompiler::SupportsUnboxedMints()) { | 1773 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1834 comp->set_operands_class_id(kMintCid); | 1774 comp->set_operands_class_id(kMintCid); |
| 1835 } else { | 1775 } else { |
| 1836 ASSERT(comp->operands_class_id() == kIllegalCid); | 1776 ASSERT(comp->operands_class_id() == kIllegalCid); |
| 1837 } | 1777 } |
| 1838 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1778 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1839 FlowGraphCompiler::SupportsUnboxedMints()) { | 1779 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1840 comp->set_operands_class_id(kMintCid); | 1780 comp->set_operands_class_id(kMintCid); |
| 1841 } | 1781 } |
| 1842 } | 1782 } |
| 1843 | 1783 |
| 1844 | 1784 |
| 1845 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { | 1785 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { |
| 1846 HandleRelationalOp(this, instr, instr); | 1786 HandleRelationalOp(instr); |
| 1847 } | 1787 } |
| 1848 | 1788 |
| 1849 | 1789 |
| 1850 template <typename T> | 1790 template <typename T> |
| 1851 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, | 1791 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, |
| 1852 EqualityCompareInstr* comp, | 1792 T current_instruction) { |
| 1853 T instr, | |
| 1854 ForwardInstructionIterator* iterator) { | |
| 1855 // If one of the inputs is null, no ICdata will be collected. | 1793 // If one of the inputs is null, no ICdata will be collected. |
| 1856 if (comp->left()->BindsToConstantNull() || | 1794 if (comp->left()->BindsToConstantNull() || |
| 1857 comp->right()->BindsToConstantNull()) { | 1795 comp->right()->BindsToConstantNull()) { |
| 1858 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? | 1796 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? |
| 1859 Token::kEQ_STRICT : Token::kNE_STRICT; | 1797 Token::kEQ_STRICT : Token::kNE_STRICT; |
| 1860 StrictCompareInstr* strict_comp = | 1798 StrictCompareInstr* strict_comp = |
| 1861 new StrictCompareInstr(strict_kind, comp->left(), comp->right()); | 1799 new StrictCompareInstr(strict_kind, |
| 1862 instr->ReplaceWith(strict_comp, iterator); | 1800 comp->left()->Copy(), |
| 1801 comp->right()->Copy()); |
| 1802 current_instruction->ReplaceWith(strict_comp, current_iterator()); |
| 1863 return; | 1803 return; |
| 1864 } | 1804 } |
| 1865 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 1805 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 1866 return; | 1806 return; |
| 1867 } | 1807 } |
| 1868 ASSERT(comp->ic_data()->num_args_tested() == 2); | 1808 ASSERT(comp->ic_data()->num_args_tested() == 2); |
| 1869 if (comp->ic_data()->NumberOfChecks() == 1) { | 1809 if (comp->ic_data()->NumberOfChecks() == 1) { |
| 1870 GrowableArray<intptr_t> class_ids; | 1810 GrowableArray<intptr_t> class_ids; |
| 1871 Function& target = Function::Handle(); | 1811 Function& target = Function::Handle(); |
| 1872 comp->ic_data()->GetCheckAt(0, &class_ids, &target); | 1812 comp->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 1873 // TODO(srdjan): allow for mixed mode int/double comparison. | 1813 // TODO(srdjan): allow for mixed mode int/double comparison. |
| 1874 | 1814 |
| 1875 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { | 1815 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { |
| 1876 optimizer->InsertBefore( | 1816 InsertBefore(current_instruction, |
| 1877 instr, | 1817 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| 1878 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 1818 current_instruction->env(), |
| 1879 instr->env(), | 1819 Definition::kEffect); |
| 1880 Definition::kEffect); | 1820 InsertBefore(current_instruction, |
| 1881 optimizer->InsertBefore( | 1821 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| 1882 instr, | 1822 current_instruction->env(), |
| 1883 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 1823 Definition::kEffect); |
| 1884 instr->env(), | |
| 1885 Definition::kEffect); | |
| 1886 comp->set_receiver_class_id(kSmiCid); | 1824 comp->set_receiver_class_id(kSmiCid); |
| 1887 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { | 1825 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { |
| 1888 comp->set_receiver_class_id(kDoubleCid); | 1826 comp->set_receiver_class_id(kDoubleCid); |
| 1889 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1827 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1890 FlowGraphCompiler::SupportsUnboxedMints()) { | 1828 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1891 comp->set_receiver_class_id(kMintCid); | 1829 comp->set_receiver_class_id(kMintCid); |
| 1892 } else { | 1830 } else { |
| 1893 ASSERT(comp->receiver_class_id() == kIllegalCid); | 1831 ASSERT(comp->receiver_class_id() == kIllegalCid); |
| 1894 } | 1832 } |
| 1895 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1833 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1896 FlowGraphCompiler::SupportsUnboxedMints()) { | 1834 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1897 comp->set_receiver_class_id(kMintCid); | 1835 comp->set_receiver_class_id(kMintCid); |
| 1898 } | 1836 } |
| 1899 | 1837 |
| 1900 if (comp->receiver_class_id() != kIllegalCid) { | 1838 if (comp->receiver_class_id() != kIllegalCid) { |
| 1901 // Done. | 1839 // Done. |
| 1902 return; | 1840 return; |
| 1903 } | 1841 } |
| 1904 | 1842 |
| 1905 // Check if ICDData contains checks with Smi/Null combinations. In that case | 1843 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 1906 // we can still emit the optimized Smi equality operation but need to add | 1844 // we can still emit the optimized Smi equality operation but need to add |
| 1907 // checks for null or Smi. | 1845 // checks for null or Smi. |
| 1908 // TODO(srdjan): Add it for Double and Mint. | 1846 // TODO(srdjan): Add it for Double and Mint. |
| 1909 GrowableArray<intptr_t> smi_or_null(2); | 1847 GrowableArray<intptr_t> smi_or_null(2); |
| 1910 smi_or_null.Add(kSmiCid); | 1848 smi_or_null.Add(kSmiCid); |
| 1911 smi_or_null.Add(kNullCid); | 1849 smi_or_null.Add(kNullCid); |
| 1912 if (ICDataHasOnlyReceiverArgumentClassIds( | 1850 if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(), |
| 1913 *comp->ic_data(), smi_or_null, smi_or_null)) { | 1851 smi_or_null, |
| 1852 smi_or_null)) { |
| 1914 const ICData& unary_checks_0 = | 1853 const ICData& unary_checks_0 = |
| 1915 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 1854 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 1916 const intptr_t deopt_id = comp->deopt_id(); | 1855 AddCheckClass(comp->left()->definition(), |
| 1917 if ((unary_checks_0.NumberOfChecks() == 1) && | 1856 unary_checks_0, |
| 1918 (unary_checks_0.GetReceiverClassIdAt(0) == kSmiCid)) { | 1857 comp->deopt_id(), |
| 1919 // Smi only. | 1858 current_instruction->env(), |
| 1920 optimizer->InsertBefore( | 1859 current_instruction); |
| 1921 instr, | |
| 1922 new CheckSmiInstr(comp->left()->Copy(), deopt_id), | |
| 1923 instr->env(), | |
| 1924 Definition::kEffect); | |
| 1925 } else { | |
| 1926 // Smi or NULL. | |
| 1927 optimizer->InsertBefore( | |
| 1928 instr, | |
| 1929 new CheckClassInstr(comp->left()->Copy(), deopt_id, unary_checks_0), | |
| 1930 instr->env(), | |
| 1931 Definition::kEffect); | |
| 1932 } | |
| 1933 | 1860 |
| 1934 const ICData& unary_checks_1 = | 1861 const ICData& unary_checks_1 = |
| 1935 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | 1862 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1936 if ((unary_checks_1.NumberOfChecks() == 1) && | 1863 AddCheckClass(comp->right()->definition(), |
| 1937 (unary_checks_1.GetReceiverClassIdAt(0) == kSmiCid)) { | 1864 unary_checks_1, |
| 1938 // Smi only. | 1865 comp->deopt_id(), |
| 1939 optimizer->InsertBefore( | 1866 current_instruction->env(), |
| 1940 instr, | 1867 current_instruction); |
| 1941 new CheckSmiInstr(comp->right()->Copy(), deopt_id), | |
| 1942 instr->env(), | |
| 1943 Definition::kEffect); | |
| 1944 } else { | |
| 1945 // Smi or NULL. | |
| 1946 optimizer->InsertBefore( | |
| 1947 instr, | |
| 1948 new CheckClassInstr(comp->right()->Copy(), deopt_id, unary_checks_1), | |
| 1949 instr->env(), | |
| 1950 Definition::kEffect); | |
| 1951 } | |
| 1952 comp->set_receiver_class_id(kSmiCid); | 1868 comp->set_receiver_class_id(kSmiCid); |
| 1953 } | 1869 } |
| 1954 } | 1870 } |
| 1955 | 1871 |
| 1956 | 1872 |
| 1957 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | 1873 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 1958 HandleEqualityCompare(this, instr, instr, current_iterator()); | 1874 HandleEqualityCompare(instr, instr); |
| 1959 } | 1875 } |
| 1960 | 1876 |
| 1961 | 1877 |
| 1962 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | 1878 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
| 1963 ComparisonInstr* comparison = instr->comparison(); | 1879 ComparisonInstr* comparison = instr->comparison(); |
| 1964 if (comparison->IsRelationalOp()) { | 1880 if (comparison->IsRelationalOp()) { |
| 1965 HandleRelationalOp(this, comparison->AsRelationalOp(), instr); | 1881 HandleRelationalOp(comparison->AsRelationalOp()); |
| 1966 } else if (comparison->IsEqualityCompare()) { | 1882 } else if (comparison->IsEqualityCompare()) { |
| 1967 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr, | 1883 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); |
| 1968 current_iterator()); | |
| 1969 } else { | 1884 } else { |
| 1970 ASSERT(comparison->IsStrictCompare()); | 1885 ASSERT(comparison->IsStrictCompare()); |
| 1971 // Nothing to do. | 1886 // Nothing to do. |
| 1972 } | 1887 } |
| 1973 } | 1888 } |
| 1974 | 1889 |
| 1975 | 1890 |
| 1976 static bool MayBeBoxableNumber(intptr_t cid) { | 1891 static bool MayBeBoxableNumber(intptr_t cid) { |
| 1977 return (cid == kDynamicCid) || | 1892 return (cid == kDynamicCid) || |
| 1978 (cid == kMintCid) || | 1893 (cid == kMintCid) || |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2245 } | 2160 } |
| 2246 } | 2161 } |
| 2247 | 2162 |
| 2248 | 2163 |
| 2249 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, | 2164 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, |
| 2250 Range* constraint_range, | 2165 Range* constraint_range, |
| 2251 Instruction* after) { | 2166 Instruction* after) { |
| 2252 // No need to constrain constants. | 2167 // No need to constrain constants. |
| 2253 if (defn->IsConstant()) return NULL; | 2168 if (defn->IsConstant()) return NULL; |
| 2254 | 2169 |
| 2255 Value* value = new Value(defn); | 2170 ConstraintInstr* constraint = |
| 2256 ConstraintInstr* constraint = new ConstraintInstr(value, constraint_range); | 2171 new ConstraintInstr(new Value(defn), constraint_range); |
| 2257 constraint->InsertAfter(after); | 2172 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue); |
| 2258 constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 2173 RenameDominatedUses(defn, constraint, constraint); |
| 2259 RenameDominatedUses(defn, after, constraint); | |
| 2260 constraints_.Add(constraint); | 2174 constraints_.Add(constraint); |
| 2261 value->set_instruction(constraint); | |
| 2262 value->set_use_index(0); | |
| 2263 defn->AddInputUse(value); | |
| 2264 return constraint; | 2175 return constraint; |
| 2265 } | 2176 } |
| 2266 | 2177 |
| 2267 | 2178 |
| 2268 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { | 2179 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { |
| 2269 BranchInstr* branch = use->instruction()->AsBranch(); | 2180 BranchInstr* branch = use->instruction()->AsBranch(); |
| 2270 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); | 2181 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); |
| 2271 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { | 2182 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { |
| 2272 // Found comparison of two smis. Constrain defn at true and false | 2183 // Found comparison of two smis. Constrain defn at true and false |
| 2273 // successors using the other operand as a boundary. | 2184 // successors using the other operand as a boundary. |
| (...skipping 1938 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4212 !defn->IsPushArgument() && | 4123 !defn->IsPushArgument() && |
| 4213 !defn->IsStoreIndexed() && | 4124 !defn->IsStoreIndexed() && |
| 4214 !defn->IsStoreInstanceField() && | 4125 !defn->IsStoreInstanceField() && |
| 4215 !defn->IsStoreStaticField() && | 4126 !defn->IsStoreStaticField() && |
| 4216 !defn->IsStoreVMField()) { | 4127 !defn->IsStoreVMField()) { |
| 4217 if (FLAG_trace_constant_propagation) { | 4128 if (FLAG_trace_constant_propagation) { |
| 4218 OS::Print("Constant v%"Pd" = %s\n", | 4129 OS::Print("Constant v%"Pd" = %s\n", |
| 4219 defn->ssa_temp_index(), | 4130 defn->ssa_temp_index(), |
| 4220 defn->constant_value().ToCString()); | 4131 defn->constant_value().ToCString()); |
| 4221 } | 4132 } |
| 4222 i.ReplaceCurrentWith(new ConstantInstr(defn->constant_value())); | 4133 defn->ReplaceWith(new ConstantInstr(defn->constant_value()), &i); |
| 4223 } | 4134 } |
| 4224 } | 4135 } |
| 4225 | 4136 |
| 4226 // Replace branches where one target is unreachable with jumps. | 4137 // Replace branches where one target is unreachable with jumps. |
| 4227 BranchInstr* branch = block->last_instruction()->AsBranch(); | 4138 BranchInstr* branch = block->last_instruction()->AsBranch(); |
| 4228 if (branch != NULL) { | 4139 if (branch != NULL) { |
| 4229 TargetEntryInstr* if_true = branch->true_successor(); | 4140 TargetEntryInstr* if_true = branch->true_successor(); |
| 4230 TargetEntryInstr* if_false = branch->false_successor(); | 4141 TargetEntryInstr* if_false = branch->false_successor(); |
| 4231 JoinEntryInstr* join = NULL; | 4142 JoinEntryInstr* join = NULL; |
| 4232 Instruction* next = NULL; | 4143 Instruction* next = NULL; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4275 | 4186 |
| 4276 if (FLAG_trace_constant_propagation) { | 4187 if (FLAG_trace_constant_propagation) { |
| 4277 OS::Print("\n==== After constant propagation ====\n"); | 4188 OS::Print("\n==== After constant propagation ====\n"); |
| 4278 FlowGraphPrinter printer(*graph_); | 4189 FlowGraphPrinter printer(*graph_); |
| 4279 printer.PrintBlocks(); | 4190 printer.PrintBlocks(); |
| 4280 } | 4191 } |
| 4281 } | 4192 } |
| 4282 | 4193 |
| 4283 | 4194 |
| 4284 } // namespace dart | 4195 } // namespace dart |
| OLD | NEW |