| 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 |