• 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 #include "src/compiler/node.h"
6 
7 namespace v8 {
8 namespace internal {
9 namespace compiler {
10 
New(Zone * zone,int capacity)11 Node::OutOfLineInputs* Node::OutOfLineInputs::New(Zone* zone, int capacity) {
12   size_t size =
13       sizeof(OutOfLineInputs) + capacity * (sizeof(Node*) + sizeof(Use));
14   intptr_t raw_buffer =
15       reinterpret_cast<intptr_t>(zone->Allocate<Node::OutOfLineInputs>(size));
16   Node::OutOfLineInputs* outline =
17       reinterpret_cast<OutOfLineInputs*>(raw_buffer + capacity * sizeof(Use));
18   outline->capacity_ = capacity;
19   outline->count_ = 0;
20   return outline;
21 }
22 
ExtractFrom(Use * old_use_ptr,ZoneNodePtr * old_input_ptr,int count)23 void Node::OutOfLineInputs::ExtractFrom(Use* old_use_ptr,
24                                         ZoneNodePtr* old_input_ptr, int count) {
25   DCHECK_GE(count, 0);
26   // Extract the inputs from the old use and input pointers and copy them
27   // to this out-of-line-storage.
28   Use* new_use_ptr = reinterpret_cast<Use*>(this) - 1;
29   ZoneNodePtr* new_input_ptr = inputs();
30   CHECK_IMPLIES(count > 0, Use::InputIndexField::is_valid(count - 1));
31   for (int current = 0; current < count; current++) {
32     new_use_ptr->bit_field_ =
33         Use::InputIndexField::encode(current) | Use::InlineField::encode(false);
34     DCHECK_EQ(old_input_ptr, old_use_ptr->input_ptr());
35     DCHECK_EQ(new_input_ptr, new_use_ptr->input_ptr());
36     Node* old_to = *old_input_ptr;
37     if (old_to) {
38       *old_input_ptr = nullptr;
39       old_to->RemoveUse(old_use_ptr);
40       *new_input_ptr = old_to;
41       old_to->AppendUse(new_use_ptr);
42     } else {
43       *new_input_ptr = nullptr;
44     }
45     old_input_ptr++;
46     new_input_ptr++;
47     old_use_ptr--;
48     new_use_ptr--;
49   }
50   this->count_ = count;
51 }
52 
53 // These structs are just type tags for Zone::Allocate<T>(size_t) calls.
54 struct NodeWithOutOfLineInputs {};
55 struct NodeWithInLineInputs {};
56 
57 template <typename NodePtrT>
NewImpl(Zone * zone,NodeId id,const Operator * op,int input_count,NodePtrT const * inputs,bool has_extensible_inputs)58 Node* Node::NewImpl(Zone* zone, NodeId id, const Operator* op, int input_count,
59                     NodePtrT const* inputs, bool has_extensible_inputs) {
60   // Node uses compressed pointers, so zone must support pointer compression.
61   DCHECK_IMPLIES(kCompressGraphZone, zone->supports_compression());
62   DCHECK_GE(input_count, 0);
63 
64   ZoneNodePtr* input_ptr;
65   Use* use_ptr;
66   Node* node;
67   bool is_inline;
68 
69   // Verify that none of the inputs are {nullptr}.
70   for (int i = 0; i < input_count; i++) {
71     if (inputs[i] == nullptr) {
72       FATAL("Node::New() Error: #%d:%s[%d] is nullptr", static_cast<int>(id),
73             op->mnemonic(), i);
74     }
75   }
76 
77   if (input_count > kMaxInlineCapacity) {
78     // Allocate out-of-line inputs.
79     int capacity =
80         has_extensible_inputs ? input_count + kMaxInlineCapacity : input_count;
81     OutOfLineInputs* outline = OutOfLineInputs::New(zone, capacity);
82 
83     // Allocate node, with space for OutOfLineInputs pointer.
84     void* node_buffer = zone->Allocate<NodeWithOutOfLineInputs>(
85         sizeof(Node) + sizeof(ZoneOutOfLineInputsPtr));
86     node = new (node_buffer) Node(id, op, kOutlineMarker, 0);
87     node->set_outline_inputs(outline);
88 
89     outline->node_ = node;
90     outline->count_ = input_count;
91 
92     input_ptr = outline->inputs();
93     use_ptr = reinterpret_cast<Use*>(outline);
94     is_inline = false;
95   } else {
96     // Allocate node with inline inputs. Capacity must be at least 1 so that
97     // an OutOfLineInputs pointer can be stored when inputs are added later.
98     int capacity = std::max(1, input_count);
99     if (has_extensible_inputs) {
100       const int max = kMaxInlineCapacity;
101       capacity = std::min(input_count + 3, max);
102     }
103 
104     size_t size = sizeof(Node) + capacity * (sizeof(ZoneNodePtr) + sizeof(Use));
105     intptr_t raw_buffer =
106         reinterpret_cast<intptr_t>(zone->Allocate<NodeWithInLineInputs>(size));
107     void* node_buffer =
108         reinterpret_cast<void*>(raw_buffer + capacity * sizeof(Use));
109 
110     node = new (node_buffer) Node(id, op, input_count, capacity);
111     input_ptr = node->inline_inputs();
112     use_ptr = reinterpret_cast<Use*>(node);
113     is_inline = true;
114   }
115 
116   // Initialize the input pointers and the uses.
117   CHECK_IMPLIES(input_count > 0,
118                 Use::InputIndexField::is_valid(input_count - 1));
119   for (int current = 0; current < input_count; ++current) {
120     Node* to = *inputs++;
121     input_ptr[current] = to;
122     Use* use = use_ptr - 1 - current;
123     use->bit_field_ = Use::InputIndexField::encode(current) |
124                       Use::InlineField::encode(is_inline);
125     to->AppendUse(use);
126   }
127   node->Verify();
128   return node;
129 }
130 
New(Zone * zone,NodeId id,const Operator * op,int input_count,Node * const * inputs,bool has_extensible_inputs)131 Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
132                 Node* const* inputs, bool has_extensible_inputs) {
133   return NewImpl(zone, id, op, input_count, inputs, has_extensible_inputs);
134 }
135 
Clone(Zone * zone,NodeId id,const Node * node)136 Node* Node::Clone(Zone* zone, NodeId id, const Node* node) {
137   int const input_count = node->InputCount();
138   ZoneNodePtr const* const inputs = node->has_inline_inputs()
139                                         ? node->inline_inputs()
140                                         : node->outline_inputs()->inputs();
141   Node* const clone = NewImpl(zone, id, node->op(), input_count, inputs, false);
142   clone->set_type(node->type());
143   return clone;
144 }
145 
146 
Kill()147 void Node::Kill() {
148   DCHECK_NOT_NULL(op());
149   NullAllInputs();
150   DCHECK(uses().empty());
151 }
152 
153 
AppendInput(Zone * zone,Node * new_to)154 void Node::AppendInput(Zone* zone, Node* new_to) {
155   DCHECK_NOT_NULL(zone);
156   DCHECK_NOT_NULL(new_to);
157 
158   int const inline_count = InlineCountField::decode(bit_field_);
159   int const inline_capacity = InlineCapacityField::decode(bit_field_);
160   if (inline_count < inline_capacity) {
161     // Append inline input.
162     bit_field_ = InlineCountField::update(bit_field_, inline_count + 1);
163     *GetInputPtr(inline_count) = new_to;
164     Use* use = GetUsePtr(inline_count);
165     STATIC_ASSERT(InlineCapacityField::kMax <= Use::InputIndexField::kMax);
166     use->bit_field_ = Use::InputIndexField::encode(inline_count) |
167                       Use::InlineField::encode(true);
168     new_to->AppendUse(use);
169   } else {
170     // Append out-of-line input.
171     int const input_count = InputCount();
172     OutOfLineInputs* outline = nullptr;
173     if (inline_count != kOutlineMarker) {
174       // switch to out of line inputs.
175       outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
176       outline->node_ = this;
177       outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
178       bit_field_ = InlineCountField::update(bit_field_, kOutlineMarker);
179       set_outline_inputs(outline);
180     } else {
181       // use current out of line inputs.
182       outline = outline_inputs();
183       if (input_count >= outline->capacity_) {
184         // out of space in out-of-line inputs.
185         outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
186         outline->node_ = this;
187         outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
188         set_outline_inputs(outline);
189       }
190     }
191     outline->count_++;
192     *GetInputPtr(input_count) = new_to;
193     Use* use = GetUsePtr(input_count);
194     CHECK(Use::InputIndexField::is_valid(input_count));
195     use->bit_field_ = Use::InputIndexField::encode(input_count) |
196                       Use::InlineField::encode(false);
197     new_to->AppendUse(use);
198   }
199   Verify();
200 }
201 
202 
InsertInput(Zone * zone,int index,Node * new_to)203 void Node::InsertInput(Zone* zone, int index, Node* new_to) {
204   DCHECK_NOT_NULL(zone);
205   DCHECK_LE(0, index);
206   DCHECK_LT(index, InputCount());
207   AppendInput(zone, InputAt(InputCount() - 1));
208   for (int i = InputCount() - 1; i > index; --i) {
209     ReplaceInput(i, InputAt(i - 1));
210   }
211   ReplaceInput(index, new_to);
212   Verify();
213 }
214 
InsertInputs(Zone * zone,int index,int count)215 void Node::InsertInputs(Zone* zone, int index, int count) {
216   DCHECK_NOT_NULL(zone);
217   DCHECK_LE(0, index);
218   DCHECK_LT(0, count);
219   DCHECK_LT(index, InputCount());
220   for (int i = 0; i < count; i++) {
221     AppendInput(zone, InputAt(std::max(InputCount() - count, 0)));
222   }
223   for (int i = InputCount() - count - 1; i >= std::max(index, count); --i) {
224     ReplaceInput(i, InputAt(i - count));
225   }
226   for (int i = 0; i < count; i++) {
227     ReplaceInput(index + i, nullptr);
228   }
229   Verify();
230 }
231 
RemoveInput(int index)232 Node* Node::RemoveInput(int index) {
233   DCHECK_LE(0, index);
234   DCHECK_LT(index, InputCount());
235   Node* result = InputAt(index);
236   for (; index < InputCount() - 1; ++index) {
237     ReplaceInput(index, InputAt(index + 1));
238   }
239   TrimInputCount(InputCount() - 1);
240   Verify();
241   return result;
242 }
243 
ClearInputs(int start,int count)244 void Node::ClearInputs(int start, int count) {
245   ZoneNodePtr* input_ptr = GetInputPtr(start);
246   Use* use_ptr = GetUsePtr(start);
247   while (count-- > 0) {
248     DCHECK_EQ(input_ptr, use_ptr->input_ptr());
249     Node* input = *input_ptr;
250     *input_ptr = nullptr;
251     if (input) input->RemoveUse(use_ptr);
252     input_ptr++;
253     use_ptr--;
254   }
255   Verify();
256 }
257 
258 
NullAllInputs()259 void Node::NullAllInputs() { ClearInputs(0, InputCount()); }
260 
261 
TrimInputCount(int new_input_count)262 void Node::TrimInputCount(int new_input_count) {
263   int current_count = InputCount();
264   DCHECK_LE(new_input_count, current_count);
265   if (new_input_count == current_count) return;  // Nothing to do.
266   ClearInputs(new_input_count, current_count - new_input_count);
267   if (has_inline_inputs()) {
268     bit_field_ = InlineCountField::update(bit_field_, new_input_count);
269   } else {
270     outline_inputs()->count_ = new_input_count;
271   }
272 }
273 
EnsureInputCount(Zone * zone,int new_input_count)274 void Node::EnsureInputCount(Zone* zone, int new_input_count) {
275   int current_count = InputCount();
276   DCHECK_NE(current_count, 0);
277   if (current_count > new_input_count) {
278     TrimInputCount(new_input_count);
279   } else if (current_count < new_input_count) {
280     Node* dummy = InputAt(current_count - 1);
281     do {
282       AppendInput(zone, dummy);
283       current_count++;
284     } while (current_count < new_input_count);
285   }
286 }
287 
UseCount() const288 int Node::UseCount() const {
289   int use_count = 0;
290   for (const Use* use = first_use_; use; use = use->next) {
291     ++use_count;
292   }
293   return use_count;
294 }
295 
296 
ReplaceUses(Node * that)297 void Node::ReplaceUses(Node* that) {
298   DCHECK(this->first_use_ == nullptr || this->first_use_->prev == nullptr);
299   DCHECK(that->first_use_ == nullptr || that->first_use_->prev == nullptr);
300 
301   // Update the pointers to {this} to point to {that}.
302   Use* last_use = nullptr;
303   for (Use* use = this->first_use_; use; use = use->next) {
304     *use->input_ptr() = that;
305     last_use = use;
306   }
307   if (last_use) {
308     // Concat the use list of {this} and {that}.
309     last_use->next = that->first_use_;
310     if (that->first_use_) that->first_use_->prev = last_use;
311     that->first_use_ = this->first_use_;
312   }
313   first_use_ = nullptr;
314 }
315 
OwnedBy(Node const * owner) const316 bool Node::OwnedBy(Node const* owner) const {
317   for (Use* use = first_use_; use; use = use->next) {
318     if (use->from() != owner) {
319       return false;
320     }
321   }
322   return first_use_ != nullptr;
323 }
324 
OwnedBy(Node const * owner1,Node const * owner2) const325 bool Node::OwnedBy(Node const* owner1, Node const* owner2) const {
326   unsigned mask = 0;
327   for (Use* use = first_use_; use; use = use->next) {
328     Node* from = use->from();
329     if (from == owner1) {
330       mask |= 1;
331     } else if (from == owner2) {
332       mask |= 2;
333     } else {
334       return false;
335     }
336   }
337   return mask == 3;
338 }
339 
Print(int depth) const340 void Node::Print(int depth) const {
341   StdoutStream os;
342   Print(os, depth);
343 }
344 
345 namespace {
PrintNode(const Node * node,std::ostream & os,int depth,int indentation=0)346 void PrintNode(const Node* node, std::ostream& os, int depth,
347                int indentation = 0) {
348   for (int i = 0; i < indentation; ++i) {
349     os << "  ";
350   }
351   if (node) {
352     os << *node;
353   } else {
354     os << "(NULL)";
355   }
356   os << std::endl;
357   if (depth <= 0) return;
358   for (Node* input : node->inputs()) {
359     PrintNode(input, os, depth - 1, indentation + 1);
360   }
361 }
362 }  // namespace
363 
Print(std::ostream & os,int depth) const364 void Node::Print(std::ostream& os, int depth) const {
365   PrintNode(this, os, depth);
366 }
367 
operator <<(std::ostream & os,const Node & n)368 std::ostream& operator<<(std::ostream& os, const Node& n) {
369   os << n.id() << ": " << *n.op();
370   if (n.InputCount() > 0) {
371     os << "(";
372     for (int i = 0; i < n.InputCount(); ++i) {
373       if (i != 0) os << ", ";
374       if (n.InputAt(i)) {
375         os << n.InputAt(i)->id();
376       } else {
377         os << "null";
378       }
379     }
380     os << ")";
381   }
382   return os;
383 }
384 
Node(NodeId id,const Operator * op,int inline_count,int inline_capacity)385 Node::Node(NodeId id, const Operator* op, int inline_count, int inline_capacity)
386     : op_(op),
387       mark_(0),
388       bit_field_(IdField::encode(id) | InlineCountField::encode(inline_count) |
389                  InlineCapacityField::encode(inline_capacity)),
390       first_use_(nullptr) {
391   // Check that the id didn't overflow.
392   STATIC_ASSERT(IdField::kMax < std::numeric_limits<NodeId>::max());
393   CHECK(IdField::is_valid(id));
394 
395   // Inputs must either be out of line or within the inline capacity.
396   DCHECK(inline_count == kOutlineMarker || inline_count <= inline_capacity);
397   DCHECK_LE(inline_capacity, kMaxInlineCapacity);
398 }
399 
400 
AppendUse(Use * use)401 void Node::AppendUse(Use* use) {
402   DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
403   DCHECK_EQ(this, *use->input_ptr());
404   use->next = first_use_;
405   use->prev = nullptr;
406   if (first_use_) first_use_->prev = use;
407   first_use_ = use;
408 }
409 
410 
RemoveUse(Use * use)411 void Node::RemoveUse(Use* use) {
412   DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
413   if (use->prev) {
414     DCHECK_NE(first_use_, use);
415     use->prev->next = use->next;
416   } else {
417     DCHECK_EQ(first_use_, use);
418     first_use_ = use->next;
419   }
420   if (use->next) {
421     use->next->prev = use->prev;
422   }
423 }
424 
425 
426 #if DEBUG
Verify()427 void Node::Verify() {
428   // Check basic validity of input data structures.
429   fflush(stdout);
430   int count = this->InputCount();
431   // Avoid quadratic explosion for mega nodes; only verify if the input
432   // count is less than 200 or is a round number of 100s.
433   if (count > 200 && count % 100) return;
434 
435   for (int i = 0; i < count; i++) {
436     DCHECK_EQ(i, this->GetUsePtr(i)->input_index());
437     DCHECK_EQ(this->GetInputPtr(i), this->GetUsePtr(i)->input_ptr());
438     DCHECK_EQ(count, this->InputCount());
439   }
440   {  // Direct input iteration.
441     int index = 0;
442     for (Node* input : this->inputs()) {
443       DCHECK_EQ(this->InputAt(index), input);
444       index++;
445     }
446     DCHECK_EQ(count, index);
447     DCHECK_EQ(this->InputCount(), index);
448   }
449   {  // Input edge iteration.
450     int index = 0;
451     for (Edge edge : this->input_edges()) {
452       DCHECK_EQ(edge.from(), this);
453       DCHECK_EQ(index, edge.index());
454       DCHECK_EQ(this->InputAt(index), edge.to());
455       index++;
456     }
457     DCHECK_EQ(count, index);
458     DCHECK_EQ(this->InputCount(), index);
459   }
460 }
461 #endif
462 
operator ++(int n)463 Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) {
464   iterator result(*this);
465   ++(*this);
466   return result;
467 }
468 
469 
operator ++(int n)470 Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
471   const_iterator result(*this);
472   ++(*this);
473   return result;
474 }
475 
476 
operator ++(int n)477 Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) {
478   iterator result(*this);
479   ++(*this);
480   return result;
481 }
482 
483 
empty() const484 bool Node::UseEdges::empty() const { return begin() == end(); }
485 
486 
operator ++(int n)487 Node::Uses::const_iterator Node::Uses::const_iterator::operator++(int n) {
488   const_iterator result(*this);
489   ++(*this);
490   return result;
491 }
492 
493 
empty() const494 bool Node::Uses::empty() const { return begin() == end(); }
495 
496 }  // namespace compiler
497 }  // namespace internal
498 }  // namespace v8
499 
_v8_internal_Node_Print(void * object)500 V8_EXPORT_PRIVATE extern void _v8_internal_Node_Print(void* object) {
501   reinterpret_cast<i::compiler::Node*>(object)->Print();
502 }
503