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 7namespace v8 { 8namespace internal { 9namespace compiler { 10 11Node::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 23void 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. 54struct NodeWithOutOfLineInputs {}; 55struct NodeWithInLineInputs {}; 56 57template <typename NodePtrT> 58Node* 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 131Node* 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 136Node* 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 147void Node::Kill() { 148 DCHECK_NOT_NULL(op()); 149 NullAllInputs(); 150 DCHECK(uses().empty()); 151} 152 153 154void 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 203void 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 215void 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 232Node* 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 244void 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 259void Node::NullAllInputs() { ClearInputs(0, InputCount()); } 260 261 262void 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 274void 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 288int 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 297void 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 316bool 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 325bool 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 340void Node::Print(int depth) const { 341 StdoutStream os; 342 Print(os, depth); 343} 344 345namespace { 346void 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 364void Node::Print(std::ostream& os, int depth) const { 365 PrintNode(this, os, depth); 366} 367 368std::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 385Node::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 401void 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 411void 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 427void 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 463Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) { 464 iterator result(*this); 465 ++(*this); 466 return result; 467} 468 469 470Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) { 471 const_iterator result(*this); 472 ++(*this); 473 return result; 474} 475 476 477Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) { 478 iterator result(*this); 479 ++(*this); 480 return result; 481} 482 483 484bool Node::UseEdges::empty() const { return begin() == end(); } 485 486 487Node::Uses::const_iterator Node::Uses::const_iterator::operator++(int n) { 488 const_iterator result(*this); 489 ++(*this); 490 return result; 491} 492 493 494bool Node::Uses::empty() const { return begin() == end(); } 495 496} // namespace compiler 497} // namespace internal 498} // namespace v8 499 500V8_EXPORT_PRIVATE extern void _v8_internal_Node_Print(void* object) { 501 reinterpret_cast<i::compiler::Node*>(object)->Print(); 502} 503