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