LCOV - code coverage report
Current view: top level - src/compiler - node.h (source / functions) Hit Total Coverage
Test: app.info Lines: 69 69 100.0 %
Date: 2019-04-17 Functions: 2 2 100.0 %

          Line data    Source code
       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_NODE_H_
       6             : #define V8_COMPILER_NODE_H_
       7             : 
       8             : #include "src/compiler/opcodes.h"
       9             : #include "src/compiler/operator.h"
      10             : #include "src/compiler/types.h"
      11             : #include "src/globals.h"
      12             : #include "src/zone/zone-containers.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace compiler {
      17             : 
      18             : // Forward declarations.
      19             : class Edge;
      20             : class Graph;
      21             : 
      22             : 
      23             : // Marks are used during traversal of the graph to distinguish states of nodes.
      24             : // Each node has a mark which is a monotonically increasing integer, and a
      25             : // {NodeMarker} has a range of values that indicate states of a node.
      26             : using Mark = uint32_t;
      27             : 
      28             : // NodeIds are identifying numbers for nodes that can be used to index auxiliary
      29             : // out-of-line data associated with each node.
      30             : using NodeId = uint32_t;
      31             : 
      32             : // A Node is the basic primitive of graphs. Nodes are chained together by
      33             : // input/use chains but by default otherwise contain only an identifying number
      34             : // which specific applications of graphs and nodes can use to index auxiliary
      35             : // out-of-line data, especially transient data.
      36             : //
      37             : // In addition Nodes only contain a mutable Operator that may change during
      38             : // compilation, e.g. during lowering passes. Other information that needs to be
      39             : // associated with Nodes during compilation must be stored out-of-line indexed
      40             : // by the Node's id.
      41             : class V8_EXPORT_PRIVATE Node final {
      42             :  public:
      43             :   static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
      44             :                    Node* const* inputs, bool has_extensible_inputs);
      45             :   static Node* Clone(Zone* zone, NodeId id, const Node* node);
      46             : 
      47             :   inline bool IsDead() const;
      48             :   void Kill();
      49             : 
      50             :   const Operator* op() const { return op_; }
      51             : 
      52             :   IrOpcode::Value opcode() const {
      53             :     DCHECK_GE(IrOpcode::kLast, op_->opcode());
      54  3435784922 :     return static_cast<IrOpcode::Value>(op_->opcode());
      55             :   }
      56             : 
      57             :   NodeId id() const { return IdField::decode(bit_field_); }
      58             : 
      59             :   int InputCount() const {
      60             :     return has_inline_inputs() ? InlineCountField::decode(bit_field_)
      61  1279821177 :                                : outline_inputs()->count_;
      62             :   }
      63             : 
      64             : #ifdef DEBUG
      65             :   void Verify();
      66             : #define BOUNDS_CHECK(index)                                                   \
      67             :   do {                                                                        \
      68             :     if (index < 0 || index >= InputCount()) {                                 \
      69             :       FATAL("Node #%d:%s->InputAt(%d) out of bounds", id(), op()->mnemonic(), \
      70             :             index);                                                           \
      71             :     }                                                                         \
      72             :   } while (false)
      73             : #else
      74             :   // No bounds checks or verification in release mode.
      75             :   inline void Verify() {}
      76             : #define BOUNDS_CHECK(index) \
      77             :   do {                      \
      78             :   } while (false)
      79             : #endif
      80             : 
      81             :   Node* InputAt(int index) const {
      82             :     BOUNDS_CHECK(index);
      83  2017840644 :     return *GetInputPtrConst(index);
      84             :   }
      85             : 
      86   141200915 :   void ReplaceInput(int index, Node* new_to) {
      87             :     BOUNDS_CHECK(index);
      88             :     Node** input_ptr = GetInputPtr(index);
      89   141200915 :     Node* old_to = *input_ptr;
      90   141200915 :     if (old_to != new_to) {
      91             :       Use* use = GetUsePtr(index);
      92    91400179 :       if (old_to) old_to->RemoveUse(use);
      93    91400012 :       *input_ptr = new_to;
      94    91400012 :       if (new_to) new_to->AppendUse(use);
      95             :     }
      96   141200828 :   }
      97             : 
      98             : #undef BOUNDS_CHECK
      99             : 
     100             :   void AppendInput(Zone* zone, Node* new_to);
     101             :   void InsertInput(Zone* zone, int index, Node* new_to);
     102             :   void InsertInputs(Zone* zone, int index, int count);
     103             :   void RemoveInput(int index);
     104             :   void NullAllInputs();
     105             :   void TrimInputCount(int new_input_count);
     106             : 
     107             :   int UseCount() const;
     108             :   void ReplaceUses(Node* replace_to);
     109             : 
     110             :   class InputEdges;
     111             :   inline InputEdges input_edges();
     112             : 
     113             :   class Inputs;
     114             :   inline Inputs inputs() const;
     115             : 
     116             :   class UseEdges final {
     117             :    public:
     118             :     using value_type = Edge;
     119             : 
     120             :     class iterator;
     121             :     inline iterator begin() const;
     122             :     inline iterator end() const;
     123             : 
     124             :     bool empty() const;
     125             : 
     126             :     explicit UseEdges(Node* node) : node_(node) {}
     127             : 
     128             :    private:
     129             :     Node* node_;
     130             :   };
     131             : 
     132             :   UseEdges use_edges() { return UseEdges(this); }
     133             : 
     134             :   class V8_EXPORT_PRIVATE Uses final {
     135             :    public:
     136             :     using value_type = Node*;
     137             : 
     138             :     class const_iterator;
     139             :     inline const_iterator begin() const;
     140             :     inline const_iterator end() const;
     141             : 
     142             :     bool empty() const;
     143             : 
     144             :     explicit Uses(Node* node) : node_(node) {}
     145             : 
     146             :    private:
     147             :     Node* node_;
     148             :   };
     149             : 
     150             :   Uses uses() { return Uses(this); }
     151             : 
     152             :   // Returns true if {owner} is the user of {this} node.
     153             :   bool OwnedBy(Node* owner) const {
     154    20861617 :     return first_use_ && first_use_->from() == owner && !first_use_->next;
     155             :   }
     156             : 
     157             :   // Returns true if {owner1} and {owner2} are the only users of {this} node.
     158             :   bool OwnedBy(Node const* owner1, Node const* owner2) const;
     159             : 
     160             :   void Print() const;
     161             :   void Print(std::ostream&) const;
     162             : 
     163             :  private:
     164             :   struct Use;
     165             :   // Out of line storage for inputs when the number of inputs overflowed the
     166             :   // capacity of the inline-allocated space.
     167             :   struct OutOfLineInputs {
     168             :     Node* node_;
     169             :     int count_;
     170             :     int capacity_;
     171             : 
     172             :     // Inputs are allocated right behind the OutOfLineInputs instance.
     173             :     inline Node** inputs();
     174             : 
     175             :     static OutOfLineInputs* New(Zone* zone, int capacity);
     176             :     void ExtractFrom(Use* use_ptr, Node** input_ptr, int count);
     177             :   };
     178             : 
     179             :   // A link in the use chain for a node. Every input {i} to a node {n} has an
     180             :   // associated {Use} which is linked into the use chain of the {i} node.
     181             :   struct Use {
     182             :     Use* next;
     183             :     Use* prev;
     184             :     uint32_t bit_field_;
     185             : 
     186  4140733251 :     int input_index() const { return InputIndexField::decode(bit_field_); }
     187             :     bool is_inline_use() const { return InlineField::decode(bit_field_); }
     188             :     Node** input_ptr() {
     189             :       int index = input_index();
     190  1519579904 :       Use* start = this + 1 + index;
     191             :       Node** inputs = is_inline_use()
     192             :                           ? reinterpret_cast<Node*>(start)->inline_inputs()
     193  1495503944 :                           : reinterpret_cast<OutOfLineInputs*>(start)->inputs();
     194  1495503944 :       return &inputs[index];
     195             :     }
     196             : 
     197             :     Node* from() {
     198  2321436770 :       Use* start = this + 1 + input_index();
     199             :       return is_inline_use() ? reinterpret_cast<Node*>(start)
     200  3550454849 :                              : reinterpret_cast<OutOfLineInputs*>(start)->node_;
     201             :     }
     202             : 
     203             :     using InlineField = BitField<bool, 0, 1>;
     204             :     using InputIndexField = BitField<unsigned, 1, 17>;
     205             :     // Leaving some space in the bitset in case we ever decide to record
     206             :     // the output index.
     207             :   };
     208             : 
     209             :   //============================================================================
     210             :   //== Memory layout ===========================================================
     211             :   //============================================================================
     212             :   // Saving space for big graphs is important. We use a memory layout trick to
     213             :   // be able to map {Node} objects to {Use} objects and vice-versa in a
     214             :   // space-efficient manner.
     215             :   //
     216             :   // {Use} links are laid out in memory directly before a {Node}, followed by
     217             :   // direct pointers to input {Nodes}.
     218             :   //
     219             :   // inline case:
     220             :   // |Use #N  |Use #N-1|...|Use #1  |Use #0  |Node xxxx |I#0|I#1|...|I#N-1|I#N|
     221             :   //          ^                              ^                  ^
     222             :   //          + Use                          + Node             + Input
     223             :   //
     224             :   // Since every {Use} instance records its {input_index}, pointer arithmetic
     225             :   // can compute the {Node}.
     226             :   //
     227             :   // out-of-line case:
     228             :   //     |Node xxxx |
     229             :   //     ^       + outline ------------------+
     230             :   //     +----------------------------------------+
     231             :   //                                         |    |
     232             :   //                                         v    | node
     233             :   // |Use #N  |Use #N-1|...|Use #1  |Use #0  |OOL xxxxx |I#0|I#1|...|I#N-1|I#N|
     234             :   //          ^                                                 ^
     235             :   //          + Use                                             + Input
     236             :   //
     237             :   // Out-of-line storage of input lists is needed if appending an input to
     238             :   // a node exceeds the maximum inline capacity.
     239             : 
     240             :   Node(NodeId id, const Operator* op, int inline_count, int inline_capacity);
     241             : 
     242             :   inline Address inputs_location() const;
     243             : 
     244             :   Node** inline_inputs() const {
     245  6449028916 :     return reinterpret_cast<Node**>(inputs_location());
     246             :   }
     247             :   OutOfLineInputs* outline_inputs() const {
     248  1133237770 :     return *reinterpret_cast<OutOfLineInputs**>(inputs_location());
     249             :   }
     250             :   void set_outline_inputs(OutOfLineInputs* outline) {
     251    13663221 :     *reinterpret_cast<OutOfLineInputs**>(inputs_location()) = outline;
     252             :   }
     253             : 
     254             :   Node* const* GetInputPtrConst(int input_index) const {
     255             :     return has_inline_inputs() ? &(inline_inputs()[input_index])
     256  3848615114 :                                : &(outline_inputs()->inputs()[input_index]);
     257             :   }
     258             :   Node** GetInputPtr(int input_index) {
     259    75642380 :     return has_inline_inputs() ? &(inline_inputs()[input_index])
     260   380654896 :                                : &(outline_inputs()->inputs()[input_index]);
     261             :   }
     262             :   Use* GetUsePtr(int input_index) {
     263             :     Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
     264   147337968 :                                    : reinterpret_cast<Use*>(outline_inputs());
     265   147337968 :     return &ptr[-1 - input_index];
     266             :   }
     267             : 
     268             :   void AppendUse(Use* use);
     269             :   void RemoveUse(Use* use);
     270             : 
     271             :   void* operator new(size_t, void* location) { return location; }
     272             : 
     273             :   // Only NodeProperties should manipulate the op.
     274    38660602 :   void set_op(const Operator* op) { op_ = op; }
     275             : 
     276             :   // Only NodeProperties should manipulate the type.
     277             :   Type type() const { return type_; }
     278    47687717 :   void set_type(Type type) { type_ = type; }
     279             : 
     280             :   // Only NodeMarkers should manipulate the marks on nodes.
     281             :   Mark mark() const { return mark_; }
     282  1516631229 :   void set_mark(Mark mark) { mark_ = mark; }
     283             : 
     284             :   inline bool has_inline_inputs() const {
     285             :     return InlineCountField::decode(bit_field_) != kOutlineMarker;
     286             :   }
     287             : 
     288             :   void ClearInputs(int start, int count);
     289             : 
     290             :   using IdField = BitField<NodeId, 0, 24>;
     291             :   using InlineCountField = BitField<unsigned, 24, 4>;
     292             :   using InlineCapacityField = BitField<unsigned, 28, 4>;
     293             :   static const int kOutlineMarker = InlineCountField::kMax;
     294             :   static const int kMaxInlineCount = InlineCountField::kMax - 1;
     295             :   static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1;
     296             : 
     297             :   const Operator* op_;
     298             :   Type type_;
     299             :   Mark mark_;
     300             :   uint32_t bit_field_;
     301             :   Use* first_use_;
     302             : 
     303             :   friend class Edge;
     304             :   friend class NodeMarkerBase;
     305             :   friend class NodeProperties;
     306             : 
     307             :   DISALLOW_COPY_AND_ASSIGN(Node);
     308             : };
     309             : 
     310             : Address Node::inputs_location() const {
     311  7595482436 :   return reinterpret_cast<Address>(this) + sizeof(Node);
     312             : }
     313             : 
     314             : Node** Node::OutOfLineInputs::inputs() {
     315  1301939203 :   return reinterpret_cast<Node**>(reinterpret_cast<Address>(this) +
     316  1301939203 :                                   sizeof(Node::OutOfLineInputs));
     317             : }
     318             : 
     319             : std::ostream& operator<<(std::ostream& os, const Node& n);
     320             : 
     321             : 
     322             : // Typedefs to shorten commonly used Node containers.
     323             : using NodeDeque = ZoneDeque<Node*>;
     324             : using NodeSet = ZoneSet<Node*>;
     325             : using NodeVector = ZoneVector<Node*>;
     326             : using NodeVectorVector = ZoneVector<NodeVector>;
     327             : 
     328             : class Node::InputEdges final {
     329             :  public:
     330             :   using value_type = Edge;
     331             : 
     332             :   class iterator;
     333             :   inline iterator begin() const;
     334             :   inline iterator end() const;
     335             : 
     336             :   bool empty() const { return count_ == 0; }
     337             :   int count() const { return count_; }
     338             : 
     339             :   inline value_type operator[](int index) const;
     340             : 
     341             :   InputEdges(Node** input_root, Use* use_root, int count)
     342             :       : input_root_(input_root), use_root_(use_root), count_(count) {}
     343             : 
     344             :  private:
     345             :   Node** input_root_;
     346             :   Use* use_root_;
     347             :   int count_;
     348             : };
     349             : 
     350             : class V8_EXPORT_PRIVATE Node::Inputs final {
     351             :  public:
     352             :   using value_type = Node*;
     353             : 
     354             :   class const_iterator;
     355             :   inline const_iterator begin() const;
     356             :   inline const_iterator end() const;
     357             : 
     358           4 :   bool empty() const { return count_ == 0; }
     359             :   int count() const { return count_; }
     360             : 
     361             :   inline value_type operator[](int index) const;
     362             : 
     363             :   explicit Inputs(Node* const* input_root, int count)
     364             :       : input_root_(input_root), count_(count) {}
     365             : 
     366             :  private:
     367             :   Node* const* input_root_;
     368             :   int count_;
     369             : };
     370             : 
     371             : // An encapsulation for information associated with a single use of node as a
     372             : // input from another node, allowing access to both the defining node and
     373             : // the node having the input.
     374             : class Edge final {
     375             :  public:
     376             :   Node* from() const { return use_->from(); }
     377   704430004 :   Node* to() const { return *input_ptr_; }
     378             :   int index() const {
     379             :     int const index = use_->input_index();
     380             :     DCHECK_LT(index, use_->from()->InputCount());
     381             :     return index;
     382             :   }
     383             : 
     384             :   bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; }
     385             :   bool operator!=(const Edge& other) { return !(*this == other); }
     386             : 
     387    94780492 :   void UpdateTo(Node* new_to) {
     388    94780492 :     Node* old_to = *input_ptr_;
     389    94780492 :     if (old_to != new_to) {
     390    90810173 :       if (old_to) old_to->RemoveUse(use_);
     391    90810448 :       *input_ptr_ = new_to;
     392    90810448 :       if (new_to) new_to->AppendUse(use_);
     393             :     }
     394    94781166 :   }
     395             : 
     396             :  private:
     397             :   friend class Node::UseEdges::iterator;
     398             :   friend class Node::InputEdges;
     399             :   friend class Node::InputEdges::iterator;
     400             : 
     401             :   Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) {
     402             :     DCHECK_NOT_NULL(use);
     403             :     DCHECK_NOT_NULL(input_ptr);
     404             :     DCHECK_EQ(input_ptr, use->input_ptr());
     405             :   }
     406             : 
     407             :   Node::Use* use_;
     408             :   Node** input_ptr_;
     409             : };
     410             : 
     411             : bool Node::IsDead() const {
     412             :   Node::Inputs inputs = this->inputs();
     413  2817504204 :   return inputs.count() > 0 && inputs[0] == nullptr;
     414             : }
     415             : 
     416             : Node::InputEdges Node::input_edges() {
     417   943695231 :   int inline_count = InlineCountField::decode(bit_field_);
     418   519214205 :   if (inline_count != kOutlineMarker) {
     419             :     return InputEdges(inline_inputs(), reinterpret_cast<Use*>(this) - 1,
     420   168841789 :                       inline_count);
     421             :   } else {
     422             :     return InputEdges(outline_inputs()->inputs(),
     423             :                       reinterpret_cast<Use*>(outline_inputs()) - 1,
     424   128873129 :                       outline_inputs()->count_);
     425             :   }
     426             : }
     427             : 
     428             : Node::Inputs Node::inputs() const {
     429  4890468188 :   int inline_count = InlineCountField::decode(bit_field_);
     430  3354287086 :   if (inline_count != kOutlineMarker) {
     431             :     return Inputs(inline_inputs(), inline_count);
     432             :   } else {
     433   337329758 :     return Inputs(outline_inputs()->inputs(), outline_inputs()->count_);
     434             :   }
     435             : }
     436             : 
     437             : // A forward iterator to visit the edges for the input dependencies of a node.
     438             : class Node::InputEdges::iterator final {
     439             :  public:
     440             :   using iterator_category = std::forward_iterator_tag;
     441             :   using difference_type = std::ptrdiff_t;
     442             :   using value_type = Edge;
     443             :   using pointer = Edge*;
     444             :   using reference = Edge&;
     445             : 
     446             :   iterator() : use_(nullptr), input_ptr_(nullptr) {}
     447             :   iterator(const iterator& other) = default;
     448             : 
     449   457445930 :   Edge operator*() const { return Edge(use_, input_ptr_); }
     450             :   bool operator==(const iterator& other) const {
     451             :     return input_ptr_ == other.input_ptr_;
     452             :   }
     453             :   bool operator!=(const iterator& other) const { return !(*this == other); }
     454             :   iterator& operator++() {
     455   564726495 :     input_ptr_++;
     456   564726495 :     use_--;
     457             :     return *this;
     458             :   }
     459             :   iterator operator++(int);
     460             :   iterator& operator+=(difference_type offset) {
     461             :     input_ptr_ += offset;
     462             :     use_ -= offset;
     463             :     return *this;
     464             :   }
     465             :   iterator operator+(difference_type offset) const {
     466             :     return iterator(use_ - offset, input_ptr_ + offset);
     467             :   }
     468             :   difference_type operator-(const iterator& other) const {
     469             :     return input_ptr_ - other.input_ptr_;
     470             :   }
     471             : 
     472             :  private:
     473             :   friend class Node;
     474             : 
     475             :   explicit iterator(Use* use, Node** input_ptr)
     476             :       : use_(use), input_ptr_(input_ptr) {}
     477             : 
     478             :   Use* use_;
     479             :   Node** input_ptr_;
     480             : };
     481             : 
     482             : 
     483             : Node::InputEdges::iterator Node::InputEdges::begin() const {
     484             :   return Node::InputEdges::iterator(use_root_, input_root_);
     485             : }
     486             : 
     487             : 
     488             : Node::InputEdges::iterator Node::InputEdges::end() const {
     489   421427496 :   return Node::InputEdges::iterator(use_root_ - count_, input_root_ + count_);
     490             : }
     491             : 
     492             : Edge Node::InputEdges::operator[](int index) const {
     493             :   return Edge(use_root_ + index, input_root_ + index);
     494             : }
     495             : 
     496             : // A forward iterator to visit the inputs of a node.
     497             : class Node::Inputs::const_iterator final {
     498             :  public:
     499             :   using iterator_category = std::forward_iterator_tag;
     500             :   using difference_type = std::ptrdiff_t;
     501             :   using value_type = Node*;
     502             :   using pointer = const value_type*;
     503             :   using reference = value_type&;
     504             : 
     505             :   const_iterator(const const_iterator& other) = default;
     506             : 
     507  2130712762 :   Node* operator*() const { return *input_ptr_; }
     508             :   bool operator==(const const_iterator& other) const {
     509           1 :     return input_ptr_ == other.input_ptr_;
     510             :   }
     511             :   bool operator!=(const const_iterator& other) const {
     512             :     return !(*this == other);
     513             :   }
     514             :   const_iterator& operator++() {
     515  2122598181 :     ++input_ptr_;
     516             :     return *this;
     517             :   }
     518             :   const_iterator operator++(int);
     519             :   const_iterator& operator+=(difference_type offset) {
     520             :     input_ptr_ += offset;
     521             :     return *this;
     522             :   }
     523             :   const_iterator operator+(difference_type offset) const {
     524             :     return const_iterator(input_ptr_ + offset);
     525             :   }
     526             :   difference_type operator-(const const_iterator& other) const {
     527             :     return input_ptr_ - other.input_ptr_;
     528             :   }
     529             : 
     530             :  private:
     531             :   friend class Node::Inputs;
     532             : 
     533             :   explicit const_iterator(Node* const* input_ptr) : input_ptr_(input_ptr) {}
     534             : 
     535             :   Node* const* input_ptr_;
     536             : };
     537             : 
     538             : 
     539             : Node::Inputs::const_iterator Node::Inputs::begin() const {
     540             :   return const_iterator(input_root_);
     541             : }
     542             : 
     543             : 
     544             : Node::Inputs::const_iterator Node::Inputs::end() const {
     545   815517283 :   return const_iterator(input_root_ + count_);
     546             : }
     547             : 
     548  3592786520 : Node* Node::Inputs::operator[](int index) const { return input_root_[index]; }
     549             : 
     550             : // A forward iterator to visit the uses edges of a node.
     551             : class Node::UseEdges::iterator final {
     552             :  public:
     553             :   iterator(const iterator& other) = default;
     554             : 
     555             :   Edge operator*() const { return Edge(current_, current_->input_ptr()); }
     556             :   bool operator==(const iterator& other) const {
     557       18799 :     return current_ == other.current_;
     558             :   }
     559             :   bool operator!=(const iterator& other) const { return !(*this == other); }
     560             :   iterator& operator++() {
     561             :     DCHECK_NOT_NULL(current_);
     562      640609 :     current_ = next_;
     563  1496326444 :     next_ = current_ ? current_->next : nullptr;
     564             :     return *this;
     565             :   }
     566             :   iterator operator++(int);
     567             : 
     568             :  private:
     569             :   friend class Node::UseEdges;
     570             : 
     571             :   iterator() : current_(nullptr), next_(nullptr) {}
     572             :   explicit iterator(Node* node)
     573   576973244 :       : current_(node->first_use_),
     574   576955270 :         next_(current_ ? current_->next : nullptr) {}
     575             : 
     576             :   Node::Use* current_;
     577             :   Node::Use* next_;
     578             : };
     579             : 
     580             : 
     581             : Node::UseEdges::iterator Node::UseEdges::begin() const {
     582       18799 :   return Node::UseEdges::iterator(this->node_);
     583             : }
     584             : 
     585             : 
     586             : Node::UseEdges::iterator Node::UseEdges::end() const {
     587             :   return Node::UseEdges::iterator();
     588             : }
     589             : 
     590             : 
     591             : // A forward iterator to visit the uses of a node.
     592             : class Node::Uses::const_iterator final {
     593             :  public:
     594             :   using iterator_category = std::forward_iterator_tag;
     595             :   using difference_type = int;
     596             :   using value_type = Node*;
     597             :   using pointer = Node**;
     598             :   using reference = Node*&;
     599             : 
     600      182072 :   Node* operator*() const { return current_->from(); }
     601             :   bool operator==(const const_iterator& other) const {
     602     1214134 :     return other.current_ == current_;
     603             :   }
     604             :   bool operator!=(const const_iterator& other) const {
     605        8540 :     return other.current_ != current_;
     606             :   }
     607             :   const_iterator& operator++() {
     608             :     DCHECK_NOT_NULL(current_);
     609             :     // Checking no use gets mutated while iterating through them, a potential
     610             :     // very tricky cause of bug.
     611   603626783 :     current_ = current_->next;
     612             : #ifdef DEBUG
     613             :     DCHECK_EQ(current_, next_);
     614             :     next_ = current_ ? current_->next : nullptr;
     615             : #endif
     616             :     return *this;
     617             :   }
     618             :   const_iterator operator++(int);
     619             : 
     620             :  private:
     621             :   friend class Node::Uses;
     622             : 
     623             :   const_iterator() : current_(nullptr) {}
     624             :   explicit const_iterator(Node* node)
     625   225934710 :       : current_(node->first_use_)
     626             : #ifdef DEBUG
     627             :         ,
     628             :         next_(current_ ? current_->next : nullptr)
     629             : #endif
     630             :   {
     631             :   }
     632             : 
     633             :   Node::Use* current_;
     634             : #ifdef DEBUG
     635             :   Node::Use* next_;
     636             : #endif
     637             : };
     638             : 
     639             : 
     640             : Node::Uses::const_iterator Node::Uses::begin() const {
     641     1214265 :   return const_iterator(this->node_);
     642             : }
     643             : 
     644             : 
     645             : Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
     646             : 
     647             : }  // namespace compiler
     648             : }  // namespace internal
     649             : }  // namespace v8
     650             : 
     651             : #endif  // V8_COMPILER_NODE_H_

Generated by: LCOV version 1.10