| 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 |