| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/cha.h" | 7 #include "vm/cha.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/hash_map.h" | 9 #include "vm/hash_map.h" |
| 10 #include "vm/il_printer.h" | 10 #include "vm/il_printer.h" |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 if (op_kind == Token::kASSIGN_INDEX) return false; | 219 if (op_kind == Token::kASSIGN_INDEX) return false; |
| 220 // Fall through. | 220 // Fall through. |
| 221 case kArrayCid: | 221 case kArrayCid: |
| 222 case kGrowableObjectArrayCid: { | 222 case kGrowableObjectArrayCid: { |
| 223 Value* array = comp->ArgumentAt(0)->value(); | 223 Value* array = comp->ArgumentAt(0)->value(); |
| 224 Value* index = comp->ArgumentAt(1)->value(); | 224 Value* index = comp->ArgumentAt(1)->value(); |
| 225 // Insert class check and index smi checks and attach a copy of the | 225 // Insert class check and index smi checks and attach a copy of the |
| 226 // original environment because the operation can still deoptimize. | 226 // original environment because the operation can still deoptimize. |
| 227 AddCheckClass(instr, comp, array->Copy()); | 227 AddCheckClass(instr, comp, array->Copy()); |
| 228 InsertBefore(instr, | 228 InsertBefore(instr, |
| 229 new CheckSmiComp(index->Copy(), comp), | 229 new CheckSmiComp(index->Copy(), comp->deopt_id()), |
| 230 instr->env(), | 230 instr->env(), |
| 231 BindInstr::kUnused); | 231 BindInstr::kUnused); |
| 232 // Insert array bounds check. | 232 // Insert array bounds check. |
| 233 InsertBefore(instr, | 233 InsertBefore(instr, |
| 234 new CheckArrayBoundComp(array->Copy(), | 234 new CheckArrayBoundComp(array->Copy(), |
| 235 index->Copy(), | 235 index->Copy(), |
| 236 class_id, | 236 class_id, |
| 237 comp), | 237 comp), |
| 238 instr->env(), | 238 instr->env(), |
| 239 BindInstr::kUnused); | 239 BindInstr::kUnused); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 bin_op->set_ic_data(comp->ic_data()); | 390 bin_op->set_ic_data(comp->ic_data()); |
| 391 instr->set_computation(bin_op); | 391 instr->set_computation(bin_op); |
| 392 RemovePushArguments(comp); | 392 RemovePushArguments(comp); |
| 393 } else { | 393 } else { |
| 394 ASSERT(operands_type == kSmiCid); | 394 ASSERT(operands_type == kSmiCid); |
| 395 Value* left = comp->ArgumentAt(0)->value(); | 395 Value* left = comp->ArgumentAt(0)->value(); |
| 396 Value* right = comp->ArgumentAt(1)->value(); | 396 Value* right = comp->ArgumentAt(1)->value(); |
| 397 // Insert two smi checks and attach a copy of the original | 397 // Insert two smi checks and attach a copy of the original |
| 398 // environment because the smi operation can still deoptimize. | 398 // environment because the smi operation can still deoptimize. |
| 399 InsertBefore(instr, | 399 InsertBefore(instr, |
| 400 new CheckSmiComp(left->Copy(), comp), | 400 new CheckSmiComp(left->Copy(), comp->deopt_id()), |
| 401 instr->env(), | 401 instr->env(), |
| 402 BindInstr::kUnused); | 402 BindInstr::kUnused); |
| 403 InsertBefore(instr, | 403 InsertBefore(instr, |
| 404 new CheckSmiComp(right->Copy(), comp), | 404 new CheckSmiComp(right->Copy(), comp->deopt_id()), |
| 405 instr->env(), | 405 instr->env(), |
| 406 BindInstr::kUnused); | 406 BindInstr::kUnused); |
| 407 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, | 407 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, |
| 408 comp, | 408 comp, |
| 409 left, | 409 left, |
| 410 right); | 410 right); |
| 411 bin_op->set_ic_data(comp->ic_data()); | 411 bin_op->set_ic_data(comp->ic_data()); |
| 412 instr->set_computation(bin_op); | 412 instr->set_computation(bin_op); |
| 413 RemovePushArguments(comp); | 413 RemovePushArguments(comp); |
| 414 } | 414 } |
| 415 return true; | 415 return true; |
| 416 } | 416 } |
| 417 | 417 |
| 418 | 418 |
| 419 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, | 419 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, |
| 420 InstanceCallComp* comp, | 420 InstanceCallComp* comp, |
| 421 Token::Kind op_kind) { | 421 Token::Kind op_kind) { |
| 422 if (comp->ic_data()->NumberOfChecks() != 1) { | 422 if (comp->ic_data()->NumberOfChecks() != 1) { |
| 423 // TODO(srdjan): Not yet supported. | 423 // TODO(srdjan): Not yet supported. |
| 424 return false; | 424 return false; |
| 425 } | 425 } |
| 426 ASSERT(comp->ArgumentCount() == 1); | 426 ASSERT(comp->ArgumentCount() == 1); |
| 427 Computation* unary_op = NULL; | 427 Computation* unary_op = NULL; |
| 428 if (HasOneSmi(*comp->ic_data())) { | 428 if (HasOneSmi(*comp->ic_data())) { |
| 429 Value* value = comp->ArgumentAt(0)->value(); | 429 Value* value = comp->ArgumentAt(0)->value(); |
| 430 InsertBefore(instr, | 430 InsertBefore(instr, |
| 431 new CheckSmiComp(value->Copy(), comp), | 431 new CheckSmiComp(value->Copy(), comp->deopt_id()), |
| 432 instr->env(), | 432 instr->env(), |
| 433 BindInstr::kUnused); | 433 BindInstr::kUnused); |
| 434 unary_op = new UnarySmiOpComp(op_kind, | 434 unary_op = new UnarySmiOpComp(op_kind, |
| 435 (op_kind == Token::kNEGATE) ? comp : NULL, | 435 (op_kind == Token::kNEGATE) ? comp : NULL, |
| 436 value); | 436 value); |
| 437 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { | 437 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
| 438 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); | 438 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); |
| 439 } | 439 } |
| 440 if (unary_op == NULL) return false; | 440 if (unary_op == NULL) return false; |
| 441 | 441 |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 689 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 690 field, | 690 field, |
| 691 comp->ArgumentAt(0)->value(), | 691 comp->ArgumentAt(0)->value(), |
| 692 comp->ArgumentAt(1)->value()); | 692 comp->ArgumentAt(1)->value()); |
| 693 instr->set_computation(store); | 693 instr->set_computation(store); |
| 694 RemovePushArguments(comp); | 694 RemovePushArguments(comp); |
| 695 return true; | 695 return true; |
| 696 } | 696 } |
| 697 | 697 |
| 698 | 698 |
| 699 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, | 699 // TODO(fschneider): Once we get rid of the distinction between Instruction |
| 700 BindInstr* instr) { | 700 // and computation, this helper can go away. |
| 701 static void HandleRelationalOp(FlowGraphOptimizer* optimizer, |
| 702 RelationalOpComp* comp, |
| 703 Instruction* instr) { |
| 701 if (!comp->HasICData()) return; | 704 if (!comp->HasICData()) return; |
| 702 | 705 |
| 703 const ICData& ic_data = *comp->ic_data(); | 706 const ICData& ic_data = *comp->ic_data(); |
| 704 if (ic_data.NumberOfChecks() == 0) return; | 707 if (ic_data.NumberOfChecks() == 0) return; |
| 705 // TODO(srdjan): Add multiple receiver type support. | 708 // TODO(srdjan): Add multiple receiver type support. |
| 706 if (ic_data.NumberOfChecks() != 1) return; | 709 if (ic_data.NumberOfChecks() != 1) return; |
| 707 ASSERT(HasOneTarget(ic_data)); | 710 ASSERT(HasOneTarget(ic_data)); |
| 708 | 711 |
| 709 if (HasOnlyTwoSmi(ic_data)) { | 712 if (HasOnlyTwoSmi(ic_data)) { |
| 713 optimizer->InsertBefore( |
| 714 instr, |
| 715 new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), |
| 716 instr->env(), |
| 717 BindInstr::kUnused); |
| 718 optimizer->InsertBefore( |
| 719 instr, |
| 720 new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), |
| 721 instr->env(), |
| 722 BindInstr::kUnused); |
| 710 comp->set_operands_class_id(kSmiCid); | 723 comp->set_operands_class_id(kSmiCid); |
| 711 } else if (HasOnlyTwoDouble(ic_data)) { | 724 } else if (HasOnlyTwoDouble(ic_data)) { |
| 712 comp->set_operands_class_id(kDoubleCid); | 725 comp->set_operands_class_id(kDoubleCid); |
| 713 } else if (comp->ic_data()->AllReceiversAreNumbers()) { | 726 } else if (comp->ic_data()->AllReceiversAreNumbers()) { |
| 714 comp->set_operands_class_id(kNumberCid); | 727 comp->set_operands_class_id(kNumberCid); |
| 715 } | 728 } |
| 716 } | 729 } |
| 717 | 730 |
| 731 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, |
| 732 BindInstr* instr) { |
| 733 HandleRelationalOp(this, comp, instr); |
| 734 } |
| 718 | 735 |
| 719 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp, | 736 |
| 720 BindInstr* instr) { | 737 // TODO(fschneider): Once we get rid of the distinction between Instruction |
| 738 // and computation, this helper can go away. |
| 739 template <typename T> |
| 740 static void HandleEqualityCompare(FlowGraphOptimizer* optimizer, |
| 741 EqualityCompareComp* comp, |
| 742 T instr) { |
| 721 // If one of the inputs is null, no ICdata will be collected. | 743 // If one of the inputs is null, no ICdata will be collected. |
| 722 if (comp->left()->BindsToConstantNull() || | 744 if (comp->left()->BindsToConstantNull() || |
| 723 comp->right()->BindsToConstantNull()) { | 745 comp->right()->BindsToConstantNull()) { |
| 724 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? | 746 Token::Kind strict_kind = (comp->kind() == Token::kEQ) ? |
| 725 Token::kEQ_STRICT : Token::kNE_STRICT; | 747 Token::kEQ_STRICT : Token::kNE_STRICT; |
| 726 StrictCompareComp* strict_comp = | 748 StrictCompareComp* strict_comp = |
| 727 new StrictCompareComp(strict_kind, comp->left(), comp->right()); | 749 new StrictCompareComp(strict_kind, comp->left(), comp->right()); |
| 728 instr->set_computation(strict_comp); | 750 instr->set_computation(strict_comp); |
| 729 return; | 751 return; |
| 730 } | 752 } |
| 731 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return; | 753 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) return; |
| 732 if (comp->ic_data()->NumberOfChecks() == 1) { | 754 if (comp->ic_data()->NumberOfChecks() == 1) { |
| 733 ASSERT(comp->ic_data()->num_args_tested() == 2); | 755 ASSERT(comp->ic_data()->num_args_tested() == 2); |
| 734 GrowableArray<intptr_t> class_ids; | 756 GrowableArray<intptr_t> class_ids; |
| 735 Function& target = Function::Handle(); | 757 Function& target = Function::Handle(); |
| 736 comp->ic_data()->GetCheckAt(0, &class_ids, &target); | 758 comp->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 737 // TODO(srdjan): allow for mixed mode comparison. | 759 // TODO(srdjan): allow for mixed mode comparison. |
| 738 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { | 760 if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) { |
| 761 optimizer->InsertBefore( |
| 762 instr, |
| 763 new CheckSmiComp(comp->left()->Copy(), comp->deopt_id()), |
| 764 instr->env(), |
| 765 BindInstr::kUnused); |
| 766 optimizer->InsertBefore( |
| 767 instr, |
| 768 new CheckSmiComp(comp->right()->Copy(), comp->deopt_id()), |
| 769 instr->env(), |
| 770 BindInstr::kUnused); |
| 739 comp->set_receiver_class_id(kSmiCid); | 771 comp->set_receiver_class_id(kSmiCid); |
| 740 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { | 772 } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) { |
| 741 comp->set_receiver_class_id(kDoubleCid); | 773 comp->set_receiver_class_id(kDoubleCid); |
| 742 } else { | 774 } else { |
| 743 ASSERT(comp->receiver_class_id() == kIllegalCid); | 775 ASSERT(comp->receiver_class_id() == kIllegalCid); |
| 744 } | 776 } |
| 745 } else if (comp->ic_data()->AllReceiversAreNumbers()) { | 777 } else if (comp->ic_data()->AllReceiversAreNumbers()) { |
| 746 comp->set_receiver_class_id(kNumberCid); | 778 comp->set_receiver_class_id(kNumberCid); |
| 747 } | 779 } |
| 748 } | 780 } |
| 749 | 781 |
| 750 | 782 |
| 783 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp, |
| 784 BindInstr* instr) { |
| 785 HandleEqualityCompare(this, comp, instr); |
| 786 } |
| 787 |
| 788 |
| 751 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 789 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 752 instr->computation()->Accept(this, instr); | 790 instr->computation()->Accept(this, instr); |
| 753 } | 791 } |
| 754 | 792 |
| 755 | 793 |
| 756 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | 794 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { |
| 757 instr->computation()->Accept(this, NULL); | 795 ComparisonComp* comparison = instr->computation(); |
| 796 if (comparison->IsRelationalOp()) { |
| 797 HandleRelationalOp(this, comparison->AsRelationalOp(), instr); |
| 798 } else if (comparison->IsEqualityCompare()) { |
| 799 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr); |
| 800 } else { |
| 801 ASSERT(comparison->IsStrictCompare()); |
| 802 // Nothing to do. |
| 803 } |
| 758 } | 804 } |
| 759 | 805 |
| 760 | 806 |
| 761 void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, | 807 void FlowGraphTypePropagator::VisitAssertAssignable(AssertAssignableComp* comp, |
| 762 BindInstr* instr) { | 808 BindInstr* instr) { |
| 763 if (FLAG_eliminate_type_checks && | 809 if (FLAG_eliminate_type_checks && |
| 764 !comp->is_eliminated() && | 810 !comp->is_eliminated() && |
| 765 comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { | 811 comp->value()->CompileTypeIsMoreSpecificThan(comp->dst_type())) { |
| 766 // TODO(regis): Remove is_eliminated_ field and support. | 812 // TODO(regis): Remove is_eliminated_ field and support. |
| 767 comp->eliminate(); | 813 comp->eliminate(); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. | 1112 DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. |
| 1067 OptimizeRecursive(child, &child_map); | 1113 OptimizeRecursive(child, &child_map); |
| 1068 } else { | 1114 } else { |
| 1069 OptimizeRecursive(child, map); // Reuse map for the last child. | 1115 OptimizeRecursive(child, map); // Reuse map for the last child. |
| 1070 } | 1116 } |
| 1071 } | 1117 } |
| 1072 } | 1118 } |
| 1073 | 1119 |
| 1074 | 1120 |
| 1075 } // namespace dart | 1121 } // namespace dart |
| OLD | NEW |