• 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   unsigned mask = 0;
318   for (Use* use = first_use_; use; use = use->next) {
319     if (use->from() == owner) {
320       mask |= 1;
321     } else {
322       return false;
323     }
324   }
325   return mask == 1;
326 }
327 
OwnedBy(Node const * owner1,Node const * owner2) const328 bool Node::OwnedBy(Node const* owner1, Node const* owner2) const {
329   unsigned mask = 0;
330   for (Use* use = first_use_; use; use = use->next) {
331     Node* from = use->from();
332     if (from == owner1) {
333       mask |= 1;
334     } else if (from == owner2) {
335       mask |= 2;
336     } else {
337       return false;
338     }
339   }
340   return mask == 3;
341 }
342 
Print(int depth) const343 void Node::Print(int depth) const {
344   StdoutStream os;
345   Print(os, depth);
346 }
347 
348 namespace {
PrintNode(const Node * node,std::ostream & os,int depth,int indentation=0)349 void PrintNode(const Node* node, std::ostream& os, int depth,
350                int indentation = 0) {
351   for (int i = 0; i < indentation; ++i) {
352     os << "  ";
353   }
354   if (node) {
355     os << *node;
356   } else {
357     os << "(NULL)";
358   }
359   os << std::endl;
360   if (depth <= 0) return;
361   for (Node* input : node->inputs()) {
362     PrintNode(input, os, depth - 1, indentation + 1);
363   }
364 }
365 }  // namespace
366 
Print(std::ostream & os,int depth) const367 void Node::Print(std::ostream& os, int depth) const {
368   PrintNode(this, os, depth);
369 }
370 
operator <<(std::ostream & os,const Node & n)371 std::ostream& operator<<(std::ostream& os, const Node& n) {
372   os << n.id() << ": " << *n.op();
373   if (n.InputCount() > 0) {
374     os << "(";
375     for (int i = 0; i < n.InputCount(); ++i) {
376       if (i != 0) os << ", ";
377       if (n.InputAt(i)) {
378         os << n.InputAt(i)->id();
379       } else {
380         os << "null";
381       }
382     }
383     os << ")";
384   }
385   return os;
386 }
387 
Node(NodeId id,const Operator * op,int inline_count,int inline_capacity)388 Node::Node(NodeId id, const Operator* op, int inline_count, int inline_capacity)
389     : op_(op),
390       mark_(0),
391       bit_field_(IdField::encode(id) | InlineCountField::encode(inline_count) |
392                  InlineCapacityField::encode(inline_capacity)),
393       first_use_(nullptr) {
394   // Check that the id didn't overflow.
395   STATIC_ASSERT(IdField::kMax < std::numeric_limits<NodeId>::max());
396   CHECK(IdField::is_valid(id));
397 
398   // Inputs must either be out of line or within the inline capacity.
399   DCHECK(inline_count == kOutlineMarker || inline_count <= inline_capacity);
400   DCHECK_LE(inline_capacity, kMaxInlineCapacity);
401 }
402 
403 
AppendUse(Use * use)404 void Node::AppendUse(Use* use) {
405   DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
406   DCHECK_EQ(this, *use->input_ptr());
407   use->next = first_use_;
408   use->prev = nullptr;
409   if (first_use_) first_use_->prev = use;
410   first_use_ = use;
411 }
412 
413 
RemoveUse(Use * use)414 void Node::RemoveUse(Use* use) {
415   DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
416   if (use->prev) {
417     DCHECK_NE(first_use_, use);
418     use->prev->next = use->next;
419   } else {
420     DCHECK_EQ(first_use_, use);
421     first_use_ = use->next;
422   }
423   if (use->next) {
424     use->next->prev = use->prev;
425   }
426 }
427 
428 
429 #if DEBUG
Verify()430 void Node::Verify() {
431   // Check basic validity of input data structures.
432   fflush(stdout);
433   int count = this->InputCount();
434   // Avoid quadratic explosion for mega nodes; only verify if the input
435   // count is less than 200 or is a round number of 100s.
436   if (count > 200 && count % 100) return;
437 
438   for (int i = 0; i < count; i++) {
439     DCHECK_EQ(i, this->GetUsePtr(i)->input_index());
440     DCHECK_EQ(this->GetInputPtr(i), this->GetUsePtr(i)->input_ptr());
441     DCHECK_EQ(count, this->InputCount());
442   }
443   {  // Direct input iteration.
444     int index = 0;
445     for (Node* input : this->inputs()) {
446       DCHECK_EQ(this->InputAt(index), input);
447       index++;
448     }
449     DCHECK_EQ(count, index);
450     DCHECK_EQ(this->InputCount(), index);
451   }
452   {  // Input edge iteration.
453     int index = 0;
454     for (Edge edge : this->input_edges()) {
455       DCHECK_EQ(edge.from(), this);
456       DCHECK_EQ(index, edge.index());
457       DCHECK_EQ(this->InputAt(index), edge.to());
458       index++;
459     }
460     DCHECK_EQ(count, index);
461     DCHECK_EQ(this->InputCount(), index);
462   }
463 }
464 #endif
465 
operator ++(int n)466 Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) {
467   iterator result(*this);
468   ++(*this);
469   return result;
470 }
471 
472 
operator ++(int n)473 Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
474   const_iterator result(*this);
475   ++(*this);
476   return result;
477 }
478 
479 
operator ++(int n)480 Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) {
481   iterator result(*this);
482   ++(*this);
483   return result;
484 }
485 
486 
empty() const487 bool Node::UseEdges::empty() const { return begin() == end(); }
488 
489 
operator ++(int n)490 Node::Uses::const_iterator Node::Uses::const_iterator::operator++(int n) {
491   const_iterator result(*this);
492   ++(*this);
493   return result;
494 }
495 
496 
empty() const497 bool Node::Uses::empty() const { return begin() == end(); }
498 
499 }  // namespace compiler
500 }  // namespace internal
501 }  // namespace v8
502