| 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> |
| 8 |
| 7 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
| 8 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| 9 #include "src/compilation-dependencies.h" | 11 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/common-operator.h" | 12 #include "src/compiler/common-operator.h" |
| 11 #include "src/compiler/graph-reducer.h" | 13 #include "src/compiler/graph-reducer.h" |
| 12 #include "src/compiler/js-operator.h" | 14 #include "src/compiler/js-operator.h" |
| 13 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
| 14 #include "src/compiler/node-matchers.h" | 16 #include "src/compiler/node-matchers.h" |
| 15 #include "src/compiler/node-properties.h" | 17 #include "src/compiler/node-properties.h" |
| 18 #include "src/compiler/operator-properties.h" |
| 16 #include "src/compiler/simplified-operator.h" | 19 #include "src/compiler/simplified-operator.h" |
| 17 #include "src/objects-inl.h" | 20 #include "src/objects-inl.h" |
| 18 #include "src/type-cache.h" | 21 #include "src/type-cache.h" |
| 19 | 22 |
| 20 namespace v8 { | 23 namespace v8 { |
| 21 namespace internal { | 24 namespace internal { |
| 22 namespace compiler { | 25 namespace compiler { |
| 23 | 26 |
| 27 const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable = |
| 28 std::numeric_limits<Alias>::max(); |
| 29 const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable = |
| 30 std::numeric_limits<Alias>::max() - 1; |
| 31 |
| 32 |
| 24 class VirtualObject : public ZoneObject { | 33 class VirtualObject : public ZoneObject { |
| 25 public: | 34 public: |
| 26 enum Status { kUntracked = 0, kTracked = 1 }; | 35 enum Status { kUntracked = 0, kTracked = 1 }; |
| 27 VirtualObject(NodeId id, Zone* zone) | 36 VirtualObject(NodeId id, Zone* zone) |
| 28 : id_(id), | 37 : id_(id), |
| 29 status_(kUntracked), | 38 status_(kUntracked), |
| 30 fields_(zone), | 39 fields_(zone), |
| 31 phi_(zone), | 40 phi_(zone), |
| 32 object_state_(nullptr) {} | 41 object_state_(nullptr) {} |
| 33 | 42 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 if (fields_[i] != nullptr) { | 100 if (fields_[i] != nullptr) { |
| 92 fields_[i] = nullptr; | 101 fields_[i] = nullptr; |
| 93 changed = true; | 102 changed = true; |
| 94 } | 103 } |
| 95 phi_[i] = false; | 104 phi_[i] = false; |
| 96 } | 105 } |
| 97 return changed; | 106 return changed; |
| 98 } | 107 } |
| 99 bool UpdateFrom(const VirtualObject& other); | 108 bool UpdateFrom(const VirtualObject& other); |
| 100 void SetObjectState(Node* node) { object_state_ = node; } | 109 void SetObjectState(Node* node) { object_state_ = node; } |
| 101 Node* GetObjectState() { return object_state_; } | 110 Node* GetObjectState() const { return object_state_; } |
| 102 | 111 |
| 103 NodeId id() { return id_; } | 112 NodeId id() const { return id_; } |
| 104 void id(NodeId id) { id_ = id; } | 113 void id(NodeId id) { id_ = id; } |
| 105 | 114 |
| 106 private: | 115 private: |
| 107 NodeId id_; | 116 NodeId id_; |
| 108 Status status_; | 117 Status status_; |
| 109 ZoneVector<Node*> fields_; | 118 ZoneVector<Node*> fields_; |
| 110 ZoneVector<bool> phi_; | 119 ZoneVector<bool> phi_; |
| 111 Node* object_state_; | 120 Node* object_state_; |
| 112 }; | 121 }; |
| 113 | 122 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 127 } | 136 } |
| 128 return changed; | 137 return changed; |
| 129 } | 138 } |
| 130 | 139 |
| 131 | 140 |
| 132 class VirtualState : public ZoneObject { | 141 class VirtualState : public ZoneObject { |
| 133 public: | 142 public: |
| 134 VirtualState(Zone* zone, size_t size); | 143 VirtualState(Zone* zone, size_t size); |
| 135 VirtualState(const VirtualState& states); | 144 VirtualState(const VirtualState& states); |
| 136 | 145 |
| 137 VirtualObject* GetVirtualObject(Node* node); | 146 VirtualObject* VirtualObjectFromAlias(size_t alias); |
| 138 VirtualObject* GetVirtualObject(size_t id); | 147 VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias, |
| 139 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); | 148 NodeId id, Zone* zone); |
| 140 void SetVirtualObject(NodeId id, VirtualObject* state); | 149 void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state); |
| 141 void LastChangedAt(Node* node) { last_changed_ = node; } | 150 void LastChangedAt(Node* node) { last_changed_ = node; } |
| 142 Node* GetLastChanged() { return last_changed_; } | 151 Node* GetLastChanged() { return last_changed_; } |
| 143 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); | |
| 144 bool UpdateFrom(VirtualState* state, Zone* zone); | 152 bool UpdateFrom(VirtualState* state, Zone* zone); |
| 145 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 153 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 146 CommonOperatorBuilder* common, Node* control); | 154 CommonOperatorBuilder* common, Node* control); |
| 147 | 155 size_t size() const { return info_.size(); } |
| 148 size_t size() { return info_.size(); } | |
| 149 | 156 |
| 150 private: | 157 private: |
| 151 ZoneVector<VirtualObject*> info_; | 158 ZoneVector<VirtualObject*> info_; |
| 152 Node* last_changed_; | 159 Node* last_changed_; |
| 153 }; | 160 }; |
| 154 | 161 |
| 155 | 162 |
| 156 class MergeCache : public ZoneObject { | 163 class MergeCache : public ZoneObject { |
| 157 public: | 164 public: |
| 158 explicit MergeCache(Zone* zone) | 165 explicit MergeCache(Zone* zone) |
| 159 : states_(zone), objects_(zone), fields_(zone), min_size_(SIZE_MAX) { | 166 : states_(zone), objects_(zone), fields_(zone) { |
| 160 states_.reserve(4); | 167 states_.reserve(4); |
| 161 objects_.reserve(4); | 168 objects_.reserve(4); |
| 162 fields_.reserve(4); | 169 fields_.reserve(4); |
| 163 } | 170 } |
| 164 ZoneVector<VirtualState*>& states() { return states_; } | 171 ZoneVector<VirtualState*>& states() { return states_; } |
| 165 ZoneVector<VirtualObject*>& objects() { return objects_; } | 172 ZoneVector<VirtualObject*>& objects() { return objects_; } |
| 166 ZoneVector<Node*>& fields() { return fields_; } | 173 ZoneVector<Node*>& fields() { return fields_; } |
| 167 void Clear() { | 174 void Clear() { |
| 168 states_.clear(); | 175 states_.clear(); |
| 169 objects_.clear(); | 176 objects_.clear(); |
| 170 fields_.clear(); | 177 fields_.clear(); |
| 171 min_size_ = SIZE_MAX; | |
| 172 } | 178 } |
| 173 void push_back(VirtualState* state) { | 179 size_t LoadVirtualObjectsFromStatesFor(EscapeAnalysis::Alias alias); |
| 174 states_.push_back(state); | 180 void LoadVirtualObjectsForFieldsFrom( |
| 175 min_size_ = std::min(state->size(), min_size_); | 181 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases); |
| 176 } | |
| 177 size_t min_size() { return min_size_; } | |
| 178 | |
| 179 size_t LoadVirtualObjectsFromStatesFor(NodeId id); | |
| 180 void LoadVirtualObjectsForFieldsFrom(VirtualState* state); | |
| 181 Node* GetFields(size_t pos); | 182 Node* GetFields(size_t pos); |
| 182 | 183 |
| 183 private: | 184 private: |
| 184 ZoneVector<VirtualState*> states_; | 185 ZoneVector<VirtualState*> states_; |
| 185 ZoneVector<VirtualObject*> objects_; | 186 ZoneVector<VirtualObject*> objects_; |
| 186 ZoneVector<Node*> fields_; | 187 ZoneVector<Node*> fields_; |
| 187 size_t min_size_; | |
| 188 }; | 188 }; |
| 189 | 189 |
| 190 | 190 |
| 191 size_t MergeCache::LoadVirtualObjectsFromStatesFor(NodeId id) { | 191 size_t MergeCache::LoadVirtualObjectsFromStatesFor( |
| 192 EscapeAnalysis::Alias alias) { |
| 192 objects_.clear(); | 193 objects_.clear(); |
| 193 DCHECK_GT(states_.size(), 0u); | 194 DCHECK_GT(states_.size(), 0u); |
| 194 size_t min = SIZE_MAX; | 195 size_t min = std::numeric_limits<size_t>::max(); |
| 195 for (VirtualState* state : states_) { | 196 for (VirtualState* state : states_) { |
| 196 if (VirtualObject* obj = state->GetVirtualObject(id)) { | 197 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
| 197 objects_.push_back(obj); | 198 objects_.push_back(obj); |
| 198 min = std::min(obj->field_count(), min); | 199 min = std::min(obj->field_count(), min); |
| 199 } | 200 } |
| 200 } | 201 } |
| 201 return min; | 202 return min; |
| 202 } | 203 } |
| 203 | 204 |
| 204 | 205 |
| 205 void MergeCache::LoadVirtualObjectsForFieldsFrom(VirtualState* state) { | 206 void MergeCache::LoadVirtualObjectsForFieldsFrom( |
| 207 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases) { |
| 206 objects_.clear(); | 208 objects_.clear(); |
| 209 size_t max_alias = state->size(); |
| 207 for (Node* field : fields_) { | 210 for (Node* field : fields_) { |
| 208 if (VirtualObject* obj = state->GetVirtualObject(field)) { | 211 EscapeAnalysis::Alias alias = aliases[field->id()]; |
| 212 if (alias >= max_alias) continue; |
| 213 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
| 209 objects_.push_back(obj); | 214 objects_.push_back(obj); |
| 210 } | 215 } |
| 211 } | 216 } |
| 212 } | 217 } |
| 213 | 218 |
| 214 | 219 |
| 215 Node* MergeCache::GetFields(size_t pos) { | 220 Node* MergeCache::GetFields(size_t pos) { |
| 216 fields_.clear(); | 221 fields_.clear(); |
| 217 Node* rep = objects_.front()->GetField(pos); | 222 Node* rep = objects_.front()->GetField(pos); |
| 218 for (VirtualObject* obj : objects_) { | 223 for (VirtualObject* obj : objects_) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 229 | 234 |
| 230 | 235 |
| 231 VirtualState::VirtualState(Zone* zone, size_t size) | 236 VirtualState::VirtualState(Zone* zone, size_t size) |
| 232 : info_(size, nullptr, zone), last_changed_(nullptr) {} | 237 : info_(size, nullptr, zone), last_changed_(nullptr) {} |
| 233 | 238 |
| 234 | 239 |
| 235 VirtualState::VirtualState(const VirtualState& state) | 240 VirtualState::VirtualState(const VirtualState& state) |
| 236 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), | 241 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
| 237 last_changed_(state.last_changed_) { | 242 last_changed_(state.last_changed_) { |
| 238 for (size_t i = 0; i < state.info_.size(); ++i) { | 243 for (size_t i = 0; i < state.info_.size(); ++i) { |
| 239 if (state.info_[i] && state.info_[i]->id() == i) { | 244 if (state.info_[i]) { |
| 240 info_[i] = new (state.info_.get_allocator().zone()) | 245 info_[i] = |
| 241 VirtualObject(*state.info_[i]); | 246 new (info_.get_allocator().zone()) VirtualObject(*state.info_[i]); |
| 242 } | |
| 243 } | |
| 244 for (size_t i = 0; i < state.info_.size(); ++i) { | |
| 245 if (state.info_[i] && state.info_[i]->id() != i) { | |
| 246 info_[i] = info_[state.info_[i]->id()]; | |
| 247 } | 247 } |
| 248 } | 248 } |
| 249 } | 249 } |
| 250 | 250 |
| 251 | 251 |
| 252 VirtualObject* VirtualState::GetVirtualObject(size_t id) { | 252 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
| 253 if (id >= info_.size()) return nullptr; | 253 return info_[alias]; |
| 254 return info_[id]; | |
| 255 } | 254 } |
| 256 | 255 |
| 257 | 256 |
| 258 VirtualObject* VirtualState::GetVirtualObject(Node* node) { | 257 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
| 259 return GetVirtualObject(node->id()); | 258 EscapeAnalysis::Alias alias, NodeId id, Zone* zone) { |
| 260 } | 259 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
| 261 | |
| 262 | |
| 263 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id, | |
| 264 Zone* zone) { | |
| 265 if (VirtualObject* obj = GetVirtualObject(id)) { | |
| 266 return obj; | 260 return obj; |
| 267 } | 261 } |
| 268 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); | 262 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); |
| 269 SetVirtualObject(id, obj); | 263 SetVirtualObject(alias, obj); |
| 270 return obj; | 264 return obj; |
| 271 } | 265 } |
| 272 | 266 |
| 273 | 267 |
| 274 void VirtualState::SetVirtualObject(NodeId id, VirtualObject* obj) { | 268 void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias, |
| 275 info_[id] = obj; | 269 VirtualObject* obj) { |
| 276 } | 270 info_[alias] = obj; |
| 277 | |
| 278 | |
| 279 bool VirtualState::UpdateFrom(NodeId id, VirtualObject* fromObj, Zone* zone) { | |
| 280 VirtualObject* obj = GetVirtualObject(id); | |
| 281 if (!obj) { | |
| 282 obj = new (zone) VirtualObject(*fromObj); | |
| 283 SetVirtualObject(id, obj); | |
| 284 if (FLAG_trace_turbo_escape) { | |
| 285 PrintF(" Taking field for #%d from %p\n", id, | |
| 286 static_cast<void*>(fromObj)); | |
| 287 } | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 if (obj->UpdateFrom(*fromObj)) { | |
| 292 if (FLAG_trace_turbo_escape) { | |
| 293 PrintF(" Updating field for #%d from %p\n", id, | |
| 294 static_cast<void*>(fromObj)); | |
| 295 } | |
| 296 return true; | |
| 297 } | |
| 298 | |
| 299 return false; | |
| 300 } | 271 } |
| 301 | 272 |
| 302 | 273 |
| 303 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { | 274 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { |
| 304 bool changed = false; | 275 bool changed = false; |
| 305 for (NodeId id = 0; id < size(); ++id) { | 276 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { |
| 306 VirtualObject* ls = GetVirtualObject(id); | 277 VirtualObject* ls = VirtualObjectFromAlias(alias); |
| 307 VirtualObject* rs = from->GetVirtualObject(id); | 278 VirtualObject* rs = from->VirtualObjectFromAlias(alias); |
| 308 | 279 |
| 309 if (rs == nullptr) { | 280 if (rs == nullptr) { |
| 310 continue; | 281 continue; |
| 311 } | 282 } |
| 312 | 283 |
| 313 if (ls == nullptr) { | 284 if (ls == nullptr) { |
| 314 ls = new (zone) VirtualObject(*rs); | 285 ls = new (zone) VirtualObject(*rs); |
| 315 SetVirtualObject(id, ls); | 286 SetVirtualObject(alias, ls); |
| 316 changed = true; | 287 changed = true; |
| 317 continue; | 288 continue; |
| 318 } | 289 } |
| 319 | 290 |
| 320 if (FLAG_trace_turbo_escape) { | 291 if (FLAG_trace_turbo_escape) { |
| 321 PrintF(" Updating fields of #%d\n", id); | 292 PrintF(" Updating fields of @%d\n", alias); |
| 322 } | 293 } |
| 323 | 294 |
| 324 changed = ls->UpdateFrom(*rs) || changed; | 295 changed = ls->UpdateFrom(*rs) || changed; |
| 325 } | 296 } |
| 326 return false; | 297 return false; |
| 327 } | 298 } |
| 328 | 299 |
| 329 | 300 |
| 330 namespace { | 301 namespace { |
| 331 | 302 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 } | 342 } |
| 372 } | 343 } |
| 373 return rep; | 344 return rep; |
| 374 } | 345 } |
| 375 | 346 |
| 376 | 347 |
| 377 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 348 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 378 CommonOperatorBuilder* common, Node* control) { | 349 CommonOperatorBuilder* common, Node* control) { |
| 379 DCHECK_GT(cache->states().size(), 0u); | 350 DCHECK_GT(cache->states().size(), 0u); |
| 380 bool changed = false; | 351 bool changed = false; |
| 381 for (NodeId id = 0; id < cache->min_size(); ++id) { | 352 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { |
| 382 size_t fields = cache->LoadVirtualObjectsFromStatesFor(id); | 353 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); |
| 383 if (cache->objects().size() == cache->states().size()) { | 354 if (cache->objects().size() == cache->states().size()) { |
| 384 // Don't process linked objects. | |
| 385 if (cache->objects()[0]->id() != id) continue; | |
| 386 if (FLAG_trace_turbo_escape) { | 355 if (FLAG_trace_turbo_escape) { |
| 387 PrintF(" Merging virtual objects of #%d\n", id); | 356 PrintF(" Merging virtual objects of @%d\n", alias); |
| 388 } | 357 } |
| 389 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); | 358 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( |
| 359 alias, cache->objects().front()->id(), zone); |
| 390 changed = mergeObject->ResizeFields(fields) || changed; | 360 changed = mergeObject->ResizeFields(fields) || changed; |
| 391 for (size_t i = 0; i < fields; ++i) { | 361 for (size_t i = 0; i < fields; ++i) { |
| 392 if (Node* field = cache->GetFields(i)) { | 362 if (Node* field = cache->GetFields(i)) { |
| 393 changed = mergeObject->SetField(i, field) || changed; | 363 changed = mergeObject->SetField(i, field) || changed; |
| 394 if (FLAG_trace_turbo_escape) { | 364 if (FLAG_trace_turbo_escape) { |
| 395 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); | 365 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); |
| 396 } | 366 } |
| 397 } else { | 367 } else { |
| 398 int value_input_count = static_cast<int>(cache->fields().size()); | 368 int value_input_count = static_cast<int>(cache->fields().size()); |
| 399 if (cache->fields().size() == cache->objects().size()) { | 369 if (cache->fields().size() == cache->objects().size()) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 rep, common->Phi(MachineRepresentation::kTagged, | 408 rep, common->Phi(MachineRepresentation::kTagged, |
| 439 value_input_count)); | 409 value_input_count)); |
| 440 } | 410 } |
| 441 } | 411 } |
| 442 } else { | 412 } else { |
| 443 changed = mergeObject->SetField(i, nullptr) || changed; | 413 changed = mergeObject->SetField(i, nullptr) || changed; |
| 444 } | 414 } |
| 445 } | 415 } |
| 446 } | 416 } |
| 447 } else { | 417 } else { |
| 448 SetVirtualObject(id, nullptr); | 418 SetVirtualObject(alias, nullptr); |
| 449 } | |
| 450 } | |
| 451 // Update linked objects. | |
| 452 for (NodeId id = 0; id < cache->min_size(); ++id) { | |
| 453 if (VirtualObject* obj = cache->states().front()->GetVirtualObject(id)) { | |
| 454 if (obj->id() != id) { | |
| 455 SetVirtualObject(id, GetVirtualObject(obj->id())); | |
| 456 } | |
| 457 } | 419 } |
| 458 } | 420 } |
| 459 return changed; | 421 return changed; |
| 460 } | 422 } |
| 461 | 423 |
| 462 | 424 |
| 463 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 425 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
| 464 Graph* graph, Zone* zone) | 426 Graph* graph, Zone* zone) |
| 465 : object_analysis_(object_analysis), | 427 : object_analysis_(object_analysis), |
| 466 graph_(graph), | 428 graph_(graph), |
| 467 zone_(zone), | 429 zone_(zone), |
| 468 info_(graph->NodeCount(), kUnknown, zone), | 430 status_(graph->NodeCount(), kUnknown, zone), |
| 469 queue_(zone) {} | 431 queue_(zone) {} |
| 470 | 432 |
| 471 | 433 |
| 472 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 434 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
| 473 | 435 |
| 474 | 436 |
| 475 bool EscapeStatusAnalysis::HasEntry(Node* node) { | 437 bool EscapeStatusAnalysis::HasEntry(Node* node) { |
| 476 return info_[node->id()] != kUnknown; | 438 return status_[node->id()] & (kTracked | kEscaped); |
| 477 } | 439 } |
| 478 | 440 |
| 479 | 441 |
| 480 bool EscapeStatusAnalysis::IsVirtual(Node* node) { | 442 bool EscapeStatusAnalysis::IsVirtual(Node* node) { |
| 481 return info_[node->id()] == kVirtual; | 443 return (status_[node->id()] & kTracked) && !(status_[node->id()] & kEscaped); |
| 482 } | 444 } |
| 483 | 445 |
| 484 | 446 |
| 485 bool EscapeStatusAnalysis::IsEscaped(Node* node) { | 447 bool EscapeStatusAnalysis::IsEscaped(Node* node) { |
| 486 return info_[node->id()] == kEscaped; | 448 return status_[node->id()] & kEscaped; |
| 487 } | 449 } |
| 488 | 450 |
| 489 | 451 |
| 490 bool EscapeStatusAnalysis::IsAllocation(Node* node) { | 452 bool EscapeStatusAnalysis::IsAllocation(Node* node) { |
| 491 return node->opcode() == IrOpcode::kAllocate || | 453 return node->opcode() == IrOpcode::kAllocate || |
| 492 node->opcode() == IrOpcode::kFinishRegion; | 454 node->opcode() == IrOpcode::kFinishRegion; |
| 493 } | 455 } |
| 494 | 456 |
| 495 | 457 |
| 496 bool EscapeStatusAnalysis::SetEscaped(Node* node) { | 458 bool EscapeStatusAnalysis::SetEscaped(Node* node) { |
| 497 bool changed = info_[node->id()] != kEscaped; | 459 bool changed = !(status_[node->id()] & kEscaped); |
| 498 info_[node->id()] = kEscaped; | 460 status_[node->id()] |= kEscaped | kTracked; |
| 499 return changed; | 461 return changed; |
| 500 } | 462 } |
| 501 | 463 |
| 502 | 464 |
| 503 void EscapeStatusAnalysis::Resize() { | 465 void EscapeStatusAnalysis::Resize() { |
| 504 info_.resize(graph()->NodeCount(), kUnknown); | 466 status_.resize(graph()->NodeCount(), kUnknown); |
| 505 } | 467 } |
| 506 | 468 |
| 507 | 469 |
| 508 size_t EscapeStatusAnalysis::size() { return info_.size(); } | 470 size_t EscapeStatusAnalysis::size() { return status_.size(); } |
| 509 | 471 |
| 510 | 472 |
| 511 void EscapeStatusAnalysis::Run() { | 473 void EscapeStatusAnalysis::Run() { |
| 512 Resize(); | 474 Resize(); |
| 513 ZoneVector<bool> visited(zone()); | |
| 514 visited.resize(graph()->NodeCount()); | |
| 515 queue_.push_back(graph()->end()); | 475 queue_.push_back(graph()->end()); |
| 476 status_[graph()->end()->id()] |= kOnStack; |
| 516 while (!queue_.empty()) { | 477 while (!queue_.empty()) { |
| 517 Node* node = queue_.front(); | 478 Node* node = queue_.front(); |
| 518 queue_.pop_front(); | 479 queue_.pop_front(); |
| 480 status_[node->id()] &= ~kOnStack; |
| 519 Process(node); | 481 Process(node); |
| 520 if (!visited[node->id()]) { | 482 status_[node->id()] |= kVisited; |
| 521 RevisitInputs(node); | 483 for (Edge edge : node->input_edges()) { |
| 484 Node* input = edge.to(); |
| 485 if (!(status_[input->id()] & (kVisited | kOnStack))) { |
| 486 queue_.push_back(input); |
| 487 status_[input->id()] |= kOnStack; |
| 488 } |
| 522 } | 489 } |
| 523 visited[node->id()] = true; | |
| 524 } | |
| 525 if (FLAG_trace_turbo_escape) { | |
| 526 DebugPrint(); | |
| 527 } | 490 } |
| 528 } | 491 } |
| 529 | 492 |
| 530 | 493 |
| 531 void EscapeStatusAnalysis::RevisitInputs(Node* node) { | 494 void EscapeStatusAnalysis::RevisitInputs(Node* node) { |
| 532 for (Edge edge : node->input_edges()) { | 495 for (Edge edge : node->input_edges()) { |
| 533 Node* input = edge.to(); | 496 Node* input = edge.to(); |
| 534 queue_.push_back(input); | 497 if (!(status_[input->id()] & kOnStack)) { |
| 498 queue_.push_back(input); |
| 499 status_[input->id()] |= kOnStack; |
| 500 } |
| 535 } | 501 } |
| 536 } | 502 } |
| 537 | 503 |
| 538 | 504 |
| 539 void EscapeStatusAnalysis::RevisitUses(Node* node) { | 505 void EscapeStatusAnalysis::RevisitUses(Node* node) { |
| 540 for (Edge edge : node->use_edges()) { | 506 for (Edge edge : node->use_edges()) { |
| 541 Node* use = edge.from(); | 507 Node* use = edge.from(); |
| 542 queue_.push_back(use); | 508 if (!(status_[use->id()] & kOnStack)) { |
| 509 queue_.push_back(use); |
| 510 status_[use->id()] |= kOnStack; |
| 511 } |
| 543 } | 512 } |
| 544 } | 513 } |
| 545 | 514 |
| 546 | 515 |
| 547 void EscapeStatusAnalysis::Process(Node* node) { | 516 void EscapeStatusAnalysis::Process(Node* node) { |
| 548 switch (node->opcode()) { | 517 switch (node->opcode()) { |
| 549 case IrOpcode::kAllocate: | 518 case IrOpcode::kAllocate: |
| 550 ProcessAllocate(node); | 519 ProcessAllocate(node); |
| 551 break; | 520 break; |
| 552 case IrOpcode::kFinishRegion: | 521 case IrOpcode::kFinishRegion: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 563 if (Node* rep = object_analysis_->GetReplacement(node)) { | 532 if (Node* rep = object_analysis_->GetReplacement(node)) { |
| 564 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { | 533 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { |
| 565 RevisitInputs(rep); | 534 RevisitInputs(rep); |
| 566 RevisitUses(rep); | 535 RevisitUses(rep); |
| 567 } | 536 } |
| 568 } | 537 } |
| 569 break; | 538 break; |
| 570 } | 539 } |
| 571 case IrOpcode::kPhi: | 540 case IrOpcode::kPhi: |
| 572 if (!HasEntry(node)) { | 541 if (!HasEntry(node)) { |
| 573 info_[node->id()] = kVirtual; | 542 status_[node->id()] |= kTracked; |
| 574 if (!IsAllocationPhi(node)) { | 543 if (!IsAllocationPhi(node)) { |
| 575 SetEscaped(node); | 544 SetEscaped(node); |
| 576 RevisitUses(node); | 545 RevisitUses(node); |
| 577 } | 546 } |
| 578 } | 547 } |
| 579 CheckUsesForEscape(node); | 548 CheckUsesForEscape(node); |
| 580 default: | 549 default: |
| 581 break; | 550 break; |
| 582 } | 551 } |
| 583 } | 552 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 620 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | 589 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", |
| 621 val->id(), val->op()->mnemonic(), to->id()); | 590 val->id(), val->op()->mnemonic(), to->id()); |
| 622 } | 591 } |
| 623 } | 592 } |
| 624 } | 593 } |
| 625 | 594 |
| 626 | 595 |
| 627 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 596 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { |
| 628 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 597 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 629 if (!HasEntry(node)) { | 598 if (!HasEntry(node)) { |
| 630 info_[node->id()] = kVirtual; | 599 status_[node->id()] |= kTracked; |
| 631 if (FLAG_trace_turbo_escape) { | 600 if (FLAG_trace_turbo_escape) { |
| 632 PrintF("Created status entry for node #%d (%s)\n", node->id(), | 601 PrintF("Created status entry for node #%d (%s)\n", node->id(), |
| 633 node->op()->mnemonic()); | 602 node->op()->mnemonic()); |
| 634 } | 603 } |
| 635 NumberMatcher size(node->InputAt(0)); | 604 NumberMatcher size(node->InputAt(0)); |
| 636 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 605 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 637 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 606 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 638 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 607 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 639 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 608 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 640 if (!size.HasValue() && SetEscaped(node)) { | 609 if (!size.HasValue() && SetEscaped(node)) { |
| 641 RevisitUses(node); | 610 RevisitUses(node); |
| 642 if (FLAG_trace_turbo_escape) { | 611 if (FLAG_trace_turbo_escape) { |
| 643 PrintF("Setting #%d to escaped because of non-const alloc\n", | 612 PrintF("Setting #%d to escaped because of non-const alloc\n", |
| 644 node->id()); | 613 node->id()); |
| 645 } | 614 } |
| 646 // This node is known to escape, uses do not have to be checked. | 615 // This node is known to escape, uses do not have to be checked. |
| 647 return; | 616 return; |
| 648 } | 617 } |
| 649 } | 618 } |
| 650 if (CheckUsesForEscape(node, true)) { | 619 if (CheckUsesForEscape(node, true)) { |
| 651 RevisitUses(node); | 620 RevisitUses(node); |
| 652 } | 621 } |
| 653 } | 622 } |
| 654 | 623 |
| 655 | 624 |
| 656 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, | 625 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
| 657 bool phi_escaping) { | 626 bool phi_escaping) { |
| 658 for (Edge edge : uses->use_edges()) { | 627 for (Edge edge : uses->use_edges()) { |
| 659 Node* use = edge.from(); | 628 Node* use = edge.from(); |
| 660 if (!NodeProperties::IsValueEdge(edge) && | 629 if (edge.index() >= use->op()->ValueInputCount() + |
| 661 !NodeProperties::IsContextEdge(edge)) | 630 OperatorProperties::GetContextInputCount(use->op())) |
| 662 continue; | 631 continue; |
| 663 switch (use->opcode()) { | 632 switch (use->opcode()) { |
| 633 case IrOpcode::kPhi: |
| 634 if (phi_escaping && SetEscaped(rep)) { |
| 635 if (FLAG_trace_turbo_escape) { |
| 636 PrintF( |
| 637 "Setting #%d (%s) to escaped because of use by phi node " |
| 638 "#%d (%s)\n", |
| 639 rep->id(), rep->op()->mnemonic(), use->id(), |
| 640 use->op()->mnemonic()); |
| 641 } |
| 642 return true; |
| 643 } |
| 644 // Fallthrough. |
| 664 case IrOpcode::kStoreField: | 645 case IrOpcode::kStoreField: |
| 665 case IrOpcode::kLoadField: | 646 case IrOpcode::kLoadField: |
| 666 case IrOpcode::kStoreElement: | 647 case IrOpcode::kStoreElement: |
| 667 case IrOpcode::kLoadElement: | 648 case IrOpcode::kLoadElement: |
| 668 case IrOpcode::kFrameState: | 649 case IrOpcode::kFrameState: |
| 669 case IrOpcode::kStateValues: | 650 case IrOpcode::kStateValues: |
| 670 case IrOpcode::kReferenceEqual: | 651 case IrOpcode::kReferenceEqual: |
| 671 case IrOpcode::kFinishRegion: | 652 case IrOpcode::kFinishRegion: |
| 672 case IrOpcode::kPhi: | 653 if (IsEscaped(use) && SetEscaped(rep)) { |
| 673 if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) { | |
| 674 if (FLAG_trace_turbo_escape) { | 654 if (FLAG_trace_turbo_escape) { |
| 675 PrintF( | 655 PrintF( |
| 676 "Setting #%d (%s) to escaped because of use by escaping node " | 656 "Setting #%d (%s) to escaped because of use by escaping node " |
| 677 "#%d (%s)\n", | 657 "#%d (%s)\n", |
| 678 rep->id(), rep->op()->mnemonic(), use->id(), | 658 rep->id(), rep->op()->mnemonic(), use->id(), |
| 679 use->op()->mnemonic()); | 659 use->op()->mnemonic()); |
| 680 } | |
| 681 return true; | |
| 682 } | |
| 683 if (phi_escaping && use->opcode() == IrOpcode::kPhi && | |
| 684 SetEscaped(rep)) { | |
| 685 if (FLAG_trace_turbo_escape) { | |
| 686 PrintF( | |
| 687 "Setting #%d (%s) to escaped because of use by phi node " | |
| 688 "#%d (%s)\n", | |
| 689 rep->id(), rep->op()->mnemonic(), use->id(), | |
| 690 use->op()->mnemonic()); | |
| 691 } | 660 } |
| 692 return true; | 661 return true; |
| 693 } | 662 } |
| 694 break; | 663 break; |
| 695 case IrOpcode::kObjectIsSmi: | 664 case IrOpcode::kObjectIsSmi: |
| 696 if (!IsAllocation(rep) && SetEscaped(rep)) { | 665 if (!IsAllocation(rep) && SetEscaped(rep)) { |
| 697 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 666 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
| 698 rep->id(), rep->op()->mnemonic(), use->id(), | 667 rep->id(), rep->op()->mnemonic(), use->id(), |
| 699 use->op()->mnemonic()); | 668 use->op()->mnemonic()); |
| 700 return true; | 669 return true; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 717 } | 686 } |
| 718 } | 687 } |
| 719 } | 688 } |
| 720 return false; | 689 return false; |
| 721 } | 690 } |
| 722 | 691 |
| 723 | 692 |
| 724 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { | 693 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { |
| 725 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 694 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
| 726 if (!HasEntry(node)) { | 695 if (!HasEntry(node)) { |
| 727 info_[node->id()] = kVirtual; | 696 status_[node->id()] |= kTracked; |
| 728 RevisitUses(node); | 697 RevisitUses(node); |
| 729 } | 698 } |
| 730 if (CheckUsesForEscape(node, true)) { | 699 if (CheckUsesForEscape(node, true)) { |
| 731 RevisitInputs(node); | 700 RevisitInputs(node); |
| 732 } | 701 } |
| 733 } | 702 } |
| 734 | 703 |
| 735 | 704 |
| 736 void EscapeStatusAnalysis::DebugPrint() { | 705 void EscapeStatusAnalysis::DebugPrint() { |
| 737 for (NodeId id = 0; id < info_.size(); id++) { | 706 for (NodeId id = 0; id < status_.size(); id++) { |
| 738 if (info_[id] != kUnknown) { | 707 if (status_[id] & kTracked) { |
| 739 PrintF("Node #%d is %s\n", id, | 708 PrintF("Node #%d is %s\n", id, |
| 740 info_[id] == kEscaped ? "escaping" : "virtual"); | 709 (status_[id] & kEscaped) ? "escaping" : "virtual"); |
| 741 } | 710 } |
| 742 } | 711 } |
| 743 } | 712 } |
| 744 | 713 |
| 745 | 714 |
| 746 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 715 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
| 747 Zone* zone) | 716 Zone* zone) |
| 748 : graph_(graph), | 717 : graph_(graph), |
| 749 common_(common), | 718 common_(common), |
| 750 zone_(zone), | 719 zone_(zone), |
| 751 virtual_states_(zone), | 720 virtual_states_(zone), |
| 752 replacements_(zone), | 721 replacements_(zone), |
| 753 escape_status_(this, graph, zone), | 722 escape_status_(this, graph, zone), |
| 754 cache_(new (zone) MergeCache(zone)) {} | 723 cache_(new (zone) MergeCache(zone)), |
| 724 aliases_(zone), |
| 725 next_free_alias_(0) {} |
| 755 | 726 |
| 756 | 727 |
| 757 EscapeAnalysis::~EscapeAnalysis() {} | 728 EscapeAnalysis::~EscapeAnalysis() {} |
| 758 | 729 |
| 759 | 730 |
| 760 void EscapeAnalysis::Run() { | 731 void EscapeAnalysis::Run() { |
| 761 replacements_.resize(graph()->NodeCount()); | 732 replacements_.resize(graph()->NodeCount()); |
| 733 AssignAliases(); |
| 762 RunObjectAnalysis(); | 734 RunObjectAnalysis(); |
| 763 escape_status_.Run(); | 735 escape_status_.Run(); |
| 764 } | 736 } |
| 765 | 737 |
| 766 | 738 |
| 739 void EscapeAnalysis::AssignAliases() { |
| 740 ZoneVector<Node*> stack(zone()); |
| 741 stack.push_back(graph()->end()); |
| 742 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 743 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| 744 aliases_[graph()->end()->id()] = kUntrackable; |
| 745 while (!stack.empty()) { |
| 746 Node* node = stack.back(); |
| 747 stack.pop_back(); |
| 748 switch (node->opcode()) { |
| 749 case IrOpcode::kAllocate: |
| 750 if (aliases_[node->id()] >= kUntrackable) { |
| 751 aliases_[node->id()] = NextAlias(); |
| 752 } |
| 753 break; |
| 754 case IrOpcode::kFinishRegion: { |
| 755 Node* allocate = NodeProperties::GetValueInput(node, 0); |
| 756 if (allocate->opcode() == IrOpcode::kAllocate) { |
| 757 if (aliases_[allocate->id()] >= kUntrackable) { |
| 758 if (aliases_[allocate->id()] == kNotReachable) { |
| 759 stack.push_back(allocate); |
| 760 } |
| 761 aliases_[allocate->id()] = NextAlias(); |
| 762 } |
| 763 aliases_[node->id()] = aliases_[allocate->id()]; |
| 764 } else { |
| 765 aliases_[node->id()] = NextAlias(); |
| 766 } |
| 767 break; |
| 768 } |
| 769 default: |
| 770 DCHECK_EQ(aliases_[node->id()], kUntrackable); |
| 771 break; |
| 772 } |
| 773 for (Edge edge : node->input_edges()) { |
| 774 Node* input = edge.to(); |
| 775 if (aliases_[input->id()] == kNotReachable) { |
| 776 stack.push_back(input); |
| 777 aliases_[input->id()] = kUntrackable; |
| 778 } |
| 779 } |
| 780 } |
| 781 |
| 782 if (FLAG_trace_turbo_escape) { |
| 783 PrintF("Discovered trackable nodes"); |
| 784 for (EscapeAnalysis::Alias id = 0; id < graph()->NodeCount(); ++id) { |
| 785 if (aliases_[id] < kUntrackable) { |
| 786 if (FLAG_trace_turbo_escape) { |
| 787 PrintF(" #%u", id); |
| 788 } |
| 789 } |
| 790 } |
| 791 PrintF("\n"); |
| 792 } |
| 793 } |
| 794 |
| 795 |
| 767 void EscapeAnalysis::RunObjectAnalysis() { | 796 void EscapeAnalysis::RunObjectAnalysis() { |
| 768 virtual_states_.resize(graph()->NodeCount()); | 797 virtual_states_.resize(graph()->NodeCount()); |
| 769 ZoneVector<Node*> stack(zone()); | 798 ZoneVector<Node*> stack(zone()); |
| 770 stack.push_back(graph()->start()); | 799 stack.push_back(graph()->start()); |
| 771 while (!stack.empty()) { | 800 while (!stack.empty()) { |
| 772 Node* node = stack.back(); | 801 Node* node = stack.back(); |
| 773 stack.pop_back(); | 802 stack.pop_back(); |
| 774 if (Process(node)) { | 803 if (aliases_[node->id()] != kNotReachable && Process(node)) { |
| 775 for (Edge edge : node->use_edges()) { | 804 for (Edge edge : node->use_edges()) { |
| 776 if (NodeProperties::IsEffectEdge(edge)) { | 805 if (NodeProperties::IsEffectEdge(edge)) { |
| 777 Node* use = edge.from(); | 806 Node* use = edge.from(); |
| 778 if ((use->opcode() != IrOpcode::kLoadField && | 807 if ((use->opcode() != IrOpcode::kLoadField && |
| 779 use->opcode() != IrOpcode::kLoadElement) || | 808 use->opcode() != IrOpcode::kLoadElement) || |
| 780 !IsDanglingEffectNode(use)) { | 809 !IsDanglingEffectNode(use)) { |
| 781 stack.push_back(use); | 810 stack.push_back(use); |
| 782 } | 811 } |
| 783 } | 812 } |
| 784 } | 813 } |
| 785 // First process loads: dangling loads are a problem otherwise. | 814 // First process loads: dangling loads are a problem otherwise. |
| 786 for (Edge edge : node->use_edges()) { | 815 for (Edge edge : node->use_edges()) { |
| 787 if (NodeProperties::IsEffectEdge(edge)) { | 816 if (NodeProperties::IsEffectEdge(edge)) { |
| 788 Node* use = edge.from(); | 817 Node* use = edge.from(); |
| 789 if ((use->opcode() == IrOpcode::kLoadField || | 818 if ((use->opcode() == IrOpcode::kLoadField || |
| 790 use->opcode() == IrOpcode::kLoadElement) && | 819 use->opcode() == IrOpcode::kLoadElement) && |
| 791 | |
| 792 | |
| 793 IsDanglingEffectNode(use)) { | 820 IsDanglingEffectNode(use)) { |
| 794 stack.push_back(use); | 821 stack.push_back(use); |
| 795 } | 822 } |
| 796 } | 823 } |
| 797 } | 824 } |
| 798 } | 825 } |
| 799 } | 826 } |
| 800 if (FLAG_trace_turbo_escape) { | 827 if (FLAG_trace_turbo_escape) { |
| 801 DebugPrint(); | 828 DebugPrint(); |
| 802 } | 829 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { | 939 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
| 913 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 940 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
| 914 node->op()->mnemonic()); | 941 node->op()->mnemonic()); |
| 915 UNREACHABLE(); | 942 UNREACHABLE(); |
| 916 } | 943 } |
| 917 Node* effect = NodeProperties::GetEffectInput(node); | 944 Node* effect = NodeProperties::GetEffectInput(node); |
| 918 // Break the cycle for effect phis. | 945 // Break the cycle for effect phis. |
| 919 if (effect->opcode() == IrOpcode::kEffectPhi) { | 946 if (effect->opcode() == IrOpcode::kEffectPhi) { |
| 920 if (virtual_states_[effect->id()] == nullptr) { | 947 if (virtual_states_[effect->id()] == nullptr) { |
| 921 virtual_states_[effect->id()] = | 948 virtual_states_[effect->id()] = |
| 922 new (zone()) VirtualState(zone(), graph()->NodeCount()); | 949 new (zone()) VirtualState(zone(), AliasCount()); |
| 923 } | 950 } |
| 924 } | 951 } |
| 925 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 952 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
| 926 if (IsEffectBranchPoint(effect)) { | 953 if (IsEffectBranchPoint(effect)) { |
| 927 if (FLAG_trace_turbo_escape) { | 954 if (FLAG_trace_turbo_escape) { |
| 928 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", | 955 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", |
| 929 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 956 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
| 930 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 957 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 931 } | 958 } |
| 932 if (!virtual_states_[node->id()]) { | 959 if (!virtual_states_[node->id()]) { |
| 933 virtual_states_[node->id()] = | 960 virtual_states_[node->id()] = |
| 934 new (zone()) VirtualState(*virtual_states_[effect->id()]); | 961 new (zone()) VirtualState(*virtual_states_[effect->id()]); |
| 935 } else { | 962 } else { |
| 936 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 963 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
| 937 zone()); | 964 zone()); |
| 938 } | 965 } |
| 939 } else { | 966 } else { |
| 940 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 967 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
| 941 if (FLAG_trace_turbo_escape) { | 968 if (FLAG_trace_turbo_escape) { |
| 942 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", | 969 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", |
| 943 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 970 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
| 944 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 971 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 945 } | 972 } |
| 946 } | 973 } |
| 947 } | 974 } |
| 948 | 975 |
| 949 | 976 |
| 950 void EscapeAnalysis::ProcessStart(Node* node) { | 977 void EscapeAnalysis::ProcessStart(Node* node) { |
| 951 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 978 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
| 952 virtual_states_[node->id()] = | 979 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount()); |
| 953 new (zone()) VirtualState(zone(), graph()->NodeCount()); | |
| 954 } | 980 } |
| 955 | 981 |
| 956 | 982 |
| 957 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 983 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
| 958 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 984 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
| 959 bool changed = false; | 985 bool changed = false; |
| 960 | 986 |
| 961 VirtualState* mergeState = virtual_states_[node->id()]; | 987 VirtualState* mergeState = virtual_states_[node->id()]; |
| 962 if (!mergeState) { | 988 if (!mergeState) { |
| 963 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); | 989 mergeState = new (zone()) VirtualState(zone(), AliasCount()); |
| 964 virtual_states_[node->id()] = mergeState; | 990 virtual_states_[node->id()] = mergeState; |
| 965 changed = true; | 991 changed = true; |
| 966 if (FLAG_trace_turbo_escape) { | 992 if (FLAG_trace_turbo_escape) { |
| 967 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), | 993 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), |
| 968 static_cast<void*>(mergeState)); | 994 static_cast<void*>(mergeState)); |
| 969 } | 995 } |
| 970 } else if (mergeState->GetLastChanged() != node) { | 996 } else if (mergeState->GetLastChanged() != node) { |
| 971 changed = true; | 997 changed = true; |
| 972 } | 998 } |
| 973 | 999 |
| 974 cache_->Clear(); | 1000 cache_->Clear(); |
| 975 | 1001 |
| 976 if (FLAG_trace_turbo_escape) { | 1002 if (FLAG_trace_turbo_escape) { |
| 977 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), | 1003 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), |
| 978 static_cast<void*>(mergeState)); | 1004 static_cast<void*>(mergeState)); |
| 979 } | 1005 } |
| 980 | 1006 |
| 981 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1007 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
| 982 Node* input = NodeProperties::GetEffectInput(node, i); | 1008 Node* input = NodeProperties::GetEffectInput(node, i); |
| 983 VirtualState* state = virtual_states_[input->id()]; | 1009 VirtualState* state = virtual_states_[input->id()]; |
| 984 if (state) { | 1010 if (state) { |
| 985 cache_->push_back(state); | 1011 cache_->states().push_back(state); |
| 986 } | 1012 } |
| 987 if (FLAG_trace_turbo_escape) { | 1013 if (FLAG_trace_turbo_escape) { |
| 988 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1014 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
| 989 input->op()->mnemonic()); | 1015 input->op()->mnemonic()); |
| 990 } | 1016 } |
| 991 } | 1017 } |
| 992 if (FLAG_trace_turbo_escape) { | 1018 if (FLAG_trace_turbo_escape) { |
| 993 PrintF("\n"); | 1019 PrintF("\n"); |
| 994 } | 1020 } |
| 995 | 1021 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1011 } | 1037 } |
| 1012 return changed; | 1038 return changed; |
| 1013 } | 1039 } |
| 1014 | 1040 |
| 1015 | 1041 |
| 1016 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1042 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| 1017 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1043 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 1018 ForwardVirtualState(node); | 1044 ForwardVirtualState(node); |
| 1019 | 1045 |
| 1020 // Check if we have already processed this node. | 1046 // Check if we have already processed this node. |
| 1021 if (virtual_states_[node->id()]->GetVirtualObject(node)) return; | 1047 if (virtual_states_[node->id()]->VirtualObjectFromAlias( |
| 1048 aliases_[node->id()])) { |
| 1049 return; |
| 1050 } |
| 1022 | 1051 |
| 1023 NumberMatcher size(node->InputAt(0)); | 1052 NumberMatcher size(node->InputAt(0)); |
| 1024 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1053 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 1025 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1054 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 1026 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1055 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 1027 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1056 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 1028 if (size.HasValue()) { | 1057 if (size.HasValue()) { |
| 1029 virtual_states_[node->id()]->SetVirtualObject( | 1058 virtual_states_[node->id()]->SetVirtualObject( |
| 1030 node->id(), new (zone()) VirtualObject(node->id(), zone(), | 1059 aliases_[node->id()], |
| 1031 size.Value() / kPointerSize)); | 1060 new (zone()) |
| 1061 VirtualObject(node->id(), zone(), size.Value() / kPointerSize)); |
| 1032 } else { | 1062 } else { |
| 1033 virtual_states_[node->id()]->SetVirtualObject( | 1063 virtual_states_[node->id()]->SetVirtualObject( |
| 1034 node->id(), new (zone()) VirtualObject(node->id(), zone())); | 1064 aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone())); |
| 1035 } | 1065 } |
| 1036 virtual_states_[node->id()]->LastChangedAt(node); | 1066 virtual_states_[node->id()]->LastChangedAt(node); |
| 1037 } | 1067 } |
| 1038 | 1068 |
| 1039 | 1069 |
| 1040 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1070 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
| 1041 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1071 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
| 1042 ForwardVirtualState(node); | 1072 ForwardVirtualState(node); |
| 1043 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1073 Node* allocation = NodeProperties::GetValueInput(node, 0); |
| 1044 if (allocation->opcode() == IrOpcode::kAllocate) { | 1074 if (allocation->opcode() == IrOpcode::kAllocate) { |
| 1045 VirtualState* states = virtual_states_[node->id()]; | 1075 VirtualState* state = virtual_states_[node->id()]; |
| 1046 DCHECK_NOT_NULL(states->GetVirtualObject(allocation)); | 1076 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { |
| 1047 if (!states->GetVirtualObject(node->id())) { | 1077 VirtualObject* vobj_alloc = |
| 1048 states->SetVirtualObject(node->id(), | 1078 state->VirtualObjectFromAlias(aliases_[allocation->id()]); |
| 1049 states->GetVirtualObject(allocation)); | 1079 DCHECK_NOT_NULL(vobj_alloc); |
| 1080 state->SetVirtualObject(aliases_[node->id()], vobj_alloc); |
| 1050 if (FLAG_trace_turbo_escape) { | 1081 if (FLAG_trace_turbo_escape) { |
| 1051 PrintF("Linked finish region node #%d to node #%d\n", node->id(), | 1082 PrintF("Linked finish region node #%d to node #%d\n", node->id(), |
| 1052 allocation->id()); | 1083 allocation->id()); |
| 1053 } | 1084 } |
| 1054 states->LastChangedAt(node); | 1085 state->LastChangedAt(node); |
| 1055 } | 1086 } |
| 1056 } | 1087 } |
| 1057 } | 1088 } |
| 1058 | 1089 |
| 1059 | 1090 |
| 1060 Node* EscapeAnalysis::replacement(NodeId id) { | 1091 Node* EscapeAnalysis::replacement(NodeId id) { |
| 1061 if (id >= replacements_.size()) return nullptr; | 1092 if (id >= replacements_.size()) return nullptr; |
| 1062 return replacements_[id]; | 1093 return replacements_[id]; |
| 1063 } | 1094 } |
| 1064 | 1095 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1132 } | 1163 } |
| 1133 | 1164 |
| 1134 | 1165 |
| 1135 bool EscapeAnalysis::SetEscaped(Node* node) { | 1166 bool EscapeAnalysis::SetEscaped(Node* node) { |
| 1136 return escape_status_.SetEscaped(node); | 1167 return escape_status_.SetEscaped(node); |
| 1137 } | 1168 } |
| 1138 | 1169 |
| 1139 | 1170 |
| 1140 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1171 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| 1141 if (VirtualState* states = virtual_states_[at->id()]) { | 1172 if (VirtualState* states = virtual_states_[at->id()]) { |
| 1142 return states->GetVirtualObject(id); | 1173 return states->VirtualObjectFromAlias(aliases_[id]); |
| 1143 } | 1174 } |
| 1144 return nullptr; | 1175 return nullptr; |
| 1145 } | 1176 } |
| 1146 | 1177 |
| 1147 | 1178 |
| 1148 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1179 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
| 1149 Node* node) { | 1180 Node* node) { |
| 1150 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); | 1181 VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node)); |
| 1151 while (obj && replacement(obj->id()) && | 1182 while (obj && replacement(obj->id())) { |
| 1152 state->GetVirtualObject(replacement(obj->id()))) { | 1183 if (VirtualObject* next = GetVirtualObject(state, replacement(obj->id()))) { |
| 1153 obj = state->GetVirtualObject(replacement(obj->id())); | 1184 obj = next; |
| 1185 } else { |
| 1186 break; |
| 1187 } |
| 1154 } | 1188 } |
| 1155 return obj; | 1189 return obj; |
| 1156 } | 1190 } |
| 1157 | 1191 |
| 1158 | 1192 |
| 1159 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1193 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
| 1160 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1194 DCHECK(IsVirtual(left) && IsVirtual(right)); |
| 1161 left = ResolveReplacement(left); | 1195 left = ResolveReplacement(left); |
| 1162 right = ResolveReplacement(right); | 1196 right = ResolveReplacement(right); |
| 1163 if (IsEquivalentPhi(left, right)) { | 1197 if (IsEquivalentPhi(left, right)) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1178 if (FLAG_trace_turbo_escape) { | 1212 if (FLAG_trace_turbo_escape) { |
| 1179 PrintF("Load #%d from phi #%d", node->id(), from->id()); | 1213 PrintF("Load #%d from phi #%d", node->id(), from->id()); |
| 1180 } | 1214 } |
| 1181 | 1215 |
| 1182 cache_->fields().clear(); | 1216 cache_->fields().clear(); |
| 1183 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1217 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
| 1184 Node* input = NodeProperties::GetValueInput(node, i); | 1218 Node* input = NodeProperties::GetValueInput(node, i); |
| 1185 cache_->fields().push_back(input); | 1219 cache_->fields().push_back(input); |
| 1186 } | 1220 } |
| 1187 | 1221 |
| 1188 cache_->LoadVirtualObjectsForFieldsFrom(state); | 1222 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_); |
| 1189 if (cache_->objects().size() == cache_->fields().size()) { | 1223 if (cache_->objects().size() == cache_->fields().size()) { |
| 1190 cache_->GetFields(offset); | 1224 cache_->GetFields(offset); |
| 1191 if (cache_->fields().size() == cache_->objects().size()) { | 1225 if (cache_->fields().size() == cache_->objects().size()) { |
| 1192 Node* rep = replacement(node); | 1226 Node* rep = replacement(node); |
| 1193 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1227 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
| 1194 int value_input_count = static_cast<int>(cache_->fields().size()); | 1228 int value_input_count = static_cast<int>(cache_->fields().size()); |
| 1195 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1229 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
| 1196 Node* phi = graph()->NewNode( | 1230 Node* phi = graph()->NewNode( |
| 1197 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1231 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
| 1198 value_input_count + 1, &cache_->fields().front()); | 1232 value_input_count + 1, &cache_->fields().front()); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1380 } | 1414 } |
| 1381 } | 1415 } |
| 1382 return new_object_state; | 1416 return new_object_state; |
| 1383 } | 1417 } |
| 1384 } | 1418 } |
| 1385 } | 1419 } |
| 1386 return nullptr; | 1420 return nullptr; |
| 1387 } | 1421 } |
| 1388 | 1422 |
| 1389 | 1423 |
| 1390 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { | 1424 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) { |
| 1391 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); | 1425 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(), |
| 1426 object->field_count()); |
| 1392 for (size_t i = 0; i < object->field_count(); ++i) { | 1427 for (size_t i = 0; i < object->field_count(); ++i) { |
| 1393 if (Node* f = object->GetField(i)) { | 1428 if (Node* f = object->GetField(i)) { |
| 1394 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1429 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
| 1395 } | 1430 } |
| 1396 } | 1431 } |
| 1397 } | 1432 } |
| 1398 | 1433 |
| 1399 | 1434 |
| 1400 void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 1435 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
| 1401 PrintF("Dumping object state %p\n", static_cast<void*>(state)); | 1436 PrintF("Dumping object state %p\n", static_cast<void*>(state)); |
| 1402 for (size_t id = 0; id < state->size(); id++) { | 1437 for (Alias alias = 0; alias < AliasCount(); ++alias) { |
| 1403 if (VirtualObject* object = state->GetVirtualObject(id)) { | 1438 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { |
| 1404 if (object->id() == id) { | 1439 DebugPrintObject(object, alias); |
| 1405 DebugPrintObject(object, static_cast<int>(id)); | |
| 1406 } else { | |
| 1407 PrintF(" Object #%zu links to object #%d\n", id, object->id()); | |
| 1408 } | |
| 1409 } | 1440 } |
| 1410 } | 1441 } |
| 1411 } | 1442 } |
| 1412 | 1443 |
| 1413 | 1444 |
| 1414 void EscapeAnalysis::DebugPrint() { | 1445 void EscapeAnalysis::DebugPrint() { |
| 1415 ZoneVector<VirtualState*> object_states(zone()); | 1446 ZoneVector<VirtualState*> object_states(zone()); |
| 1416 for (NodeId id = 0; id < virtual_states_.size(); id++) { | 1447 for (NodeId id = 0; id < virtual_states_.size(); id++) { |
| 1417 if (VirtualState* states = virtual_states_[id]) { | 1448 if (VirtualState* states = virtual_states_[id]) { |
| 1418 if (std::find(object_states.begin(), object_states.end(), states) == | 1449 if (std::find(object_states.begin(), object_states.end(), states) == |
| 1419 object_states.end()) { | 1450 object_states.end()) { |
| 1420 object_states.push_back(states); | 1451 object_states.push_back(states); |
| 1421 } | 1452 } |
| 1422 } | 1453 } |
| 1423 } | 1454 } |
| 1424 for (size_t n = 0; n < object_states.size(); n++) { | 1455 for (size_t n = 0; n < object_states.size(); n++) { |
| 1425 DebugPrintState(object_states[n]); | 1456 DebugPrintState(object_states[n]); |
| 1426 } | 1457 } |
| 1427 } | 1458 } |
| 1428 | 1459 |
| 1460 |
| 1461 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
| 1462 Node* node) { |
| 1463 if (node->id() >= aliases_.size()) return nullptr; |
| 1464 Alias alias = aliases_[node->id()]; |
| 1465 if (alias >= state->size()) return nullptr; |
| 1466 return state->VirtualObjectFromAlias(alias); |
| 1467 } |
| 1468 |
| 1429 } // namespace compiler | 1469 } // namespace compiler |
| 1430 } // namespace internal | 1470 } // namespace internal |
| 1431 } // namespace v8 | 1471 } // namespace v8 |
| OLD | NEW |