C++程序  |  156行  |  5.49 KB

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_
#define ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_

#include "compiler_ir.h"
#include "mir_graph.h"

namespace art {

  /*
   * This class supports iterating over lists of basic blocks in various
   * interesting orders.  Note that for efficiency, the visit orders have been pre-computed.
   * The order itself will not change during the iteration.  However, for some uses,
   * auxiliary data associated with the basic blocks may be changed during the iteration,
   * necessitating another pass over the list.
   *
   * To support this usage, we have is_iterative_.  If false, the iteration is a one-shot
   * pass through the pre-computed list using Next().  If true, the caller must tell the
   * iterator whether a change has been made that necessitates another pass.  Use
   * Next(had_change) for this.  The general idea is that the iterative_ use case means
   * that the iterator will keep repeating the full basic block list until a complete pass
   * is made through it with no changes.  Note that calling Next(true) does not affect
   * the iteration order or short-curcuit the current pass - it simply tells the iterator
   * that once it has finished walking through the block list it should reset and do another
   * full pass through the list.
   */
  class DataflowIterator {
    public:
      virtual ~DataflowIterator() {}

      // Return the next BasicBlock* to visit.
      BasicBlock* Next() {
        DCHECK(!is_iterative_);
        return NextBody(false);
      }

      /*
       * Return the next BasicBlock* to visit, and tell the iterator whether any change
       * has occurred that requires another full pass over the block list.
       */
      BasicBlock* Next(bool had_change) {
        DCHECK(is_iterative_);
        return NextBody(had_change);
      }

    protected:
      DataflowIterator(MIRGraph* mir_graph, bool is_iterative, int start_idx, int end_idx,
                       bool reverse)
          : mir_graph_(mir_graph),
            is_iterative_(is_iterative),
            start_idx_(start_idx),
            end_idx_(end_idx),
            reverse_(reverse),
            block_id_list_(NULL),
            idx_(0),
            changed_(false) {}

      virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;

      MIRGraph* const mir_graph_;
      const bool is_iterative_;
      const int start_idx_;
      const int end_idx_;
      const bool reverse_;
      GrowableArray<int>* block_id_list_;
      int idx_;
      bool changed_;
  };  // DataflowIterator

  class ReachableNodesIterator : public DataflowIterator {
    public:
      ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative)
          : DataflowIterator(mir_graph, is_iterative, 0,
                             mir_graph->GetNumReachableBlocks(), false) {
        idx_ = start_idx_;
        block_id_list_ = mir_graph->GetDfsOrder();
      }
  };

  class PreOrderDfsIterator : public DataflowIterator {
    public:
      PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
          : DataflowIterator(mir_graph, is_iterative, 0,
                             mir_graph->GetNumReachableBlocks(), false) {
        idx_ = start_idx_;
        block_id_list_ = mir_graph->GetDfsOrder();
      }
  };

  class PostOrderDfsIterator : public DataflowIterator {
    public:
      PostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
          : DataflowIterator(mir_graph, is_iterative, 0,
                             mir_graph->GetNumReachableBlocks(), false) {
        idx_ = start_idx_;
        block_id_list_ = mir_graph->GetDfsPostOrder();
      }
  };

  class ReversePostOrderDfsIterator : public DataflowIterator {
    public:
      ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
          : DataflowIterator(mir_graph, is_iterative,
                             mir_graph->GetNumReachableBlocks() -1, 0, true) {
        idx_ = start_idx_;
        block_id_list_ = mir_graph->GetDfsPostOrder();
      }
  };

  class PostOrderDOMIterator : public DataflowIterator {
    public:
      PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative)
          : DataflowIterator(mir_graph, is_iterative, 0,
                             mir_graph->GetNumReachableBlocks(), false) {
        idx_ = start_idx_;
        block_id_list_ = mir_graph->GetDomPostOrder();
      }
  };

  class AllNodesIterator : public DataflowIterator {
    public:
      AllNodesIterator(MIRGraph* mir_graph, bool is_iterative)
          : DataflowIterator(mir_graph, is_iterative, 0, 0, false) {
        all_nodes_iterator_ =
            new (mir_graph->GetArena()) GrowableArray<BasicBlock*>::Iterator(mir_graph->GetBlockList());
      }

      void Reset() {
        all_nodes_iterator_->Reset();
      }

      BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;

    private:
      GrowableArray<BasicBlock*>::Iterator* all_nodes_iterator_;
  };

}  // namespace art

#endif  // ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_