OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_COMPILER_NODE_H_ | 5 #ifndef V8_COMPILER_NODE_H_ |
6 #define V8_COMPILER_NODE_H_ | 6 #define V8_COMPILER_NODE_H_ |
7 | 7 |
8 #include <deque> | 8 #include <deque> |
9 #include <set> | 9 #include <set> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "src/v8.h" | 12 #include "src/v8.h" |
13 | 13 |
14 #include "src/compiler/opcodes.h" | 14 #include "src/compiler/opcodes.h" |
15 #include "src/compiler/operator.h" | 15 #include "src/compiler/operator.h" |
16 #include "src/types.h" | 16 #include "src/types.h" |
17 #include "src/zone.h" | 17 #include "src/zone.h" |
18 #include "src/zone-allocator.h" | 18 #include "src/zone-allocator.h" |
19 #include "src/zone-containers.h" | 19 #include "src/zone-containers.h" |
20 | 20 |
21 namespace v8 { | 21 namespace v8 { |
22 namespace internal { | 22 namespace internal { |
23 namespace compiler { | 23 namespace compiler { |
24 | 24 |
| 25 // Forward declarations. |
25 class Edge; | 26 class Edge; |
26 class Graph; | 27 class Graph; |
27 | 28 |
| 29 |
28 // Marks are used during traversal of the graph to distinguish states of nodes. | 30 // Marks are used during traversal of the graph to distinguish states of nodes. |
29 // Each node has a mark which is a monotonically increasing integer, and a | 31 // Each node has a mark which is a monotonically increasing integer, and a |
30 // {NodeMarker} has a range of values that indicate states of a node. | 32 // {NodeMarker} has a range of values that indicate states of a node. |
31 typedef uint32_t Mark; | 33 typedef uint32_t Mark; |
32 | 34 |
33 // NodeIds are identifying numbers for nodes that can be used to index auxiliary | 35 // NodeIds are identifying numbers for nodes that can be used to index auxiliary |
34 // out-of-line data associated with each node. | 36 // out-of-line data associated with each node. |
35 typedef int NodeId; | 37 typedef int NodeId; |
36 | 38 |
37 // A Node is the basic primitive of graphs. Nodes are chained together by | 39 // A Node is the basic primitive of graphs. Nodes are chained together by |
(...skipping 21 matching lines...) Expand all Loading... |
59 const Operator* op() const { return op_; } | 61 const Operator* op() const { return op_; } |
60 void set_op(const Operator* op) { op_ = op; } | 62 void set_op(const Operator* op) { op_ = op; } |
61 | 63 |
62 IrOpcode::Value opcode() const { | 64 IrOpcode::Value opcode() const { |
63 DCHECK(op_->opcode() <= IrOpcode::kLast); | 65 DCHECK(op_->opcode() <= IrOpcode::kLast); |
64 return static_cast<IrOpcode::Value>(op_->opcode()); | 66 return static_cast<IrOpcode::Value>(op_->opcode()); |
65 } | 67 } |
66 | 68 |
67 NodeId id() const { return id_; } | 69 NodeId id() const { return id_; } |
68 | 70 |
69 int InputCount() const { return input_count_; } | 71 int InputCount() const { return input_count(); } |
70 Node* InputAt(int index) const { return GetInputRecordPtr(index)->to; } | 72 Node* InputAt(int index) const { return GetInputRecordPtr(index)->to; } |
71 inline void ReplaceInput(int index, Node* new_input); | 73 inline void ReplaceInput(int index, Node* new_input); |
72 inline void AppendInput(Zone* zone, Node* new_input); | 74 inline void AppendInput(Zone* zone, Node* new_input); |
73 inline void InsertInput(Zone* zone, int index, Node* new_input); | 75 inline void InsertInput(Zone* zone, int index, Node* new_input); |
74 inline void RemoveInput(int index); | 76 inline void RemoveInput(int index); |
75 | 77 |
76 int UseCount() { return use_count_; } | 78 int UseCount() const; |
77 Node* UseAt(int index) { | 79 Node* UseAt(int index) const; |
78 DCHECK(index < use_count_); | |
79 Use* current = first_use_; | |
80 while (index-- != 0) { | |
81 current = current->next; | |
82 } | |
83 return current->from; | |
84 } | |
85 inline void ReplaceUses(Node* replace_to); | 80 inline void ReplaceUses(Node* replace_to); |
86 template <class UnaryPredicate> | 81 template <class UnaryPredicate> |
87 inline void ReplaceUsesIf(UnaryPredicate pred, Node* replace_to); | 82 inline void ReplaceUsesIf(UnaryPredicate pred, Node* replace_to); |
88 inline void RemoveAllInputs(); | 83 inline void RemoveAllInputs(); |
89 | 84 |
90 inline void TrimInputCount(int input_count); | 85 inline void TrimInputCount(int input_count); |
91 | 86 |
92 class InputEdges { | 87 class InputEdges { |
93 public: | 88 public: |
94 class iterator; | 89 class iterator; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 public: | 163 public: |
169 Node* to; | 164 Node* to; |
170 Use* use; | 165 Use* use; |
171 | 166 |
172 void Update(Node* new_to); | 167 void Update(Node* new_to); |
173 }; | 168 }; |
174 | 169 |
175 void EnsureAppendableInputs(Zone* zone); | 170 void EnsureAppendableInputs(Zone* zone); |
176 | 171 |
177 Input* GetInputRecordPtr(int index) const { | 172 Input* GetInputRecordPtr(int index) const { |
178 if (has_appendable_inputs_) { | 173 if (has_appendable_inputs()) { |
179 return &((*inputs_.appendable_)[index]); | 174 return &((*inputs_.appendable_)[index]); |
180 } else { | 175 } else { |
181 return inputs_.static_ + index; | 176 return &inputs_.static_[index]; |
182 } | 177 } |
183 } | 178 } |
184 | 179 |
185 inline void AppendUse(Use* use); | 180 inline void AppendUse(Use* use); |
186 inline void RemoveUse(Use* use); | 181 inline void RemoveUse(Use* use); |
187 | 182 |
188 void* operator new(size_t, void* location) { return location; } | 183 void* operator new(size_t, void* location) { return location; } |
189 | 184 |
190 private: | 185 private: |
191 Node(Graph* graph, int input_count, int reserve_input_count); | 186 inline Node(NodeId id, int input_count, int reserve_input_count); |
192 | 187 |
193 typedef ZoneDeque<Input> InputDeque; | 188 typedef ZoneDeque<Input> InputDeque; |
194 | 189 |
195 friend class NodeProperties; | 190 friend class NodeProperties; |
196 template <typename State> | 191 template <typename State> |
197 friend class NodeMarker; | 192 friend class NodeMarker; |
198 | 193 |
199 // Only NodeProperties should manipulate the bounds. | 194 // Only NodeProperties should manipulate the bounds. |
200 Bounds bounds() { return bounds_; } | 195 Bounds bounds() { return bounds_; } |
201 void set_bounds(Bounds b) { bounds_ = b; } | 196 void set_bounds(Bounds b) { bounds_ = b; } |
202 | 197 |
203 // Only NodeMarkers should manipulate the marks on nodes. | 198 // Only NodeMarkers should manipulate the marks on nodes. |
204 Mark mark() { return mark_; } | 199 Mark mark() { return mark_; } |
205 void set_mark(Mark mark) { mark_ = mark; } | 200 void set_mark(Mark mark) { mark_ = mark; } |
206 | 201 |
207 static const int kReservedInputCountBits = 2; | 202 int input_count() const { return InputCountField::decode(bit_field_); } |
208 static const int kMaxReservedInputs = (1 << kReservedInputCountBits) - 1; | 203 void set_input_count(int input_count) { |
209 static const int kDefaultReservedInputs = kMaxReservedInputs; | 204 DCHECK_LE(0, input_count); |
| 205 bit_field_ = InputCountField::update(bit_field_, input_count); |
| 206 } |
| 207 |
| 208 int reserved_input_count() const { |
| 209 return ReservedInputCountField::decode(bit_field_); |
| 210 } |
| 211 void set_reserved_input_count(int reserved_input_count) { |
| 212 DCHECK_LE(0, reserved_input_count); |
| 213 bit_field_ = |
| 214 ReservedInputCountField::update(bit_field_, reserved_input_count); |
| 215 } |
| 216 |
| 217 bool has_appendable_inputs() const { |
| 218 return HasAppendableInputsField::decode(bit_field_); |
| 219 } |
| 220 void set_has_appendable_inputs(bool has_appendable_inputs) { |
| 221 bit_field_ = |
| 222 HasAppendableInputsField::update(bit_field_, has_appendable_inputs); |
| 223 } |
| 224 |
| 225 typedef BitField<unsigned, 0, 29> InputCountField; |
| 226 typedef BitField<unsigned, 29, 2> ReservedInputCountField; |
| 227 typedef BitField<unsigned, 31, 1> HasAppendableInputsField; |
| 228 static const int kDefaultReservedInputs = ReservedInputCountField::kMax; |
210 | 229 |
211 const Operator* op_; | 230 const Operator* op_; |
212 Bounds bounds_; | 231 Bounds bounds_; |
213 Mark mark_; | 232 Mark mark_; |
214 NodeId id_; | 233 NodeId id_; |
215 int input_count_ : 29; | 234 unsigned bit_field_; |
216 unsigned int reserve_input_count_ : kReservedInputCountBits; | |
217 bool has_appendable_inputs_ : 1; | |
218 union { | 235 union { |
219 // When a node is initially allocated, it uses a static buffer to hold its | 236 // When a node is initially allocated, it uses a static buffer to hold its |
220 // inputs under the assumption that the number of outputs will not increase. | 237 // inputs under the assumption that the number of outputs will not increase. |
221 // When the first input is appended, the static buffer is converted into a | 238 // When the first input is appended, the static buffer is converted into a |
222 // deque to allow for space-efficient growing. | 239 // deque to allow for space-efficient growing. |
223 Input* static_; | 240 Input* static_; |
224 InputDeque* appendable_; | 241 InputDeque* appendable_; |
225 } inputs_; | 242 } inputs_; |
226 int use_count_; | |
227 Use* first_use_; | 243 Use* first_use_; |
228 Use* last_use_; | 244 Use* last_use_; |
229 | 245 |
230 DISALLOW_COPY_AND_ASSIGN(Node); | 246 DISALLOW_COPY_AND_ASSIGN(Node); |
231 }; | 247 }; |
232 | 248 |
233 | 249 |
234 // An encapsulation for information associated with a single use of node as a | 250 // An encapsulation for information associated with a single use of node as a |
235 // input from another node, allowing access to both the defining node and | 251 // input from another node, allowing access to both the defining node and |
236 // the node having the input. | 252 // the node having the input. |
237 class Edge { | 253 class Edge { |
238 public: | 254 public: |
239 Node* from() const { return input_->use->from; } | 255 Node* from() const { return input_->use->from; } |
240 Node* to() const { return input_->to; } | 256 Node* to() const { return input_->to; } |
241 int index() const { | 257 int index() const { |
242 int index = input_->use->input_index; | 258 int index = input_->use->input_index; |
243 DCHECK(index < input_->use->from->input_count_); | 259 DCHECK(index < input_->use->from->input_count()); |
244 return index; | 260 return index; |
245 } | 261 } |
246 | 262 |
247 bool operator==(const Edge& other) { return input_ == other.input_; } | 263 bool operator==(const Edge& other) { return input_ == other.input_; } |
248 bool operator!=(const Edge& other) { return !(*this == other); } | 264 bool operator!=(const Edge& other) { return !(*this == other); } |
249 | 265 |
250 void UpdateTo(Node* new_to) { input_->Update(new_to); } | 266 void UpdateTo(Node* new_to) { input_->Update(new_to); } |
251 | 267 |
252 private: | 268 private: |
253 friend class Node::Uses::iterator; | 269 friend class Node::Uses::iterator; |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 if (replace_to->last_use_ == NULL) { | 509 if (replace_to->last_use_ == NULL) { |
494 DCHECK_EQ(NULL, replace_to->first_use_); | 510 DCHECK_EQ(NULL, replace_to->first_use_); |
495 replace_to->first_use_ = first_use_; | 511 replace_to->first_use_ = first_use_; |
496 replace_to->last_use_ = last_use_; | 512 replace_to->last_use_ = last_use_; |
497 } else if (first_use_ != NULL) { | 513 } else if (first_use_ != NULL) { |
498 DCHECK_NE(NULL, replace_to->first_use_); | 514 DCHECK_NE(NULL, replace_to->first_use_); |
499 replace_to->last_use_->next = first_use_; | 515 replace_to->last_use_->next = first_use_; |
500 first_use_->prev = replace_to->last_use_; | 516 first_use_->prev = replace_to->last_use_; |
501 replace_to->last_use_ = last_use_; | 517 replace_to->last_use_ = last_use_; |
502 } | 518 } |
503 replace_to->use_count_ += use_count_; | |
504 use_count_ = 0; | |
505 first_use_ = NULL; | 519 first_use_ = NULL; |
506 last_use_ = NULL; | 520 last_use_ = NULL; |
507 } | 521 } |
508 | 522 |
509 template <class UnaryPredicate> | 523 template <class UnaryPredicate> |
510 inline void Node::ReplaceUsesIf(UnaryPredicate pred, Node* replace_to) { | 524 inline void Node::ReplaceUsesIf(UnaryPredicate pred, Node* replace_to) { |
511 for (Use* use = first_use_; use != NULL;) { | 525 for (Use* use = first_use_; use != NULL;) { |
512 Use* next = use->next; | 526 Use* next = use->next; |
513 if (pred(use->from)) { | 527 if (pred(use->from)) { |
514 RemoveUse(use); | 528 RemoveUse(use); |
515 replace_to->AppendUse(use); | 529 replace_to->AppendUse(use); |
516 use->from->GetInputRecordPtr(use->input_index)->to = replace_to; | 530 use->from->GetInputRecordPtr(use->input_index)->to = replace_to; |
517 } | 531 } |
518 use = next; | 532 use = next; |
519 } | 533 } |
520 } | 534 } |
521 | 535 |
522 inline void Node::RemoveAllInputs() { | 536 inline void Node::RemoveAllInputs() { |
523 for (Edge edge : input_edges()) { | 537 for (Edge edge : input_edges()) { |
524 edge.UpdateTo(NULL); | 538 edge.UpdateTo(NULL); |
525 } | 539 } |
526 } | 540 } |
527 | 541 |
528 inline void Node::TrimInputCount(int new_input_count) { | 542 inline void Node::TrimInputCount(int new_input_count) { |
529 if (new_input_count == input_count_) return; // Nothing to do. | 543 if (new_input_count == input_count()) return; // Nothing to do. |
530 | 544 |
531 DCHECK(new_input_count < input_count_); | 545 DCHECK(new_input_count < input_count()); |
532 | 546 |
533 // Update inline inputs. | 547 // Update inline inputs. |
534 for (int i = new_input_count; i < input_count_; i++) { | 548 for (int i = new_input_count; i < input_count(); i++) { |
535 Node::Input* input = GetInputRecordPtr(i); | 549 Node::Input* input = GetInputRecordPtr(i); |
536 input->Update(NULL); | 550 input->Update(NULL); |
537 } | 551 } |
538 input_count_ = new_input_count; | 552 set_input_count(new_input_count); |
539 } | 553 } |
540 | 554 |
541 inline void Node::ReplaceInput(int index, Node* new_to) { | 555 inline void Node::ReplaceInput(int index, Node* new_to) { |
542 Input* input = GetInputRecordPtr(index); | 556 Input* input = GetInputRecordPtr(index); |
543 input->Update(new_to); | 557 input->Update(new_to); |
544 } | 558 } |
545 | 559 |
546 inline void Node::Input::Update(Node* new_to) { | 560 inline void Node::Input::Update(Node* new_to) { |
547 Node* old_to = this->to; | 561 Node* old_to = this->to; |
548 if (new_to == old_to) return; // Nothing to do. | 562 if (new_to == old_to) return; // Nothing to do. |
549 // Snip out the use from where it used to be | 563 // Snip out the use from where it used to be |
550 if (old_to != NULL) { | 564 if (old_to != NULL) { |
551 old_to->RemoveUse(use); | 565 old_to->RemoveUse(use); |
552 } | 566 } |
553 to = new_to; | 567 to = new_to; |
554 // And put it into the new node's use list. | 568 // And put it into the new node's use list. |
555 if (new_to != NULL) { | 569 if (new_to != NULL) { |
556 new_to->AppendUse(use); | 570 new_to->AppendUse(use); |
557 } else { | 571 } else { |
558 use->next = NULL; | 572 use->next = NULL; |
559 use->prev = NULL; | 573 use->prev = NULL; |
560 } | 574 } |
561 } | 575 } |
562 | 576 |
563 inline void Node::EnsureAppendableInputs(Zone* zone) { | 577 inline void Node::EnsureAppendableInputs(Zone* zone) { |
564 if (!has_appendable_inputs_) { | 578 if (!has_appendable_inputs()) { |
565 void* deque_buffer = zone->New(sizeof(InputDeque)); | 579 void* deque_buffer = zone->New(sizeof(InputDeque)); |
566 InputDeque* deque = new (deque_buffer) InputDeque(zone); | 580 InputDeque* deque = new (deque_buffer) InputDeque(zone); |
567 for (int i = 0; i < input_count_; ++i) { | 581 for (int i = 0; i < input_count(); ++i) { |
568 deque->push_back(inputs_.static_[i]); | 582 deque->push_back(inputs_.static_[i]); |
569 } | 583 } |
570 inputs_.appendable_ = deque; | 584 inputs_.appendable_ = deque; |
571 has_appendable_inputs_ = true; | 585 set_has_appendable_inputs(true); |
572 } | 586 } |
573 } | 587 } |
574 | 588 |
575 inline void Node::AppendInput(Zone* zone, Node* to_append) { | 589 inline void Node::AppendInput(Zone* zone, Node* to_append) { |
576 Use* new_use = new (zone) Use; | 590 Use* new_use = new (zone) Use; |
577 Input new_input; | 591 Input new_input; |
578 new_input.to = to_append; | 592 new_input.to = to_append; |
579 new_input.use = new_use; | 593 new_input.use = new_use; |
580 if (reserve_input_count_ > 0) { | 594 if (reserved_input_count() > 0) { |
581 DCHECK(!has_appendable_inputs_); | 595 DCHECK(!has_appendable_inputs()); |
582 reserve_input_count_--; | 596 set_reserved_input_count(reserved_input_count() - 1); |
583 inputs_.static_[input_count_] = new_input; | 597 inputs_.static_[input_count()] = new_input; |
584 } else { | 598 } else { |
585 EnsureAppendableInputs(zone); | 599 EnsureAppendableInputs(zone); |
586 inputs_.appendable_->push_back(new_input); | 600 inputs_.appendable_->push_back(new_input); |
587 } | 601 } |
588 new_use->input_index = input_count_; | 602 new_use->input_index = input_count(); |
589 new_use->from = this; | 603 new_use->from = this; |
590 to_append->AppendUse(new_use); | 604 to_append->AppendUse(new_use); |
591 input_count_++; | 605 set_input_count(input_count() + 1); |
592 } | 606 } |
593 | 607 |
594 inline void Node::InsertInput(Zone* zone, int index, Node* to_insert) { | 608 inline void Node::InsertInput(Zone* zone, int index, Node* to_insert) { |
595 DCHECK(index >= 0 && index < InputCount()); | 609 DCHECK(index >= 0 && index < InputCount()); |
596 // TODO(turbofan): Optimize this implementation! | 610 // TODO(turbofan): Optimize this implementation! |
597 AppendInput(zone, InputAt(InputCount() - 1)); | 611 AppendInput(zone, InputAt(InputCount() - 1)); |
598 for (int i = InputCount() - 1; i > index; --i) { | 612 for (int i = InputCount() - 1; i > index; --i) { |
599 ReplaceInput(i, InputAt(i - 1)); | 613 ReplaceInput(i, InputAt(i - 1)); |
600 } | 614 } |
601 ReplaceInput(index, to_insert); | 615 ReplaceInput(index, to_insert); |
(...skipping 10 matching lines...) Expand all Loading... |
612 | 626 |
613 inline void Node::AppendUse(Use* use) { | 627 inline void Node::AppendUse(Use* use) { |
614 use->next = NULL; | 628 use->next = NULL; |
615 use->prev = last_use_; | 629 use->prev = last_use_; |
616 if (last_use_ == NULL) { | 630 if (last_use_ == NULL) { |
617 first_use_ = use; | 631 first_use_ = use; |
618 } else { | 632 } else { |
619 last_use_->next = use; | 633 last_use_->next = use; |
620 } | 634 } |
621 last_use_ = use; | 635 last_use_ = use; |
622 ++use_count_; | |
623 } | 636 } |
624 | 637 |
625 inline void Node::RemoveUse(Use* use) { | 638 inline void Node::RemoveUse(Use* use) { |
626 if (last_use_ == use) { | 639 if (last_use_ == use) { |
627 last_use_ = use->prev; | 640 last_use_ = use->prev; |
628 } | 641 } |
629 if (use->prev != NULL) { | 642 if (use->prev != NULL) { |
630 use->prev->next = use->next; | 643 use->prev->next = use->next; |
631 } else { | 644 } else { |
632 first_use_ = use->next; | 645 first_use_ = use->next; |
633 } | 646 } |
634 if (use->next != NULL) { | 647 if (use->next != NULL) { |
635 use->next->prev = use->prev; | 648 use->next->prev = use->prev; |
636 } | 649 } |
637 --use_count_; | |
638 } | 650 } |
639 | 651 |
640 inline bool Node::OwnedBy(Node* owner) const { | 652 inline bool Node::OwnedBy(Node* owner) const { |
641 return first_use_ != NULL && first_use_->from == owner && | 653 return first_use_ != NULL && first_use_->from == owner && |
642 first_use_->next == NULL; | 654 first_use_->next == NULL; |
643 } | 655 } |
644 | 656 |
645 } // namespace compiler | 657 } // namespace compiler |
646 } // namespace internal | 658 } // namespace internal |
647 } // namespace v8 | 659 } // namespace v8 |
648 | 660 |
649 #endif // V8_COMPILER_NODE_H_ | 661 #endif // V8_COMPILER_NODE_H_ |
OLD | NEW |