Index: src/compiler/generic-node.h |
diff --git a/src/compiler/generic-node.h b/src/compiler/generic-node.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..506a34fc1323d4250a5b6e2c841f626111b98677 |
--- /dev/null |
+++ b/src/compiler/generic-node.h |
@@ -0,0 +1,279 @@ |
+// Copyright 2013 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef V8_COMPILER_GENERIC_NODE_H_ |
+#define V8_COMPILER_GENERIC_NODE_H_ |
+ |
+#include "src/v8.h" |
+ |
+#include "src/zone-containers.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+class GenericGraphBase; |
+ |
+typedef int NodeId; |
+ |
+// A GenericNode<> is the basic primitive of graphs. GenericNode's are |
+// chained together by input/use chains but by default otherwise contain only an |
+// identifying number which specific applications of graphs and nodes can use |
+// to index auxiliary out-of-line data, especially transient data. |
+// Specializations of the templatized GenericNode<> class must provide a base |
+// class B that contains all of the members to be made available in each |
+// specialized Node instance. GenericNode uses a mixin template pattern to |
+// ensure that common accessors and methods expect the derived class S type |
+// rather than the GenericNode<B, S> type. |
+template <class B, class S> |
+class GenericNode : public B { |
+ public: |
+ typedef B BaseClass; |
+ typedef S DerivedClass; |
+ |
+ inline NodeId id() const { return id_; } |
+ |
+ int InputCount() const { return input_count_; } |
+ S* InputAt(int index) const { |
+ return static_cast<S*>(GetInputRecordPtr(index)->to); |
+ } |
+ inline void ReplaceInput(int index, GenericNode* new_input); |
+ inline void AppendInput(Zone* zone, GenericNode* new_input); |
+ inline void InsertInput(Zone* zone, int index, GenericNode* new_input); |
+ inline void RemoveInput(int index); |
+ |
+ int UseCount() { return use_count_; } |
+ S* UseAt(int index) { |
+ DCHECK(index < use_count_); |
+ Use* current = first_use_; |
+ while (index-- != 0) { |
+ current = current->next; |
+ } |
+ return static_cast<S*>(current->from); |
+ } |
+ inline void ReplaceUses(GenericNode* replace_to); |
+ template <class UnaryPredicate> |
+ inline void ReplaceUsesIf(UnaryPredicate pred, GenericNode* replace_to); |
+ inline void RemoveAllInputs(); |
+ |
+ inline void TrimInputCount(int input_count); |
+ |
+ class Inputs { |
+ public: |
+ class iterator; |
+ iterator begin(); |
+ iterator end(); |
+ |
+ explicit Inputs(GenericNode* node) : node_(node) {} |
+ |
+ private: |
+ GenericNode* node_; |
+ }; |
+ |
+ Inputs inputs() { return Inputs(this); } |
+ |
+ class Uses { |
+ public: |
+ class iterator; |
+ iterator begin(); |
+ iterator end(); |
+ bool empty() { return begin() == end(); } |
+ |
+ explicit Uses(GenericNode* node) : node_(node) {} |
+ |
+ private: |
+ GenericNode* node_; |
+ }; |
+ |
+ Uses uses() { return Uses(this); } |
+ |
+ class Edge; |
+ |
+ bool OwnedBy(GenericNode* owner) const; |
+ |
+ static S* New(GenericGraphBase* graph, int input_count, S** inputs, |
+ bool has_extensible_inputs); |
+ |
+ protected: |
+ friend class GenericGraphBase; |
+ |
+ class Use : public ZoneObject { |
+ public: |
+ GenericNode* from; |
+ Use* next; |
+ Use* prev; |
+ int input_index; |
+ }; |
+ |
+ class Input { |
+ public: |
+ GenericNode* to; |
+ Use* use; |
+ |
+ void Update(GenericNode* new_to); |
+ }; |
+ |
+ void EnsureAppendableInputs(Zone* zone); |
+ |
+ Input* GetInputRecordPtr(int index) const { |
+ if (has_appendable_inputs_) { |
+ return &((*inputs_.appendable_)[index]); |
+ } else { |
+ return inputs_.static_ + index; |
+ } |
+ } |
+ |
+ inline void AppendUse(Use* use); |
+ inline void RemoveUse(Use* use); |
+ |
+ void* operator new(size_t, void* location) { return location; } |
+ |
+ GenericNode(GenericGraphBase* graph, int input_count, |
+ int reserved_input_count); |
+ |
+ private: |
+ void AssignUniqueID(GenericGraphBase* graph); |
+ |
+ typedef ZoneDeque<Input> InputDeque; |
+ |
+ static const int kReservedInputCountBits = 2; |
+ static const int kMaxReservedInputs = (1 << kReservedInputCountBits) - 1; |
+ static const int kDefaultReservedInputs = kMaxReservedInputs; |
+ |
+ NodeId id_; |
+ int input_count_ : 29; |
+ unsigned int reserve_input_count_ : kReservedInputCountBits; |
+ bool has_appendable_inputs_ : 1; |
+ union { |
+ // When a node is initially allocated, it uses a static buffer to hold its |
+ // inputs under the assumption that the number of outputs will not increase. |
+ // When the first input is appended, the static buffer is converted into a |
+ // deque to allow for space-efficient growing. |
+ Input* static_; |
+ InputDeque* appendable_; |
+ } inputs_; |
+ int use_count_; |
+ Use* first_use_; |
+ Use* last_use_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GenericNode); |
+}; |
+ |
+// An encapsulation for information associated with a single use of node as a |
+// input from another node, allowing access to both the defining node and |
+// the ndoe having the input. |
+template <class B, class S> |
+class GenericNode<B, S>::Edge { |
+ public: |
+ S* from() const { return static_cast<S*>(input_->use->from); } |
+ S* to() const { return static_cast<S*>(input_->to); } |
+ int index() const { |
+ int index = input_->use->input_index; |
+ DCHECK(index < input_->use->from->input_count_); |
+ return index; |
+ } |
+ |
+ private: |
+ friend class GenericNode<B, S>::Uses::iterator; |
+ friend class GenericNode<B, S>::Inputs::iterator; |
+ |
+ explicit Edge(typename GenericNode<B, S>::Input* input) : input_(input) {} |
+ |
+ typename GenericNode<B, S>::Input* input_; |
+}; |
+ |
+// A forward iterator to visit the nodes which are depended upon by a node |
+// in the order of input. |
+template <class B, class S> |
+class GenericNode<B, S>::Inputs::iterator { |
+ public: |
+ iterator(const typename GenericNode<B, S>::Inputs::iterator& other) // NOLINT |
+ : node_(other.node_), |
+ index_(other.index_) {} |
+ |
+ S* operator*() { return static_cast<S*>(GetInput()->to); } |
+ typename GenericNode<B, S>::Edge edge() { |
+ return typename GenericNode::Edge(GetInput()); |
+ } |
+ bool operator==(const iterator& other) const { |
+ return other.index_ == index_ && other.node_ == node_; |
+ } |
+ bool operator!=(const iterator& other) const { return !(other == *this); } |
+ iterator& operator++() { |
+ DCHECK(node_ != NULL); |
+ DCHECK(index_ < node_->input_count_); |
+ ++index_; |
+ return *this; |
+ } |
+ iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) { |
+ typename GenericNode<B, S>::Input* input = GetInput(); |
+ input->Update(new_to); |
+ index_++; |
+ return *this; |
+ } |
+ int index() { return index_; } |
+ |
+ private: |
+ friend class GenericNode; |
+ |
+ explicit iterator(GenericNode* node, int index) |
+ : node_(node), index_(index) {} |
+ |
+ Input* GetInput() const { return node_->GetInputRecordPtr(index_); } |
+ |
+ GenericNode* node_; |
+ int index_; |
+}; |
+ |
+// A forward iterator to visit the uses of a node. The uses are returned in |
+// the order in which they were added as inputs. |
+template <class B, class S> |
+class GenericNode<B, S>::Uses::iterator { |
+ public: |
+ iterator(const typename GenericNode<B, S>::Uses::iterator& other) // NOLINT |
+ : current_(other.current_), |
+ index_(other.index_) {} |
+ |
+ S* operator*() { return static_cast<S*>(current_->from); } |
+ typename GenericNode<B, S>::Edge edge() { |
+ return typename GenericNode::Edge(CurrentInput()); |
+ } |
+ |
+ bool operator==(const iterator& other) { return other.current_ == current_; } |
+ bool operator!=(const iterator& other) { return other.current_ != current_; } |
+ iterator& operator++() { |
+ DCHECK(current_ != NULL); |
+ index_++; |
+ current_ = current_->next; |
+ return *this; |
+ } |
+ iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) { |
+ DCHECK(current_ != NULL); |
+ index_++; |
+ typename GenericNode<B, S>::Input* input = CurrentInput(); |
+ current_ = current_->next; |
+ input->Update(new_to); |
+ return *this; |
+ } |
+ int index() const { return index_; } |
+ |
+ private: |
+ friend class GenericNode<B, S>::Uses; |
+ |
+ iterator() : current_(NULL), index_(0) {} |
+ explicit iterator(GenericNode<B, S>* node) |
+ : current_(node->first_use_), index_(0) {} |
+ |
+ Input* CurrentInput() const { |
+ return current_->from->GetInputRecordPtr(current_->input_index); |
+ } |
+ |
+ typename GenericNode<B, S>::Use* current_; |
+ int index_; |
+}; |
+} |
+} |
+} // namespace v8::internal::compiler |
+ |
+#endif // V8_COMPILER_GENERIC_NODE_H_ |