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

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

Issue 12212093: Convert some compiler passes to preserve valid def-use chains. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/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
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_ = &it; 50 current_iterator_ = &it;
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698