1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 18 #define ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 19 20 #include "compiler_ir.h" 21 #include "mir_graph.h" 22 23 namespace art { 24 25 /* 26 * This class supports iterating over lists of basic blocks in various 27 * interesting orders. Note that for efficiency, the visit orders have been pre-computed. 28 * The order itself will not change during the iteration. However, for some uses, 29 * auxiliary data associated with the basic blocks may be changed during the iteration, 30 * necessitating another pass over the list. 31 * 32 * To support this usage, we have is_iterative_. If false, the iteration is a one-shot 33 * pass through the pre-computed list using Next(). If true, the caller must tell the 34 * iterator whether a change has been made that necessitates another pass. Use 35 * Next(had_change) for this. The general idea is that the iterative_ use case means 36 * that the iterator will keep repeating the full basic block list until a complete pass 37 * is made through it with no changes. Note that calling Next(true) does not affect 38 * the iteration order or short-curcuit the current pass - it simply tells the iterator 39 * that once it has finished walking through the block list it should reset and do another 40 * full pass through the list. 41 */ 42 class DataflowIterator { 43 public: ~DataflowIterator()44 virtual ~DataflowIterator() {} 45 46 // Return the next BasicBlock* to visit. Next()47 BasicBlock* Next() { 48 DCHECK(!is_iterative_); 49 return NextBody(false); 50 } 51 52 /* 53 * Return the next BasicBlock* to visit, and tell the iterator whether any change 54 * has occurred that requires another full pass over the block list. 55 */ Next(bool had_change)56 BasicBlock* Next(bool had_change) { 57 DCHECK(is_iterative_); 58 return NextBody(had_change); 59 } 60 61 protected: DataflowIterator(MIRGraph * mir_graph,bool is_iterative,int start_idx,int end_idx,bool reverse)62 DataflowIterator(MIRGraph* mir_graph, bool is_iterative, int start_idx, int end_idx, 63 bool reverse) 64 : mir_graph_(mir_graph), 65 is_iterative_(is_iterative), 66 start_idx_(start_idx), 67 end_idx_(end_idx), 68 reverse_(reverse), 69 block_id_list_(NULL), 70 idx_(0), 71 changed_(false) {} 72 73 virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE; 74 75 MIRGraph* const mir_graph_; 76 const bool is_iterative_; 77 const int start_idx_; 78 const int end_idx_; 79 const bool reverse_; 80 GrowableArray<int>* block_id_list_; 81 int idx_; 82 bool changed_; 83 }; // DataflowIterator 84 85 class ReachableNodesIterator : public DataflowIterator { 86 public: ReachableNodesIterator(MIRGraph * mir_graph,bool is_iterative)87 ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative) 88 : DataflowIterator(mir_graph, is_iterative, 0, 89 mir_graph->GetNumReachableBlocks(), false) { 90 idx_ = start_idx_; 91 block_id_list_ = mir_graph->GetDfsOrder(); 92 } 93 }; 94 95 class PreOrderDfsIterator : public DataflowIterator { 96 public: PreOrderDfsIterator(MIRGraph * mir_graph,bool is_iterative)97 PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative) 98 : DataflowIterator(mir_graph, is_iterative, 0, 99 mir_graph->GetNumReachableBlocks(), false) { 100 idx_ = start_idx_; 101 block_id_list_ = mir_graph->GetDfsOrder(); 102 } 103 }; 104 105 class PostOrderDfsIterator : public DataflowIterator { 106 public: PostOrderDfsIterator(MIRGraph * mir_graph,bool is_iterative)107 PostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative) 108 : DataflowIterator(mir_graph, is_iterative, 0, 109 mir_graph->GetNumReachableBlocks(), false) { 110 idx_ = start_idx_; 111 block_id_list_ = mir_graph->GetDfsPostOrder(); 112 } 113 }; 114 115 class ReversePostOrderDfsIterator : public DataflowIterator { 116 public: ReversePostOrderDfsIterator(MIRGraph * mir_graph,bool is_iterative)117 ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative) 118 : DataflowIterator(mir_graph, is_iterative, 119 mir_graph->GetNumReachableBlocks() -1, 0, true) { 120 idx_ = start_idx_; 121 block_id_list_ = mir_graph->GetDfsPostOrder(); 122 } 123 }; 124 125 class PostOrderDOMIterator : public DataflowIterator { 126 public: PostOrderDOMIterator(MIRGraph * mir_graph,bool is_iterative)127 PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative) 128 : DataflowIterator(mir_graph, is_iterative, 0, 129 mir_graph->GetNumReachableBlocks(), false) { 130 idx_ = start_idx_; 131 block_id_list_ = mir_graph->GetDomPostOrder(); 132 } 133 }; 134 135 class AllNodesIterator : public DataflowIterator { 136 public: AllNodesIterator(MIRGraph * mir_graph,bool is_iterative)137 AllNodesIterator(MIRGraph* mir_graph, bool is_iterative) 138 : DataflowIterator(mir_graph, is_iterative, 0, 0, false) { 139 all_nodes_iterator_ = 140 new (mir_graph->GetArena()) GrowableArray<BasicBlock*>::Iterator(mir_graph->GetBlockList()); 141 } 142 Reset()143 void Reset() { 144 all_nodes_iterator_->Reset(); 145 } 146 147 BasicBlock* NextBody(bool had_change) ALWAYS_INLINE; 148 149 private: 150 GrowableArray<BasicBlock*>::Iterator* all_nodes_iterator_; 151 }; 152 153 } // namespace art 154 155 #endif // ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 156