Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/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()->ResultCid(); | 87 intptr_t cid = call->PushArgumentAt(i)->value()->ResultCid(); |
| 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()->ResultCid(); | 153 const intptr_t receiver_cid = call->PushArgumentAt(0)->value()->ResultCid(); |
| 154 if (receiver_cid == kDynamicCid) { | 154 if (receiver_cid == kDynamicCid) { |
| 155 return; // No information about receiver was infered. | 155 return; // No information about receiver was infered. |
| 156 } | 156 } |
| 157 | 157 |
| 158 const ICData& ic_data = SpecializeICData(call->ic_data(), receiver_cid); | 158 const ICData& ic_data = SpecializeICData(call->ic_data(), receiver_cid); |
| 159 | 159 |
| 160 const bool with_checks = false; | 160 const bool with_checks = false; |
| 161 PolymorphicInstanceCallInstr* specialized = | 161 PolymorphicInstanceCallInstr* specialized = |
| 162 new PolymorphicInstanceCallInstr(call->instance_call(), | 162 new PolymorphicInstanceCallInstr(call->instance_call(), |
| 163 ic_data, | 163 ic_data, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 Representation to, | 227 Representation to, |
| 228 Value* use, | 228 Value* use, |
| 229 Instruction* insert_before, | 229 Instruction* insert_before, |
| 230 Instruction* deopt_target) { | 230 Instruction* deopt_target) { |
| 231 Definition* converted = NULL; | 231 Definition* converted = NULL; |
| 232 if ((from == kTagged) && (to == kUnboxedMint)) { | 232 if ((from == kTagged) && (to == kUnboxedMint)) { |
| 233 ASSERT((deopt_target != NULL) || | 233 ASSERT((deopt_target != NULL) || |
| 234 (use->definition()->GetPropagatedCid() == kDoubleCid)); | 234 (use->definition()->GetPropagatedCid() == kDoubleCid)); |
| 235 const intptr_t deopt_id = (deopt_target != NULL) ? | 235 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 236 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 236 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 237 converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id); | 237 converted = new UnboxIntegerInstr(use->Copy(), deopt_id); |
| 238 | |
| 238 } else if ((from == kUnboxedMint) && (to == kTagged)) { | 239 } else if ((from == kUnboxedMint) && (to == kTagged)) { |
| 239 converted = new BoxIntegerInstr(new Value(use->definition())); | 240 converted = new BoxIntegerInstr(use->Copy()); |
| 241 | |
| 240 } else if (from == kUnboxedMint && to == kUnboxedDouble) { | 242 } else if (from == kUnboxedMint && to == kUnboxedDouble) { |
| 241 // Convert by boxing/unboxing. | 243 // Convert by boxing/unboxing. |
| 242 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. | 244 // TODO(fschneider): Implement direct unboxed mint-to-double conversion. |
| 243 BoxIntegerInstr* boxed = new BoxIntegerInstr(new Value(use->definition())); | 245 BoxIntegerInstr* boxed = new BoxIntegerInstr(use->Copy()); |
| 246 use->RemoveFromUseList(); | |
| 247 use->set_definition(boxed); | |
| 248 boxed->AddInputUse(use); | |
|
Vyacheslav Egorov (Google)
2013/02/08 16:44:49
I don't think these three lines are needed. You ca
Kevin Millikin (Google)
2013/02/19 10:49:30
You are right. Thank you.
| |
| 244 InsertBefore(insert_before, boxed, NULL, Definition::kValue); | 249 InsertBefore(insert_before, boxed, NULL, Definition::kValue); |
| 250 | |
| 245 const intptr_t deopt_id = (deopt_target != NULL) ? | 251 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 246 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 252 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 247 converted = new UnboxDoubleInstr(new Value(boxed), deopt_id); | 253 converted = new UnboxDoubleInstr(new Value(boxed), deopt_id); |
| 254 | |
| 248 } else if ((from == kUnboxedDouble) && (to == kTagged)) { | 255 } else if ((from == kUnboxedDouble) && (to == kTagged)) { |
| 249 converted = new BoxDoubleInstr(new Value(use->definition()), NULL); | 256 converted = new BoxDoubleInstr(use->Copy(), NULL); |
| 257 | |
| 250 } else if ((from == kTagged) && (to == kUnboxedDouble)) { | 258 } else if ((from == kTagged) && (to == kUnboxedDouble)) { |
| 259 ASSERT((deopt_target != NULL) || | |
| 260 (use->definition()->GetPropagatedCid() == kDoubleCid)); | |
| 251 const intptr_t deopt_id = (deopt_target != NULL) ? | 261 const intptr_t deopt_id = (deopt_target != NULL) ? |
| 252 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; | 262 deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId; |
| 253 ASSERT((deopt_target != NULL) || | |
| 254 (use->definition()->GetPropagatedCid() == kDoubleCid)); | |
| 255 ConstantInstr* constant = use->definition()->AsConstant(); | 263 ConstantInstr* constant = use->definition()->AsConstant(); |
| 256 if ((constant != NULL) && constant->value().IsSmi()) { | 264 if ((constant != NULL) && constant->value().IsSmi()) { |
| 257 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); | 265 const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue(); |
| 258 const Double& dbl_obj = | 266 const Double& dbl_obj = |
| 259 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); | 267 Double::ZoneHandle(Double::New(dbl_val, Heap::kOld)); |
| 260 ConstantInstr* double_const = new ConstantInstr(dbl_obj); | 268 ConstantInstr* double_const = new ConstantInstr(dbl_obj); |
| 261 InsertBefore(insert_before, double_const, NULL, Definition::kValue); | 269 InsertBefore(insert_before, double_const, NULL, Definition::kValue); |
| 262 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); | 270 converted = new UnboxDoubleInstr(new Value(double_const), deopt_id); |
| 263 } else { | 271 } else { |
| 264 converted = new UnboxDoubleInstr(new Value(use->definition()), deopt_id); | 272 converted = new UnboxDoubleInstr(use->Copy(), deopt_id); |
| 265 } | 273 } |
| 266 } | 274 } |
| 267 ASSERT(converted != NULL); | 275 ASSERT(converted != NULL); |
| 276 use->RemoveFromUseList(); | |
| 277 use->set_definition(converted); | |
| 278 converted->AddInputUse(use); | |
| 268 InsertBefore(insert_before, converted, use->instruction()->env(), | 279 InsertBefore(insert_before, converted, use->instruction()->env(), |
| 269 Definition::kValue); | 280 Definition::kValue); |
| 270 use->set_definition(converted); | |
| 271 } | 281 } |
| 272 | 282 |
| 273 | 283 |
| 274 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { | 284 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
| 275 const Representation from_rep = def->representation(); | 285 const Representation from_rep = def->representation(); |
| 276 | 286 |
| 277 for (Value::Iterator it(def->input_use_list()); | 287 for (Value::Iterator it(def->input_use_list()); |
| 278 !it.Done(); | 288 !it.Done(); |
| 279 it.Advance()) { | 289 it.Advance()) { |
| 280 Value* use = it.Current(); | 290 Value* use = it.Current(); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 452 } | 462 } |
| 453 | 463 |
| 454 // Check that it have seen only smis and doubles. | 464 // Check that it have seen only smis and doubles. |
| 455 GrowableArray<intptr_t> class_ids(2); | 465 GrowableArray<intptr_t> class_ids(2); |
| 456 class_ids.Add(kSmiCid); | 466 class_ids.Add(kSmiCid); |
| 457 class_ids.Add(kDoubleCid); | 467 class_ids.Add(kDoubleCid); |
| 458 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); | 468 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
| 459 } | 469 } |
| 460 | 470 |
| 461 | 471 |
| 462 static void RemovePushArguments(InstanceCallInstr* call) { | 472 void FlowGraphOptimizer::ReplaceCall(Definition* call, |
| 463 // Remove original push arguments. | 473 Definition* replacement) { |
| 474 // Remove the original push arguments. | |
| 464 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 475 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 465 PushArgumentInstr* push = call->ArgumentAt(i); | 476 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 466 push->ReplaceUsesWith(push->value()->definition()); | 477 push->ReplaceUsesWith(push->value()->definition()); |
| 478 push->UnuseAllInputs(); | |
| 467 push->RemoveFromGraph(); | 479 push->RemoveFromGraph(); |
| 468 } | 480 } |
| 481 call->ReplaceWith(replacement, current_iterator()); | |
| 469 } | 482 } |
| 470 | 483 |
| 471 | 484 |
| 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) { | 485 static intptr_t ReceiverClassId(InstanceCallInstr* call) { |
| 483 if (!call->HasICData()) return kIllegalCid; | 486 if (!call->HasICData()) return kIllegalCid; |
| 484 | 487 |
| 485 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); | 488 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); |
| 486 | 489 |
| 487 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; | 490 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; |
| 488 // TODO(vegorov): Add multiple receiver type support. | 491 // TODO(vegorov): Add multiple receiver type support. |
| 489 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; | 492 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; |
| 490 ASSERT(ic_data.HasOneTarget()); | 493 ASSERT(ic_data.HasOneTarget()); |
| 491 | 494 |
| 492 Function& target = Function::Handle(); | 495 Function& target = Function::Handle(); |
| 493 intptr_t class_id; | 496 intptr_t class_id; |
| 494 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 497 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 495 return class_id; | 498 return class_id; |
| 496 } | 499 } |
| 497 | 500 |
| 498 | 501 |
| 499 void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call, | 502 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, |
| 500 Value* value) { | 503 const ICData& unary_checks, |
| 504 intptr_t deopt_id, | |
| 505 Environment* deopt_environment, | |
| 506 Instruction* insert_before) { | |
| 501 // Type propagation has not run yet, we cannot eliminate the check. | 507 // 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; | 508 Instruction* check = NULL; |
| 505 if ((unary_checks.NumberOfChecks() == 1) && | 509 if ((unary_checks.NumberOfChecks() == 1) && |
| 506 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { | 510 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { |
| 507 check = new CheckSmiInstr(value, call->deopt_id()); | 511 check = new CheckSmiInstr(new Value(to_check), deopt_id); |
| 508 } else { | 512 } else { |
| 509 check = new CheckClassInstr(value, call->deopt_id(), unary_checks); | 513 check = new CheckClassInstr(new Value(to_check), deopt_id, unary_checks); |
| 510 } | 514 } |
| 511 InsertBefore(call, check, call->env(), Definition::kEffect); | 515 InsertBefore(insert_before, check, deopt_environment, Definition::kEffect); |
| 512 } | 516 } |
| 513 | 517 |
| 514 | 518 |
| 519 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { | |
| 520 AddCheckClass(call->ArgumentAt(0), | |
| 521 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()), | |
| 522 call->deopt_id(), | |
| 523 call->env(), | |
| 524 call); | |
| 525 } | |
| 526 | |
| 527 | |
| 515 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { | 528 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { |
| 516 ASSERT(ic_data.num_args_tested() > arg_n); | 529 ASSERT(ic_data.num_args_tested() > arg_n); |
| 517 if (ic_data.NumberOfChecks() == 0) return false; | 530 if (ic_data.NumberOfChecks() == 0) return false; |
| 518 GrowableArray<intptr_t> class_ids; | 531 GrowableArray<intptr_t> class_ids; |
| 519 Function& target = Function::Handle(); | 532 Function& target = Function::Handle(); |
| 520 const intptr_t len = ic_data.NumberOfChecks(); | 533 const intptr_t len = ic_data.NumberOfChecks(); |
| 521 for (intptr_t i = 0; i < len; i++) { | 534 for (intptr_t i = 0; i < len; i++) { |
| 522 ic_data.GetCheckAt(i, &class_ids, &target); | 535 ic_data.GetCheckAt(i, &class_ids, &target); |
| 523 if (class_ids[arg_n] != kSmiCid) return false; | 536 if (class_ids[arg_n] != kSmiCid) return false; |
| 524 } | 537 } |
| 525 return true; | 538 return true; |
| 526 } | 539 } |
| 527 | 540 |
| 528 | 541 |
| 529 // Returns array classid to load from, array and index value | 542 // Returns array classid to load from, array and index value |
| 530 | 543 |
| 531 intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call, | 544 intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call, |
| 532 intptr_t class_id, | 545 intptr_t class_id, |
| 533 Value** array, | 546 Definition** array, |
| 534 Value** index) { | 547 Definition** index) { |
|
Vyacheslav Egorov (Google)
2013/02/08 16:44:49
it seems the index is not assigned in the body any
| |
| 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 | 548 // Insert class check and index smi checks and attach a copy of the |
| 538 // original environment because the operation can still deoptimize. | 549 // original environment because the operation can still deoptimize. |
| 539 AddCheckClass(call, (*array)->Copy()); | 550 AddReceiverCheck(call); |
| 540 InsertBefore(call, | 551 InsertBefore(call, |
| 541 new CheckSmiInstr((*index)->Copy(), call->deopt_id()), | 552 new CheckSmiInstr(new Value(*index), call->deopt_id()), |
| 542 call->env(), | 553 call->env(), |
| 543 Definition::kEffect); | 554 Definition::kEffect); |
| 555 | |
| 544 // If both index and array are constants, then do a compile-time check. | 556 // If both index and array are constants, then do a compile-time check. |
| 545 // TODO(srdjan): Remove once constant propagation handles bounds checks. | 557 // TODO(srdjan): Remove once constant propagation handles bounds checks. |
| 546 bool skip_check = false; | 558 bool skip_check = false; |
| 547 if ((*array)->BindsToConstant() && (*index)->BindsToConstant()) { | 559 if ((*array)->IsConstant() && (*index)->IsConstant()) { |
| 548 ConstantInstr* array_def = (*array)->definition()->AsConstant(); | |
| 549 const ImmutableArray& constant_array = | 560 const ImmutableArray& constant_array = |
| 550 ImmutableArray::Cast(array_def->value()); | 561 ImmutableArray::Cast((*array)->AsConstant()->value()); |
| 551 ConstantInstr* index_def = (*index)->definition()->AsConstant(); | 562 const Object& constant_index = (*index)->AsConstant()->value(); |
| 552 if (index_def->value().IsSmi()) { | 563 skip_check = constant_index.IsSmi() && |
| 553 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); | 564 (Smi::Cast(constant_index).Value() < constant_array.Length()); |
| 554 skip_check = (constant_index < constant_array.Length()); | |
| 555 } | |
| 556 } | 565 } |
| 557 if (!skip_check) { | 566 if (!skip_check) { |
| 558 // Insert array length load and bounds check. | 567 // Insert array length load and bounds check. |
| 559 const bool is_immutable = | 568 const bool is_immutable = |
| 560 CheckArrayBoundInstr::IsFixedLengthArrayType(class_id); | 569 CheckArrayBoundInstr::IsFixedLengthArrayType(class_id); |
| 561 LoadFieldInstr* length = new LoadFieldInstr( | 570 LoadFieldInstr* length = |
| 562 (*array)->Copy(), | 571 new LoadFieldInstr(new Value(*array), |
| 563 CheckArrayBoundInstr::LengthOffsetFor(class_id), | 572 CheckArrayBoundInstr::LengthOffsetFor(class_id), |
| 564 Type::ZoneHandle(Type::SmiType()), | 573 Type::ZoneHandle(Type::SmiType()), |
| 565 is_immutable); | 574 is_immutable); |
| 566 length->set_result_cid(kSmiCid); | 575 length->set_result_cid(kSmiCid); |
| 567 length->set_recognized_kind( | 576 length->set_recognized_kind( |
| 568 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); | 577 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); |
| 569 InsertBefore(call, length, NULL, Definition::kValue); | 578 InsertBefore(call, length, NULL, Definition::kValue); |
| 579 | |
| 570 InsertBefore(call, | 580 InsertBefore(call, |
| 571 new CheckArrayBoundInstr(new Value(length), | 581 new CheckArrayBoundInstr(new Value(length), |
| 572 (*index)->Copy(), | 582 new Value(*index), |
| 573 class_id, | 583 class_id, |
| 574 call), | 584 call), |
| 575 call->env(), | 585 call->env(), |
| 576 Definition::kEffect); | 586 Definition::kEffect); |
| 577 } | 587 } |
| 578 if (class_id == kGrowableObjectArrayCid) { | 588 if (class_id == kGrowableObjectArrayCid) { |
| 579 // Insert data elements load. | 589 // Insert data elements load. |
| 580 LoadFieldInstr* elements = | 590 LoadFieldInstr* elements = |
| 581 new LoadFieldInstr((*array)->Copy(), | 591 new LoadFieldInstr(new Value(*array), |
| 582 GrowableObjectArray::data_offset(), | 592 GrowableObjectArray::data_offset(), |
| 583 Type::ZoneHandle(Type::DynamicType())); | 593 Type::ZoneHandle(Type::DynamicType())); |
| 584 elements->set_result_cid(kArrayCid); | 594 elements->set_result_cid(kArrayCid); |
| 585 InsertBefore(call, elements, NULL, Definition::kValue); | 595 InsertBefore(call, elements, NULL, Definition::kValue); |
| 586 *array = new Value(elements); | 596 *array = elements; |
| 587 return kArrayCid; | 597 return kArrayCid; |
| 588 } | 598 } |
| 589 return class_id; | 599 return class_id; |
| 590 } | 600 } |
| 591 | 601 |
| 592 | 602 |
| 593 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { | 603 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
| 594 const intptr_t class_id = ReceiverClassId(call); | 604 const intptr_t class_id = ReceiverClassId(call); |
| 595 ICData& value_check = ICData::ZoneHandle(); | 605 ICData& value_check = ICData::ZoneHandle(); |
| 596 switch (class_id) { | 606 switch (class_id) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 642 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { | 652 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { |
| 643 return false; | 653 return false; |
| 644 } | 654 } |
| 645 break; | 655 break; |
| 646 } | 656 } |
| 647 default: | 657 default: |
| 648 // TODO(fschneider): Add support for other array types. | 658 // TODO(fschneider): Add support for other array types. |
| 649 return false; | 659 return false; |
| 650 } | 660 } |
| 651 | 661 |
| 662 Definition* array = call->ArgumentAt(0); | |
| 663 Definition* index = call->ArgumentAt(1); | |
| 664 Definition* stored_value = call->ArgumentAt(2); | |
| 652 if (FLAG_enable_type_checks) { | 665 if (FLAG_enable_type_checks) { |
| 653 Value* array = call->ArgumentAt(0)->value(); | |
| 654 Value* value = call->ArgumentAt(2)->value(); | |
| 655 // Only type check for the value. A type check for the index is not | 666 // Only type check for the value. A type check for the index is not |
| 656 // needed here because we insert a deoptimizing smi-check for the case | 667 // needed here because we insert a deoptimizing smi-check for the case |
| 657 // the index is not a smi. | 668 // the index is not a smi. |
| 658 const Function& target = | 669 const Function& target = |
| 659 Function::ZoneHandle(call->ic_data()->GetTargetAt(0)); | 670 Function::ZoneHandle(call->ic_data()->GetTargetAt(0)); |
| 660 const AbstractType& value_type = | 671 const AbstractType& value_type = |
| 661 AbstractType::ZoneHandle(target.ParameterTypeAt(2)); | 672 AbstractType::ZoneHandle(target.ParameterTypeAt(2)); |
| 662 Value* instantiator = NULL; | 673 Definition* instantiator = NULL; |
| 663 Value* type_args = NULL; | 674 Definition* type_args = NULL; |
| 664 switch (class_id) { | 675 switch (class_id) { |
| 665 case kArrayCid: | 676 case kArrayCid: |
| 666 case kGrowableObjectArrayCid: { | 677 case kGrowableObjectArrayCid: { |
| 667 const Class& instantiator_class = Class::Handle(target.Owner()); | 678 const Class& instantiator_class = Class::Handle(target.Owner()); |
| 668 intptr_t type_arguments_field_offset = | 679 intptr_t type_arguments_field_offset = |
| 669 instantiator_class.type_arguments_field_offset(); | 680 instantiator_class.type_arguments_field_offset(); |
| 670 LoadFieldInstr* load_type_args = | 681 LoadFieldInstr* load_type_args = |
| 671 new LoadFieldInstr(array->Copy(), | 682 new LoadFieldInstr(new Value(array), |
| 672 type_arguments_field_offset, | 683 type_arguments_field_offset, |
| 673 Type::ZoneHandle()); // No type. | 684 Type::ZoneHandle()); // No type. |
| 674 InsertBefore(call, load_type_args, NULL, Definition::kValue); | 685 InsertBefore(call, load_type_args, NULL, Definition::kValue); |
| 675 instantiator = array->Copy(); | 686 instantiator = array; |
| 676 type_args = new Value(load_type_args); | 687 type_args = load_type_args; |
| 677 break; | 688 break; |
| 678 } | 689 } |
| 679 case kInt8ArrayCid: | 690 case kInt8ArrayCid: |
| 680 case kUint8ArrayCid: | 691 case kUint8ArrayCid: |
| 681 case kUint8ClampedArrayCid: | 692 case kUint8ClampedArrayCid: |
| 682 case kInt16ArrayCid: | 693 case kInt16ArrayCid: |
| 683 case kUint16ArrayCid: | 694 case kUint16ArrayCid: |
| 684 case kInt32ArrayCid: | 695 case kInt32ArrayCid: |
| 685 case kUint32ArrayCid: | 696 case kUint32ArrayCid: |
| 686 ASSERT(value_type.IsIntType()); | 697 ASSERT(value_type.IsIntType()); |
| 687 // Fall through. | 698 // Fall through. |
| 688 case kFloat32ArrayCid: | 699 case kFloat32ArrayCid: |
| 689 case kFloat64ArrayCid: { | 700 case kFloat64ArrayCid: { |
| 690 instantiator = new Value(flow_graph_->constant_null()); | 701 type_args = instantiator = flow_graph_->constant_null(); |
| 691 type_args = new Value(flow_graph_->constant_null()); | |
| 692 ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || | 702 ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || |
| 693 value_type.IsDoubleType()); | 703 value_type.IsDoubleType()); |
| 694 ASSERT(value_type.IsInstantiated()); | 704 ASSERT(value_type.IsInstantiated()); |
| 695 break; | 705 break; |
| 696 } | 706 } |
| 697 default: | 707 default: |
| 698 // TODO(fschneider): Add support for other array types. | 708 // TODO(fschneider): Add support for other array types. |
| 699 UNREACHABLE(); | 709 UNREACHABLE(); |
| 700 } | 710 } |
| 701 AssertAssignableInstr* assert_value = | 711 AssertAssignableInstr* assert_value = |
| 702 new AssertAssignableInstr(call->token_pos(), | 712 new AssertAssignableInstr(call->token_pos(), |
| 703 value->Copy(), | 713 new Value(stored_value), |
| 704 instantiator, | 714 new Value(instantiator), |
| 705 type_args, | 715 new Value(type_args), |
| 706 value_type, | 716 value_type, |
| 707 Symbols::Value()); | 717 Symbols::Value()); |
| 708 // Newly inserted instructions that can deoptimize or throw an exception | 718 // Newly inserted instructions that can deoptimize or throw an exception |
| 709 // must have a deoptimization id that is valid for lookup in the unoptimized | 719 // must have a deoptimization id that is valid for lookup in the unoptimized |
| 710 // code. | 720 // code. |
| 711 assert_value->deopt_id_ = call->deopt_id(); | 721 assert_value->deopt_id_ = call->deopt_id(); |
| 712 InsertBefore(call, assert_value, call->env(), Definition::kValue); | 722 InsertBefore(call, assert_value, call->env(), Definition::kValue); |
| 713 } | 723 } |
| 714 | 724 |
| 715 Value* array = NULL; | |
| 716 Value* index = NULL; | |
| 717 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 725 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| 718 Value* value = call->ArgumentAt(2)->value(); | |
| 719 // Check if store barrier is needed. | 726 // Check if store barrier is needed. |
| 720 bool needs_store_barrier = true; | 727 bool needs_store_barrier = true; |
| 721 if (!value_check.IsNull()) { | 728 if (!value_check.IsNull()) { |
| 722 needs_store_barrier = false; | 729 needs_store_barrier = false; |
| 723 if (value_check.NumberOfChecks() == 1 && | 730 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), |
| 724 value_check.GetReceiverClassIdAt(0) == kSmiCid) { | 731 call); |
| 725 InsertBefore(call, | |
| 726 new CheckSmiInstr(value->Copy(), call->deopt_id()), | |
| 727 call->env(), | |
| 728 Definition::kEffect); | |
| 729 } else { | |
| 730 InsertBefore(call, | |
| 731 new CheckClassInstr(value->Copy(), | |
| 732 call->deopt_id(), | |
| 733 value_check), | |
| 734 call->env(), | |
| 735 Definition::kEffect); | |
| 736 } | |
| 737 } | 732 } |
| 738 | 733 |
| 739 Definition* array_op = | 734 Definition* array_op = new StoreIndexedInstr(new Value(array), |
| 740 new StoreIndexedInstr(array, index, value, | 735 new Value(index), |
| 741 needs_store_barrier, array_cid, call->deopt_id()); | 736 new Value(stored_value), |
| 742 call->ReplaceWith(array_op, current_iterator()); | 737 needs_store_barrier, |
| 743 RemovePushArguments(call); | 738 array_cid, |
| 739 call->deopt_id()); | |
| 740 ReplaceCall(call, array_op); | |
| 744 return true; | 741 return true; |
| 745 } | 742 } |
| 746 | 743 |
| 747 | 744 |
| 748 | 745 |
| 749 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 746 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 750 const intptr_t class_id = ReceiverClassId(call); | 747 const intptr_t class_id = ReceiverClassId(call); |
| 751 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. | 748 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. |
| 752 intptr_t deopt_id = Isolate::kNoDeoptId; | 749 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 753 switch (class_id) { | 750 switch (class_id) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 776 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 773 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| 777 ASSERT(call->HasICData()); | 774 ASSERT(call->HasICData()); |
| 778 const ICData& ic_data = *call->ic_data(); | 775 const ICData& ic_data = *call->ic_data(); |
| 779 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 776 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| 780 call->deopt_id() : Isolate::kNoDeoptId; | 777 call->deopt_id() : Isolate::kNoDeoptId; |
| 781 } | 778 } |
| 782 break; | 779 break; |
| 783 default: | 780 default: |
| 784 return false; | 781 return false; |
| 785 } | 782 } |
| 786 Value* array = NULL; | 783 Definition* array = call->ArgumentAt(0); |
| 787 Value* index = NULL; | 784 Definition* index = call->ArgumentAt(1); |
| 788 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 785 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| 789 Definition* array_op = | 786 Definition* array_op = |
| 790 new LoadIndexedInstr(array, | 787 new LoadIndexedInstr(new Value(array), |
| 791 index, | 788 new Value(index), |
| 792 FlowGraphCompiler::ElementSizeFor(array_cid), | 789 FlowGraphCompiler::ElementSizeFor(array_cid), |
| 793 array_cid, | 790 array_cid, |
| 794 deopt_id); | 791 deopt_id); |
| 795 call->ReplaceWith(array_op, current_iterator()); | 792 ReplaceCall(call, array_op); |
| 796 RemovePushArguments(call); | |
| 797 return true; | 793 return true; |
| 798 } | 794 } |
| 799 | 795 |
| 800 | 796 |
| 801 void FlowGraphOptimizer::InsertBefore(Instruction* next, | |
| 802 Instruction* instr, | |
| 803 Environment* env, | |
| 804 Definition::UseKind use_kind) { | |
| 805 if (env != NULL) env->DeepCopyTo(instr); | |
| 806 if (use_kind == Definition::kValue) { | |
| 807 ASSERT(instr->IsDefinition()); | |
| 808 instr->AsDefinition()->set_ssa_temp_index( | |
| 809 flow_graph_->alloc_ssa_temp_index()); | |
| 810 } | |
| 811 instr->InsertBefore(next); | |
| 812 } | |
| 813 | |
| 814 | |
| 815 void FlowGraphOptimizer::InsertAfter(Instruction* prev, | |
| 816 Instruction* instr, | |
| 817 Environment* env, | |
| 818 Definition::UseKind use_kind) { | |
| 819 if (env != NULL) env->DeepCopyTo(instr); | |
| 820 if (use_kind == Definition::kValue) { | |
| 821 ASSERT(instr->IsDefinition()); | |
| 822 instr->AsDefinition()->set_ssa_temp_index( | |
| 823 flow_graph_->alloc_ssa_temp_index()); | |
| 824 } | |
| 825 instr->InsertAfter(prev); | |
| 826 } | |
| 827 | |
| 828 | |
| 829 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 797 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 830 Token::Kind op_kind) { | 798 Token::Kind op_kind) { |
| 831 intptr_t operands_type = kIllegalCid; | 799 intptr_t operands_type = kIllegalCid; |
| 832 ASSERT(call->HasICData()); | 800 ASSERT(call->HasICData()); |
| 833 const ICData& ic_data = *call->ic_data(); | 801 const ICData& ic_data = *call->ic_data(); |
| 834 switch (op_kind) { | 802 switch (op_kind) { |
| 835 case Token::kADD: | 803 case Token::kADD: |
| 836 case Token::kSUB: | 804 case Token::kSUB: |
| 837 if (HasOnlyTwoSmis(ic_data)) { | 805 if (HasOnlyTwoSmis(ic_data)) { |
| 838 // Don't generate smi code if the IC data is marked because | 806 // 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... | |
| 915 case Token::kTRUNCDIV: | 883 case Token::kTRUNCDIV: |
| 916 if (HasOnlyTwoSmis(ic_data)) { | 884 if (HasOnlyTwoSmis(ic_data)) { |
| 917 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; | 885 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; |
| 918 operands_type = kSmiCid; | 886 operands_type = kSmiCid; |
| 919 } else { | 887 } else { |
| 920 return false; | 888 return false; |
| 921 } | 889 } |
| 922 break; | 890 break; |
| 923 default: | 891 default: |
| 924 UNREACHABLE(); | 892 UNREACHABLE(); |
| 925 }; | 893 } |
| 926 | 894 |
| 927 ASSERT(call->ArgumentCount() == 2); | 895 ASSERT(call->ArgumentCount() == 2); |
| 896 Definition* left = call->ArgumentAt(0); | |
| 897 Definition* right = call->ArgumentAt(1); | |
| 928 if (operands_type == kDoubleCid) { | 898 if (operands_type == kDoubleCid) { |
| 929 Value* left = call->ArgumentAt(0)->value(); | |
| 930 Value* right = call->ArgumentAt(1)->value(); | |
| 931 | |
| 932 // Check that either left or right are not a smi. Result or a | 899 // Check that either left or right are not a smi. Result or a |
| 933 // binary operation with two smis is a smi not a double. | 900 // binary operation with two smis is a smi not a double. |
| 934 InsertBefore(call, | 901 InsertBefore(call, |
| 935 new CheckEitherNonSmiInstr(left->Copy(), | 902 new CheckEitherNonSmiInstr(new Value(left), |
| 936 right->Copy(), | 903 new Value(right), |
| 937 call), | 904 call), |
| 938 call->env(), | 905 call->env(), |
| 939 Definition::kEffect); | 906 Definition::kEffect); |
| 940 | 907 |
| 941 BinaryDoubleOpInstr* double_bin_op = | 908 BinaryDoubleOpInstr* double_bin_op = |
| 942 new BinaryDoubleOpInstr(op_kind, left->Copy(), right->Copy(), call); | 909 new BinaryDoubleOpInstr(op_kind, new Value(left), new Value(right), |
| 943 call->ReplaceWith(double_bin_op, current_iterator()); | 910 call); |
| 944 RemovePushArguments(call); | 911 ReplaceCall(call, double_bin_op); |
| 945 } else if (operands_type == kMintCid) { | 912 } else if (operands_type == kMintCid) { |
| 946 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; | 913 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; |
| 947 Value* left = call->ArgumentAt(0)->value(); | |
| 948 Value* right = call->ArgumentAt(1)->value(); | |
| 949 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | 914 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { |
| 950 ShiftMintOpInstr* shift_op = | 915 ShiftMintOpInstr* shift_op = |
| 951 new ShiftMintOpInstr(op_kind, left, right, call); | 916 new ShiftMintOpInstr(op_kind, new Value(left), new Value(right), |
| 952 call->ReplaceWith(shift_op, current_iterator()); | 917 call); |
| 918 ReplaceCall(call, shift_op); | |
| 953 } else { | 919 } else { |
| 954 BinaryMintOpInstr* bin_op = | 920 BinaryMintOpInstr* bin_op = |
| 955 new BinaryMintOpInstr(op_kind, left, right, call); | 921 new BinaryMintOpInstr(op_kind, new Value(left), new Value(right), |
| 956 call->ReplaceWith(bin_op, current_iterator()); | 922 call); |
| 923 ReplaceCall(call, bin_op); | |
| 957 } | 924 } |
| 958 RemovePushArguments(call); | |
| 959 } else if (op_kind == Token::kMOD) { | 925 } else if (op_kind == Token::kMOD) { |
| 960 // TODO(vegorov): implement fast path code for modulo. | 926 // TODO(vegorov): implement fast path code for modulo. |
| 961 ASSERT(operands_type == kSmiCid); | 927 ASSERT(operands_type == kSmiCid); |
| 962 if (!call->ArgumentAt(1)->value()->BindsToConstant()) return false; | 928 if (!right->IsConstant()) return false; |
| 963 const Object& obj = call->ArgumentAt(1)->value()->BoundConstant(); | 929 const Object& obj = right->AsConstant()->value(); |
| 964 if (!obj.IsSmi()) return false; | 930 if (!obj.IsSmi()) return false; |
| 965 const intptr_t value = Smi::Cast(obj).Value(); | 931 const intptr_t value = Smi::Cast(obj).Value(); |
| 966 if ((value > 0) && Utils::IsPowerOfTwo(value)) { | 932 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; |
| 967 Value* left = call->ArgumentAt(0)->value(); | 933 |
| 968 // Insert smi check and attach a copy of the original | 934 // Insert smi check and attach a copy of the original environment |
| 969 // environment because the smi operation can still deoptimize. | 935 // because the smi operation can still deoptimize. |
| 970 InsertBefore(call, | 936 InsertBefore(call, |
| 971 new CheckSmiInstr(left->Copy(), call->deopt_id()), | 937 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 972 call->env(), | 938 call->env(), |
| 973 Definition::kEffect); | 939 Definition::kEffect); |
| 974 ConstantInstr* c = new ConstantInstr(Smi::Handle(Smi::New(value - 1))); | 940 ConstantInstr* constant = |
| 975 InsertBefore(call, c, NULL, Definition::kValue); | 941 new ConstantInstr(Smi::Handle(Smi::New(value - 1))); |
| 976 BinarySmiOpInstr* bin_op = | 942 InsertBefore(call, constant, NULL, Definition::kValue); |
| 977 new BinarySmiOpInstr(Token::kBIT_AND, call, left, new Value(c)); | 943 BinarySmiOpInstr* bin_op = |
| 978 call->ReplaceWith(bin_op, current_iterator()); | 944 new BinarySmiOpInstr(Token::kBIT_AND, call, |
| 979 RemovePushArguments(call); | 945 new Value(left), |
| 980 } else { | 946 new Value(constant)); |
| 981 // Did not replace. | 947 ReplaceCall(call, bin_op); |
| 982 return false; | |
| 983 } | |
| 984 } else { | 948 } else { |
| 985 ASSERT(operands_type == kSmiCid); | 949 ASSERT(operands_type == kSmiCid); |
| 986 Value* left = call->ArgumentAt(0)->value(); | |
| 987 Value* right = call->ArgumentAt(1)->value(); | |
| 988 // Insert two smi checks and attach a copy of the original | 950 // Insert two smi checks and attach a copy of the original |
| 989 // environment because the smi operation can still deoptimize. | 951 // environment because the smi operation can still deoptimize. |
| 990 InsertBefore(call, | 952 InsertBefore(call, |
| 991 new CheckSmiInstr(left->Copy(), call->deopt_id()), | 953 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 992 call->env(), | 954 call->env(), |
| 993 Definition::kEffect); | 955 Definition::kEffect); |
| 994 InsertBefore(call, | 956 InsertBefore(call, |
| 995 new CheckSmiInstr(right->Copy(), call->deopt_id()), | 957 new CheckSmiInstr(new Value(right), call->deopt_id()), |
| 996 call->env(), | 958 call->env(), |
| 997 Definition::kEffect); | 959 Definition::kEffect); |
| 998 if (left->BindsToConstant() && | 960 if (left->IsConstant() && |
| 999 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { | 961 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { |
| 1000 // Constant should be on the right side. | 962 // Constant should be on the right side. |
| 1001 Value* temp = left; | 963 Definition* temp = left; |
| 1002 left = right; | 964 left = right; |
| 1003 right = temp; | 965 right = temp; |
| 1004 } | 966 } |
| 1005 BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right); | 967 BinarySmiOpInstr* bin_op = |
| 1006 call->ReplaceWith(bin_op, current_iterator()); | 968 new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right)); |
| 1007 RemovePushArguments(call); | 969 ReplaceCall(call, bin_op); |
| 1008 } | 970 } |
| 1009 return true; | 971 return true; |
| 1010 } | 972 } |
| 1011 | 973 |
| 1012 | 974 |
| 1013 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 975 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| 1014 Token::Kind op_kind) { | 976 Token::Kind op_kind) { |
| 1015 ASSERT(call->ArgumentCount() == 1); | 977 ASSERT(call->ArgumentCount() == 1); |
| 978 Definition* input = call->ArgumentAt(0); | |
| 1016 Definition* unary_op = NULL; | 979 Definition* unary_op = NULL; |
| 1017 if (HasOnlyOneSmi(*call->ic_data())) { | 980 if (HasOnlyOneSmi(*call->ic_data())) { |
| 1018 Value* value = call->ArgumentAt(0)->value(); | |
| 1019 InsertBefore(call, | 981 InsertBefore(call, |
| 1020 new CheckSmiInstr(value->Copy(), call->deopt_id()), | 982 new CheckSmiInstr(new Value(input), call->deopt_id()), |
| 1021 call->env(), | 983 call->env(), |
| 1022 Definition::kEffect); | 984 Definition::kEffect); |
| 1023 unary_op = new UnarySmiOpInstr(op_kind, call, value); | 985 unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input)); |
| 1024 } else if ((op_kind == Token::kBIT_NOT) && | 986 } else if ((op_kind == Token::kBIT_NOT) && |
| 1025 HasOnlySmiOrMint(*call->ic_data()) && | 987 HasOnlySmiOrMint(*call->ic_data()) && |
| 1026 FlowGraphCompiler::SupportsUnboxedMints()) { | 988 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1027 Value* value = call->ArgumentAt(0)->value(); | 989 unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call); |
| 1028 unary_op = new UnaryMintOpInstr(op_kind, value, call); | |
| 1029 } else if (HasOnlyOneDouble(*call->ic_data()) && | 990 } else if (HasOnlyOneDouble(*call->ic_data()) && |
| 1030 (op_kind == Token::kNEGATE)) { | 991 (op_kind == Token::kNEGATE)) { |
| 1031 Value* value = call->ArgumentAt(0)->value(); | 992 AddReceiverCheck(call); |
| 1032 AddCheckClass(call, value->Copy()); | |
| 1033 ConstantInstr* minus_one = | 993 ConstantInstr* minus_one = |
| 1034 new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1))); | 994 new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1))); |
| 1035 InsertBefore(call, minus_one, NULL, Definition::kValue); | 995 InsertBefore(call, minus_one, NULL, Definition::kValue); |
| 1036 unary_op = new BinaryDoubleOpInstr(Token::kMUL, | 996 unary_op = new BinaryDoubleOpInstr(Token::kMUL, |
| 1037 value, | 997 new Value(input), |
| 1038 new Value(minus_one), | 998 new Value(minus_one), |
| 1039 call); | 999 call); |
| 1040 } | 1000 } |
| 1041 if (unary_op == NULL) return false; | 1001 if (unary_op == NULL) return false; |
| 1042 | 1002 |
| 1043 call->ReplaceWith(unary_op, current_iterator()); | 1003 ReplaceCall(call, unary_op); |
| 1044 RemovePushArguments(call); | |
| 1045 return true; | 1004 return true; |
| 1046 } | 1005 } |
| 1047 | 1006 |
| 1048 | 1007 |
| 1049 // Using field class | 1008 // Using field class |
| 1050 static RawField* GetField(intptr_t class_id, const String& field_name) { | 1009 static RawField* GetField(intptr_t class_id, const String& field_name) { |
| 1051 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); | 1010 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); |
| 1052 Field& field = Field::Handle(); | 1011 Field& field = Field::Handle(); |
| 1053 while (!cls.IsNull()) { | 1012 while (!cls.IsNull()) { |
| 1054 field = cls.LookupInstanceField(field_name); | 1013 field = cls.LookupInstanceField(field_name); |
| 1055 if (!field.IsNull()) { | 1014 if (!field.IsNull()) { |
| 1056 return field.raw(); | 1015 return field.raw(); |
| 1057 } | 1016 } |
| 1058 cls = cls.SuperClass(); | 1017 cls = cls.SuperClass(); |
| 1059 } | 1018 } |
| 1060 return Field::null(); | 1019 return Field::null(); |
| 1061 } | 1020 } |
| 1062 | 1021 |
| 1063 | 1022 |
| 1064 // Use CHA to determine if the call needs a class check: if the callee's | 1023 // Use CHA to determine if the call needs a class check: if the callee's |
| 1065 // receiver is the same as the caller's receiver and there are no overriden | 1024 // receiver is the same as the caller's receiver and there are no overriden |
| 1066 // callee functions, then no class check is needed. | 1025 // callee functions, then no class check is needed. |
| 1067 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( | 1026 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( |
| 1068 InstanceCallInstr* call) const { | 1027 InstanceCallInstr* call) const { |
| 1069 if (!FLAG_use_cha) return true; | 1028 if (!FLAG_use_cha) return true; |
| 1070 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); | 1029 Definition* callee_receiver = call->ArgumentAt(0); |
| 1071 ASSERT(callee_receiver != NULL); | 1030 ASSERT(callee_receiver != NULL); |
| 1072 const Function& function = flow_graph_->parsed_function().function(); | 1031 const Function& function = flow_graph_->parsed_function().function(); |
| 1073 if (function.IsDynamicFunction() && | 1032 if (function.IsDynamicFunction() && |
| 1074 callee_receiver->IsParameter() && | 1033 callee_receiver->IsParameter() && |
| 1075 (callee_receiver->AsParameter()->index() == 0)) { | 1034 (callee_receiver->AsParameter()->index() == 0)) { |
| 1076 return CHA::HasOverride(Class::Handle(function.Owner()), | 1035 return CHA::HasOverride(Class::Handle(function.Owner()), |
| 1077 call->function_name()); | 1036 call->function_name()); |
| 1078 } | 1037 } |
| 1079 return true; | 1038 return true; |
| 1080 } | 1039 } |
| 1081 | 1040 |
| 1082 | 1041 |
| 1083 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( | 1042 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( |
| 1084 InstanceCallInstr* call) const { | 1043 InstanceCallInstr* call) const { |
| 1085 if (!FLAG_use_cha) return true; | 1044 if (!FLAG_use_cha) return true; |
| 1086 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); | 1045 Definition* callee_receiver = call->ArgumentAt(0); |
| 1087 ASSERT(callee_receiver != NULL); | 1046 ASSERT(callee_receiver != NULL); |
| 1088 const Function& function = flow_graph_->parsed_function().function(); | 1047 const Function& function = flow_graph_->parsed_function().function(); |
| 1089 if (function.IsDynamicFunction() && | 1048 if (function.IsDynamicFunction() && |
| 1090 callee_receiver->IsParameter() && | 1049 callee_receiver->IsParameter() && |
| 1091 (callee_receiver->AsParameter()->index() == 0)) { | 1050 (callee_receiver->AsParameter()->index() == 0)) { |
| 1092 const String& field_name = | 1051 const String& field_name = |
| 1093 String::Handle(Field::NameFromGetter(call->function_name())); | 1052 String::Handle(Field::NameFromGetter(call->function_name())); |
| 1094 return CHA::HasOverride(Class::Handle(function.Owner()), field_name); | 1053 return CHA::HasOverride(Class::Handle(function.Owner()), field_name); |
| 1095 } | 1054 } |
| 1096 return true; | 1055 return true; |
| 1097 } | 1056 } |
| 1098 | 1057 |
| 1099 | 1058 |
| 1100 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 1059 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
| 1101 ASSERT(call->HasICData()); | 1060 ASSERT(call->HasICData()); |
| 1102 const ICData& ic_data = *call->ic_data(); | 1061 const ICData& ic_data = *call->ic_data(); |
| 1103 Function& target = Function::Handle(); | 1062 Function& target = Function::Handle(); |
| 1104 GrowableArray<intptr_t> class_ids; | 1063 GrowableArray<intptr_t> class_ids; |
| 1105 ic_data.GetCheckAt(0, &class_ids, &target); | 1064 ic_data.GetCheckAt(0, &class_ids, &target); |
| 1106 ASSERT(class_ids.length() == 1); | 1065 ASSERT(class_ids.length() == 1); |
| 1107 // Inline implicit instance getter. | 1066 // Inline implicit instance getter. |
| 1108 const String& field_name = | 1067 const String& field_name = |
| 1109 String::Handle(Field::NameFromGetter(call->function_name())); | 1068 String::Handle(Field::NameFromGetter(call->function_name())); |
| 1110 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 1069 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 1111 ASSERT(!field.IsNull()); | 1070 ASSERT(!field.IsNull()); |
| 1112 | 1071 |
| 1113 if (InstanceCallNeedsClassCheck(call)) { | 1072 if (InstanceCallNeedsClassCheck(call)) { |
| 1114 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1073 AddReceiverCheck(call); |
| 1115 } | 1074 } |
| 1116 // Detach environment from the original instruction because it can't | |
| 1117 // deoptimize. | |
| 1118 call->set_env(NULL); | |
| 1119 LoadFieldInstr* load = new LoadFieldInstr( | 1075 LoadFieldInstr* load = new LoadFieldInstr( |
| 1120 call->ArgumentAt(0)->value(), | 1076 new Value(call->ArgumentAt(0)), |
| 1121 field.Offset(), | 1077 field.Offset(), |
| 1122 AbstractType::ZoneHandle(field.type()), | 1078 AbstractType::ZoneHandle(field.type()), |
| 1123 field.is_final()); | 1079 field.is_final()); |
| 1124 call->ReplaceWith(load, current_iterator()); | 1080 // Detach environment from the original instruction because it can't |
| 1125 RemovePushArguments(call); | 1081 // deoptimize. |
| 1082 for (Environment::DeepIterator it(call->env()); !it.Done(); it.Advance()) { | |
| 1083 it.CurrentValue()->RemoveFromUseList(); | |
| 1084 } | |
| 1085 call->set_env(NULL); | |
| 1086 ReplaceCall(call, load); | |
| 1126 } | 1087 } |
| 1127 | 1088 |
| 1128 | 1089 |
| 1129 void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call, | 1090 void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call, |
| 1130 intptr_t length_offset, | 1091 intptr_t length_offset, |
| 1131 bool is_immutable, | 1092 bool is_immutable, |
| 1132 MethodRecognizer::Kind kind) { | 1093 MethodRecognizer::Kind kind) { |
| 1133 // Check receiver class. | 1094 AddReceiverCheck(call); |
| 1134 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1135 | 1095 |
| 1136 LoadFieldInstr* load = new LoadFieldInstr( | 1096 LoadFieldInstr* load = new LoadFieldInstr( |
| 1137 call->ArgumentAt(0)->value(), | 1097 new Value(call->ArgumentAt(0)), |
| 1138 length_offset, | 1098 length_offset, |
| 1139 Type::ZoneHandle(Type::SmiType()), | 1099 Type::ZoneHandle(Type::SmiType()), |
| 1140 is_immutable); | 1100 is_immutable); |
| 1141 load->set_result_cid(kSmiCid); | 1101 load->set_result_cid(kSmiCid); |
| 1142 load->set_recognized_kind(kind); | 1102 load->set_recognized_kind(kind); |
| 1143 call->ReplaceWith(load, current_iterator()); | 1103 ReplaceCall(call, load); |
| 1144 RemovePushArguments(call); | |
| 1145 } | 1104 } |
| 1146 | 1105 |
| 1147 | 1106 |
| 1148 void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter( | 1107 void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter( |
| 1149 InstanceCallInstr* call) { | 1108 InstanceCallInstr* call) { |
| 1150 // Check receiver class. | 1109 AddReceiverCheck(call); |
| 1151 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1152 | 1110 |
| 1153 // TODO(srdjan): type of load should be GrowableObjectArrayType. | 1111 // TODO(srdjan): type of load should be GrowableObjectArrayType. |
| 1154 LoadFieldInstr* data_load = new LoadFieldInstr( | 1112 LoadFieldInstr* data_load = new LoadFieldInstr( |
| 1155 call->ArgumentAt(0)->value(), | 1113 new Value(call->ArgumentAt(0)), |
| 1156 Array::data_offset(), | 1114 Array::data_offset(), |
| 1157 Type::ZoneHandle(Type::DynamicType())); | 1115 Type::ZoneHandle(Type::DynamicType())); |
| 1158 data_load->set_result_cid(kArrayCid); | 1116 data_load->set_result_cid(kArrayCid); |
| 1159 InsertBefore(call, data_load, NULL, Definition::kValue); | 1117 InsertBefore(call, data_load, NULL, Definition::kValue); |
| 1160 | 1118 |
| 1161 LoadFieldInstr* length_load = new LoadFieldInstr( | 1119 LoadFieldInstr* length_load = new LoadFieldInstr( |
| 1162 new Value(data_load), | 1120 new Value(data_load), |
| 1163 Array::length_offset(), | 1121 Array::length_offset(), |
| 1164 Type::ZoneHandle(Type::SmiType())); | 1122 Type::ZoneHandle(Type::SmiType())); |
| 1165 length_load->set_result_cid(kSmiCid); | 1123 length_load->set_result_cid(kSmiCid); |
| 1166 length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength); | 1124 length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength); |
| 1167 | 1125 |
| 1168 call->ReplaceWith(length_load, current_iterator()); | 1126 ReplaceCall(call, length_load); |
| 1169 RemovePushArguments(call); | |
| 1170 } | 1127 } |
| 1171 | 1128 |
| 1172 | 1129 |
| 1173 static LoadFieldInstr* BuildLoadStringLength(Value* str) { | 1130 static LoadFieldInstr* BuildLoadStringLength(Definition* str) { |
| 1174 const bool is_immutable = true; // String length is immutable. | 1131 const bool is_immutable = true; // String length is immutable. |
| 1175 LoadFieldInstr* load = new LoadFieldInstr( | 1132 LoadFieldInstr* load = new LoadFieldInstr( |
| 1176 str, | 1133 new Value(str), |
| 1177 String::length_offset(), | 1134 String::length_offset(), |
| 1178 Type::ZoneHandle(Type::SmiType()), | 1135 Type::ZoneHandle(Type::SmiType()), |
| 1179 is_immutable); | 1136 is_immutable); |
| 1180 load->set_result_cid(kSmiCid); | 1137 load->set_result_cid(kSmiCid); |
| 1181 return load; | 1138 return load; |
| 1182 } | 1139 } |
| 1183 | 1140 |
| 1184 | 1141 |
| 1185 void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) { | 1142 void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) { |
| 1186 // Check receiver class. | 1143 AddReceiverCheck(call); |
| 1187 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1188 | 1144 |
| 1189 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value()); | 1145 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)); |
| 1190 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); | 1146 load->set_recognized_kind(MethodRecognizer::kStringBaseLength); |
| 1191 call->ReplaceWith(load, current_iterator()); | 1147 ReplaceCall(call, load); |
| 1192 RemovePushArguments(call); | |
| 1193 } | 1148 } |
| 1194 | 1149 |
| 1195 | 1150 |
| 1196 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { | 1151 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { |
| 1197 // Check receiver class. | 1152 AddReceiverCheck(call); |
| 1198 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | |
| 1199 | 1153 |
| 1200 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value()); | 1154 LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)); |
| 1201 InsertBefore(call, load, NULL, Definition::kValue); | 1155 InsertBefore(call, load, NULL, Definition::kValue); |
| 1202 | 1156 |
| 1203 ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0))); | 1157 ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0))); |
| 1204 InsertBefore(call, zero, NULL, Definition::kValue); | 1158 InsertBefore(call, zero, NULL, Definition::kValue); |
| 1205 | 1159 |
| 1206 StrictCompareInstr* compare = | 1160 StrictCompareInstr* compare = |
| 1207 new StrictCompareInstr(Token::kEQ_STRICT, | 1161 new StrictCompareInstr(Token::kEQ_STRICT, |
| 1208 new Value(load), | 1162 new Value(load), |
| 1209 new Value(zero)); | 1163 new Value(zero)); |
| 1210 call->ReplaceWith(compare, current_iterator()); | 1164 ReplaceCall(call, compare); |
| 1211 RemovePushArguments(call); | |
| 1212 } | 1165 } |
| 1213 | 1166 |
| 1214 | 1167 |
| 1215 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { | 1168 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { |
| 1216 switch (kind) { | 1169 switch (kind) { |
| 1217 case MethodRecognizer::kObjectArrayLength: | 1170 case MethodRecognizer::kObjectArrayLength: |
| 1218 case MethodRecognizer::kImmutableArrayLength: | 1171 case MethodRecognizer::kImmutableArrayLength: |
| 1219 return Array::length_offset(); | 1172 return Array::length_offset(); |
| 1220 case MethodRecognizer::kByteArrayBaseLength: | 1173 case MethodRecognizer::kByteArrayBaseLength: |
| 1221 return ByteArray::length_offset(); | 1174 return ByteArray::length_offset(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1292 default: | 1245 default: |
| 1293 ASSERT(recognized_kind == MethodRecognizer::kUnknown); | 1246 ASSERT(recognized_kind == MethodRecognizer::kUnknown); |
| 1294 } | 1247 } |
| 1295 return false; | 1248 return false; |
| 1296 } | 1249 } |
| 1297 | 1250 |
| 1298 | 1251 |
| 1299 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt( | 1252 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt( |
| 1300 InstanceCallInstr* call, | 1253 InstanceCallInstr* call, |
| 1301 intptr_t cid) { | 1254 intptr_t cid) { |
| 1302 Value* str = call->ArgumentAt(0)->value(); | 1255 Definition* str = call->ArgumentAt(0); |
| 1303 Value* index = call->ArgumentAt(1)->value(); | 1256 Definition* index = call->ArgumentAt(1); |
| 1304 AddCheckClass(call, str->Copy()); | 1257 AddReceiverCheck(call); |
| 1305 InsertBefore(call, | 1258 InsertBefore(call, |
| 1306 new CheckSmiInstr(index->Copy(), call->deopt_id()), | 1259 new CheckSmiInstr(new Value(index), call->deopt_id()), |
| 1307 call->env(), | 1260 call->env(), |
| 1308 Definition::kEffect); | 1261 Definition::kEffect); |
| 1309 // If both index and string are constants, then do a compile-time check. | 1262 // If both index and string are constants, then do a compile-time check. |
| 1310 // TODO(srdjan): Remove once constant propagation handles bounds checks. | 1263 // TODO(srdjan): Remove once constant propagation handles bounds checks. |
| 1311 bool skip_check = false; | 1264 bool skip_check = false; |
| 1312 if (str->BindsToConstant() && index->BindsToConstant()) { | 1265 if (str->IsConstant() && index->IsConstant()) { |
| 1313 ConstantInstr* string_def = str->definition()->AsConstant(); | |
| 1314 const String& constant_string = | 1266 const String& constant_string = |
| 1315 String::Cast(string_def->value()); | 1267 String::Cast(str->AsConstant()->value()); |
| 1316 ConstantInstr* index_def = index->definition()->AsConstant(); | 1268 const Object& constant_index = index->AsConstant()->value(); |
| 1317 if (index_def->value().IsSmi()) { | 1269 skip_check = constant_index.IsSmi() && |
| 1318 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); | 1270 (Smi::Cast(constant_index).Value() < constant_string.Length()); |
| 1319 skip_check = (constant_index < constant_string.Length()); | |
| 1320 } | |
| 1321 } | 1271 } |
| 1322 if (!skip_check) { | 1272 if (!skip_check) { |
| 1323 // Insert bounds check. | 1273 // Insert bounds check. |
| 1324 const bool is_immutable = true; | 1274 const bool is_immutable = true; |
| 1325 LoadFieldInstr* length = new LoadFieldInstr( | 1275 LoadFieldInstr* length = new LoadFieldInstr( |
| 1326 str->Copy(), | 1276 new Value(str), |
| 1327 CheckArrayBoundInstr::LengthOffsetFor(cid), | 1277 CheckArrayBoundInstr::LengthOffsetFor(cid), |
| 1328 Type::ZoneHandle(Type::SmiType()), | 1278 Type::ZoneHandle(Type::SmiType()), |
| 1329 is_immutable); | 1279 is_immutable); |
| 1330 length->set_result_cid(kSmiCid); | 1280 length->set_result_cid(kSmiCid); |
| 1331 length->set_recognized_kind(MethodRecognizer::kStringBaseLength); | 1281 length->set_recognized_kind(MethodRecognizer::kStringBaseLength); |
| 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 kInt16ArrayCid: | 1319 case kInt16ArrayCid: |
| 1371 case kUint16ArrayCid: | 1320 case kUint16ArrayCid: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1391 Function& target = Function::Handle(); | 1340 Function& target = Function::Handle(); |
| 1392 GrowableArray<intptr_t> class_ids; | 1341 GrowableArray<intptr_t> class_ids; |
| 1393 ic_data.GetCheckAt(0, &class_ids, &target); | 1342 ic_data.GetCheckAt(0, &class_ids, &target); |
| 1394 MethodRecognizer::Kind recognized_kind = | 1343 MethodRecognizer::Kind recognized_kind = |
| 1395 MethodRecognizer::RecognizeKind(target); | 1344 MethodRecognizer::RecognizeKind(target); |
| 1396 if ((recognized_kind == MethodRecognizer::kStringBaseCharCodeAt) && | 1345 if ((recognized_kind == MethodRecognizer::kStringBaseCharCodeAt) && |
| 1397 (ic_data.NumberOfChecks() == 1) && | 1346 (ic_data.NumberOfChecks() == 1) && |
| 1398 ((class_ids[0] == kOneByteStringCid) || | 1347 ((class_ids[0] == kOneByteStringCid) || |
| 1399 (class_ids[0] == kTwoByteStringCid))) { | 1348 (class_ids[0] == kTwoByteStringCid))) { |
| 1400 LoadIndexedInstr* instr = BuildStringCharCodeAt(call, class_ids[0]); | 1349 LoadIndexedInstr* instr = BuildStringCharCodeAt(call, class_ids[0]); |
| 1401 call->ReplaceWith(instr, current_iterator()); | 1350 ReplaceCall(call, instr); |
| 1402 RemovePushArguments(call); | |
| 1403 return true; | 1351 return true; |
| 1404 } | 1352 } |
| 1405 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && | 1353 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && |
| 1406 (ic_data.NumberOfChecks() == 1) && | 1354 (ic_data.NumberOfChecks() == 1) && |
| 1407 (class_ids[0] == kOneByteStringCid)) { | 1355 (class_ids[0] == kOneByteStringCid)) { |
| 1408 // TODO(fschneider): Handle TwoByteString. | 1356 // TODO(fschneider): Handle TwoByteString. |
| 1409 LoadIndexedInstr* load_char_code = | 1357 LoadIndexedInstr* load_char_code = |
| 1410 BuildStringCharCodeAt(call, class_ids[0]); | 1358 BuildStringCharCodeAt(call, class_ids[0]); |
| 1411 InsertBefore(call, load_char_code, NULL, Definition::kValue); | 1359 InsertBefore(call, load_char_code, NULL, Definition::kValue); |
| 1412 StringFromCharCodeInstr* char_at = | 1360 StringFromCharCodeInstr* char_at = |
| 1413 new StringFromCharCodeInstr(new Value(load_char_code), | 1361 new StringFromCharCodeInstr(new Value(load_char_code), |
| 1414 kOneByteStringCid); | 1362 kOneByteStringCid); |
| 1415 call->ReplaceWith(char_at, current_iterator()); | 1363 ReplaceCall(call, char_at); |
| 1416 RemovePushArguments(call); | |
| 1417 return true; | 1364 return true; |
| 1418 } | 1365 } |
| 1419 | 1366 |
| 1420 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && | 1367 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && |
| 1421 (class_ids[0] == kSmiCid)) { | 1368 (class_ids[0] == kSmiCid)) { |
| 1422 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); | 1369 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); |
| 1423 call->ReplaceWith(s2d_instr, current_iterator()); | 1370 call->ReplaceWith(s2d_instr, current_iterator()); |
| 1424 // Pushed arguments are not removed because SmiToDouble is implemented | 1371 // Pushed arguments are not removed because SmiToDouble is implemented |
| 1425 // as a call. | 1372 // as a call. |
| 1426 return true; | 1373 return true; |
| 1427 } | 1374 } |
| 1428 | 1375 |
| 1429 if (class_ids[0] == kDoubleCid) { | 1376 if (class_ids[0] == kDoubleCid) { |
| 1430 switch (recognized_kind) { | 1377 switch (recognized_kind) { |
| 1431 case MethodRecognizer::kDoubleToInteger: { | 1378 case MethodRecognizer::kDoubleToInteger: { |
| 1432 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1379 AddReceiverCheck(call); |
| 1433 ASSERT(call->HasICData()); | 1380 ASSERT(call->HasICData()); |
| 1434 const ICData& ic_data = *call->ic_data(); | 1381 const ICData& ic_data = *call->ic_data(); |
| 1382 Definition* input = call->ArgumentAt(0); | |
| 1435 Definition* d2i_instr = NULL; | 1383 Definition* d2i_instr = NULL; |
| 1436 if (ic_data.deopt_reason() == kDeoptDoubleToSmi) { | 1384 if (ic_data.deopt_reason() == kDeoptDoubleToSmi) { |
| 1437 // Do not repeatedly deoptimize because result didn't fit into Smi. | 1385 // Do not repeatedly deoptimize because result didn't fit into Smi. |
| 1438 d2i_instr = new DoubleToIntegerInstr(call->ArgumentAt(0)->value(), | 1386 d2i_instr = new DoubleToIntegerInstr(new Value(input), call); |
| 1439 call); | |
| 1440 } else { | 1387 } else { |
| 1441 // Optimistically assume result fits into Smi. | 1388 // Optimistically assume result fits into Smi. |
| 1442 d2i_instr = new DoubleToSmiInstr(call->ArgumentAt(0)->value(), call); | 1389 d2i_instr = new DoubleToSmiInstr(new Value(input), call); |
| 1443 } | 1390 } |
| 1444 call->ReplaceWith(d2i_instr, current_iterator()); | 1391 ReplaceCall(call, d2i_instr); |
| 1445 RemovePushArguments(call); | |
| 1446 return true; | 1392 return true; |
| 1447 } | 1393 } |
| 1448 case MethodRecognizer::kDoubleMod: | 1394 case MethodRecognizer::kDoubleMod: |
| 1449 case MethodRecognizer::kDoublePow: | 1395 case MethodRecognizer::kDoublePow: |
| 1450 ReplaceWithMathCFunction(call, recognized_kind); | 1396 ReplaceWithMathCFunction(call, recognized_kind); |
| 1451 return true; | 1397 return true; |
| 1452 case MethodRecognizer::kDoubleTruncate: | 1398 case MethodRecognizer::kDoubleTruncate: |
| 1453 case MethodRecognizer::kDoubleRound: | 1399 case MethodRecognizer::kDoubleRound: |
| 1454 case MethodRecognizer::kDoubleFloor: | 1400 case MethodRecognizer::kDoubleFloor: |
| 1455 case MethodRecognizer::kDoubleCeil: | 1401 case MethodRecognizer::kDoubleCeil: |
| 1456 if (!CPUFeatures::double_truncate_round_supported()) { | 1402 if (!CPUFeatures::double_truncate_round_supported()) { |
| 1457 ReplaceWithMathCFunction(call, recognized_kind); | 1403 ReplaceWithMathCFunction(call, recognized_kind); |
| 1458 } else { | 1404 } else { |
| 1459 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); | 1405 AddReceiverCheck(call); |
| 1460 DoubleToDoubleInstr* d2d_instr = | 1406 DoubleToDoubleInstr* d2d_instr = |
| 1461 new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), | 1407 new DoubleToDoubleInstr(new Value(call->ArgumentAt(0)), |
| 1462 call, | 1408 call, |
| 1463 recognized_kind); | 1409 recognized_kind); |
| 1464 call->ReplaceWith(d2d_instr, current_iterator()); | 1410 ReplaceCall(call, d2d_instr); |
| 1465 RemovePushArguments(call); | |
| 1466 } | 1411 } |
| 1467 return true; | 1412 return true; |
| 1468 default: | 1413 default: |
| 1469 // Unsupported method. | 1414 // Unsupported method. |
| 1470 return false; | 1415 return false; |
| 1471 } | 1416 } |
| 1472 } | 1417 } |
| 1473 | 1418 |
| 1474 if (IsSupportedByteArrayCid(class_ids[0]) && | 1419 if (IsSupportedByteArrayCid(class_ids[0]) && |
| 1475 (ic_data.NumberOfChecks() == 1)) { | 1420 (ic_data.NumberOfChecks() == 1)) { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1497 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); | 1442 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); |
| 1498 break; | 1443 break; |
| 1499 case MethodRecognizer::kByteArrayBaseGetFloat64: | 1444 case MethodRecognizer::kByteArrayBaseGetFloat64: |
| 1500 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); | 1445 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); |
| 1501 break; | 1446 break; |
| 1502 default: | 1447 default: |
| 1503 // Unsupported method. | 1448 // Unsupported method. |
| 1504 return false; | 1449 return false; |
| 1505 } | 1450 } |
| 1506 ASSERT(array_op != NULL); | 1451 ASSERT(array_op != NULL); |
| 1507 call->ReplaceWith(array_op, current_iterator()); | 1452 ReplaceCall(call, array_op); |
| 1508 RemovePushArguments(call); | |
| 1509 return true; | 1453 return true; |
| 1510 } | 1454 } |
| 1511 return false; | 1455 return false; |
| 1512 } | 1456 } |
| 1513 | 1457 |
| 1514 | 1458 |
| 1515 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( | 1459 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( |
| 1516 InstanceCallInstr* call, | 1460 InstanceCallInstr* call, |
| 1517 intptr_t receiver_cid, | 1461 intptr_t receiver_cid, |
| 1518 intptr_t view_cid) { | 1462 intptr_t view_cid) { |
| 1519 Value* array = call->ArgumentAt(0)->value(); | 1463 Definition* array = call->ArgumentAt(0); |
| 1520 Value* byte_index = call->ArgumentAt(1)->value(); | 1464 Definition* byte_index = call->ArgumentAt(1); |
| 1521 | 1465 |
| 1522 AddCheckClass(call, array->Copy()); | 1466 AddReceiverCheck(call); |
| 1523 const bool is_immutable = true; | 1467 const bool is_immutable = true; |
| 1524 LoadFieldInstr* length = new LoadFieldInstr( | 1468 LoadFieldInstr* length = new LoadFieldInstr( |
| 1525 array->Copy(), | 1469 new Value(array), |
| 1526 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), | 1470 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), |
| 1527 Type::ZoneHandle(Type::SmiType()), | 1471 Type::ZoneHandle(Type::SmiType()), |
| 1528 is_immutable); | 1472 is_immutable); |
| 1529 length->set_result_cid(kSmiCid); | 1473 length->set_result_cid(kSmiCid); |
| 1530 length->set_recognized_kind( | 1474 length->set_recognized_kind( |
| 1531 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); | 1475 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); |
| 1532 InsertBefore(call, length, NULL, Definition::kValue); | 1476 InsertBefore(call, length, NULL, Definition::kValue); |
| 1533 | 1477 |
| 1534 // len_in_bytes = length * kBytesPerElement(receiver) | 1478 // len_in_bytes = length * kBytesPerElement(receiver) |
| 1535 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | 1479 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); |
| 1536 ConstantInstr* bytes_per_element = | 1480 ConstantInstr* bytes_per_element = |
| 1537 new ConstantInstr(Smi::Handle(Smi::New(element_size))); | 1481 new ConstantInstr(Smi::Handle(Smi::New(element_size))); |
| 1538 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); | 1482 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); |
| 1539 BinarySmiOpInstr* len_in_bytes = | 1483 BinarySmiOpInstr* len_in_bytes = |
| 1540 new BinarySmiOpInstr(Token::kMUL, | 1484 new BinarySmiOpInstr(Token::kMUL, |
| 1541 call, | 1485 call, |
| 1542 new Value(length), | 1486 new Value(length), |
| 1543 new Value(bytes_per_element)); | 1487 new Value(bytes_per_element)); |
| 1544 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | 1488 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); |
| 1545 | 1489 |
| 1546 // Check byte_index < len_in_bytes. | 1490 // Check byte_index < len_in_bytes. |
| 1547 InsertBefore(call, | 1491 InsertBefore(call, |
| 1548 new CheckArrayBoundInstr(new Value(len_in_bytes), | 1492 new CheckArrayBoundInstr(new Value(len_in_bytes), |
| 1549 byte_index->Copy(), | 1493 new Value(byte_index), |
| 1550 receiver_cid, | 1494 receiver_cid, |
| 1551 call), | 1495 call), |
| 1552 call->env(), | 1496 call->env(), |
| 1553 Definition::kEffect); | 1497 Definition::kEffect); |
| 1554 | 1498 |
| 1555 // TODO(fschneider): Optimistically build smi load for Int32 and Uint32 | 1499 // TODO(fschneider): Optimistically build smi load for Int32 and Uint32 |
| 1556 // loads on ia32 like we do for normal array loads, and only revert to | 1500 // loads on ia32 like we do for normal array loads, and only revert to |
| 1557 // mint case after deoptimizing here. | 1501 // mint case after deoptimizing here. |
| 1558 return new LoadIndexedInstr(array, | 1502 return new LoadIndexedInstr(new Value(array), |
| 1559 byte_index, | 1503 new Value(byte_index), |
| 1560 1, // Index scale. | 1504 1, // Index scale. |
| 1561 view_cid, | 1505 view_cid, |
| 1562 Isolate::kNoDeoptId); // Can't deoptimize. | 1506 Isolate::kNoDeoptId); // Can't deoptimize. |
| 1563 } | 1507 } |
| 1564 | 1508 |
| 1565 | 1509 |
| 1566 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 1510 // Returns a Boolean constant if all classes in ic_data yield the same type-test |
| 1567 // result and the type tests do not depend on type arguments. Otherwise return | 1511 // result and the type tests do not depend on type arguments. Otherwise return |
| 1568 // Bool::null(). | 1512 // Bool::null(). |
| 1569 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 1513 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, |
| 1570 const AbstractType& type) const { | 1514 const AbstractType& type) const { |
| 1571 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 1515 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 1572 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); | 1516 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1588 if (is_subtype != prev.value()) return Bool::null(); | 1532 if (is_subtype != prev.value()) return Bool::null(); |
| 1589 } | 1533 } |
| 1590 } | 1534 } |
| 1591 return prev.raw(); | 1535 return prev.raw(); |
| 1592 } | 1536 } |
| 1593 | 1537 |
| 1594 | 1538 |
| 1595 // TODO(srdjan): Use ICData to check if always true or false. | 1539 // TODO(srdjan): Use ICData to check if always true or false. |
| 1596 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 1540 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 1597 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 1541 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 1598 Value* left_val = call->ArgumentAt(0)->value(); | 1542 Definition* left = call->ArgumentAt(0); |
| 1599 Value* instantiator_val = call->ArgumentAt(1)->value(); | 1543 Definition* instantiator = call->ArgumentAt(1); |
| 1600 Value* type_args_val = call->ArgumentAt(2)->value(); | 1544 Definition* type_args = call->ArgumentAt(2); |
| 1601 const AbstractType& type = | 1545 const AbstractType& type = |
| 1602 AbstractType::Cast(call->ArgumentAt(3)->value()->BoundConstant()); | 1546 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 1603 const bool negate = | 1547 const bool negate = |
| 1604 Bool::Cast(call->ArgumentAt(4)->value()->BoundConstant()).value(); | 1548 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); |
| 1605 const ICData& unary_checks = | 1549 const ICData& unary_checks = |
| 1606 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 1550 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 1607 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 1551 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 1608 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 1552 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); |
| 1609 if (!as_bool.IsNull()) { | 1553 if (!as_bool.IsNull()) { |
| 1610 AddCheckClass(call, left_val->Copy()); | 1554 AddReceiverCheck(call); |
| 1611 if (negate) { | 1555 if (negate) { |
| 1612 as_bool = as_bool.value() ? Bool::False().raw() : Bool::True().raw(); | 1556 as_bool = Bool::Get(!as_bool.value()); |
| 1613 } | 1557 } |
| 1614 ConstantInstr* bool_const = new ConstantInstr(as_bool); | 1558 ConstantInstr* bool_const = new ConstantInstr(as_bool); |
| 1615 call->ReplaceWith(bool_const, current_iterator()); | 1559 ReplaceCall(call, bool_const); |
| 1616 RemovePushArguments(call); | |
| 1617 return; | 1560 return; |
| 1618 } | 1561 } |
| 1619 } | 1562 } |
| 1620 InstanceOfInstr* instance_of = | 1563 InstanceOfInstr* instance_of = |
| 1621 new InstanceOfInstr(call->token_pos(), | 1564 new InstanceOfInstr(call->token_pos(), |
| 1622 left_val, | 1565 new Value(left), |
| 1623 instantiator_val, | 1566 new Value(instantiator), |
| 1624 type_args_val, | 1567 new Value(type_args), |
| 1625 type, | 1568 type, |
| 1626 negate); | 1569 negate); |
| 1627 call->ReplaceWith(instance_of, current_iterator()); | 1570 ReplaceCall(call, instance_of); |
| 1628 RemovePushArguments(call); | |
| 1629 } | 1571 } |
| 1630 | 1572 |
| 1631 | 1573 |
| 1632 // Tries to optimize instance call by replacing it with a faster instruction | 1574 // Tries to optimize instance call by replacing it with a faster instruction |
| 1633 // (e.g, binary op, field load, ..). | 1575 // (e.g, binary op, field load, ..). |
| 1634 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 1576 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 1635 if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) { | 1577 if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) { |
| 1636 // An instance call without ICData will trigger deoptimization. | |
| 1637 return; | 1578 return; |
| 1638 } | 1579 } |
| 1639 | 1580 |
| 1640 const Token::Kind op_kind = instr->token_kind(); | 1581 const Token::Kind op_kind = instr->token_kind(); |
| 1641 // Type test is special as it always gets converted into inlined code. | 1582 // Type test is special as it always gets converted into inlined code. |
| 1642 if (Token::IsTypeTestOperator(op_kind)) { | 1583 if (Token::IsTypeTestOperator(op_kind)) { |
| 1643 ReplaceWithInstanceOf(instr); | 1584 ReplaceWithInstanceOf(instr); |
| 1644 return; | 1585 return; |
| 1645 } | 1586 } |
| 1646 | 1587 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1694 call_with_checks); | 1635 call_with_checks); |
| 1695 instr->ReplaceWith(call, current_iterator()); | 1636 instr->ReplaceWith(call, current_iterator()); |
| 1696 return; | 1637 return; |
| 1697 } | 1638 } |
| 1698 } | 1639 } |
| 1699 | 1640 |
| 1700 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 1641 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 1701 bool call_with_checks; | 1642 bool call_with_checks; |
| 1702 if (has_one_target) { | 1643 if (has_one_target) { |
| 1703 // Type propagation has not run yet, we cannot eliminate the check. | 1644 // Type propagation has not run yet, we cannot eliminate the check. |
| 1704 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1645 AddReceiverCheck(instr); |
| 1705 // Call can still deoptimize, do not detach environment from instr. | 1646 // Call can still deoptimize, do not detach environment from instr. |
| 1706 call_with_checks = false; | 1647 call_with_checks = false; |
| 1707 } else { | 1648 } else { |
| 1708 call_with_checks = true; | 1649 call_with_checks = true; |
| 1709 } | 1650 } |
| 1710 PolymorphicInstanceCallInstr* call = | 1651 PolymorphicInstanceCallInstr* call = |
| 1711 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1652 new PolymorphicInstanceCallInstr(instr, unary_checks, |
| 1712 call_with_checks); | 1653 call_with_checks); |
| 1713 instr->ReplaceWith(call, current_iterator()); | 1654 instr->ReplaceWith(call, current_iterator()); |
| 1714 } | 1655 } |
| 1715 } | 1656 } |
| 1716 | 1657 |
| 1717 | 1658 |
| 1718 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1659 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 1719 MethodRecognizer::Kind recognized_kind = | 1660 MethodRecognizer::Kind recognized_kind = |
| 1720 MethodRecognizer::RecognizeKind(call->function()); | 1661 MethodRecognizer::RecognizeKind(call->function()); |
| 1721 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 1662 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 1722 MathSqrtInstr* sqrt = new MathSqrtInstr(call->ArgumentAt(0)->value(), call); | 1663 MathSqrtInstr* sqrt = |
| 1723 call->ReplaceWith(sqrt, current_iterator()); | 1664 new MathSqrtInstr(new Value(call->ArgumentAt(0)), call); |
| 1724 RemovePushArguments(call); | 1665 ReplaceCall(call, sqrt); |
| 1725 } | 1666 } |
| 1726 } | 1667 } |
| 1727 | 1668 |
| 1728 | 1669 |
| 1729 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 1670 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
| 1730 const ICData& unary_ic_data) { | 1671 const ICData& unary_ic_data) { |
| 1731 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 1672 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
| 1732 (unary_ic_data.num_args_tested() == 1)); | 1673 (unary_ic_data.num_args_tested() == 1)); |
| 1733 if (FLAG_enable_type_checks) { | 1674 if (FLAG_enable_type_checks) { |
| 1734 // TODO(srdjan): Add assignable check node if --enable_type_checks. | 1675 // TODO(srdjan): Add assignable check node if --enable_type_checks. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1752 // TODO(srdjan): Inline special setters. | 1693 // TODO(srdjan): Inline special setters. |
| 1753 return false; | 1694 return false; |
| 1754 } | 1695 } |
| 1755 // Inline implicit instance setter. | 1696 // Inline implicit instance setter. |
| 1756 const String& field_name = | 1697 const String& field_name = |
| 1757 String::Handle(Field::NameFromSetter(instr->function_name())); | 1698 String::Handle(Field::NameFromSetter(instr->function_name())); |
| 1758 const Field& field = Field::Handle(GetField(class_id, field_name)); | 1699 const Field& field = Field::Handle(GetField(class_id, field_name)); |
| 1759 ASSERT(!field.IsNull()); | 1700 ASSERT(!field.IsNull()); |
| 1760 | 1701 |
| 1761 if (InstanceCallNeedsClassCheck(instr)) { | 1702 if (InstanceCallNeedsClassCheck(instr)) { |
| 1762 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1703 AddReceiverCheck(instr); |
| 1763 } | 1704 } |
| 1764 bool needs_store_barrier = true; | 1705 bool needs_store_barrier = true; |
| 1765 if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) { | 1706 if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) { |
| 1766 InsertBefore(instr, | 1707 InsertBefore(instr, |
| 1767 new CheckSmiInstr(instr->ArgumentAt(1)->value()->Copy(), | 1708 new CheckSmiInstr(new Value(instr->ArgumentAt(1)), |
| 1768 instr->deopt_id()), | 1709 instr->deopt_id()), |
| 1769 instr->env(), | 1710 instr->env(), |
| 1770 Definition::kEffect); | 1711 Definition::kEffect); |
| 1771 needs_store_barrier = false; | 1712 needs_store_barrier = false; |
| 1772 } | 1713 } |
| 1714 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( | |
| 1715 field, | |
| 1716 new Value(instr->ArgumentAt(0)), | |
| 1717 new Value(instr->ArgumentAt(1)), | |
| 1718 needs_store_barrier); | |
| 1773 // Detach environment from the original instruction because it can't | 1719 // Detach environment from the original instruction because it can't |
| 1774 // deoptimize. | 1720 // deoptimize. |
| 1721 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { | |
| 1722 it.CurrentValue()->RemoveFromUseList(); | |
| 1723 } | |
| 1775 instr->set_env(NULL); | 1724 instr->set_env(NULL); |
|
Vyacheslav Egorov (Google)
2013/02/08 16:44:49
Loop + set_env(NULL) can be factored out into a he
| |
| 1776 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( | 1725 ReplaceCall(instr, store); |
| 1777 field, | |
| 1778 instr->ArgumentAt(0)->value(), | |
| 1779 instr->ArgumentAt(1)->value(), | |
| 1780 needs_store_barrier); | |
| 1781 instr->ReplaceWith(store, current_iterator()); | |
| 1782 RemovePushArguments(instr); | |
| 1783 return true; | 1726 return true; |
| 1784 } | 1727 } |
| 1785 | 1728 |
| 1786 | 1729 |
| 1787 static void HandleRelationalOp(FlowGraphOptimizer* optimizer, | 1730 void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) { |
| 1788 RelationalOpInstr* comp, | |
| 1789 Instruction* instr) { | |
| 1790 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 1731 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 1791 return; | 1732 return; |
| 1792 } | 1733 } |
| 1793 const ICData& ic_data = *comp->ic_data(); | 1734 const ICData& ic_data = *comp->ic_data(); |
| 1735 Instruction* instr = current_iterator()->Current(); | |
|
Vyacheslav Egorov (Google)
2013/02/08 16:44:49
This is somewhat confusing.
Consider calling Han
| |
| 1794 if (ic_data.NumberOfChecks() == 1) { | 1736 if (ic_data.NumberOfChecks() == 1) { |
| 1795 ASSERT(ic_data.HasOneTarget()); | 1737 ASSERT(ic_data.HasOneTarget()); |
| 1796 if (HasOnlyTwoSmis(ic_data)) { | 1738 if (HasOnlyTwoSmis(ic_data)) { |
| 1797 optimizer->InsertBefore( | 1739 InsertBefore(instr, |
| 1798 instr, | 1740 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| 1799 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 1741 instr->env(), |
| 1800 instr->env(), | 1742 Definition::kEffect); |
| 1801 Definition::kEffect); | 1743 InsertBefore(instr, |
| 1802 optimizer->InsertBefore( | 1744 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| 1803 instr, | 1745 instr->env(), |
| 1804 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 1746 Definition::kEffect); |
| 1805 instr->env(), | |
| 1806 Definition::kEffect); | |
| 1807 comp->set_operands_class_id(kSmiCid); | 1747 comp->set_operands_class_id(kSmiCid); |
| 1808 } else if (ShouldSpecializeForDouble(ic_data)) { | 1748 } else if (ShouldSpecializeForDouble(ic_data)) { |
| 1809 comp->set_operands_class_id(kDoubleCid); | 1749 comp->set_operands_class_id(kDoubleCid); |
| 1810 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1750 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1811 FlowGraphCompiler::SupportsUnboxedMints()) { | 1751 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1812 comp->set_operands_class_id(kMintCid); | 1752 comp->set_operands_class_id(kMintCid); |
| 1813 } else { | 1753 } else { |
| 1814 ASSERT(comp->operands_class_id() == kIllegalCid); | 1754 ASSERT(comp->operands_class_id() == kIllegalCid); |
| 1815 } | 1755 } |
| 1816 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1756 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1817 FlowGraphCompiler::SupportsUnboxedMints()) { | 1757 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1818 comp->set_operands_class_id(kMintCid); | 1758 comp->set_operands_class_id(kMintCid); |
| 1819 } | 1759 } |
| 1820 } | 1760 } |
| 1821 | 1761 |
| 1822 | 1762 |
| 1823 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { | 1763 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) { |
| 1824 HandleRelationalOp(this, instr, instr); | 1764 HandleRelationalOp(instr); |
| 1825 } | 1765 } |
| 1826 | 1766 |
| 1827 | 1767 |
| 1828 template <typename T> | 1768 template <typename T> |
| 1829 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, | 1769 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, |
| 1830 EqualityCompareInstr* comp, | 1770 T current_instruction) { |
|
Vyacheslav Egorov (Google)
2013/02/08 16:44:49
I think this function is un-necessarily a template
Kevin Millikin (Google)
2013/02/19 10:49:30
I agree the architecture is a mess. It's a preexi
| |
| 1831 T instr, | |
| 1832 ForwardInstructionIterator* iterator) { | |
| 1833 // If one of the inputs is null, no ICdata will be collected. | 1771 // If one of the inputs is null, no ICdata will be collected. |
| 1834 if (comp->left()->BindsToConstantNull() || | 1772 if (comp->left()->BindsToConstantNull() || |
| 1835 comp->right()->BindsToConstantNull()) { | 1773 comp->right()->BindsToConstantNull()) { |
| 1836 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? | 1774 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? |
| 1837 Token::kEQ_STRICT : Token::kNE_STRICT; | 1775 Token::kEQ_STRICT : Token::kNE_STRICT; |
| 1838 StrictCompareInstr* strict_comp = | 1776 StrictCompareInstr* strict_comp = |
| 1839 new StrictCompareInstr(strict_kind, comp->left(), comp->right()); | 1777 new StrictCompareInstr(strict_kind, |
| 1840 instr->ReplaceWith(strict_comp, iterator); | 1778 comp->left()->Copy(), |
| 1779 comp->right()->Copy()); | |
| 1780 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
| 1841 return; | 1781 return; |
| 1842 } | 1782 } |
| 1843 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | 1783 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { |
| 1844 return; | 1784 return; |
| 1845 } | 1785 } |
| 1846 ASSERT(comp->ic_data()->num_args_tested() == 2); | 1786 ASSERT(comp->ic_data()->num_args_tested() == 2); |
| 1847 if (comp->ic_data()->NumberOfChecks() == 1) { | 1787 if (comp->ic_data()->NumberOfChecks() == 1) { |
| 1848 GrowableArray<intptr_t> class_ids; | 1788 GrowableArray<intptr_t> class_ids; |
| 1849 Function& target = Function::Handle(); | 1789 Function& target = Function::Handle(); |
| 1850 comp->ic_data()->GetCheckAt(0, &class_ids, &target); | 1790 comp->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 1851 // TODO(srdjan): allow for mixed mode int/double comparison. | 1791 // TODO(srdjan): allow for mixed mode int/double comparison. |
| 1852 | 1792 |
| 1853 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { | 1793 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { |
| 1854 optimizer->InsertBefore( | 1794 InsertBefore(current_instruction, |
| 1855 instr, | 1795 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), |
| 1856 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | 1796 current_instruction->env(), |
| 1857 instr->env(), | 1797 Definition::kEffect); |
| 1858 Definition::kEffect); | 1798 InsertBefore(current_instruction, |
| 1859 optimizer->InsertBefore( | 1799 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), |
| 1860 instr, | 1800 current_instruction->env(), |
| 1861 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | 1801 Definition::kEffect); |
| 1862 instr->env(), | |
| 1863 Definition::kEffect); | |
| 1864 comp->set_receiver_class_id(kSmiCid); | 1802 comp->set_receiver_class_id(kSmiCid); |
| 1865 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { | 1803 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { |
| 1866 comp->set_receiver_class_id(kDoubleCid); | 1804 comp->set_receiver_class_id(kDoubleCid); |
| 1867 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1805 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1868 FlowGraphCompiler::SupportsUnboxedMints()) { | 1806 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1869 comp->set_receiver_class_id(kMintCid); | 1807 comp->set_receiver_class_id(kMintCid); |
| 1870 } else { | 1808 } else { |
| 1871 ASSERT(comp->receiver_class_id() == kIllegalCid); | 1809 ASSERT(comp->receiver_class_id() == kIllegalCid); |
| 1872 } | 1810 } |
| 1873 } else if (HasTwoMintOrSmi(*comp->ic_data()) && | 1811 } else if (HasTwoMintOrSmi(*comp->ic_data()) && |
| 1874 FlowGraphCompiler::SupportsUnboxedMints()) { | 1812 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1875 comp->set_receiver_class_id(kMintCid); | 1813 comp->set_receiver_class_id(kMintCid); |
| 1876 } | 1814 } |
| 1877 | 1815 |
| 1878 if (comp->receiver_class_id() != kIllegalCid) { | 1816 if (comp->receiver_class_id() != kIllegalCid) { |
| 1879 // Done. | 1817 // Done. |
| 1880 return; | 1818 return; |
| 1881 } | 1819 } |
| 1882 | 1820 |
| 1883 // Check if ICDData contains checks with Smi/Null combinations. In that case | 1821 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 1884 // we can still emit the optimized Smi equality operation but need to add | 1822 // we can still emit the optimized Smi equality operation but need to add |
| 1885 // checks for null or Smi. | 1823 // checks for null or Smi. |
| 1886 // TODO(srdjan): Add it for Double and Mint. | 1824 // TODO(srdjan): Add it for Double and Mint. |
| 1887 GrowableArray<intptr_t> smi_or_null(2); | 1825 GrowableArray<intptr_t> smi_or_null(2); |
| 1888 smi_or_null.Add(kSmiCid); | 1826 smi_or_null.Add(kSmiCid); |
| 1889 smi_or_null.Add(kNullCid); | 1827 smi_or_null.Add(kNullCid); |
| 1890 if (ICDataHasOnlyReceiverArgumentClassIds( | 1828 if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(), |
| 1891 *comp->ic_data(), smi_or_null, smi_or_null)) { | 1829 smi_or_null, |
| 1830 smi_or_null)) { | |
| 1892 const ICData& unary_checks_0 = | 1831 const ICData& unary_checks_0 = |
| 1893 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 1832 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 1894 const intptr_t deopt_id = comp->deopt_id(); | 1833 AddCheckClass(comp->left()->definition(), |
| 1895 if ((unary_checks_0.NumberOfChecks() == 1) && | 1834 unary_checks_0, |
| 1896 (unary_checks_0.GetReceiverClassIdAt(0) == kSmiCid)) { | 1835 comp->deopt_id(), |
| 1897 // Smi only. | 1836 current_instruction->env(), |
| 1898 optimizer->InsertBefore( | 1837 current_instruction); |
| 1899 instr, | |
| 1900 new CheckSmiInstr(comp->left()->Copy(), deopt_id), | |
| 1901 instr->env(), | |
| 1902 Definition::kEffect); | |
| 1903 } else { | |
| 1904 // Smi or NULL. | |
| 1905 optimizer->InsertBefore( | |
| 1906 instr, | |
| 1907 new CheckClassInstr(comp->left()->Copy(), deopt_id, unary_checks_0), | |
| 1908 instr->env(), | |
| 1909 Definition::kEffect); | |
| 1910 } | |
| 1911 | 1838 |
| 1912 const ICData& unary_checks_1 = | 1839 const ICData& unary_checks_1 = |
| 1913 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | 1840 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1914 if ((unary_checks_1.NumberOfChecks() == 1) && | 1841 AddCheckClass(comp->right()->definition(), |
| 1915 (unary_checks_1.GetReceiverClassIdAt(0) == kSmiCid)) { | 1842 unary_checks_1, |
| 1916 // Smi only. | 1843 comp->deopt_id(), |
| 1917 optimizer->InsertBefore( | 1844 current_instruction->env(), |
| 1918 instr, | 1845 current_instruction); |
| 1919 new CheckSmiInstr(comp->right()->Copy(), deopt_id), | |
| 1920 instr->env(), | |
| 1921 Definition::kEffect); | |
| 1922 } else { | |
| 1923 // Smi or NULL. | |
| 1924 optimizer->InsertBefore( | |
| 1925 instr, | |
| 1926 new CheckClassInstr(comp->right()->Copy(), deopt_id, unary_checks_1), | |
| 1927 instr->env(), | |
| 1928 Definition::kEffect); | |
| 1929 } | |
| 1930 comp->set_receiver_class_id(kSmiCid); | 1846 comp->set_receiver_class_id(kSmiCid); |
| 1931 } | 1847 } |
| 1932 } | 1848 } |
| 1933 | 1849 |
| 1934 | 1850 |
| 1935 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | 1851 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 1936 HandleEqualityCompare(this, instr, instr, current_iterator()); | 1852 HandleEqualityCompare(instr, instr); |
| 1937 } | 1853 } |
| 1938 | 1854 |
| 1939 | 1855 |
| 1940 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | 1856 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
| 1941 ComparisonInstr* comparison = instr->comparison(); | 1857 ComparisonInstr* comparison = instr->comparison(); |
| 1942 if (comparison->IsRelationalOp()) { | 1858 if (comparison->IsRelationalOp()) { |
| 1943 HandleRelationalOp(this, comparison->AsRelationalOp(), instr); | 1859 HandleRelationalOp(comparison->AsRelationalOp()); |
| 1944 } else if (comparison->IsEqualityCompare()) { | 1860 } else if (comparison->IsEqualityCompare()) { |
| 1945 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr, | 1861 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); |
| 1946 current_iterator()); | |
| 1947 } else { | 1862 } else { |
| 1948 ASSERT(comparison->IsStrictCompare()); | 1863 ASSERT(comparison->IsStrictCompare()); |
| 1949 // Nothing to do. | 1864 // Nothing to do. |
| 1950 } | 1865 } |
| 1951 } | 1866 } |
| 1952 | 1867 |
| 1953 | 1868 |
| 1954 static bool MayBeBoxableNumber(intptr_t cid) { | 1869 static bool MayBeBoxableNumber(intptr_t cid) { |
| 1955 return (cid == kDynamicCid) || | 1870 return (cid == kDynamicCid) || |
| 1956 (cid == kMintCid) || | 1871 (cid == kMintCid) || |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2402 } | 2317 } |
| 2403 } | 2318 } |
| 2404 | 2319 |
| 2405 | 2320 |
| 2406 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, | 2321 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, |
| 2407 Range* constraint_range, | 2322 Range* constraint_range, |
| 2408 Instruction* after) { | 2323 Instruction* after) { |
| 2409 // No need to constrain constants. | 2324 // No need to constrain constants. |
| 2410 if (defn->IsConstant()) return NULL; | 2325 if (defn->IsConstant()) return NULL; |
| 2411 | 2326 |
| 2412 Value* value = new Value(defn); | 2327 ConstraintInstr* constraint = |
| 2413 ConstraintInstr* constraint = new ConstraintInstr(value, constraint_range); | 2328 new ConstraintInstr(new Value(defn), constraint_range); |
| 2414 constraint->InsertAfter(after); | 2329 flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue); |
| 2415 constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 2330 RenameDominatedUses(defn, constraint, constraint); |
|
Vyacheslav Egorov (Google)
2013/02/08 16:44:49
That was an easy fix. Nice!
| |
| 2416 RenameDominatedUses(defn, after, constraint); | |
| 2417 constraints_.Add(constraint); | 2331 constraints_.Add(constraint); |
| 2418 value->set_instruction(constraint); | |
| 2419 value->set_use_index(0); | |
| 2420 defn->AddInputUse(value); | |
| 2421 return constraint; | 2332 return constraint; |
| 2422 } | 2333 } |
| 2423 | 2334 |
| 2424 | 2335 |
| 2425 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { | 2336 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { |
| 2426 BranchInstr* branch = use->instruction()->AsBranch(); | 2337 BranchInstr* branch = use->instruction()->AsBranch(); |
| 2427 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); | 2338 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); |
| 2428 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { | 2339 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { |
| 2429 // Found comparison of two smis. Constrain defn at true and false | 2340 // Found comparison of two smis. Constrain defn at true and false |
| 2430 // successors using the other operand as a boundary. | 2341 // successors using the other operand as a boundary. |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2844 | 2755 |
| 2845 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) { | 2756 void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) { |
| 2846 bool is_null; | 2757 bool is_null; |
| 2847 bool is_instance = false; | 2758 bool is_instance = false; |
| 2848 if (FLAG_eliminate_type_checks && | 2759 if (FLAG_eliminate_type_checks && |
| 2849 instr->value()->CanComputeIsNull(&is_null) && | 2760 instr->value()->CanComputeIsNull(&is_null) && |
| 2850 (is_null || | 2761 (is_null || |
| 2851 instr->value()->CanComputeIsInstanceOf(instr->type(), &is_instance))) { | 2762 instr->value()->CanComputeIsInstanceOf(instr->type(), &is_instance))) { |
| 2852 bool val = instr->negate_result() ? !is_instance : is_instance; | 2763 bool val = instr->negate_result() ? !is_instance : is_instance; |
| 2853 Definition* result = new ConstantInstr(val ? Bool::True() : Bool::False()); | 2764 Definition* result = new ConstantInstr(val ? Bool::True() : Bool::False()); |
| 2854 result->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 2765 instr->ReplaceWith(result, current_iterator()); |
| 2855 result->InsertBefore(instr); | |
| 2856 // Replace uses and remove the current instruction via the iterator. | |
| 2857 instr->ReplaceUsesWith(result); | |
| 2858 ASSERT(current_iterator()->Current() == instr); | |
| 2859 current_iterator()->RemoveCurrentFromGraph(); | |
| 2860 if (FLAG_trace_optimization) { | 2766 if (FLAG_trace_optimization) { |
| 2861 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | 2767 OS::Print("Replacing v%"Pd" with v%"Pd"\n", |
| 2862 instr->ssa_temp_index(), | 2768 instr->ssa_temp_index(), |
| 2863 result->ssa_temp_index()); | 2769 result->ssa_temp_index()); |
| 2864 } | 2770 } |
| 2865 | 2771 |
| 2866 if (FLAG_trace_type_check_elimination) { | 2772 if (FLAG_trace_type_check_elimination) { |
| 2867 FlowGraphPrinter::PrintTypeCheck(parsed_function(), | 2773 FlowGraphPrinter::PrintTypeCheck(parsed_function(), |
| 2868 instr->token_pos(), | 2774 instr->token_pos(), |
| 2869 instr->value(), | 2775 instr->value(), |
| (...skipping 1816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4686 | 4592 |
| 4687 if (FLAG_trace_constant_propagation) { | 4593 if (FLAG_trace_constant_propagation) { |
| 4688 OS::Print("\n==== After constant propagation ====\n"); | 4594 OS::Print("\n==== After constant propagation ====\n"); |
| 4689 FlowGraphPrinter printer(*graph_); | 4595 FlowGraphPrinter printer(*graph_); |
| 4690 printer.PrintBlocks(); | 4596 printer.PrintBlocks(); |
| 4691 } | 4597 } |
| 4692 } | 4598 } |
| 4693 | 4599 |
| 4694 | 4600 |
| 4695 } // namespace dart | 4601 } // namespace dart |
| OLD | NEW |