Home | History | Annotate | Download | only in compiler
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_COMPILER_GENERIC_NODE_H_
      6 #define V8_COMPILER_GENERIC_NODE_H_
      7 
      8 #include "src/v8.h"
      9 
     10 #include "src/zone-containers.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace compiler {
     15 
     16 class GenericGraphBase;
     17 
     18 typedef int NodeId;
     19 
     20 // A GenericNode<> is the basic primitive of graphs. GenericNode's are
     21 // chained together by input/use chains but by default otherwise contain only an
     22 // identifying number which specific applications of graphs and nodes can use
     23 // to index auxiliary out-of-line data, especially transient data.
     24 // Specializations of the templatized GenericNode<> class must provide a base
     25 // class B that contains all of the members to be made available in each
     26 // specialized Node instance. GenericNode uses a mixin template pattern to
     27 // ensure that common accessors and methods expect the derived class S type
     28 // rather than the GenericNode<B, S> type.
     29 template <class B, class S>
     30 class GenericNode : public B {
     31  public:
     32   typedef B BaseClass;
     33   typedef S DerivedClass;
     34 
     35   inline NodeId id() const { return id_; }
     36 
     37   int InputCount() const { return input_count_; }
     38   S* InputAt(int index) const {
     39     return static_cast<S*>(GetInputRecordPtr(index)->to);
     40   }
     41   inline void ReplaceInput(int index, GenericNode* new_input);
     42   inline void AppendInput(Zone* zone, GenericNode* new_input);
     43   inline void InsertInput(Zone* zone, int index, GenericNode* new_input);
     44   inline void RemoveInput(int index);
     45 
     46   int UseCount() { return use_count_; }
     47   S* UseAt(int index) {
     48     DCHECK(index < use_count_);
     49     Use* current = first_use_;
     50     while (index-- != 0) {
     51       current = current->next;
     52     }
     53     return static_cast<S*>(current->from);
     54   }
     55   inline void ReplaceUses(GenericNode* replace_to);
     56   template <class UnaryPredicate>
     57   inline void ReplaceUsesIf(UnaryPredicate pred, GenericNode* replace_to);
     58   inline void RemoveAllInputs();
     59 
     60   inline void TrimInputCount(int input_count);
     61 
     62   class Inputs {
     63    public:
     64     class iterator;
     65     iterator begin();
     66     iterator end();
     67 
     68     explicit Inputs(GenericNode* node) : node_(node) {}
     69 
     70    private:
     71     GenericNode* node_;
     72   };
     73 
     74   Inputs inputs() { return Inputs(this); }
     75 
     76   class Uses {
     77    public:
     78     class iterator;
     79     iterator begin();
     80     iterator end();
     81     bool empty() { return begin() == end(); }
     82 
     83     explicit Uses(GenericNode* node) : node_(node) {}
     84 
     85    private:
     86     GenericNode* node_;
     87   };
     88 
     89   Uses uses() { return Uses(this); }
     90 
     91   class Edge;
     92 
     93   bool OwnedBy(GenericNode* owner) const;
     94 
     95   static S* New(GenericGraphBase* graph, int input_count, S** inputs);
     96 
     97  protected:
     98   friend class GenericGraphBase;
     99 
    100   class Use : public ZoneObject {
    101    public:
    102     GenericNode* from;
    103     Use* next;
    104     Use* prev;
    105     int input_index;
    106   };
    107 
    108   class Input {
    109    public:
    110     GenericNode* to;
    111     Use* use;
    112 
    113     void Update(GenericNode* new_to);
    114   };
    115 
    116   void EnsureAppendableInputs(Zone* zone);
    117 
    118   Input* GetInputRecordPtr(int index) const {
    119     if (has_appendable_inputs_) {
    120       return &((*inputs_.appendable_)[index]);
    121     } else {
    122       return inputs_.static_ + index;
    123     }
    124   }
    125 
    126   inline void AppendUse(Use* use);
    127   inline void RemoveUse(Use* use);
    128 
    129   void* operator new(size_t, void* location) { return location; }
    130 
    131   GenericNode(GenericGraphBase* graph, int input_count);
    132 
    133  private:
    134   void AssignUniqueID(GenericGraphBase* graph);
    135 
    136   typedef ZoneDeque<Input> InputDeque;
    137 
    138   NodeId id_;
    139   int input_count_ : 31;
    140   bool has_appendable_inputs_ : 1;
    141   union {
    142     // When a node is initially allocated, it uses a static buffer to hold its
    143     // inputs under the assumption that the number of outputs will not increase.
    144     // When the first input is appended, the static buffer is converted into a
    145     // deque to allow for space-efficient growing.
    146     Input* static_;
    147     InputDeque* appendable_;
    148   } inputs_;
    149   int use_count_;
    150   Use* first_use_;
    151   Use* last_use_;
    152 
    153   DISALLOW_COPY_AND_ASSIGN(GenericNode);
    154 };
    155 
    156 // An encapsulation for information associated with a single use of node as a
    157 // input from another node, allowing access to both the defining node and
    158 // the ndoe having the input.
    159 template <class B, class S>
    160 class GenericNode<B, S>::Edge {
    161  public:
    162   S* from() const { return static_cast<S*>(input_->use->from); }
    163   S* to() const { return static_cast<S*>(input_->to); }
    164   int index() const {
    165     int index = input_->use->input_index;
    166     DCHECK(index < input_->use->from->input_count_);
    167     return index;
    168   }
    169 
    170  private:
    171   friend class GenericNode<B, S>::Uses::iterator;
    172   friend class GenericNode<B, S>::Inputs::iterator;
    173 
    174   explicit Edge(typename GenericNode<B, S>::Input* input) : input_(input) {}
    175 
    176   typename GenericNode<B, S>::Input* input_;
    177 };
    178 
    179 // A forward iterator to visit the nodes which are depended upon by a node
    180 // in the order of input.
    181 template <class B, class S>
    182 class GenericNode<B, S>::Inputs::iterator {
    183  public:
    184   iterator(const typename GenericNode<B, S>::Inputs::iterator& other)  // NOLINT
    185       : node_(other.node_),
    186         index_(other.index_) {}
    187 
    188   S* operator*() { return static_cast<S*>(GetInput()->to); }
    189   typename GenericNode<B, S>::Edge edge() {
    190     return typename GenericNode::Edge(GetInput());
    191   }
    192   bool operator==(const iterator& other) const {
    193     return other.index_ == index_ && other.node_ == node_;
    194   }
    195   bool operator!=(const iterator& other) const { return !(other == *this); }
    196   iterator& operator++() {
    197     DCHECK(node_ != NULL);
    198     DCHECK(index_ < node_->input_count_);
    199     ++index_;
    200     return *this;
    201   }
    202   iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) {
    203     typename GenericNode<B, S>::Input* input = GetInput();
    204     input->Update(new_to);
    205     index_++;
    206     return *this;
    207   }
    208   int index() { return index_; }
    209 
    210  private:
    211   friend class GenericNode;
    212 
    213   explicit iterator(GenericNode* node, int index)
    214       : node_(node), index_(index) {}
    215 
    216   Input* GetInput() const { return node_->GetInputRecordPtr(index_); }
    217 
    218   GenericNode* node_;
    219   int index_;
    220 };
    221 
    222 // A forward iterator to visit the uses of a node. The uses are returned in
    223 // the order in which they were added as inputs.
    224 template <class B, class S>
    225 class GenericNode<B, S>::Uses::iterator {
    226  public:
    227   iterator(const typename GenericNode<B, S>::Uses::iterator& other)  // NOLINT
    228       : current_(other.current_),
    229         index_(other.index_) {}
    230 
    231   S* operator*() { return static_cast<S*>(current_->from); }
    232   typename GenericNode<B, S>::Edge edge() {
    233     return typename GenericNode::Edge(CurrentInput());
    234   }
    235 
    236   bool operator==(const iterator& other) { return other.current_ == current_; }
    237   bool operator!=(const iterator& other) { return other.current_ != current_; }
    238   iterator& operator++() {
    239     DCHECK(current_ != NULL);
    240     index_++;
    241     current_ = current_->next;
    242     return *this;
    243   }
    244   iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) {
    245     DCHECK(current_ != NULL);
    246     index_++;
    247     typename GenericNode<B, S>::Input* input = CurrentInput();
    248     current_ = current_->next;
    249     input->Update(new_to);
    250     return *this;
    251   }
    252   int index() const { return index_; }
    253 
    254  private:
    255   friend class GenericNode<B, S>::Uses;
    256 
    257   iterator() : current_(NULL), index_(0) {}
    258   explicit iterator(GenericNode<B, S>* node)
    259       : current_(node->first_use_), index_(0) {}
    260 
    261   Input* CurrentInput() const {
    262     return current_->from->GetInputRecordPtr(current_->input_index);
    263   }
    264 
    265   typename GenericNode<B, S>::Use* current_;
    266   int index_;
    267 };
    268 }
    269 }
    270 }  // namespace v8::internal::compiler
    271 
    272 #endif  // V8_COMPILER_GENERIC_NODE_H_
    273