• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/common/globals.h"
9 #include "src/compiler/graph-zone-traits.h"
10 #include "src/compiler/opcodes.h"
11 #include "src/compiler/operator.h"
12 #include "src/compiler/types.h"
13 #include "src/zone/zone-containers.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18 
19 // Forward declarations.
20 class Edge;
21 class Graph;
22 
23 
24 // Marks are used during traversal of the graph to distinguish states of nodes.
25 // Each node has a mark which is a monotonically increasing integer, and a
26 // {NodeMarker} has a range of values that indicate states of a node.
27 using Mark = uint32_t;
28 
29 // NodeIds are identifying numbers for nodes that can be used to index auxiliary
30 // out-of-line data associated with each node.
31 using NodeId = uint32_t;
32 
33 // A Node is the basic primitive of graphs. Nodes are chained together by
34 // input/use chains but by default otherwise contain only an identifying number
35 // which specific applications of graphs and nodes can use to index auxiliary
36 // out-of-line data, especially transient data.
37 //
38 // In addition Nodes only contain a mutable Operator that may change during
39 // compilation, e.g. during lowering passes. Other information that needs to be
40 // associated with Nodes during compilation must be stored out-of-line indexed
41 // by the Node's id.
42 class V8_EXPORT_PRIVATE Node final {
43  public:
44   static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
45                    Node* const* inputs, bool has_extensible_inputs);
46   static Node* Clone(Zone* zone, NodeId id, const Node* node);
47 
48   inline bool IsDead() const;
49   void Kill();
50 
op()51   const Operator* op() const { return op_; }
52 
opcode()53   IrOpcode::Value opcode() const {
54     DCHECK_GE(IrOpcode::kLast, op_->opcode());
55     return static_cast<IrOpcode::Value>(op_->opcode());
56   }
57 
id()58   NodeId id() const { return IdField::decode(bit_field_); }
59 
InputCount()60   int InputCount() const {
61     return has_inline_inputs() ? InlineCountField::decode(bit_field_)
62                                : outline_inputs()->count_;
63   }
64 
65 #ifdef DEBUG
66   void Verify();
67 #else
Verify()68   inline void Verify() {}
69 #endif
70 
InputAt(int index)71   Node* InputAt(int index) const {
72     CHECK_LE(0, index);
73     CHECK_LT(index, InputCount());
74     return *GetInputPtrConst(index);
75   }
76 
ReplaceInput(int index,Node * new_to)77   void ReplaceInput(int index, Node* new_to) {
78     CHECK_LE(0, index);
79     CHECK_LT(index, InputCount());
80     ZoneNodePtr* input_ptr = GetInputPtr(index);
81     Node* old_to = *input_ptr;
82     if (old_to != new_to) {
83       Use* use = GetUsePtr(index);
84       if (old_to) old_to->RemoveUse(use);
85       *input_ptr = new_to;
86       if (new_to) new_to->AppendUse(use);
87     }
88   }
89 
90   void AppendInput(Zone* zone, Node* new_to);
91   void InsertInput(Zone* zone, int index, Node* new_to);
92   void InsertInputs(Zone* zone, int index, int count);
93   // Returns the removed input.
94   Node* RemoveInput(int index);
95   void NullAllInputs();
96   void TrimInputCount(int new_input_count);
97   // Can trim, extend by appending new inputs, or do nothing.
98   void EnsureInputCount(Zone* zone, int new_input_count);
99 
100   int UseCount() const;
101   void ReplaceUses(Node* replace_to);
102 
103   class InputEdges;
104   inline InputEdges input_edges();
105 
106   class Inputs;
107   inline Inputs inputs() const;
108 
109   class UseEdges final {
110    public:
111     using value_type = Edge;
112 
113     class iterator;
114     inline iterator begin() const;
115     inline iterator end() const;
116 
117     bool empty() const;
118 
UseEdges(Node * node)119     explicit UseEdges(Node* node) : node_(node) {}
120 
121    private:
122     Node* node_;
123   };
124 
use_edges()125   UseEdges use_edges() { return UseEdges(this); }
126 
127   class V8_EXPORT_PRIVATE Uses final {
128    public:
129     using value_type = Node*;
130 
131     class const_iterator;
132     inline const_iterator begin() const;
133     inline const_iterator end() const;
134 
135     bool empty() const;
136 
Uses(Node * node)137     explicit Uses(Node* node) : node_(node) {}
138 
139    private:
140     Node* node_;
141   };
142 
uses()143   Uses uses() { return Uses(this); }
144 
145   // Returns true if {owner} is the only user of {this} node.
146   bool OwnedBy(Node const* owner) const;
147 
148   // Returns true if {owner1} and {owner2} are the only users of {this} node.
149   bool OwnedBy(Node const* owner1, Node const* owner2) const;
150 
Print()151   void Print() const { Print(1); }
152   void Print(int depth) const;
153   void Print(std::ostream&, int depth = 1) const;
154 
155  private:
156   template <typename NodePtrT>
157   inline static Node* NewImpl(Zone* zone, NodeId id, const Operator* op,
158                               int input_count, NodePtrT const* inputs,
159                               bool has_extensible_inputs);
160 
161   struct Use;
162   using ZoneUsePtr = GraphZoneTraits::Ptr<Use>;
163 
164   // Out of line storage for inputs when the number of inputs overflowed the
165   // capacity of the inline-allocated space.
166   struct OutOfLineInputs {
167     ZoneNodePtr node_;
168     int count_;
169     int capacity_;
170 
171     // Inputs are allocated right behind the OutOfLineInputs instance.
172     inline ZoneNodePtr* inputs();
173 
174     static OutOfLineInputs* New(Zone* zone, int capacity);
175     void ExtractFrom(Use* use_ptr, ZoneNodePtr* input_ptr, int count);
176   };
177   using ZoneOutOfLineInputsPtr = GraphZoneTraits::Ptr<OutOfLineInputs>;
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     ZoneUsePtr next;
183     ZoneUsePtr prev;
184     uint32_t bit_field_;
185 
input_indexUse186     int input_index() const { return InputIndexField::decode(bit_field_); }
is_inline_useUse187     bool is_inline_use() const { return InlineField::decode(bit_field_); }
input_ptrUse188     ZoneNodePtr* input_ptr() {
189       int index = input_index();
190       Use* start = this + 1 + index;
191       ZoneNodePtr* inputs =
192           is_inline_use() ? reinterpret_cast<Node*>(start)->inline_inputs()
193                           : reinterpret_cast<OutOfLineInputs*>(start)->inputs();
194       return &inputs[index];
195     }
196 
fromUse197     Node* from() {
198       Use* start = this + 1 + input_index();
199       return is_inline_use() ? reinterpret_cast<Node*>(start)
200                              : reinterpret_cast<OutOfLineInputs*>(start)->node_;
201     }
202 
203     using InlineField = base::BitField<bool, 0, 1>;
204     using InputIndexField = base::BitField<unsigned, 1, 31>;
205   };
206 
207   //============================================================================
208   //== Memory layout ===========================================================
209   //============================================================================
210   // Saving space for big graphs is important. We use a memory layout trick to
211   // be able to map {Node} objects to {Use} objects and vice-versa in a
212   // space-efficient manner.
213   //
214   // {Use} links are laid out in memory directly before a {Node}, followed by
215   // direct pointers to input {Nodes}.
216   //
217   // inline case:
218   // |Use #N  |Use #N-1|...|Use #1  |Use #0  |Node xxxx |I#0|I#1|...|I#N-1|I#N|
219   //          ^                              ^                  ^
220   //          + Use                          + Node             + Input
221   //
222   // Since every {Use} instance records its {input_index}, pointer arithmetic
223   // can compute the {Node}.
224   //
225   // out-of-line case:
226   //     |Node xxxx |
227   //     ^       + outline ------------------+
228   //     +----------------------------------------+
229   //                                         |    |
230   //                                         v    | node
231   // |Use #N  |Use #N-1|...|Use #1  |Use #0  |OOL xxxxx |I#0|I#1|...|I#N-1|I#N|
232   //          ^                                                 ^
233   //          + Use                                             + Input
234   //
235   // Out-of-line storage of input lists is needed if appending an input to
236   // a node exceeds the maximum inline capacity.
237 
238   Node(NodeId id, const Operator* op, int inline_count, int inline_capacity);
239   Node(const Node&) = delete;
240   Node& operator=(const Node&) = delete;
241 
242   inline Address inputs_location() const;
243 
inline_inputs()244   ZoneNodePtr* inline_inputs() const {
245     return reinterpret_cast<ZoneNodePtr*>(inputs_location());
246   }
outline_inputs()247   OutOfLineInputs* outline_inputs() const {
248     return *reinterpret_cast<ZoneOutOfLineInputsPtr*>(inputs_location());
249   }
set_outline_inputs(OutOfLineInputs * outline)250   void set_outline_inputs(OutOfLineInputs* outline) {
251     *reinterpret_cast<ZoneOutOfLineInputsPtr*>(inputs_location()) = outline;
252   }
253 
GetInputPtrConst(int input_index)254   ZoneNodePtr const* GetInputPtrConst(int input_index) const {
255     return has_inline_inputs() ? &(inline_inputs()[input_index])
256                                : &(outline_inputs()->inputs()[input_index]);
257   }
GetInputPtr(int input_index)258   ZoneNodePtr* GetInputPtr(int input_index) {
259     return has_inline_inputs() ? &(inline_inputs()[input_index])
260                                : &(outline_inputs()->inputs()[input_index]);
261   }
GetUsePtr(int input_index)262   Use* GetUsePtr(int input_index) {
263     Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
264                                    : reinterpret_cast<Use*>(outline_inputs());
265     return &ptr[-1 - input_index];
266   }
267 
268   void AppendUse(Use* use);
269   void RemoveUse(Use* use);
270 
new(size_t,void * location)271   void* operator new(size_t, void* location) { return location; }
272 
273   // Only NodeProperties should manipulate the op.
set_op(const Operator * op)274   void set_op(const Operator* op) { op_ = op; }
275 
276   // Only NodeProperties should manipulate the type.
type()277   Type type() const { return type_; }
set_type(Type type)278   void set_type(Type type) { type_ = type; }
279 
280   // Only NodeMarkers should manipulate the marks on nodes.
mark()281   Mark mark() const { return mark_; }
set_mark(Mark mark)282   void set_mark(Mark mark) { mark_ = mark; }
283 
has_inline_inputs()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 = base::BitField<NodeId, 0, 24>;
291   using InlineCountField = base::BitField<unsigned, 24, 4>;
292   using InlineCapacityField = base::BitField<unsigned, 28, 4>;
293   static const int kOutlineMarker = InlineCountField::kMax;
294   static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1;
295 
296   const Operator* op_;
297   Type type_;
298   Mark mark_;
299   uint32_t bit_field_;
300   ZoneUsePtr first_use_;
301 
302   friend class Edge;
303   friend class NodeMarkerBase;
304   friend class NodeProperties;
305 };
306 
inputs_location()307 Address Node::inputs_location() const {
308   return reinterpret_cast<Address>(this) + sizeof(Node);
309 }
310 
inputs()311 ZoneNodePtr* Node::OutOfLineInputs::inputs() {
312   return reinterpret_cast<ZoneNodePtr*>(reinterpret_cast<Address>(this) +
313                                         sizeof(Node::OutOfLineInputs));
314 }
315 
316 std::ostream& operator<<(std::ostream& os, const Node& n);
317 
318 // Base class for node wrappers.
319 class NodeWrapper {
320  public:
NodeWrapper(Node * node)321   explicit constexpr NodeWrapper(Node* node) : node_(node) {}
322   operator Node*() const { return node_; }
323   Node* operator->() const { return node_; }
324 
325  protected:
node()326   Node* node() const { return node_; }
set_node(Node * node)327   void set_node(Node* node) {
328     DCHECK_NOT_NULL(node);
329     node_ = node;
330   }
331 
332  private:
333   Node* node_;
334 };
335 
336 // Wrapper classes for special node/edge types (effect, control, frame states).
337 
338 class Effect : public NodeWrapper {
339  public:
Effect(Node * node)340   explicit constexpr Effect(Node* node) : NodeWrapper(node) {
341     // TODO(jgruber): Remove the End special case.
342     SLOW_DCHECK(node == nullptr || node->op()->opcode() == IrOpcode::kEnd ||
343                 node->op()->EffectOutputCount() > 0);
344   }
345 
346   // Support the common `Node* x = effect = ...` pattern.
347   Node* operator=(Node* value) {
348     DCHECK_GT(value->op()->EffectOutputCount(), 0);
349     set_node(value);
350     return value;
351   }
352 };
353 
354 class Control : public NodeWrapper {
355  public:
Control(Node * node)356   explicit constexpr Control(Node* node) : NodeWrapper(node) {
357     // TODO(jgruber): Remove the End special case.
358     SLOW_DCHECK(node == nullptr || node->opcode() == IrOpcode::kEnd ||
359                 node->op()->ControlOutputCount() > 0);
360   }
361 
362   // Support the common `Node* x = control = ...` pattern.
363   Node* operator=(Node* value) {
364     DCHECK_GT(value->op()->ControlOutputCount(), 0);
365     set_node(value);
366     return value;
367   }
368 };
369 
370 class FrameState : public NodeWrapper {
371  public:
FrameState(Node * node)372   explicit constexpr FrameState(Node* node) : NodeWrapper(node) {
373     // TODO(jgruber): Disallow kStart (needed for PromiseConstructorBasic unit
374     // test, among others).
375     SLOW_DCHECK(node->opcode() == IrOpcode::kFrameState ||
376                 node->opcode() == IrOpcode::kStart);
377   }
378 
379   // Duplicating here from frame-states.h for ease of access and to keep
380   // header include-balls small. Equality of the two constants is
381   // static-asserted elsewhere.
382   static constexpr int kFrameStateOuterStateInput = 5;
383 
outer_frame_state()384   FrameState outer_frame_state() const {
385     return FrameState{node()->InputAt(kFrameStateOuterStateInput)};
386   }
387 };
388 
389 // Typedefs to shorten commonly used Node containers.
390 using NodeDeque = ZoneDeque<Node*>;
391 using NodeSet = ZoneSet<Node*>;
392 using NodeVector = ZoneVector<Node*>;
393 using NodeVectorVector = ZoneVector<NodeVector>;
394 
395 class Node::InputEdges final {
396  public:
397   using value_type = Edge;
398 
399   class iterator;
400   inline iterator begin() const;
401   inline iterator end() const;
402 
empty()403   bool empty() const { return count_ == 0; }
count()404   int count() const { return count_; }
405 
406   inline value_type operator[](int index) const;
407 
InputEdges(ZoneNodePtr * input_root,Use * use_root,int count)408   InputEdges(ZoneNodePtr* input_root, Use* use_root, int count)
409       : input_root_(input_root), use_root_(use_root), count_(count) {}
410 
411  private:
412   ZoneNodePtr* input_root_;
413   Use* use_root_;
414   int count_;
415 };
416 
417 class V8_EXPORT_PRIVATE Node::Inputs final {
418  public:
419   using value_type = Node*;
420 
421   class const_iterator;
422   inline const_iterator begin() const;
423   inline const_iterator end() const;
424 
empty()425   bool empty() const { return count_ == 0; }
count()426   int count() const { return count_; }
427 
428   inline value_type operator[](int index) const;
429 
Inputs(ZoneNodePtr const * input_root,int count)430   explicit Inputs(ZoneNodePtr const* input_root, int count)
431       : input_root_(input_root), count_(count) {}
432 
433  private:
434   ZoneNodePtr const* input_root_;
435   int count_;
436 };
437 
438 // An encapsulation for information associated with a single use of node as a
439 // input from another node, allowing access to both the defining node and
440 // the node having the input.
441 class Edge final {
442  public:
from()443   Node* from() const { return use_->from(); }
to()444   Node* to() const { return *input_ptr_; }
index()445   int index() const {
446     int const index = use_->input_index();
447     DCHECK_LT(index, use_->from()->InputCount());
448     return index;
449   }
450 
451   bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; }
452   bool operator!=(const Edge& other) { return !(*this == other); }
453 
UpdateTo(Node * new_to)454   void UpdateTo(Node* new_to) {
455     Node* old_to = *input_ptr_;
456     if (old_to != new_to) {
457       if (old_to) old_to->RemoveUse(use_);
458       *input_ptr_ = new_to;
459       if (new_to) new_to->AppendUse(use_);
460     }
461   }
462 
463  private:
464   friend class Node::UseEdges::iterator;
465   friend class Node::InputEdges;
466   friend class Node::InputEdges::iterator;
467 
Edge(Node::Use * use,ZoneNodePtr * input_ptr)468   Edge(Node::Use* use, ZoneNodePtr* input_ptr)
469       : use_(use), input_ptr_(input_ptr) {
470     DCHECK_NOT_NULL(use);
471     DCHECK_NOT_NULL(input_ptr);
472     DCHECK_EQ(input_ptr, use->input_ptr());
473   }
474 
475   Node::Use* use_;
476   ZoneNodePtr* input_ptr_;
477 };
478 
IsDead()479 bool Node::IsDead() const {
480   Node::Inputs inputs = this->inputs();
481   return inputs.count() > 0 && inputs[0] == nullptr;
482 }
483 
input_edges()484 Node::InputEdges Node::input_edges() {
485   int inline_count = InlineCountField::decode(bit_field_);
486   if (inline_count != kOutlineMarker) {
487     return InputEdges(inline_inputs(), reinterpret_cast<Use*>(this) - 1,
488                       inline_count);
489   } else {
490     return InputEdges(outline_inputs()->inputs(),
491                       reinterpret_cast<Use*>(outline_inputs()) - 1,
492                       outline_inputs()->count_);
493   }
494 }
495 
inputs()496 Node::Inputs Node::inputs() const {
497   int inline_count = InlineCountField::decode(bit_field_);
498   if (inline_count != kOutlineMarker) {
499     return Inputs(inline_inputs(), inline_count);
500   } else {
501     return Inputs(outline_inputs()->inputs(), outline_inputs()->count_);
502   }
503 }
504 
505 // A forward iterator to visit the edges for the input dependencies of a node.
506 class Node::InputEdges::iterator final {
507  public:
508   using iterator_category = std::forward_iterator_tag;
509   using difference_type = std::ptrdiff_t;
510   using value_type = Edge;
511   using pointer = Edge*;
512   using reference = Edge&;
513 
iterator()514   iterator() : use_(nullptr), input_ptr_(nullptr) {}
515   iterator(const iterator& other) = default;
516 
517   Edge operator*() const { return Edge(use_, input_ptr_); }
518   bool operator==(const iterator& other) const {
519     return input_ptr_ == other.input_ptr_;
520   }
521   bool operator!=(const iterator& other) const { return !(*this == other); }
522   iterator& operator++() {
523     input_ptr_++;
524     use_--;
525     return *this;
526   }
527   iterator operator++(int);
528   iterator& operator+=(difference_type offset) {
529     input_ptr_ += offset;
530     use_ -= offset;
531     return *this;
532   }
533   iterator operator+(difference_type offset) const {
534     return iterator(use_ - offset, input_ptr_ + offset);
535   }
536   difference_type operator-(const iterator& other) const {
537     return input_ptr_ - other.input_ptr_;
538   }
539 
540  private:
541   friend class Node;
542 
iterator(Use * use,ZoneNodePtr * input_ptr)543   explicit iterator(Use* use, ZoneNodePtr* input_ptr)
544       : use_(use), input_ptr_(input_ptr) {}
545 
546   Use* use_;
547   ZoneNodePtr* input_ptr_;
548 };
549 
550 
begin()551 Node::InputEdges::iterator Node::InputEdges::begin() const {
552   return Node::InputEdges::iterator(use_root_, input_root_);
553 }
554 
555 
end()556 Node::InputEdges::iterator Node::InputEdges::end() const {
557   return Node::InputEdges::iterator(use_root_ - count_, input_root_ + count_);
558 }
559 
560 Edge Node::InputEdges::operator[](int index) const {
561   return Edge(use_root_ + index, input_root_ + index);
562 }
563 
564 // A forward iterator to visit the inputs of a node.
565 class Node::Inputs::const_iterator final {
566  public:
567   using iterator_category = std::forward_iterator_tag;
568   using difference_type = std::ptrdiff_t;
569   using value_type = Node*;
570   using pointer = const value_type*;
571   using reference = value_type&;
572 
573   const_iterator(const const_iterator& other) = default;
574 
575   Node* operator*() const { return *input_ptr_; }
576   bool operator==(const const_iterator& other) const {
577     return input_ptr_ == other.input_ptr_;
578   }
579   bool operator!=(const const_iterator& other) const {
580     return !(*this == other);
581   }
582   const_iterator& operator++() {
583     ++input_ptr_;
584     return *this;
585   }
586   const_iterator operator++(int);
587   const_iterator& operator+=(difference_type offset) {
588     input_ptr_ += offset;
589     return *this;
590   }
591   const_iterator operator+(difference_type offset) const {
592     return const_iterator(input_ptr_ + offset);
593   }
594   difference_type operator-(const const_iterator& other) const {
595     return input_ptr_ - other.input_ptr_;
596   }
597 
598  private:
599   friend class Node::Inputs;
600 
const_iterator(ZoneNodePtr const * input_ptr)601   explicit const_iterator(ZoneNodePtr const* input_ptr)
602       : input_ptr_(input_ptr) {}
603 
604   ZoneNodePtr const* input_ptr_;
605 };
606 
607 
begin()608 Node::Inputs::const_iterator Node::Inputs::begin() const {
609   return const_iterator(input_root_);
610 }
611 
612 
end()613 Node::Inputs::const_iterator Node::Inputs::end() const {
614   return const_iterator(input_root_ + count_);
615 }
616 
617 Node* Node::Inputs::operator[](int index) const { return input_root_[index]; }
618 
619 // A forward iterator to visit the uses edges of a node.
620 class Node::UseEdges::iterator final {
621  public:
622   iterator(const iterator& other) = default;
623 
624   Edge operator*() const { return Edge(current_, current_->input_ptr()); }
625   bool operator==(const iterator& other) const {
626     return current_ == other.current_;
627   }
628   bool operator!=(const iterator& other) const { return !(*this == other); }
629   iterator& operator++() {
630     DCHECK_NOT_NULL(current_);
631     current_ = next_;
632     next_ = current_ ? static_cast<Node::Use*>(current_->next) : nullptr;
633     return *this;
634   }
635   iterator operator++(int);
636 
637  private:
638   friend class Node::UseEdges;
639 
iterator()640   iterator() : current_(nullptr), next_(nullptr) {}
iterator(Node * node)641   explicit iterator(Node* node)
642       : current_(node->first_use_),
643         next_(current_ ? static_cast<Node::Use*>(current_->next) : nullptr) {}
644 
645   Node::Use* current_;
646   Node::Use* next_;
647 };
648 
649 
begin()650 Node::UseEdges::iterator Node::UseEdges::begin() const {
651   return Node::UseEdges::iterator(this->node_);
652 }
653 
654 
end()655 Node::UseEdges::iterator Node::UseEdges::end() const {
656   return Node::UseEdges::iterator();
657 }
658 
659 
660 // A forward iterator to visit the uses of a node.
661 class Node::Uses::const_iterator final {
662  public:
663   using iterator_category = std::forward_iterator_tag;
664   using difference_type = int;
665   using value_type = Node*;
666   using pointer = Node**;
667   using reference = Node*&;
668 
669   Node* operator*() const { return current_->from(); }
670   bool operator==(const const_iterator& other) const {
671     return other.current_ == current_;
672   }
673   bool operator!=(const const_iterator& other) const {
674     return other.current_ != current_;
675   }
676   const_iterator& operator++() {
677     DCHECK_NOT_NULL(current_);
678     // Checking no use gets mutated while iterating through them, a potential
679     // very tricky cause of bug.
680     current_ = current_->next;
681 #ifdef DEBUG
682     DCHECK_EQ(current_, next_);
683     next_ = current_ ? current_->next : nullptr;
684 #endif
685     return *this;
686   }
687   const_iterator operator++(int);
688 
689  private:
690   friend class Node::Uses;
691 
const_iterator()692   const_iterator() : current_(nullptr) {}
const_iterator(Node * node)693   explicit const_iterator(Node* node)
694       : current_(node->first_use_)
695 #ifdef DEBUG
696         ,
697         next_(current_ ? current_->next : nullptr)
698 #endif
699   {
700   }
701 
702   Node::Use* current_;
703 #ifdef DEBUG
704   Node::Use* next_;
705 #endif
706 };
707 
708 
begin()709 Node::Uses::const_iterator Node::Uses::begin() const {
710   return const_iterator(this->node_);
711 }
712 
713 
end()714 Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
715 
716 }  // namespace compiler
717 }  // namespace internal
718 }  // namespace v8
719 
720 #endif  // V8_COMPILER_NODE_H_
721