Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "data-flow.h" | 30 #include "data-flow.h" |
| 31 #include "flow-graph.h" | |
| 32 #include "scopes.h" | 31 #include "scopes.h" |
| 33 | 32 |
| 34 namespace v8 { | 33 namespace v8 { |
| 35 namespace internal { | 34 namespace internal { |
| 36 | 35 |
| 37 | 36 |
| 38 #ifdef DEBUG | 37 #ifdef DEBUG |
| 39 void BitVector::Print() { | 38 void BitVector::Print() { |
| 40 bool first = true; | 39 bool first = true; |
| 41 PrintF("{"); | 40 PrintF("{"); |
| (...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 CatchExtensionObject* expr) { | 613 CatchExtensionObject* expr) { |
| 615 ASSERT(av_.IsEmpty()); | 614 ASSERT(av_.IsEmpty()); |
| 616 Visit(expr->key()); | 615 Visit(expr->key()); |
| 617 ProcessExpression(expr->value()); | 616 ProcessExpression(expr->value()); |
| 618 } | 617 } |
| 619 | 618 |
| 620 | 619 |
| 621 void AssignedVariablesAnalyzer::VisitAssignment(Assignment* expr) { | 620 void AssignedVariablesAnalyzer::VisitAssignment(Assignment* expr) { |
| 622 ASSERT(av_.IsEmpty()); | 621 ASSERT(av_.IsEmpty()); |
| 623 | 622 |
| 624 if (expr->target()->AsProperty() != NULL) { | 623 // There are three kinds of assignments: variable assignments, property |
| 625 // Visit receiver and key of property store and rhs. | 624 // assignments, and reference errors (invalid left-hand sides). |
| 626 Visit(expr->target()->AsProperty()->obj()); | 625 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 627 ProcessExpression(expr->target()->AsProperty()->key()); | 626 Property* prop = expr->target()->AsProperty(); |
| 628 ProcessExpression(expr->value()); | 627 ASSERT(var == NULL || prop == NULL); |
| 629 | 628 |
| 630 // If we have a variable as a receiver in a property store, check if | 629 if (var != NULL) { |
| 631 // we can mark it as trivial. | 630 MarkIfTrivial(expr->value()); |
| 632 MarkIfTrivial(expr->target()->AsProperty()->obj()); | 631 Visit(expr->value()); |
| 632 if (expr->is_compound()) { | |
| 633 // Left-hand side occurs also as an rvalue. | |
| 634 MarkIfTrivial(expr->target()); | |
| 635 ProcessExpression(expr->target()); | |
| 636 } | |
| 637 RecordAssignedVar(var); | |
| 638 | |
| 639 } else if (prop != NULL) { | |
| 640 MarkIfTrivial(expr->value()); | |
| 641 Visit(expr->value()); | |
| 642 if (!prop->key()->IsPropertyName()) { | |
| 643 MarkIfTrivial(prop->key()); | |
| 644 ProcessExpression(prop->key()); | |
| 645 } | |
| 646 MarkIfTrivial(prop->obj()); | |
| 647 ProcessExpression(prop->obj()); | |
| 648 | |
| 633 } else { | 649 } else { |
| 634 Visit(expr->target()); | 650 Visit(expr->target()); |
| 635 ProcessExpression(expr->value()); | |
| 636 | |
| 637 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | |
| 638 if (var != NULL) RecordAssignedVar(var); | |
| 639 } | 651 } |
| 640 } | 652 } |
| 641 | 653 |
| 642 | 654 |
| 643 void AssignedVariablesAnalyzer::VisitThrow(Throw* expr) { | 655 void AssignedVariablesAnalyzer::VisitThrow(Throw* expr) { |
| 644 ASSERT(av_.IsEmpty()); | 656 ASSERT(av_.IsEmpty()); |
| 645 Visit(expr->exception()); | 657 Visit(expr->exception()); |
| 646 } | 658 } |
| 647 | 659 |
| 648 | 660 |
| 649 void AssignedVariablesAnalyzer::VisitProperty(Property* expr) { | 661 void AssignedVariablesAnalyzer::VisitProperty(Property* expr) { |
| 650 ASSERT(av_.IsEmpty()); | 662 ASSERT(av_.IsEmpty()); |
| 651 Visit(expr->obj()); | 663 if (!expr->key()->IsPropertyName()) { |
| 664 MarkIfTrivial(expr->key()); | |
| 665 Visit(expr->key()); | |
| 666 } | |
| 667 MarkIfTrivial(expr->obj()); | |
| 652 ProcessExpression(expr->key()); | 668 ProcessExpression(expr->key()); |
|
fschneider
2010/03/29 13:49:59
That should be
ProcessExpression(expr->obj());
Kevin Millikin (Chromium)
2010/03/29 14:22:53
Thank you.
| |
| 653 | |
| 654 // In case we have a variable as a receiver, check if we can mark | |
| 655 // it as trivial. | |
| 656 MarkIfTrivial(expr->obj()); | |
| 657 } | 669 } |
| 658 | 670 |
| 659 | 671 |
| 660 void AssignedVariablesAnalyzer::VisitCall(Call* expr) { | 672 void AssignedVariablesAnalyzer::VisitCall(Call* expr) { |
| 661 ASSERT(av_.IsEmpty()); | 673 ASSERT(av_.IsEmpty()); |
| 662 Visit(expr->expression()); | 674 Visit(expr->expression()); |
| 663 BitVector result(av_); | 675 BitVector result(av_); |
| 664 for (int i = 0; i < expr->arguments()->length(); i++) { | 676 for (int i = 0; i < expr->arguments()->length(); i++) { |
| 665 av_.Clear(); | 677 av_.Clear(); |
| 666 Visit(expr->arguments()->at(i)); | 678 Visit(expr->arguments()->at(i)); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 706 | 718 |
| 707 Visit(expr->expression()); | 719 Visit(expr->expression()); |
| 708 | 720 |
| 709 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 721 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 710 if (var != NULL) RecordAssignedVar(var); | 722 if (var != NULL) RecordAssignedVar(var); |
| 711 } | 723 } |
| 712 | 724 |
| 713 | 725 |
| 714 void AssignedVariablesAnalyzer::VisitBinaryOperation(BinaryOperation* expr) { | 726 void AssignedVariablesAnalyzer::VisitBinaryOperation(BinaryOperation* expr) { |
| 715 ASSERT(av_.IsEmpty()); | 727 ASSERT(av_.IsEmpty()); |
| 716 Visit(expr->left()); | 728 MarkIfTrivial(expr->right()); |
| 717 | 729 Visit(expr->right()); |
| 718 ProcessExpression(expr->right()); | |
| 719 | |
| 720 // In case we have a variable on the left side, check if we can mark | |
| 721 // it as trivial. | |
| 722 MarkIfTrivial(expr->left()); | 730 MarkIfTrivial(expr->left()); |
| 731 ProcessExpression(expr->left()); | |
| 723 } | 732 } |
| 724 | 733 |
| 725 | 734 |
| 726 void AssignedVariablesAnalyzer::VisitCompareOperation(CompareOperation* expr) { | 735 void AssignedVariablesAnalyzer::VisitCompareOperation(CompareOperation* expr) { |
| 727 ASSERT(av_.IsEmpty()); | 736 ASSERT(av_.IsEmpty()); |
| 728 Visit(expr->left()); | 737 MarkIfTrivial(expr->right()); |
| 729 | 738 Visit(expr->right()); |
| 730 ProcessExpression(expr->right()); | |
| 731 | |
| 732 // In case we have a variable on the left side, check if we can mark | |
| 733 // it as trivial. | |
| 734 MarkIfTrivial(expr->left()); | 739 MarkIfTrivial(expr->left()); |
| 740 ProcessExpression(expr->left()); | |
| 735 } | 741 } |
| 736 | 742 |
| 737 | 743 |
| 738 void AssignedVariablesAnalyzer::VisitThisFunction(ThisFunction* expr) { | 744 void AssignedVariablesAnalyzer::VisitThisFunction(ThisFunction* expr) { |
| 739 // Nothing to do. | 745 // Nothing to do. |
| 740 ASSERT(av_.IsEmpty()); | 746 ASSERT(av_.IsEmpty()); |
| 741 } | 747 } |
| 742 | 748 |
| 743 | 749 |
| 744 void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) { | 750 void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) { |
| 745 UNREACHABLE(); | 751 UNREACHABLE(); |
| 746 } | 752 } |
| 747 | 753 |
| 748 | 754 |
| 749 int ReachingDefinitions::IndexFor(Variable* var, int variable_count) { | |
| 750 // Parameters are numbered left-to-right from the beginning of the bit | |
| 751 // set. Stack-allocated locals are allocated right-to-left from the end. | |
| 752 ASSERT(var != NULL && var->IsStackAllocated()); | |
| 753 Slot* slot = var->slot(); | |
| 754 if (slot->type() == Slot::PARAMETER) { | |
| 755 return slot->index(); | |
| 756 } else { | |
| 757 return (variable_count - 1) - slot->index(); | |
| 758 } | |
| 759 } | |
| 760 | |
| 761 | |
| 762 void Node::InitializeReachingDefinitions(int definition_count, | |
| 763 List<BitVector*>* variables, | |
| 764 WorkList<Node>* worklist, | |
| 765 bool mark) { | |
| 766 ASSERT(!IsMarkedWith(mark)); | |
| 767 rd_.Initialize(definition_count); | |
| 768 MarkWith(mark); | |
| 769 worklist->Insert(this); | |
| 770 } | |
| 771 | |
| 772 | |
| 773 void BlockNode::InitializeReachingDefinitions(int definition_count, | |
| 774 List<BitVector*>* variables, | |
| 775 WorkList<Node>* worklist, | |
| 776 bool mark) { | |
| 777 ASSERT(!IsMarkedWith(mark)); | |
| 778 int instruction_count = instructions_.length(); | |
| 779 int variable_count = variables->length(); | |
| 780 | |
| 781 rd_.Initialize(definition_count); | |
| 782 // The RD_in set for the entry node has a definition for each parameter | |
| 783 // and local. | |
| 784 if (predecessor_ == NULL) { | |
| 785 for (int i = 0; i < variable_count; i++) rd_.rd_in()->Add(i); | |
| 786 } | |
| 787 | |
| 788 for (int i = 0; i < instruction_count; i++) { | |
| 789 Expression* expr = instructions_[i]->AsExpression(); | |
| 790 if (expr == NULL) continue; | |
| 791 Variable* var = expr->AssignedVariable(); | |
| 792 if (var == NULL || !var->IsStackAllocated()) continue; | |
| 793 | |
| 794 // All definitions of this variable are killed. | |
| 795 BitVector* def_set = | |
| 796 variables->at(ReachingDefinitions::IndexFor(var, variable_count)); | |
| 797 rd_.kill()->Union(*def_set); | |
| 798 | |
| 799 // All previously generated definitions are not generated. | |
| 800 rd_.gen()->Subtract(*def_set); | |
| 801 | |
| 802 // This one is generated. | |
| 803 rd_.gen()->Add(expr->num()); | |
| 804 } | |
| 805 | |
| 806 // Add all blocks except the entry node to the worklist. | |
| 807 if (predecessor_ != NULL) { | |
| 808 MarkWith(mark); | |
| 809 worklist->Insert(this); | |
| 810 } | |
| 811 } | |
| 812 | |
| 813 | |
| 814 void ExitNode::ComputeRDOut(BitVector* result) { | |
| 815 // Should not be the predecessor of any node. | |
| 816 UNREACHABLE(); | |
| 817 } | |
| 818 | |
| 819 | |
| 820 void BlockNode::ComputeRDOut(BitVector* result) { | |
| 821 // All definitions reaching this block ... | |
| 822 *result = *rd_.rd_in(); | |
| 823 // ... except those killed by the block ... | |
| 824 result->Subtract(*rd_.kill()); | |
| 825 // ... but including those generated by the block. | |
| 826 result->Union(*rd_.gen()); | |
| 827 } | |
| 828 | |
| 829 | |
| 830 void BranchNode::ComputeRDOut(BitVector* result) { | |
| 831 // Branch nodes don't kill or generate definitions. | |
| 832 *result = *rd_.rd_in(); | |
| 833 } | |
| 834 | |
| 835 | |
| 836 void JoinNode::ComputeRDOut(BitVector* result) { | |
| 837 // Join nodes don't kill or generate definitions. | |
| 838 *result = *rd_.rd_in(); | |
| 839 } | |
| 840 | |
| 841 | |
| 842 void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) { | |
| 843 // The exit node has no successors so we can just update in place. New | |
| 844 // RD_in is the union over all predecessors. | |
| 845 int definition_count = rd_.rd_in()->length(); | |
| 846 rd_.rd_in()->Clear(); | |
| 847 | |
| 848 BitVector temp(definition_count); | |
| 849 for (int i = 0, len = predecessors_.length(); i < len; i++) { | |
| 850 // Because ComputeRDOut always overwrites temp and its value is | |
| 851 // always read out before calling ComputeRDOut again, we do not | |
| 852 // have to clear it on each iteration of the loop. | |
| 853 predecessors_[i]->ComputeRDOut(&temp); | |
| 854 rd_.rd_in()->Union(temp); | |
| 855 } | |
| 856 } | |
| 857 | |
| 858 | |
| 859 void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) { | |
| 860 // The entry block has no predecessor. Its RD_in does not change. | |
| 861 if (predecessor_ == NULL) return; | |
| 862 | |
| 863 BitVector new_rd_in(rd_.rd_in()->length()); | |
| 864 predecessor_->ComputeRDOut(&new_rd_in); | |
| 865 | |
| 866 if (rd_.rd_in()->Equals(new_rd_in)) return; | |
| 867 | |
| 868 // Update RD_in. | |
| 869 *rd_.rd_in() = new_rd_in; | |
| 870 // Add the successor to the worklist if not already present. | |
| 871 if (!successor_->IsMarkedWith(mark)) { | |
| 872 successor_->MarkWith(mark); | |
| 873 worklist->Insert(successor_); | |
| 874 } | |
| 875 } | |
| 876 | |
| 877 | |
| 878 void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) { | |
| 879 BitVector new_rd_in(rd_.rd_in()->length()); | |
| 880 predecessor_->ComputeRDOut(&new_rd_in); | |
| 881 | |
| 882 if (rd_.rd_in()->Equals(new_rd_in)) return; | |
| 883 | |
| 884 // Update RD_in. | |
| 885 *rd_.rd_in() = new_rd_in; | |
| 886 // Add the successors to the worklist if not already present. | |
| 887 if (!successor0_->IsMarkedWith(mark)) { | |
| 888 successor0_->MarkWith(mark); | |
| 889 worklist->Insert(successor0_); | |
| 890 } | |
| 891 if (!successor1_->IsMarkedWith(mark)) { | |
| 892 successor1_->MarkWith(mark); | |
| 893 worklist->Insert(successor1_); | |
| 894 } | |
| 895 } | |
| 896 | |
| 897 | |
| 898 void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) { | |
| 899 int definition_count = rd_.rd_in()->length(); | |
| 900 BitVector new_rd_in(definition_count); | |
| 901 | |
| 902 // New RD_in is the union over all predecessors. | |
| 903 BitVector temp(definition_count); | |
| 904 for (int i = 0, len = predecessors_.length(); i < len; i++) { | |
| 905 predecessors_[i]->ComputeRDOut(&temp); | |
| 906 new_rd_in.Union(temp); | |
| 907 } | |
| 908 | |
| 909 if (rd_.rd_in()->Equals(new_rd_in)) return; | |
| 910 | |
| 911 // Update RD_in. | |
| 912 *rd_.rd_in() = new_rd_in; | |
| 913 // Add the successor to the worklist if not already present. | |
| 914 if (!successor_->IsMarkedWith(mark)) { | |
| 915 successor_->MarkWith(mark); | |
| 916 worklist->Insert(successor_); | |
| 917 } | |
| 918 } | |
| 919 | |
| 920 | |
| 921 void Node::PropagateReachingDefinitions(List<BitVector*>* variables) { | |
| 922 // Nothing to do. | |
| 923 } | |
| 924 | |
| 925 | |
| 926 void BlockNode::PropagateReachingDefinitions(List<BitVector*>* variables) { | |
| 927 // Propagate RD_in from the start of the block to all the variable | |
| 928 // references. | |
| 929 int variable_count = variables->length(); | |
| 930 BitVector rd = *rd_.rd_in(); | |
| 931 for (int i = 0, len = instructions_.length(); i < len; i++) { | |
| 932 Expression* expr = instructions_[i]->AsExpression(); | |
| 933 if (expr == NULL) continue; | |
| 934 | |
| 935 // Look for a variable reference to record its reaching definitions. | |
| 936 VariableProxy* proxy = expr->AsVariableProxy(); | |
| 937 if (proxy == NULL) { | |
| 938 // Not a VariableProxy? Maybe it's a count operation. | |
| 939 CountOperation* count_operation = expr->AsCountOperation(); | |
| 940 if (count_operation != NULL) { | |
| 941 proxy = count_operation->expression()->AsVariableProxy(); | |
| 942 } | |
| 943 } | |
| 944 if (proxy == NULL) { | |
| 945 // OK, Maybe it's a compound assignment. | |
| 946 Assignment* assignment = expr->AsAssignment(); | |
| 947 if (assignment != NULL && assignment->is_compound()) { | |
| 948 proxy = assignment->target()->AsVariableProxy(); | |
| 949 } | |
| 950 } | |
| 951 | |
| 952 if (proxy != NULL && | |
| 953 proxy->var()->IsStackAllocated() && | |
| 954 !proxy->var()->is_this()) { | |
| 955 // All definitions for this variable. | |
| 956 BitVector* definitions = | |
| 957 variables->at(ReachingDefinitions::IndexFor(proxy->var(), | |
| 958 variable_count)); | |
| 959 BitVector* reaching_definitions = new BitVector(*definitions); | |
| 960 // Intersected with all definitions (of any variable) reaching this | |
| 961 // instruction. | |
| 962 reaching_definitions->Intersect(rd); | |
| 963 proxy->set_reaching_definitions(reaching_definitions); | |
| 964 } | |
| 965 | |
| 966 // It may instead (or also) be a definition. If so update the running | |
| 967 // value of reaching definitions for the block. | |
| 968 Variable* var = expr->AssignedVariable(); | |
| 969 if (var == NULL || !var->IsStackAllocated()) continue; | |
| 970 | |
| 971 // All definitions of this variable are killed. | |
| 972 BitVector* def_set = | |
| 973 variables->at(ReachingDefinitions::IndexFor(var, variable_count)); | |
| 974 rd.Subtract(*def_set); | |
| 975 // This definition is generated. | |
| 976 rd.Add(expr->num()); | |
| 977 } | |
| 978 } | |
| 979 | |
| 980 | |
| 981 void ReachingDefinitions::Compute() { | |
| 982 // The definitions in the body plus an implicit definition for each | |
| 983 // variable at function entry. | |
| 984 int definition_count = body_definitions_->length() + variable_count_; | |
| 985 int node_count = postorder_->length(); | |
| 986 | |
| 987 // Step 1: For each stack-allocated variable, identify the set of all its | |
| 988 // definitions. | |
| 989 List<BitVector*> variables; | |
| 990 for (int i = 0; i < variable_count_; i++) { | |
| 991 // Add the initial definition for each variable. | |
| 992 BitVector* initial = new BitVector(definition_count); | |
| 993 initial->Add(i); | |
| 994 variables.Add(initial); | |
| 995 } | |
| 996 for (int i = 0, len = body_definitions_->length(); i < len; i++) { | |
| 997 // Account for each definition in the body as a definition of the | |
| 998 // defined variable. | |
| 999 Variable* var = body_definitions_->at(i)->AssignedVariable(); | |
| 1000 variables[IndexFor(var, variable_count_)]->Add(i + variable_count_); | |
| 1001 } | |
| 1002 | |
| 1003 // Step 2: Compute KILL and GEN for each block node, initialize RD_in for | |
| 1004 // all nodes, and mark and add all nodes to the worklist in reverse | |
| 1005 // postorder. All nodes should currently have the same mark. | |
| 1006 bool mark = postorder_->at(0)->IsMarkedWith(false); // Negation of current. | |
| 1007 WorkList<Node> worklist(node_count); | |
| 1008 for (int i = node_count - 1; i >= 0; i--) { | |
| 1009 postorder_->at(i)->InitializeReachingDefinitions(definition_count, | |
| 1010 &variables, | |
| 1011 &worklist, | |
| 1012 mark); | |
| 1013 } | |
| 1014 | |
| 1015 // Step 3: Until the worklist is empty, remove an item compute and update | |
| 1016 // its rd_in based on its predecessor's rd_out. If rd_in has changed, add | |
| 1017 // all necessary successors to the worklist. | |
| 1018 while (!worklist.is_empty()) { | |
| 1019 Node* node = worklist.Remove(); | |
| 1020 node->MarkWith(!mark); | |
| 1021 node->UpdateRDIn(&worklist, mark); | |
| 1022 } | |
| 1023 | |
| 1024 // Step 4: Based on RD_in for block nodes, propagate reaching definitions | |
| 1025 // to all variable uses in the block. | |
| 1026 for (int i = 0; i < node_count; i++) { | |
| 1027 postorder_->at(i)->PropagateReachingDefinitions(&variables); | |
| 1028 } | |
| 1029 } | |
| 1030 | |
| 1031 | |
| 1032 bool TypeAnalyzer::IsPrimitiveDef(int def_num) { | |
| 1033 if (def_num < param_count_) return false; | |
| 1034 if (def_num < variable_count_) return true; | |
| 1035 return body_definitions_->at(def_num - variable_count_)->IsPrimitive(); | |
| 1036 } | |
| 1037 | |
| 1038 | |
| 1039 void TypeAnalyzer::Compute() { | |
| 1040 bool changed; | |
| 1041 int count = 0; | |
| 1042 | |
| 1043 do { | |
| 1044 changed = false; | |
| 1045 | |
| 1046 if (FLAG_print_graph_text) { | |
| 1047 PrintF("TypeAnalyzer::Compute - iteration %d\n", count++); | |
| 1048 } | |
| 1049 | |
| 1050 for (int i = postorder_->length() - 1; i >= 0; --i) { | |
| 1051 Node* node = postorder_->at(i); | |
| 1052 if (node->IsBlockNode()) { | |
| 1053 BlockNode* block = BlockNode::cast(node); | |
| 1054 for (int j = 0; j < block->instructions()->length(); j++) { | |
| 1055 Expression* expr = block->instructions()->at(j)->AsExpression(); | |
| 1056 if (expr != NULL) { | |
| 1057 // For variable uses: Compute new type from reaching definitions. | |
| 1058 VariableProxy* proxy = expr->AsVariableProxy(); | |
| 1059 if (proxy != NULL && proxy->reaching_definitions() != NULL) { | |
| 1060 BitVector* rd = proxy->reaching_definitions(); | |
| 1061 bool prim_type = true; | |
| 1062 // TODO(fsc): A sparse set representation of reaching | |
| 1063 // definitions would speed up iterating here. | |
| 1064 for (int k = 0; k < rd->length(); k++) { | |
| 1065 if (rd->Contains(k) && !IsPrimitiveDef(k)) { | |
| 1066 prim_type = false; | |
| 1067 break; | |
| 1068 } | |
| 1069 } | |
| 1070 // Reset changed flag if new type information was computed. | |
| 1071 if (prim_type != proxy->IsPrimitive()) { | |
| 1072 changed = true; | |
| 1073 proxy->SetIsPrimitive(prim_type); | |
| 1074 } | |
| 1075 } | |
| 1076 } | |
| 1077 } | |
| 1078 } | |
| 1079 } | |
| 1080 } while (changed); | |
| 1081 } | |
| 1082 | |
| 1083 | |
| 1084 void Node::MarkCriticalInstructions( | |
| 1085 List<AstNode*>* stack, | |
| 1086 ZoneList<Expression*>* body_definitions, | |
| 1087 int variable_count) { | |
| 1088 } | |
| 1089 | |
| 1090 | |
| 1091 void BlockNode::MarkCriticalInstructions( | |
| 1092 List<AstNode*>* stack, | |
| 1093 ZoneList<Expression*>* body_definitions, | |
| 1094 int variable_count) { | |
| 1095 for (int i = instructions_.length() - 1; i >= 0; i--) { | |
| 1096 // Only expressions can appear in the flow graph for now. | |
| 1097 Expression* expr = instructions_[i]->AsExpression(); | |
| 1098 if (expr != NULL && !expr->is_live() && | |
| 1099 (expr->is_loop_condition() || expr->IsCritical())) { | |
| 1100 expr->mark_as_live(); | |
| 1101 expr->ProcessNonLiveChildren(stack, body_definitions, variable_count); | |
| 1102 } | |
| 1103 } | |
| 1104 } | |
| 1105 | |
| 1106 | |
| 1107 void MarkLiveCode(ZoneList<Node*>* nodes, | |
| 1108 ZoneList<Expression*>* body_definitions, | |
| 1109 int variable_count) { | |
| 1110 List<AstNode*> stack(20); | |
| 1111 | |
| 1112 // Mark the critical AST nodes as live; mark their dependencies and | |
| 1113 // add them to the marking stack. | |
| 1114 for (int i = nodes->length() - 1; i >= 0; i--) { | |
| 1115 nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions, | |
| 1116 variable_count); | |
| 1117 } | |
| 1118 | |
| 1119 // Continue marking dependencies until no more. | |
| 1120 while (!stack.is_empty()) { | |
| 1121 // Only expressions can appear in the flow graph for now. | |
| 1122 Expression* expr = stack.RemoveLast()->AsExpression(); | |
| 1123 if (expr != NULL) { | |
| 1124 expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count); | |
| 1125 } | |
| 1126 } | |
| 1127 } | |
| 1128 | |
| 1129 | |
| 1130 #ifdef DEBUG | |
| 1131 | |
| 1132 // Print a textual representation of an instruction in a flow graph. Using | |
| 1133 // the AstVisitor is overkill because there is no recursion here. It is | |
| 1134 // only used for printing in debug mode. | |
| 1135 class TextInstructionPrinter: public AstVisitor { | |
| 1136 public: | |
| 1137 TextInstructionPrinter() : number_(0) {} | |
| 1138 | |
| 1139 int NextNumber() { return number_; } | |
| 1140 void AssignNumber(AstNode* node) { node->set_num(number_++); } | |
| 1141 | |
| 1142 private: | |
| 1143 // AST node visit functions. | |
| 1144 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); | |
| 1145 AST_NODE_LIST(DECLARE_VISIT) | |
| 1146 #undef DECLARE_VISIT | |
| 1147 | |
| 1148 int number_; | |
| 1149 | |
| 1150 DISALLOW_COPY_AND_ASSIGN(TextInstructionPrinter); | |
| 1151 }; | |
| 1152 | |
| 1153 | |
| 1154 void TextInstructionPrinter::VisitDeclaration(Declaration* decl) { | |
| 1155 UNREACHABLE(); | |
| 1156 } | |
| 1157 | |
| 1158 | |
| 1159 void TextInstructionPrinter::VisitBlock(Block* stmt) { | |
| 1160 PrintF("Block"); | |
| 1161 } | |
| 1162 | |
| 1163 | |
| 1164 void TextInstructionPrinter::VisitExpressionStatement( | |
| 1165 ExpressionStatement* stmt) { | |
| 1166 PrintF("ExpressionStatement"); | |
| 1167 } | |
| 1168 | |
| 1169 | |
| 1170 void TextInstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) { | |
| 1171 PrintF("EmptyStatement"); | |
| 1172 } | |
| 1173 | |
| 1174 | |
| 1175 void TextInstructionPrinter::VisitIfStatement(IfStatement* stmt) { | |
| 1176 PrintF("IfStatement"); | |
| 1177 } | |
| 1178 | |
| 1179 | |
| 1180 void TextInstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) { | |
| 1181 UNREACHABLE(); | |
| 1182 } | |
| 1183 | |
| 1184 | |
| 1185 void TextInstructionPrinter::VisitBreakStatement(BreakStatement* stmt) { | |
| 1186 UNREACHABLE(); | |
| 1187 } | |
| 1188 | |
| 1189 | |
| 1190 void TextInstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) { | |
| 1191 PrintF("return @%d", stmt->expression()->num()); | |
| 1192 } | |
| 1193 | |
| 1194 | |
| 1195 void TextInstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
| 1196 PrintF("WithEnterStatement"); | |
| 1197 } | |
| 1198 | |
| 1199 | |
| 1200 void TextInstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) { | |
| 1201 PrintF("WithExitStatement"); | |
| 1202 } | |
| 1203 | |
| 1204 | |
| 1205 void TextInstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) { | |
| 1206 UNREACHABLE(); | |
| 1207 } | |
| 1208 | |
| 1209 | |
| 1210 void TextInstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
| 1211 PrintF("DoWhileStatement"); | |
| 1212 } | |
| 1213 | |
| 1214 | |
| 1215 void TextInstructionPrinter::VisitWhileStatement(WhileStatement* stmt) { | |
| 1216 PrintF("WhileStatement"); | |
| 1217 } | |
| 1218 | |
| 1219 | |
| 1220 void TextInstructionPrinter::VisitForStatement(ForStatement* stmt) { | |
| 1221 PrintF("ForStatement"); | |
| 1222 } | |
| 1223 | |
| 1224 | |
| 1225 void TextInstructionPrinter::VisitForInStatement(ForInStatement* stmt) { | |
| 1226 PrintF("ForInStatement"); | |
| 1227 } | |
| 1228 | |
| 1229 | |
| 1230 void TextInstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
| 1231 UNREACHABLE(); | |
| 1232 } | |
| 1233 | |
| 1234 | |
| 1235 void TextInstructionPrinter::VisitTryFinallyStatement( | |
| 1236 TryFinallyStatement* stmt) { | |
| 1237 UNREACHABLE(); | |
| 1238 } | |
| 1239 | |
| 1240 | |
| 1241 void TextInstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
| 1242 PrintF("DebuggerStatement"); | |
| 1243 } | |
| 1244 | |
| 1245 | |
| 1246 void TextInstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) { | |
| 1247 PrintF("FunctionLiteral"); | |
| 1248 } | |
| 1249 | |
| 1250 | |
| 1251 void TextInstructionPrinter::VisitSharedFunctionInfoLiteral( | |
| 1252 SharedFunctionInfoLiteral* expr) { | |
| 1253 PrintF("SharedFunctionInfoLiteral"); | |
| 1254 } | |
| 1255 | |
| 1256 | |
| 1257 void TextInstructionPrinter::VisitConditional(Conditional* expr) { | |
| 1258 PrintF("Conditional"); | |
| 1259 } | |
| 1260 | |
| 1261 | |
| 1262 void TextInstructionPrinter::VisitSlot(Slot* expr) { | |
| 1263 UNREACHABLE(); | |
| 1264 } | |
| 1265 | |
| 1266 | |
| 1267 void TextInstructionPrinter::VisitVariableProxy(VariableProxy* expr) { | |
| 1268 Variable* var = expr->AsVariable(); | |
| 1269 if (var != NULL) { | |
| 1270 PrintF("%s", *var->name()->ToCString()); | |
| 1271 if (var->IsStackAllocated() && expr->reaching_definitions() != NULL) { | |
| 1272 expr->reaching_definitions()->Print(); | |
| 1273 } | |
| 1274 } else { | |
| 1275 ASSERT(expr->AsProperty() != NULL); | |
| 1276 VisitProperty(expr->AsProperty()); | |
| 1277 } | |
| 1278 } | |
| 1279 | |
| 1280 | |
| 1281 void TextInstructionPrinter::VisitLiteral(Literal* expr) { | |
| 1282 expr->handle()->ShortPrint(); | |
| 1283 } | |
| 1284 | |
| 1285 | |
| 1286 void TextInstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) { | |
| 1287 PrintF("RegExpLiteral"); | |
| 1288 } | |
| 1289 | |
| 1290 | |
| 1291 void TextInstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) { | |
| 1292 PrintF("ObjectLiteral"); | |
| 1293 } | |
| 1294 | |
| 1295 | |
| 1296 void TextInstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) { | |
| 1297 PrintF("ArrayLiteral"); | |
| 1298 } | |
| 1299 | |
| 1300 | |
| 1301 void TextInstructionPrinter::VisitCatchExtensionObject( | |
| 1302 CatchExtensionObject* expr) { | |
| 1303 PrintF("CatchExtensionObject"); | |
| 1304 } | |
| 1305 | |
| 1306 | |
| 1307 void TextInstructionPrinter::VisitAssignment(Assignment* expr) { | |
| 1308 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | |
| 1309 Property* prop = expr->target()->AsProperty(); | |
| 1310 | |
| 1311 if (var == NULL && prop == NULL) { | |
| 1312 // Throw reference error. | |
| 1313 Visit(expr->target()); | |
| 1314 return; | |
| 1315 } | |
| 1316 | |
| 1317 // Print the left-hand side. | |
| 1318 if (var != NULL) { | |
| 1319 PrintF("%s", *var->name()->ToCString()); | |
| 1320 } else if (prop != NULL) { | |
| 1321 PrintF("@%d", prop->obj()->num()); | |
| 1322 if (prop->key()->IsPropertyName()) { | |
| 1323 PrintF("."); | |
| 1324 ASSERT(prop->key()->AsLiteral() != NULL); | |
| 1325 prop->key()->AsLiteral()->handle()->Print(); | |
| 1326 } else { | |
| 1327 PrintF("[@%d]", prop->key()->num()); | |
| 1328 } | |
| 1329 } | |
| 1330 | |
| 1331 // Print the operation. | |
| 1332 if (expr->is_compound()) { | |
| 1333 PrintF(" = "); | |
| 1334 // Print the left-hand side again when compound. | |
| 1335 if (var != NULL) { | |
| 1336 PrintF("@%d", expr->target()->num()); | |
| 1337 } else { | |
| 1338 PrintF("@%d", prop->obj()->num()); | |
| 1339 if (prop->key()->IsPropertyName()) { | |
| 1340 PrintF("."); | |
| 1341 ASSERT(prop->key()->AsLiteral() != NULL); | |
| 1342 prop->key()->AsLiteral()->handle()->Print(); | |
| 1343 } else { | |
| 1344 PrintF("[@%d]", prop->key()->num()); | |
| 1345 } | |
| 1346 } | |
| 1347 // Print the corresponding binary operator. | |
| 1348 PrintF(" %s ", Token::String(expr->binary_op())); | |
| 1349 } else { | |
| 1350 PrintF(" %s ", Token::String(expr->op())); | |
| 1351 } | |
| 1352 | |
| 1353 // Print the right-hand side. | |
| 1354 PrintF("@%d", expr->value()->num()); | |
| 1355 | |
| 1356 if (expr->num() != AstNode::kNoNumber) { | |
| 1357 PrintF(" ;; D%d", expr->num()); | |
| 1358 } | |
| 1359 } | |
| 1360 | |
| 1361 | |
| 1362 void TextInstructionPrinter::VisitThrow(Throw* expr) { | |
| 1363 PrintF("throw @%d", expr->exception()->num()); | |
| 1364 } | |
| 1365 | |
| 1366 | |
| 1367 void TextInstructionPrinter::VisitProperty(Property* expr) { | |
| 1368 if (expr->key()->IsPropertyName()) { | |
| 1369 PrintF("@%d.", expr->obj()->num()); | |
| 1370 ASSERT(expr->key()->AsLiteral() != NULL); | |
| 1371 expr->key()->AsLiteral()->handle()->Print(); | |
| 1372 } else { | |
| 1373 PrintF("@%d[@%d]", expr->obj()->num(), expr->key()->num()); | |
| 1374 } | |
| 1375 } | |
| 1376 | |
| 1377 | |
| 1378 void TextInstructionPrinter::VisitCall(Call* expr) { | |
| 1379 PrintF("@%d(", expr->expression()->num()); | |
| 1380 ZoneList<Expression*>* arguments = expr->arguments(); | |
| 1381 for (int i = 0, len = arguments->length(); i < len; i++) { | |
| 1382 if (i != 0) PrintF(", "); | |
| 1383 PrintF("@%d", arguments->at(i)->num()); | |
| 1384 } | |
| 1385 PrintF(")"); | |
| 1386 } | |
| 1387 | |
| 1388 | |
| 1389 void TextInstructionPrinter::VisitCallNew(CallNew* expr) { | |
| 1390 PrintF("new @%d(", expr->expression()->num()); | |
| 1391 ZoneList<Expression*>* arguments = expr->arguments(); | |
| 1392 for (int i = 0, len = arguments->length(); i < len; i++) { | |
| 1393 if (i != 0) PrintF(", "); | |
| 1394 PrintF("@%d", arguments->at(i)->num()); | |
| 1395 } | |
| 1396 PrintF(")"); | |
| 1397 } | |
| 1398 | |
| 1399 | |
| 1400 void TextInstructionPrinter::VisitCallRuntime(CallRuntime* expr) { | |
| 1401 PrintF("%s(", *expr->name()->ToCString()); | |
| 1402 ZoneList<Expression*>* arguments = expr->arguments(); | |
| 1403 for (int i = 0, len = arguments->length(); i < len; i++) { | |
| 1404 if (i != 0) PrintF(", "); | |
| 1405 PrintF("@%d", arguments->at(i)->num()); | |
| 1406 } | |
| 1407 PrintF(")"); | |
| 1408 } | |
| 1409 | |
| 1410 | |
| 1411 void TextInstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) { | |
| 1412 PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num()); | |
| 1413 } | |
| 1414 | |
| 1415 | |
| 1416 void TextInstructionPrinter::VisitCountOperation(CountOperation* expr) { | |
| 1417 if (expr->is_prefix()) { | |
| 1418 PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num()); | |
| 1419 } else { | |
| 1420 PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op())); | |
| 1421 } | |
| 1422 | |
| 1423 if (expr->num() != AstNode::kNoNumber) { | |
| 1424 PrintF(" ;; D%d", expr->num()); | |
| 1425 } | |
| 1426 } | |
| 1427 | |
| 1428 | |
| 1429 void TextInstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) { | |
| 1430 ASSERT(expr->op() != Token::COMMA); | |
| 1431 ASSERT(expr->op() != Token::OR); | |
| 1432 ASSERT(expr->op() != Token::AND); | |
| 1433 PrintF("@%d %s @%d", | |
| 1434 expr->left()->num(), | |
| 1435 Token::String(expr->op()), | |
| 1436 expr->right()->num()); | |
| 1437 } | |
| 1438 | |
| 1439 | |
| 1440 void TextInstructionPrinter::VisitCompareOperation(CompareOperation* expr) { | |
| 1441 PrintF("@%d %s @%d", | |
| 1442 expr->left()->num(), | |
| 1443 Token::String(expr->op()), | |
| 1444 expr->right()->num()); | |
| 1445 } | |
| 1446 | |
| 1447 | |
| 1448 void TextInstructionPrinter::VisitThisFunction(ThisFunction* expr) { | |
| 1449 PrintF("ThisFunction"); | |
| 1450 } | |
| 1451 | |
| 1452 | |
| 1453 static int node_count = 0; | |
| 1454 static int instruction_count = 0; | |
| 1455 | |
| 1456 | |
| 1457 void Node::AssignNodeNumber() { | |
| 1458 set_number(node_count++); | |
| 1459 } | |
| 1460 | |
| 1461 | |
| 1462 void Node::PrintReachingDefinitions() { | |
| 1463 if (rd_.rd_in() != NULL) { | |
| 1464 ASSERT(rd_.kill() != NULL && rd_.gen() != NULL); | |
| 1465 | |
| 1466 PrintF("RD_in = "); | |
| 1467 rd_.rd_in()->Print(); | |
| 1468 PrintF("\n"); | |
| 1469 | |
| 1470 PrintF("RD_kill = "); | |
| 1471 rd_.kill()->Print(); | |
| 1472 PrintF("\n"); | |
| 1473 | |
| 1474 PrintF("RD_gen = "); | |
| 1475 rd_.gen()->Print(); | |
| 1476 PrintF("\n"); | |
| 1477 } | |
| 1478 } | |
| 1479 | |
| 1480 | |
| 1481 void ExitNode::PrintText() { | |
| 1482 PrintReachingDefinitions(); | |
| 1483 PrintF("L%d: Exit\n\n", number()); | |
| 1484 } | |
| 1485 | |
| 1486 | |
| 1487 void BlockNode::PrintText() { | |
| 1488 PrintReachingDefinitions(); | |
| 1489 // Print the instructions in the block. | |
| 1490 PrintF("L%d: Block\n", number()); | |
| 1491 TextInstructionPrinter printer; | |
| 1492 for (int i = 0, len = instructions_.length(); i < len; i++) { | |
| 1493 AstNode* instr = instructions_[i]; | |
| 1494 // Print a star next to dead instructions. | |
| 1495 if (instr->AsExpression() != NULL && instr->AsExpression()->is_live()) { | |
| 1496 PrintF(" "); | |
| 1497 } else { | |
| 1498 PrintF("* "); | |
| 1499 } | |
| 1500 PrintF("%d ", printer.NextNumber()); | |
| 1501 printer.Visit(instr); | |
| 1502 printer.AssignNumber(instr); | |
| 1503 PrintF("\n"); | |
| 1504 } | |
| 1505 PrintF("goto L%d\n\n", successor_->number()); | |
| 1506 } | |
| 1507 | |
| 1508 | |
| 1509 void BranchNode::PrintText() { | |
| 1510 PrintReachingDefinitions(); | |
| 1511 PrintF("L%d: Branch\n", number()); | |
| 1512 PrintF("goto (L%d, L%d)\n\n", successor0_->number(), successor1_->number()); | |
| 1513 } | |
| 1514 | |
| 1515 | |
| 1516 void JoinNode::PrintText() { | |
| 1517 PrintReachingDefinitions(); | |
| 1518 PrintF("L%d: Join(", number()); | |
| 1519 for (int i = 0, len = predecessors_.length(); i < len; i++) { | |
| 1520 if (i != 0) PrintF(", "); | |
| 1521 PrintF("L%d", predecessors_[i]->number()); | |
| 1522 } | |
| 1523 PrintF(")\ngoto L%d\n\n", successor_->number()); | |
| 1524 } | |
| 1525 | |
| 1526 | |
| 1527 void FlowGraph::PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder) { | |
| 1528 PrintF("\n========\n"); | |
| 1529 PrintF("name = %s\n", *fun->name()->ToCString()); | |
| 1530 | |
| 1531 // Number nodes and instructions in reverse postorder. | |
| 1532 node_count = 0; | |
| 1533 instruction_count = 0; | |
| 1534 for (int i = postorder->length() - 1; i >= 0; i--) { | |
| 1535 postorder->at(i)->AssignNodeNumber(); | |
| 1536 } | |
| 1537 | |
| 1538 // Print basic blocks in reverse postorder. | |
| 1539 for (int i = postorder->length() - 1; i >= 0; i--) { | |
| 1540 postorder->at(i)->PrintText(); | |
| 1541 } | |
| 1542 } | |
| 1543 | |
| 1544 #endif // DEBUG | |
| 1545 | |
| 1546 | |
| 1547 } } // namespace v8::internal | 755 } } // namespace v8::internal |
| OLD | NEW |