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 
id()35   inline NodeId id() const { return id_; }
36 
InputCount()37   int InputCount() const { return input_count_; }
InputAt(int index)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 
UseCount()46   int UseCount() { return use_count_; }
UseAt(int index)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 
Inputs(GenericNode * node)68     explicit Inputs(GenericNode* node) : node_(node) {}
69 
70    private:
71     GenericNode* node_;
72   };
73 
inputs()74   Inputs inputs() { return Inputs(this); }
75 
76   class Uses {
77    public:
78     class iterator;
79     iterator begin();
80     iterator end();
empty()81     bool empty() { return begin() == end(); }
82 
Uses(GenericNode * node)83     explicit Uses(GenericNode* node) : node_(node) {}
84 
85    private:
86     GenericNode* node_;
87   };
88 
uses()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 
GetInputRecordPtr(int index)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 
new(size_t,void * location)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:
from()162   S* from() const { return static_cast<S*>(input_->use->from); }
to()163   S* to() const { return static_cast<S*>(input_->to); }
index()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 
Edge(typename GenericNode<B,S>::Input * input)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:
iterator(const typename GenericNode<B,S>::Inputs::iterator & other)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); }
edge()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   }
UpdateToAndIncrement(GenericNode<B,S> * new_to)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   }
index()208   int index() { return index_; }
209 
210  private:
211   friend class GenericNode;
212 
iterator(GenericNode * node,int index)213   explicit iterator(GenericNode* node, int index)
214       : node_(node), index_(index) {}
215 
GetInput()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:
iterator(const typename GenericNode<B,S>::Uses::iterator & other)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); }
edge()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   }
UpdateToAndIncrement(GenericNode<B,S> * new_to)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   }
index()252   int index() const { return index_; }
253 
254  private:
255   friend class GenericNode<B, S>::Uses;
256 
iterator()257   iterator() : current_(NULL), index_(0) {}
iterator(GenericNode<B,S> * node)258   explicit iterator(GenericNode<B, S>* node)
259       : current_(node->first_use_), index_(0) {}
260 
CurrentInput()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