OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/ast-graph-builder.h" | 5 #include "src/compiler/ast-graph-builder.h" |
6 | 6 |
7 #include "src/compiler.h" | 7 #include "src/compiler.h" |
8 #include "src/compiler/ast-loop-assignment-analyzer.h" | 8 #include "src/compiler/ast-loop-assignment-analyzer.h" |
9 #include "src/compiler/control-builders.h" | 9 #include "src/compiler/control-builders.h" |
10 #include "src/compiler/js-type-feedback.h" | 10 #include "src/compiler/js-type-feedback.h" |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 Node* return_value = jsgraph()->UndefinedConstant(); | 592 Node* return_value = jsgraph()->UndefinedConstant(); |
593 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); | 593 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); |
594 } | 594 } |
595 | 595 |
596 // Return 'undefined' in case we can fall off the end. | 596 // Return 'undefined' in case we can fall off the end. |
597 BuildReturn(jsgraph()->UndefinedConstant()); | 597 BuildReturn(jsgraph()->UndefinedConstant()); |
598 } | 598 } |
599 | 599 |
600 | 600 |
601 void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() { | 601 void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() { |
602 if (!FLAG_analyze_environment_liveness) return; | 602 if (!FLAG_analyze_environment_liveness || |
| 603 !info()->is_deoptimization_enabled()) { |
| 604 return; |
| 605 } |
603 | 606 |
604 NonLiveFrameStateSlotReplacer replacer( | 607 NonLiveFrameStateSlotReplacer replacer( |
605 &state_values_cache_, jsgraph()->UndefinedConstant(), | 608 &state_values_cache_, jsgraph()->UndefinedConstant(), |
606 liveness_analyzer()->local_count(), local_zone()); | 609 liveness_analyzer()->local_count(), local_zone()); |
607 Variable* arguments = info()->scope()->arguments(); | 610 Variable* arguments = info()->scope()->arguments(); |
608 if (arguments != nullptr && arguments->IsStackAllocated()) { | 611 if (arguments != nullptr && arguments->IsStackAllocated()) { |
609 replacer.MarkPermanentlyLive(arguments->index()); | 612 replacer.MarkPermanentlyLive(arguments->index()); |
610 } | 613 } |
611 liveness_analyzer()->Run(&replacer); | 614 liveness_analyzer()->Run(&replacer); |
612 if (FLAG_trace_environment_liveness) { | 615 if (FLAG_trace_environment_liveness) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 return nullptr; | 656 return nullptr; |
654 } | 657 } |
655 | 658 |
656 | 659 |
657 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, | 660 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, |
658 Scope* scope, | 661 Scope* scope, |
659 Node* control_dependency) | 662 Node* control_dependency) |
660 : builder_(builder), | 663 : builder_(builder), |
661 parameters_count_(scope->num_parameters() + 1), | 664 parameters_count_(scope->num_parameters() + 1), |
662 locals_count_(scope->num_stack_slots()), | 665 locals_count_(scope->num_stack_slots()), |
663 liveness_block_(builder_->liveness_analyzer()->NewBlock()), | 666 liveness_block_(IsLivenessAnalysisEnabled() |
| 667 ? builder_->liveness_analyzer()->NewBlock() |
| 668 : nullptr), |
664 values_(builder_->local_zone()), | 669 values_(builder_->local_zone()), |
665 contexts_(builder_->local_zone()), | 670 contexts_(builder_->local_zone()), |
666 control_dependency_(control_dependency), | 671 control_dependency_(control_dependency), |
667 effect_dependency_(control_dependency), | 672 effect_dependency_(control_dependency), |
668 parameters_node_(nullptr), | 673 parameters_node_(nullptr), |
669 locals_node_(nullptr), | 674 locals_node_(nullptr), |
670 stack_node_(nullptr) { | 675 stack_node_(nullptr) { |
671 DCHECK_EQ(scope->num_parameters() + 1, parameters_count()); | 676 DCHECK_EQ(scope->num_parameters() + 1, parameters_count()); |
672 | 677 |
673 // Bind the receiver variable. | 678 // Bind the receiver variable. |
(...skipping 15 matching lines...) Expand all Loading... |
689 builder->graph()->start()); | 694 builder->graph()->start()); |
690 values()->push_back(parameter); | 695 values()->push_back(parameter); |
691 } | 696 } |
692 | 697 |
693 // Bind all local variables to undefined. | 698 // Bind all local variables to undefined. |
694 Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); | 699 Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); |
695 values()->insert(values()->end(), locals_count(), undefined_constant); | 700 values()->insert(values()->end(), locals_count(), undefined_constant); |
696 } | 701 } |
697 | 702 |
698 | 703 |
699 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy) | 704 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy, |
| 705 LivenessAnalyzerBlock* liveness_block) |
700 : builder_(copy->builder_), | 706 : builder_(copy->builder_), |
701 parameters_count_(copy->parameters_count_), | 707 parameters_count_(copy->parameters_count_), |
702 locals_count_(copy->locals_count_), | 708 locals_count_(copy->locals_count_), |
| 709 liveness_block_(liveness_block), |
703 values_(copy->zone()), | 710 values_(copy->zone()), |
704 contexts_(copy->zone()), | 711 contexts_(copy->zone()), |
705 control_dependency_(copy->control_dependency_), | 712 control_dependency_(copy->control_dependency_), |
706 effect_dependency_(copy->effect_dependency_), | 713 effect_dependency_(copy->effect_dependency_), |
707 parameters_node_(copy->parameters_node_), | 714 parameters_node_(copy->parameters_node_), |
708 locals_node_(copy->locals_node_), | 715 locals_node_(copy->locals_node_), |
709 stack_node_(copy->stack_node_) { | 716 stack_node_(copy->stack_node_) { |
710 const size_t kStackEstimate = 7; // optimum from experimentation! | 717 const size_t kStackEstimate = 7; // optimum from experimentation! |
711 values_.reserve(copy->values_.size() + kStackEstimate); | 718 values_.reserve(copy->values_.size() + kStackEstimate); |
712 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end()); | 719 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end()); |
713 contexts_.reserve(copy->contexts_.size()); | 720 contexts_.reserve(copy->contexts_.size()); |
714 contexts_.insert(contexts_.begin(), copy->contexts_.begin(), | 721 contexts_.insert(contexts_.begin(), copy->contexts_.begin(), |
715 copy->contexts_.end()); | 722 copy->contexts_.end()); |
716 | |
717 if (FLAG_analyze_environment_liveness) { | |
718 // Split the liveness blocks. | |
719 copy->liveness_block_ = | |
720 builder_->liveness_analyzer()->NewBlock(copy->liveness_block()); | |
721 liveness_block_ = | |
722 builder_->liveness_analyzer()->NewBlock(copy->liveness_block()); | |
723 } | |
724 } | 723 } |
725 | 724 |
726 | 725 |
727 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) { | 726 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) { |
728 DCHECK(variable->IsStackAllocated()); | 727 DCHECK(variable->IsStackAllocated()); |
729 if (variable->IsParameter()) { | 728 if (variable->IsParameter()) { |
730 // The parameter indices are shifted by 1 (receiver is parameter | 729 // The parameter indices are shifted by 1 (receiver is parameter |
731 // index -1 but environment index 0). | 730 // index -1 but environment index 0). |
732 values()->at(variable->index() + 1) = node; | 731 values()->at(variable->index() + 1) = node; |
733 } else { | 732 } else { |
734 DCHECK(variable->IsStackLocal()); | 733 DCHECK(variable->IsStackLocal()); |
735 values()->at(variable->index() + parameters_count_) = node; | 734 values()->at(variable->index() + parameters_count_) = node; |
736 if (FLAG_analyze_environment_liveness) { | 735 |
| 736 DCHECK(IsLivenessBlockConsistent()); |
| 737 if (liveness_block() != nullptr) { |
737 liveness_block()->Bind(variable->index()); | 738 liveness_block()->Bind(variable->index()); |
738 } | 739 } |
739 } | 740 } |
740 } | 741 } |
741 | 742 |
742 | 743 |
743 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) { | 744 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) { |
744 DCHECK(variable->IsStackAllocated()); | 745 DCHECK(variable->IsStackAllocated()); |
745 if (variable->IsParameter()) { | 746 if (variable->IsParameter()) { |
746 // The parameter indices are shifted by 1 (receiver is parameter | 747 // The parameter indices are shifted by 1 (receiver is parameter |
747 // index -1 but environment index 0). | 748 // index -1 but environment index 0). |
748 return values()->at(variable->index() + 1); | 749 return values()->at(variable->index() + 1); |
749 } else { | 750 } else { |
750 DCHECK(variable->IsStackLocal()); | 751 DCHECK(variable->IsStackLocal()); |
751 if (FLAG_analyze_environment_liveness) { | 752 DCHECK(IsLivenessBlockConsistent()); |
| 753 if (liveness_block() != nullptr) { |
752 liveness_block()->Lookup(variable->index()); | 754 liveness_block()->Lookup(variable->index()); |
753 } | 755 } |
754 return values()->at(variable->index() + parameters_count_); | 756 return values()->at(variable->index() + parameters_count_); |
755 } | 757 } |
756 } | 758 } |
757 | 759 |
758 | 760 |
759 void AstGraphBuilder::Environment::MarkAllLocalsLive() { | 761 void AstGraphBuilder::Environment::MarkAllLocalsLive() { |
760 if (FLAG_analyze_environment_liveness) { | 762 DCHECK(IsLivenessBlockConsistent()); |
| 763 if (liveness_block() != nullptr) { |
761 for (int i = 0; i < locals_count_; i++) { | 764 for (int i = 0; i < locals_count_; i++) { |
762 liveness_block()->Lookup(i); | 765 liveness_block()->Lookup(i); |
763 } | 766 } |
764 } | 767 } |
765 } | 768 } |
766 | 769 |
767 | 770 |
768 AstGraphBuilder::Environment* | 771 AstGraphBuilder::Environment* |
| 772 AstGraphBuilder::Environment::CopyForConditional() { |
| 773 LivenessAnalyzerBlock* copy_liveness_block = nullptr; |
| 774 if (liveness_block() != nullptr) { |
| 775 copy_liveness_block = |
| 776 builder_->liveness_analyzer()->NewBlock(liveness_block()); |
| 777 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); |
| 778 } |
| 779 return new (zone()) Environment(this, copy_liveness_block); |
| 780 } |
| 781 |
| 782 |
| 783 AstGraphBuilder::Environment* |
| 784 AstGraphBuilder::Environment::CopyAsUnreachable() { |
| 785 Environment* env = new (zone()) Environment(this, nullptr); |
| 786 env->MarkAsUnreachable(); |
| 787 return env; |
| 788 } |
| 789 |
| 790 |
| 791 AstGraphBuilder::Environment* |
769 AstGraphBuilder::Environment::CopyAndShareLiveness() { | 792 AstGraphBuilder::Environment::CopyAndShareLiveness() { |
770 Environment* env = new (zone()) Environment(this); | 793 if (liveness_block() != nullptr) { |
771 if (FLAG_analyze_environment_liveness) { | 794 // Finish the current liveness block before copying. |
772 env->liveness_block_ = liveness_block(); | 795 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); |
773 } | 796 } |
| 797 Environment* env = new (zone()) Environment(this, liveness_block()); |
774 return env; | 798 return env; |
775 } | 799 } |
776 | 800 |
777 | 801 |
| 802 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop( |
| 803 BitVector* assigned, bool is_osr) { |
| 804 PrepareForLoop(assigned, is_osr); |
| 805 return CopyAndShareLiveness(); |
| 806 } |
| 807 |
| 808 |
778 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, | 809 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, |
779 int offset, int count) { | 810 int offset, int count) { |
780 bool should_update = false; | 811 bool should_update = false; |
781 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); | 812 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); |
782 if (*state_values == NULL || (*state_values)->InputCount() != count) { | 813 if (*state_values == NULL || (*state_values)->InputCount() != count) { |
783 should_update = true; | 814 should_update = true; |
784 } else { | 815 } else { |
785 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); | 816 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); |
786 for (int i = 0; i < count; i++) { | 817 for (int i = 0; i < count; i++) { |
787 if ((*state_values)->InputAt(i) != env_values[i]) { | 818 if ((*state_values)->InputAt(i) != env_values[i]) { |
(...skipping 27 matching lines...) Expand all Loading... |
815 UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count()); | 846 UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count()); |
816 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), | 847 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), |
817 stack_height()); | 848 stack_height()); |
818 | 849 |
819 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine); | 850 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine); |
820 | 851 |
821 Node* result = graph()->NewNode(op, parameters_node_, locals_node_, | 852 Node* result = graph()->NewNode(op, parameters_node_, locals_node_, |
822 stack_node_, builder()->current_context(), | 853 stack_node_, builder()->current_context(), |
823 builder()->GetFunctionClosure(), | 854 builder()->GetFunctionClosure(), |
824 builder()->jsgraph()->UndefinedConstant()); | 855 builder()->jsgraph()->UndefinedConstant()); |
825 if (FLAG_analyze_environment_liveness) { | 856 |
| 857 DCHECK(IsLivenessBlockConsistent()); |
| 858 if (liveness_block() != nullptr) { |
826 liveness_block()->Checkpoint(result); | 859 liveness_block()->Checkpoint(result); |
827 } | 860 } |
828 return result; | 861 return result; |
829 } | 862 } |
830 | 863 |
831 | 864 |
| 865 bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() { |
| 866 return FLAG_analyze_environment_liveness && |
| 867 builder()->info()->is_deoptimization_enabled(); |
| 868 } |
| 869 |
| 870 |
| 871 bool AstGraphBuilder::Environment::IsLivenessBlockConsistent() { |
| 872 return (!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()) == |
| 873 (liveness_block() == nullptr); |
| 874 } |
| 875 |
| 876 |
832 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, | 877 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, |
833 Expression::Context kind) | 878 Expression::Context kind) |
834 : kind_(kind), owner_(own), outer_(own->ast_context()) { | 879 : kind_(kind), owner_(own), outer_(own->ast_context()) { |
835 owner()->set_ast_context(this); // Push. | 880 owner()->set_ast_context(this); // Push. |
836 #ifdef DEBUG | 881 #ifdef DEBUG |
837 original_height_ = environment()->stack_height(); | 882 original_height_ = environment()->stack_height(); |
838 #endif | 883 #endif |
839 } | 884 } |
840 | 885 |
841 | 886 |
(...skipping 2615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3457 if (has_effect) { | 3502 if (has_effect) { |
3458 environment_->UpdateEffectDependency(result); | 3503 environment_->UpdateEffectDependency(result); |
3459 } | 3504 } |
3460 if (!environment()->IsMarkedAsUnreachable()) { | 3505 if (!environment()->IsMarkedAsUnreachable()) { |
3461 // Update the current control dependency for control-producing nodes. | 3506 // Update the current control dependency for control-producing nodes. |
3462 if (NodeProperties::IsControl(result)) { | 3507 if (NodeProperties::IsControl(result)) { |
3463 environment_->UpdateControlDependency(result); | 3508 environment_->UpdateControlDependency(result); |
3464 } | 3509 } |
3465 // Add implicit exception continuation for throwing nodes. | 3510 // Add implicit exception continuation for throwing nodes. |
3466 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { | 3511 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { |
| 3512 // Copy the environment for the success continuation. |
| 3513 Environment* success_env = environment()->CopyForConditional(); |
| 3514 |
3467 Node* on_exception = graph()->NewNode(common()->IfException(), result); | 3515 Node* on_exception = graph()->NewNode(common()->IfException(), result); |
3468 environment_->UpdateControlDependency(on_exception); | 3516 environment_->UpdateControlDependency(on_exception); |
3469 execution_control()->ThrowValue(on_exception); | 3517 execution_control()->ThrowValue(on_exception); |
| 3518 set_environment(success_env); |
3470 } | 3519 } |
3471 // Add implicit success continuation for throwing nodes. | 3520 // Add implicit success continuation for throwing nodes. |
3472 if (!result->op()->HasProperty(Operator::kNoThrow)) { | 3521 if (!result->op()->HasProperty(Operator::kNoThrow)) { |
3473 Node* on_success = graph()->NewNode(common()->IfSuccess(), result); | 3522 Node* on_success = graph()->NewNode(common()->IfSuccess(), result); |
3474 environment_->UpdateControlDependency(on_success); | 3523 environment_->UpdateControlDependency(on_success); |
3475 } | 3524 } |
3476 } | 3525 } |
3477 } | 3526 } |
3478 | 3527 |
3479 return result; | 3528 return result; |
(...skipping 15 matching lines...) Expand all Loading... |
3495 DCHECK(contexts_.size() == other->contexts_.size()); | 3544 DCHECK(contexts_.size() == other->contexts_.size()); |
3496 | 3545 |
3497 // Nothing to do if the other environment is dead. | 3546 // Nothing to do if the other environment is dead. |
3498 if (other->IsMarkedAsUnreachable()) return; | 3547 if (other->IsMarkedAsUnreachable()) return; |
3499 | 3548 |
3500 // Resurrect a dead environment by copying the contents of the other one and | 3549 // Resurrect a dead environment by copying the contents of the other one and |
3501 // placing a singleton merge as the new control dependency. | 3550 // placing a singleton merge as the new control dependency. |
3502 if (this->IsMarkedAsUnreachable()) { | 3551 if (this->IsMarkedAsUnreachable()) { |
3503 Node* other_control = other->control_dependency_; | 3552 Node* other_control = other->control_dependency_; |
3504 Node* inputs[] = {other_control}; | 3553 Node* inputs[] = {other_control}; |
3505 liveness_block_ = other->liveness_block_; | |
3506 control_dependency_ = | 3554 control_dependency_ = |
3507 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); | 3555 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); |
3508 effect_dependency_ = other->effect_dependency_; | 3556 effect_dependency_ = other->effect_dependency_; |
3509 values_ = other->values_; | 3557 values_ = other->values_; |
3510 contexts_ = other->contexts_; | 3558 contexts_ = other->contexts_; |
| 3559 if (IsLivenessAnalysisEnabled()) { |
| 3560 liveness_block_ = |
| 3561 builder_->liveness_analyzer()->NewBlock(other->liveness_block()); |
| 3562 } |
3511 return; | 3563 return; |
3512 } | 3564 } |
3513 | 3565 |
3514 // Record the merge for the local variable liveness calculation. | 3566 // Record the merge for the local variable liveness calculation. |
3515 // Unfortunately, we have to mirror the logic in the MergeControl method: | 3567 // For loops, we are connecting a back edge into the existing block; |
3516 // connect before merge or loop, or create a new merge otherwise. | 3568 // for merges, we create a new merged block. |
3517 if (FLAG_analyze_environment_liveness) { | 3569 if (IsLivenessAnalysisEnabled()) { |
3518 if (GetControlDependency()->opcode() != IrOpcode::kLoop && | 3570 if (GetControlDependency()->opcode() != IrOpcode::kLoop) { |
3519 GetControlDependency()->opcode() != IrOpcode::kMerge) { | |
3520 liveness_block_ = | 3571 liveness_block_ = |
3521 builder_->liveness_analyzer()->NewBlock(liveness_block()); | 3572 builder_->liveness_analyzer()->NewBlock(liveness_block()); |
3522 } | 3573 } |
3523 liveness_block()->AddPredecessor(other->liveness_block()); | 3574 liveness_block()->AddPredecessor(other->liveness_block()); |
3524 } | 3575 } |
3525 | 3576 |
3526 // Create a merge of the control dependencies of both environments and update | 3577 // Create a merge of the control dependencies of both environments and update |
3527 // the current environment's control dependency accordingly. | 3578 // the current environment's control dependency accordingly. |
3528 Node* control = builder_->MergeControl(this->GetControlDependency(), | 3579 Node* control = builder_->MergeControl(this->GetControlDependency(), |
3529 other->GetControlDependency()); | 3580 other->GetControlDependency()); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3686 // Phi does not exist yet, introduce one. | 3737 // Phi does not exist yet, introduce one. |
3687 value = NewPhi(inputs, value, control); | 3738 value = NewPhi(inputs, value, control); |
3688 value->ReplaceInput(inputs - 1, other); | 3739 value->ReplaceInput(inputs - 1, other); |
3689 } | 3740 } |
3690 return value; | 3741 return value; |
3691 } | 3742 } |
3692 | 3743 |
3693 } // namespace compiler | 3744 } // namespace compiler |
3694 } // namespace internal | 3745 } // namespace internal |
3695 } // namespace v8 | 3746 } // namespace v8 |
OLD | NEW |