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 |