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

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

Powered by Google App Engine
This is Rietveld 408576698