// 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 type. template 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(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(current->from); } inline void ReplaceUses(GenericNode* replace_to); template 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); 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); private: void AssignUniqueID(GenericGraphBase* graph); typedef ZoneDeque InputDeque; NodeId id_; int input_count_ : 31; 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 GenericNode::Edge { public: S* from() const { return static_cast(input_->use->from); } S* to() const { return static_cast(input_->to); } int index() const { int index = input_->use->input_index; DCHECK(index < input_->use->from->input_count_); return index; } private: friend class GenericNode::Uses::iterator; friend class GenericNode::Inputs::iterator; explicit Edge(typename GenericNode::Input* input) : input_(input) {} typename GenericNode::Input* input_; }; // A forward iterator to visit the nodes which are depended upon by a node // in the order of input. template class GenericNode::Inputs::iterator { public: iterator(const typename GenericNode::Inputs::iterator& other) // NOLINT : node_(other.node_), index_(other.index_) {} S* operator*() { return static_cast(GetInput()->to); } typename GenericNode::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* new_to) { typename GenericNode::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 GenericNode::Uses::iterator { public: iterator(const typename GenericNode::Uses::iterator& other) // NOLINT : current_(other.current_), index_(other.index_) {} S* operator*() { return static_cast(current_->from); } typename GenericNode::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* new_to) { DCHECK(current_ != NULL); index_++; typename GenericNode::Input* input = CurrentInput(); current_ = current_->next; input->Update(new_to); return *this; } int index() const { return index_; } private: friend class GenericNode::Uses; iterator() : current_(NULL), index_(0) {} explicit iterator(GenericNode* node) : current_(node->first_use_), index_(0) {} Input* CurrentInput() const { return current_->from->GetInputRecordPtr(current_->input_index); } typename GenericNode::Use* current_; int index_; }; } } } // namespace v8::internal::compiler #endif // V8_COMPILER_GENERIC_NODE_H_