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 if (liveness_block() != nullptr) { |
737 liveness_block()->Bind(variable->index()); | 736 liveness_block()->Bind(variable->index()); |
737 } else { | |
738 DCHECK(!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()); | |
titzer
2015/05/20 17:57:26
You could move the DCHECKS here into a helper func
Jarin
2015/05/20 19:35:06
Done.
| |
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 if (liveness_block() != nullptr) { |
752 liveness_block()->Lookup(variable->index()); | 753 liveness_block()->Lookup(variable->index()); |
754 } else { | |
755 DCHECK(!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()); | |
753 } | 756 } |
754 return values()->at(variable->index() + parameters_count_); | 757 return values()->at(variable->index() + parameters_count_); |
755 } | 758 } |
756 } | 759 } |
757 | 760 |
758 | 761 |
759 void AstGraphBuilder::Environment::MarkAllLocalsLive() { | 762 void AstGraphBuilder::Environment::MarkAllLocalsLive() { |
760 if (FLAG_analyze_environment_liveness) { | 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 } |
767 } else { | |
768 DCHECK(!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()); | |
764 } | 769 } |
765 } | 770 } |
766 | 771 |
767 | 772 |
768 AstGraphBuilder::Environment* | 773 AstGraphBuilder::Environment* |
774 AstGraphBuilder::Environment::CopyForConditional() { | |
775 LivenessAnalyzerBlock* copy_liveness_block = nullptr; | |
776 if (liveness_block() != nullptr) { | |
777 copy_liveness_block = | |
778 builder_->liveness_analyzer()->NewBlock(liveness_block()); | |
779 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); | |
780 } | |
781 return new (zone()) Environment(this, copy_liveness_block); | |
782 } | |
783 | |
784 | |
785 AstGraphBuilder::Environment* | |
786 AstGraphBuilder::Environment::CopyAsUnreachable() { | |
787 Environment* env = new (zone()) Environment(this, nullptr); | |
788 env->MarkAsUnreachable(); | |
789 return env; | |
790 } | |
791 | |
792 | |
793 AstGraphBuilder::Environment* | |
769 AstGraphBuilder::Environment::CopyAndShareLiveness() { | 794 AstGraphBuilder::Environment::CopyAndShareLiveness() { |
770 Environment* env = new (zone()) Environment(this); | 795 if (liveness_block() != nullptr) { |
771 if (FLAG_analyze_environment_liveness) { | 796 // Finish the current liveness block before copying. |
772 env->liveness_block_ = liveness_block(); | 797 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); |
773 } | 798 } |
799 Environment* env = new (zone()) Environment(this, liveness_block()); | |
774 return env; | 800 return env; |
775 } | 801 } |
776 | 802 |
777 | 803 |
804 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop( | |
805 BitVector* assigned, bool is_osr) { | |
806 PrepareForLoop(assigned, is_osr); | |
807 return CopyAndShareLiveness(); | |
808 } | |
809 | |
810 | |
778 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, | 811 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, |
779 int offset, int count) { | 812 int offset, int count) { |
780 bool should_update = false; | 813 bool should_update = false; |
781 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); | 814 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); |
782 if (*state_values == NULL || (*state_values)->InputCount() != count) { | 815 if (*state_values == NULL || (*state_values)->InputCount() != count) { |
783 should_update = true; | 816 should_update = true; |
784 } else { | 817 } else { |
785 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); | 818 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); |
786 for (int i = 0; i < count; i++) { | 819 for (int i = 0; i < count; i++) { |
787 if ((*state_values)->InputAt(i) != env_values[i]) { | 820 if ((*state_values)->InputAt(i) != env_values[i]) { |
(...skipping 27 matching lines...) Expand all Loading... | |
815 UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count()); | 848 UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count()); |
816 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), | 849 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), |
817 stack_height()); | 850 stack_height()); |
818 | 851 |
819 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine); | 852 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine); |
820 | 853 |
821 Node* result = graph()->NewNode(op, parameters_node_, locals_node_, | 854 Node* result = graph()->NewNode(op, parameters_node_, locals_node_, |
822 stack_node_, builder()->current_context(), | 855 stack_node_, builder()->current_context(), |
823 builder()->GetFunctionClosure(), | 856 builder()->GetFunctionClosure(), |
824 builder()->jsgraph()->UndefinedConstant()); | 857 builder()->jsgraph()->UndefinedConstant()); |
825 if (FLAG_analyze_environment_liveness) { | 858 if (liveness_block() != nullptr) { |
826 liveness_block()->Checkpoint(result); | 859 liveness_block()->Checkpoint(result); |
860 } else { | |
861 DCHECK(!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()); | |
827 } | 862 } |
828 return result; | 863 return result; |
829 } | 864 } |
830 | 865 |
831 | 866 |
867 bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() { | |
868 return FLAG_analyze_environment_liveness && | |
869 builder()->info()->is_deoptimization_enabled(); | |
870 } | |
871 | |
872 | |
832 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, | 873 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, |
833 Expression::Context kind) | 874 Expression::Context kind) |
834 : kind_(kind), owner_(own), outer_(own->ast_context()) { | 875 : kind_(kind), owner_(own), outer_(own->ast_context()) { |
835 owner()->set_ast_context(this); // Push. | 876 owner()->set_ast_context(this); // Push. |
836 #ifdef DEBUG | 877 #ifdef DEBUG |
837 original_height_ = environment()->stack_height(); | 878 original_height_ = environment()->stack_height(); |
838 #endif | 879 #endif |
839 } | 880 } |
840 | 881 |
841 | 882 |
(...skipping 2615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3457 if (has_effect) { | 3498 if (has_effect) { |
3458 environment_->UpdateEffectDependency(result); | 3499 environment_->UpdateEffectDependency(result); |
3459 } | 3500 } |
3460 if (!environment()->IsMarkedAsUnreachable()) { | 3501 if (!environment()->IsMarkedAsUnreachable()) { |
3461 // Update the current control dependency for control-producing nodes. | 3502 // Update the current control dependency for control-producing nodes. |
3462 if (NodeProperties::IsControl(result)) { | 3503 if (NodeProperties::IsControl(result)) { |
3463 environment_->UpdateControlDependency(result); | 3504 environment_->UpdateControlDependency(result); |
3464 } | 3505 } |
3465 // Add implicit exception continuation for throwing nodes. | 3506 // Add implicit exception continuation for throwing nodes. |
3466 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { | 3507 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { |
3508 // Copy the environment for the success continuation. | |
3509 Environment* success_env = environment()->CopyForConditional(); | |
3510 | |
3467 Node* on_exception = graph()->NewNode(common()->IfException(), result); | 3511 Node* on_exception = graph()->NewNode(common()->IfException(), result); |
3468 environment_->UpdateControlDependency(on_exception); | 3512 environment_->UpdateControlDependency(on_exception); |
3469 execution_control()->ThrowValue(on_exception); | 3513 execution_control()->ThrowValue(on_exception); |
3514 set_environment(success_env); | |
3470 } | 3515 } |
3471 // Add implicit success continuation for throwing nodes. | 3516 // Add implicit success continuation for throwing nodes. |
3472 if (!result->op()->HasProperty(Operator::kNoThrow)) { | 3517 if (!result->op()->HasProperty(Operator::kNoThrow)) { |
3473 Node* on_success = graph()->NewNode(common()->IfSuccess(), result); | 3518 Node* on_success = graph()->NewNode(common()->IfSuccess(), result); |
3474 environment_->UpdateControlDependency(on_success); | 3519 environment_->UpdateControlDependency(on_success); |
3475 } | 3520 } |
3476 } | 3521 } |
3477 } | 3522 } |
3478 | 3523 |
3479 return result; | 3524 return result; |
(...skipping 15 matching lines...) Expand all Loading... | |
3495 DCHECK(contexts_.size() == other->contexts_.size()); | 3540 DCHECK(contexts_.size() == other->contexts_.size()); |
3496 | 3541 |
3497 // Nothing to do if the other environment is dead. | 3542 // Nothing to do if the other environment is dead. |
3498 if (other->IsMarkedAsUnreachable()) return; | 3543 if (other->IsMarkedAsUnreachable()) return; |
3499 | 3544 |
3500 // Resurrect a dead environment by copying the contents of the other one and | 3545 // Resurrect a dead environment by copying the contents of the other one and |
3501 // placing a singleton merge as the new control dependency. | 3546 // placing a singleton merge as the new control dependency. |
3502 if (this->IsMarkedAsUnreachable()) { | 3547 if (this->IsMarkedAsUnreachable()) { |
3503 Node* other_control = other->control_dependency_; | 3548 Node* other_control = other->control_dependency_; |
3504 Node* inputs[] = {other_control}; | 3549 Node* inputs[] = {other_control}; |
3505 liveness_block_ = other->liveness_block_; | |
3506 control_dependency_ = | 3550 control_dependency_ = |
3507 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); | 3551 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); |
3508 effect_dependency_ = other->effect_dependency_; | 3552 effect_dependency_ = other->effect_dependency_; |
3509 values_ = other->values_; | 3553 values_ = other->values_; |
3510 contexts_ = other->contexts_; | 3554 contexts_ = other->contexts_; |
3555 if (IsLivenessAnalysisEnabled()) { | |
3556 liveness_block_ = | |
3557 builder_->liveness_analyzer()->NewBlock(other->liveness_block()); | |
3558 } | |
3511 return; | 3559 return; |
3512 } | 3560 } |
3513 | 3561 |
3514 // Record the merge for the local variable liveness calculation. | 3562 // Record the merge for the local variable liveness calculation. |
3515 // Unfortunately, we have to mirror the logic in the MergeControl method: | 3563 // For loops, we are connecting a back edge into the existing block; |
3516 // connect before merge or loop, or create a new merge otherwise. | 3564 // for merges, we create a new merged block. |
3517 if (FLAG_analyze_environment_liveness) { | 3565 if (IsLivenessAnalysisEnabled()) { |
3518 if (GetControlDependency()->opcode() != IrOpcode::kLoop && | 3566 if (GetControlDependency()->opcode() != IrOpcode::kLoop) { |
3519 GetControlDependency()->opcode() != IrOpcode::kMerge) { | |
3520 liveness_block_ = | 3567 liveness_block_ = |
3521 builder_->liveness_analyzer()->NewBlock(liveness_block()); | 3568 builder_->liveness_analyzer()->NewBlock(liveness_block()); |
3522 } | 3569 } |
3523 liveness_block()->AddPredecessor(other->liveness_block()); | 3570 liveness_block()->AddPredecessor(other->liveness_block()); |
3524 } | 3571 } |
3525 | 3572 |
3526 // Create a merge of the control dependencies of both environments and update | 3573 // Create a merge of the control dependencies of both environments and update |
3527 // the current environment's control dependency accordingly. | 3574 // the current environment's control dependency accordingly. |
3528 Node* control = builder_->MergeControl(this->GetControlDependency(), | 3575 Node* control = builder_->MergeControl(this->GetControlDependency(), |
3529 other->GetControlDependency()); | 3576 other->GetControlDependency()); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3686 // Phi does not exist yet, introduce one. | 3733 // Phi does not exist yet, introduce one. |
3687 value = NewPhi(inputs, value, control); | 3734 value = NewPhi(inputs, value, control); |
3688 value->ReplaceInput(inputs - 1, other); | 3735 value->ReplaceInput(inputs - 1, other); |
3689 } | 3736 } |
3690 return value; | 3737 return value; |
3691 } | 3738 } |
3692 | 3739 |
3693 } // namespace compiler | 3740 } // namespace compiler |
3694 } // namespace internal | 3741 } // namespace internal |
3695 } // namespace v8 | 3742 } // namespace v8 |
OLD | NEW |