OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 phis_.RemoveElement(phi); | 107 phis_.RemoveElement(phi); |
108 phi->SetBlock(NULL); | 108 phi->SetBlock(NULL); |
109 } | 109 } |
110 | 110 |
111 | 111 |
112 void HBasicBlock::AddInstruction(HInstruction* instr) { | 112 void HBasicBlock::AddInstruction(HInstruction* instr) { |
113 ASSERT(!IsStartBlock() || !IsFinished()); | 113 ASSERT(!IsStartBlock() || !IsFinished()); |
114 ASSERT(!instr->IsLinked()); | 114 ASSERT(!instr->IsLinked()); |
115 ASSERT(!IsFinished()); | 115 ASSERT(!IsFinished()); |
116 if (first_ == NULL) { | 116 if (first_ == NULL) { |
| 117 ASSERT(last_environment() != NULL); |
| 118 ASSERT(!last_environment()->ast_id().IsNone()); |
117 HBlockEntry* entry = new(zone()) HBlockEntry(); | 119 HBlockEntry* entry = new(zone()) HBlockEntry(); |
118 entry->InitializeAsFirst(this); | 120 entry->InitializeAsFirst(this); |
119 first_ = last_ = entry; | 121 first_ = last_ = entry; |
120 } | 122 } |
121 instr->InsertAfter(last_); | 123 instr->InsertAfter(last_); |
122 } | 124 } |
123 | 125 |
124 | 126 |
125 HDeoptimize* HBasicBlock::CreateDeoptimize( | 127 HDeoptimize* HBasicBlock::CreateDeoptimize( |
126 HDeoptimize::UseEnvironment has_uses) { | 128 HDeoptimize::UseEnvironment has_uses) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 for (int i = 0; i < length; i++) { | 226 for (int i = 0; i < length; i++) { |
225 HBasicBlock* predecessor = predecessors_[i]; | 227 HBasicBlock* predecessor = predecessors_[i]; |
226 ASSERT(predecessor->end()->IsGoto()); | 228 ASSERT(predecessor->end()->IsGoto()); |
227 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); | 229 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
228 // We only need to verify the ID once. | 230 // We only need to verify the ID once. |
229 ASSERT(i != 0 || | 231 ASSERT(i != 0 || |
230 (predecessor->last_environment()->closure().is_null() || | 232 (predecessor->last_environment()->closure().is_null() || |
231 predecessor->last_environment()->closure()->shared() | 233 predecessor->last_environment()->closure()->shared() |
232 ->VerifyBailoutId(ast_id))); | 234 ->VerifyBailoutId(ast_id))); |
233 simulate->set_ast_id(ast_id); | 235 simulate->set_ast_id(ast_id); |
| 236 predecessor->last_environment()->set_ast_id(ast_id); |
234 } | 237 } |
235 } | 238 } |
236 | 239 |
237 | 240 |
238 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 241 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
239 HBasicBlock* current = other->dominator(); | 242 HBasicBlock* current = other->dominator(); |
240 while (current != NULL) { | 243 while (current != NULL) { |
241 if (current == this) return true; | 244 if (current == this) return true; |
242 current = current->dominator(); | 245 current = current->dominator(); |
243 } | 246 } |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
637 HConstant* HGraph::GetConstantHole() { | 640 HConstant* HGraph::GetConstantHole() { |
638 return GetConstant(&constant_hole_, isolate()->factory()->the_hole_value()); | 641 return GetConstant(&constant_hole_, isolate()->factory()->the_hole_value()); |
639 } | 642 } |
640 | 643 |
641 | 644 |
642 HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder, BailoutId id) | 645 HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder, BailoutId id) |
643 : builder_(builder), | 646 : builder_(builder), |
644 finished_(false), | 647 finished_(false), |
645 id_(id) { | 648 id_(id) { |
646 HEnvironment* env = builder->environment(); | 649 HEnvironment* env = builder->environment(); |
647 failure_block_ = builder->CreateBasicBlock(env->Copy()); | 650 failure_block_ = builder->CreateBasicBlock(env->CopyWithoutHistory()); |
648 merge_block_ = builder->CreateBasicBlock(env->Copy()); | 651 merge_block_ = builder->CreateBasicBlock(env->CopyWithoutHistory()); |
649 } | 652 } |
650 | 653 |
651 | 654 |
652 void HGraphBuilder::CheckBuilder::CheckNotUndefined(HValue* value) { | 655 HValue* HGraphBuilder::CheckBuilder::CheckNotUndefined(HValue* value) { |
653 HEnvironment* env = builder_->environment(); | 656 HEnvironment* env = builder_->environment(); |
654 HIsNilAndBranch* compare = | 657 HIsNilAndBranch* compare = |
655 new(zone()) HIsNilAndBranch(value, kStrictEquality, kUndefinedValue); | 658 new(zone()) HIsNilAndBranch(value, kStrictEquality, kUndefinedValue); |
656 HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy()); | 659 HBasicBlock* success_block = |
657 HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy()); | 660 builder_->CreateBasicBlock(env->CopyWithoutHistory()); |
| 661 HBasicBlock* failure_block = |
| 662 builder_->CreateBasicBlock(env->CopyWithoutHistory()); |
658 compare->SetSuccessorAt(0, failure_block); | 663 compare->SetSuccessorAt(0, failure_block); |
659 compare->SetSuccessorAt(1, success_block); | 664 compare->SetSuccessorAt(1, success_block); |
660 failure_block->Goto(failure_block_); | 665 failure_block->Goto(failure_block_); |
661 builder_->current_block()->Finish(compare); | 666 builder_->current_block()->Finish(compare); |
662 builder_->set_current_block(success_block); | 667 builder_->set_current_block(success_block); |
| 668 return compare; |
663 } | 669 } |
664 | 670 |
665 | 671 |
666 void HGraphBuilder::CheckBuilder::CheckIntegerEq(HValue* left, HValue* right) { | 672 HValue* HGraphBuilder::CheckBuilder::CheckIntegerCompare(HValue* left, |
| 673 HValue* right, |
| 674 Token::Value op) { |
667 HEnvironment* env = builder_->environment(); | 675 HEnvironment* env = builder_->environment(); |
668 HCompareIDAndBranch* compare = | 676 HCompareIDAndBranch* compare = |
669 new(zone()) HCompareIDAndBranch(left, right, Token::EQ); | 677 new(zone()) HCompareIDAndBranch(left, right, op); |
670 compare->AssumeRepresentation(Representation::Integer32()); | 678 compare->AssumeRepresentation(Representation::Integer32()); |
671 HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy()); | 679 HBasicBlock* success_block = |
672 HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy()); | 680 builder_->CreateBasicBlock(env->CopyWithoutHistory()); |
| 681 HBasicBlock* failure_block = |
| 682 builder_->CreateBasicBlock(env->CopyWithoutHistory()); |
673 compare->SetSuccessorAt(0, success_block); | 683 compare->SetSuccessorAt(0, success_block); |
674 compare->SetSuccessorAt(1, failure_block); | 684 compare->SetSuccessorAt(1, failure_block); |
675 failure_block->Goto(failure_block_); | 685 failure_block->Goto(failure_block_); |
676 builder_->current_block()->Finish(compare); | 686 builder_->current_block()->Finish(compare); |
677 builder_->set_current_block(success_block); | 687 builder_->set_current_block(success_block); |
| 688 return compare; |
678 } | 689 } |
679 | 690 |
680 | 691 |
| 692 HValue* HGraphBuilder::CheckBuilder::CheckIntegerEq(HValue* left, |
| 693 HValue* right) { |
| 694 return CheckIntegerCompare(left, right, Token::EQ); |
| 695 } |
| 696 |
| 697 |
681 void HGraphBuilder::CheckBuilder::End() { | 698 void HGraphBuilder::CheckBuilder::End() { |
682 ASSERT(!finished_); | 699 ASSERT(!finished_); |
683 builder_->current_block()->Goto(merge_block_); | 700 builder_->current_block()->Goto(merge_block_); |
684 failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll); | 701 failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll); |
685 failure_block_->SetJoinId(id_); | 702 failure_block_->SetJoinId(id_); |
686 builder_->set_current_block(merge_block_); | 703 builder_->set_current_block(merge_block_); |
687 merge_block_->SetJoinId(id_); | 704 merge_block_->SetJoinId(id_); |
688 finished_ = true; | 705 finished_ = true; |
689 } | 706 } |
690 | 707 |
691 | 708 |
692 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id) | 709 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id) |
693 : builder_(builder), | 710 : builder_(builder), |
694 finished_(false), | 711 finished_(false), |
| 712 did_else_(false), |
695 id_(id) { | 713 id_(id) { |
696 HEnvironment* env = builder->environment(); | 714 HEnvironment* env = builder->environment(); |
697 first_true_block_ = builder->CreateBasicBlock(env->Copy()); | 715 first_true_block_ = builder->CreateBasicBlock(env->Copy()); |
698 last_true_block_ = NULL; | 716 last_true_block_ = NULL; |
699 first_false_block_ = builder->CreateBasicBlock(env->Copy()); | 717 first_false_block_ = builder->CreateBasicBlock(env->Copy()); |
700 } | 718 } |
701 | 719 |
702 | 720 |
703 HInstruction* HGraphBuilder::IfBuilder::BeginTrue( | 721 HInstruction* HGraphBuilder::IfBuilder::BeginIf( |
704 HValue* left, | 722 HValue* left, |
705 HValue* right, | 723 HValue* right, |
706 Token::Value token, | 724 Token::Value token, |
707 Representation input_representation) { | 725 Representation input_representation) { |
708 HCompareIDAndBranch* compare = | 726 HCompareIDAndBranch* compare = |
709 new(zone()) HCompareIDAndBranch(left, right, token); | 727 new(zone()) HCompareIDAndBranch(left, right, token); |
710 compare->set_observed_input_representation(input_representation, | 728 compare->set_observed_input_representation(input_representation, |
711 input_representation); | 729 input_representation); |
712 compare->ChangeRepresentation(input_representation); | 730 compare->ChangeRepresentation(input_representation); |
713 compare->SetSuccessorAt(0, first_true_block_); | 731 compare->SetSuccessorAt(0, first_true_block_); |
714 compare->SetSuccessorAt(1, first_false_block_); | 732 compare->SetSuccessorAt(1, first_false_block_); |
715 builder_->current_block()->Finish(compare); | 733 builder_->current_block()->Finish(compare); |
716 builder_->set_current_block(first_true_block_); | 734 builder_->set_current_block(first_true_block_); |
717 return compare; | 735 return compare; |
718 } | 736 } |
719 | 737 |
720 | 738 |
721 void HGraphBuilder::IfBuilder::BeginFalse() { | 739 HInstruction* HGraphBuilder::IfBuilder::BeginIfObjectsEqual( |
| 740 HValue* left, |
| 741 HValue* right) { |
| 742 HCompareObjectEqAndBranch* compare = |
| 743 new(zone()) HCompareObjectEqAndBranch(left, right); |
| 744 compare->SetSuccessorAt(0, first_true_block_); |
| 745 compare->SetSuccessorAt(1, first_false_block_); |
| 746 builder_->current_block()->Finish(compare); |
| 747 builder_->set_current_block(first_true_block_); |
| 748 return compare; |
| 749 } |
| 750 |
| 751 |
| 752 HInstruction* HGraphBuilder::IfBuilder::BeginIfMapEquals(HValue* value, |
| 753 Handle<Map> map) { |
| 754 HCompareMap* compare = new(zone()) |
| 755 HCompareMap(value, map, first_true_block_, first_false_block_); |
| 756 builder_->current_block()->Finish(compare); |
| 757 builder_->set_current_block(first_true_block_); |
| 758 return compare; |
| 759 } |
| 760 |
| 761 |
| 762 void HGraphBuilder::IfBuilder::BeginElse() { |
722 last_true_block_ = builder_->current_block(); | 763 last_true_block_ = builder_->current_block(); |
723 ASSERT(!last_true_block_->IsFinished()); | 764 ASSERT(!last_true_block_->IsFinished()); |
724 builder_->set_current_block(first_false_block_); | 765 builder_->set_current_block(first_false_block_); |
| 766 did_else_ = true; |
725 } | 767 } |
726 | 768 |
727 | 769 |
728 void HGraphBuilder::IfBuilder::End() { | 770 void HGraphBuilder::IfBuilder::End() { |
729 ASSERT(!finished_); | 771 ASSERT(!finished_); |
| 772 if (!did_else_) BeginElse(); |
730 ASSERT(!last_true_block_->IsFinished()); | 773 ASSERT(!last_true_block_->IsFinished()); |
731 HBasicBlock* last_false_block = builder_->current_block(); | 774 HBasicBlock* last_false_block = builder_->current_block(); |
732 ASSERT(!last_false_block->IsFinished()); | 775 ASSERT(!last_false_block->IsFinished()); |
733 HEnvironment* merge_env = | 776 HEnvironment* merge_env = |
734 last_true_block_->last_environment()->Copy(); | 777 last_true_block_->last_environment()->CopyWithoutHistory(); |
735 merge_block_ = builder_->CreateBasicBlock(merge_env); | 778 merge_block_ = builder_->CreateBasicBlock(merge_env); |
736 last_true_block_->Goto(merge_block_); | 779 last_true_block_->Goto(merge_block_); |
737 last_false_block->Goto(merge_block_); | 780 last_false_block->Goto(merge_block_); |
738 merge_block_->SetJoinId(id_); | 781 merge_block_->SetJoinId(id_); |
739 builder_->set_current_block(merge_block_); | 782 builder_->set_current_block(merge_block_); |
740 finished_ = true; | 783 finished_ = true; |
741 } | 784 } |
742 | 785 |
743 | 786 |
744 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, | 787 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 ASSERT(current_block() != NULL); | 889 ASSERT(current_block() != NULL); |
847 current_block()->AddInstruction(instr); | 890 current_block()->AddInstruction(instr); |
848 return instr; | 891 return instr; |
849 } | 892 } |
850 | 893 |
851 | 894 |
852 void HGraphBuilder::AddSimulate(BailoutId id, | 895 void HGraphBuilder::AddSimulate(BailoutId id, |
853 RemovableSimulate removable) { | 896 RemovableSimulate removable) { |
854 ASSERT(current_block() != NULL); | 897 ASSERT(current_block() != NULL); |
855 current_block()->AddSimulate(id, removable); | 898 current_block()->AddSimulate(id, removable); |
| 899 environment()->set_ast_id(id); |
856 } | 900 } |
857 | 901 |
858 | 902 |
859 HBoundsCheck* HGraphBuilder::AddBoundsCheck(HValue* index, | 903 HBoundsCheck* HGraphBuilder::AddBoundsCheck(HValue* index, |
860 HValue* length, | 904 HValue* length, |
861 BoundsCheckKeyMode key_mode, | 905 BoundsCheckKeyMode key_mode, |
862 Representation r) { | 906 Representation r) { |
863 if (!index->type().IsSmi()) { | 907 if (!index->type().IsSmi()) { |
864 index = new(graph()->zone()) HCheckSmiOrInt32(index); | 908 index = new(graph()->zone()) HCheckSmiOrInt32(index); |
865 AddInstruction(HCheckSmiOrInt32::cast(index)); | 909 AddInstruction(HCheckSmiOrInt32::cast(index)); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
955 } | 999 } |
956 } | 1000 } |
957 | 1001 |
958 | 1002 |
959 HInstruction* HGraphBuilder::BuildFastElementAccess( | 1003 HInstruction* HGraphBuilder::BuildFastElementAccess( |
960 HValue* elements, | 1004 HValue* elements, |
961 HValue* checked_key, | 1005 HValue* checked_key, |
962 HValue* val, | 1006 HValue* val, |
963 HValue* load_dependency, | 1007 HValue* load_dependency, |
964 ElementsKind elements_kind, | 1008 ElementsKind elements_kind, |
965 bool is_store) { | 1009 bool is_store, |
| 1010 KeyedAccessStoreMode store_mode) { |
966 Zone* zone = this->zone(); | 1011 Zone* zone = this->zone(); |
967 if (is_store) { | 1012 if (is_store) { |
968 ASSERT(val != NULL); | 1013 ASSERT(val != NULL); |
969 switch (elements_kind) { | 1014 switch (elements_kind) { |
970 case FAST_SMI_ELEMENTS: | 1015 case FAST_SMI_ELEMENTS: |
971 case FAST_HOLEY_SMI_ELEMENTS: | 1016 case FAST_HOLEY_SMI_ELEMENTS: |
972 // Smi-only arrays need a smi check. | 1017 // Smi-only arrays need a smi check. |
973 AddInstruction(new(zone) HCheckSmi(val)); | 1018 AddInstruction(new(zone) HCheckSmi(val)); |
974 // Fall through. | 1019 // Fall through. |
975 case FAST_ELEMENTS: | 1020 case FAST_ELEMENTS: |
976 case FAST_HOLEY_ELEMENTS: | 1021 case FAST_HOLEY_ELEMENTS: |
977 case FAST_DOUBLE_ELEMENTS: | 1022 case FAST_DOUBLE_ELEMENTS: |
978 case FAST_HOLEY_DOUBLE_ELEMENTS: | 1023 case FAST_HOLEY_DOUBLE_ELEMENTS: |
979 return new(zone) HStoreKeyed(elements, checked_key, val, elements_kind); | 1024 return new(zone) HStoreKeyed(elements, checked_key, val, elements_kind); |
980 default: | 1025 default: |
981 UNREACHABLE(); | 1026 UNREACHABLE(); |
982 return NULL; | 1027 return NULL; |
983 } | 1028 } |
984 } | 1029 } |
985 // It's an element load (!is_store). | 1030 // It's an element load (!is_store). |
986 return new(zone) HLoadKeyed(elements, | 1031 return new(zone) HLoadKeyed(elements, |
987 checked_key, | 1032 checked_key, |
988 load_dependency, | 1033 load_dependency, |
989 elements_kind); | 1034 elements_kind); |
990 } | 1035 } |
991 | 1036 |
992 | 1037 |
| 1038 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
| 1039 HValue* elements, |
| 1040 ElementsKind kind, |
| 1041 HValue* length, |
| 1042 HValue* key, |
| 1043 bool is_js_array) { |
| 1044 BailoutId ast_id = environment()->ast_id(); |
| 1045 Zone* zone = this->zone(); |
| 1046 IfBuilder length_checker(this, ast_id); |
| 1047 |
| 1048 length_checker.BeginIf(length, key, Token::EQ); |
| 1049 |
| 1050 HValue* current_capacity = |
| 1051 AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
| 1052 |
| 1053 IfBuilder capacity_checker(this, ast_id); |
| 1054 |
| 1055 capacity_checker.BeginIf(length, current_capacity, Token::EQ); |
| 1056 |
| 1057 HValue* context = environment()->LookupContext(); |
| 1058 |
| 1059 HValue* new_capacity = |
| 1060 BuildNewElementsCapacity(context, current_capacity); |
| 1061 |
| 1062 HValue* new_elements = BuildGrowElementsCapacity(object, elements, |
| 1063 kind, length, |
| 1064 new_capacity, ast_id); |
| 1065 |
| 1066 environment()->Push(new_elements); |
| 1067 capacity_checker.BeginElse(); |
| 1068 |
| 1069 environment()->Push(elements); |
| 1070 capacity_checker.End(); |
| 1071 |
| 1072 if (is_js_array) { |
| 1073 HValue* new_length = AddInstruction( |
| 1074 HAdd::New(zone, context, length, graph_->GetConstant1())); |
| 1075 new_length->ChangeRepresentation(Representation::Integer32()); |
| 1076 new_length->ClearFlag(HValue::kCanOverflow); |
| 1077 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
| 1078 |
| 1079 Factory* factory = isolate()->factory(); |
| 1080 HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField( |
| 1081 object, |
| 1082 factory->length_field_string(), |
| 1083 new_length, true, |
| 1084 JSArray::kLengthOffset)); |
| 1085 length_store->SetGVNFlag(kChangesArrayLengths); |
| 1086 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
| 1087 } |
| 1088 |
| 1089 length_checker.BeginElse(); |
| 1090 |
| 1091 AddBoundsCheck(key, length, ALLOW_SMI_KEY); |
| 1092 environment()->Push(elements); |
| 1093 |
| 1094 length_checker.End(); |
| 1095 |
| 1096 return environment()->Pop(); |
| 1097 } |
| 1098 |
| 1099 |
| 1100 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, |
| 1101 HValue* elements, |
| 1102 ElementsKind kind, |
| 1103 HValue* length) { |
| 1104 BailoutId ast_id = environment()->ast_id(); |
| 1105 Zone* zone = this->zone(); |
| 1106 Heap* heap = isolate()->heap(); |
| 1107 |
| 1108 IfBuilder cow_checker(this, ast_id); |
| 1109 |
| 1110 cow_checker.BeginIfMapEquals(elements, |
| 1111 Handle<Map>(heap->fixed_cow_array_map())); |
| 1112 |
| 1113 HValue* capacity = |
| 1114 AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
| 1115 |
| 1116 HValue* new_elements = BuildGrowElementsCapacity(object, elements, |
| 1117 kind, length, |
| 1118 capacity, ast_id); |
| 1119 |
| 1120 environment()->Push(new_elements); |
| 1121 |
| 1122 cow_checker.BeginElse(); |
| 1123 |
| 1124 environment()->Push(elements); |
| 1125 |
| 1126 cow_checker.End(); |
| 1127 |
| 1128 return environment()->Pop(); |
| 1129 } |
| 1130 |
| 1131 |
993 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 1132 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
994 HValue* object, | 1133 HValue* object, |
995 HValue* key, | 1134 HValue* key, |
996 HValue* val, | 1135 HValue* val, |
997 HCheckMaps* mapcheck, | 1136 HCheckMaps* mapcheck, |
998 bool is_js_array, | 1137 bool is_js_array, |
999 ElementsKind elements_kind, | 1138 ElementsKind elements_kind, |
1000 bool is_store, | 1139 bool is_store, |
| 1140 KeyedAccessStoreMode store_mode, |
1001 Representation checked_index_representation) { | 1141 Representation checked_index_representation) { |
| 1142 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); |
1002 Zone* zone = this->zone(); | 1143 Zone* zone = this->zone(); |
1003 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 1144 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
1004 // on a HElementsTransition instruction. The flag can also be removed if the | 1145 // on a HElementsTransition instruction. The flag can also be removed if the |
1005 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 1146 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
1006 // ElementsKind transitions. Finally, the dependency can be removed for stores | 1147 // ElementsKind transitions. Finally, the dependency can be removed for stores |
1007 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 1148 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
1008 // generated store code. | 1149 // generated store code. |
1009 if ((elements_kind == FAST_HOLEY_ELEMENTS) || | 1150 if ((elements_kind == FAST_HOLEY_ELEMENTS) || |
1010 (elements_kind == FAST_ELEMENTS && is_store)) { | 1151 (elements_kind == FAST_ELEMENTS && is_store)) { |
1011 if (mapcheck != NULL) { | 1152 if (mapcheck != NULL) { |
1012 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 1153 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
1013 } | 1154 } |
1014 } | 1155 } |
1015 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); | 1156 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); |
1016 bool fast_elements = IsFastObjectElementsKind(elements_kind); | 1157 bool fast_elements = IsFastObjectElementsKind(elements_kind); |
1017 HInstruction* elements = | 1158 HValue* elements = |
1018 AddInstruction(new(zone) HLoadElements(object, mapcheck)); | 1159 AddInstruction(new(zone) HLoadElements(object, mapcheck)); |
1019 if (is_store && (fast_elements || fast_smi_only_elements)) { | 1160 if (is_store && (fast_elements || fast_smi_only_elements) && |
| 1161 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
1020 HCheckMaps* check_cow_map = new(zone) HCheckMaps( | 1162 HCheckMaps* check_cow_map = new(zone) HCheckMaps( |
1021 elements, isolate()->factory()->fixed_array_map(), zone); | 1163 elements, isolate()->factory()->fixed_array_map(), zone); |
1022 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 1164 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
1023 AddInstruction(check_cow_map); | 1165 AddInstruction(check_cow_map); |
1024 } | 1166 } |
1025 HInstruction* length = NULL; | 1167 HInstruction* length = NULL; |
1026 HInstruction* checked_key = NULL; | |
1027 if (IsExternalArrayElementsKind(elements_kind)) { | |
1028 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | |
1029 checked_key = AddBoundsCheck( | |
1030 key, length, ALLOW_SMI_KEY, checked_index_representation); | |
1031 HLoadExternalArrayPointer* external_elements = | |
1032 new(zone) HLoadExternalArrayPointer(elements); | |
1033 AddInstruction(external_elements); | |
1034 return BuildExternalArrayElementAccess( | |
1035 external_elements, checked_key, val, mapcheck, | |
1036 elements_kind, is_store); | |
1037 } | |
1038 ASSERT(fast_smi_only_elements || | |
1039 fast_elements || | |
1040 IsFastDoubleElementsKind(elements_kind)); | |
1041 if (is_js_array) { | 1168 if (is_js_array) { |
1042 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, | 1169 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, |
1043 HType::Smi())); | 1170 HType::Smi())); |
1044 } else { | 1171 } else { |
1045 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | 1172 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
1046 } | 1173 } |
1047 checked_key = AddBoundsCheck( | 1174 HValue* checked_key = NULL; |
1048 key, length, ALLOW_SMI_KEY, checked_index_representation); | 1175 if (IsExternalArrayElementsKind(elements_kind)) { |
1049 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 1176 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
1050 elements_kind, is_store); | 1177 HLoadExternalArrayPointer* external_elements = |
| 1178 new(zone) HLoadExternalArrayPointer(elements); |
| 1179 AddInstruction(external_elements); |
| 1180 BailoutId previous_id = environment()->ast_id(); |
| 1181 ASSERT(!previous_id.IsNone()); |
| 1182 IfBuilder length_checker(this, previous_id); |
| 1183 length_checker.BeginIf(key, length, Token::LT); |
| 1184 CheckBuilder negative_checker(this, previous_id); |
| 1185 HValue* bounds_check = negative_checker.CheckIntegerCompare( |
| 1186 key, graph()->GetConstant0(), Token::GTE); |
| 1187 negative_checker.End(); |
| 1188 HInstruction* result = BuildExternalArrayElementAccess( |
| 1189 external_elements, key, val, bounds_check, |
| 1190 elements_kind, is_store); |
| 1191 AddInstruction(result); |
| 1192 length_checker.End(); |
| 1193 return result; |
| 1194 } else { |
| 1195 ASSERT(store_mode == STANDARD_STORE); |
| 1196 checked_key = AddBoundsCheck( |
| 1197 key, length, ALLOW_SMI_KEY, checked_index_representation); |
| 1198 HLoadExternalArrayPointer* external_elements = |
| 1199 new(zone) HLoadExternalArrayPointer(elements); |
| 1200 AddInstruction(external_elements); |
| 1201 return AddInstruction(BuildExternalArrayElementAccess( |
| 1202 external_elements, checked_key, val, mapcheck, |
| 1203 elements_kind, is_store)); |
| 1204 } |
| 1205 } |
| 1206 ASSERT(fast_smi_only_elements || |
| 1207 fast_elements || |
| 1208 IsFastDoubleElementsKind(elements_kind)); |
| 1209 |
| 1210 if (is_store && IsFastSmiElementsKind(elements_kind) && |
| 1211 !val->type().IsSmi()) { |
| 1212 AddInstruction(new(zone) HCheckSmi(val)); |
| 1213 } |
| 1214 |
| 1215 if (IsGrowStoreMode(store_mode)) { |
| 1216 elements = BuildCheckForCapacityGrow(object, elements, elements_kind, |
| 1217 length, key, is_js_array); |
| 1218 checked_key = key; |
| 1219 } else { |
| 1220 checked_key = AddBoundsCheck( |
| 1221 key, length, ALLOW_SMI_KEY, checked_index_representation); |
| 1222 |
| 1223 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 1224 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { |
| 1225 elements = BuildCopyElementsOnWrite(object, elements, elements_kind, |
| 1226 length); |
| 1227 } else { |
| 1228 HCheckMaps* check_cow_map = new(zone) HCheckMaps( |
| 1229 elements, isolate()->factory()->fixed_array_map(), zone); |
| 1230 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 1231 AddInstruction(check_cow_map); |
| 1232 } |
| 1233 } |
| 1234 } |
| 1235 return AddInstruction( |
| 1236 BuildFastElementAccess(elements, checked_key, val, mapcheck, |
| 1237 elements_kind, is_store, store_mode)); |
1051 } | 1238 } |
1052 | 1239 |
1053 | 1240 |
1054 HValue* HGraphBuilder::BuildAllocateElements(HContext* context, | 1241 HValue* HGraphBuilder::BuildAllocateElements(HValue* context, |
1055 ElementsKind kind, | 1242 ElementsKind kind, |
1056 HValue* capacity) { | 1243 HValue* capacity, |
| 1244 BailoutId ast_id) { |
1057 Zone* zone = this->zone(); | 1245 Zone* zone = this->zone(); |
1058 | 1246 |
1059 int elements_size = IsFastDoubleElementsKind(kind) | 1247 int elements_size = IsFastDoubleElementsKind(kind) |
1060 ? kDoubleSize : kPointerSize; | 1248 ? kDoubleSize : kPointerSize; |
1061 HConstant* elements_size_value = | 1249 HConstant* elements_size_value = |
1062 new(zone) HConstant(elements_size, Representation::Integer32()); | 1250 new(zone) HConstant(elements_size, Representation::Integer32()); |
1063 AddInstruction(elements_size_value); | 1251 AddInstruction(elements_size_value); |
1064 HValue* mul = AddInstruction( | 1252 HValue* mul = AddInstruction( |
1065 HMul::New(zone, context, capacity, elements_size_value)); | 1253 HMul::New(zone, context, capacity, elements_size_value)); |
1066 mul->ChangeRepresentation(Representation::Integer32()); | 1254 mul->ChangeRepresentation(Representation::Integer32()); |
(...skipping 14 matching lines...) Expand all Loading... |
1081 } | 1269 } |
1082 | 1270 |
1083 HValue* elements = | 1271 HValue* elements = |
1084 AddInstruction(new(zone) HAllocate(context, total_size, | 1272 AddInstruction(new(zone) HAllocate(context, total_size, |
1085 HType::JSArray(), flags)); | 1273 HType::JSArray(), flags)); |
1086 | 1274 |
1087 Factory* factory = isolate()->factory(); | 1275 Factory* factory = isolate()->factory(); |
1088 Handle<Map> map = IsFastDoubleElementsKind(kind) | 1276 Handle<Map> map = IsFastDoubleElementsKind(kind) |
1089 ? factory->fixed_double_array_map() | 1277 ? factory->fixed_double_array_map() |
1090 : factory->fixed_array_map(); | 1278 : factory->fixed_array_map(); |
1091 BuildStoreMap(elements, map, BailoutId::StubEntry()); | 1279 BuildStoreMap(elements, map, ast_id); |
1092 | 1280 |
1093 Handle<String> fixed_array_length_field_name = factory->length_field_string(); | 1281 Handle<String> fixed_array_length_field_name = factory->length_field_string(); |
1094 HInstruction* store_length = | 1282 HInstruction* store_length = |
1095 new(zone) HStoreNamedField(elements, fixed_array_length_field_name, | 1283 new(zone) HStoreNamedField(elements, fixed_array_length_field_name, |
1096 capacity, true, FixedArray::kLengthOffset); | 1284 capacity, true, FixedArray::kLengthOffset); |
1097 AddInstruction(store_length); | 1285 AddInstruction(store_length); |
1098 AddSimulate(BailoutId::StubEntry(), FIXED_SIMULATE); | 1286 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
1099 | 1287 |
1100 return elements; | 1288 return elements; |
1101 } | 1289 } |
1102 | 1290 |
1103 | 1291 |
1104 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, | 1292 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
1105 HValue* map, | 1293 HValue* map, |
1106 BailoutId id) { | 1294 BailoutId id) { |
1107 Zone* zone = this->zone(); | 1295 Zone* zone = this->zone(); |
1108 Factory* factory = isolate()->factory(); | 1296 Factory* factory = isolate()->factory(); |
1109 Handle<String> map_field_name = factory->map_field_string(); | 1297 Handle<String> map_field_name = factory->map_field_string(); |
1110 HInstruction* store_map = | 1298 HInstruction* store_map = |
1111 new(zone) HStoreNamedField(object, map_field_name, map, | 1299 new(zone) HStoreNamedField(object, map_field_name, map, |
1112 true, JSObject::kMapOffset); | 1300 true, JSObject::kMapOffset); |
1113 store_map->SetGVNFlag(kChangesMaps); | 1301 store_map->SetGVNFlag(kChangesMaps); |
1114 AddInstruction(store_map); | 1302 AddInstruction(store_map); |
1115 AddSimulate(id, FIXED_SIMULATE); | 1303 AddSimulate(id, REMOVABLE_SIMULATE); |
1116 return store_map; | 1304 return store_map; |
1117 } | 1305 } |
1118 | 1306 |
1119 | 1307 |
1120 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, | 1308 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
1121 Handle<Map> map, | 1309 Handle<Map> map, |
1122 BailoutId id) { | 1310 BailoutId id) { |
1123 Zone* zone = this->zone(); | 1311 Zone* zone = this->zone(); |
1124 HValue* map_constant = | 1312 HValue* map_constant = |
1125 AddInstruction(new(zone) HConstant(map, Representation::Tagged())); | 1313 AddInstruction(new(zone) HConstant(map, Representation::Tagged())); |
1126 return BuildStoreMap(object, map_constant, id); | 1314 return BuildStoreMap(object, map_constant, id); |
1127 } | 1315 } |
1128 | 1316 |
1129 | 1317 |
1130 void HGraphBuilder::BuildCopyElements(HContext* context, | 1318 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* context, |
| 1319 HValue* old_capacity) { |
| 1320 Zone* zone = this->zone(); |
| 1321 HValue* half_old_capacity = |
| 1322 AddInstruction(HShr::New(zone, context, old_capacity, |
| 1323 graph_->GetConstant1())); |
| 1324 half_old_capacity->ChangeRepresentation(Representation::Integer32()); |
| 1325 half_old_capacity->ClearFlag(HValue::kCanOverflow); |
| 1326 |
| 1327 HValue* new_capacity = AddInstruction( |
| 1328 HAdd::New(zone, context, half_old_capacity, old_capacity)); |
| 1329 new_capacity->ChangeRepresentation(Representation::Integer32()); |
| 1330 new_capacity->ClearFlag(HValue::kCanOverflow); |
| 1331 |
| 1332 HValue* min_growth = |
| 1333 AddInstruction(new(zone) HConstant(16, Representation::Integer32())); |
| 1334 |
| 1335 new_capacity = AddInstruction( |
| 1336 HAdd::New(zone, context, new_capacity, min_growth)); |
| 1337 new_capacity->ChangeRepresentation(Representation::Integer32()); |
| 1338 new_capacity->ClearFlag(HValue::kCanOverflow); |
| 1339 |
| 1340 return new_capacity; |
| 1341 } |
| 1342 |
| 1343 |
| 1344 void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) { |
| 1345 Zone* zone = this->zone(); |
| 1346 Heap* heap = isolate()->heap(); |
| 1347 int element_size = IsFastDoubleElementsKind(kind) ? kDoubleSize |
| 1348 : kPointerSize; |
| 1349 int max_size = heap->MaxNewSpaceAllocationSize() / element_size; |
| 1350 max_size -= JSArray::kSize / element_size; |
| 1351 HConstant* max_size_constant = |
| 1352 new(zone) HConstant(max_size, Representation::Integer32()); |
| 1353 AddInstruction(max_size_constant); |
| 1354 // Since we're forcing Integer32 representation for this HBoundsCheck, |
| 1355 // there's no need to Smi-check the index. |
| 1356 AddInstruction(new(zone) |
| 1357 HBoundsCheck(length, max_size_constant, |
| 1358 DONT_ALLOW_SMI_KEY, Representation::Integer32())); |
| 1359 } |
| 1360 |
| 1361 |
| 1362 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, |
| 1363 HValue* elements, |
| 1364 ElementsKind kind, |
| 1365 HValue* length, |
| 1366 HValue* new_capacity, |
| 1367 BailoutId ast_id) { |
| 1368 Zone* zone = this->zone(); |
| 1369 HValue* context = environment()->LookupContext(); |
| 1370 |
| 1371 BuildNewSpaceArrayCheck(new_capacity, kind); |
| 1372 |
| 1373 HValue* new_elements = |
| 1374 BuildAllocateElements(context, kind, new_capacity, ast_id); |
| 1375 |
| 1376 BuildCopyElements(context, elements, kind, |
| 1377 new_elements, kind, |
| 1378 length, new_capacity, ast_id); |
| 1379 |
| 1380 Factory* factory = isolate()->factory(); |
| 1381 HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField( |
| 1382 object, |
| 1383 factory->elements_field_string(), |
| 1384 new_elements, true, |
| 1385 JSArray::kElementsOffset)); |
| 1386 elements_store->SetGVNFlag(kChangesElementsPointer); |
| 1387 |
| 1388 return new_elements; |
| 1389 } |
| 1390 |
| 1391 |
| 1392 void HGraphBuilder::BuildFillElementsWithHole(HValue* context, |
| 1393 HValue* elements, |
| 1394 ElementsKind elements_kind, |
| 1395 HValue* from, |
| 1396 HValue* to, |
| 1397 BailoutId ast_id) { |
| 1398 // Fast elements kinds need to be initialized in case statements below cause |
| 1399 // a garbage collection. |
| 1400 Factory* factory = isolate()->factory(); |
| 1401 |
| 1402 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 1403 Zone* zone = this->zone(); |
| 1404 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 1405 ? AddInstruction(new(zone) HConstant(factory->the_hole_value(), |
| 1406 Representation::Tagged())) |
| 1407 : AddInstruction(new(zone) HConstant(nan_double, |
| 1408 Representation::Double())); |
| 1409 |
| 1410 LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, ast_id); |
| 1411 |
| 1412 HValue* key = builder.BeginBody(from, to, Token::LT); |
| 1413 |
| 1414 AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind)); |
| 1415 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
| 1416 |
| 1417 builder.EndBody(); |
| 1418 } |
| 1419 |
| 1420 |
| 1421 void HGraphBuilder::BuildCopyElements(HValue* context, |
1131 HValue* from_elements, | 1422 HValue* from_elements, |
1132 ElementsKind from_elements_kind, | 1423 ElementsKind from_elements_kind, |
1133 HValue* to_elements, | 1424 HValue* to_elements, |
1134 ElementsKind to_elements_kind, | 1425 ElementsKind to_elements_kind, |
1135 HValue* length) { | 1426 HValue* length, |
1136 LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, | 1427 HValue* capacity, |
1137 BailoutId::StubEntry()); | 1428 BailoutId ast_id) { |
| 1429 bool pre_fill_with_holes = |
| 1430 IsFastDoubleElementsKind(from_elements_kind) && |
| 1431 IsFastObjectElementsKind(to_elements_kind); |
1138 | 1432 |
1139 HValue* key = builder.BeginBody(graph()->GetConstant0(), | 1433 if (pre_fill_with_holes) { |
1140 length, Token::LT); | 1434 // If the copy might trigger a GC, make sure that the FixedArray is |
| 1435 // pre-initialized with holes to make sure that it's always in a consistent |
| 1436 // state. |
| 1437 BuildFillElementsWithHole(context, to_elements, to_elements_kind, |
| 1438 graph()->GetConstant0(), capacity, ast_id); |
| 1439 } |
| 1440 |
| 1441 LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, ast_id); |
| 1442 |
| 1443 HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT); |
1141 | 1444 |
1142 HValue* element = | 1445 HValue* element = |
1143 AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL, | 1446 AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL, |
1144 from_elements_kind, | 1447 from_elements_kind, |
1145 ALLOW_RETURN_HOLE)); | 1448 ALLOW_RETURN_HOLE)); |
1146 | 1449 |
1147 AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element, | 1450 AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element, |
1148 to_elements_kind)); | 1451 to_elements_kind)); |
1149 AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE); | 1452 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
1150 | 1453 |
1151 builder.EndBody(); | 1454 builder.EndBody(); |
| 1455 |
| 1456 if (!pre_fill_with_holes && length != capacity) { |
| 1457 // Fill unused capacity with the hole. |
| 1458 BuildFillElementsWithHole(context, to_elements, to_elements_kind, |
| 1459 key, capacity, ast_id); |
| 1460 } |
1152 } | 1461 } |
1153 | 1462 |
1154 | 1463 |
1155 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, | 1464 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, |
1156 TypeFeedbackOracle* oracle) | 1465 TypeFeedbackOracle* oracle) |
1157 : HGraphBuilder(info), | 1466 : HGraphBuilder(info), |
1158 function_state_(NULL), | 1467 function_state_(NULL), |
1159 initial_function_state_(this, info, oracle, NORMAL_RETURN), | 1468 initial_function_state_(this, info, oracle, NORMAL_RETURN), |
1160 ast_context_(NULL), | 1469 ast_context_(NULL), |
1161 break_scope_(NULL), | 1470 break_scope_(NULL), |
(...skipping 5620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6782 return new(zone()) HLoadKeyedGeneric(context, object, key); | 7091 return new(zone()) HLoadKeyedGeneric(context, object, key); |
6783 } | 7092 } |
6784 | 7093 |
6785 | 7094 |
6786 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( | 7095 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( |
6787 HValue* object, | 7096 HValue* object, |
6788 HValue* key, | 7097 HValue* key, |
6789 HValue* val, | 7098 HValue* val, |
6790 HValue* dependency, | 7099 HValue* dependency, |
6791 Handle<Map> map, | 7100 Handle<Map> map, |
6792 bool is_store) { | 7101 bool is_store, |
| 7102 KeyedAccessStoreMode store_mode) { |
6793 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, | 7103 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, |
6794 zone(), dependency); | 7104 zone(), dependency); |
6795 AddInstruction(mapcheck); | 7105 AddInstruction(mapcheck); |
6796 if (dependency) { | 7106 if (dependency) { |
6797 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 7107 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
6798 } | 7108 } |
6799 return BuildUncheckedMonomorphicElementAccess( | 7109 return BuildUncheckedMonomorphicElementAccess( |
6800 object, key, val, | 7110 object, key, val, |
6801 mapcheck, map->instance_type() == JS_ARRAY_TYPE, | 7111 mapcheck, map->instance_type() == JS_ARRAY_TYPE, |
6802 map->elements_kind(), is_store); | 7112 map->elements_kind(), is_store, store_mode); |
6803 } | 7113 } |
6804 | 7114 |
6805 | 7115 |
6806 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( | 7116 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( |
6807 HValue* object, | 7117 HValue* object, |
6808 HValue* key, | 7118 HValue* key, |
6809 HValue* val, | 7119 HValue* val, |
6810 SmallMapList* maps) { | 7120 SmallMapList* maps) { |
6811 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 7121 // For polymorphic loads of similar elements kinds (i.e. all tagged or all |
6812 // double), always use the "worst case" code without a transition. This is | 7122 // double), always use the "worst case" code without a transition. This is |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6847 } | 7157 } |
6848 } | 7158 } |
6849 if (!has_double_maps && !has_smi_or_object_maps) return NULL; | 7159 if (!has_double_maps && !has_smi_or_object_maps) return NULL; |
6850 | 7160 |
6851 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); | 7161 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); |
6852 AddInstruction(check_maps); | 7162 AddInstruction(check_maps); |
6853 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( | 7163 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( |
6854 object, key, val, check_maps, | 7164 object, key, val, check_maps, |
6855 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, | 7165 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, |
6856 most_general_consolidated_map->elements_kind(), | 7166 most_general_consolidated_map->elements_kind(), |
6857 false); | 7167 false, STANDARD_STORE); |
6858 return instr; | 7168 return instr; |
6859 } | 7169 } |
6860 | 7170 |
6861 | 7171 |
6862 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 7172 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
6863 HValue* object, | 7173 HValue* object, |
6864 HValue* key, | 7174 HValue* key, |
6865 HValue* val, | 7175 HValue* val, |
6866 Expression* prop, | 7176 Expression* prop, |
6867 BailoutId ast_id, | 7177 BailoutId ast_id, |
6868 int position, | 7178 int position, |
6869 bool is_store, | 7179 bool is_store, |
| 7180 KeyedAccessStoreMode store_mode, |
6870 bool* has_side_effects) { | 7181 bool* has_side_effects) { |
6871 *has_side_effects = false; | 7182 *has_side_effects = false; |
6872 AddInstruction(new(zone()) HCheckNonSmi(object)); | 7183 AddInstruction(new(zone()) HCheckNonSmi(object)); |
6873 SmallMapList* maps = prop->GetReceiverTypes(); | 7184 SmallMapList* maps = prop->GetReceiverTypes(); |
6874 bool todo_external_array = false; | 7185 bool todo_external_array = false; |
6875 | 7186 |
6876 if (!is_store) { | 7187 if (!is_store) { |
6877 HInstruction* consolidated_load = | 7188 HInstruction* consolidated_load = |
6878 TryBuildConsolidatedElementLoad(object, key, val, maps); | 7189 TryBuildConsolidatedElementLoad(object, key, val, maps); |
6879 if (consolidated_load != NULL) { | 7190 if (consolidated_load != NULL) { |
6880 AddInstruction(consolidated_load); | |
6881 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 7191 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
6882 if (position != RelocInfo::kNoPosition) { | 7192 if (position != RelocInfo::kNoPosition) { |
6883 consolidated_load->set_position(position); | 7193 consolidated_load->set_position(position); |
6884 } | 7194 } |
6885 return consolidated_load; | 7195 return consolidated_load; |
6886 } | 7196 } |
6887 } | 7197 } |
6888 | 7198 |
6889 static const int kNumElementTypes = kElementsKindCount; | 7199 static const int kNumElementTypes = kElementsKindCount; |
6890 bool type_todo[kNumElementTypes]; | 7200 bool type_todo[kNumElementTypes]; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6937 } | 7247 } |
6938 | 7248 |
6939 // If only one map is left after transitioning, handle this case | 7249 // If only one map is left after transitioning, handle this case |
6940 // monomorphically. | 7250 // monomorphically. |
6941 if (num_untransitionable_maps == 1) { | 7251 if (num_untransitionable_maps == 1) { |
6942 HInstruction* instr = NULL; | 7252 HInstruction* instr = NULL; |
6943 if (untransitionable_map->has_slow_elements_kind()) { | 7253 if (untransitionable_map->has_slow_elements_kind()) { |
6944 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 7254 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
6945 : BuildLoadKeyedGeneric(object, key)); | 7255 : BuildLoadKeyedGeneric(object, key)); |
6946 } else { | 7256 } else { |
6947 instr = AddInstruction(BuildMonomorphicElementAccess( | 7257 instr = BuildMonomorphicElementAccess( |
6948 object, key, val, transition, untransitionable_map, is_store)); | 7258 object, key, val, transition, untransitionable_map, is_store, |
| 7259 store_mode); |
6949 } | 7260 } |
6950 *has_side_effects |= instr->HasObservableSideEffects(); | 7261 *has_side_effects |= instr->HasObservableSideEffects(); |
6951 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 7262 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
6952 return is_store ? NULL : instr; | 7263 return is_store ? NULL : instr; |
6953 } | 7264 } |
6954 | 7265 |
6955 HInstruction* checkspec = | 7266 HInstruction* checkspec = |
6956 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); | 7267 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); |
6957 HBasicBlock* join = graph()->CreateBasicBlock(); | 7268 HBasicBlock* join = graph()->CreateBasicBlock(); |
6958 | 7269 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7019 typecheck->SetSuccessorAt(1, if_fastobject); | 7330 typecheck->SetSuccessorAt(1, if_fastobject); |
7020 current_block()->Finish(typecheck); | 7331 current_block()->Finish(typecheck); |
7021 | 7332 |
7022 set_current_block(if_jsarray); | 7333 set_current_block(if_jsarray); |
7023 HInstruction* length; | 7334 HInstruction* length; |
7024 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, | 7335 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, |
7025 HType::Smi())); | 7336 HType::Smi())); |
7026 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); | 7337 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); |
7027 access = AddInstruction(BuildFastElementAccess( | 7338 access = AddInstruction(BuildFastElementAccess( |
7028 elements, checked_key, val, elements_kind_branch, | 7339 elements, checked_key, val, elements_kind_branch, |
7029 elements_kind, is_store)); | 7340 elements_kind, is_store, STANDARD_STORE)); |
7030 if (!is_store) { | 7341 if (!is_store) { |
7031 Push(access); | 7342 Push(access); |
7032 } | 7343 } |
7033 | 7344 |
7034 *has_side_effects |= access->HasObservableSideEffects(); | 7345 *has_side_effects |= access->HasObservableSideEffects(); |
7035 if (position != -1) { | 7346 if (position != -1) { |
7036 access->set_position(position); | 7347 access->set_position(position); |
7037 } | 7348 } |
7038 if_jsarray->Goto(join); | 7349 if_jsarray->Goto(join); |
7039 | 7350 |
7040 set_current_block(if_fastobject); | 7351 set_current_block(if_fastobject); |
7041 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 7352 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
7042 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); | 7353 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); |
7043 access = AddInstruction(BuildFastElementAccess( | 7354 access = AddInstruction(BuildFastElementAccess( |
7044 elements, checked_key, val, elements_kind_branch, | 7355 elements, checked_key, val, elements_kind_branch, |
7045 elements_kind, is_store)); | 7356 elements_kind, is_store, STANDARD_STORE)); |
7046 } else if (elements_kind == DICTIONARY_ELEMENTS) { | 7357 } else if (elements_kind == DICTIONARY_ELEMENTS) { |
7047 if (is_store) { | 7358 if (is_store) { |
7048 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | 7359 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
7049 } else { | 7360 } else { |
7050 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | 7361 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
7051 } | 7362 } |
7052 } else { // External array elements. | 7363 } else { // External array elements. |
7053 access = AddInstruction(BuildExternalArrayElementAccess( | 7364 access = AddInstruction(BuildExternalArrayElementAccess( |
7054 external_elements, checked_key, val, | 7365 external_elements, checked_key, val, |
7055 elements_kind_branch, elements_kind, is_store)); | 7366 elements_kind_branch, elements_kind, is_store)); |
(...skipping 25 matching lines...) Expand all Loading... |
7081 int position, | 7392 int position, |
7082 bool is_store, | 7393 bool is_store, |
7083 bool* has_side_effects) { | 7394 bool* has_side_effects) { |
7084 ASSERT(!expr->IsPropertyName()); | 7395 ASSERT(!expr->IsPropertyName()); |
7085 HInstruction* instr = NULL; | 7396 HInstruction* instr = NULL; |
7086 if (expr->IsMonomorphic()) { | 7397 if (expr->IsMonomorphic()) { |
7087 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 7398 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
7088 if (map->has_slow_elements_kind()) { | 7399 if (map->has_slow_elements_kind()) { |
7089 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 7400 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
7090 : BuildLoadKeyedGeneric(obj, key); | 7401 : BuildLoadKeyedGeneric(obj, key); |
| 7402 AddInstruction(instr); |
7091 } else { | 7403 } else { |
7092 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 7404 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
7093 instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); | 7405 instr = BuildMonomorphicElementAccess( |
| 7406 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
7094 } | 7407 } |
7095 } else if (expr->GetReceiverTypes() != NULL && | 7408 } else if (expr->GetReceiverTypes() != NULL && |
7096 !expr->GetReceiverTypes()->is_empty()) { | 7409 !expr->GetReceiverTypes()->is_empty()) { |
7097 return HandlePolymorphicElementAccess( | 7410 return HandlePolymorphicElementAccess( |
7098 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 7411 obj, key, val, expr, ast_id, position, is_store, |
| 7412 expr->GetStoreMode(), has_side_effects); |
7099 } else { | 7413 } else { |
7100 if (is_store) { | 7414 if (is_store) { |
7101 instr = BuildStoreKeyedGeneric(obj, key, val); | 7415 instr = BuildStoreKeyedGeneric(obj, key, val); |
7102 } else { | 7416 } else { |
7103 instr = BuildLoadKeyedGeneric(obj, key); | 7417 instr = BuildLoadKeyedGeneric(obj, key); |
7104 } | 7418 } |
| 7419 AddInstruction(instr); |
7105 } | 7420 } |
7106 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 7421 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
7107 AddInstruction(instr); | |
7108 *has_side_effects = instr->HasObservableSideEffects(); | 7422 *has_side_effects = instr->HasObservableSideEffects(); |
7109 return instr; | 7423 return instr; |
7110 } | 7424 } |
7111 | 7425 |
7112 | 7426 |
7113 HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric( | 7427 HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric( |
7114 HValue* object, | 7428 HValue* object, |
7115 HValue* key, | 7429 HValue* key, |
7116 HValue* value) { | 7430 HValue* value) { |
7117 HValue* context = environment()->LookupContext(); | 7431 HValue* context = environment()->LookupContext(); |
(...skipping 3810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10928 } | 11242 } |
10929 } | 11243 } |
10930 | 11244 |
10931 #ifdef DEBUG | 11245 #ifdef DEBUG |
10932 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 11246 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
10933 if (allocator_ != NULL) allocator_->Verify(); | 11247 if (allocator_ != NULL) allocator_->Verify(); |
10934 #endif | 11248 #endif |
10935 } | 11249 } |
10936 | 11250 |
10937 } } // namespace v8::internal | 11251 } } // namespace v8::internal |
OLD | NEW |