| 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" |
| 11 #include "src/compilation-dependencies.h" | 11 #include "src/compilation-dependencies.h" |
| 12 #include "src/compiler/common-operator.h" | 12 #include "src/compiler/common-operator.h" |
| 13 #include "src/compiler/graph-reducer.h" | 13 #include "src/compiler/graph-reducer.h" |
| 14 #include "src/compiler/js-operator.h" | 14 #include "src/compiler/js-operator.h" |
| 15 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
| 16 #include "src/compiler/node-matchers.h" | 16 #include "src/compiler/node-matchers.h" |
| 17 #include "src/compiler/node-properties.h" | 17 #include "src/compiler/node-properties.h" |
| 18 #include "src/compiler/operator-properties.h" | 18 #include "src/compiler/operator-properties.h" |
| 19 #include "src/compiler/simplified-operator.h" | 19 #include "src/compiler/simplified-operator.h" |
| 20 #include "src/objects-inl.h" | 20 #include "src/objects-inl.h" |
| 21 #include "src/type-cache.h" | 21 #include "src/type-cache.h" |
| 22 | 22 |
| 23 namespace v8 { | 23 namespace v8 { |
| 24 namespace internal { | 24 namespace internal { |
| 25 namespace compiler { | 25 namespace compiler { |
| 26 | 26 |
| 27 using Alias = EscapeStatusAnalysis::Alias; |
| 28 |
| 27 #ifdef DEBUG | 29 #ifdef DEBUG |
| 28 #define TRACE(...) \ | 30 #define TRACE(...) \ |
| 29 do { \ | 31 do { \ |
| 30 if (FLAG_trace_turbo_escape) PrintF(__VA_ARGS__); \ | 32 if (FLAG_trace_turbo_escape) PrintF(__VA_ARGS__); \ |
| 31 } while (false) | 33 } while (false) |
| 32 #else | 34 #else |
| 33 #define TRACE(...) | 35 #define TRACE(...) |
| 34 #endif | 36 #endif |
| 35 | 37 |
| 36 const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable = | 38 const Alias EscapeStatusAnalysis::kNotReachable = |
| 37 std::numeric_limits<Alias>::max(); | 39 std::numeric_limits<Alias>::max(); |
| 38 const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable = | 40 const Alias EscapeStatusAnalysis::kUntrackable = |
| 39 std::numeric_limits<Alias>::max() - 1; | 41 std::numeric_limits<Alias>::max() - 1; |
| 40 | 42 |
| 41 | 43 |
| 42 class VirtualObject : public ZoneObject { | 44 class VirtualObject : public ZoneObject { |
| 43 public: | 45 public: |
| 44 enum Status { kUntracked = 0, kTracked = 1 }; | 46 enum Status { |
| 45 VirtualObject(NodeId id, Zone* zone) | 47 kInitial = 0, |
| 48 kTracked = 1u << 0, |
| 49 kInitialized = 1u << 1, |
| 50 kCopyRequired = 1u << 2, |
| 51 }; |
| 52 typedef base::Flags<Status, unsigned char> StatusFlags; |
| 53 |
| 54 VirtualObject(NodeId id, VirtualState* owner, Zone* zone) |
| 46 : id_(id), | 55 : id_(id), |
| 47 status_(kUntracked), | 56 status_(kInitial), |
| 48 fields_(zone), | 57 fields_(zone), |
| 49 phi_(zone), | 58 phi_(zone), |
| 50 object_state_(nullptr) {} | 59 object_state_(nullptr), |
| 60 owner_(owner) {} |
| 51 | 61 |
| 52 VirtualObject(const VirtualObject& other) | 62 VirtualObject(VirtualState* owner, const VirtualObject& other) |
| 53 : id_(other.id_), | 63 : id_(other.id_), |
| 54 status_(other.status_), | 64 status_(other.status_ & ~kCopyRequired), |
| 55 fields_(other.fields_), | 65 fields_(other.fields_), |
| 56 phi_(other.phi_), | 66 phi_(other.phi_), |
| 57 object_state_(other.object_state_) {} | 67 object_state_(other.object_state_), |
| 68 owner_(owner) {} |
| 58 | 69 |
| 59 VirtualObject(NodeId id, Zone* zone, size_t field_number) | 70 VirtualObject(NodeId id, VirtualState* owner, Zone* zone, size_t field_number, |
| 71 bool initialized) |
| 60 : id_(id), | 72 : id_(id), |
| 61 status_(kTracked), | 73 status_(kTracked | (initialized ? kInitialized : kInitial)), |
| 62 fields_(zone), | 74 fields_(zone), |
| 63 phi_(zone), | 75 phi_(zone), |
| 64 object_state_(nullptr) { | 76 object_state_(nullptr), |
| 77 owner_(owner) { |
| 65 fields_.resize(field_number); | 78 fields_.resize(field_number); |
| 66 phi_.resize(field_number, false); | 79 phi_.resize(field_number, false); |
| 67 } | 80 } |
| 68 | 81 |
| 69 Node* GetField(size_t offset) { | 82 Node* GetField(size_t offset) { return fields_[offset]; } |
| 70 if (offset < fields_.size()) { | |
| 71 return fields_[offset]; | |
| 72 } | |
| 73 return nullptr; | |
| 74 } | |
| 75 | 83 |
| 76 bool IsCreatedPhi(size_t offset) { | 84 bool IsCreatedPhi(size_t offset) { return phi_[offset]; } |
| 77 if (offset < phi_.size()) { | |
| 78 return phi_[offset]; | |
| 79 } | |
| 80 return false; | |
| 81 } | |
| 82 | 85 |
| 83 bool SetField(size_t offset, Node* node, bool created_phi = false) { | 86 void SetField(size_t offset, Node* node, bool created_phi = false) { |
| 84 bool changed = fields_[offset] != node || phi_[offset] != created_phi; | |
| 85 fields_[offset] = node; | 87 fields_[offset] = node; |
| 86 phi_[offset] = created_phi; | 88 phi_[offset] = created_phi; |
| 87 if (changed && node) { | |
| 88 TRACE("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(), | |
| 89 node->op()->mnemonic()); | |
| 90 } | |
| 91 return changed; | |
| 92 } | 89 } |
| 93 bool IsVirtual() const { return status_ == kTracked; } | 90 bool IsTracked() const { return status_ & kTracked; } |
| 94 bool IsTracked() const { return status_ != kUntracked; } | 91 bool IsInitialized() const { return status_ & kInitialized; } |
| 92 bool SetInitialized() { return status_ |= kInitialized; } |
| 93 VirtualState* owner() const { return owner_; } |
| 95 | 94 |
| 96 Node** fields_array() { return &fields_.front(); } | 95 Node** fields_array() { return &fields_.front(); } |
| 97 size_t field_count() { return fields_.size(); } | 96 size_t field_count() { return fields_.size(); } |
| 98 bool ResizeFields(size_t field_count) { | 97 bool ResizeFields(size_t field_count) { |
| 99 if (field_count != fields_.size()) { | 98 if (field_count != fields_.size()) { |
| 100 fields_.resize(field_count); | 99 fields_.resize(field_count); |
| 101 phi_.resize(field_count); | 100 phi_.resize(field_count); |
| 102 return true; | 101 return true; |
| 103 } | 102 } |
| 104 return false; | 103 return false; |
| 105 } | 104 } |
| 106 bool ClearAllFields() { | 105 void ClearAllFields() { |
| 107 bool changed = false; | 106 for (size_t i = 0; i < fields_.size(); ++i) { |
| 107 fields_[i] = nullptr; |
| 108 phi_[i] = false; |
| 109 } |
| 110 } |
| 111 bool AllFieldsClear() { |
| 108 for (size_t i = 0; i < fields_.size(); ++i) { | 112 for (size_t i = 0; i < fields_.size(); ++i) { |
| 109 if (fields_[i] != nullptr) { | 113 if (fields_[i] != nullptr) { |
| 110 fields_[i] = nullptr; | 114 return false; |
| 111 changed = true; | |
| 112 } | 115 } |
| 113 phi_[i] = false; | |
| 114 } | 116 } |
| 115 return changed; | 117 return true; |
| 116 } | 118 } |
| 117 bool UpdateFrom(const VirtualObject& other); | 119 bool UpdateFrom(const VirtualObject& other); |
| 118 void SetObjectState(Node* node) { object_state_ = node; } | 120 void SetObjectState(Node* node) { object_state_ = node; } |
| 119 Node* GetObjectState() const { return object_state_; } | 121 Node* GetObjectState() const { return object_state_; } |
| 122 bool IsCopyRequired() const { return status_ & kCopyRequired; } |
| 123 void SetCopyRequired() { status_ |= kCopyRequired; } |
| 124 bool NeedCopyForModification() { |
| 125 if (!IsCopyRequired() || !IsInitialized()) { |
| 126 return false; |
| 127 } |
| 128 return true; |
| 129 } |
| 120 | 130 |
| 121 NodeId id() const { return id_; } | 131 NodeId id() const { return id_; } |
| 122 void id(NodeId id) { id_ = id; } | 132 void id(NodeId id) { id_ = id; } |
| 123 | 133 |
| 124 private: | 134 private: |
| 125 NodeId id_; | 135 NodeId id_; |
| 126 Status status_; | 136 StatusFlags status_; |
| 127 ZoneVector<Node*> fields_; | 137 ZoneVector<Node*> fields_; |
| 128 ZoneVector<bool> phi_; | 138 ZoneVector<bool> phi_; |
| 129 Node* object_state_; | 139 Node* object_state_; |
| 140 VirtualState* owner_; |
| 141 |
| 142 DISALLOW_COPY_AND_ASSIGN(VirtualObject); |
| 130 }; | 143 }; |
| 131 | 144 |
| 132 | 145 |
| 146 DEFINE_OPERATORS_FOR_FLAGS(VirtualObject::StatusFlags) |
| 147 |
| 148 |
| 133 bool VirtualObject::UpdateFrom(const VirtualObject& other) { | 149 bool VirtualObject::UpdateFrom(const VirtualObject& other) { |
| 134 bool changed = status_ != other.status_; | 150 bool changed = status_ != other.status_; |
| 135 status_ = other.status_; | 151 status_ = other.status_; |
| 136 phi_ = other.phi_; | 152 phi_ = other.phi_; |
| 137 if (fields_.size() != other.fields_.size()) { | 153 if (fields_.size() != other.fields_.size()) { |
| 138 fields_ = other.fields_; | 154 fields_ = other.fields_; |
| 139 return true; | 155 return true; |
| 140 } | 156 } |
| 141 for (size_t i = 0; i < fields_.size(); ++i) { | 157 for (size_t i = 0; i < fields_.size(); ++i) { |
| 142 if (fields_[i] != other.fields_[i]) { | 158 if (fields_[i] != other.fields_[i]) { |
| 143 changed = true; | 159 changed = true; |
| 144 fields_[i] = other.fields_[i]; | 160 fields_[i] = other.fields_[i]; |
| 145 } | 161 } |
| 146 } | 162 } |
| 147 return changed; | 163 return changed; |
| 148 } | 164 } |
| 149 | 165 |
| 150 | 166 |
| 151 class VirtualState : public ZoneObject { | 167 class VirtualState : public ZoneObject { |
| 152 public: | 168 public: |
| 153 VirtualState(Zone* zone, size_t size); | 169 VirtualState(Node* owner, Zone* zone, size_t size); |
| 154 VirtualState(const VirtualState& states); | 170 VirtualState(Node* owner, const VirtualState& states); |
| 155 | 171 |
| 156 VirtualObject* VirtualObjectFromAlias(size_t alias); | 172 VirtualObject* VirtualObjectFromAlias(size_t alias); |
| 157 VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias, | 173 VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, |
| 158 NodeId id, size_t fields, | 174 size_t fields, |
| 159 Zone* zone); | 175 bool initialized, Zone* zone, |
| 160 void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state); | 176 bool force_copy); |
| 161 void LastChangedAt(Node* node) { last_changed_ = node; } | 177 void SetVirtualObject(Alias alias, VirtualObject* state); |
| 162 Node* GetLastChanged() { return last_changed_; } | |
| 163 bool UpdateFrom(VirtualState* state, Zone* zone); | 178 bool UpdateFrom(VirtualState* state, Zone* zone); |
| 164 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 179 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 165 CommonOperatorBuilder* common, Node* control); | 180 CommonOperatorBuilder* common, Node* control, int arity); |
| 166 size_t size() const { return info_.size(); } | 181 size_t size() const { return info_.size(); } |
| 182 Node* owner() const { return owner_; } |
| 183 VirtualObject* Copy(VirtualObject* obj, Alias alias); |
| 184 void SetCopyRequired() { |
| 185 for (VirtualObject* obj : info_) { |
| 186 if (obj) obj->SetCopyRequired(); |
| 187 } |
| 188 } |
| 167 | 189 |
| 168 private: | 190 private: |
| 169 ZoneVector<VirtualObject*> info_; | 191 ZoneVector<VirtualObject*> info_; |
| 170 Node* last_changed_; | 192 Node* owner_; |
| 193 |
| 194 DISALLOW_COPY_AND_ASSIGN(VirtualState); |
| 171 }; | 195 }; |
| 172 | 196 |
| 173 | 197 |
| 174 class MergeCache : public ZoneObject { | 198 class MergeCache : public ZoneObject { |
| 175 public: | 199 public: |
| 176 explicit MergeCache(Zone* zone) | 200 explicit MergeCache(Zone* zone) |
| 177 : states_(zone), objects_(zone), fields_(zone) { | 201 : states_(zone), objects_(zone), fields_(zone) { |
| 178 states_.reserve(4); | 202 states_.reserve(5); |
| 179 objects_.reserve(4); | 203 objects_.reserve(5); |
| 180 fields_.reserve(4); | 204 fields_.reserve(5); |
| 181 } | 205 } |
| 182 ZoneVector<VirtualState*>& states() { return states_; } | 206 ZoneVector<VirtualState*>& states() { return states_; } |
| 183 ZoneVector<VirtualObject*>& objects() { return objects_; } | 207 ZoneVector<VirtualObject*>& objects() { return objects_; } |
| 184 ZoneVector<Node*>& fields() { return fields_; } | 208 ZoneVector<Node*>& fields() { return fields_; } |
| 185 void Clear() { | 209 void Clear() { |
| 186 states_.clear(); | 210 states_.clear(); |
| 187 objects_.clear(); | 211 objects_.clear(); |
| 188 fields_.clear(); | 212 fields_.clear(); |
| 189 } | 213 } |
| 190 size_t LoadVirtualObjectsFromStatesFor(EscapeAnalysis::Alias alias); | 214 size_t LoadVirtualObjectsFromStatesFor(Alias alias); |
| 191 void LoadVirtualObjectsForFieldsFrom( | 215 void LoadVirtualObjectsForFieldsFrom(VirtualState* state, |
| 192 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases); | 216 const ZoneVector<Alias>& aliases); |
| 193 Node* GetFields(size_t pos); | 217 Node* GetFields(size_t pos); |
| 194 | 218 |
| 195 private: | 219 private: |
| 196 ZoneVector<VirtualState*> states_; | 220 ZoneVector<VirtualState*> states_; |
| 197 ZoneVector<VirtualObject*> objects_; | 221 ZoneVector<VirtualObject*> objects_; |
| 198 ZoneVector<Node*> fields_; | 222 ZoneVector<Node*> fields_; |
| 223 |
| 224 DISALLOW_COPY_AND_ASSIGN(MergeCache); |
| 199 }; | 225 }; |
| 200 | 226 |
| 201 | 227 |
| 202 size_t MergeCache::LoadVirtualObjectsFromStatesFor( | 228 size_t MergeCache::LoadVirtualObjectsFromStatesFor(Alias alias) { |
| 203 EscapeAnalysis::Alias alias) { | |
| 204 objects_.clear(); | 229 objects_.clear(); |
| 205 DCHECK_GT(states_.size(), 0u); | 230 DCHECK_GT(states_.size(), 0u); |
| 206 size_t min = std::numeric_limits<size_t>::max(); | 231 size_t min = std::numeric_limits<size_t>::max(); |
| 207 for (VirtualState* state : states_) { | 232 for (VirtualState* state : states_) { |
| 208 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { | 233 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
| 209 objects_.push_back(obj); | 234 objects_.push_back(obj); |
| 210 min = std::min(obj->field_count(), min); | 235 min = std::min(obj->field_count(), min); |
| 211 } | 236 } |
| 212 } | 237 } |
| 213 return min; | 238 return min; |
| 214 } | 239 } |
| 215 | 240 |
| 216 | 241 |
| 217 void MergeCache::LoadVirtualObjectsForFieldsFrom( | 242 void MergeCache::LoadVirtualObjectsForFieldsFrom( |
| 218 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases) { | 243 VirtualState* state, const ZoneVector<Alias>& aliases) { |
| 219 objects_.clear(); | 244 objects_.clear(); |
| 220 size_t max_alias = state->size(); | 245 size_t max_alias = state->size(); |
| 221 for (Node* field : fields_) { | 246 for (Node* field : fields_) { |
| 222 EscapeAnalysis::Alias alias = aliases[field->id()]; | 247 Alias alias = aliases[field->id()]; |
| 223 if (alias >= max_alias) continue; | 248 if (alias >= max_alias) continue; |
| 224 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { | 249 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
| 225 objects_.push_back(obj); | 250 objects_.push_back(obj); |
| 226 } | 251 } |
| 227 } | 252 } |
| 228 } | 253 } |
| 229 | 254 |
| 230 | 255 |
| 231 Node* MergeCache::GetFields(size_t pos) { | 256 Node* MergeCache::GetFields(size_t pos) { |
| 232 fields_.clear(); | 257 fields_.clear(); |
| 233 Node* rep = objects_.front()->GetField(pos); | 258 Node* rep = pos >= objects_.front()->field_count() |
| 259 ? nullptr |
| 260 : objects_.front()->GetField(pos); |
| 234 for (VirtualObject* obj : objects_) { | 261 for (VirtualObject* obj : objects_) { |
| 262 if (pos >= obj->field_count()) continue; |
| 235 Node* field = obj->GetField(pos); | 263 Node* field = obj->GetField(pos); |
| 236 if (field) { | 264 if (field) { |
| 237 fields_.push_back(field); | 265 fields_.push_back(field); |
| 238 } | 266 } |
| 239 if (field != rep) { | 267 if (field != rep) { |
| 240 rep = nullptr; | 268 rep = nullptr; |
| 241 } | 269 } |
| 242 } | 270 } |
| 243 return rep; | 271 return rep; |
| 244 } | 272 } |
| 245 | 273 |
| 246 | 274 |
| 247 VirtualState::VirtualState(Zone* zone, size_t size) | 275 VirtualState::VirtualState(Node* owner, Zone* zone, size_t size) |
| 248 : info_(size, nullptr, zone), last_changed_(nullptr) {} | 276 : info_(size, nullptr, zone), owner_(owner) {} |
| 249 | 277 |
| 250 | 278 |
| 251 VirtualState::VirtualState(const VirtualState& state) | 279 VirtualState::VirtualState(Node* owner, const VirtualState& state) |
| 252 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), | 280 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
| 253 last_changed_(state.last_changed_) { | 281 owner_(owner) { |
| 254 for (size_t i = 0; i < state.info_.size(); ++i) { | 282 for (size_t i = 0; i < info_.size(); ++i) { |
| 255 if (state.info_[i]) { | 283 if (state.info_[i]) { |
| 256 info_[i] = | 284 info_[i] = state.info_[i]; |
| 257 new (info_.get_allocator().zone()) VirtualObject(*state.info_[i]); | |
| 258 } | 285 } |
| 259 } | 286 } |
| 260 } | 287 } |
| 261 | 288 |
| 262 | 289 |
| 290 VirtualObject* VirtualState::Copy(VirtualObject* obj, Alias alias) { |
| 291 if (obj->owner() == this) return obj; |
| 292 VirtualObject* new_obj = |
| 293 new (info_.get_allocator().zone()) VirtualObject(this, *obj); |
| 294 TRACE("At state %p, alias @%d (#%d), copying virtual object from %p to %p\n", |
| 295 static_cast<void*>(this), alias, obj->id(), static_cast<void*>(obj), |
| 296 static_cast<void*>(new_obj)); |
| 297 info_[alias] = new_obj; |
| 298 return new_obj; |
| 299 } |
| 300 |
| 301 |
| 263 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { | 302 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
| 264 return info_[alias]; | 303 return info_[alias]; |
| 265 } | 304 } |
| 266 | 305 |
| 267 | 306 |
| 268 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( | 307 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
| 269 EscapeAnalysis::Alias alias, NodeId id, size_t field_number, Zone* zone) { | 308 Alias alias, NodeId id, size_t field_number, bool initialized, Zone* zone, |
| 270 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { | 309 bool force_copy) { |
| 271 return obj; | 310 if (!force_copy) { |
| 311 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
| 312 return obj; |
| 313 } |
| 272 } | 314 } |
| 273 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); | 315 VirtualObject* obj = new (zone) VirtualObject(id, this, zone, 0, initialized); |
| 274 SetVirtualObject(alias, obj); | 316 SetVirtualObject(alias, obj); |
| 275 return obj; | 317 return obj; |
| 276 } | 318 } |
| 277 | 319 |
| 278 | 320 |
| 279 void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias, | 321 void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { |
| 280 VirtualObject* obj) { | |
| 281 info_[alias] = obj; | 322 info_[alias] = obj; |
| 282 } | 323 } |
| 283 | 324 |
| 284 | 325 |
| 285 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { | 326 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { |
| 327 if (from == this) return false; |
| 286 bool changed = false; | 328 bool changed = false; |
| 287 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { | 329 for (Alias alias = 0; alias < size(); ++alias) { |
| 288 VirtualObject* ls = VirtualObjectFromAlias(alias); | 330 VirtualObject* ls = VirtualObjectFromAlias(alias); |
| 289 VirtualObject* rs = from->VirtualObjectFromAlias(alias); | 331 VirtualObject* rs = from->VirtualObjectFromAlias(alias); |
| 290 | 332 |
| 291 if (rs == nullptr) { | 333 if (ls == rs || rs == nullptr) continue; |
| 292 continue; | |
| 293 } | |
| 294 | 334 |
| 295 if (ls == nullptr) { | 335 if (ls == nullptr) { |
| 296 ls = new (zone) VirtualObject(*rs); | 336 ls = new (zone) VirtualObject(this, *rs); |
| 297 SetVirtualObject(alias, ls); | 337 SetVirtualObject(alias, ls); |
| 298 changed = true; | 338 changed = true; |
| 299 continue; | 339 continue; |
| 300 } | 340 } |
| 301 | 341 |
| 302 TRACE(" Updating fields of @%d\n", alias); | 342 TRACE(" Updating fields of @%d\n", alias); |
| 303 | 343 |
| 304 changed = ls->UpdateFrom(*rs) || changed; | 344 changed = ls->UpdateFrom(*rs) || changed; |
| 305 } | 345 } |
| 306 return false; | 346 return false; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 for (VirtualObject* obj : objs) { | 388 for (VirtualObject* obj : objs) { |
| 349 if (GetReplacement(obj->id()) != rep) { | 389 if (GetReplacement(obj->id()) != rep) { |
| 350 return nullptr; | 390 return nullptr; |
| 351 } | 391 } |
| 352 } | 392 } |
| 353 return rep; | 393 return rep; |
| 354 } | 394 } |
| 355 | 395 |
| 356 | 396 |
| 357 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 397 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 358 CommonOperatorBuilder* common, Node* control) { | 398 CommonOperatorBuilder* common, Node* control, |
| 399 int arity) { |
| 359 DCHECK_GT(cache->states().size(), 0u); | 400 DCHECK_GT(cache->states().size(), 0u); |
| 360 bool changed = false; | 401 bool changed = false; |
| 361 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { | 402 for (Alias alias = 0; alias < size(); ++alias) { |
| 362 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); | 403 cache->objects().clear(); |
| 404 VirtualObject* mergeObject = VirtualObjectFromAlias(alias); |
| 405 bool copy_merge_object = false; |
| 406 size_t fields = std::numeric_limits<size_t>::max(); |
| 407 for (VirtualState* state : cache->states()) { |
| 408 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
| 409 cache->objects().push_back(obj); |
| 410 if (mergeObject == obj) { |
| 411 copy_merge_object = true; |
| 412 changed = true; |
| 413 } |
| 414 fields = std::min(obj->field_count(), fields); |
| 415 } |
| 416 } |
| 363 if (cache->objects().size() == cache->states().size()) { | 417 if (cache->objects().size() == cache->states().size()) { |
| 364 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( | 418 mergeObject = GetOrCreateTrackedVirtualObject( |
| 365 alias, cache->objects().front()->id(), fields, zone); | 419 alias, cache->objects().front()->id(), |
| 420 cache->objects().front()->IsInitialized(), fields, zone, |
| 421 copy_merge_object); |
| 366 #ifdef DEBUG | 422 #ifdef DEBUG |
| 367 if (FLAG_trace_turbo_escape) { | 423 if (FLAG_trace_turbo_escape) { |
| 368 PrintF(" Alias @%d, merging into %p virtual objects", alias, | 424 PrintF(" Alias @%d, merging into %p virtual objects", alias, |
| 369 static_cast<void*>(mergeObject)); | 425 static_cast<void*>(mergeObject)); |
| 370 for (size_t i = 0; i < cache->objects().size(); i++) { | 426 for (size_t i = 0; i < cache->objects().size(); i++) { |
| 371 PrintF(" %p", static_cast<void*>(cache->objects()[i])); | 427 PrintF(" %p", static_cast<void*>(cache->objects()[i])); |
| 372 } | 428 } |
| 373 PrintF("\n"); | 429 PrintF("\n"); |
| 374 } | 430 } |
| 375 #endif // DEBUG | 431 #endif // DEBUG |
| 376 changed = mergeObject->ResizeFields(fields) || changed; | 432 changed = mergeObject->ResizeFields(fields) || changed; |
| 377 for (size_t i = 0; i < fields; ++i) { | 433 for (size_t i = 0; i < fields; ++i) { |
| 378 if (Node* field = cache->GetFields(i)) { | 434 if (Node* field = cache->GetFields(i)) { |
| 379 changed = mergeObject->SetField(i, field) || changed; | 435 changed = changed || mergeObject->GetField(i) != field; |
| 436 mergeObject->SetField(i, field); |
| 380 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); | 437 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); |
| 381 } else { | 438 } else { |
| 382 int value_input_count = static_cast<int>(cache->fields().size()); | 439 int value_input_count = static_cast<int>(cache->fields().size()); |
| 383 if (cache->fields().size() == cache->objects().size()) { | 440 if (cache->fields().size() == arity) { |
| 384 Node* rep = mergeObject->GetField(i); | 441 Node* rep = mergeObject->GetField(i); |
| 385 if (!rep || !mergeObject->IsCreatedPhi(i)) { | 442 if (!rep || !mergeObject->IsCreatedPhi(i)) { |
| 386 cache->fields().push_back(control); | 443 cache->fields().push_back(control); |
| 387 Node* phi = graph->NewNode( | 444 Node* phi = graph->NewNode( |
| 388 common->Phi(MachineRepresentation::kTagged, | 445 common->Phi(MachineRepresentation::kTagged, |
| 389 value_input_count), | 446 value_input_count), |
| 390 value_input_count + 1, &cache->fields().front()); | 447 value_input_count + 1, &cache->fields().front()); |
| 391 mergeObject->SetField(i, phi, true); | 448 mergeObject->SetField(i, phi, true); |
| 392 #ifdef DEBUG | 449 #ifdef DEBUG |
| 393 if (FLAG_trace_turbo_escape) { | 450 if (FLAG_trace_turbo_escape) { |
| 394 PrintF(" Creating Phi #%d as merge of", phi->id()); | 451 PrintF(" Creating Phi #%d as merge of", phi->id()); |
| 395 for (int i = 0; i < value_input_count; i++) { | 452 for (int i = 0; i < value_input_count; i++) { |
| 396 PrintF(" #%d (%s)", cache->fields()[i]->id(), | 453 PrintF(" #%d (%s)", cache->fields()[i]->id(), |
| 397 cache->fields()[i]->op()->mnemonic()); | 454 cache->fields()[i]->op()->mnemonic()); |
| 398 } | 455 } |
| 399 PrintF("\n"); | 456 PrintF("\n"); |
| 400 } | 457 } |
| 401 #endif // DEBUG | 458 #endif // DEBUG |
| 402 changed = true; | 459 changed = true; |
| 403 } else { | 460 } else { |
| 404 DCHECK(rep->opcode() == IrOpcode::kPhi); | 461 DCHECK(rep->opcode() == IrOpcode::kPhi); |
| 405 for (int n = 0; n < value_input_count; ++n) { | 462 for (int n = 0; n < value_input_count; ++n) { |
| 406 if (n < rep->op()->ValueInputCount()) { | 463 Node* old = NodeProperties::GetValueInput(rep, n); |
| 407 Node* old = NodeProperties::GetValueInput(rep, n); | 464 if (old != cache->fields()[n]) { |
| 408 if (old != cache->fields()[n]) { | |
| 409 changed = true; | |
| 410 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], | |
| 411 n); | |
| 412 } | |
| 413 } else { | |
| 414 changed = true; | 465 changed = true; |
| 415 rep->InsertInput(graph->zone(), n, cache->fields()[n]); | 466 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); |
| 416 } | 467 } |
| 417 } | 468 } |
| 418 if (rep->op()->ValueInputCount() != value_input_count) { | |
| 419 TRACE(" Widening Phi #%d of arity %d to %d\n", rep->id(), | |
| 420 rep->op()->ValueInputCount(), value_input_count); | |
| 421 NodeProperties::ChangeOp( | |
| 422 rep, common->Phi(MachineRepresentation::kTagged, | |
| 423 value_input_count)); | |
| 424 } | |
| 425 } | 469 } |
| 426 } else { | 470 } else { |
| 427 if (mergeObject->GetField(i) != nullptr) { | 471 if (mergeObject->GetField(i) != nullptr) { |
| 428 TRACE(" Field %zu cleared\n", i); | 472 TRACE(" Field %zu cleared\n", i); |
| 429 changed = true; | 473 changed = true; |
| 430 } | 474 } |
| 431 changed = mergeObject->SetField(i, nullptr) || changed; | 475 mergeObject->SetField(i, nullptr); |
| 432 } | 476 } |
| 433 } | 477 } |
| 434 } | 478 } |
| 435 } else { | 479 } else { |
| 480 if (mergeObject) { |
| 481 TRACE(" Alias %d, virtual object removed\n", alias); |
| 482 changed = true; |
| 483 } |
| 436 SetVirtualObject(alias, nullptr); | 484 SetVirtualObject(alias, nullptr); |
| 437 } | 485 } |
| 438 } | 486 } |
| 439 return changed; | 487 return changed; |
| 440 } | 488 } |
| 441 | 489 |
| 442 | 490 |
| 443 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 491 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
| 444 Graph* graph, Zone* zone) | 492 Graph* graph, Zone* zone) |
| 445 : object_analysis_(object_analysis), | 493 : stack_(zone), |
| 494 object_analysis_(object_analysis), |
| 446 graph_(graph), | 495 graph_(graph), |
| 447 zone_(zone), | 496 zone_(zone), |
| 448 status_(graph->NodeCount(), kUnknown, zone), | 497 status_(graph->NodeCount(), kUnknown, zone), |
| 449 queue_(zone) {} | 498 next_free_alias_(0), |
| 499 status_stack_(zone), |
| 500 aliases_(zone) {} |
| 450 | 501 |
| 451 | 502 |
| 452 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 503 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
| 453 | 504 |
| 454 | 505 |
| 455 bool EscapeStatusAnalysis::HasEntry(Node* node) { | 506 bool EscapeStatusAnalysis::HasEntry(Node* node) { |
| 456 return status_[node->id()] & (kTracked | kEscaped); | 507 return status_[node->id()] & (kTracked | kEscaped); |
| 457 } | 508 } |
| 458 | 509 |
| 459 | 510 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 478 } | 529 } |
| 479 | 530 |
| 480 | 531 |
| 481 bool EscapeStatusAnalysis::SetEscaped(Node* node) { | 532 bool EscapeStatusAnalysis::SetEscaped(Node* node) { |
| 482 bool changed = !(status_[node->id()] & kEscaped); | 533 bool changed = !(status_[node->id()] & kEscaped); |
| 483 status_[node->id()] |= kEscaped | kTracked; | 534 status_[node->id()] |= kEscaped | kTracked; |
| 484 return changed; | 535 return changed; |
| 485 } | 536 } |
| 486 | 537 |
| 487 | 538 |
| 488 void EscapeStatusAnalysis::Resize() { | 539 void EscapeStatusAnalysis::ResizeStatusVector() { |
| 489 status_.resize(graph()->NodeCount(), kUnknown); | 540 if (status_.size() <= graph()->NodeCount()) { |
| 541 status_.resize(graph()->NodeCount() * 1.1, kUnknown); |
| 542 } |
| 490 } | 543 } |
| 491 | 544 |
| 492 | 545 |
| 493 size_t EscapeStatusAnalysis::size() { return status_.size(); } | 546 size_t EscapeStatusAnalysis::GetStatusVectorSize() { return status_.size(); } |
| 494 | 547 |
| 495 | 548 |
| 496 void EscapeStatusAnalysis::Run() { | 549 void EscapeStatusAnalysis::RunStatusAnalysis() { |
| 497 Resize(); | 550 ResizeStatusVector(); |
| 498 queue_.push_back(graph()->end()); | 551 while (!status_stack_.empty()) { |
| 499 status_[graph()->end()->id()] |= kOnStack; | 552 Node* node = status_stack_.back(); |
| 500 while (!queue_.empty()) { | 553 status_stack_.pop_back(); |
| 501 Node* node = queue_.front(); | |
| 502 queue_.pop_front(); | |
| 503 status_[node->id()] &= ~kOnStack; | 554 status_[node->id()] &= ~kOnStack; |
| 504 Process(node); | 555 Process(node); |
| 505 status_[node->id()] |= kVisited; | 556 status_[node->id()] |= kVisited; |
| 506 for (Edge edge : node->input_edges()) { | |
| 507 Node* input = edge.to(); | |
| 508 if (!(status_[input->id()] & (kVisited | kOnStack))) { | |
| 509 queue_.push_back(input); | |
| 510 status_[input->id()] |= kOnStack; | |
| 511 } | |
| 512 } | |
| 513 } | 557 } |
| 514 } | 558 } |
| 515 | 559 |
| 560 |
| 561 void EscapeStatusAnalysis::EnqueueForStatusAnalysis(Node* node) { |
| 562 DCHECK_NOT_NULL(node); |
| 563 if (!(status_[node->id()] & kOnStack)) { |
| 564 status_stack_.push_back(node); |
| 565 status_[node->id()] |= kOnStack; |
| 566 } |
| 567 } |
| 568 |
| 516 | 569 |
| 517 void EscapeStatusAnalysis::RevisitInputs(Node* node) { | 570 void EscapeStatusAnalysis::RevisitInputs(Node* node) { |
| 518 for (Edge edge : node->input_edges()) { | 571 for (Edge edge : node->input_edges()) { |
| 519 Node* input = edge.to(); | 572 Node* input = edge.to(); |
| 520 if (!(status_[input->id()] & kOnStack)) { | 573 if (!(status_[input->id()] & kOnStack)) { |
| 521 queue_.push_back(input); | 574 status_stack_.push_back(input); |
| 522 status_[input->id()] |= kOnStack; | 575 status_[input->id()] |= kOnStack; |
| 523 } | 576 } |
| 524 } | 577 } |
| 525 } | 578 } |
| 526 | 579 |
| 527 | 580 |
| 528 void EscapeStatusAnalysis::RevisitUses(Node* node) { | 581 void EscapeStatusAnalysis::RevisitUses(Node* node) { |
| 529 for (Edge edge : node->use_edges()) { | 582 for (Edge edge : node->use_edges()) { |
| 530 Node* use = edge.from(); | 583 Node* use = edge.from(); |
| 531 if (!(status_[use->id()] & kOnStack)) { | 584 if (!(status_[use->id()] & kOnStack) && !IsNotReachable(use)) { |
| 532 queue_.push_back(use); | 585 status_stack_.push_back(use); |
| 533 status_[use->id()] |= kOnStack; | 586 status_[use->id()] |= kOnStack; |
| 534 } | 587 } |
| 535 } | 588 } |
| 536 } | 589 } |
| 537 | 590 |
| 538 | 591 |
| 539 void EscapeStatusAnalysis::Process(Node* node) { | 592 void EscapeStatusAnalysis::Process(Node* node) { |
| 540 switch (node->opcode()) { | 593 switch (node->opcode()) { |
| 541 case IrOpcode::kAllocate: | 594 case IrOpcode::kAllocate: |
| 542 ProcessAllocate(node); | 595 ProcessAllocate(node); |
| 543 break; | 596 break; |
| 544 case IrOpcode::kFinishRegion: | 597 case IrOpcode::kFinishRegion: |
| 545 ProcessFinishRegion(node); | 598 ProcessFinishRegion(node); |
| 546 break; | 599 break; |
| 547 case IrOpcode::kStoreField: | 600 case IrOpcode::kStoreField: |
| 548 ProcessStoreField(node); | 601 ProcessStoreField(node); |
| 549 break; | 602 break; |
| 550 case IrOpcode::kStoreElement: | 603 case IrOpcode::kStoreElement: |
| 551 ProcessStoreElement(node); | 604 ProcessStoreElement(node); |
| 552 break; | 605 break; |
| 553 case IrOpcode::kLoadField: | 606 case IrOpcode::kLoadField: |
| 554 case IrOpcode::kLoadElement: { | 607 case IrOpcode::kLoadElement: { |
| 555 if (Node* rep = object_analysis_->GetReplacement(node)) { | 608 if (Node* rep = object_analysis_->GetReplacement(node)) { |
| 556 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { | 609 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { |
| 557 RevisitInputs(rep); | 610 RevisitInputs(rep); |
| 558 RevisitUses(rep); | 611 RevisitUses(rep); |
| 559 } | 612 } |
| 560 } | 613 } |
| 614 RevisitUses(node); |
| 561 break; | 615 break; |
| 562 } | 616 } |
| 563 case IrOpcode::kPhi: | 617 case IrOpcode::kPhi: |
| 564 if (!HasEntry(node)) { | 618 if (!HasEntry(node)) { |
| 565 status_[node->id()] |= kTracked; | 619 status_[node->id()] |= kTracked; |
| 566 if (!IsAllocationPhi(node)) { | 620 RevisitUses(node); |
| 567 SetEscaped(node); | 621 } |
| 568 RevisitUses(node); | 622 if (!IsAllocationPhi(node) && SetEscaped(node)) { |
| 569 } | 623 RevisitInputs(node); |
| 624 RevisitUses(node); |
| 570 } | 625 } |
| 571 CheckUsesForEscape(node); | 626 CheckUsesForEscape(node); |
| 572 default: | 627 default: |
| 573 break; | 628 break; |
| 574 } | 629 } |
| 575 } | 630 } |
| 576 | 631 |
| 577 | 632 |
| 578 bool EscapeStatusAnalysis::IsAllocationPhi(Node* node) { | 633 bool EscapeStatusAnalysis::IsAllocationPhi(Node* node) { |
| 579 for (Edge edge : node->input_edges()) { | 634 for (Edge edge : node->input_edges()) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 671 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 617 if (!HasEntry(node)) { | 672 if (!HasEntry(node)) { |
| 618 status_[node->id()] |= kTracked; | 673 status_[node->id()] |= kTracked; |
| 619 TRACE("Created status entry for node #%d (%s)\n", node->id(), | 674 TRACE("Created status entry for node #%d (%s)\n", node->id(), |
| 620 node->op()->mnemonic()); | 675 node->op()->mnemonic()); |
| 621 NumberMatcher size(node->InputAt(0)); | 676 NumberMatcher size(node->InputAt(0)); |
| 622 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 677 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 623 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 678 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 624 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 679 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 625 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 680 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 681 RevisitUses(node); |
| 626 if (!size.HasValue() && SetEscaped(node)) { | 682 if (!size.HasValue() && SetEscaped(node)) { |
| 627 RevisitUses(node); | |
| 628 TRACE("Setting #%d to escaped because of non-const alloc\n", node->id()); | 683 TRACE("Setting #%d to escaped because of non-const alloc\n", node->id()); |
| 629 // This node is known to escape, uses do not have to be checked. | 684 // This node is already known to escape, uses do not have to be checked |
| 685 // for escape. |
| 630 return; | 686 return; |
| 631 } | 687 } |
| 632 } | 688 } |
| 633 if (CheckUsesForEscape(node, true)) { | 689 if (CheckUsesForEscape(node, true)) { |
| 634 RevisitUses(node); | 690 RevisitUses(node); |
| 635 } | 691 } |
| 636 } | 692 } |
| 637 | 693 |
| 638 | 694 |
| 639 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, | 695 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
| 640 bool phi_escaping) { | 696 bool phi_escaping) { |
| 641 for (Edge edge : uses->use_edges()) { | 697 for (Edge edge : uses->use_edges()) { |
| 642 Node* use = edge.from(); | 698 Node* use = edge.from(); |
| 699 if (IsNotReachable(use)) continue; |
| 643 if (edge.index() >= use->op()->ValueInputCount() + | 700 if (edge.index() >= use->op()->ValueInputCount() + |
| 644 OperatorProperties::GetContextInputCount(use->op())) | 701 OperatorProperties::GetContextInputCount(use->op())) |
| 645 continue; | 702 continue; |
| 646 switch (use->opcode()) { | 703 switch (use->opcode()) { |
| 647 case IrOpcode::kPhi: | 704 case IrOpcode::kPhi: |
| 648 if (phi_escaping && SetEscaped(rep)) { | 705 if (phi_escaping && SetEscaped(rep)) { |
| 649 TRACE( | 706 TRACE( |
| 650 "Setting #%d (%s) to escaped because of use by phi node " | 707 "Setting #%d (%s) to escaped because of use by phi node " |
| 651 "#%d (%s)\n", | 708 "#%d (%s)\n", |
| 652 rep->id(), rep->op()->mnemonic(), use->id(), | 709 rep->id(), rep->op()->mnemonic(), use->id(), |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 if (status_[id] & kTracked) { | 780 if (status_[id] & kTracked) { |
| 724 PrintF("Node #%d is %s\n", id, | 781 PrintF("Node #%d is %s\n", id, |
| 725 (status_[id] & kEscaped) ? "escaping" : "virtual"); | 782 (status_[id] & kEscaped) ? "escaping" : "virtual"); |
| 726 } | 783 } |
| 727 } | 784 } |
| 728 } | 785 } |
| 729 | 786 |
| 730 | 787 |
| 731 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 788 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
| 732 Zone* zone) | 789 Zone* zone) |
| 733 : graph_(graph), | 790 : status_analysis_(this, graph, zone), |
| 734 common_(common), | 791 common_(common), |
| 735 zone_(zone), | |
| 736 virtual_states_(zone), | 792 virtual_states_(zone), |
| 737 replacements_(zone), | 793 replacements_(zone), |
| 738 escape_status_(this, graph, zone), | 794 cache_(new (zone) MergeCache(zone)) {} |
| 739 cache_(new (zone) MergeCache(zone)), | |
| 740 aliases_(zone), | |
| 741 next_free_alias_(0) {} | |
| 742 | 795 |
| 743 | 796 |
| 744 EscapeAnalysis::~EscapeAnalysis() {} | 797 EscapeAnalysis::~EscapeAnalysis() {} |
| 745 | 798 |
| 746 | 799 |
| 747 void EscapeAnalysis::Run() { | 800 void EscapeAnalysis::Run() { |
| 748 replacements_.resize(graph()->NodeCount()); | 801 replacements_.resize(graph()->NodeCount()); |
| 749 AssignAliases(); | 802 status_analysis_.AssignAliases(); |
| 750 if (AliasCount() == 0) return; | 803 if (status_analysis_.AliasCount() == 0) return; |
| 751 escape_status_.Resize(); | 804 status_analysis_.ResizeStatusVector(); |
| 752 RunObjectAnalysis(); | 805 RunObjectAnalysis(); |
| 753 escape_status_.Run(); | 806 status_analysis_.RunStatusAnalysis(); |
| 754 } | 807 } |
| 755 | 808 |
| 756 | 809 |
| 757 void EscapeAnalysis::AssignAliases() { | 810 void EscapeStatusAnalysis::AssignAliases() { |
| 758 ZoneVector<Node*> stack(zone()); | 811 stack_.reserve(graph()->NodeCount() * 0.2); |
| 759 stack.push_back(graph()->end()); | 812 ResizeStatusVector(); |
| 813 stack_.push_back(graph()->end()); |
| 760 CHECK_LT(graph()->NodeCount(), kUntrackable); | 814 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 761 aliases_.resize(graph()->NodeCount(), kNotReachable); | 815 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| 762 aliases_[graph()->end()->id()] = kUntrackable; | 816 aliases_[graph()->end()->id()] = kUntrackable; |
| 817 status_stack_.reserve(8); |
| 763 TRACE("Discovering trackable nodes"); | 818 TRACE("Discovering trackable nodes"); |
| 764 while (!stack.empty()) { | 819 while (!stack_.empty()) { |
| 765 Node* node = stack.back(); | 820 Node* node = stack_.back(); |
| 766 stack.pop_back(); | 821 stack_.pop_back(); |
| 767 switch (node->opcode()) { | 822 switch (node->opcode()) { |
| 768 case IrOpcode::kAllocate: | 823 case IrOpcode::kAllocate: |
| 769 if (aliases_[node->id()] >= kUntrackable) { | 824 if (aliases_[node->id()] >= kUntrackable) { |
| 770 aliases_[node->id()] = NextAlias(); | 825 aliases_[node->id()] = NextAlias(); |
| 771 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), | 826 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), |
| 772 node->id()); | 827 node->id()); |
| 828 EnqueueForStatusAnalysis(node); |
| 773 } | 829 } |
| 774 break; | 830 break; |
| 775 case IrOpcode::kFinishRegion: { | 831 case IrOpcode::kFinishRegion: { |
| 776 Node* allocate = NodeProperties::GetValueInput(node, 0); | 832 Node* allocate = NodeProperties::GetValueInput(node, 0); |
| 833 DCHECK_NOT_NULL(allocate); |
| 777 if (allocate->opcode() == IrOpcode::kAllocate) { | 834 if (allocate->opcode() == IrOpcode::kAllocate) { |
| 778 if (aliases_[allocate->id()] >= kUntrackable) { | 835 if (aliases_[allocate->id()] >= kUntrackable) { |
| 779 if (aliases_[allocate->id()] == kNotReachable) { | 836 if (aliases_[allocate->id()] == kNotReachable) { |
| 780 stack.push_back(allocate); | 837 stack_.push_back(allocate); |
| 781 } | 838 } |
| 782 aliases_[allocate->id()] = NextAlias(); | 839 aliases_[allocate->id()] = NextAlias(); |
| 783 TRACE(" @%d:%s#%u", aliases_[allocate->id()], | 840 TRACE(" @%d:%s#%u", aliases_[allocate->id()], |
| 784 allocate->op()->mnemonic(), allocate->id()); | 841 allocate->op()->mnemonic(), allocate->id()); |
| 842 EnqueueForStatusAnalysis(allocate); |
| 785 } | 843 } |
| 786 aliases_[node->id()] = aliases_[allocate->id()]; | 844 aliases_[node->id()] = aliases_[allocate->id()]; |
| 787 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), | 845 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), |
| 788 node->id()); | 846 node->id()); |
| 789 | 847 |
| 790 } else { | 848 } else { |
| 791 aliases_[node->id()] = NextAlias(); | 849 aliases_[node->id()] = NextAlias(); |
| 792 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), | 850 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), |
| 793 node->id()); | 851 node->id()); |
| 794 } | 852 } |
| 795 break; | 853 break; |
| 796 } | 854 } |
| 797 default: | 855 default: |
| 798 DCHECK_EQ(aliases_[node->id()], kUntrackable); | 856 DCHECK_EQ(aliases_[node->id()], kUntrackable); |
| 799 break; | 857 break; |
| 800 } | 858 } |
| 801 for (Edge edge : node->input_edges()) { | 859 for (Edge edge : node->input_edges()) { |
| 802 Node* input = edge.to(); | 860 Node* input = edge.to(); |
| 803 if (aliases_[input->id()] == kNotReachable) { | 861 if (aliases_[input->id()] == kNotReachable) { |
| 804 stack.push_back(input); | 862 stack_.push_back(input); |
| 805 aliases_[input->id()] = kUntrackable; | 863 aliases_[input->id()] = kUntrackable; |
| 806 } | 864 } |
| 807 } | 865 } |
| 808 } | 866 } |
| 809 TRACE("\n"); | 867 TRACE("\n"); |
| 810 } | 868 } |
| 811 | 869 |
| 812 | 870 |
| 871 bool EscapeStatusAnalysis::IsNotReachable(Node* node) { |
| 872 if (node->id() >= aliases_.size()) { |
| 873 return false; |
| 874 } |
| 875 return aliases_[node->id()] == kNotReachable; |
| 876 } |
| 877 |
| 878 |
| 813 void EscapeAnalysis::RunObjectAnalysis() { | 879 void EscapeAnalysis::RunObjectAnalysis() { |
| 814 virtual_states_.resize(graph()->NodeCount()); | 880 virtual_states_.resize(graph()->NodeCount()); |
| 815 ZoneVector<Node*> stack(zone()); | 881 stack().push_back(graph()->start()); |
| 816 stack.push_back(graph()->start()); | 882 while (!stack().empty()) { |
| 817 while (!stack.empty()) { | 883 Node* node = stack().back(); |
| 818 Node* node = stack.back(); | 884 stack().pop_back(); |
| 819 stack.pop_back(); | 885 if (Process(node)) { |
| 820 if (aliases_[node->id()] != kNotReachable && Process(node)) { | |
| 821 for (Edge edge : node->use_edges()) { | 886 for (Edge edge : node->use_edges()) { |
| 887 Node* use = edge.from(); |
| 888 if (IsNotReachable(use)) { |
| 889 continue; |
| 890 } |
| 822 if (NodeProperties::IsEffectEdge(edge)) { | 891 if (NodeProperties::IsEffectEdge(edge)) { |
| 823 Node* use = edge.from(); | |
| 824 if ((use->opcode() != IrOpcode::kLoadField && | 892 if ((use->opcode() != IrOpcode::kLoadField && |
| 825 use->opcode() != IrOpcode::kLoadElement) || | 893 use->opcode() != IrOpcode::kLoadElement) || |
| 826 !IsDanglingEffectNode(use)) { | 894 !IsDanglingEffectNode(use)) { |
| 827 stack.push_back(use); | 895 stack().push_back(use); |
| 828 } | 896 } |
| 829 } | 897 } |
| 830 } | 898 } |
| 831 // First process loads: dangling loads are a problem otherwise. | 899 // First process loads: dangling loads are a problem otherwise. |
| 832 for (Edge edge : node->use_edges()) { | 900 for (Edge edge : node->use_edges()) { |
| 901 Node* use = edge.from(); |
| 902 if (IsNotReachable(use)) { |
| 903 continue; |
| 904 } |
| 833 if (NodeProperties::IsEffectEdge(edge)) { | 905 if (NodeProperties::IsEffectEdge(edge)) { |
| 834 Node* use = edge.from(); | |
| 835 if ((use->opcode() == IrOpcode::kLoadField || | 906 if ((use->opcode() == IrOpcode::kLoadField || |
| 836 use->opcode() == IrOpcode::kLoadElement) && | 907 use->opcode() == IrOpcode::kLoadElement) && |
| 837 IsDanglingEffectNode(use)) { | 908 IsDanglingEffectNode(use)) { |
| 838 stack.push_back(use); | 909 stack().push_back(use); |
| 839 } | 910 } |
| 840 } | 911 } |
| 841 } | 912 } |
| 842 } | 913 } |
| 843 } | 914 } |
| 844 #ifdef DEBUG | 915 #ifdef DEBUG |
| 845 if (FLAG_trace_turbo_escape) { | 916 if (FLAG_trace_turbo_escape) { |
| 846 DebugPrint(); | 917 DebugPrint(); |
| 847 } | 918 } |
| 848 #endif | 919 #endif |
| 849 } | 920 } |
| 850 | 921 |
| 851 | 922 |
| 852 bool EscapeAnalysis::IsDanglingEffectNode(Node* node) { | 923 bool EscapeStatusAnalysis::IsDanglingEffectNode(Node* node) { |
| 924 if (status_[node->id()] & kDanglingComputed) { |
| 925 return status_[node->id()] & kDangling; |
| 926 } |
| 853 if (node->op()->EffectInputCount() == 0) return false; | 927 if (node->op()->EffectInputCount() == 0) return false; |
| 854 if (node->op()->EffectOutputCount() == 0) return false; | 928 if (node->op()->EffectOutputCount() == 0) return false; |
| 855 if (node->op()->EffectInputCount() == 1 && | 929 if (node->op()->EffectInputCount() == 1 && |
| 856 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) { | 930 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) { |
| 857 // The start node is used as sentinel for nodes that are in general | 931 // The start node is used as sentinel for nodes that are in general |
| 858 // effectful, but of which an analysis has determined that they do not | 932 // effectful, but of which an analysis has determined that they do not |
| 859 // produce effects in this instance. We don't consider these nodes dangling. | 933 // produce effects in this instance. We don't consider these nodes dangling. |
| 934 status_[node->id()] |= kDanglingComputed; |
| 860 return false; | 935 return false; |
| 861 } | 936 } |
| 862 for (Edge edge : node->use_edges()) { | 937 for (Edge edge : node->use_edges()) { |
| 938 Node* use = edge.from(); |
| 939 if (aliases_[use->id()] == kNotReachable) continue; |
| 863 if (NodeProperties::IsEffectEdge(edge)) { | 940 if (NodeProperties::IsEffectEdge(edge)) { |
| 941 status_[node->id()] |= kDanglingComputed; |
| 864 return false; | 942 return false; |
| 865 } | 943 } |
| 866 } | 944 } |
| 945 status_[node->id()] |= kDanglingComputed | kDangling; |
| 867 return true; | 946 return true; |
| 868 } | 947 } |
| 869 | 948 |
| 870 | 949 |
| 950 bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) { |
| 951 if (status_[node->id()] & kBranchPointComputed) { |
| 952 return status_[node->id()] & kBranchPoint; |
| 953 } |
| 954 int count = 0; |
| 955 for (Edge edge : node->use_edges()) { |
| 956 Node* use = edge.from(); |
| 957 if (aliases_[use->id()] == kNotReachable) continue; |
| 958 if (NodeProperties::IsEffectEdge(edge)) { |
| 959 if ((node->opcode() == IrOpcode::kLoadField || |
| 960 node->opcode() == IrOpcode::kLoadElement || |
| 961 node->opcode() == IrOpcode::kLoad) && |
| 962 IsDanglingEffectNode(node)) |
| 963 continue; |
| 964 if (++count > 1) { |
| 965 status_[node->id()] |= kBranchPointComputed | kBranchPoint; |
| 966 return true; |
| 967 } |
| 968 } |
| 969 } |
| 970 status_[node->id()] |= kBranchPointComputed; |
| 971 return false; |
| 972 } |
| 973 |
| 974 |
| 871 bool EscapeAnalysis::Process(Node* node) { | 975 bool EscapeAnalysis::Process(Node* node) { |
| 872 switch (node->opcode()) { | 976 switch (node->opcode()) { |
| 873 case IrOpcode::kAllocate: | 977 case IrOpcode::kAllocate: |
| 874 ProcessAllocation(node); | 978 ProcessAllocation(node); |
| 875 break; | 979 break; |
| 876 case IrOpcode::kBeginRegion: | 980 case IrOpcode::kBeginRegion: |
| 877 ForwardVirtualState(node); | 981 ForwardVirtualState(node); |
| 878 break; | 982 break; |
| 879 case IrOpcode::kFinishRegion: | 983 case IrOpcode::kFinishRegion: |
| 880 ProcessFinishRegion(node); | 984 ProcessFinishRegion(node); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 904 ProcessAllocationUsers(node); | 1008 ProcessAllocationUsers(node); |
| 905 break; | 1009 break; |
| 906 } | 1010 } |
| 907 return true; | 1011 return true; |
| 908 } | 1012 } |
| 909 | 1013 |
| 910 | 1014 |
| 911 void EscapeAnalysis::ProcessAllocationUsers(Node* node) { | 1015 void EscapeAnalysis::ProcessAllocationUsers(Node* node) { |
| 912 for (Edge edge : node->input_edges()) { | 1016 for (Edge edge : node->input_edges()) { |
| 913 Node* input = edge.to(); | 1017 Node* input = edge.to(); |
| 914 if (!NodeProperties::IsValueEdge(edge) && | 1018 Node* use = edge.from(); |
| 915 !NodeProperties::IsContextEdge(edge)) | 1019 if (edge.index() >= use->op()->ValueInputCount() + |
| 1020 OperatorProperties::GetContextInputCount(use->op())) |
| 916 continue; | 1021 continue; |
| 917 switch (node->opcode()) { | 1022 switch (node->opcode()) { |
| 918 case IrOpcode::kStoreField: | 1023 case IrOpcode::kStoreField: |
| 919 case IrOpcode::kLoadField: | 1024 case IrOpcode::kLoadField: |
| 920 case IrOpcode::kStoreElement: | 1025 case IrOpcode::kStoreElement: |
| 921 case IrOpcode::kLoadElement: | 1026 case IrOpcode::kLoadElement: |
| 922 case IrOpcode::kFrameState: | 1027 case IrOpcode::kFrameState: |
| 923 case IrOpcode::kStateValues: | 1028 case IrOpcode::kStateValues: |
| 924 case IrOpcode::kReferenceEqual: | 1029 case IrOpcode::kReferenceEqual: |
| 925 case IrOpcode::kFinishRegion: | 1030 case IrOpcode::kFinishRegion: |
| 926 case IrOpcode::kPhi: | 1031 case IrOpcode::kPhi: |
| 927 break; | 1032 break; |
| 928 default: | 1033 default: |
| 929 VirtualState* state = virtual_states_[node->id()]; | 1034 VirtualState* state = virtual_states_[node->id()]; |
| 930 if (VirtualObject* obj = ResolveVirtualObject(state, input)) { | 1035 if (VirtualObject* obj = ResolveVirtualObject(state, input)) { |
| 931 if (obj->ClearAllFields()) { | 1036 if (!obj->AllFieldsClear()) { |
| 932 state->LastChangedAt(node); | 1037 obj = CopyForModificationAt(obj, state, node); |
| 1038 obj->ClearAllFields(); |
| 1039 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), |
| 1040 obj->id()); |
| 933 } | 1041 } |
| 934 } | 1042 } |
| 935 break; | 1043 break; |
| 936 } | 1044 } |
| 937 } | 1045 } |
| 938 } | 1046 } |
| 939 | 1047 |
| 940 | 1048 |
| 941 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { | 1049 VirtualState* EscapeAnalysis::CopyForModificationAt(VirtualState* state, |
| 942 int count = 0; | 1050 Node* node) { |
| 943 for (Edge edge : node->use_edges()) { | 1051 if (state->owner() != node) { |
| 944 if (NodeProperties::IsEffectEdge(edge)) { | 1052 VirtualState* new_state = new (zone()) VirtualState(node, *state); |
| 945 if (++count > 1) { | 1053 virtual_states_[node->id()] = new_state; |
| 946 return true; | 1054 TRACE("Copying virtual state %p to new state %p at node %s#%d\n", |
| 947 } | 1055 static_cast<void*>(state), static_cast<void*>(new_state), |
| 948 } | 1056 node->op()->mnemonic(), node->id()); |
| 1057 return new_state; |
| 949 } | 1058 } |
| 950 return false; | 1059 return state; |
| 1060 } |
| 1061 |
| 1062 |
| 1063 VirtualObject* EscapeAnalysis::CopyForModificationAt(VirtualObject* obj, |
| 1064 VirtualState* state, |
| 1065 Node* node) { |
| 1066 if (obj->NeedCopyForModification()) { |
| 1067 state = CopyForModificationAt(state, node); |
| 1068 return state->Copy(obj, GetAlias(obj->id())); |
| 1069 } |
| 1070 return obj; |
| 951 } | 1071 } |
| 952 | 1072 |
| 953 | 1073 |
| 954 void EscapeAnalysis::ForwardVirtualState(Node* node) { | 1074 void EscapeAnalysis::ForwardVirtualState(Node* node) { |
| 955 DCHECK_EQ(node->op()->EffectInputCount(), 1); | 1075 DCHECK_EQ(node->op()->EffectInputCount(), 1); |
| 1076 #ifdef DEBUG |
| 956 if (node->opcode() != IrOpcode::kLoadField && | 1077 if (node->opcode() != IrOpcode::kLoadField && |
| 957 node->opcode() != IrOpcode::kLoadElement && | 1078 node->opcode() != IrOpcode::kLoadElement && |
| 958 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { | 1079 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
| 959 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 1080 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
| 960 node->op()->mnemonic()); | 1081 node->op()->mnemonic()); |
| 961 UNREACHABLE(); | 1082 UNREACHABLE(); |
| 962 } | 1083 } |
| 1084 #endif // DEBUG |
| 963 Node* effect = NodeProperties::GetEffectInput(node); | 1085 Node* effect = NodeProperties::GetEffectInput(node); |
| 964 // Break the cycle for effect phis. | 1086 // Break the cycle for effect phis. |
| 965 if (effect->opcode() == IrOpcode::kEffectPhi) { | 1087 if (effect->opcode() == IrOpcode::kEffectPhi && |
| 966 if (virtual_states_[effect->id()] == nullptr) { | 1088 virtual_states_[effect->id()] == nullptr) { |
| 967 virtual_states_[effect->id()] = | 1089 VirtualState* state = |
| 968 new (zone()) VirtualState(zone(), AliasCount()); | 1090 new (zone()) VirtualState(effect, zone(), AliasCount()); |
| 969 } | 1091 virtual_states_[effect->id()] = state; |
| 1092 TRACE("Effect Phi #%d got new virtual state %p.\n", effect->id(), |
| 1093 static_cast<void*>(virtual_states_[effect->id()])); |
| 970 } | 1094 } |
| 971 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 1095 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
| 972 if (IsEffectBranchPoint(effect)) { | 1096 if (virtual_states_[node->id()]) { |
| 973 TRACE("Copying virtual state %p from #%d (%s) to #%d (%s)\n", | 1097 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
| 974 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 1098 zone()); |
| 975 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | |
| 976 if (!virtual_states_[node->id()]) { | |
| 977 virtual_states_[node->id()] = | |
| 978 new (zone()) VirtualState(*virtual_states_[effect->id()]); | |
| 979 } else { | |
| 980 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | |
| 981 zone()); | |
| 982 } | |
| 983 } else { | 1099 } else { |
| 984 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 1100 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
| 985 TRACE("Forwarding virtual state %p from #%d (%s) to #%d (%s)\n", | 1101 TRACE("Forwarding object state %p from %s#%d to %s#%d", |
| 986 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 1102 static_cast<void*>(virtual_states_[effect->id()]), |
| 987 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 1103 effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), |
| 1104 node->id()); |
| 1105 if (IsEffectBranchPoint(effect) || |
| 1106 OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { |
| 1107 virtual_states_[node->id()]->SetCopyRequired(); |
| 1108 TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), |
| 1109 effect->id()); |
| 1110 } |
| 1111 TRACE("\n"); |
| 988 } | 1112 } |
| 989 } | 1113 } |
| 990 | 1114 |
| 991 | 1115 |
| 992 void EscapeAnalysis::ProcessStart(Node* node) { | 1116 void EscapeAnalysis::ProcessStart(Node* node) { |
| 993 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 1117 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
| 994 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount()); | 1118 virtual_states_[node->id()] = |
| 1119 new (zone()) VirtualState(node, zone(), AliasCount()); |
| 995 } | 1120 } |
| 996 | 1121 |
| 997 | 1122 |
| 998 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 1123 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
| 999 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 1124 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
| 1000 bool changed = false; | 1125 bool changed = false; |
| 1001 | 1126 |
| 1002 VirtualState* mergeState = virtual_states_[node->id()]; | 1127 VirtualState* mergeState = virtual_states_[node->id()]; |
| 1003 if (!mergeState) { | 1128 if (!mergeState) { |
| 1004 mergeState = new (zone()) VirtualState(zone(), AliasCount()); | 1129 mergeState = new (zone()) VirtualState(node, zone(), AliasCount()); |
| 1005 virtual_states_[node->id()] = mergeState; | 1130 virtual_states_[node->id()] = mergeState; |
| 1006 changed = true; | 1131 changed = true; |
| 1007 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), | 1132 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), |
| 1008 static_cast<void*>(mergeState)); | 1133 static_cast<void*>(mergeState)); |
| 1009 } else if (mergeState->GetLastChanged() != node) { | |
| 1010 changed = true; | |
| 1011 } | 1134 } |
| 1012 | 1135 |
| 1013 cache_->Clear(); | 1136 cache_->Clear(); |
| 1014 | 1137 |
| 1015 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), | 1138 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), |
| 1016 static_cast<void*>(mergeState)); | 1139 static_cast<void*>(mergeState)); |
| 1017 | 1140 |
| 1018 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1141 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
| 1019 Node* input = NodeProperties::GetEffectInput(node, i); | 1142 Node* input = NodeProperties::GetEffectInput(node, i); |
| 1020 VirtualState* state = virtual_states_[input->id()]; | 1143 VirtualState* state = virtual_states_[input->id()]; |
| 1021 if (state) { | 1144 if (state) { |
| 1022 cache_->states().push_back(state); | 1145 cache_->states().push_back(state); |
| 1146 if (state == mergeState) { |
| 1147 mergeState = new (zone()) VirtualState(node, zone(), AliasCount()); |
| 1148 virtual_states_[node->id()] = mergeState; |
| 1149 changed = true; |
| 1150 } |
| 1023 } | 1151 } |
| 1024 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1152 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
| 1025 input->op()->mnemonic()); | 1153 input->op()->mnemonic()); |
| 1026 } | 1154 } |
| 1027 TRACE("\n"); | 1155 TRACE("\n"); |
| 1028 | 1156 |
| 1029 if (cache_->states().size() == 0) { | 1157 if (cache_->states().size() == 0) { |
| 1030 return changed; | 1158 return changed; |
| 1031 } | 1159 } |
| 1032 | 1160 |
| 1033 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), | 1161 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), |
| 1034 NodeProperties::GetControlInput(node)) || | 1162 NodeProperties::GetControlInput(node), |
| 1163 node->op()->EffectInputCount()) || |
| 1035 changed; | 1164 changed; |
| 1036 | 1165 |
| 1037 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); | 1166 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
| 1038 | 1167 |
| 1039 if (changed) { | 1168 if (changed) { |
| 1040 mergeState->LastChangedAt(node); | 1169 status_analysis_.ResizeStatusVector(); |
| 1041 escape_status_.Resize(); | |
| 1042 } | 1170 } |
| 1043 return changed; | 1171 return changed; |
| 1044 } | 1172 } |
| 1045 | 1173 |
| 1046 | 1174 |
| 1047 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1175 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| 1048 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1176 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 1049 ForwardVirtualState(node); | 1177 ForwardVirtualState(node); |
| 1050 VirtualState* state = virtual_states_[node->id()]; | 1178 VirtualState* state = virtual_states_[node->id()]; |
| 1051 Alias alias = aliases_[node->id()]; | 1179 Alias alias = GetAlias(node->id()); |
| 1052 | 1180 |
| 1053 // Check if we have already processed this node. | 1181 // Check if we have already processed this node. |
| 1054 if (state->VirtualObjectFromAlias(alias)) { | 1182 if (state->VirtualObjectFromAlias(alias)) { |
| 1055 return; | 1183 return; |
| 1056 } | 1184 } |
| 1057 | 1185 |
| 1186 state = CopyForModificationAt(state, node); |
| 1187 |
| 1058 NumberMatcher size(node->InputAt(0)); | 1188 NumberMatcher size(node->InputAt(0)); |
| 1059 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1189 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 1060 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1190 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 1061 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1191 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 1062 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1192 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 1063 if (size.HasValue()) { | 1193 if (size.HasValue()) { |
| 1064 state->SetVirtualObject( | 1194 state->SetVirtualObject( |
| 1065 alias, new (zone()) VirtualObject(node->id(), zone(), | 1195 alias, new (zone()) VirtualObject(node->id(), state, zone(), |
| 1066 size.Value() / kPointerSize)); | 1196 size.Value() / kPointerSize, false)); |
| 1067 } else { | 1197 } else { |
| 1068 state->SetVirtualObject(alias, | 1198 state->SetVirtualObject( |
| 1069 new (zone()) VirtualObject(node->id(), zone())); | 1199 alias, new (zone()) VirtualObject(node->id(), state, zone())); |
| 1070 } | 1200 } |
| 1071 state->LastChangedAt(node); | |
| 1072 } | 1201 } |
| 1073 | 1202 |
| 1074 | 1203 |
| 1075 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1204 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
| 1076 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1205 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
| 1077 ForwardVirtualState(node); | 1206 ForwardVirtualState(node); |
| 1078 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1207 Node* allocation = NodeProperties::GetValueInput(node, 0); |
| 1079 if (allocation->opcode() == IrOpcode::kAllocate) { | 1208 if (allocation->opcode() == IrOpcode::kAllocate) { |
| 1080 VirtualState* state = virtual_states_[node->id()]; | 1209 VirtualState* state = virtual_states_[node->id()]; |
| 1081 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { | 1210 VirtualObject* obj = state->VirtualObjectFromAlias(GetAlias(node->id())); |
| 1082 VirtualObject* vobj_alloc = | 1211 DCHECK_NOT_NULL(obj); |
| 1083 state->VirtualObjectFromAlias(aliases_[allocation->id()]); | 1212 obj->SetInitialized(); |
| 1084 DCHECK_NOT_NULL(vobj_alloc); | |
| 1085 state->SetVirtualObject(aliases_[node->id()], vobj_alloc); | |
| 1086 TRACE("Linked finish region node #%d to node #%d\n", node->id(), | |
| 1087 allocation->id()); | |
| 1088 state->LastChangedAt(node); | |
| 1089 } | |
| 1090 } | 1213 } |
| 1091 } | 1214 } |
| 1092 | 1215 |
| 1093 | 1216 |
| 1094 Node* EscapeAnalysis::replacement(NodeId id) { | 1217 Node* EscapeAnalysis::replacement(NodeId id) { |
| 1095 if (id >= replacements_.size()) return nullptr; | 1218 if (id >= replacements_.size()) return nullptr; |
| 1096 return replacements_[id]; | 1219 return replacements_[id]; |
| 1097 } | 1220 } |
| 1098 | 1221 |
| 1099 | 1222 |
| 1100 Node* EscapeAnalysis::replacement(Node* node) { | 1223 Node* EscapeAnalysis::replacement(Node* node) { |
| 1101 return replacement(node->id()); | 1224 return replacement(node->id()); |
| 1102 } | 1225 } |
| 1103 | 1226 |
| 1104 | 1227 |
| 1105 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { | 1228 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { |
| 1106 bool changed = replacements_[node->id()] != rep; | 1229 bool changed = replacements_[node->id()] != rep; |
| 1107 replacements_[node->id()] = rep; | 1230 replacements_[node->id()] = rep; |
| 1108 return changed; | 1231 return changed; |
| 1109 } | 1232 } |
| 1110 | 1233 |
| 1111 | 1234 |
| 1112 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, | 1235 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, |
| 1113 Node* rep) { | 1236 Node* rep) { |
| 1114 if (SetReplacement(node, rep)) { | 1237 if (SetReplacement(node, rep)) { |
| 1115 state->LastChangedAt(node); | |
| 1116 if (rep) { | 1238 if (rep) { |
| 1117 TRACE("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), | 1239 TRACE("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), |
| 1118 rep->op()->mnemonic()); | 1240 rep->op()->mnemonic()); |
| 1119 } else { | 1241 } else { |
| 1120 TRACE("Replacement of #%d cleared\n", node->id()); | 1242 TRACE("Replacement of #%d cleared\n", node->id()); |
| 1121 } | 1243 } |
| 1122 return true; | 1244 return true; |
| 1123 } | 1245 } |
| 1124 return false; | 1246 return false; |
| 1125 } | 1247 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1142 Node* node = nullptr; | 1264 Node* node = nullptr; |
| 1143 while (replacement(id)) { | 1265 while (replacement(id)) { |
| 1144 node = replacement(id); | 1266 node = replacement(id); |
| 1145 id = node->id(); | 1267 id = node->id(); |
| 1146 } | 1268 } |
| 1147 return node; | 1269 return node; |
| 1148 } | 1270 } |
| 1149 | 1271 |
| 1150 | 1272 |
| 1151 bool EscapeAnalysis::IsVirtual(Node* node) { | 1273 bool EscapeAnalysis::IsVirtual(Node* node) { |
| 1152 if (node->id() >= escape_status_.size()) { | 1274 if (node->id() >= status_analysis_.GetStatusVectorSize()) { |
| 1153 return false; | 1275 return false; |
| 1154 } | 1276 } |
| 1155 return escape_status_.IsVirtual(node); | 1277 return status_analysis_.IsVirtual(node); |
| 1156 } | 1278 } |
| 1157 | 1279 |
| 1158 | 1280 |
| 1159 bool EscapeAnalysis::IsEscaped(Node* node) { | 1281 bool EscapeAnalysis::IsEscaped(Node* node) { |
| 1160 if (node->id() >= escape_status_.size()) { | 1282 if (node->id() >= status_analysis_.GetStatusVectorSize()) { |
| 1161 return false; | 1283 return false; |
| 1162 } | 1284 } |
| 1163 return escape_status_.IsEscaped(node); | 1285 return status_analysis_.IsEscaped(node); |
| 1164 } | 1286 } |
| 1165 | 1287 |
| 1166 | 1288 |
| 1167 bool EscapeAnalysis::SetEscaped(Node* node) { | 1289 bool EscapeAnalysis::SetEscaped(Node* node) { |
| 1168 return escape_status_.SetEscaped(node); | 1290 return status_analysis_.SetEscaped(node); |
| 1169 } | 1291 } |
| 1170 | 1292 |
| 1171 | 1293 |
| 1172 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1294 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| 1173 if (VirtualState* states = virtual_states_[at->id()]) { | 1295 if (VirtualState* states = virtual_states_[at->id()]) { |
| 1174 return states->VirtualObjectFromAlias(aliases_[id]); | 1296 return states->VirtualObjectFromAlias(GetAlias(id)); |
| 1175 } | 1297 } |
| 1176 return nullptr; | 1298 return nullptr; |
| 1177 } | 1299 } |
| 1178 | 1300 |
| 1179 | 1301 |
| 1180 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1302 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
| 1181 Node* node) { | 1303 Node* node) { |
| 1182 return GetVirtualObject(state, ResolveReplacement(node)); | 1304 return GetVirtualObject(state, ResolveReplacement(node)); |
| 1183 } | 1305 } |
| 1184 | 1306 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1203 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1325 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
| 1204 VirtualState* state) { | 1326 VirtualState* state) { |
| 1205 TRACE("Load #%d from phi #%d", node->id(), from->id()); | 1327 TRACE("Load #%d from phi #%d", node->id(), from->id()); |
| 1206 | 1328 |
| 1207 cache_->fields().clear(); | 1329 cache_->fields().clear(); |
| 1208 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1330 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
| 1209 Node* input = NodeProperties::GetValueInput(node, i); | 1331 Node* input = NodeProperties::GetValueInput(node, i); |
| 1210 cache_->fields().push_back(input); | 1332 cache_->fields().push_back(input); |
| 1211 } | 1333 } |
| 1212 | 1334 |
| 1213 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_); | 1335 cache_->LoadVirtualObjectsForFieldsFrom(state, |
| 1336 status_analysis_.GetAliasMap()); |
| 1214 if (cache_->objects().size() == cache_->fields().size()) { | 1337 if (cache_->objects().size() == cache_->fields().size()) { |
| 1215 cache_->GetFields(offset); | 1338 cache_->GetFields(offset); |
| 1216 if (cache_->fields().size() == cache_->objects().size()) { | 1339 if (cache_->fields().size() == cache_->objects().size()) { |
| 1217 Node* rep = replacement(node); | 1340 Node* rep = replacement(node); |
| 1218 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1341 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
| 1219 int value_input_count = static_cast<int>(cache_->fields().size()); | 1342 int value_input_count = static_cast<int>(cache_->fields().size()); |
| 1220 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1343 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
| 1221 Node* phi = graph()->NewNode( | 1344 Node* phi = graph()->NewNode( |
| 1222 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1345 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
| 1223 value_input_count + 1, &cache_->fields().front()); | 1346 value_input_count + 1, &cache_->fields().front()); |
| 1224 escape_status_.Resize(); | 1347 status_analysis_.ResizeStatusVector(); |
| 1225 SetReplacement(node, phi); | 1348 SetReplacement(node, phi); |
| 1226 state->LastChangedAt(node); | |
| 1227 TRACE(" got phi created.\n"); | 1349 TRACE(" got phi created.\n"); |
| 1228 } else { | 1350 } else { |
| 1229 TRACE(" has already phi #%d.\n", rep->id()); | 1351 TRACE(" has already phi #%d.\n", rep->id()); |
| 1230 } | 1352 } |
| 1231 } else { | 1353 } else { |
| 1232 TRACE(" has incomplete field info.\n"); | 1354 TRACE(" has incomplete field info.\n"); |
| 1233 } | 1355 } |
| 1234 } else { | 1356 } else { |
| 1235 TRACE(" has incomplete virtual object info.\n"); | 1357 TRACE(" has incomplete virtual object info.\n"); |
| 1236 } | 1358 } |
| 1237 } | 1359 } |
| 1238 | 1360 |
| 1239 | 1361 |
| 1240 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1362 void EscapeAnalysis::ProcessLoadField(Node* node) { |
| 1241 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1363 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
| 1242 ForwardVirtualState(node); | 1364 ForwardVirtualState(node); |
| 1243 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1365 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1244 VirtualState* state = virtual_states_[node->id()]; | 1366 VirtualState* state = virtual_states_[node->id()]; |
| 1245 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1367 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1246 int offset = OffsetFromAccess(node); | 1368 int offset = OffsetFromAccess(node); |
| 1247 if (!object->IsTracked()) return; | 1369 if (!object->IsTracked() || |
| 1370 static_cast<size_t>(offset) >= object->field_count()) { |
| 1371 return; |
| 1372 } |
| 1248 Node* value = object->GetField(offset); | 1373 Node* value = object->GetField(offset); |
| 1249 if (value) { | 1374 if (value) { |
| 1250 value = ResolveReplacement(value); | 1375 value = ResolveReplacement(value); |
| 1251 } | 1376 } |
| 1252 // Record that the load has this alias. | 1377 // Record that the load has this alias. |
| 1253 UpdateReplacement(state, node, value); | 1378 UpdateReplacement(state, node, value); |
| 1254 } else if (from->opcode() == IrOpcode::kPhi && | 1379 } else if (from->opcode() == IrOpcode::kPhi && |
| 1255 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { | 1380 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
| 1256 int offset = OffsetFromAccess(node); | 1381 int offset = OffsetFromAccess(node); |
| 1257 // Only binary phis are supported for now. | 1382 // Only binary phis are supported for now. |
| 1258 ProcessLoadFromPhi(offset, from, node, state); | 1383 ProcessLoadFromPhi(offset, from, node, state); |
| 1259 } else { | 1384 } else { |
| 1260 UpdateReplacement(state, node, nullptr); | 1385 UpdateReplacement(state, node, nullptr); |
| 1261 } | 1386 } |
| 1262 } | 1387 } |
| 1263 | 1388 |
| 1264 | 1389 |
| 1265 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1390 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
| 1266 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1391 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
| 1267 ForwardVirtualState(node); | 1392 ForwardVirtualState(node); |
| 1268 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1393 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1269 VirtualState* state = virtual_states_[node->id()]; | 1394 VirtualState* state = virtual_states_[node->id()]; |
| 1270 Node* index_node = node->InputAt(1); | 1395 Node* index_node = node->InputAt(1); |
| 1271 NumberMatcher index(index_node); | 1396 NumberMatcher index(index_node); |
| 1272 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1397 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1273 index_node->opcode() != IrOpcode::kInt64Constant && | 1398 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1274 index_node->opcode() != IrOpcode::kFloat32Constant && | 1399 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1275 index_node->opcode() != IrOpcode::kFloat64Constant); | 1400 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1276 ElementAccess access = OpParameter<ElementAccess>(node); | 1401 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1277 if (index.HasValue()) { | 1402 if (index.HasValue()) { |
| 1278 int offset = index.Value() + access.header_size / kPointerSize; | 1403 int offset = index.Value() + access.header_size / kPointerSize; |
| 1279 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1404 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| 1280 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1405 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1281 kPointerSizeLog2); | 1406 kPointerSizeLog2); |
| 1282 CHECK_EQ(access.header_size % kPointerSize, 0); | 1407 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1283 | 1408 |
| 1284 if (!object->IsTracked()) return; | 1409 if (!object->IsTracked() || |
| 1410 static_cast<size_t>(offset) >= object->field_count()) { |
| 1411 return; |
| 1412 } |
| 1413 |
| 1285 Node* value = object->GetField(offset); | 1414 Node* value = object->GetField(offset); |
| 1286 if (value) { | 1415 if (value) { |
| 1287 value = ResolveReplacement(value); | 1416 value = ResolveReplacement(value); |
| 1288 } | 1417 } |
| 1289 // Record that the load has this alias. | 1418 // Record that the load has this alias. |
| 1290 UpdateReplacement(state, node, value); | 1419 UpdateReplacement(state, node, value); |
| 1291 } else if (from->opcode() == IrOpcode::kPhi) { | 1420 } else if (from->opcode() == IrOpcode::kPhi) { |
| 1292 ElementAccess access = OpParameter<ElementAccess>(node); | 1421 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1293 int offset = index.Value() + access.header_size / kPointerSize; | 1422 int offset = index.Value() + access.header_size / kPointerSize; |
| 1294 ProcessLoadFromPhi(offset, from, node, state); | 1423 ProcessLoadFromPhi(offset, from, node, state); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1307 } | 1436 } |
| 1308 } | 1437 } |
| 1309 | 1438 |
| 1310 | 1439 |
| 1311 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1440 void EscapeAnalysis::ProcessStoreField(Node* node) { |
| 1312 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1441 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 1313 ForwardVirtualState(node); | 1442 ForwardVirtualState(node); |
| 1314 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1443 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1315 VirtualState* state = virtual_states_[node->id()]; | 1444 VirtualState* state = virtual_states_[node->id()]; |
| 1316 VirtualObject* obj = GetVirtualObject(state, to); | 1445 VirtualObject* obj = GetVirtualObject(state, to); |
| 1317 if (obj && obj->IsTracked()) { | 1446 int offset = OffsetFromAccess(node); |
| 1318 int offset = OffsetFromAccess(node); | 1447 if (obj && obj->IsTracked() && |
| 1448 static_cast<size_t>(offset) < obj->field_count()) { |
| 1319 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); | 1449 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
| 1320 if (obj->SetField(offset, val)) { | 1450 if (obj->GetField(offset) != val) { |
| 1321 state->LastChangedAt(node); | 1451 obj = CopyForModificationAt(obj, state, node); |
| 1452 obj->SetField(offset, val); |
| 1322 } | 1453 } |
| 1323 } | 1454 } |
| 1324 } | 1455 } |
| 1325 | 1456 |
| 1326 | 1457 |
| 1327 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1458 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
| 1328 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1459 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 1329 ForwardVirtualState(node); | 1460 ForwardVirtualState(node); |
| 1330 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1461 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1331 Node* index_node = node->InputAt(1); | 1462 Node* index_node = node->InputAt(1); |
| 1332 NumberMatcher index(index_node); | 1463 NumberMatcher index(index_node); |
| 1333 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1464 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
| 1334 index_node->opcode() != IrOpcode::kInt64Constant && | 1465 index_node->opcode() != IrOpcode::kInt64Constant && |
| 1335 index_node->opcode() != IrOpcode::kFloat32Constant && | 1466 index_node->opcode() != IrOpcode::kFloat32Constant && |
| 1336 index_node->opcode() != IrOpcode::kFloat64Constant); | 1467 index_node->opcode() != IrOpcode::kFloat64Constant); |
| 1337 ElementAccess access = OpParameter<ElementAccess>(node); | 1468 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1338 VirtualState* state = virtual_states_[node->id()]; | 1469 VirtualState* state = virtual_states_[node->id()]; |
| 1339 VirtualObject* obj = GetVirtualObject(state, to); | 1470 VirtualObject* obj = GetVirtualObject(state, to); |
| 1340 if (index.HasValue()) { | 1471 if (index.HasValue()) { |
| 1341 int offset = index.Value() + access.header_size / kPointerSize; | 1472 int offset = index.Value() + access.header_size / kPointerSize; |
| 1342 if (obj && obj->IsTracked()) { | 1473 if (obj && obj->IsTracked() && |
| 1474 static_cast<size_t>(offset) < obj->field_count()) { |
| 1343 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 1475 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
| 1344 kPointerSizeLog2); | 1476 kPointerSizeLog2); |
| 1345 CHECK_EQ(access.header_size % kPointerSize, 0); | 1477 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1346 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); | 1478 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
| 1347 if (obj->SetField(offset, val)) { | 1479 if (obj->GetField(offset) != val) { |
| 1348 state->LastChangedAt(node); | 1480 obj = CopyForModificationAt(obj, state, node); |
| 1481 obj->SetField(offset, val); |
| 1349 } | 1482 } |
| 1350 } | 1483 } |
| 1351 } else { | 1484 } else { |
| 1352 // We have a store to a non-const index, cannot eliminate object. | 1485 // We have a store to a non-const index, cannot eliminate object. |
| 1353 if (SetEscaped(to)) { | 1486 if (SetEscaped(to)) { |
| 1354 TRACE( | 1487 TRACE( |
| 1355 "Setting #%d (%s) to escaped because store element #%d to non-const " | 1488 "Setting #%d (%s) to escaped because store element #%d to non-const " |
| 1356 "index #%d (%s)\n", | 1489 "index #%d (%s)\n", |
| 1357 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), | 1490 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), |
| 1358 index_node->op()->mnemonic()); | 1491 index_node->op()->mnemonic()); |
| 1359 } | 1492 } |
| 1360 if (obj && obj->IsTracked() && obj->ClearAllFields()) { | 1493 if (obj && obj->IsTracked()) { |
| 1361 state->LastChangedAt(node); | 1494 if (!obj->AllFieldsClear()) { |
| 1362 TRACE("Cleared all fields of @%d:#%d\n", aliases_[obj->id()], obj->id()); | 1495 obj = CopyForModificationAt(obj, state, node); |
| 1496 obj->ClearAllFields(); |
| 1497 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), |
| 1498 obj->id()); |
| 1499 } |
| 1363 } | 1500 } |
| 1364 } | 1501 } |
| 1365 } | 1502 } |
| 1366 | 1503 |
| 1367 | 1504 |
| 1368 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1505 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| 1369 if ((node->opcode() == IrOpcode::kFinishRegion || | 1506 if ((node->opcode() == IrOpcode::kFinishRegion || |
| 1370 node->opcode() == IrOpcode::kAllocate) && | 1507 node->opcode() == IrOpcode::kAllocate) && |
| 1371 IsVirtual(node)) { | 1508 IsVirtual(node)) { |
| 1372 if (VirtualObject* vobj = | 1509 if (VirtualObject* vobj = |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1440 } | 1577 } |
| 1441 } | 1578 } |
| 1442 for (size_t n = 0; n < object_states.size(); n++) { | 1579 for (size_t n = 0; n < object_states.size(); n++) { |
| 1443 DebugPrintState(object_states[n]); | 1580 DebugPrintState(object_states[n]); |
| 1444 } | 1581 } |
| 1445 } | 1582 } |
| 1446 | 1583 |
| 1447 | 1584 |
| 1448 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, | 1585 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
| 1449 Node* node) { | 1586 Node* node) { |
| 1450 if (node->id() >= aliases_.size()) return nullptr; | 1587 if (node->id() >= status_analysis_.GetAliasMap().size()) return nullptr; |
| 1451 Alias alias = aliases_[node->id()]; | 1588 Alias alias = GetAlias(node->id()); |
| 1452 if (alias >= state->size()) return nullptr; | 1589 if (alias >= state->size()) return nullptr; |
| 1453 return state->VirtualObjectFromAlias(alias); | 1590 return state->VirtualObjectFromAlias(alias); |
| 1454 } | 1591 } |
| 1455 | 1592 |
| 1456 | 1593 |
| 1457 bool EscapeAnalysis::ExistsVirtualAllocate() { | 1594 bool EscapeAnalysis::ExistsVirtualAllocate() { |
| 1458 for (size_t id = 0; id < aliases_.size(); ++id) { | 1595 for (size_t id = 0; id < status_analysis_.GetAliasMap().size(); ++id) { |
| 1459 Alias alias = aliases_[id]; | 1596 Alias alias = GetAlias(static_cast<NodeId>(id)); |
| 1460 if (alias < kUntrackable) { | 1597 if (alias < EscapeStatusAnalysis::kUntrackable) { |
| 1461 if (escape_status_.IsVirtual(static_cast<int>(id))) { | 1598 if (status_analysis_.IsVirtual(static_cast<int>(id))) { |
| 1462 return true; | 1599 return true; |
| 1463 } | 1600 } |
| 1464 } | 1601 } |
| 1465 } | 1602 } |
| 1466 return false; | 1603 return false; |
| 1467 } | 1604 } |
| 1468 | 1605 |
| 1469 } // namespace compiler | 1606 } // namespace compiler |
| 1470 } // namespace internal | 1607 } // namespace internal |
| 1471 } // namespace v8 | 1608 } // namespace v8 |
| OLD | NEW |