OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 changed = true; | 159 changed = true; |
160 fields_[i] = other.fields_[i]; | 160 fields_[i] = other.fields_[i]; |
161 } | 161 } |
162 } | 162 } |
163 return changed; | 163 return changed; |
164 } | 164 } |
165 | 165 |
166 | 166 |
167 class VirtualState : public ZoneObject { | 167 class VirtualState : public ZoneObject { |
168 public: | 168 public: |
169 VirtualState(Node* owner, Zone* zone, size_t size); | 169 VirtualState(NodeId owner, Zone* zone, size_t size); |
170 VirtualState(Node* owner, const VirtualState& states); | 170 VirtualState(NodeId owner, const VirtualState& states); |
171 | 171 |
172 VirtualObject* VirtualObjectFromAlias(size_t alias); | 172 VirtualObject* VirtualObjectFromAlias(size_t alias); |
173 VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, | 173 VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, |
174 size_t fields, | 174 size_t fields, |
175 bool initialized, Zone* zone, | 175 bool initialized, Zone* zone, |
176 bool force_copy); | 176 bool force_copy); |
177 void SetVirtualObject(Alias alias, VirtualObject* state); | 177 void SetVirtualObject(Alias alias, VirtualObject* state); |
178 bool UpdateFrom(VirtualState* state, Zone* zone); | 178 bool UpdateFrom(VirtualState* state, Zone* zone); |
179 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 179 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
180 CommonOperatorBuilder* common, Node* control, int arity); | 180 CommonOperatorBuilder* common, Node* control, int arity); |
181 size_t size() const { return info_.size(); } | 181 size_t size() const { return info_.size(); } |
182 Node* owner() const { return owner_; } | 182 NodeId owner() const { return owner_; } |
183 VirtualObject* Copy(VirtualObject* obj, Alias alias); | 183 VirtualObject* Copy(VirtualObject* obj, Alias alias); |
184 void SetCopyRequired() { | 184 void SetCopyRequired() { |
185 for (VirtualObject* obj : info_) { | 185 for (VirtualObject* obj : info_) { |
186 if (obj) obj->SetCopyRequired(); | 186 if (obj) obj->SetCopyRequired(); |
187 } | 187 } |
188 } | 188 } |
189 | 189 |
190 private: | 190 private: |
191 ZoneVector<VirtualObject*> info_; | 191 ZoneVector<VirtualObject*> info_; |
192 Node* owner_; | 192 NodeId owner_; |
193 | 193 |
194 DISALLOW_COPY_AND_ASSIGN(VirtualState); | 194 DISALLOW_COPY_AND_ASSIGN(VirtualState); |
195 }; | 195 }; |
196 | 196 |
197 | 197 |
198 class MergeCache : public ZoneObject { | 198 class MergeCache : public ZoneObject { |
199 public: | 199 public: |
200 explicit MergeCache(Zone* zone) | 200 explicit MergeCache(Zone* zone) |
201 : states_(zone), objects_(zone), fields_(zone) { | 201 : states_(zone), objects_(zone), fields_(zone) { |
202 states_.reserve(5); | 202 states_.reserve(5); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 fields_.push_back(field); | 265 fields_.push_back(field); |
266 } | 266 } |
267 if (field != rep) { | 267 if (field != rep) { |
268 rep = nullptr; | 268 rep = nullptr; |
269 } | 269 } |
270 } | 270 } |
271 return rep; | 271 return rep; |
272 } | 272 } |
273 | 273 |
274 | 274 |
275 VirtualState::VirtualState(Node* owner, Zone* zone, size_t size) | 275 VirtualState::VirtualState(NodeId owner, Zone* zone, size_t size) |
276 : info_(size, nullptr, zone), owner_(owner) {} | 276 : info_(size, nullptr, zone), owner_(owner) {} |
277 | 277 |
278 | 278 |
279 VirtualState::VirtualState(Node* owner, const VirtualState& state) | 279 VirtualState::VirtualState(NodeId owner, const VirtualState& state) |
280 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), | 280 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
281 owner_(owner) { | 281 owner_(owner) { |
282 for (size_t i = 0; i < info_.size(); ++i) { | 282 for (size_t i = 0; i < info_.size(); ++i) { |
283 if (state.info_[i]) { | 283 if (state.info_[i]) { |
284 info_[i] = state.info_[i]; | 284 info_[i] = state.info_[i]; |
285 } | 285 } |
286 } | 286 } |
287 } | 287 } |
288 | 288 |
289 | 289 |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
872 if (node->id() >= aliases_.size()) { | 872 if (node->id() >= aliases_.size()) { |
873 return false; | 873 return false; |
874 } | 874 } |
875 return aliases_[node->id()] == kNotReachable; | 875 return aliases_[node->id()] == kNotReachable; |
876 } | 876 } |
877 | 877 |
878 | 878 |
879 void EscapeAnalysis::RunObjectAnalysis() { | 879 void EscapeAnalysis::RunObjectAnalysis() { |
880 virtual_states_.resize(graph()->NodeCount()); | 880 virtual_states_.resize(graph()->NodeCount()); |
881 stack().push_back(graph()->start()); | 881 stack().push_back(graph()->start()); |
| 882 ZoneVector<Node*> danglers(zone()); |
882 while (!stack().empty()) { | 883 while (!stack().empty()) { |
883 Node* node = stack().back(); | 884 Node* node = stack().back(); |
884 stack().pop_back(); | 885 stack().pop_back(); |
885 if (Process(node)) { | 886 if (Process(node)) { |
886 for (Edge edge : node->use_edges()) { | 887 for (Edge edge : node->use_edges()) { |
887 Node* use = edge.from(); | 888 Node* use = edge.from(); |
888 if (IsNotReachable(use)) { | 889 if (IsNotReachable(use)) { |
889 continue; | 890 continue; |
890 } | 891 } |
891 if (NodeProperties::IsEffectEdge(edge)) { | 892 if (NodeProperties::IsEffectEdge(edge)) { |
892 if ((use->opcode() != IrOpcode::kLoadField && | 893 if ((use->opcode() != IrOpcode::kLoadField && |
893 use->opcode() != IrOpcode::kLoadElement) || | 894 use->opcode() != IrOpcode::kLoadElement) || |
894 !IsDanglingEffectNode(use)) { | 895 !IsDanglingEffectNode(use)) { |
895 stack().push_back(use); | 896 stack().push_back(use); |
| 897 } else { |
| 898 danglers.push_back(use); |
896 } | 899 } |
897 } | 900 } |
898 } | 901 } |
899 // First process loads: dangling loads are a problem otherwise. | 902 stack().insert(stack().end(), danglers.begin(), danglers.end()); |
900 for (Edge edge : node->use_edges()) { | 903 danglers.clear(); |
901 Node* use = edge.from(); | |
902 if (IsNotReachable(use)) { | |
903 continue; | |
904 } | |
905 if (NodeProperties::IsEffectEdge(edge)) { | |
906 if ((use->opcode() == IrOpcode::kLoadField || | |
907 use->opcode() == IrOpcode::kLoadElement) && | |
908 IsDanglingEffectNode(use)) { | |
909 stack().push_back(use); | |
910 } | |
911 } | |
912 } | |
913 } | 904 } |
914 } | 905 } |
915 #ifdef DEBUG | 906 #ifdef DEBUG |
916 if (FLAG_trace_turbo_escape) { | 907 if (FLAG_trace_turbo_escape) { |
917 DebugPrint(); | 908 DebugPrint(); |
918 } | 909 } |
919 #endif | 910 #endif |
920 } | 911 } |
921 | 912 |
922 | 913 |
923 bool EscapeStatusAnalysis::IsDanglingEffectNode(Node* node) { | 914 bool EscapeStatusAnalysis::IsDanglingEffectNode(Node* node) { |
924 if (status_[node->id()] & kDanglingComputed) { | 915 if (status_[node->id()] & kDanglingComputed) { |
925 return status_[node->id()] & kDangling; | 916 return status_[node->id()] & kDangling; |
926 } | 917 } |
927 if (node->op()->EffectInputCount() == 0) return false; | 918 if (node->op()->EffectInputCount() == 0 || |
928 if (node->op()->EffectOutputCount() == 0) return false; | 919 node->op()->EffectOutputCount() == 0 || |
929 if (node->op()->EffectInputCount() == 1 && | 920 (node->op()->EffectInputCount() == 1 && |
930 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) { | 921 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart)) { |
931 // The start node is used as sentinel for nodes that are in general | 922 // The start node is used as sentinel for nodes that are in general |
932 // effectful, but of which an analysis has determined that they do not | 923 // effectful, but of which an analysis has determined that they do not |
933 // produce effects in this instance. We don't consider these nodes dangling. | 924 // produce effects in this instance. We don't consider these nodes dangling. |
934 status_[node->id()] |= kDanglingComputed; | 925 status_[node->id()] |= kDanglingComputed; |
935 return false; | 926 return false; |
936 } | 927 } |
937 for (Edge edge : node->use_edges()) { | 928 for (Edge edge : node->use_edges()) { |
938 Node* use = edge.from(); | 929 Node* use = edge.from(); |
939 if (aliases_[use->id()] == kNotReachable) continue; | 930 if (aliases_[use->id()] == kNotReachable) continue; |
940 if (NodeProperties::IsEffectEdge(edge)) { | 931 if (NodeProperties::IsEffectEdge(edge)) { |
941 status_[node->id()] |= kDanglingComputed; | 932 status_[node->id()] |= kDanglingComputed; |
942 return false; | 933 return false; |
943 } | 934 } |
944 } | 935 } |
945 status_[node->id()] |= kDanglingComputed | kDangling; | 936 status_[node->id()] |= kDanglingComputed | kDangling; |
946 return true; | 937 return true; |
947 } | 938 } |
948 | 939 |
949 | 940 |
950 bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) { | 941 bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) { |
951 if (status_[node->id()] & kBranchPointComputed) { | 942 if (status_[node->id()] & kBranchPointComputed) { |
952 return status_[node->id()] & kBranchPoint; | 943 return status_[node->id()] & kBranchPoint; |
953 } | 944 } |
954 int count = 0; | 945 int count = 0; |
955 for (Edge edge : node->use_edges()) { | 946 for (Edge edge : node->use_edges()) { |
956 Node* use = edge.from(); | 947 Node* use = edge.from(); |
957 if (aliases_[use->id()] == kNotReachable) continue; | 948 if (aliases_[use->id()] == kNotReachable) continue; |
958 if (NodeProperties::IsEffectEdge(edge)) { | 949 if (NodeProperties::IsEffectEdge(edge)) { |
959 if ((node->opcode() == IrOpcode::kLoadField || | 950 if ((use->opcode() == IrOpcode::kLoadField || |
960 node->opcode() == IrOpcode::kLoadElement || | 951 use->opcode() == IrOpcode::kLoadElement || |
961 node->opcode() == IrOpcode::kLoad) && | 952 use->opcode() == IrOpcode::kLoad) && |
962 IsDanglingEffectNode(node)) | 953 IsDanglingEffectNode(use)) |
963 continue; | 954 continue; |
964 if (++count > 1) { | 955 if (++count > 1) { |
965 status_[node->id()] |= kBranchPointComputed | kBranchPoint; | 956 status_[node->id()] |= kBranchPointComputed | kBranchPoint; |
966 return true; | 957 return true; |
967 } | 958 } |
968 } | 959 } |
969 } | 960 } |
970 status_[node->id()] |= kBranchPointComputed; | 961 status_[node->id()] |= kBranchPointComputed; |
971 return false; | 962 return false; |
972 } | 963 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 } | 1032 } |
1042 } | 1033 } |
1043 break; | 1034 break; |
1044 } | 1035 } |
1045 } | 1036 } |
1046 } | 1037 } |
1047 | 1038 |
1048 | 1039 |
1049 VirtualState* EscapeAnalysis::CopyForModificationAt(VirtualState* state, | 1040 VirtualState* EscapeAnalysis::CopyForModificationAt(VirtualState* state, |
1050 Node* node) { | 1041 Node* node) { |
1051 if (state->owner() != node) { | 1042 if (state->owner() != node->id()) { |
1052 VirtualState* new_state = new (zone()) VirtualState(node, *state); | 1043 VirtualState* new_state = new (zone()) VirtualState(node->id(), *state); |
1053 virtual_states_[node->id()] = new_state; | 1044 virtual_states_[node->id()] = new_state; |
1054 TRACE("Copying virtual state %p to new state %p at node %s#%d\n", | 1045 TRACE("Copying virtual state %p to new state %p at node %s#%d\n", |
1055 static_cast<void*>(state), static_cast<void*>(new_state), | 1046 static_cast<void*>(state), static_cast<void*>(new_state), |
1056 node->op()->mnemonic(), node->id()); | 1047 node->op()->mnemonic(), node->id()); |
1057 return new_state; | 1048 return new_state; |
1058 } | 1049 } |
1059 return state; | 1050 return state; |
1060 } | 1051 } |
1061 | 1052 |
1062 | 1053 |
(...skipping 17 matching lines...) Expand all Loading... |
1080 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 1071 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
1081 node->op()->mnemonic()); | 1072 node->op()->mnemonic()); |
1082 UNREACHABLE(); | 1073 UNREACHABLE(); |
1083 } | 1074 } |
1084 #endif // DEBUG | 1075 #endif // DEBUG |
1085 Node* effect = NodeProperties::GetEffectInput(node); | 1076 Node* effect = NodeProperties::GetEffectInput(node); |
1086 // Break the cycle for effect phis. | 1077 // Break the cycle for effect phis. |
1087 if (effect->opcode() == IrOpcode::kEffectPhi && | 1078 if (effect->opcode() == IrOpcode::kEffectPhi && |
1088 virtual_states_[effect->id()] == nullptr) { | 1079 virtual_states_[effect->id()] == nullptr) { |
1089 VirtualState* state = | 1080 VirtualState* state = |
1090 new (zone()) VirtualState(effect, zone(), AliasCount()); | 1081 new (zone()) VirtualState(effect->id(), zone(), AliasCount()); |
1091 virtual_states_[effect->id()] = state; | 1082 virtual_states_[effect->id()] = state; |
1092 TRACE("Effect Phi #%d got new virtual state %p.\n", effect->id(), | 1083 TRACE("Effect Phi #%d got new virtual state %p.\n", effect->id(), |
1093 static_cast<void*>(virtual_states_[effect->id()])); | 1084 static_cast<void*>(virtual_states_[effect->id()])); |
1094 } | 1085 } |
1095 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 1086 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
1096 if (virtual_states_[node->id()]) { | 1087 if (virtual_states_[node->id()]) { |
1097 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 1088 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
1098 zone()); | 1089 zone()); |
1099 } else { | 1090 } else { |
1100 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 1091 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
1101 TRACE("Forwarding object state %p from %s#%d to %s#%d", | 1092 TRACE("Forwarding object state %p from %s#%d to %s#%d", |
1102 static_cast<void*>(virtual_states_[effect->id()]), | 1093 static_cast<void*>(virtual_states_[effect->id()]), |
1103 effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), | 1094 effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), |
1104 node->id()); | 1095 node->id()); |
1105 if (IsEffectBranchPoint(effect) || | 1096 if (IsEffectBranchPoint(effect) || |
1106 OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { | 1097 OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { |
1107 virtual_states_[node->id()]->SetCopyRequired(); | 1098 virtual_states_[node->id()]->SetCopyRequired(); |
1108 TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), | 1099 TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), |
1109 effect->id()); | 1100 effect->id()); |
1110 } | 1101 } |
1111 TRACE("\n"); | 1102 TRACE("\n"); |
1112 } | 1103 } |
1113 } | 1104 } |
1114 | 1105 |
1115 | 1106 |
1116 void EscapeAnalysis::ProcessStart(Node* node) { | 1107 void EscapeAnalysis::ProcessStart(Node* node) { |
1117 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 1108 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
1118 virtual_states_[node->id()] = | 1109 virtual_states_[node->id()] = |
1119 new (zone()) VirtualState(node, zone(), AliasCount()); | 1110 new (zone()) VirtualState(node->id(), zone(), AliasCount()); |
1120 } | 1111 } |
1121 | 1112 |
1122 | 1113 |
1123 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 1114 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
1124 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 1115 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
1125 bool changed = false; | 1116 bool changed = false; |
1126 | 1117 |
1127 VirtualState* mergeState = virtual_states_[node->id()]; | 1118 VirtualState* mergeState = virtual_states_[node->id()]; |
1128 if (!mergeState) { | 1119 if (!mergeState) { |
1129 mergeState = new (zone()) VirtualState(node, zone(), AliasCount()); | 1120 mergeState = new (zone()) VirtualState(node->id(), zone(), AliasCount()); |
1130 virtual_states_[node->id()] = mergeState; | 1121 virtual_states_[node->id()] = mergeState; |
1131 changed = true; | 1122 changed = true; |
1132 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), | 1123 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), |
1133 static_cast<void*>(mergeState)); | 1124 static_cast<void*>(mergeState)); |
1134 } | 1125 } |
1135 | 1126 |
1136 cache_->Clear(); | 1127 cache_->Clear(); |
1137 | 1128 |
1138 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), | 1129 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), |
1139 static_cast<void*>(mergeState)); | 1130 static_cast<void*>(mergeState)); |
1140 | 1131 |
1141 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1132 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
1142 Node* input = NodeProperties::GetEffectInput(node, i); | 1133 Node* input = NodeProperties::GetEffectInput(node, i); |
1143 VirtualState* state = virtual_states_[input->id()]; | 1134 VirtualState* state = virtual_states_[input->id()]; |
1144 if (state) { | 1135 if (state) { |
1145 cache_->states().push_back(state); | 1136 cache_->states().push_back(state); |
1146 if (state == mergeState) { | 1137 if (state == mergeState) { |
1147 mergeState = new (zone()) VirtualState(node, zone(), AliasCount()); | 1138 mergeState = |
| 1139 new (zone()) VirtualState(node->id(), zone(), AliasCount()); |
1148 virtual_states_[node->id()] = mergeState; | 1140 virtual_states_[node->id()] = mergeState; |
1149 changed = true; | 1141 changed = true; |
1150 } | 1142 } |
1151 } | 1143 } |
1152 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1144 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
1153 input->op()->mnemonic()); | 1145 input->op()->mnemonic()); |
1154 } | 1146 } |
1155 TRACE("\n"); | 1147 TRACE("\n"); |
1156 | 1148 |
1157 if (cache_->states().size() == 0) { | 1149 if (cache_->states().size() == 0) { |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1599 return true; | 1591 return true; |
1600 } | 1592 } |
1601 } | 1593 } |
1602 } | 1594 } |
1603 return false; | 1595 return false; |
1604 } | 1596 } |
1605 | 1597 |
1606 } // namespace compiler | 1598 } // namespace compiler |
1607 } // namespace internal | 1599 } // namespace internal |
1608 } // namespace v8 | 1600 } // namespace v8 |
OLD | NEW |