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" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 } | 109 } |
| 110 bool AllFieldsClear() { | 110 bool AllFieldsClear() { |
| 111 for (size_t i = 0; i < fields_.size(); ++i) { | 111 for (size_t i = 0; i < fields_.size(); ++i) { |
| 112 if (fields_[i] != nullptr) { | 112 if (fields_[i] != nullptr) { |
| 113 return false; | 113 return false; |
| 114 } | 114 } |
| 115 } | 115 } |
| 116 return true; | 116 return true; |
| 117 } | 117 } |
| 118 bool UpdateFrom(const VirtualObject& other); | 118 bool UpdateFrom(const VirtualObject& other); |
| 119 bool MergeFrom(MergeCache* cache, Node* at, Graph* graph, | |
| 120 CommonOperatorBuilder* common); | |
| 119 void SetObjectState(Node* node) { object_state_ = node; } | 121 void SetObjectState(Node* node) { object_state_ = node; } |
| 120 Node* GetObjectState() const { return object_state_; } | 122 Node* GetObjectState() const { return object_state_; } |
| 121 bool IsCopyRequired() const { return status_ & kCopyRequired; } | 123 bool IsCopyRequired() const { return status_ & kCopyRequired; } |
| 122 void SetCopyRequired() { status_ |= kCopyRequired; } | 124 void SetCopyRequired() { status_ |= kCopyRequired; } |
| 123 bool NeedCopyForModification() { | 125 bool NeedCopyForModification() { |
| 124 if (!IsCopyRequired() || !IsInitialized()) { | 126 if (!IsCopyRequired() || !IsInitialized()) { |
| 125 return false; | 127 return false; |
| 126 } | 128 } |
| 127 return true; | 129 return true; |
| 128 } | 130 } |
| 129 | 131 |
| 130 NodeId id() const { return id_; } | 132 NodeId id() const { return id_; } |
| 131 void id(NodeId id) { id_ = id; } | 133 void id(NodeId id) { id_ = id; } |
| 132 | 134 |
| 133 private: | 135 private: |
| 136 bool MergeFields(size_t i, Node* at, MergeCache* cache, Graph* graph, | |
| 137 CommonOperatorBuilder* common); | |
| 138 | |
| 134 NodeId id_; | 139 NodeId id_; |
| 135 StatusFlags status_; | 140 StatusFlags status_; |
| 136 ZoneVector<Node*> fields_; | 141 ZoneVector<Node*> fields_; |
| 137 ZoneVector<bool> phi_; | 142 ZoneVector<bool> phi_; |
| 138 Node* object_state_; | 143 Node* object_state_; |
| 139 VirtualState* owner_; | 144 VirtualState* owner_; |
| 140 | 145 |
| 141 DISALLOW_COPY_AND_ASSIGN(VirtualObject); | 146 DISALLOW_COPY_AND_ASSIGN(VirtualObject); |
| 142 }; | 147 }; |
| 143 | 148 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 169 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), | 174 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
| 170 owner_(owner) { | 175 owner_(owner) { |
| 171 for (size_t i = 0; i < info_.size(); ++i) { | 176 for (size_t i = 0; i < info_.size(); ++i) { |
| 172 if (state.info_[i]) { | 177 if (state.info_[i]) { |
| 173 info_[i] = state.info_[i]; | 178 info_[i] = state.info_[i]; |
| 174 } | 179 } |
| 175 } | 180 } |
| 176 } | 181 } |
| 177 | 182 |
| 178 VirtualObject* VirtualObjectFromAlias(size_t alias); | 183 VirtualObject* VirtualObjectFromAlias(size_t alias); |
| 179 VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, | |
| 180 size_t fields, | |
| 181 bool initialized, Zone* zone, | |
| 182 bool force_copy); | |
| 183 void SetVirtualObject(Alias alias, VirtualObject* state); | 184 void SetVirtualObject(Alias alias, VirtualObject* state); |
| 184 bool UpdateFrom(VirtualState* state, Zone* zone); | 185 bool UpdateFrom(VirtualState* state, Zone* zone); |
| 185 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 186 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 186 CommonOperatorBuilder* common, Node* control, int arity); | 187 CommonOperatorBuilder* common, Node* at); |
| 187 size_t size() const { return info_.size(); } | 188 size_t size() const { return info_.size(); } |
| 188 Node* owner() const { return owner_; } | 189 Node* owner() const { return owner_; } |
| 189 VirtualObject* Copy(VirtualObject* obj, Alias alias); | 190 VirtualObject* Copy(VirtualObject* obj, Alias alias); |
| 190 void SetCopyRequired() { | 191 void SetCopyRequired() { |
| 191 for (VirtualObject* obj : info_) { | 192 for (VirtualObject* obj : info_) { |
| 192 if (obj) obj->SetCopyRequired(); | 193 if (obj) obj->SetCopyRequired(); |
| 193 } | 194 } |
| 194 } | 195 } |
| 195 | 196 |
| 196 private: | 197 private: |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 static_cast<void*>(this), alias, obj->id(), static_cast<void*>(obj), | 282 static_cast<void*>(this), alias, obj->id(), static_cast<void*>(obj), |
| 282 static_cast<void*>(new_obj)); | 283 static_cast<void*>(new_obj)); |
| 283 info_[alias] = new_obj; | 284 info_[alias] = new_obj; |
| 284 return new_obj; | 285 return new_obj; |
| 285 } | 286 } |
| 286 | 287 |
| 287 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { | 288 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
| 288 return info_[alias]; | 289 return info_[alias]; |
| 289 } | 290 } |
| 290 | 291 |
| 291 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( | |
| 292 Alias alias, NodeId id, size_t field_number, bool initialized, Zone* zone, | |
| 293 bool force_copy) { | |
| 294 if (!force_copy) { | |
| 295 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { | |
| 296 return obj; | |
| 297 } | |
| 298 } | |
| 299 VirtualObject* obj = new (zone) VirtualObject(id, this, zone, 0, initialized); | |
| 300 SetVirtualObject(alias, obj); | |
| 301 return obj; | |
| 302 } | |
| 303 | |
| 304 void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { | 292 void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { |
| 305 info_[alias] = obj; | 293 info_[alias] = obj; |
| 306 } | 294 } |
| 307 | 295 |
| 308 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { | 296 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { |
| 309 if (from == this) return false; | 297 if (from == this) return false; |
| 310 bool changed = false; | 298 bool changed = false; |
| 311 for (Alias alias = 0; alias < size(); ++alias) { | 299 for (Alias alias = 0; alias < size(); ++alias) { |
| 312 VirtualObject* ls = VirtualObjectFromAlias(alias); | 300 VirtualObject* ls = VirtualObjectFromAlias(alias); |
| 313 VirtualObject* rs = from->VirtualObjectFromAlias(alias); | 301 VirtualObject* rs = from->VirtualObjectFromAlias(alias); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i)); | 343 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i)); |
| 356 if (!IsEquivalentPhi(input, inputs[i])) { | 344 if (!IsEquivalentPhi(input, inputs[i])) { |
| 357 return false; | 345 return false; |
| 358 } | 346 } |
| 359 } | 347 } |
| 360 return true; | 348 return true; |
| 361 } | 349 } |
| 362 | 350 |
| 363 } // namespace | 351 } // namespace |
| 364 | 352 |
| 365 Node* EscapeAnalysis::GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) { | 353 bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache, |
| 366 Node* rep = GetReplacement(objs.front()->id()); | 354 Graph* graph, CommonOperatorBuilder* common) { |
| 367 for (VirtualObject* obj : objs) { | 355 bool changed = false; |
| 368 if (GetReplacement(obj->id()) != rep) { | 356 int value_input_count = static_cast<int>(cache->fields().size()); |
| 369 return nullptr; | 357 Node* rep = GetField(i); |
| 358 if (!rep || !IsCreatedPhi(i)) { | |
| 359 Node* control = NodeProperties::GetControlInput(at); | |
| 360 cache->fields().push_back(control); | |
| 361 Node* phi = graph->NewNode( | |
| 362 common->Phi(MachineRepresentation::kTagged, value_input_count), | |
| 363 value_input_count + 1, &cache->fields().front()); | |
| 364 SetField(i, phi, true); | |
| 365 #ifdef DEBUG | |
| 366 if (FLAG_trace_turbo_escape) { | |
| 367 PrintF(" Creating Phi #%d as merge of", phi->id()); | |
| 368 for (int i = 0; i < value_input_count; i++) { | |
| 369 PrintF(" #%d (%s)", cache->fields()[i]->id(), | |
| 370 cache->fields()[i]->op()->mnemonic()); | |
| 371 } | |
| 372 PrintF("\n"); | |
| 373 } | |
| 374 #endif | |
| 375 changed = true; | |
| 376 } else { | |
| 377 DCHECK(rep->opcode() == IrOpcode::kPhi); | |
| 378 for (int n = 0; n < value_input_count; ++n) { | |
| 379 Node* old = NodeProperties::GetValueInput(rep, n); | |
| 380 if (old != cache->fields()[n]) { | |
| 381 changed = true; | |
| 382 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); | |
| 383 } | |
| 370 } | 384 } |
| 371 } | 385 } |
| 372 return rep; | 386 return changed; |
| 387 } | |
| 388 | |
| 389 bool VirtualObject::MergeFrom(MergeCache* cache, Node* at, Graph* graph, | |
| 390 CommonOperatorBuilder* common) { | |
| 391 DCHECK(at->opcode() == IrOpcode::kEffectPhi || | |
| 392 at->opcode() == IrOpcode::kPhi); | |
| 393 bool changed = false; | |
| 394 for (size_t i = 0; i < field_count(); ++i) { | |
| 395 if (Node* field = cache->GetFields(i)) { | |
| 396 changed = changed || GetField(i) != field; | |
| 397 SetField(i, field); | |
| 398 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); | |
| 399 } else { | |
| 400 int arity = at->opcode() == IrOpcode::kEffectPhi | |
| 401 ? at->op()->EffectInputCount() | |
| 402 : at->op()->ValueInputCount(); | |
| 403 if (cache->fields().size() == arity) { | |
| 404 changed = MergeFields(i, at, cache, graph, common) || changed; | |
| 405 } else { | |
| 406 if (GetField(i) != nullptr) { | |
| 407 TRACE(" Field %zu cleared\n", i); | |
| 408 changed = true; | |
| 409 } | |
| 410 SetField(i, nullptr); | |
| 411 } | |
| 412 } | |
| 413 } | |
| 414 return changed; | |
| 373 } | 415 } |
| 374 | 416 |
| 375 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 417 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 376 CommonOperatorBuilder* common, Node* control, | 418 CommonOperatorBuilder* common, Node* at) { |
| 377 int arity) { | |
| 378 DCHECK_GT(cache->states().size(), 0u); | 419 DCHECK_GT(cache->states().size(), 0u); |
| 379 bool changed = false; | 420 bool changed = false; |
| 380 for (Alias alias = 0; alias < size(); ++alias) { | 421 for (Alias alias = 0; alias < size(); ++alias) { |
| 381 cache->objects().clear(); | 422 cache->objects().clear(); |
| 382 VirtualObject* mergeObject = VirtualObjectFromAlias(alias); | 423 VirtualObject* mergeObject = VirtualObjectFromAlias(alias); |
| 383 bool copy_merge_object = false; | 424 bool copy_merge_object = false; |
| 384 size_t fields = std::numeric_limits<size_t>::max(); | 425 size_t fields = std::numeric_limits<size_t>::max(); |
| 385 for (VirtualState* state : cache->states()) { | 426 for (VirtualState* state : cache->states()) { |
| 386 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { | 427 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
| 387 cache->objects().push_back(obj); | 428 cache->objects().push_back(obj); |
| 388 if (mergeObject == obj) { | 429 if (mergeObject == obj) { |
| 389 copy_merge_object = true; | 430 copy_merge_object = true; |
| 390 changed = true; | |
| 391 } | 431 } |
| 392 fields = std::min(obj->field_count(), fields); | 432 fields = std::min(obj->field_count(), fields); |
| 393 } | 433 } |
| 394 } | 434 } |
| 395 if (cache->objects().size() == cache->states().size()) { | 435 if (cache->objects().size() == cache->states().size()) { |
| 396 mergeObject = GetOrCreateTrackedVirtualObject( | 436 if (!mergeObject) { |
| 397 alias, cache->objects().front()->id(), | 437 VirtualObject* obj = new (zone) |
| 398 cache->objects().front()->IsInitialized(), fields, zone, | 438 VirtualObject(cache->objects().front()->id(), this, zone, fields, |
| 399 copy_merge_object); | 439 cache->objects().front()->IsInitialized()); |
| 440 SetVirtualObject(alias, obj); | |
| 441 mergeObject = obj; | |
| 442 changed = true; | |
| 443 } else if (copy_merge_object) { | |
| 444 VirtualObject* obj = new (zone) VirtualObject(this, *mergeObject); | |
| 445 SetVirtualObject(alias, obj); | |
| 446 mergeObject = obj; | |
| 447 changed = true; | |
| 448 } else { | |
| 449 changed = mergeObject->ResizeFields(fields) || changed; | |
| 450 } | |
| 400 #ifdef DEBUG | 451 #ifdef DEBUG |
| 401 if (FLAG_trace_turbo_escape) { | 452 if (FLAG_trace_turbo_escape) { |
| 402 PrintF(" Alias @%d, merging into %p virtual objects", alias, | 453 PrintF(" Alias @%d, merging into %p virtual objects", alias, |
| 403 static_cast<void*>(mergeObject)); | 454 static_cast<void*>(mergeObject)); |
| 404 for (size_t i = 0; i < cache->objects().size(); i++) { | 455 for (size_t i = 0; i < cache->objects().size(); i++) { |
| 405 PrintF(" %p", static_cast<void*>(cache->objects()[i])); | 456 PrintF(" %p", static_cast<void*>(cache->objects()[i])); |
| 406 } | 457 } |
| 407 PrintF("\n"); | 458 PrintF("\n"); |
| 408 } | 459 } |
| 409 #endif // DEBUG | 460 #endif // DEBUG |
| 410 changed = mergeObject->ResizeFields(fields) || changed; | 461 changed = mergeObject->MergeFrom(cache, at, graph, common) || changed; |
| 411 for (size_t i = 0; i < fields; ++i) { | |
| 412 if (Node* field = cache->GetFields(i)) { | |
| 413 changed = changed || mergeObject->GetField(i) != field; | |
| 414 mergeObject->SetField(i, field); | |
| 415 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); | |
| 416 } else { | |
| 417 int value_input_count = static_cast<int>(cache->fields().size()); | |
| 418 if (cache->fields().size() == arity) { | |
| 419 Node* rep = mergeObject->GetField(i); | |
| 420 if (!rep || !mergeObject->IsCreatedPhi(i)) { | |
| 421 cache->fields().push_back(control); | |
| 422 Node* phi = graph->NewNode( | |
| 423 common->Phi(MachineRepresentation::kTagged, | |
| 424 value_input_count), | |
| 425 value_input_count + 1, &cache->fields().front()); | |
| 426 mergeObject->SetField(i, phi, true); | |
| 427 #ifdef DEBUG | |
| 428 if (FLAG_trace_turbo_escape) { | |
| 429 PrintF(" Creating Phi #%d as merge of", phi->id()); | |
| 430 for (int i = 0; i < value_input_count; i++) { | |
| 431 PrintF(" #%d (%s)", cache->fields()[i]->id(), | |
| 432 cache->fields()[i]->op()->mnemonic()); | |
| 433 } | |
| 434 PrintF("\n"); | |
| 435 } | |
| 436 #endif // DEBUG | |
| 437 changed = true; | |
| 438 } else { | |
| 439 DCHECK(rep->opcode() == IrOpcode::kPhi); | |
| 440 for (int n = 0; n < value_input_count; ++n) { | |
| 441 Node* old = NodeProperties::GetValueInput(rep, n); | |
| 442 if (old != cache->fields()[n]) { | |
| 443 changed = true; | |
| 444 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); | |
| 445 } | |
| 446 } | |
| 447 } | |
| 448 } else { | |
| 449 if (mergeObject->GetField(i) != nullptr) { | |
| 450 TRACE(" Field %zu cleared\n", i); | |
| 451 changed = true; | |
| 452 } | |
| 453 mergeObject->SetField(i, nullptr); | |
| 454 } | |
| 455 } | |
| 456 } | |
| 457 } else { | 462 } else { |
| 458 if (mergeObject) { | 463 if (mergeObject) { |
| 459 TRACE(" Alias %d, virtual object removed\n", alias); | 464 TRACE(" Alias %d, virtual object removed\n", alias); |
| 460 changed = true; | 465 changed = true; |
| 461 } | 466 } |
| 462 SetVirtualObject(alias, nullptr); | 467 SetVirtualObject(alias, nullptr); |
| 463 } | 468 } |
| 464 } | 469 } |
| 465 return changed; | 470 return changed; |
| 466 } | 471 } |
| 467 | 472 |
| 468 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 473 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
| 469 Graph* graph, Zone* zone) | 474 Graph* graph, Zone* zone) |
| 470 : stack_(zone), | 475 : stack_(zone), |
| 471 object_analysis_(object_analysis), | 476 object_analysis_(object_analysis), |
| 472 graph_(graph), | 477 graph_(graph), |
| 473 zone_(zone), | 478 zone_(zone), |
| 474 status_(graph->NodeCount(), kUnknown, zone), | 479 status_(zone), |
| 475 next_free_alias_(0), | 480 next_free_alias_(0), |
| 476 status_stack_(zone), | 481 status_stack_(zone), |
| 477 aliases_(zone) {} | 482 aliases_(zone) {} |
| 478 | 483 |
| 479 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 484 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
| 480 | 485 |
| 481 bool EscapeStatusAnalysis::HasEntry(Node* node) { | 486 bool EscapeStatusAnalysis::HasEntry(Node* node) { |
| 482 return status_[node->id()] & (kTracked | kEscaped); | 487 return status_[node->id()] & (kTracked | kEscaped); |
| 483 } | 488 } |
| 484 | 489 |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 Zone* zone) | 761 Zone* zone) |
| 757 : status_analysis_(this, graph, zone), | 762 : status_analysis_(this, graph, zone), |
| 758 common_(common), | 763 common_(common), |
| 759 virtual_states_(zone), | 764 virtual_states_(zone), |
| 760 replacements_(zone), | 765 replacements_(zone), |
| 761 cache_(nullptr) {} | 766 cache_(nullptr) {} |
| 762 | 767 |
| 763 EscapeAnalysis::~EscapeAnalysis() {} | 768 EscapeAnalysis::~EscapeAnalysis() {} |
| 764 | 769 |
| 765 void EscapeAnalysis::Run() { | 770 void EscapeAnalysis::Run() { |
| 771 #ifndef DEBUG | |
| 772 if (FLAG_trace_turbo_escape) { | |
|
Michael Starzinger
2016/02/04 10:10:17
nit: This can be achieve more easily by moving the
| |
| 773 PrintF("--trace-turbo-escape only supported in DEBUG builds\n."); | |
| 774 } | |
| 775 #endif | |
| 766 replacements_.resize(graph()->NodeCount()); | 776 replacements_.resize(graph()->NodeCount()); |
| 767 status_analysis_.AssignAliases(); | 777 status_analysis_.AssignAliases(); |
| 768 if (status_analysis_.AliasCount() > 0) { | 778 if (status_analysis_.AliasCount() > 0) { |
| 769 cache_ = new (zone()) MergeCache(zone()); | 779 cache_ = new (zone()) MergeCache(zone()); |
| 770 replacements_.resize(graph()->NodeCount()); | 780 replacements_.resize(graph()->NodeCount()); |
| 771 status_analysis_.ResizeStatusVector(); | 781 status_analysis_.ResizeStatusVector(); |
| 772 RunObjectAnalysis(); | 782 RunObjectAnalysis(); |
| 773 status_analysis_.RunStatusAnalysis(); | 783 status_analysis_.RunStatusAnalysis(); |
| 774 } | 784 } |
| 775 } | 785 } |
| 776 | 786 |
| 777 void EscapeStatusAnalysis::AssignAliases() { | 787 void EscapeStatusAnalysis::AssignAliases() { |
| 778 size_t max_size = 1024; | 788 size_t max_size = 1024; |
| 779 size_t min_size = 32; | 789 size_t min_size = 32; |
| 780 size_t stack_size = std::min( | 790 size_t stack_size = |
| 781 std::max( | 791 std::min(std::max(graph()->NodeCount() / 5, min_size), max_size); |
| 782 std::min(graph()->NodeCount() / 5, graph()->NodeCount() / 20 + 128), | |
| 783 min_size), | |
| 784 max_size); | |
| 785 stack_.reserve(stack_size); | 792 stack_.reserve(stack_size); |
| 786 ResizeStatusVector(); | 793 ResizeStatusVector(); |
| 787 stack_.push_back(graph()->end()); | 794 stack_.push_back(graph()->end()); |
| 788 CHECK_LT(graph()->NodeCount(), kUntrackable); | 795 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 789 aliases_.resize(graph()->NodeCount(), kNotReachable); | 796 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| 790 aliases_[graph()->end()->id()] = kUntrackable; | 797 aliases_[graph()->end()->id()] = kUntrackable; |
| 791 status_stack_.reserve(8); | 798 status_stack_.reserve(8); |
| 792 TRACE("Discovering trackable nodes"); | 799 TRACE("Discovering trackable nodes"); |
| 793 while (!stack_.empty()) { | 800 while (!stack_.empty()) { |
| 794 Node* node = stack_.back(); | 801 Node* node = stack_.back(); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 994 case IrOpcode::kStoreElement: | 1001 case IrOpcode::kStoreElement: |
| 995 case IrOpcode::kLoadElement: | 1002 case IrOpcode::kLoadElement: |
| 996 case IrOpcode::kFrameState: | 1003 case IrOpcode::kFrameState: |
| 997 case IrOpcode::kStateValues: | 1004 case IrOpcode::kStateValues: |
| 998 case IrOpcode::kReferenceEqual: | 1005 case IrOpcode::kReferenceEqual: |
| 999 case IrOpcode::kFinishRegion: | 1006 case IrOpcode::kFinishRegion: |
| 1000 case IrOpcode::kObjectIsSmi: | 1007 case IrOpcode::kObjectIsSmi: |
| 1001 break; | 1008 break; |
| 1002 default: | 1009 default: |
| 1003 VirtualState* state = virtual_states_[node->id()]; | 1010 VirtualState* state = virtual_states_[node->id()]; |
| 1004 if (VirtualObject* obj = ResolveVirtualObject(state, input)) { | 1011 if (VirtualObject* obj = |
| 1012 GetVirtualObject(state, ResolveReplacement(input))) { | |
| 1005 if (!obj->AllFieldsClear()) { | 1013 if (!obj->AllFieldsClear()) { |
| 1006 obj = CopyForModificationAt(obj, state, node); | 1014 obj = CopyForModificationAt(obj, state, node); |
| 1007 obj->ClearAllFields(); | 1015 obj->ClearAllFields(); |
| 1008 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), | 1016 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), |
| 1009 obj->id()); | 1017 obj->id()); |
| 1010 } | 1018 } |
| 1011 } | 1019 } |
| 1012 break; | 1020 break; |
| 1013 } | 1021 } |
| 1014 } | 1022 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1106 } | 1114 } |
| 1107 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1115 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
| 1108 input->op()->mnemonic()); | 1116 input->op()->mnemonic()); |
| 1109 } | 1117 } |
| 1110 TRACE("\n"); | 1118 TRACE("\n"); |
| 1111 | 1119 |
| 1112 if (cache_->states().size() == 0) { | 1120 if (cache_->states().size() == 0) { |
| 1113 return changed; | 1121 return changed; |
| 1114 } | 1122 } |
| 1115 | 1123 |
| 1116 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), | 1124 changed = |
| 1117 NodeProperties::GetControlInput(node), | 1125 mergeState->MergeFrom(cache_, zone(), graph(), common(), node) || changed; |
| 1118 node->op()->EffectInputCount()) || | |
| 1119 changed; | |
| 1120 | 1126 |
| 1121 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); | 1127 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
| 1122 | 1128 |
| 1123 if (changed) { | 1129 if (changed) { |
| 1124 status_analysis_.ResizeStatusVector(); | 1130 status_analysis_.ResizeStatusVector(); |
| 1125 } | 1131 } |
| 1126 return changed; | 1132 return changed; |
| 1127 } | 1133 } |
| 1128 | 1134 |
| 1129 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1135 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1235 return status_analysis_.SetEscaped(node); | 1241 return status_analysis_.SetEscaped(node); |
| 1236 } | 1242 } |
| 1237 | 1243 |
| 1238 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1244 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| 1239 if (VirtualState* states = virtual_states_[at->id()]) { | 1245 if (VirtualState* states = virtual_states_[at->id()]) { |
| 1240 return states->VirtualObjectFromAlias(GetAlias(id)); | 1246 return states->VirtualObjectFromAlias(GetAlias(id)); |
| 1241 } | 1247 } |
| 1242 return nullptr; | 1248 return nullptr; |
| 1243 } | 1249 } |
| 1244 | 1250 |
| 1245 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | |
| 1246 Node* node) { | |
| 1247 return GetVirtualObject(state, ResolveReplacement(node)); | |
| 1248 } | |
| 1249 | |
| 1250 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1251 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
| 1251 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1252 DCHECK(IsVirtual(left) && IsVirtual(right)); |
| 1252 left = ResolveReplacement(left); | 1253 left = ResolveReplacement(left); |
| 1253 right = ResolveReplacement(right); | 1254 right = ResolveReplacement(right); |
| 1254 if (IsEquivalentPhi(left, right)) { | 1255 if (IsEquivalentPhi(left, right)) { |
| 1255 return true; | 1256 return true; |
| 1256 } | 1257 } |
| 1257 return false; | 1258 return false; |
| 1258 } | 1259 } |
| 1259 | 1260 |
| 1260 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1261 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
| 1261 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1262 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
| 1262 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1263 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
| 1263 } | 1264 } |
| 1264 | 1265 |
| 1265 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1266 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, |
| 1266 VirtualState* state) { | 1267 VirtualState* state) { |
| 1267 TRACE("Load #%d from phi #%d", node->id(), from->id()); | 1268 TRACE("Load #%d from phi #%d", load->id(), from->id()); |
| 1268 | 1269 |
| 1269 cache_->fields().clear(); | 1270 cache_->fields().clear(); |
| 1270 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1271 for (int i = 0; i < load->op()->ValueInputCount(); ++i) { |
| 1271 Node* input = NodeProperties::GetValueInput(node, i); | 1272 Node* input = NodeProperties::GetValueInput(load, i); |
| 1272 cache_->fields().push_back(input); | 1273 cache_->fields().push_back(input); |
| 1273 } | 1274 } |
| 1274 | 1275 |
| 1275 cache_->LoadVirtualObjectsForFieldsFrom(state, | 1276 cache_->LoadVirtualObjectsForFieldsFrom(state, |
| 1276 status_analysis_.GetAliasMap()); | 1277 status_analysis_.GetAliasMap()); |
| 1277 if (cache_->objects().size() == cache_->fields().size()) { | 1278 if (cache_->objects().size() == cache_->fields().size()) { |
| 1278 cache_->GetFields(offset); | 1279 cache_->GetFields(offset); |
| 1279 if (cache_->fields().size() == cache_->objects().size()) { | 1280 if (cache_->fields().size() == cache_->objects().size()) { |
| 1280 Node* rep = replacement(node); | 1281 Node* rep = replacement(load); |
| 1281 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1282 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
| 1282 int value_input_count = static_cast<int>(cache_->fields().size()); | 1283 int value_input_count = static_cast<int>(cache_->fields().size()); |
| 1283 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1284 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
| 1284 Node* phi = graph()->NewNode( | 1285 Node* phi = graph()->NewNode( |
| 1285 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1286 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
| 1286 value_input_count + 1, &cache_->fields().front()); | 1287 value_input_count + 1, &cache_->fields().front()); |
| 1287 status_analysis_.ResizeStatusVector(); | 1288 status_analysis_.ResizeStatusVector(); |
| 1288 SetReplacement(node, phi); | 1289 SetReplacement(load, phi); |
| 1289 TRACE(" got phi created.\n"); | 1290 TRACE(" got phi created.\n"); |
| 1290 } else { | 1291 } else { |
| 1291 TRACE(" has already phi #%d.\n", rep->id()); | 1292 TRACE(" has already phi #%d.\n", rep->id()); |
| 1292 } | 1293 } |
| 1293 } else { | 1294 } else { |
| 1294 TRACE(" has incomplete field info.\n"); | 1295 TRACE(" has incomplete field info.\n"); |
| 1295 } | 1296 } |
| 1296 } else { | 1297 } else { |
| 1297 TRACE(" has incomplete virtual object info.\n"); | 1298 TRACE(" has incomplete virtual object info.\n"); |
| 1298 } | 1299 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1434 obj->id()); | 1435 obj->id()); |
| 1435 } | 1436 } |
| 1436 } | 1437 } |
| 1437 } | 1438 } |
| 1438 } | 1439 } |
| 1439 | 1440 |
| 1440 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1441 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| 1441 if ((node->opcode() == IrOpcode::kFinishRegion || | 1442 if ((node->opcode() == IrOpcode::kFinishRegion || |
| 1442 node->opcode() == IrOpcode::kAllocate) && | 1443 node->opcode() == IrOpcode::kAllocate) && |
| 1443 IsVirtual(node)) { | 1444 IsVirtual(node)) { |
| 1444 if (VirtualObject* vobj = | 1445 if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()], |
| 1445 ResolveVirtualObject(virtual_states_[effect->id()], node)) { | 1446 ResolveReplacement(node))) { |
| 1446 if (Node* object_state = vobj->GetObjectState()) { | 1447 if (Node* object_state = vobj->GetObjectState()) { |
| 1447 return object_state; | 1448 return object_state; |
| 1448 } else { | 1449 } else { |
| 1449 cache_->fields().clear(); | 1450 cache_->fields().clear(); |
| 1450 for (size_t i = 0; i < vobj->field_count(); ++i) { | 1451 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1451 if (Node* field = vobj->GetField(i)) { | 1452 if (Node* field = vobj->GetField(i)) { |
| 1452 cache_->fields().push_back(field); | 1453 cache_->fields().push_back(field); |
| 1453 } | 1454 } |
| 1454 } | 1455 } |
| 1455 int input_count = static_cast<int>(cache_->fields().size()); | 1456 int input_count = static_cast<int>(cache_->fields().size()); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1529 return true; | 1530 return true; |
| 1530 } | 1531 } |
| 1531 } | 1532 } |
| 1532 } | 1533 } |
| 1533 return false; | 1534 return false; |
| 1534 } | 1535 } |
| 1535 | 1536 |
| 1536 } // namespace compiler | 1537 } // namespace compiler |
| 1537 } // namespace internal | 1538 } // namespace internal |
| 1538 } // namespace v8 | 1539 } // namespace v8 |
| OLD | NEW |