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 |