| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| 11 #include "src/compilation-dependencies.h" | 11 #include "src/compilation-dependencies.h" |
| 12 #include "src/compiler/common-operator.h" | 12 #include "src/compiler/common-operator.h" |
| 13 #include "src/compiler/graph-reducer.h" | 13 #include "src/compiler/graph-reducer.h" |
| 14 #include "src/compiler/js-operator.h" | 14 #include "src/compiler/js-operator.h" |
| 15 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
| 16 #include "src/compiler/node-matchers.h" | 16 #include "src/compiler/node-matchers.h" |
| 17 #include "src/compiler/node-properties.h" | 17 #include "src/compiler/node-properties.h" |
| 18 #include "src/compiler/operator-properties.h" | 18 #include "src/compiler/operator-properties.h" |
| 19 #include "src/compiler/simplified-operator.h" | 19 #include "src/compiler/simplified-operator.h" |
| 20 #include "src/objects-inl.h" | 20 #include "src/objects-inl.h" |
| 21 #include "src/type-cache.h" | 21 #include "src/type-cache.h" |
| 22 | 22 |
| 23 namespace v8 { | 23 namespace v8 { |
| 24 namespace internal { | 24 namespace internal { |
| 25 namespace compiler { | 25 namespace compiler { |
| 26 | 26 |
| 27 #ifdef DEBUG |
| 28 #define TRACE(...) \ |
| 29 do { \ |
| 30 if (FLAG_trace_turbo_escape) PrintF(__VA_ARGS__); \ |
| 31 } while (false) |
| 32 #else |
| 33 #define TRACE(...) |
| 34 #endif |
| 35 |
| 27 const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable = | 36 const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable = |
| 28 std::numeric_limits<Alias>::max(); | 37 std::numeric_limits<Alias>::max(); |
| 29 const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable = | 38 const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable = |
| 30 std::numeric_limits<Alias>::max() - 1; | 39 std::numeric_limits<Alias>::max() - 1; |
| 31 | 40 |
| 32 | 41 |
| 33 class VirtualObject : public ZoneObject { | 42 class VirtualObject : public ZoneObject { |
| 34 public: | 43 public: |
| 35 enum Status { kUntracked = 0, kTracked = 1 }; | 44 enum Status { kUntracked = 0, kTracked = 1 }; |
| 36 VirtualObject(NodeId id, Zone* zone) | 45 VirtualObject(NodeId id, Zone* zone) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 if (offset < phi_.size()) { | 77 if (offset < phi_.size()) { |
| 69 return phi_[offset]; | 78 return phi_[offset]; |
| 70 } | 79 } |
| 71 return false; | 80 return false; |
| 72 } | 81 } |
| 73 | 82 |
| 74 bool SetField(size_t offset, Node* node, bool created_phi = false) { | 83 bool SetField(size_t offset, Node* node, bool created_phi = false) { |
| 75 bool changed = fields_[offset] != node || phi_[offset] != created_phi; | 84 bool changed = fields_[offset] != node || phi_[offset] != created_phi; |
| 76 fields_[offset] = node; | 85 fields_[offset] = node; |
| 77 phi_[offset] = created_phi; | 86 phi_[offset] = created_phi; |
| 78 if (changed && FLAG_trace_turbo_escape && node) { | 87 if (changed && node) { |
| 79 PrintF("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(), | 88 TRACE("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(), |
| 80 node->op()->mnemonic()); | 89 node->op()->mnemonic()); |
| 81 } | 90 } |
| 82 return changed; | 91 return changed; |
| 83 } | 92 } |
| 84 bool IsVirtual() const { return status_ == kTracked; } | 93 bool IsVirtual() const { return status_ == kTracked; } |
| 85 bool IsTracked() const { return status_ != kUntracked; } | 94 bool IsTracked() const { return status_ != kUntracked; } |
| 86 | 95 |
| 87 Node** fields_array() { return &fields_.front(); } | 96 Node** fields_array() { return &fields_.front(); } |
| 88 size_t field_count() { return fields_.size(); } | 97 size_t field_count() { return fields_.size(); } |
| 89 bool ResizeFields(size_t field_count) { | 98 bool ResizeFields(size_t field_count) { |
| 90 if (field_count != fields_.size()) { | 99 if (field_count != fields_.size()) { |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 continue; | 292 continue; |
| 284 } | 293 } |
| 285 | 294 |
| 286 if (ls == nullptr) { | 295 if (ls == nullptr) { |
| 287 ls = new (zone) VirtualObject(*rs); | 296 ls = new (zone) VirtualObject(*rs); |
| 288 SetVirtualObject(alias, ls); | 297 SetVirtualObject(alias, ls); |
| 289 changed = true; | 298 changed = true; |
| 290 continue; | 299 continue; |
| 291 } | 300 } |
| 292 | 301 |
| 293 if (FLAG_trace_turbo_escape) { | 302 TRACE(" Updating fields of @%d\n", alias); |
| 294 PrintF(" Updating fields of @%d\n", alias); | |
| 295 } | |
| 296 | 303 |
| 297 changed = ls->UpdateFrom(*rs) || changed; | 304 changed = ls->UpdateFrom(*rs) || changed; |
| 298 } | 305 } |
| 299 return false; | 306 return false; |
| 300 } | 307 } |
| 301 | 308 |
| 302 | 309 |
| 303 namespace { | 310 namespace { |
| 304 | 311 |
| 305 bool IsEquivalentPhi(Node* node1, Node* node2) { | 312 bool IsEquivalentPhi(Node* node1, Node* node2) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 } | 354 } |
| 348 | 355 |
| 349 | 356 |
| 350 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 357 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
| 351 CommonOperatorBuilder* common, Node* control) { | 358 CommonOperatorBuilder* common, Node* control) { |
| 352 DCHECK_GT(cache->states().size(), 0u); | 359 DCHECK_GT(cache->states().size(), 0u); |
| 353 bool changed = false; | 360 bool changed = false; |
| 354 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { | 361 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { |
| 355 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); | 362 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); |
| 356 if (cache->objects().size() == cache->states().size()) { | 363 if (cache->objects().size() == cache->states().size()) { |
| 357 if (FLAG_trace_turbo_escape) { | |
| 358 PrintF(" Merging virtual objects of @%d\n", alias); | |
| 359 } | |
| 360 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( | 364 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( |
| 361 alias, cache->objects().front()->id(), fields, zone); | 365 alias, cache->objects().front()->id(), fields, zone); |
| 366 #ifdef DEBUG |
| 367 if (FLAG_trace_turbo_escape) { |
| 368 PrintF(" Alias @%d, merging into %p virtual objects", alias, |
| 369 static_cast<void*>(mergeObject)); |
| 370 for (size_t i = 0; i < cache->objects().size(); i++) { |
| 371 PrintF(" %p", static_cast<void*>(cache->objects()[i])); |
| 372 } |
| 373 PrintF("\n"); |
| 374 } |
| 375 #endif // DEBUG |
| 362 changed = mergeObject->ResizeFields(fields) || changed; | 376 changed = mergeObject->ResizeFields(fields) || changed; |
| 363 for (size_t i = 0; i < fields; ++i) { | 377 for (size_t i = 0; i < fields; ++i) { |
| 364 if (Node* field = cache->GetFields(i)) { | 378 if (Node* field = cache->GetFields(i)) { |
| 365 changed = mergeObject->SetField(i, field) || changed; | 379 changed = mergeObject->SetField(i, field) || changed; |
| 366 if (FLAG_trace_turbo_escape) { | 380 TRACE(" Field %zu agree on rep #%d\n", i, field->id()); |
| 367 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); | |
| 368 } | |
| 369 } else { | 381 } else { |
| 370 int value_input_count = static_cast<int>(cache->fields().size()); | 382 int value_input_count = static_cast<int>(cache->fields().size()); |
| 371 if (cache->fields().size() == cache->objects().size()) { | 383 if (cache->fields().size() == cache->objects().size()) { |
| 372 Node* rep = mergeObject->GetField(i); | 384 Node* rep = mergeObject->GetField(i); |
| 373 if (!rep || !mergeObject->IsCreatedPhi(i)) { | 385 if (!rep || !mergeObject->IsCreatedPhi(i)) { |
| 374 cache->fields().push_back(control); | 386 cache->fields().push_back(control); |
| 375 Node* phi = graph->NewNode( | 387 Node* phi = graph->NewNode( |
| 376 common->Phi(MachineRepresentation::kTagged, | 388 common->Phi(MachineRepresentation::kTagged, |
| 377 value_input_count), | 389 value_input_count), |
| 378 value_input_count + 1, &cache->fields().front()); | 390 value_input_count + 1, &cache->fields().front()); |
| 379 mergeObject->SetField(i, phi, true); | 391 mergeObject->SetField(i, phi, true); |
| 392 #ifdef DEBUG |
| 380 if (FLAG_trace_turbo_escape) { | 393 if (FLAG_trace_turbo_escape) { |
| 381 PrintF(" Creating Phi #%d as merge of", phi->id()); | 394 PrintF(" Creating Phi #%d as merge of", phi->id()); |
| 382 for (int i = 0; i < value_input_count; i++) { | 395 for (int i = 0; i < value_input_count; i++) { |
| 383 PrintF(" #%d (%s)", cache->fields()[i]->id(), | 396 PrintF(" #%d (%s)", cache->fields()[i]->id(), |
| 384 cache->fields()[i]->op()->mnemonic()); | 397 cache->fields()[i]->op()->mnemonic()); |
| 385 } | 398 } |
| 386 PrintF("\n"); | 399 PrintF("\n"); |
| 387 } | 400 } |
| 401 #endif // DEBUG |
| 388 changed = true; | 402 changed = true; |
| 389 } else { | 403 } else { |
| 390 DCHECK(rep->opcode() == IrOpcode::kPhi); | 404 DCHECK(rep->opcode() == IrOpcode::kPhi); |
| 391 for (int n = 0; n < value_input_count; ++n) { | 405 for (int n = 0; n < value_input_count; ++n) { |
| 392 if (n < rep->op()->ValueInputCount()) { | 406 if (n < rep->op()->ValueInputCount()) { |
| 393 Node* old = NodeProperties::GetValueInput(rep, n); | 407 Node* old = NodeProperties::GetValueInput(rep, n); |
| 394 if (old != cache->fields()[n]) { | 408 if (old != cache->fields()[n]) { |
| 395 changed = true; | 409 changed = true; |
| 396 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], | 410 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], |
| 397 n); | 411 n); |
| 398 } | 412 } |
| 399 } else { | 413 } else { |
| 400 changed = true; | 414 changed = true; |
| 401 rep->InsertInput(graph->zone(), n, cache->fields()[n]); | 415 rep->InsertInput(graph->zone(), n, cache->fields()[n]); |
| 402 } | 416 } |
| 403 } | 417 } |
| 404 if (rep->op()->ValueInputCount() != value_input_count) { | 418 if (rep->op()->ValueInputCount() != value_input_count) { |
| 405 if (FLAG_trace_turbo_escape) { | 419 TRACE(" Widening Phi #%d of arity %d to %d\n", rep->id(), |
| 406 PrintF(" Widening Phi #%d of arity %d to %d", rep->id(), | 420 rep->op()->ValueInputCount(), value_input_count); |
| 407 rep->op()->ValueInputCount(), value_input_count); | |
| 408 } | |
| 409 NodeProperties::ChangeOp( | 421 NodeProperties::ChangeOp( |
| 410 rep, common->Phi(MachineRepresentation::kTagged, | 422 rep, common->Phi(MachineRepresentation::kTagged, |
| 411 value_input_count)); | 423 value_input_count)); |
| 412 } | 424 } |
| 413 } | 425 } |
| 414 } else { | 426 } else { |
| 415 if (FLAG_trace_turbo_escape) { | 427 if (mergeObject->GetField(i) != nullptr) { |
| 416 PrintF(" Field %zu cleared\n", i); | 428 TRACE(" Field %zu cleared\n", i); |
| 429 changed = true; |
| 417 } | 430 } |
| 418 changed = mergeObject->SetField(i, nullptr) || changed; | 431 changed = mergeObject->SetField(i, nullptr) || changed; |
| 419 } | 432 } |
| 420 } | 433 } |
| 421 } | 434 } |
| 422 } else { | 435 } else { |
| 423 SetVirtualObject(alias, nullptr); | 436 SetVirtualObject(alias, nullptr); |
| 424 } | 437 } |
| 425 } | 438 } |
| 426 return changed; | 439 return changed; |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 } | 586 } |
| 574 | 587 |
| 575 | 588 |
| 576 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { | 589 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { |
| 577 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 590 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 578 Node* to = NodeProperties::GetValueInput(node, 0); | 591 Node* to = NodeProperties::GetValueInput(node, 0); |
| 579 Node* val = NodeProperties::GetValueInput(node, 1); | 592 Node* val = NodeProperties::GetValueInput(node, 1); |
| 580 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { | 593 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { |
| 581 RevisitUses(val); | 594 RevisitUses(val); |
| 582 RevisitInputs(val); | 595 RevisitInputs(val); |
| 583 if (FLAG_trace_turbo_escape) { | 596 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", |
| 584 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | 597 val->id(), val->op()->mnemonic(), to->id()); |
| 585 val->id(), val->op()->mnemonic(), to->id()); | |
| 586 } | |
| 587 } | 598 } |
| 588 } | 599 } |
| 589 | 600 |
| 590 | 601 |
| 591 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) { | 602 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) { |
| 592 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 603 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 593 Node* to = NodeProperties::GetValueInput(node, 0); | 604 Node* to = NodeProperties::GetValueInput(node, 0); |
| 594 Node* val = NodeProperties::GetValueInput(node, 2); | 605 Node* val = NodeProperties::GetValueInput(node, 2); |
| 595 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { | 606 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { |
| 596 RevisitUses(val); | 607 RevisitUses(val); |
| 597 RevisitInputs(val); | 608 RevisitInputs(val); |
| 598 if (FLAG_trace_turbo_escape) { | 609 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", |
| 599 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | 610 val->id(), val->op()->mnemonic(), to->id()); |
| 600 val->id(), val->op()->mnemonic(), to->id()); | |
| 601 } | |
| 602 } | 611 } |
| 603 } | 612 } |
| 604 | 613 |
| 605 | 614 |
| 606 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 615 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { |
| 607 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 616 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
| 608 if (!HasEntry(node)) { | 617 if (!HasEntry(node)) { |
| 609 status_[node->id()] |= kTracked; | 618 status_[node->id()] |= kTracked; |
| 610 if (FLAG_trace_turbo_escape) { | 619 TRACE("Created status entry for node #%d (%s)\n", node->id(), |
| 611 PrintF("Created status entry for node #%d (%s)\n", node->id(), | 620 node->op()->mnemonic()); |
| 612 node->op()->mnemonic()); | |
| 613 } | |
| 614 NumberMatcher size(node->InputAt(0)); | 621 NumberMatcher size(node->InputAt(0)); |
| 615 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 622 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
| 616 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 623 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
| 617 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 624 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
| 618 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 625 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
| 619 if (!size.HasValue() && SetEscaped(node)) { | 626 if (!size.HasValue() && SetEscaped(node)) { |
| 620 RevisitUses(node); | 627 RevisitUses(node); |
| 621 if (FLAG_trace_turbo_escape) { | 628 TRACE("Setting #%d to escaped because of non-const alloc\n", node->id()); |
| 622 PrintF("Setting #%d to escaped because of non-const alloc\n", | |
| 623 node->id()); | |
| 624 } | |
| 625 // This node is known to escape, uses do not have to be checked. | 629 // This node is known to escape, uses do not have to be checked. |
| 626 return; | 630 return; |
| 627 } | 631 } |
| 628 } | 632 } |
| 629 if (CheckUsesForEscape(node, true)) { | 633 if (CheckUsesForEscape(node, true)) { |
| 630 RevisitUses(node); | 634 RevisitUses(node); |
| 631 } | 635 } |
| 632 } | 636 } |
| 633 | 637 |
| 634 | 638 |
| 635 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, | 639 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
| 636 bool phi_escaping) { | 640 bool phi_escaping) { |
| 637 for (Edge edge : uses->use_edges()) { | 641 for (Edge edge : uses->use_edges()) { |
| 638 Node* use = edge.from(); | 642 Node* use = edge.from(); |
| 639 if (edge.index() >= use->op()->ValueInputCount() + | 643 if (edge.index() >= use->op()->ValueInputCount() + |
| 640 OperatorProperties::GetContextInputCount(use->op())) | 644 OperatorProperties::GetContextInputCount(use->op())) |
| 641 continue; | 645 continue; |
| 642 switch (use->opcode()) { | 646 switch (use->opcode()) { |
| 643 case IrOpcode::kPhi: | 647 case IrOpcode::kPhi: |
| 644 if (phi_escaping && SetEscaped(rep)) { | 648 if (phi_escaping && SetEscaped(rep)) { |
| 645 if (FLAG_trace_turbo_escape) { | 649 TRACE( |
| 646 PrintF( | 650 "Setting #%d (%s) to escaped because of use by phi node " |
| 647 "Setting #%d (%s) to escaped because of use by phi node " | 651 "#%d (%s)\n", |
| 648 "#%d (%s)\n", | 652 rep->id(), rep->op()->mnemonic(), use->id(), |
| 649 rep->id(), rep->op()->mnemonic(), use->id(), | 653 use->op()->mnemonic()); |
| 650 use->op()->mnemonic()); | |
| 651 } | |
| 652 return true; | 654 return true; |
| 653 } | 655 } |
| 654 // Fallthrough. | 656 // Fallthrough. |
| 655 case IrOpcode::kStoreField: | 657 case IrOpcode::kStoreField: |
| 656 case IrOpcode::kLoadField: | 658 case IrOpcode::kLoadField: |
| 657 case IrOpcode::kStoreElement: | 659 case IrOpcode::kStoreElement: |
| 658 case IrOpcode::kLoadElement: | 660 case IrOpcode::kLoadElement: |
| 659 case IrOpcode::kFrameState: | 661 case IrOpcode::kFrameState: |
| 660 case IrOpcode::kStateValues: | 662 case IrOpcode::kStateValues: |
| 661 case IrOpcode::kReferenceEqual: | 663 case IrOpcode::kReferenceEqual: |
| 662 case IrOpcode::kFinishRegion: | 664 case IrOpcode::kFinishRegion: |
| 663 if (IsEscaped(use) && SetEscaped(rep)) { | 665 if (IsEscaped(use) && SetEscaped(rep)) { |
| 664 if (FLAG_trace_turbo_escape) { | 666 TRACE( |
| 665 PrintF( | 667 "Setting #%d (%s) to escaped because of use by escaping node " |
| 666 "Setting #%d (%s) to escaped because of use by escaping node " | 668 "#%d (%s)\n", |
| 667 "#%d (%s)\n", | 669 rep->id(), rep->op()->mnemonic(), use->id(), |
| 668 rep->id(), rep->op()->mnemonic(), use->id(), | 670 use->op()->mnemonic()); |
| 669 use->op()->mnemonic()); | |
| 670 } | |
| 671 return true; | 671 return true; |
| 672 } | 672 } |
| 673 break; | 673 break; |
| 674 case IrOpcode::kObjectIsSmi: | 674 case IrOpcode::kObjectIsSmi: |
| 675 if (!IsAllocation(rep) && SetEscaped(rep)) { | 675 if (!IsAllocation(rep) && SetEscaped(rep)) { |
| 676 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 676 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
| 677 rep->id(), rep->op()->mnemonic(), use->id(), | 677 rep->id(), rep->op()->mnemonic(), use->id(), |
| 678 use->op()->mnemonic()); | 678 use->op()->mnemonic()); |
| 679 return true; | 679 return true; |
| 680 } | 680 } |
| 681 break; | 681 break; |
| 682 case IrOpcode::kSelect: | 682 case IrOpcode::kSelect: |
| 683 if (SetEscaped(rep)) { | 683 if (SetEscaped(rep)) { |
| 684 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 684 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
| 685 rep->id(), rep->op()->mnemonic(), use->id(), | 685 rep->id(), rep->op()->mnemonic(), use->id(), |
| 686 use->op()->mnemonic()); | 686 use->op()->mnemonic()); |
| 687 return true; | 687 return true; |
| 688 } | 688 } |
| 689 break; | 689 break; |
| 690 default: | 690 default: |
| 691 if (use->op()->EffectInputCount() == 0 && | 691 if (use->op()->EffectInputCount() == 0 && |
| 692 uses->op()->EffectInputCount() > 0) { | 692 uses->op()->EffectInputCount() > 0) { |
| 693 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(), | 693 TRACE("Encountered unaccounted use by #%d (%s)\n", use->id(), |
| 694 use->op()->mnemonic()); | 694 use->op()->mnemonic()); |
| 695 UNREACHABLE(); | 695 UNREACHABLE(); |
| 696 } | 696 } |
| 697 if (SetEscaped(rep)) { | 697 if (SetEscaped(rep)) { |
| 698 if (FLAG_trace_turbo_escape) { | 698 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
| 699 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 699 rep->id(), rep->op()->mnemonic(), use->id(), |
| 700 rep->id(), rep->op()->mnemonic(), use->id(), | 700 use->op()->mnemonic()); |
| 701 use->op()->mnemonic()); | |
| 702 } | |
| 703 return true; | 701 return true; |
| 704 } | 702 } |
| 705 } | 703 } |
| 706 } | 704 } |
| 707 return false; | 705 return false; |
| 708 } | 706 } |
| 709 | 707 |
| 710 | 708 |
| 711 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { | 709 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { |
| 712 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 710 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 escape_status_.Run(); | 753 escape_status_.Run(); |
| 756 } | 754 } |
| 757 | 755 |
| 758 | 756 |
| 759 void EscapeAnalysis::AssignAliases() { | 757 void EscapeAnalysis::AssignAliases() { |
| 760 ZoneVector<Node*> stack(zone()); | 758 ZoneVector<Node*> stack(zone()); |
| 761 stack.push_back(graph()->end()); | 759 stack.push_back(graph()->end()); |
| 762 CHECK_LT(graph()->NodeCount(), kUntrackable); | 760 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 763 aliases_.resize(graph()->NodeCount(), kNotReachable); | 761 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| 764 aliases_[graph()->end()->id()] = kUntrackable; | 762 aliases_[graph()->end()->id()] = kUntrackable; |
| 763 TRACE("Discovering trackable nodes"); |
| 765 while (!stack.empty()) { | 764 while (!stack.empty()) { |
| 766 Node* node = stack.back(); | 765 Node* node = stack.back(); |
| 767 stack.pop_back(); | 766 stack.pop_back(); |
| 768 switch (node->opcode()) { | 767 switch (node->opcode()) { |
| 769 case IrOpcode::kAllocate: | 768 case IrOpcode::kAllocate: |
| 770 if (aliases_[node->id()] >= kUntrackable) { | 769 if (aliases_[node->id()] >= kUntrackable) { |
| 771 aliases_[node->id()] = NextAlias(); | 770 aliases_[node->id()] = NextAlias(); |
| 771 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), |
| 772 node->id()); |
| 772 } | 773 } |
| 773 break; | 774 break; |
| 774 case IrOpcode::kFinishRegion: { | 775 case IrOpcode::kFinishRegion: { |
| 775 Node* allocate = NodeProperties::GetValueInput(node, 0); | 776 Node* allocate = NodeProperties::GetValueInput(node, 0); |
| 776 if (allocate->opcode() == IrOpcode::kAllocate) { | 777 if (allocate->opcode() == IrOpcode::kAllocate) { |
| 777 if (aliases_[allocate->id()] >= kUntrackable) { | 778 if (aliases_[allocate->id()] >= kUntrackable) { |
| 778 if (aliases_[allocate->id()] == kNotReachable) { | 779 if (aliases_[allocate->id()] == kNotReachable) { |
| 779 stack.push_back(allocate); | 780 stack.push_back(allocate); |
| 780 } | 781 } |
| 781 aliases_[allocate->id()] = NextAlias(); | 782 aliases_[allocate->id()] = NextAlias(); |
| 783 TRACE(" @%d:%s#%u", aliases_[allocate->id()], |
| 784 allocate->op()->mnemonic(), allocate->id()); |
| 782 } | 785 } |
| 783 aliases_[node->id()] = aliases_[allocate->id()]; | 786 aliases_[node->id()] = aliases_[allocate->id()]; |
| 787 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), |
| 788 node->id()); |
| 789 |
| 784 } else { | 790 } else { |
| 785 aliases_[node->id()] = NextAlias(); | 791 aliases_[node->id()] = NextAlias(); |
| 792 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), |
| 793 node->id()); |
| 786 } | 794 } |
| 787 break; | 795 break; |
| 788 } | 796 } |
| 789 default: | 797 default: |
| 790 DCHECK_EQ(aliases_[node->id()], kUntrackable); | 798 DCHECK_EQ(aliases_[node->id()], kUntrackable); |
| 791 break; | 799 break; |
| 792 } | 800 } |
| 793 for (Edge edge : node->input_edges()) { | 801 for (Edge edge : node->input_edges()) { |
| 794 Node* input = edge.to(); | 802 Node* input = edge.to(); |
| 795 if (aliases_[input->id()] == kNotReachable) { | 803 if (aliases_[input->id()] == kNotReachable) { |
| 796 stack.push_back(input); | 804 stack.push_back(input); |
| 797 aliases_[input->id()] = kUntrackable; | 805 aliases_[input->id()] = kUntrackable; |
| 798 } | 806 } |
| 799 } | 807 } |
| 800 } | 808 } |
| 801 | 809 TRACE("\n"); |
| 802 if (FLAG_trace_turbo_escape) { | |
| 803 PrintF("Discovered trackable nodes"); | |
| 804 for (EscapeAnalysis::Alias id = 0; id < graph()->NodeCount(); ++id) { | |
| 805 if (aliases_[id] < kUntrackable) { | |
| 806 if (FLAG_trace_turbo_escape) { | |
| 807 PrintF(" #%u", id); | |
| 808 } | |
| 809 } | |
| 810 } | |
| 811 PrintF("\n"); | |
| 812 } | |
| 813 } | 810 } |
| 814 | 811 |
| 815 | 812 |
| 816 void EscapeAnalysis::RunObjectAnalysis() { | 813 void EscapeAnalysis::RunObjectAnalysis() { |
| 817 virtual_states_.resize(graph()->NodeCount()); | 814 virtual_states_.resize(graph()->NodeCount()); |
| 818 ZoneVector<Node*> stack(zone()); | 815 ZoneVector<Node*> stack(zone()); |
| 819 stack.push_back(graph()->start()); | 816 stack.push_back(graph()->start()); |
| 820 while (!stack.empty()) { | 817 while (!stack.empty()) { |
| 821 Node* node = stack.back(); | 818 Node* node = stack.back(); |
| 822 stack.pop_back(); | 819 stack.pop_back(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 837 Node* use = edge.from(); | 834 Node* use = edge.from(); |
| 838 if ((use->opcode() == IrOpcode::kLoadField || | 835 if ((use->opcode() == IrOpcode::kLoadField || |
| 839 use->opcode() == IrOpcode::kLoadElement) && | 836 use->opcode() == IrOpcode::kLoadElement) && |
| 840 IsDanglingEffectNode(use)) { | 837 IsDanglingEffectNode(use)) { |
| 841 stack.push_back(use); | 838 stack.push_back(use); |
| 842 } | 839 } |
| 843 } | 840 } |
| 844 } | 841 } |
| 845 } | 842 } |
| 846 } | 843 } |
| 844 #ifdef DEBUG |
| 847 if (FLAG_trace_turbo_escape) { | 845 if (FLAG_trace_turbo_escape) { |
| 848 DebugPrint(); | 846 DebugPrint(); |
| 849 } | 847 } |
| 848 #endif |
| 850 } | 849 } |
| 851 | 850 |
| 852 | 851 |
| 853 bool EscapeAnalysis::IsDanglingEffectNode(Node* node) { | 852 bool EscapeAnalysis::IsDanglingEffectNode(Node* node) { |
| 854 if (node->op()->EffectInputCount() == 0) return false; | 853 if (node->op()->EffectInputCount() == 0) return false; |
| 855 if (node->op()->EffectOutputCount() == 0) return false; | 854 if (node->op()->EffectOutputCount() == 0) return false; |
| 856 if (node->op()->EffectInputCount() == 1 && | 855 if (node->op()->EffectInputCount() == 1 && |
| 857 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) { | 856 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) { |
| 858 // The start node is used as sentinel for nodes that are in general | 857 // The start node is used as sentinel for nodes that are in general |
| 859 // effectful, but of which an analysis has determined that they do not | 858 // effectful, but of which an analysis has determined that they do not |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 Node* effect = NodeProperties::GetEffectInput(node); | 963 Node* effect = NodeProperties::GetEffectInput(node); |
| 965 // Break the cycle for effect phis. | 964 // Break the cycle for effect phis. |
| 966 if (effect->opcode() == IrOpcode::kEffectPhi) { | 965 if (effect->opcode() == IrOpcode::kEffectPhi) { |
| 967 if (virtual_states_[effect->id()] == nullptr) { | 966 if (virtual_states_[effect->id()] == nullptr) { |
| 968 virtual_states_[effect->id()] = | 967 virtual_states_[effect->id()] = |
| 969 new (zone()) VirtualState(zone(), AliasCount()); | 968 new (zone()) VirtualState(zone(), AliasCount()); |
| 970 } | 969 } |
| 971 } | 970 } |
| 972 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 971 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
| 973 if (IsEffectBranchPoint(effect)) { | 972 if (IsEffectBranchPoint(effect)) { |
| 974 if (FLAG_trace_turbo_escape) { | 973 TRACE("Copying virtual state %p from #%d (%s) to #%d (%s)\n", |
| 975 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", | 974 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
| 976 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 975 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 977 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | |
| 978 } | |
| 979 if (!virtual_states_[node->id()]) { | 976 if (!virtual_states_[node->id()]) { |
| 980 virtual_states_[node->id()] = | 977 virtual_states_[node->id()] = |
| 981 new (zone()) VirtualState(*virtual_states_[effect->id()]); | 978 new (zone()) VirtualState(*virtual_states_[effect->id()]); |
| 982 } else { | 979 } else { |
| 983 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 980 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
| 984 zone()); | 981 zone()); |
| 985 } | 982 } |
| 986 } else { | 983 } else { |
| 987 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 984 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
| 988 if (FLAG_trace_turbo_escape) { | 985 TRACE("Forwarding virtual state %p from #%d (%s) to #%d (%s)\n", |
| 989 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", | 986 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
| 990 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 987 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 991 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | |
| 992 } | |
| 993 } | 988 } |
| 994 } | 989 } |
| 995 | 990 |
| 996 | 991 |
| 997 void EscapeAnalysis::ProcessStart(Node* node) { | 992 void EscapeAnalysis::ProcessStart(Node* node) { |
| 998 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 993 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
| 999 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount()); | 994 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount()); |
| 1000 } | 995 } |
| 1001 | 996 |
| 1002 | 997 |
| 1003 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 998 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
| 1004 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 999 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
| 1005 bool changed = false; | 1000 bool changed = false; |
| 1006 | 1001 |
| 1007 VirtualState* mergeState = virtual_states_[node->id()]; | 1002 VirtualState* mergeState = virtual_states_[node->id()]; |
| 1008 if (!mergeState) { | 1003 if (!mergeState) { |
| 1009 mergeState = new (zone()) VirtualState(zone(), AliasCount()); | 1004 mergeState = new (zone()) VirtualState(zone(), AliasCount()); |
| 1010 virtual_states_[node->id()] = mergeState; | 1005 virtual_states_[node->id()] = mergeState; |
| 1011 changed = true; | 1006 changed = true; |
| 1012 if (FLAG_trace_turbo_escape) { | 1007 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), |
| 1013 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), | 1008 static_cast<void*>(mergeState)); |
| 1014 static_cast<void*>(mergeState)); | |
| 1015 } | |
| 1016 } else if (mergeState->GetLastChanged() != node) { | 1009 } else if (mergeState->GetLastChanged() != node) { |
| 1017 changed = true; | 1010 changed = true; |
| 1018 } | 1011 } |
| 1019 | 1012 |
| 1020 cache_->Clear(); | 1013 cache_->Clear(); |
| 1021 | 1014 |
| 1022 if (FLAG_trace_turbo_escape) { | 1015 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), |
| 1023 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), | 1016 static_cast<void*>(mergeState)); |
| 1024 static_cast<void*>(mergeState)); | |
| 1025 } | |
| 1026 | 1017 |
| 1027 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1018 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
| 1028 Node* input = NodeProperties::GetEffectInput(node, i); | 1019 Node* input = NodeProperties::GetEffectInput(node, i); |
| 1029 VirtualState* state = virtual_states_[input->id()]; | 1020 VirtualState* state = virtual_states_[input->id()]; |
| 1030 if (state) { | 1021 if (state) { |
| 1031 cache_->states().push_back(state); | 1022 cache_->states().push_back(state); |
| 1032 } | 1023 } |
| 1033 if (FLAG_trace_turbo_escape) { | 1024 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
| 1034 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1025 input->op()->mnemonic()); |
| 1035 input->op()->mnemonic()); | |
| 1036 } | |
| 1037 } | 1026 } |
| 1038 if (FLAG_trace_turbo_escape) { | 1027 TRACE("\n"); |
| 1039 PrintF("\n"); | |
| 1040 } | |
| 1041 | 1028 |
| 1042 if (cache_->states().size() == 0) { | 1029 if (cache_->states().size() == 0) { |
| 1043 return changed; | 1030 return changed; |
| 1044 } | 1031 } |
| 1045 | 1032 |
| 1046 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), | 1033 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), |
| 1047 NodeProperties::GetControlInput(node)) || | 1034 NodeProperties::GetControlInput(node)) || |
| 1048 changed; | 1035 changed; |
| 1049 | 1036 |
| 1050 if (FLAG_trace_turbo_escape) { | 1037 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
| 1051 PrintF("Merge %s the node.\n", changed ? "changed" : "did not change"); | |
| 1052 } | |
| 1053 | 1038 |
| 1054 if (changed) { | 1039 if (changed) { |
| 1055 mergeState->LastChangedAt(node); | 1040 mergeState->LastChangedAt(node); |
| 1056 escape_status_.Resize(); | 1041 escape_status_.Resize(); |
| 1057 } | 1042 } |
| 1058 return changed; | 1043 return changed; |
| 1059 } | 1044 } |
| 1060 | 1045 |
| 1061 | 1046 |
| 1062 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1047 void EscapeAnalysis::ProcessAllocation(Node* node) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1091 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1076 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
| 1092 ForwardVirtualState(node); | 1077 ForwardVirtualState(node); |
| 1093 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1078 Node* allocation = NodeProperties::GetValueInput(node, 0); |
| 1094 if (allocation->opcode() == IrOpcode::kAllocate) { | 1079 if (allocation->opcode() == IrOpcode::kAllocate) { |
| 1095 VirtualState* state = virtual_states_[node->id()]; | 1080 VirtualState* state = virtual_states_[node->id()]; |
| 1096 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { | 1081 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { |
| 1097 VirtualObject* vobj_alloc = | 1082 VirtualObject* vobj_alloc = |
| 1098 state->VirtualObjectFromAlias(aliases_[allocation->id()]); | 1083 state->VirtualObjectFromAlias(aliases_[allocation->id()]); |
| 1099 DCHECK_NOT_NULL(vobj_alloc); | 1084 DCHECK_NOT_NULL(vobj_alloc); |
| 1100 state->SetVirtualObject(aliases_[node->id()], vobj_alloc); | 1085 state->SetVirtualObject(aliases_[node->id()], vobj_alloc); |
| 1101 if (FLAG_trace_turbo_escape) { | 1086 TRACE("Linked finish region node #%d to node #%d\n", node->id(), |
| 1102 PrintF("Linked finish region node #%d to node #%d\n", node->id(), | 1087 allocation->id()); |
| 1103 allocation->id()); | |
| 1104 } | |
| 1105 state->LastChangedAt(node); | 1088 state->LastChangedAt(node); |
| 1106 } | 1089 } |
| 1107 } | 1090 } |
| 1108 } | 1091 } |
| 1109 | 1092 |
| 1110 | 1093 |
| 1111 Node* EscapeAnalysis::replacement(NodeId id) { | 1094 Node* EscapeAnalysis::replacement(NodeId id) { |
| 1112 if (id >= replacements_.size()) return nullptr; | 1095 if (id >= replacements_.size()) return nullptr; |
| 1113 return replacements_[id]; | 1096 return replacements_[id]; |
| 1114 } | 1097 } |
| 1115 | 1098 |
| 1116 | 1099 |
| 1117 Node* EscapeAnalysis::replacement(Node* node) { | 1100 Node* EscapeAnalysis::replacement(Node* node) { |
| 1118 return replacement(node->id()); | 1101 return replacement(node->id()); |
| 1119 } | 1102 } |
| 1120 | 1103 |
| 1121 | 1104 |
| 1122 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { | 1105 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { |
| 1123 bool changed = replacements_[node->id()] != rep; | 1106 bool changed = replacements_[node->id()] != rep; |
| 1124 replacements_[node->id()] = rep; | 1107 replacements_[node->id()] = rep; |
| 1125 return changed; | 1108 return changed; |
| 1126 } | 1109 } |
| 1127 | 1110 |
| 1128 | 1111 |
| 1129 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, | 1112 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, |
| 1130 Node* rep) { | 1113 Node* rep) { |
| 1131 if (SetReplacement(node, rep)) { | 1114 if (SetReplacement(node, rep)) { |
| 1132 state->LastChangedAt(node); | 1115 state->LastChangedAt(node); |
| 1133 if (FLAG_trace_turbo_escape) { | 1116 if (rep) { |
| 1134 if (rep) { | 1117 TRACE("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), |
| 1135 PrintF("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), | 1118 rep->op()->mnemonic()); |
| 1136 rep->op()->mnemonic()); | 1119 } else { |
| 1137 } else { | 1120 TRACE("Replacement of #%d cleared\n", node->id()); |
| 1138 PrintF("Replacement of #%d cleared\n", node->id()); | |
| 1139 } | |
| 1140 } | 1121 } |
| 1141 return true; | 1122 return true; |
| 1142 } | 1123 } |
| 1143 return false; | 1124 return false; |
| 1144 } | 1125 } |
| 1145 | 1126 |
| 1146 | 1127 |
| 1147 Node* EscapeAnalysis::ResolveReplacement(Node* node) { | 1128 Node* EscapeAnalysis::ResolveReplacement(Node* node) { |
| 1148 while (replacement(node)) { | 1129 while (replacement(node)) { |
| 1149 node = replacement(node); | 1130 node = replacement(node); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1214 | 1195 |
| 1215 | 1196 |
| 1216 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1197 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
| 1217 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1198 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
| 1218 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1199 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
| 1219 } | 1200 } |
| 1220 | 1201 |
| 1221 | 1202 |
| 1222 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1203 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
| 1223 VirtualState* state) { | 1204 VirtualState* state) { |
| 1224 if (FLAG_trace_turbo_escape) { | 1205 TRACE("Load #%d from phi #%d", node->id(), from->id()); |
| 1225 PrintF("Load #%d from phi #%d", node->id(), from->id()); | |
| 1226 } | |
| 1227 | 1206 |
| 1228 cache_->fields().clear(); | 1207 cache_->fields().clear(); |
| 1229 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1208 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
| 1230 Node* input = NodeProperties::GetValueInput(node, i); | 1209 Node* input = NodeProperties::GetValueInput(node, i); |
| 1231 cache_->fields().push_back(input); | 1210 cache_->fields().push_back(input); |
| 1232 } | 1211 } |
| 1233 | 1212 |
| 1234 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_); | 1213 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_); |
| 1235 if (cache_->objects().size() == cache_->fields().size()) { | 1214 if (cache_->objects().size() == cache_->fields().size()) { |
| 1236 cache_->GetFields(offset); | 1215 cache_->GetFields(offset); |
| 1237 if (cache_->fields().size() == cache_->objects().size()) { | 1216 if (cache_->fields().size() == cache_->objects().size()) { |
| 1238 Node* rep = replacement(node); | 1217 Node* rep = replacement(node); |
| 1239 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1218 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
| 1240 int value_input_count = static_cast<int>(cache_->fields().size()); | 1219 int value_input_count = static_cast<int>(cache_->fields().size()); |
| 1241 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1220 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
| 1242 Node* phi = graph()->NewNode( | 1221 Node* phi = graph()->NewNode( |
| 1243 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1222 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
| 1244 value_input_count + 1, &cache_->fields().front()); | 1223 value_input_count + 1, &cache_->fields().front()); |
| 1245 escape_status_.Resize(); | 1224 escape_status_.Resize(); |
| 1246 SetReplacement(node, phi); | 1225 SetReplacement(node, phi); |
| 1247 state->LastChangedAt(node); | 1226 state->LastChangedAt(node); |
| 1248 if (FLAG_trace_turbo_escape) { | 1227 TRACE(" got phi created.\n"); |
| 1249 PrintF(" got phi created.\n"); | 1228 } else { |
| 1250 } | 1229 TRACE(" has already phi #%d.\n", rep->id()); |
| 1251 } else if (FLAG_trace_turbo_escape) { | |
| 1252 PrintF(" has already phi #%d.\n", rep->id()); | |
| 1253 } | 1230 } |
| 1254 } else if (FLAG_trace_turbo_escape) { | 1231 } else { |
| 1255 PrintF(" has incomplete field info.\n"); | 1232 TRACE(" has incomplete field info.\n"); |
| 1256 } | 1233 } |
| 1257 } else if (FLAG_trace_turbo_escape) { | 1234 } else { |
| 1258 PrintF(" has incomplete virtual object info.\n"); | 1235 TRACE(" has incomplete virtual object info.\n"); |
| 1259 } | 1236 } |
| 1260 } | 1237 } |
| 1261 | 1238 |
| 1262 | 1239 |
| 1263 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1240 void EscapeAnalysis::ProcessLoadField(Node* node) { |
| 1264 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1241 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
| 1265 ForwardVirtualState(node); | 1242 ForwardVirtualState(node); |
| 1266 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1243 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1267 VirtualState* state = virtual_states_[node->id()]; | 1244 VirtualState* state = virtual_states_[node->id()]; |
| 1268 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1245 if (VirtualObject* object = GetVirtualObject(state, from)) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 } else if (from->opcode() == IrOpcode::kPhi) { | 1291 } else if (from->opcode() == IrOpcode::kPhi) { |
| 1315 ElementAccess access = OpParameter<ElementAccess>(node); | 1292 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1316 int offset = index.Value() + access.header_size / kPointerSize; | 1293 int offset = index.Value() + access.header_size / kPointerSize; |
| 1317 ProcessLoadFromPhi(offset, from, node, state); | 1294 ProcessLoadFromPhi(offset, from, node, state); |
| 1318 } else { | 1295 } else { |
| 1319 UpdateReplacement(state, node, nullptr); | 1296 UpdateReplacement(state, node, nullptr); |
| 1320 } | 1297 } |
| 1321 } else { | 1298 } else { |
| 1322 // We have a load from a non-const index, cannot eliminate object. | 1299 // We have a load from a non-const index, cannot eliminate object. |
| 1323 if (SetEscaped(from)) { | 1300 if (SetEscaped(from)) { |
| 1324 if (FLAG_trace_turbo_escape) { | 1301 TRACE( |
| 1325 PrintF( | 1302 "Setting #%d (%s) to escaped because load element #%d from non-const " |
| 1326 "Setting #%d (%s) to escaped because load element #%d from " | 1303 "index #%d (%s)\n", |
| 1327 "non-const " | 1304 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
| 1328 "index #%d (%s)\n", | 1305 index_node->op()->mnemonic()); |
| 1329 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | |
| 1330 index_node->op()->mnemonic()); | |
| 1331 } | |
| 1332 } | 1306 } |
| 1333 } | 1307 } |
| 1334 } | 1308 } |
| 1335 | 1309 |
| 1336 | 1310 |
| 1337 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1311 void EscapeAnalysis::ProcessStoreField(Node* node) { |
| 1338 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1312 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
| 1339 ForwardVirtualState(node); | 1313 ForwardVirtualState(node); |
| 1340 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1314 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
| 1341 VirtualState* state = virtual_states_[node->id()]; | 1315 VirtualState* state = virtual_states_[node->id()]; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1370 kPointerSizeLog2); | 1344 kPointerSizeLog2); |
| 1371 CHECK_EQ(access.header_size % kPointerSize, 0); | 1345 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1372 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); | 1346 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
| 1373 if (obj->SetField(offset, val)) { | 1347 if (obj->SetField(offset, val)) { |
| 1374 state->LastChangedAt(node); | 1348 state->LastChangedAt(node); |
| 1375 } | 1349 } |
| 1376 } | 1350 } |
| 1377 } else { | 1351 } else { |
| 1378 // We have a store to a non-const index, cannot eliminate object. | 1352 // We have a store to a non-const index, cannot eliminate object. |
| 1379 if (SetEscaped(to)) { | 1353 if (SetEscaped(to)) { |
| 1380 if (FLAG_trace_turbo_escape) { | 1354 TRACE( |
| 1381 PrintF( | 1355 "Setting #%d (%s) to escaped because store element #%d to non-const " |
| 1382 "Setting #%d (%s) to escaped because store element #%d to " | 1356 "index #%d (%s)\n", |
| 1383 "non-const " | 1357 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), |
| 1384 "index #%d (%s)\n", | 1358 index_node->op()->mnemonic()); |
| 1385 to->id(), to->op()->mnemonic(), node->id(), index_node->id(), | |
| 1386 index_node->op()->mnemonic()); | |
| 1387 } | |
| 1388 } | 1359 } |
| 1389 if (obj && obj->IsTracked() && obj->ClearAllFields()) { | 1360 if (obj && obj->IsTracked() && obj->ClearAllFields()) { |
| 1390 state->LastChangedAt(node); | 1361 state->LastChangedAt(node); |
| 1362 TRACE("Cleared all fields of @%d:#%d\n", aliases_[obj->id()], obj->id()); |
| 1391 } | 1363 } |
| 1392 } | 1364 } |
| 1393 } | 1365 } |
| 1394 | 1366 |
| 1395 | 1367 |
| 1396 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1368 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| 1397 if ((node->opcode() == IrOpcode::kFinishRegion || | 1369 if ((node->opcode() == IrOpcode::kFinishRegion || |
| 1398 node->opcode() == IrOpcode::kAllocate) && | 1370 node->opcode() == IrOpcode::kAllocate) && |
| 1399 IsVirtual(node)) { | 1371 IsVirtual(node)) { |
| 1400 if (VirtualObject* vobj = | 1372 if (VirtualObject* vobj = |
| 1401 ResolveVirtualObject(virtual_states_[effect->id()], node)) { | 1373 ResolveVirtualObject(virtual_states_[effect->id()], node)) { |
| 1402 if (Node* object_state = vobj->GetObjectState()) { | 1374 if (Node* object_state = vobj->GetObjectState()) { |
| 1403 return object_state; | 1375 return object_state; |
| 1404 } else { | 1376 } else { |
| 1405 cache_->fields().clear(); | 1377 cache_->fields().clear(); |
| 1406 for (size_t i = 0; i < vobj->field_count(); ++i) { | 1378 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1407 if (Node* field = vobj->GetField(i)) { | 1379 if (Node* field = vobj->GetField(i)) { |
| 1408 cache_->fields().push_back(field); | 1380 cache_->fields().push_back(field); |
| 1409 } | 1381 } |
| 1410 } | 1382 } |
| 1411 int input_count = static_cast<int>(cache_->fields().size()); | 1383 int input_count = static_cast<int>(cache_->fields().size()); |
| 1412 Node* new_object_state = | 1384 Node* new_object_state = |
| 1413 graph()->NewNode(common()->ObjectState(input_count, vobj->id()), | 1385 graph()->NewNode(common()->ObjectState(input_count, vobj->id()), |
| 1414 input_count, &cache_->fields().front()); | 1386 input_count, &cache_->fields().front()); |
| 1415 vobj->SetObjectState(new_object_state); | 1387 vobj->SetObjectState(new_object_state); |
| 1416 if (FLAG_trace_turbo_escape) { | 1388 TRACE( |
| 1417 PrintF( | 1389 "Creating object state #%d for vobj %p (from node #%d) at effect " |
| 1418 "Creating object state #%d for vobj %p (from node #%d) at effect " | 1390 "#%d\n", |
| 1419 "#%d\n", | 1391 new_object_state->id(), static_cast<void*>(vobj), node->id(), |
| 1420 new_object_state->id(), static_cast<void*>(vobj), node->id(), | 1392 effect->id()); |
| 1421 effect->id()); | |
| 1422 } | |
| 1423 // Now fix uses of other objects. | 1393 // Now fix uses of other objects. |
| 1424 for (size_t i = 0; i < vobj->field_count(); ++i) { | 1394 for (size_t i = 0; i < vobj->field_count(); ++i) { |
| 1425 if (Node* field = vobj->GetField(i)) { | 1395 if (Node* field = vobj->GetField(i)) { |
| 1426 if (Node* field_object_state = | 1396 if (Node* field_object_state = |
| 1427 GetOrCreateObjectState(effect, field)) { | 1397 GetOrCreateObjectState(effect, field)) { |
| 1428 NodeProperties::ReplaceValueInput( | 1398 NodeProperties::ReplaceValueInput( |
| 1429 new_object_state, field_object_state, static_cast<int>(i)); | 1399 new_object_state, field_object_state, static_cast<int>(i)); |
| 1430 } | 1400 } |
| 1431 } | 1401 } |
| 1432 } | 1402 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1443 object->field_count()); | 1413 object->field_count()); |
| 1444 for (size_t i = 0; i < object->field_count(); ++i) { | 1414 for (size_t i = 0; i < object->field_count(); ++i) { |
| 1445 if (Node* f = object->GetField(i)) { | 1415 if (Node* f = object->GetField(i)) { |
| 1446 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1416 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
| 1447 } | 1417 } |
| 1448 } | 1418 } |
| 1449 } | 1419 } |
| 1450 | 1420 |
| 1451 | 1421 |
| 1452 void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 1422 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
| 1453 PrintF("Dumping object state %p\n", static_cast<void*>(state)); | 1423 PrintF("Dumping virtual state %p\n", static_cast<void*>(state)); |
| 1454 for (Alias alias = 0; alias < AliasCount(); ++alias) { | 1424 for (Alias alias = 0; alias < AliasCount(); ++alias) { |
| 1455 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { | 1425 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { |
| 1456 DebugPrintObject(object, alias); | 1426 DebugPrintObject(object, alias); |
| 1457 } | 1427 } |
| 1458 } | 1428 } |
| 1459 } | 1429 } |
| 1460 | 1430 |
| 1461 | 1431 |
| 1462 void EscapeAnalysis::DebugPrint() { | 1432 void EscapeAnalysis::DebugPrint() { |
| 1463 ZoneVector<VirtualState*> object_states(zone()); | 1433 ZoneVector<VirtualState*> object_states(zone()); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1492 return true; | 1462 return true; |
| 1493 } | 1463 } |
| 1494 } | 1464 } |
| 1495 } | 1465 } |
| 1496 return false; | 1466 return false; |
| 1497 } | 1467 } |
| 1498 | 1468 |
| 1499 } // namespace compiler | 1469 } // namespace compiler |
| 1500 } // namespace internal | 1470 } // namespace internal |
| 1501 } // namespace v8 | 1471 } // namespace v8 |
| OLD | NEW |