| 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 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 replacements_.resize(graph()->NodeCount()); | 775 replacements_.resize(graph()->NodeCount()); |
| 771 status_analysis_.ResizeStatusVector(); | 776 status_analysis_.ResizeStatusVector(); |
| 772 RunObjectAnalysis(); | 777 RunObjectAnalysis(); |
| 773 status_analysis_.RunStatusAnalysis(); | 778 status_analysis_.RunStatusAnalysis(); |
| 774 } | 779 } |
| 775 } | 780 } |
| 776 | 781 |
| 777 void EscapeStatusAnalysis::AssignAliases() { | 782 void EscapeStatusAnalysis::AssignAliases() { |
| 778 size_t max_size = 1024; | 783 size_t max_size = 1024; |
| 779 size_t min_size = 32; | 784 size_t min_size = 32; |
| 780 size_t stack_size = std::min( | 785 size_t stack_size = |
| 781 std::max( | 786 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); | 787 stack_.reserve(stack_size); |
| 786 ResizeStatusVector(); | 788 ResizeStatusVector(); |
| 787 stack_.push_back(graph()->end()); | 789 stack_.push_back(graph()->end()); |
| 788 CHECK_LT(graph()->NodeCount(), kUntrackable); | 790 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 789 aliases_.resize(graph()->NodeCount(), kNotReachable); | 791 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| 790 aliases_[graph()->end()->id()] = kUntrackable; | 792 aliases_[graph()->end()->id()] = kUntrackable; |
| 791 status_stack_.reserve(8); | 793 status_stack_.reserve(8); |
| 792 TRACE("Discovering trackable nodes"); | 794 TRACE("Discovering trackable nodes"); |
| 793 while (!stack_.empty()) { | 795 while (!stack_.empty()) { |
| 794 Node* node = stack_.back(); | 796 Node* node = stack_.back(); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 case IrOpcode::kStoreElement: | 996 case IrOpcode::kStoreElement: |
| 995 case IrOpcode::kLoadElement: | 997 case IrOpcode::kLoadElement: |
| 996 case IrOpcode::kFrameState: | 998 case IrOpcode::kFrameState: |
| 997 case IrOpcode::kStateValues: | 999 case IrOpcode::kStateValues: |
| 998 case IrOpcode::kReferenceEqual: | 1000 case IrOpcode::kReferenceEqual: |
| 999 case IrOpcode::kFinishRegion: | 1001 case IrOpcode::kFinishRegion: |
| 1000 case IrOpcode::kObjectIsSmi: | 1002 case IrOpcode::kObjectIsSmi: |
| 1001 break; | 1003 break; |
| 1002 default: | 1004 default: |
| 1003 VirtualState* state = virtual_states_[node->id()]; | 1005 VirtualState* state = virtual_states_[node->id()]; |
| 1004 if (VirtualObject* obj = ResolveVirtualObject(state, input)) { | 1006 if (VirtualObject* obj = |
| 1007 GetVirtualObject(state, ResolveReplacement(input))) { |
| 1005 if (!obj->AllFieldsClear()) { | 1008 if (!obj->AllFieldsClear()) { |
| 1006 obj = CopyForModificationAt(obj, state, node); | 1009 obj = CopyForModificationAt(obj, state, node); |
| 1007 obj->ClearAllFields(); | 1010 obj->ClearAllFields(); |
| 1008 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), | 1011 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), |
| 1009 obj->id()); | 1012 obj->id()); |
| 1010 } | 1013 } |
| 1011 } | 1014 } |
| 1012 break; | 1015 break; |
| 1013 } | 1016 } |
| 1014 } | 1017 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1106 } | 1109 } |
| 1107 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1110 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
| 1108 input->op()->mnemonic()); | 1111 input->op()->mnemonic()); |
| 1109 } | 1112 } |
| 1110 TRACE("\n"); | 1113 TRACE("\n"); |
| 1111 | 1114 |
| 1112 if (cache_->states().size() == 0) { | 1115 if (cache_->states().size() == 0) { |
| 1113 return changed; | 1116 return changed; |
| 1114 } | 1117 } |
| 1115 | 1118 |
| 1116 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), | 1119 changed = |
| 1117 NodeProperties::GetControlInput(node), | 1120 mergeState->MergeFrom(cache_, zone(), graph(), common(), node) || changed; |
| 1118 node->op()->EffectInputCount()) || | |
| 1119 changed; | |
| 1120 | 1121 |
| 1121 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); | 1122 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
| 1122 | 1123 |
| 1123 if (changed) { | 1124 if (changed) { |
| 1124 status_analysis_.ResizeStatusVector(); | 1125 status_analysis_.ResizeStatusVector(); |
| 1125 } | 1126 } |
| 1126 return changed; | 1127 return changed; |
| 1127 } | 1128 } |
| 1128 | 1129 |
| 1129 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1130 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1235 return status_analysis_.SetEscaped(node); | 1236 return status_analysis_.SetEscaped(node); |
| 1236 } | 1237 } |
| 1237 | 1238 |
| 1238 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1239 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| 1239 if (VirtualState* states = virtual_states_[at->id()]) { | 1240 if (VirtualState* states = virtual_states_[at->id()]) { |
| 1240 return states->VirtualObjectFromAlias(GetAlias(id)); | 1241 return states->VirtualObjectFromAlias(GetAlias(id)); |
| 1241 } | 1242 } |
| 1242 return nullptr; | 1243 return nullptr; |
| 1243 } | 1244 } |
| 1244 | 1245 |
| 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) { | 1246 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
| 1251 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1247 DCHECK(IsVirtual(left) && IsVirtual(right)); |
| 1252 left = ResolveReplacement(left); | 1248 left = ResolveReplacement(left); |
| 1253 right = ResolveReplacement(right); | 1249 right = ResolveReplacement(right); |
| 1254 if (IsEquivalentPhi(left, right)) { | 1250 if (IsEquivalentPhi(left, right)) { |
| 1255 return true; | 1251 return true; |
| 1256 } | 1252 } |
| 1257 return false; | 1253 return false; |
| 1258 } | 1254 } |
| 1259 | 1255 |
| 1260 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1256 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
| 1261 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1257 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
| 1262 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1258 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
| 1263 } | 1259 } |
| 1264 | 1260 |
| 1265 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1261 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, |
| 1266 VirtualState* state) { | 1262 VirtualState* state) { |
| 1267 TRACE("Load #%d from phi #%d", node->id(), from->id()); | 1263 TRACE("Load #%d from phi #%d", load->id(), from->id()); |
| 1268 | 1264 |
| 1269 cache_->fields().clear(); | 1265 cache_->fields().clear(); |
| 1270 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1266 for (int i = 0; i < load->op()->ValueInputCount(); ++i) { |
| 1271 Node* input = NodeProperties::GetValueInput(node, i); | 1267 Node* input = NodeProperties::GetValueInput(load, i); |
| 1272 cache_->fields().push_back(input); | 1268 cache_->fields().push_back(input); |
| 1273 } | 1269 } |
| 1274 | 1270 |
| 1275 cache_->LoadVirtualObjectsForFieldsFrom(state, | 1271 cache_->LoadVirtualObjectsForFieldsFrom(state, |
| 1276 status_analysis_.GetAliasMap()); | 1272 status_analysis_.GetAliasMap()); |
| 1277 if (cache_->objects().size() == cache_->fields().size()) { | 1273 if (cache_->objects().size() == cache_->fields().size()) { |
| 1278 cache_->GetFields(offset); | 1274 cache_->GetFields(offset); |
| 1279 if (cache_->fields().size() == cache_->objects().size()) { | 1275 if (cache_->fields().size() == cache_->objects().size()) { |
| 1280 Node* rep = replacement(node); | 1276 Node* rep = replacement(load); |
| 1281 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1277 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
| 1282 int value_input_count = static_cast<int>(cache_->fields().size()); | 1278 int value_input_count = static_cast<int>(cache_->fields().size()); |
| 1283 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1279 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
| 1284 Node* phi = graph()->NewNode( | 1280 Node* phi = graph()->NewNode( |
| 1285 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1281 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
| 1286 value_input_count + 1, &cache_->fields().front()); | 1282 value_input_count + 1, &cache_->fields().front()); |
| 1287 status_analysis_.ResizeStatusVector(); | 1283 status_analysis_.ResizeStatusVector(); |
| 1288 SetReplacement(node, phi); | 1284 SetReplacement(load, phi); |
| 1289 TRACE(" got phi created.\n"); | 1285 TRACE(" got phi created.\n"); |
| 1290 } else { | 1286 } else { |
| 1291 TRACE(" has already phi #%d.\n", rep->id()); | 1287 TRACE(" has already phi #%d.\n", rep->id()); |
| 1292 } | 1288 } |
| 1293 } else { | 1289 } else { |
| 1294 TRACE(" has incomplete field info.\n"); | 1290 TRACE(" has incomplete field info.\n"); |
| 1295 } | 1291 } |
| 1296 } else { | 1292 } else { |
| 1297 TRACE(" has incomplete virtual object info.\n"); | 1293 TRACE(" has incomplete virtual object info.\n"); |
| 1298 } | 1294 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1434 obj->id()); | 1430 obj->id()); |
| 1435 } | 1431 } |
| 1436 } | 1432 } |
| 1437 } | 1433 } |
| 1438 } | 1434 } |
| 1439 | 1435 |
| 1440 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1436 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| 1441 if ((node->opcode() == IrOpcode::kFinishRegion || | 1437 if ((node->opcode() == IrOpcode::kFinishRegion || |
| 1442 node->opcode() == IrOpcode::kAllocate) && | 1438 node->opcode() == IrOpcode::kAllocate) && |
| 1443 IsVirtual(node)) { | 1439 IsVirtual(node)) { |
| 1444 if (VirtualObject* vobj = | 1440 if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()], |
| 1445 ResolveVirtualObject(virtual_states_[effect->id()], node)) { | 1441 ResolveReplacement(node))) { |
| 1446 if (Node* object_state = vobj->GetObjectState()) { | 1442 if (Node* object_state = vobj->GetObjectState()) { |
| 1447 return object_state; | 1443 return object_state; |
| 1448 } else { | 1444 } else { |
| 1449 cache_->fields().clear(); | 1445 cache_->fields().clear(); |
| 1450 for (size_t i = 0; i < vobj->field_count(); ++i) { | 1446 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1451 if (Node* field = vobj->GetField(i)) { | 1447 if (Node* field = vobj->GetField(i)) { |
| 1452 cache_->fields().push_back(field); | 1448 cache_->fields().push_back(field); |
| 1453 } | 1449 } |
| 1454 } | 1450 } |
| 1455 int input_count = static_cast<int>(cache_->fields().size()); | 1451 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; | 1525 return true; |
| 1530 } | 1526 } |
| 1531 } | 1527 } |
| 1532 } | 1528 } |
| 1533 return false; | 1529 return false; |
| 1534 } | 1530 } |
| 1535 | 1531 |
| 1536 } // namespace compiler | 1532 } // namespace compiler |
| 1537 } // namespace internal | 1533 } // namespace internal |
| 1538 } // namespace v8 | 1534 } // namespace v8 |
| OLD | NEW |