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 "src/compiler/opcodes.h" | 8 #include "src/compiler/opcodes.h" |
9 #include "src/compiler/operator.h" | 9 #include "src/compiler/operator.h" |
10 #include "src/types-inl.h" | 10 #include "src/types-inl.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 void Kill(); | 48 void Kill(); |
49 | 49 |
50 const Operator* op() const { return op_; } | 50 const Operator* op() const { return op_; } |
51 void set_op(const Operator* op) { op_ = op; } | 51 void set_op(const Operator* op) { op_ = op; } |
52 | 52 |
53 IrOpcode::Value opcode() const { | 53 IrOpcode::Value opcode() const { |
54 DCHECK(op_->opcode() <= IrOpcode::kLast); | 54 DCHECK(op_->opcode() <= IrOpcode::kLast); |
55 return static_cast<IrOpcode::Value>(op_->opcode()); | 55 return static_cast<IrOpcode::Value>(op_->opcode()); |
56 } | 56 } |
57 | 57 |
58 NodeId id() const { return id_; } | 58 NodeId id() const { return IdField::decode(bit_field_); } |
59 | 59 |
60 int InputCount() const { return input_count(); } | 60 int InputCount() const { |
| 61 return has_inline_inputs() ? InlineCountField::decode(bit_field_) |
| 62 : inputs_.outline_->count_; |
| 63 } |
| 64 |
| 65 #if DEBUG |
| 66 void Verify(); |
| 67 #define BOUNDS_CHECK(index) \ |
| 68 do { \ |
| 69 if (index < 0 || index >= InputCount()) { \ |
| 70 V8_Fatal(__FILE__, __LINE__, "Node #%d:%s->InputAt(%d) out of bounds", \ |
| 71 id(), op()->mnemonic(), index); \ |
| 72 } \ |
| 73 } while (false) |
| 74 #else |
| 75 // No bounds checks or verification in release mode. |
| 76 inline void Verify() {} |
| 77 #define BOUNDS_CHECK(index) \ |
| 78 do { \ |
| 79 } while (false) |
| 80 #endif |
| 81 |
61 Node* InputAt(int index) const { | 82 Node* InputAt(int index) const { |
62 #if DEBUG | 83 BOUNDS_CHECK(index); |
63 if (index < 0 || index >= InputCount()) { | 84 return *GetInputPtrConst(index); |
64 V8_Fatal(__FILE__, __LINE__, "Node #%d:%s->InputAt(%d) out of bounds", | 85 } |
65 id(), op()->mnemonic(), index); | 86 |
| 87 void ReplaceInput(int index, Node* new_to) { |
| 88 BOUNDS_CHECK(index); |
| 89 Node** input_ptr = GetInputPtr(index); |
| 90 Node* old_to = *input_ptr; |
| 91 if (old_to != new_to) { |
| 92 Use* use = GetUsePtr(index); |
| 93 if (old_to) old_to->RemoveUse(use); |
| 94 *input_ptr = new_to; |
| 95 if (new_to) new_to->AppendUse(use); |
66 } | 96 } |
67 #endif | |
68 return GetInputRecordPtr(index)->to; | |
69 } | 97 } |
70 inline void ReplaceInput(int index, Node* new_to); | 98 |
| 99 #undef BOUNDS_CHECK |
| 100 |
71 void AppendInput(Zone* zone, Node* new_to); | 101 void AppendInput(Zone* zone, Node* new_to); |
72 void InsertInput(Zone* zone, int index, Node* new_to); | 102 void InsertInput(Zone* zone, int index, Node* new_to); |
73 void RemoveInput(int index); | 103 void RemoveInput(int index); |
74 void NullAllInputs(); | 104 void NullAllInputs(); |
75 void TrimInputCount(int new_input_count); | 105 void TrimInputCount(int new_input_count); |
76 | 106 |
77 int UseCount() const; | 107 int UseCount() const; |
78 void ReplaceUses(Node* replace_to); | 108 void ReplaceUses(Node* replace_to); |
79 | 109 |
80 class InputEdges final { | 110 class InputEdges final { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 explicit Uses(Node* node) : node_(node) {} | 174 explicit Uses(Node* node) : node_(node) {} |
145 | 175 |
146 private: | 176 private: |
147 Node* node_; | 177 Node* node_; |
148 }; | 178 }; |
149 | 179 |
150 Uses uses() { return Uses(this); } | 180 Uses uses() { return Uses(this); } |
151 | 181 |
152 // Returns true if {owner} is the user of {this} node. | 182 // Returns true if {owner} is the user of {this} node. |
153 bool OwnedBy(Node* owner) const { | 183 bool OwnedBy(Node* owner) const { |
154 return first_use_ && first_use_->from == owner && !first_use_->next; | 184 return first_use_ && first_use_->from() == owner && !first_use_->next; |
155 } | 185 } |
156 | 186 |
157 // Returns true if {owner1} and {owner2} are the only users of {this} node. | 187 // Returns true if {owner1} and {owner2} are the only users of {this} node. |
158 bool OwnedBy(Node const* owner1, Node const* owner2) const; | 188 bool OwnedBy(Node const* owner1, Node const* owner2) const; |
159 | 189 |
160 private: | 190 private: |
161 struct Use final : public ZoneObject { | 191 struct Use; |
162 Node* from; | 192 // Out of line storage for inputs when the number of inputs overflowed the |
| 193 // capacity of the inline-allocated space. |
| 194 struct OutOfLineInputs { |
| 195 Node* node_; |
| 196 int count_; |
| 197 int capacity_; |
| 198 Node* inputs_[1]; |
| 199 |
| 200 static OutOfLineInputs* New(Zone* zone, int capacity); |
| 201 void ExtractFrom(Use* use_ptr, Node** input_ptr, int count); |
| 202 }; |
| 203 |
| 204 // A link in the use chain for a node. Every input {i} to a node {n} has an |
| 205 // associated {Use} which is linked into the use chain of the {i} node. |
| 206 struct Use { |
163 Use* next; | 207 Use* next; |
164 Use* prev; | 208 Use* prev; |
165 int input_index; | 209 uint32_t bit_field_; |
| 210 |
| 211 int input_index() const { return InputIndexField::decode(bit_field_); } |
| 212 int output_index() const { return OutputIndexField::decode(bit_field_); } |
| 213 bool is_inline_use() const { return InlineField::decode(bit_field_); } |
| 214 Node** input_ptr() { |
| 215 int index = input_index(); |
| 216 Use* start = this + 1 + index; |
| 217 Node** inputs = is_inline_use() |
| 218 ? reinterpret_cast<Node*>(start)->inputs_.inline_ |
| 219 : reinterpret_cast<OutOfLineInputs*>(start)->inputs_; |
| 220 return &inputs[index]; |
| 221 } |
| 222 |
| 223 Node* from() { |
| 224 Use* start = this + 1 + input_index(); |
| 225 return is_inline_use() ? reinterpret_cast<Node*>(start) |
| 226 : reinterpret_cast<OutOfLineInputs*>(start)->node_; |
| 227 } |
| 228 |
| 229 typedef BitField<bool, 0, 1> InlineField; |
| 230 typedef BitField<unsigned, 1, 17> InputIndexField; |
| 231 typedef BitField<unsigned, 17, 14> OutputIndexField; |
166 }; | 232 }; |
167 | 233 |
168 class Input final { | 234 //============================================================================ |
169 public: | 235 //== Memory layout =========================================================== |
170 Node* to; | 236 //============================================================================ |
171 Use* use; | 237 // Saving space for big graphs is important. We use a memory layout trick to |
| 238 // be able to map {Node} objects to {Use} objects and vice-versa in a |
| 239 // space-efficient manner. |
| 240 // |
| 241 // {Use} links are laid out in memory directly before a {Node}, followed by |
| 242 // direct pointers to input {Nodes}. |
| 243 // |
| 244 // inline case: |
| 245 // |Use #N |Use #N-1|...|Use #1 |Use #0 |Node xxxx |I#0|I#1|...|I#N-1|I#N| |
| 246 // ^ ^ ^ |
| 247 // + Use + Node + Input |
| 248 // |
| 249 // Since every {Use} instance records its {input_index}, pointer arithmetic |
| 250 // can compute the {Node}. |
| 251 // |
| 252 // out-of-line case: |
| 253 // |Node xxxx | |
| 254 // ^ + outline ------------------+ |
| 255 // +----------------------------------------+ |
| 256 // | | |
| 257 // v | node |
| 258 // |Use #N |Use #N-1|...|Use #1 |Use #0 |OOL xxxxx |I#0|I#1|...|I#N-1|I#N| |
| 259 // ^ ^ |
| 260 // + Use + Input |
| 261 // |
| 262 // Out-of-line storage of input lists is needed if appending an input to |
| 263 // a node exceeds the maximum inline capacity. |
172 | 264 |
173 void Update(Node* new_to); | 265 Node(NodeId id, const Operator* op, int inline_count, int inline_capacity); |
174 }; | |
175 | 266 |
176 inline Node(NodeId id, const Operator* op, int input_count, | 267 Node* const* GetInputPtrConst(int input_index) const { |
177 int reserve_input_count); | 268 return has_inline_inputs() ? &(inputs_.inline_[input_index]) |
178 | 269 : &inputs_.outline_->inputs_[input_index]; |
179 inline void EnsureAppendableInputs(Zone* zone); | |
180 | |
181 Input* GetInputRecordPtr(int index) { | |
182 return has_appendable_inputs() ? &((*inputs_.appendable_)[index]) | |
183 : &inputs_.static_[index]; | |
184 } | 270 } |
185 const Input* GetInputRecordPtr(int index) const { | 271 Node** GetInputPtr(int input_index) { |
186 return has_appendable_inputs() ? &((*inputs_.appendable_)[index]) | 272 return has_inline_inputs() ? &(inputs_.inline_[input_index]) |
187 : &inputs_.static_[index]; | 273 : &inputs_.outline_->inputs_[input_index]; |
| 274 } |
| 275 Use* GetUsePtr(int input_index) { |
| 276 Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this) |
| 277 : reinterpret_cast<Use*>(inputs_.outline_); |
| 278 return &ptr[-1 - input_index]; |
188 } | 279 } |
189 | 280 |
190 inline void AppendUse(Use* const use); | 281 void AppendUse(Use* use); |
191 inline void RemoveUse(Use* const use); | 282 void RemoveUse(Use* use); |
192 | 283 |
193 void* operator new(size_t, void* location) { return location; } | 284 void* operator new(size_t, void* location) { return location; } |
194 | 285 |
195 typedef ZoneDeque<Input> InputDeque; | |
196 | |
197 // Only NodeProperties should manipulate the bounds. | 286 // Only NodeProperties should manipulate the bounds. |
198 Bounds bounds() { return bounds_; } | 287 Bounds bounds() { return bounds_; } |
199 void set_bounds(Bounds b) { bounds_ = b; } | 288 void set_bounds(Bounds b) { bounds_ = b; } |
200 | 289 |
201 // Only NodeMarkers should manipulate the marks on nodes. | 290 // Only NodeMarkers should manipulate the marks on nodes. |
202 Mark mark() { return mark_; } | 291 Mark mark() { return mark_; } |
203 void set_mark(Mark mark) { mark_ = mark; } | 292 void set_mark(Mark mark) { mark_ = mark; } |
204 | 293 |
205 int input_count() const { return InputCountField::decode(bit_field_); } | 294 inline bool has_inline_inputs() const { |
206 void set_input_count(int input_count) { | 295 return InlineCountField::decode(bit_field_) != kOutlineMarker; |
207 DCHECK_LE(0, input_count); | |
208 bit_field_ = InputCountField::update(bit_field_, input_count); | |
209 } | 296 } |
210 | 297 |
211 int reserved_input_count() const { | 298 void ClearInputs(int start, int count); |
212 return ReservedInputCountField::decode(bit_field_); | |
213 } | |
214 void set_reserved_input_count(int reserved_input_count) { | |
215 DCHECK_LE(0, reserved_input_count); | |
216 bit_field_ = | |
217 ReservedInputCountField::update(bit_field_, reserved_input_count); | |
218 } | |
219 | 299 |
220 bool has_appendable_inputs() const { | 300 typedef BitField<NodeId, 0, 24> IdField; |
221 return HasAppendableInputsField::decode(bit_field_); | 301 typedef BitField<unsigned, 24, 4> InlineCountField; |
222 } | 302 typedef BitField<unsigned, 28, 4> InlineCapacityField; |
223 void set_has_appendable_inputs(bool has_appendable_inputs) { | 303 static const int kOutlineMarker = InlineCountField::kMax; |
224 bit_field_ = | 304 static const int kMaxInlineCount = InlineCountField::kMax - 1; |
225 HasAppendableInputsField::update(bit_field_, has_appendable_inputs); | 305 static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1; |
226 } | |
227 | |
228 typedef BitField<unsigned, 0, 29> InputCountField; | |
229 typedef BitField<unsigned, 29, 2> ReservedInputCountField; | |
230 typedef BitField<unsigned, 31, 1> HasAppendableInputsField; | |
231 static const int kDefaultReservedInputs = ReservedInputCountField::kMax; | |
232 | 306 |
233 const Operator* op_; | 307 const Operator* op_; |
234 Bounds bounds_; | 308 Bounds bounds_; |
235 Mark mark_; | 309 Mark mark_; |
236 NodeId const id_; | 310 uint32_t bit_field_; |
237 unsigned bit_field_; | |
238 Use* first_use_; | 311 Use* first_use_; |
239 union { | 312 union { |
240 // When a node is initially allocated, it uses a static buffer to hold its | 313 // Inline storage for inputs or out-of-line storage. |
241 // inputs under the assumption that the number of outputs will not increase. | 314 Node* inline_[1]; |
242 // When the first input is appended, the static buffer is converted into a | 315 OutOfLineInputs* outline_; |
243 // deque to allow for space-efficient growing. | |
244 Input static_[1]; | |
245 InputDeque* appendable_; | |
246 } inputs_; | 316 } inputs_; |
247 | 317 |
248 friend class Edge; | 318 friend class Edge; |
249 friend class NodeMarkerBase; | 319 friend class NodeMarkerBase; |
250 friend class NodeProperties; | 320 friend class NodeProperties; |
251 | 321 |
252 DISALLOW_COPY_AND_ASSIGN(Node); | 322 DISALLOW_COPY_AND_ASSIGN(Node); |
253 }; | 323 }; |
254 | 324 |
255 | 325 |
(...skipping 12 matching lines...) Expand all Loading... |
268 static inline const T& OpParameter(const Node* node) { | 338 static inline const T& OpParameter(const Node* node) { |
269 return OpParameter<T>(node->op()); | 339 return OpParameter<T>(node->op()); |
270 } | 340 } |
271 | 341 |
272 | 342 |
273 // An encapsulation for information associated with a single use of node as a | 343 // An encapsulation for information associated with a single use of node as a |
274 // input from another node, allowing access to both the defining node and | 344 // input from another node, allowing access to both the defining node and |
275 // the node having the input. | 345 // the node having the input. |
276 class Edge final { | 346 class Edge final { |
277 public: | 347 public: |
278 Node* from() const { return input_->use->from; } | 348 Node* from() const { return use_->from(); } |
279 Node* to() const { return input_->to; } | 349 Node* to() const { return *input_ptr_; } |
280 int index() const { | 350 int index() const { |
281 int const index = input_->use->input_index; | 351 int const index = use_->input_index(); |
282 DCHECK_LT(index, input_->use->from->input_count()); | 352 DCHECK_LT(index, use_->from()->InputCount()); |
283 return index; | 353 return index; |
284 } | 354 } |
285 | 355 |
286 bool operator==(const Edge& other) { return input_ == other.input_; } | 356 bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; } |
287 bool operator!=(const Edge& other) { return !(*this == other); } | 357 bool operator!=(const Edge& other) { return !(*this == other); } |
288 | 358 |
289 void UpdateTo(Node* new_to) { input_->Update(new_to); } | 359 void UpdateTo(Node* new_to) { |
| 360 Node* old_to = *input_ptr_; |
| 361 if (old_to != new_to) { |
| 362 if (old_to) old_to->RemoveUse(use_); |
| 363 *input_ptr_ = new_to; |
| 364 if (new_to) new_to->AppendUse(use_); |
| 365 } |
| 366 } |
290 | 367 |
291 private: | 368 private: |
292 friend class Node::UseEdges::iterator; | 369 friend class Node::UseEdges::iterator; |
293 friend class Node::InputEdges::iterator; | 370 friend class Node::InputEdges::iterator; |
294 | 371 |
295 explicit Edge(Node::Input* input) : input_(input) { DCHECK_NOT_NULL(input); } | 372 Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) { |
| 373 DCHECK_NOT_NULL(use); |
| 374 DCHECK_NOT_NULL(input_ptr); |
| 375 DCHECK_EQ(input_ptr, use->input_ptr()); |
| 376 } |
296 | 377 |
297 Node::Input* input_; | 378 Node::Use* use_; |
| 379 Node** input_ptr_; |
298 }; | 380 }; |
299 | 381 |
300 | 382 |
301 // A forward iterator to visit the edges for the input dependencies of a node. | 383 // A forward iterator to visit the edges for the input dependencies of a node. |
302 class Node::InputEdges::iterator final { | 384 class Node::InputEdges::iterator final { |
303 public: | 385 public: |
304 typedef std::forward_iterator_tag iterator_category; | 386 typedef std::forward_iterator_tag iterator_category; |
305 typedef int difference_type; | 387 typedef int difference_type; |
306 typedef Edge value_type; | 388 typedef Edge value_type; |
307 typedef Edge* pointer; | 389 typedef Edge* pointer; |
308 typedef Edge& reference; | 390 typedef Edge& reference; |
309 | 391 |
310 iterator() : input_(nullptr) {} | 392 iterator() : use_(nullptr), input_ptr_(nullptr) {} |
311 iterator(const iterator& other) : input_(other.input_) {} | 393 iterator(const iterator& other) |
| 394 : use_(other.use_), input_ptr_(other.input_ptr_) {} |
312 | 395 |
313 Edge operator*() const { return Edge(input_); } | 396 Edge operator*() const { return Edge(use_, input_ptr_); } |
314 bool operator==(const iterator& other) const { | 397 bool operator==(const iterator& other) const { |
315 return input_ == other.input_; | 398 return input_ptr_ == other.input_ptr_; |
316 } | 399 } |
317 bool operator!=(const iterator& other) const { return !(*this == other); } | 400 bool operator!=(const iterator& other) const { return !(*this == other); } |
318 iterator& operator++() { | 401 iterator& operator++() { |
319 SetInput(Edge(input_).from(), input_->use->input_index + 1); | 402 input_ptr_++; |
| 403 use_--; |
320 return *this; | 404 return *this; |
321 } | 405 } |
322 iterator operator++(int); | 406 iterator operator++(int); |
323 | 407 |
324 private: | 408 private: |
325 friend class Node; | 409 friend class Node; |
326 | 410 |
327 explicit iterator(Node* from, int index = 0) : input_(nullptr) { | 411 explicit iterator(Node* from, int index = 0) |
328 SetInput(from, index); | 412 : use_(from->GetUsePtr(index)), input_ptr_(from->GetInputPtr(index)) {} |
329 } | |
330 | 413 |
331 void SetInput(Node* from, int index) { | 414 Use* use_; |
332 DCHECK(index >= 0 && index <= from->InputCount()); | 415 Node** input_ptr_; |
333 if (index < from->InputCount()) { | |
334 input_ = from->GetInputRecordPtr(index); | |
335 } else { | |
336 input_ = nullptr; | |
337 } | |
338 } | |
339 | |
340 Input* input_; | |
341 }; | 416 }; |
342 | 417 |
343 | 418 |
344 Node::InputEdges::iterator Node::InputEdges::begin() const { | 419 Node::InputEdges::iterator Node::InputEdges::begin() const { |
345 return Node::InputEdges::iterator(this->node_, 0); | 420 return Node::InputEdges::iterator(this->node_, 0); |
346 } | 421 } |
347 | 422 |
348 | 423 |
349 Node::InputEdges::iterator Node::InputEdges::end() const { | 424 Node::InputEdges::iterator Node::InputEdges::end() const { |
350 return Node::InputEdges::iterator(this->node_, this->node_->InputCount()); | 425 return Node::InputEdges::iterator(this->node_, this->node_->InputCount()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 return const_iterator(this->node_, this->node_->InputCount()); | 468 return const_iterator(this->node_, this->node_->InputCount()); |
394 } | 469 } |
395 | 470 |
396 | 471 |
397 // A forward iterator to visit the uses edges of a node. | 472 // A forward iterator to visit the uses edges of a node. |
398 class Node::UseEdges::iterator final { | 473 class Node::UseEdges::iterator final { |
399 public: | 474 public: |
400 iterator(const iterator& other) | 475 iterator(const iterator& other) |
401 : current_(other.current_), next_(other.next_) {} | 476 : current_(other.current_), next_(other.next_) {} |
402 | 477 |
403 Edge operator*() const { | 478 Edge operator*() const { return Edge(current_, current_->input_ptr()); } |
404 return Edge(current_->from->GetInputRecordPtr(current_->input_index)); | |
405 } | |
406 | |
407 bool operator==(const iterator& other) const { | 479 bool operator==(const iterator& other) const { |
408 return current_ == other.current_; | 480 return current_ == other.current_; |
409 } | 481 } |
410 bool operator!=(const iterator& other) const { return !(*this == other); } | 482 bool operator!=(const iterator& other) const { return !(*this == other); } |
411 iterator& operator++() { | 483 iterator& operator++() { |
412 DCHECK_NOT_NULL(current_); | 484 DCHECK_NOT_NULL(current_); |
413 current_ = next_; | 485 current_ = next_; |
414 next_ = current_ ? current_->next : nullptr; | 486 next_ = current_ ? current_->next : nullptr; |
415 return *this; | 487 return *this; |
416 } | 488 } |
(...skipping 26 matching lines...) Expand all Loading... |
443 class Node::Uses::const_iterator final { | 515 class Node::Uses::const_iterator final { |
444 public: | 516 public: |
445 typedef std::forward_iterator_tag iterator_category; | 517 typedef std::forward_iterator_tag iterator_category; |
446 typedef int difference_type; | 518 typedef int difference_type; |
447 typedef Node* value_type; | 519 typedef Node* value_type; |
448 typedef Node** pointer; | 520 typedef Node** pointer; |
449 typedef Node*& reference; | 521 typedef Node*& reference; |
450 | 522 |
451 const_iterator(const const_iterator& other) : current_(other.current_) {} | 523 const_iterator(const const_iterator& other) : current_(other.current_) {} |
452 | 524 |
453 Node* operator*() const { return current_->from; } | 525 Node* operator*() const { return current_->from(); } |
454 bool operator==(const const_iterator& other) const { | 526 bool operator==(const const_iterator& other) const { |
455 return other.current_ == current_; | 527 return other.current_ == current_; |
456 } | 528 } |
457 bool operator!=(const const_iterator& other) const { | 529 bool operator!=(const const_iterator& other) const { |
458 return other.current_ != current_; | 530 return other.current_ != current_; |
459 } | 531 } |
460 const_iterator& operator++() { | 532 const_iterator& operator++() { |
461 DCHECK_NOT_NULL(current_); | 533 DCHECK_NOT_NULL(current_); |
462 current_ = current_->next; | 534 current_ = current_->next; |
463 return *this; | 535 return *this; |
(...skipping 10 matching lines...) Expand all Loading... |
474 }; | 546 }; |
475 | 547 |
476 | 548 |
477 Node::Uses::const_iterator Node::Uses::begin() const { | 549 Node::Uses::const_iterator Node::Uses::begin() const { |
478 return const_iterator(this->node_); | 550 return const_iterator(this->node_); |
479 } | 551 } |
480 | 552 |
481 | 553 |
482 Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); } | 554 Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); } |
483 | 555 |
484 | |
485 void Node::ReplaceInput(int index, Node* new_to) { | |
486 GetInputRecordPtr(index)->Update(new_to); | |
487 } | |
488 | |
489 } // namespace compiler | 556 } // namespace compiler |
490 } // namespace internal | 557 } // namespace internal |
491 } // namespace v8 | 558 } // namespace v8 |
492 | 559 |
493 #endif // V8_COMPILER_NODE_H_ | 560 #endif // V8_COMPILER_NODE_H_ |
OLD | NEW |