Chromium Code Reviews| 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 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 HConstant* HGraph::GetConstant0() { | 615 HConstant* HGraph::GetConstant0() { |
| 613 return GetConstantInt32(&constant_0_, 0); | 616 return GetConstantInt32(&constant_0_, 0); |
| 614 } | 617 } |
| 615 | 618 |
| 616 | 619 |
| 617 HConstant* HGraph::GetConstant1() { | 620 HConstant* HGraph::GetConstant1() { |
| 618 return GetConstantInt32(&constant_1_, 1); | 621 return GetConstantInt32(&constant_1_, 1); |
| 619 } | 622 } |
| 620 | 623 |
| 621 | 624 |
| 625 HConstant* HGraph::GetConstant2() { | |
| 626 return GetConstantInt32(&constant_2_, 1); | |
|
Jakob Kummerow
2013/03/11 16:36:07
1 is the new 2?
danno
2013/03/13 15:36:26
Done.
| |
| 627 } | |
| 628 | |
| 629 | |
| 622 HConstant* HGraph::GetConstantMinus1() { | 630 HConstant* HGraph::GetConstantMinus1() { |
| 623 return GetConstantInt32(&constant_minus1_, -1); | 631 return GetConstantInt32(&constant_minus1_, -1); |
| 624 } | 632 } |
| 625 | 633 |
| 626 | 634 |
| 627 HConstant* HGraph::GetConstantTrue() { | 635 HConstant* HGraph::GetConstantTrue() { |
| 628 return GetConstant(&constant_true_, isolate()->factory()->true_value()); | 636 return GetConstant(&constant_true_, isolate()->factory()->true_value()); |
| 629 } | 637 } |
| 630 | 638 |
| 631 | 639 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 693 : builder_(builder), | 701 : builder_(builder), |
| 694 finished_(false), | 702 finished_(false), |
| 695 id_(id) { | 703 id_(id) { |
| 696 HEnvironment* env = builder->environment(); | 704 HEnvironment* env = builder->environment(); |
| 697 first_true_block_ = builder->CreateBasicBlock(env->Copy()); | 705 first_true_block_ = builder->CreateBasicBlock(env->Copy()); |
| 698 last_true_block_ = NULL; | 706 last_true_block_ = NULL; |
| 699 first_false_block_ = builder->CreateBasicBlock(env->Copy()); | 707 first_false_block_ = builder->CreateBasicBlock(env->Copy()); |
| 700 } | 708 } |
| 701 | 709 |
| 702 | 710 |
| 703 HInstruction* HGraphBuilder::IfBuilder::BeginTrue( | 711 HInstruction* HGraphBuilder::IfBuilder::BeginIf( |
| 704 HValue* left, | 712 HValue* left, |
| 705 HValue* right, | 713 HValue* right, |
| 706 Token::Value token, | 714 Token::Value token, |
| 707 Representation input_representation) { | 715 Representation input_representation) { |
| 708 HCompareIDAndBranch* compare = | 716 HCompareIDAndBranch* compare = |
| 709 new(zone()) HCompareIDAndBranch(left, right, token); | 717 new(zone()) HCompareIDAndBranch(left, right, token); |
| 710 compare->set_observed_input_representation(input_representation, | 718 compare->set_observed_input_representation(input_representation, |
| 711 input_representation); | 719 input_representation); |
| 712 compare->ChangeRepresentation(input_representation); | 720 compare->ChangeRepresentation(input_representation); |
| 713 compare->SetSuccessorAt(0, first_true_block_); | 721 compare->SetSuccessorAt(0, first_true_block_); |
| 714 compare->SetSuccessorAt(1, first_false_block_); | 722 compare->SetSuccessorAt(1, first_false_block_); |
| 715 builder_->current_block()->Finish(compare); | 723 builder_->current_block()->Finish(compare); |
| 716 builder_->set_current_block(first_true_block_); | 724 builder_->set_current_block(first_true_block_); |
| 717 return compare; | 725 return compare; |
| 718 } | 726 } |
| 719 | 727 |
| 720 | 728 |
| 721 void HGraphBuilder::IfBuilder::BeginFalse() { | 729 HInstruction* HGraphBuilder::IfBuilder::BeginIfObjectsEqual( |
| 730 HValue* left, | |
| 731 HValue* right) { | |
| 732 HCompareObjectEqAndBranch* compare = | |
| 733 new(zone()) HCompareObjectEqAndBranch(left, right); | |
| 734 compare->SetSuccessorAt(0, first_true_block_); | |
| 735 compare->SetSuccessorAt(1, first_false_block_); | |
| 736 builder_->current_block()->Finish(compare); | |
| 737 builder_->set_current_block(first_true_block_); | |
| 738 return compare; | |
| 739 } | |
| 740 | |
| 741 | |
| 742 void HGraphBuilder::IfBuilder::BeginElse() { | |
| 722 last_true_block_ = builder_->current_block(); | 743 last_true_block_ = builder_->current_block(); |
| 723 ASSERT(!last_true_block_->IsFinished()); | 744 ASSERT(!last_true_block_->IsFinished()); |
| 724 builder_->set_current_block(first_false_block_); | 745 builder_->set_current_block(first_false_block_); |
| 725 } | 746 } |
| 726 | 747 |
| 727 | 748 |
| 728 void HGraphBuilder::IfBuilder::End() { | 749 void HGraphBuilder::IfBuilder::End() { |
| 729 ASSERT(!finished_); | 750 ASSERT(!finished_); |
| 730 ASSERT(!last_true_block_->IsFinished()); | 751 ASSERT(!last_true_block_->IsFinished()); |
| 731 HBasicBlock* last_false_block = builder_->current_block(); | 752 HBasicBlock* last_false_block = builder_->current_block(); |
| 732 ASSERT(!last_false_block->IsFinished()); | 753 ASSERT(!last_false_block->IsFinished()); |
| 733 HEnvironment* merge_env = | 754 HEnvironment* merge_env = |
| 734 last_true_block_->last_environment()->Copy(); | 755 last_true_block_->last_environment()->CopyWithoutHistory(); |
| 735 merge_block_ = builder_->CreateBasicBlock(merge_env); | 756 merge_block_ = builder_->CreateBasicBlock(merge_env); |
| 736 last_true_block_->Goto(merge_block_); | 757 last_true_block_->Goto(merge_block_); |
| 737 last_false_block->Goto(merge_block_); | 758 last_false_block->Goto(merge_block_); |
| 738 merge_block_->SetJoinId(id_); | 759 merge_block_->SetJoinId(id_); |
| 739 builder_->set_current_block(merge_block_); | 760 builder_->set_current_block(merge_block_); |
| 740 finished_ = true; | 761 finished_ = true; |
| 741 } | 762 } |
| 742 | 763 |
| 743 | 764 |
| 744 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, | 765 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 846 ASSERT(current_block() != NULL); | 867 ASSERT(current_block() != NULL); |
| 847 current_block()->AddInstruction(instr); | 868 current_block()->AddInstruction(instr); |
| 848 return instr; | 869 return instr; |
| 849 } | 870 } |
| 850 | 871 |
| 851 | 872 |
| 852 void HGraphBuilder::AddSimulate(BailoutId id, | 873 void HGraphBuilder::AddSimulate(BailoutId id, |
| 853 RemovableSimulate removable) { | 874 RemovableSimulate removable) { |
| 854 ASSERT(current_block() != NULL); | 875 ASSERT(current_block() != NULL); |
| 855 current_block()->AddSimulate(id, removable); | 876 current_block()->AddSimulate(id, removable); |
| 877 environment()->set_ast_id(id); | |
| 856 } | 878 } |
| 857 | 879 |
| 858 | 880 |
| 859 HBoundsCheck* HGraphBuilder::AddBoundsCheck(HValue* index, | 881 HBoundsCheck* HGraphBuilder::AddBoundsCheck(HValue* index, |
| 860 HValue* length, | 882 HValue* length, |
| 861 BoundsCheckKeyMode key_mode, | 883 BoundsCheckKeyMode key_mode, |
| 862 Representation r) { | 884 Representation r) { |
| 863 if (!index->type().IsSmi()) { | 885 if (!index->type().IsSmi()) { |
| 864 index = new(graph()->zone()) HCheckSmiOrInt32(index); | 886 index = new(graph()->zone()) HCheckSmiOrInt32(index); |
| 865 AddInstruction(HCheckSmiOrInt32::cast(index)); | 887 AddInstruction(HCheckSmiOrInt32::cast(index)); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 943 } | 965 } |
| 944 } | 966 } |
| 945 | 967 |
| 946 | 968 |
| 947 HInstruction* HGraphBuilder::BuildFastElementAccess( | 969 HInstruction* HGraphBuilder::BuildFastElementAccess( |
| 948 HValue* elements, | 970 HValue* elements, |
| 949 HValue* checked_key, | 971 HValue* checked_key, |
| 950 HValue* val, | 972 HValue* val, |
| 951 HValue* load_dependency, | 973 HValue* load_dependency, |
| 952 ElementsKind elements_kind, | 974 ElementsKind elements_kind, |
| 953 bool is_store) { | 975 bool is_store, |
| 976 KeyedAccessStoreMode store_mode) { | |
| 954 Zone* zone = this->zone(); | 977 Zone* zone = this->zone(); |
| 955 if (is_store) { | 978 if (is_store) { |
| 956 ASSERT(val != NULL); | 979 ASSERT(val != NULL); |
| 957 switch (elements_kind) { | 980 switch (elements_kind) { |
| 958 case FAST_SMI_ELEMENTS: | 981 case FAST_SMI_ELEMENTS: |
| 959 case FAST_HOLEY_SMI_ELEMENTS: | 982 case FAST_HOLEY_SMI_ELEMENTS: |
| 960 // Smi-only arrays need a smi check. | 983 // Smi-only arrays need a smi check. |
| 961 AddInstruction(new(zone) HCheckSmi(val)); | 984 AddInstruction(new(zone) HCheckSmi(val)); |
| 962 // Fall through. | 985 // Fall through. |
| 963 case FAST_ELEMENTS: | 986 case FAST_ELEMENTS: |
| 964 case FAST_HOLEY_ELEMENTS: | 987 case FAST_HOLEY_ELEMENTS: |
| 965 case FAST_DOUBLE_ELEMENTS: | 988 case FAST_DOUBLE_ELEMENTS: |
| 966 case FAST_HOLEY_DOUBLE_ELEMENTS: | 989 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 967 return new(zone) HStoreKeyed(elements, checked_key, val, elements_kind); | 990 return new(zone) HStoreKeyed(elements, checked_key, val, elements_kind); |
| 968 default: | 991 default: |
| 969 UNREACHABLE(); | 992 UNREACHABLE(); |
| 970 return NULL; | 993 return NULL; |
| 971 } | 994 } |
| 972 } | 995 } |
| 973 // It's an element load (!is_store). | 996 // It's an element load (!is_store). |
| 974 return new(zone) HLoadKeyed(elements, | 997 return new(zone) HLoadKeyed(elements, |
| 975 checked_key, | 998 checked_key, |
| 976 load_dependency, | 999 load_dependency, |
| 977 elements_kind); | 1000 elements_kind); |
| 978 } | 1001 } |
| 979 | 1002 |
| 980 | 1003 |
| 1004 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, | |
| 1005 HValue* elements, | |
| 1006 ElementsKind kind, | |
| 1007 HValue* length, | |
| 1008 HValue* key, | |
| 1009 bool is_js_array) { | |
| 1010 BailoutId ast_id = environment()->ast_id(); | |
| 1011 Zone* zone = this->zone(); | |
| 1012 IfBuilder length_checker_if(this, ast_id); | |
|
Jakob Kummerow
2013/03/11 16:36:07
nit: Drop the _if. Just length_checker. It's clean
danno
2013/03/13 15:36:26
Done.
| |
| 1013 | |
| 1014 length_checker_if.BeginIf(length, key, Token::EQ); | |
| 1015 | |
| 1016 HValue* current_capacity = | |
| 1017 AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | |
| 1018 | |
| 1019 IfBuilder capacity_checker_if(this, ast_id); | |
|
Jakob Kummerow
2013/03/11 16:36:07
again
danno
2013/03/13 15:36:26
Done.
| |
| 1020 | |
| 1021 capacity_checker_if.BeginIf(length, current_capacity, Token::EQ); | |
| 1022 | |
| 1023 HValue* context = environment()->LookupContext(); | |
| 1024 | |
| 1025 HValue* new_capacity = | |
| 1026 BuildNewElementsCapacity(context, current_capacity); | |
| 1027 | |
| 1028 HValue* new_elements = BuildGrowElementsCapacity(object, elements, | |
| 1029 kind, length, | |
| 1030 new_capacity, ast_id); | |
| 1031 | |
| 1032 environment()->Push(new_elements); | |
| 1033 capacity_checker_if.BeginElse(); | |
| 1034 | |
| 1035 environment()->Push(elements); | |
| 1036 capacity_checker_if.End(); | |
| 1037 | |
| 1038 if (is_js_array) { | |
| 1039 HValue* new_length = AddInstruction( | |
| 1040 HAdd::New(zone, context, length, graph_->GetConstant1())); | |
| 1041 new_length->ChangeRepresentation(Representation::Integer32()); | |
| 1042 new_length->ClearFlag(HValue::kCanOverflow); | |
| 1043 AddSimulate(ast_id, REMOVABLE_SIMULATE); | |
| 1044 | |
| 1045 Isolate* isolate = graph()->isolate(); | |
|
Jakob Kummerow
2013/03/11 16:36:07
no need for this, HGraphBuilder has an isolate() a
danno
2013/03/13 15:36:26
Done.
| |
| 1046 Factory* factory = isolate->factory(); | |
| 1047 HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField( | |
| 1048 object, | |
| 1049 factory->length_field_string(), | |
| 1050 new_length, true, | |
| 1051 JSArray::kLengthOffset)); | |
| 1052 length_store->SetGVNFlag(kChangesArrayLengths); | |
| 1053 AddSimulate(ast_id, REMOVABLE_SIMULATE); | |
| 1054 } | |
| 1055 | |
| 1056 length_checker_if.BeginElse(); | |
| 1057 | |
| 1058 AddBoundsCheck(key, length, ALLOW_SMI_KEY); | |
| 1059 environment()->Push(elements); | |
| 1060 | |
| 1061 length_checker_if.End(); | |
| 1062 | |
| 1063 return environment()->Pop(); | |
| 1064 } | |
| 1065 | |
| 1066 | |
| 1067 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, | |
| 1068 HValue* elements, | |
| 1069 ElementsKind kind, | |
| 1070 HValue* length) { | |
| 1071 BailoutId ast_id = environment()->ast_id(); | |
| 1072 Zone* zone = this->zone(); | |
| 1073 Heap* heap = info_->isolate()->heap(); | |
|
Jakob Kummerow
2013/03/11 16:36:07
s/info_->// (or s/info_/this/ if you like needless
danno
2013/03/13 15:36:26
Done.
| |
| 1074 HValue* elements_map = | |
| 1075 AddInstruction(new(zone) HLoadNamedField(elements, true, | |
|
Jakob Kummerow
2013/03/11 16:36:07
Are you intentionally not using an HCompareMap ins
danno
2013/03/13 15:36:26
Done.
| |
| 1076 JSObject::kMapOffset)); | |
| 1077 Handle<Map> map(Handle<Map>(heap->fixed_cow_array_map())); | |
| 1078 HValue* cow_map = | |
| 1079 AddInstruction(new(zone) HConstant(map, Representation::Tagged())); | |
| 1080 | |
| 1081 IfBuilder cow_checker(this, ast_id); | |
| 1082 | |
| 1083 cow_checker.BeginIfObjectsEqual(elements_map, cow_map); | |
| 1084 | |
| 1085 HValue* capacity = | |
| 1086 AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | |
| 1087 | |
| 1088 HValue* new_elements = BuildGrowElementsCapacity(object, elements, | |
| 1089 kind, length, | |
| 1090 capacity, ast_id); | |
| 1091 | |
| 1092 environment()->Push(new_elements); | |
| 1093 | |
| 1094 cow_checker.BeginElse(); | |
| 1095 | |
| 1096 environment()->Push(elements); | |
| 1097 | |
| 1098 cow_checker.End(); | |
| 1099 | |
| 1100 return environment()->Pop(); | |
| 1101 } | |
| 1102 | |
| 1103 | |
| 981 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 1104 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 982 HValue* object, | 1105 HValue* object, |
| 983 HValue* key, | 1106 HValue* key, |
| 984 HValue* val, | 1107 HValue* val, |
| 985 HCheckMaps* mapcheck, | 1108 HCheckMaps* mapcheck, |
| 986 bool is_js_array, | 1109 bool is_js_array, |
| 987 ElementsKind elements_kind, | 1110 ElementsKind elements_kind, |
| 988 bool is_store, | 1111 bool is_store, |
| 1112 KeyedAccessStoreMode store_mode, | |
| 989 Representation checked_index_representation) { | 1113 Representation checked_index_representation) { |
| 1114 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); | |
| 990 Zone* zone = this->zone(); | 1115 Zone* zone = this->zone(); |
| 991 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 1116 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
| 992 // on a HElementsTransition instruction. The flag can also be removed if the | 1117 // on a HElementsTransition instruction. The flag can also be removed if the |
| 993 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 1118 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
| 994 // ElementsKind transitions. Finally, the dependency can be removed for stores | 1119 // ElementsKind transitions. Finally, the dependency can be removed for stores |
| 995 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 1120 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 996 // generated store code. | 1121 // generated store code. |
| 997 if ((elements_kind == FAST_HOLEY_ELEMENTS) || | 1122 if ((elements_kind == FAST_HOLEY_ELEMENTS) || |
| 998 (elements_kind == FAST_ELEMENTS && is_store)) { | 1123 (elements_kind == FAST_ELEMENTS && is_store)) { |
| 999 if (mapcheck != NULL) { | 1124 if (mapcheck != NULL) { |
| 1000 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 1125 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 1001 } | 1126 } |
| 1002 } | 1127 } |
| 1003 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); | 1128 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); |
| 1004 bool fast_elements = IsFastObjectElementsKind(elements_kind); | 1129 bool fast_elements = IsFastObjectElementsKind(elements_kind); |
| 1005 HInstruction* elements = | 1130 HValue* elements = |
| 1006 AddInstruction(new(zone) HLoadElements(object, mapcheck)); | 1131 AddInstruction(new(zone) HLoadElements(object, mapcheck)); |
| 1007 if (is_store && (fast_elements || fast_smi_only_elements)) { | 1132 if (is_store && (fast_elements || fast_smi_only_elements) && |
| 1133 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { | |
| 1008 HCheckMaps* check_cow_map = new(zone) HCheckMaps( | 1134 HCheckMaps* check_cow_map = new(zone) HCheckMaps( |
| 1009 elements, isolate()->factory()->fixed_array_map(), zone); | 1135 elements, isolate()->factory()->fixed_array_map(), zone); |
| 1010 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 1136 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 1011 AddInstruction(check_cow_map); | 1137 AddInstruction(check_cow_map); |
| 1012 } | 1138 } |
| 1013 HInstruction* length = NULL; | 1139 HInstruction* length = NULL; |
| 1014 HInstruction* checked_key = NULL; | |
| 1015 if (IsExternalArrayElementsKind(elements_kind)) { | |
| 1016 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | |
| 1017 checked_key = AddBoundsCheck( | |
| 1018 key, length, ALLOW_SMI_KEY, checked_index_representation); | |
| 1019 HLoadExternalArrayPointer* external_elements = | |
| 1020 new(zone) HLoadExternalArrayPointer(elements); | |
| 1021 AddInstruction(external_elements); | |
| 1022 return BuildExternalArrayElementAccess( | |
| 1023 external_elements, checked_key, val, mapcheck, | |
| 1024 elements_kind, is_store); | |
| 1025 } | |
| 1026 ASSERT(fast_smi_only_elements || | |
| 1027 fast_elements || | |
| 1028 IsFastDoubleElementsKind(elements_kind)); | |
| 1029 if (is_js_array) { | 1140 if (is_js_array) { |
| 1030 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, | 1141 length = AddInstruction(new(zone) HJSArrayLength(object, mapcheck, |
| 1031 HType::Smi())); | 1142 HType::Smi())); |
| 1032 } else { | 1143 } else { |
| 1033 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); | 1144 length = AddInstruction(new(zone) HFixedArrayBaseLength(elements)); |
| 1034 } | 1145 } |
| 1035 checked_key = AddBoundsCheck( | 1146 HValue* checked_key = NULL; |
| 1036 key, length, ALLOW_SMI_KEY, checked_index_representation); | 1147 if (IsExternalArrayElementsKind(elements_kind)) { |
| 1037 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 1148 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 1038 elements_kind, is_store); | 1149 HLoadExternalArrayPointer* external_elements = |
| 1150 new(zone) HLoadExternalArrayPointer(elements); | |
| 1151 AddInstruction(external_elements); | |
| 1152 HCheckSmiOrInt32* checked_index = | |
| 1153 new(graph()->zone()) HCheckSmiOrInt32(key); | |
| 1154 AddInstruction(checked_index); | |
| 1155 BailoutId previous_id = environment()->ast_id(); | |
| 1156 ASSERT(!previous_id.IsNone()); | |
| 1157 IfBuilder oob_ignore_check(this, previous_id); | |
|
Jakob Kummerow
2013/03/11 16:36:07
How about we call this IfBuilder length_checker (a
danno
2013/03/13 15:36:26
Done.
| |
| 1158 oob_ignore_check.BeginIf(checked_index, length, Token::LT); | |
| 1159 IfBuilder oob_ignore_check2(this, previous_id); | |
|
Jakob Kummerow
2013/03/11 16:36:07
...and this one negative_checker?
danno
2013/03/13 15:36:26
Done.
| |
| 1160 HInstruction* bounds_check = | |
| 1161 oob_ignore_check2.BeginIf(checked_index, | |
| 1162 graph()->GetConstant0(), | |
| 1163 Token::LT); | |
| 1164 // Negative array indices can't be ignored and must be handled by the | |
| 1165 // runtime. | |
| 1166 AddSoftDeoptimize(); | |
|
Jakob Kummerow
2013/03/11 16:36:07
You don't want a soft deopt here. HSoftDeoptimize
danno
2013/03/13 15:36:26
Done.
| |
| 1167 oob_ignore_check2.BeginElse(); | |
| 1168 HInstruction* result = BuildExternalArrayElementAccess( | |
| 1169 external_elements, key, val, bounds_check, | |
| 1170 elements_kind, is_store); | |
| 1171 AddInstruction(result); | |
| 1172 oob_ignore_check2.End(); | |
| 1173 oob_ignore_check.BeginElse(); | |
| 1174 oob_ignore_check.End(); | |
| 1175 return result; | |
| 1176 } else { | |
| 1177 ASSERT(store_mode == STANDARD_STORE); | |
| 1178 checked_key = AddBoundsCheck( | |
| 1179 key, length, ALLOW_SMI_KEY, checked_index_representation); | |
| 1180 HLoadExternalArrayPointer* external_elements = | |
| 1181 new(zone) HLoadExternalArrayPointer(elements); | |
| 1182 AddInstruction(external_elements); | |
| 1183 return AddInstruction(BuildExternalArrayElementAccess( | |
| 1184 external_elements, checked_key, val, mapcheck, | |
| 1185 elements_kind, is_store)); | |
| 1186 } | |
| 1187 } | |
| 1188 ASSERT(fast_smi_only_elements || | |
| 1189 fast_elements || | |
| 1190 IsFastDoubleElementsKind(elements_kind)); | |
| 1191 | |
| 1192 if (is_store && IsFastSmiElementsKind(elements_kind) && | |
| 1193 val->type().IsTagged() && !val->type().IsSmi()) { | |
|
Jakob Kummerow
2013/03/11 16:36:07
Fun fact: there is no HType (except "uninitialized
danno
2013/03/13 15:36:26
Done.
| |
| 1194 AddInstruction(new(zone) HCheckSmi(val)); | |
| 1195 } | |
| 1196 | |
| 1197 if (IsGrowStoreMode(store_mode)) { | |
| 1198 elements = BuildCheckForCapacityGrow(object, elements, elements_kind, | |
| 1199 length, key, is_js_array); | |
| 1200 checked_key = key; | |
| 1201 } else { | |
| 1202 checked_key = AddBoundsCheck( | |
| 1203 key, length, ALLOW_SMI_KEY, checked_index_representation); | |
| 1204 | |
| 1205 if (is_store && (fast_elements || fast_smi_only_elements)) { | |
| 1206 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { | |
| 1207 elements = | |
| 1208 BuildCopyElementsOnWrite(object, elements, elements_kind, | |
| 1209 length); | |
|
Jakob Kummerow
2013/03/11 16:36:07
nit: fits on the previous line
danno
2013/03/13 15:36:26
Done.
| |
| 1210 } else { | |
| 1211 HCheckMaps* check_cow_map = new(zone) HCheckMaps( | |
| 1212 elements, Isolate::Current()->factory()->fixed_array_map(), zone); | |
|
Jakob Kummerow
2013/03/11 16:36:07
s/Isolate::Current()/isolate()/
danno
2013/03/13 15:36:26
Done.
| |
| 1213 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | |
| 1214 AddInstruction(check_cow_map); | |
| 1215 } | |
| 1216 } | |
| 1217 } | |
| 1218 return AddInstruction( | |
| 1219 BuildFastElementAccess(elements, checked_key, val, mapcheck, | |
| 1220 elements_kind, is_store, store_mode)); | |
| 1039 } | 1221 } |
| 1040 | 1222 |
| 1041 | 1223 |
| 1042 HValue* HGraphBuilder::BuildAllocateElements(HContext* context, | 1224 HValue* HGraphBuilder::BuildAllocateElements(HValue* context, |
| 1043 ElementsKind kind, | 1225 ElementsKind kind, |
| 1044 HValue* capacity) { | 1226 HValue* capacity, |
| 1227 BailoutId ast_id) { | |
| 1045 Zone* zone = this->zone(); | 1228 Zone* zone = this->zone(); |
| 1046 | 1229 |
| 1047 int elements_size = IsFastDoubleElementsKind(kind) | 1230 int elements_size = IsFastDoubleElementsKind(kind) |
| 1048 ? kDoubleSize : kPointerSize; | 1231 ? kDoubleSize : kPointerSize; |
| 1049 HConstant* elements_size_value = | 1232 HConstant* elements_size_value = |
| 1050 new(zone) HConstant(elements_size, Representation::Integer32()); | 1233 new(zone) HConstant(elements_size, Representation::Integer32()); |
| 1051 AddInstruction(elements_size_value); | 1234 AddInstruction(elements_size_value); |
| 1052 HValue* mul = AddInstruction( | 1235 HValue* mul = AddInstruction( |
| 1053 HMul::New(zone, context, capacity, elements_size_value)); | 1236 HMul::New(zone, context, capacity, elements_size_value)); |
| 1054 mul->ChangeRepresentation(Representation::Integer32()); | 1237 mul->ChangeRepresentation(Representation::Integer32()); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1069 } | 1252 } |
| 1070 | 1253 |
| 1071 HValue* elements = | 1254 HValue* elements = |
| 1072 AddInstruction(new(zone) HAllocate(context, total_size, | 1255 AddInstruction(new(zone) HAllocate(context, total_size, |
| 1073 HType::JSArray(), flags)); | 1256 HType::JSArray(), flags)); |
| 1074 | 1257 |
| 1075 Factory* factory = isolate()->factory(); | 1258 Factory* factory = isolate()->factory(); |
| 1076 Handle<Map> map = IsFastDoubleElementsKind(kind) | 1259 Handle<Map> map = IsFastDoubleElementsKind(kind) |
| 1077 ? factory->fixed_double_array_map() | 1260 ? factory->fixed_double_array_map() |
| 1078 : factory->fixed_array_map(); | 1261 : factory->fixed_array_map(); |
| 1079 BuildStoreMap(elements, map, BailoutId::StubEntry()); | 1262 BuildStoreMap(elements, map, ast_id); |
| 1080 | 1263 |
| 1081 Handle<String> fixed_array_length_field_name = factory->length_field_string(); | 1264 Handle<String> fixed_array_length_field_name = factory->length_field_string(); |
| 1082 HInstruction* store_length = | 1265 HInstruction* store_length = |
| 1083 new(zone) HStoreNamedField(elements, fixed_array_length_field_name, | 1266 new(zone) HStoreNamedField(elements, fixed_array_length_field_name, |
| 1084 capacity, true, FixedArray::kLengthOffset); | 1267 capacity, true, FixedArray::kLengthOffset); |
| 1085 AddInstruction(store_length); | 1268 AddInstruction(store_length); |
| 1086 AddSimulate(BailoutId::StubEntry(), FIXED_SIMULATE); | 1269 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
| 1087 | 1270 |
| 1088 return elements; | 1271 return elements; |
| 1089 } | 1272 } |
| 1090 | 1273 |
| 1091 | 1274 |
| 1092 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, | 1275 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
| 1093 HValue* map, | 1276 HValue* map, |
| 1094 BailoutId id) { | 1277 BailoutId id) { |
| 1095 Zone* zone = this->zone(); | 1278 Zone* zone = this->zone(); |
| 1096 Factory* factory = isolate()->factory(); | 1279 Factory* factory = isolate()->factory(); |
| 1097 Handle<String> map_field_name = factory->map_field_string(); | 1280 Handle<String> map_field_name = factory->map_field_string(); |
| 1098 HInstruction* store_map = | 1281 HInstruction* store_map = |
| 1099 new(zone) HStoreNamedField(object, map_field_name, map, | 1282 new(zone) HStoreNamedField(object, map_field_name, map, |
| 1100 true, JSObject::kMapOffset); | 1283 true, JSObject::kMapOffset); |
| 1101 store_map->SetGVNFlag(kChangesMaps); | 1284 store_map->SetGVNFlag(kChangesMaps); |
| 1102 AddInstruction(store_map); | 1285 AddInstruction(store_map); |
| 1103 AddSimulate(id, FIXED_SIMULATE); | 1286 AddSimulate(id, REMOVABLE_SIMULATE); |
| 1104 return store_map; | 1287 return store_map; |
| 1105 } | 1288 } |
| 1106 | 1289 |
| 1107 | 1290 |
| 1108 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, | 1291 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
| 1109 Handle<Map> map, | 1292 Handle<Map> map, |
| 1110 BailoutId id) { | 1293 BailoutId id) { |
| 1111 Zone* zone = this->zone(); | 1294 Zone* zone = this->zone(); |
| 1112 HValue* map_constant = | 1295 HValue* map_constant = |
| 1113 AddInstruction(new(zone) HConstant(map, Representation::Tagged())); | 1296 AddInstruction(new(zone) HConstant(map, Representation::Tagged())); |
| 1114 return BuildStoreMap(object, map_constant, id); | 1297 return BuildStoreMap(object, map_constant, id); |
| 1115 } | 1298 } |
| 1116 | 1299 |
| 1117 | 1300 |
| 1118 void HGraphBuilder::BuildCopyElements(HContext* context, | 1301 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* context, |
| 1302 HValue* old_capacity) { | |
| 1303 Zone* zone = this->zone(); | |
| 1304 HValue* half_old_capacity = | |
| 1305 AddInstruction(HDiv::New(zone, | |
|
Jakob Kummerow
2013/03/11 16:36:07
prefer HSar (then you won't need GetConstant2() at
danno
2013/03/13 15:36:26
Done.
| |
| 1306 context, | |
| 1307 old_capacity, | |
| 1308 graph_->GetConstant2())); | |
| 1309 half_old_capacity->ChangeRepresentation(Representation::Integer32()); | |
| 1310 half_old_capacity->ClearFlag(HValue::kCanOverflow); | |
| 1311 | |
| 1312 HValue* new_capacity = AddInstruction( | |
| 1313 HAdd::New(zone, context, half_old_capacity, old_capacity)); | |
| 1314 new_capacity->ChangeRepresentation(Representation::Integer32()); | |
| 1315 new_capacity->ClearFlag(HValue::kCanOverflow); | |
| 1316 | |
| 1317 HValue* min_growth = | |
| 1318 AddInstruction(new(zone) HConstant(4, Representation::Integer32())); | |
|
Jakob Kummerow
2013/03/11 16:36:07
The C++ version (NewElementsCapacity in objects.h)
danno
2013/03/13 15:36:26
Done.
| |
| 1319 | |
| 1320 new_capacity = AddInstruction( | |
| 1321 HAdd::New(zone, context, new_capacity, min_growth)); | |
| 1322 new_capacity->ChangeRepresentation(Representation::Integer32()); | |
| 1323 new_capacity->ClearFlag(HValue::kCanOverflow); | |
| 1324 | |
| 1325 return new_capacity; | |
| 1326 } | |
| 1327 | |
| 1328 | |
| 1329 void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) { | |
| 1330 Zone* zone = this->zone(); | |
| 1331 Heap* heap = info_->isolate()->heap(); | |
|
Jakob Kummerow
2013/03/11 16:36:07
s/info_->//
danno
2013/03/13 15:36:26
Done.
| |
| 1332 int element_size = IsFastDoubleElementsKind(kind) | |
| 1333 ? kDoubleSize | |
|
Jakob Kummerow
2013/03/11 16:36:07
nit: fits on previous line. For your copy/paste co
danno
2013/03/13 15:36:26
Done.
| |
| 1334 : kPointerSize; | |
| 1335 int max_size = heap->MaxNewSpaceAllocationSize() / element_size; | |
| 1336 max_size -= sizeof(JSArray) / element_size; | |
|
Jakob Kummerow
2013/03/11 16:36:07
I think you mean s/sizeof(JSArray)/JSArray::kSize/
danno
2013/03/13 15:36:26
Done.
| |
| 1337 HConstant* max_size_constant = | |
| 1338 new(zone) HConstant(max_size, Representation::Integer32()); | |
| 1339 AddInstruction(max_size_constant); | |
| 1340 // Since we're forcing Integer32 representation for this HBoundsCheck, | |
|
Jakob Kummerow
2013/03/11 16:36:07
I'd prefer to make this explicit by passing (_, _,
danno
2013/03/13 15:36:26
Done.
| |
| 1341 // there's no need to Smi-check the index. | |
| 1342 AddInstruction(new(zone) HBoundsCheck(length, max_size_constant)); | |
| 1343 } | |
| 1344 | |
| 1345 | |
| 1346 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, | |
| 1347 HValue* elements, | |
| 1348 ElementsKind kind, | |
| 1349 HValue* length, | |
| 1350 HValue* new_capacity, | |
| 1351 BailoutId ast_id) { | |
| 1352 Zone* zone = this->zone(); | |
| 1353 HValue* context = environment()->LookupContext(); | |
| 1354 | |
| 1355 BuildNewSpaceArrayCheck(new_capacity, kind); | |
| 1356 | |
| 1357 HValue* new_elements = | |
| 1358 BuildAllocateElements(context, kind, new_capacity, ast_id); | |
| 1359 | |
| 1360 BuildCopyElements(context, elements, kind, | |
| 1361 new_elements, kind, | |
| 1362 length, new_capacity, ast_id); | |
| 1363 | |
| 1364 Isolate* isolate = graph()->isolate(); | |
|
Jakob Kummerow
2013/03/11 16:36:07
no need for this, just use [this->]isolate() direc
danno
2013/03/13 15:36:26
Done.
| |
| 1365 Factory* factory = isolate->factory(); | |
| 1366 HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField( | |
| 1367 object, | |
| 1368 factory->elements_field_string(), | |
| 1369 new_elements, true, | |
| 1370 JSArray::kElementsOffset)); | |
| 1371 elements_store->SetGVNFlag(kChangesElementsPointer); | |
| 1372 | |
| 1373 return new_elements; | |
| 1374 } | |
| 1375 | |
| 1376 | |
| 1377 void HGraphBuilder::BuildFillElementsWithHole(HValue* context, | |
| 1378 HValue* elements, | |
| 1379 ElementsKind elements_kind, | |
| 1380 HValue* from, | |
| 1381 HValue* to, | |
| 1382 BailoutId ast_id) { | |
| 1383 // Fast elements kinds need to be initialized in case statements below cause | |
| 1384 // a garbage collection. | |
| 1385 Factory* factory = info_->isolate()->factory(); | |
|
Jakob Kummerow
2013/03/11 16:36:07
s/info_->//
danno
2013/03/13 15:36:26
Done.
| |
| 1386 | |
| 1387 double nan_double = FixedDoubleArray::hole_nan_as_double(); | |
| 1388 Zone* zone = this->zone(); | |
| 1389 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) | |
| 1390 ? AddInstruction(new(zone) HConstant(factory->the_hole_value(), | |
| 1391 Representation::Tagged())) | |
| 1392 : AddInstruction(new(zone) HConstant(nan_double, | |
| 1393 Representation::Double())); | |
| 1394 | |
| 1395 LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, ast_id); | |
| 1396 | |
| 1397 HValue* key = builder.BeginBody(from, to, Token::LT); | |
| 1398 | |
| 1399 AddInstruction(new(zone) HStoreKeyed(elements, key, hole, | |
| 1400 elements_kind)); | |
|
Jakob Kummerow
2013/03/11 16:36:07
nit: fits on previous line
danno
2013/03/13 15:36:26
Done.
| |
| 1401 AddSimulate(ast_id, REMOVABLE_SIMULATE); | |
| 1402 | |
| 1403 builder.EndBody(); | |
| 1404 } | |
| 1405 | |
| 1406 | |
| 1407 void HGraphBuilder::BuildCopyElements(HValue* context, | |
| 1119 HValue* from_elements, | 1408 HValue* from_elements, |
| 1120 ElementsKind from_elements_kind, | 1409 ElementsKind from_elements_kind, |
| 1121 HValue* to_elements, | 1410 HValue* to_elements, |
| 1122 ElementsKind to_elements_kind, | 1411 ElementsKind to_elements_kind, |
| 1123 HValue* length) { | 1412 HValue* length, |
| 1124 LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, | 1413 HValue* capacity, |
| 1125 BailoutId::StubEntry()); | 1414 BailoutId ast_id) { |
| 1415 bool pre_fill_with_holes = | |
| 1416 IsFastDoubleElementsKind(from_elements_kind) && | |
| 1417 IsFastObjectElementsKind(to_elements_kind); | |
| 1126 | 1418 |
| 1127 HValue* key = builder.BeginBody(graph()->GetConstant0(), | 1419 if (pre_fill_with_holes) { |
| 1128 length, Token::LT); | 1420 // If the copy might trigger a GC, make sure that the FixedArray is |
| 1421 // pre-initialized with holes to make sure that it's always in a consistent | |
| 1422 // state. | |
| 1423 BuildFillElementsWithHole(context, to_elements, to_elements_kind, | |
| 1424 graph()->GetConstant0(), capacity, ast_id); | |
| 1425 } | |
| 1426 | |
| 1427 LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, ast_id); | |
| 1428 | |
| 1429 HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT); | |
| 1129 | 1430 |
| 1130 HValue* element = | 1431 HValue* element = |
| 1131 AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL, | 1432 AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL, |
| 1132 from_elements_kind, | 1433 from_elements_kind, |
| 1133 ALLOW_RETURN_HOLE)); | 1434 ALLOW_RETURN_HOLE)); |
| 1134 | 1435 |
| 1135 AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element, | 1436 AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element, |
| 1136 to_elements_kind)); | 1437 to_elements_kind)); |
| 1137 AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE); | 1438 AddSimulate(ast_id, REMOVABLE_SIMULATE); |
| 1138 | 1439 |
| 1139 builder.EndBody(); | 1440 builder.EndBody(); |
| 1441 | |
| 1442 if (!pre_fill_with_holes && length != capacity) { | |
| 1443 // Fill unused capacity with the hole. | |
| 1444 BuildFillElementsWithHole(context, to_elements, to_elements_kind, | |
| 1445 key, capacity, ast_id); | |
| 1446 } | |
| 1140 } | 1447 } |
| 1141 | 1448 |
| 1142 | 1449 |
| 1450 void HGraphBuilder::AddSoftDeoptimize() { | |
| 1451 if (FLAG_always_opt) return; | |
| 1452 if (current_block()->IsDeoptimizing()) return; | |
| 1453 AddInstruction(new(zone()) HSoftDeoptimize()); | |
| 1454 current_block()->MarkAsDeoptimizing(); | |
| 1455 graph()->set_has_soft_deoptimize(true); | |
| 1456 } | |
| 1457 | |
| 1458 | |
| 1143 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, | 1459 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, |
| 1144 TypeFeedbackOracle* oracle) | 1460 TypeFeedbackOracle* oracle) |
| 1145 : HGraphBuilder(info), | 1461 : HGraphBuilder(info), |
| 1146 function_state_(NULL), | 1462 function_state_(NULL), |
| 1147 initial_function_state_(this, info, oracle, NORMAL_RETURN), | 1463 initial_function_state_(this, info, oracle, NORMAL_RETURN), |
| 1148 ast_context_(NULL), | 1464 ast_context_(NULL), |
| 1149 break_scope_(NULL), | 1465 break_scope_(NULL), |
| 1150 inlined_count_(0), | 1466 inlined_count_(0), |
| 1151 globals_(10, info->zone()), | 1467 globals_(10, info->zone()), |
| 1152 inline_bailout_(false) { | 1468 inline_bailout_(false) { |
| (...skipping 3339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4492 current_block()->AddPhi(instr); | 4808 current_block()->AddPhi(instr); |
| 4493 } | 4809 } |
| 4494 | 4810 |
| 4495 | 4811 |
| 4496 void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { | 4812 void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 4497 Push(instr); | 4813 Push(instr); |
| 4498 AddInstruction(instr); | 4814 AddInstruction(instr); |
| 4499 } | 4815 } |
| 4500 | 4816 |
| 4501 | 4817 |
| 4502 void HOptimizedGraphBuilder::AddSoftDeoptimize() { | |
| 4503 if (FLAG_always_opt) return; | |
| 4504 if (current_block()->IsDeoptimizing()) return; | |
| 4505 AddInstruction(new(zone()) HSoftDeoptimize()); | |
| 4506 current_block()->MarkAsDeoptimizing(); | |
| 4507 graph()->set_has_soft_deoptimize(true); | |
| 4508 } | |
| 4509 | |
| 4510 | |
| 4511 template <class Instruction> | 4818 template <class Instruction> |
| 4512 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { | 4819 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { |
| 4513 int count = call->argument_count(); | 4820 int count = call->argument_count(); |
| 4514 ZoneList<HValue*> arguments(count, zone()); | 4821 ZoneList<HValue*> arguments(count, zone()); |
| 4515 for (int i = 0; i < count; ++i) { | 4822 for (int i = 0; i < count; ++i) { |
| 4516 arguments.Add(Pop(), zone()); | 4823 arguments.Add(Pop(), zone()); |
| 4517 } | 4824 } |
| 4518 | 4825 |
| 4519 while (!arguments.is_empty()) { | 4826 while (!arguments.is_empty()) { |
| 4520 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); | 4827 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); |
| (...skipping 2253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6774 return new(zone()) HLoadKeyedGeneric(context, object, key); | 7081 return new(zone()) HLoadKeyedGeneric(context, object, key); |
| 6775 } | 7082 } |
| 6776 | 7083 |
| 6777 | 7084 |
| 6778 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( | 7085 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( |
| 6779 HValue* object, | 7086 HValue* object, |
| 6780 HValue* key, | 7087 HValue* key, |
| 6781 HValue* val, | 7088 HValue* val, |
| 6782 HValue* dependency, | 7089 HValue* dependency, |
| 6783 Handle<Map> map, | 7090 Handle<Map> map, |
| 6784 bool is_store) { | 7091 bool is_store, |
| 7092 KeyedAccessStoreMode store_mode) { | |
| 6785 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, | 7093 HCheckMaps* mapcheck = new(zone()) HCheckMaps(object, map, |
| 6786 zone(), dependency); | 7094 zone(), dependency); |
| 6787 AddInstruction(mapcheck); | 7095 AddInstruction(mapcheck); |
| 6788 if (dependency) { | 7096 if (dependency) { |
| 6789 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | 7097 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 6790 } | 7098 } |
| 6791 return BuildUncheckedMonomorphicElementAccess( | 7099 return BuildUncheckedMonomorphicElementAccess( |
| 6792 object, key, val, | 7100 object, key, val, |
| 6793 mapcheck, map->instance_type() == JS_ARRAY_TYPE, | 7101 mapcheck, map->instance_type() == JS_ARRAY_TYPE, |
| 6794 map->elements_kind(), is_store); | 7102 map->elements_kind(), is_store, store_mode); |
| 6795 } | 7103 } |
| 6796 | 7104 |
| 6797 | 7105 |
| 6798 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( | 7106 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( |
| 6799 HValue* object, | 7107 HValue* object, |
| 6800 HValue* key, | 7108 HValue* key, |
| 6801 HValue* val, | 7109 HValue* val, |
| 6802 SmallMapList* maps) { | 7110 SmallMapList* maps) { |
| 6803 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 7111 // For polymorphic loads of similar elements kinds (i.e. all tagged or all |
| 6804 // double), always use the "worst case" code without a transition. This is | 7112 // 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... | |
| 6839 } | 7147 } |
| 6840 } | 7148 } |
| 6841 if (!has_double_maps && !has_smi_or_object_maps) return NULL; | 7149 if (!has_double_maps && !has_smi_or_object_maps) return NULL; |
| 6842 | 7150 |
| 6843 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); | 7151 HCheckMaps* check_maps = new(zone()) HCheckMaps(object, maps, zone()); |
| 6844 AddInstruction(check_maps); | 7152 AddInstruction(check_maps); |
| 6845 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( | 7153 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( |
| 6846 object, key, val, check_maps, | 7154 object, key, val, check_maps, |
| 6847 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, | 7155 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, |
| 6848 most_general_consolidated_map->elements_kind(), | 7156 most_general_consolidated_map->elements_kind(), |
| 6849 false); | 7157 false, STANDARD_STORE); |
| 6850 return instr; | 7158 return instr; |
| 6851 } | 7159 } |
| 6852 | 7160 |
| 6853 | 7161 |
| 6854 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 7162 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
| 6855 HValue* object, | 7163 HValue* object, |
| 6856 HValue* key, | 7164 HValue* key, |
| 6857 HValue* val, | 7165 HValue* val, |
| 6858 Expression* prop, | 7166 Expression* prop, |
| 6859 BailoutId ast_id, | 7167 BailoutId ast_id, |
| 6860 int position, | 7168 int position, |
| 6861 bool is_store, | 7169 bool is_store, |
| 7170 KeyedAccessStoreMode store_mode, | |
| 6862 bool* has_side_effects) { | 7171 bool* has_side_effects) { |
| 6863 *has_side_effects = false; | 7172 *has_side_effects = false; |
| 6864 AddInstruction(new(zone()) HCheckNonSmi(object)); | 7173 AddInstruction(new(zone()) HCheckNonSmi(object)); |
| 6865 SmallMapList* maps = prop->GetReceiverTypes(); | 7174 SmallMapList* maps = prop->GetReceiverTypes(); |
| 6866 bool todo_external_array = false; | 7175 bool todo_external_array = false; |
| 6867 | 7176 |
| 6868 if (!is_store) { | 7177 if (!is_store) { |
| 6869 HInstruction* consolidated_load = | 7178 HInstruction* consolidated_load = |
| 6870 TryBuildConsolidatedElementLoad(object, key, val, maps); | 7179 TryBuildConsolidatedElementLoad(object, key, val, maps); |
| 6871 if (consolidated_load != NULL) { | 7180 if (consolidated_load != NULL) { |
| 6872 AddInstruction(consolidated_load); | |
| 6873 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 7181 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
| 6874 if (position != RelocInfo::kNoPosition) { | 7182 if (position != RelocInfo::kNoPosition) { |
| 6875 consolidated_load->set_position(position); | 7183 consolidated_load->set_position(position); |
| 6876 } | 7184 } |
| 6877 return consolidated_load; | 7185 return consolidated_load; |
| 6878 } | 7186 } |
| 6879 } | 7187 } |
| 6880 | 7188 |
| 6881 static const int kNumElementTypes = kElementsKindCount; | 7189 static const int kNumElementTypes = kElementsKindCount; |
| 6882 bool type_todo[kNumElementTypes]; | 7190 bool type_todo[kNumElementTypes]; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6929 } | 7237 } |
| 6930 | 7238 |
| 6931 // If only one map is left after transitioning, handle this case | 7239 // If only one map is left after transitioning, handle this case |
| 6932 // monomorphically. | 7240 // monomorphically. |
| 6933 if (num_untransitionable_maps == 1) { | 7241 if (num_untransitionable_maps == 1) { |
| 6934 HInstruction* instr = NULL; | 7242 HInstruction* instr = NULL; |
| 6935 if (untransitionable_map->has_slow_elements_kind()) { | 7243 if (untransitionable_map->has_slow_elements_kind()) { |
| 6936 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 7244 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 6937 : BuildLoadKeyedGeneric(object, key)); | 7245 : BuildLoadKeyedGeneric(object, key)); |
| 6938 } else { | 7246 } else { |
| 6939 instr = AddInstruction(BuildMonomorphicElementAccess( | 7247 instr = BuildMonomorphicElementAccess( |
| 6940 object, key, val, transition, untransitionable_map, is_store)); | 7248 object, key, val, transition, untransitionable_map, is_store, |
| 7249 store_mode); | |
| 6941 } | 7250 } |
| 6942 *has_side_effects |= instr->HasObservableSideEffects(); | 7251 *has_side_effects |= instr->HasObservableSideEffects(); |
| 6943 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 7252 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
| 6944 return is_store ? NULL : instr; | 7253 return is_store ? NULL : instr; |
| 6945 } | 7254 } |
| 6946 | 7255 |
| 6947 HInstruction* checkspec = | 7256 HInstruction* checkspec = |
| 6948 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); | 7257 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); |
| 6949 HBasicBlock* join = graph()->CreateBasicBlock(); | 7258 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 6950 | 7259 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7011 typecheck->SetSuccessorAt(1, if_fastobject); | 7320 typecheck->SetSuccessorAt(1, if_fastobject); |
| 7012 current_block()->Finish(typecheck); | 7321 current_block()->Finish(typecheck); |
| 7013 | 7322 |
| 7014 set_current_block(if_jsarray); | 7323 set_current_block(if_jsarray); |
| 7015 HInstruction* length; | 7324 HInstruction* length; |
| 7016 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, | 7325 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, |
| 7017 HType::Smi())); | 7326 HType::Smi())); |
| 7018 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); | 7327 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); |
| 7019 access = AddInstruction(BuildFastElementAccess( | 7328 access = AddInstruction(BuildFastElementAccess( |
| 7020 elements, checked_key, val, elements_kind_branch, | 7329 elements, checked_key, val, elements_kind_branch, |
| 7021 elements_kind, is_store)); | 7330 elements_kind, is_store, STANDARD_STORE)); |
| 7022 if (!is_store) { | 7331 if (!is_store) { |
| 7023 Push(access); | 7332 Push(access); |
| 7024 } | 7333 } |
| 7025 | 7334 |
| 7026 *has_side_effects |= access->HasObservableSideEffects(); | 7335 *has_side_effects |= access->HasObservableSideEffects(); |
| 7027 if (position != -1) { | 7336 if (position != -1) { |
| 7028 access->set_position(position); | 7337 access->set_position(position); |
| 7029 } | 7338 } |
| 7030 if_jsarray->Goto(join); | 7339 if_jsarray->Goto(join); |
| 7031 | 7340 |
| 7032 set_current_block(if_fastobject); | 7341 set_current_block(if_fastobject); |
| 7033 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 7342 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 7034 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); | 7343 checked_key = AddBoundsCheck(key, length, ALLOW_SMI_KEY); |
| 7035 access = AddInstruction(BuildFastElementAccess( | 7344 access = AddInstruction(BuildFastElementAccess( |
| 7036 elements, checked_key, val, elements_kind_branch, | 7345 elements, checked_key, val, elements_kind_branch, |
| 7037 elements_kind, is_store)); | 7346 elements_kind, is_store, STANDARD_STORE)); |
| 7038 } else if (elements_kind == DICTIONARY_ELEMENTS) { | 7347 } else if (elements_kind == DICTIONARY_ELEMENTS) { |
| 7039 if (is_store) { | 7348 if (is_store) { |
| 7040 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | 7349 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
| 7041 } else { | 7350 } else { |
| 7042 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | 7351 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 7043 } | 7352 } |
| 7044 } else { // External array elements. | 7353 } else { // External array elements. |
| 7045 access = AddInstruction(BuildExternalArrayElementAccess( | 7354 access = AddInstruction(BuildExternalArrayElementAccess( |
| 7046 external_elements, checked_key, val, | 7355 external_elements, checked_key, val, |
| 7047 elements_kind_branch, elements_kind, is_store)); | 7356 elements_kind_branch, elements_kind, is_store)); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 7073 int position, | 7382 int position, |
| 7074 bool is_store, | 7383 bool is_store, |
| 7075 bool* has_side_effects) { | 7384 bool* has_side_effects) { |
| 7076 ASSERT(!expr->IsPropertyName()); | 7385 ASSERT(!expr->IsPropertyName()); |
| 7077 HInstruction* instr = NULL; | 7386 HInstruction* instr = NULL; |
| 7078 if (expr->IsMonomorphic()) { | 7387 if (expr->IsMonomorphic()) { |
| 7079 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 7388 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 7080 if (map->has_slow_elements_kind()) { | 7389 if (map->has_slow_elements_kind()) { |
| 7081 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 7390 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 7082 : BuildLoadKeyedGeneric(obj, key); | 7391 : BuildLoadKeyedGeneric(obj, key); |
| 7392 AddInstruction(instr); | |
| 7083 } else { | 7393 } else { |
| 7084 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 7394 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 7085 instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); | 7395 instr = BuildMonomorphicElementAccess( |
| 7396 obj, key, val, NULL, map, | |
| 7397 is_store, expr->GetStoreMode()); | |
|
Jakob Kummerow
2013/03/11 16:36:07
nit: fits on previous line
danno
2013/03/13 15:36:26
Done.
| |
| 7086 } | 7398 } |
| 7087 } else if (expr->GetReceiverTypes() != NULL && | 7399 } else if (expr->GetReceiverTypes() != NULL && |
| 7088 !expr->GetReceiverTypes()->is_empty()) { | 7400 !expr->GetReceiverTypes()->is_empty()) { |
| 7089 return HandlePolymorphicElementAccess( | 7401 return HandlePolymorphicElementAccess( |
| 7090 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 7402 obj, key, val, expr, ast_id, position, is_store, |
| 7403 expr->GetStoreMode(), has_side_effects); | |
| 7091 } else { | 7404 } else { |
| 7092 if (is_store) { | 7405 if (is_store) { |
| 7093 instr = BuildStoreKeyedGeneric(obj, key, val); | 7406 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 7094 } else { | 7407 } else { |
| 7095 instr = BuildLoadKeyedGeneric(obj, key); | 7408 instr = BuildLoadKeyedGeneric(obj, key); |
| 7096 } | 7409 } |
| 7410 AddInstruction(instr); | |
| 7097 } | 7411 } |
| 7098 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 7412 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
| 7099 AddInstruction(instr); | |
| 7100 *has_side_effects = instr->HasObservableSideEffects(); | 7413 *has_side_effects = instr->HasObservableSideEffects(); |
| 7101 return instr; | 7414 return instr; |
| 7102 } | 7415 } |
| 7103 | 7416 |
| 7104 | 7417 |
| 7105 HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric( | 7418 HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric( |
| 7106 HValue* object, | 7419 HValue* object, |
| 7107 HValue* key, | 7420 HValue* key, |
| 7108 HValue* value) { | 7421 HValue* value) { |
| 7109 HValue* context = environment()->LookupContext(); | 7422 HValue* context = environment()->LookupContext(); |
| (...skipping 3753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10863 } | 11176 } |
| 10864 } | 11177 } |
| 10865 | 11178 |
| 10866 #ifdef DEBUG | 11179 #ifdef DEBUG |
| 10867 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 11180 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 10868 if (allocator_ != NULL) allocator_->Verify(); | 11181 if (allocator_ != NULL) allocator_->Verify(); |
| 10869 #endif | 11182 #endif |
| 10870 } | 11183 } |
| 10871 | 11184 |
| 10872 } } // namespace v8::internal | 11185 } } // namespace v8::internal |
| OLD | NEW |