[turbofan] Reduce memory consumption of graph building
authordanno@chromium.org <danno@chromium.org>
Mon, 27 Oct 2014 10:12:16 +0000 (10:12 +0000)
committerdanno@chromium.org <danno@chromium.org>
Mon, 27 Oct 2014 10:12:40 +0000 (10:12 +0000)
Allow reservation of additional input capacity when creating nodes to prevent switching to deque representation when adding well-known additional inputs.

Also ensure that only a single temporary buffer is used to create temporary input arrays before allocating nodes.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/644083003

Cr-Commit-Position: refs/heads/master@{#24896}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24896 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler/generic-node-inl.h
src/compiler/generic-node.h
src/compiler/graph-builder.cc
src/compiler/graph-builder.h
src/compiler/graph.cc
src/compiler/node.h
src/compiler/raw-machine-assembler.cc
src/compiler/raw-machine-assembler.h
test/cctest/compiler/graph-builder-tester.h
test/cctest/compiler/simplified-graph-builder.cc
test/cctest/compiler/simplified-graph-builder.h

index 76313af..30f8f68 100644 (file)
@@ -16,13 +16,16 @@ namespace internal {
 namespace compiler {
 
 template <class B, class S>
-GenericNode<B, S>::GenericNode(GenericGraphBase* graph, int input_count)
+GenericNode<B, S>::GenericNode(GenericGraphBase* graph, int input_count,
+                               int reserve_input_count)
     : BaseClass(graph->zone()),
       input_count_(input_count),
+      reserve_input_count_(reserve_input_count),
       has_appendable_inputs_(false),
       use_count_(0),
       first_use_(NULL),
       last_use_(NULL) {
+  DCHECK(reserve_input_count <= kMaxReservedInputs);
   inputs_.static_ = reinterpret_cast<Input*>(this + 1);
   AssignUniqueID(graph);
 }
@@ -154,12 +157,18 @@ void GenericNode<B, S>::EnsureAppendableInputs(Zone* zone) {
 
 template <class B, class S>
 void GenericNode<B, S>::AppendInput(Zone* zone, GenericNode<B, S>* to_append) {
-  EnsureAppendableInputs(zone);
   Use* new_use = new (zone) Use;
   Input new_input;
   new_input.to = to_append;
   new_input.use = new_use;
-  inputs_.appendable_->push_back(new_input);
+  if (reserve_input_count_ > 0) {
+    DCHECK(!has_appendable_inputs_);
+    reserve_input_count_--;
+    inputs_.static_[input_count_] = new_input;
+  } else {
+    EnsureAppendableInputs(zone);
+    inputs_.appendable_->push_back(new_input);
+  }
   new_use->input_index = input_count_;
   new_use->from = this;
   to_append->AppendUse(new_use);
@@ -224,15 +233,17 @@ inline bool GenericNode<B, S>::OwnedBy(GenericNode* owner) const {
 }
 
 template <class B, class S>
-S* GenericNode<B, S>::New(GenericGraphBase* graph, int input_count,
-                          S** inputs) {
+S* GenericNode<B, S>::New(GenericGraphBase* graph, int input_count, S** inputs,
+                          bool has_extensible_inputs) {
   size_t node_size = sizeof(GenericNode);
-  size_t inputs_size = input_count * sizeof(Input);
+  size_t reserve_input_count =
+      has_extensible_inputs ? kDefaultReservedInputs : 0;
+  size_t inputs_size = (input_count + reserve_input_count) * sizeof(Input);
   size_t uses_size = input_count * sizeof(Use);
   int size = static_cast<int>(node_size + inputs_size + uses_size);
   Zone* zone = graph->zone();
   void* buffer = zone->New(size);
-  S* result = new (buffer) S(graph, input_count);
+  S* result = new (buffer) S(graph, input_count, reserve_input_count);
   Input* input =
       reinterpret_cast<Input*>(reinterpret_cast<char*>(buffer) + node_size);
   Use* use =
index 3dc324d..506a34f 100644 (file)
@@ -92,7 +92,8 @@ class GenericNode : public B {
 
   bool OwnedBy(GenericNode* owner) const;
 
-  static S* New(GenericGraphBase* graph, int input_count, S** inputs);
+  static S* New(GenericGraphBase* graph, int input_count, S** inputs,
+                bool has_extensible_inputs);
 
  protected:
   friend class GenericGraphBase;
@@ -128,15 +129,21 @@ class GenericNode : public B {
 
   void* operator new(size_t, void* location) { return location; }
 
-  GenericNode(GenericGraphBase* graph, int input_count);
+  GenericNode(GenericGraphBase* graph, int input_count,
+              int reserved_input_count);
 
  private:
   void AssignUniqueID(GenericGraphBase* graph);
 
   typedef ZoneDeque<Input> InputDeque;
 
+  static const int kReservedInputCountBits = 2;
+  static const int kMaxReservedInputs = (1 << kReservedInputCountBits) - 1;
+  static const int kDefaultReservedInputs = kMaxReservedInputs;
+
   NodeId id_;
-  int input_count_ : 31;
+  int input_count_ : 29;
+  unsigned int reserve_input_count_ : kReservedInputCountBits;
   bool has_appendable_inputs_ : 1;
   union {
     // When a node is initially allocated, it uses a static buffer to hold its
index 2d420e4..ae55b95 100644 (file)
@@ -25,13 +25,26 @@ StructuredGraphBuilder::StructuredGraphBuilder(Zone* local_zone, Graph* graph,
       common_(common),
       environment_(NULL),
       local_zone_(local_zone),
+      input_buffer_size_(0),
+      input_buffer_(NULL),
       current_context_(NULL),
-      exit_control_(NULL) {}
+      exit_control_(NULL) {
+  EnsureInputBufferSize(kInputBufferSizeIncrement);
+}
+
+
+Node** StructuredGraphBuilder::EnsureInputBufferSize(int size) {
+  if (size > input_buffer_size_) {
+    size += kInputBufferSizeIncrement;
+    input_buffer_ = local_zone()->NewArray<Node*>(size);
+  }
+  return input_buffer_;
+}
 
 
 Node* StructuredGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
+                                       Node** value_inputs, bool incomplete) {
   DCHECK(op->InputCount() == value_input_count);
 
   bool has_context = OperatorProperties::HasContextInput(op);
@@ -44,14 +57,14 @@ Node* StructuredGraphBuilder::MakeNode(const Operator* op,
 
   Node* result = NULL;
   if (!has_context && !has_framestate && !has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+    result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_context) ++input_count_with_deps;
     if (has_framestate) ++input_count_with_deps;
     if (has_control) ++input_count_with_deps;
     if (has_effect) ++input_count_with_deps;
-    Node** buffer = local_zone()->NewArray<Node*>(input_count_with_deps);
+    Node** buffer = EnsureInputBufferSize(input_count_with_deps);
     memcpy(buffer, value_inputs, kPointerSize * value_input_count);
     Node** current_input = buffer + value_input_count;
     if (has_context) {
@@ -69,7 +82,7 @@ Node* StructuredGraphBuilder::MakeNode(const Operator* op,
     if (has_control) {
       *current_input++ = environment_->GetControlDependency();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+    result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       environment_->UpdateEffectDependency(result);
     }
@@ -125,7 +138,9 @@ void StructuredGraphBuilder::Environment::Merge(Environment* other) {
   // placing a singleton merge as the new control dependency.
   if (this->IsMarkedAsUnreachable()) {
     Node* other_control = other->control_dependency_;
-    control_dependency_ = graph()->NewNode(common()->Merge(1), other_control);
+    Node* inputs[] = {other_control};
+    control_dependency_ =
+        graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
     effect_dependency_ = other->effect_dependency_;
     values_ = other->values_;
     return;
@@ -164,7 +179,7 @@ void StructuredGraphBuilder::Environment::PrepareForLoop() {
 
 Node* StructuredGraphBuilder::NewPhi(int count, Node* input, Node* control) {
   const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
-  Node** buffer = local_zone()->NewArray<Node*>(count + 1);
+  Node** buffer = EnsureInputBufferSize(count + 1);
   MemsetPointer(buffer, input, count);
   buffer[count] = control;
   return graph()->NewNode(phi_op, count + 1, buffer, true);
@@ -175,7 +190,7 @@ Node* StructuredGraphBuilder::NewPhi(int count, Node* input, Node* control) {
 Node* StructuredGraphBuilder::NewEffectPhi(int count, Node* input,
                                            Node* control) {
   const Operator* phi_op = common()->EffectPhi(count);
-  Node** buffer = local_zone()->NewArray<Node*>(count + 1);
+  Node** buffer = EnsureInputBufferSize(count + 1);
   MemsetPointer(buffer, input, count);
   buffer[count] = control;
   return graph()->NewNode(phi_op, count + 1, buffer, true);
@@ -197,7 +212,8 @@ Node* StructuredGraphBuilder::MergeControl(Node* control, Node* other) {
   } else {
     // Control node is a singleton, introduce a merge.
     const Operator* op = common()->Merge(inputs);
-    control = graph()->NewNode(op, control, other);
+    Node* inputs[] = {control, other};
+    control = graph()->NewNode(op, arraysize(inputs), inputs, true);
   }
   return control;
 }
index a8ef502..90df6ca 100644 (file)
@@ -24,42 +24,44 @@ class GraphBuilder {
   explicit GraphBuilder(Graph* graph) : graph_(graph) {}
   virtual ~GraphBuilder() {}
 
-  Node* NewNode(const Operator* op) {
-    return MakeNode(op, 0, static_cast<Node**>(NULL));
+  Node* NewNode(const Operator* op, bool incomplete = false) {
+    return MakeNode(op, 0, static_cast<Node**>(NULL), incomplete);
   }
 
-  Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); }
+  Node* NewNode(const Operator* op, Node* n1) {
+    return MakeNode(op, 1, &n1, false);
+  }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2) {
     Node* buffer[] = {n1, n2};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) {
     Node* buffer[] = {n1, n2, n3};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) {
     Node* buffer[] = {n1, n2, n3, n4};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
                 Node* n5) {
     Node* buffer[] = {n1, n2, n3, n4, n5};
-    return MakeNode(op, arraysize(buffer), buffer);
+    return MakeNode(op, arraysize(buffer), buffer, false);
   }
 
   Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
                 Node* n5, Node* n6) {
     Node* nodes[] = {n1, n2, n3, n4, n5, n6};
-    return MakeNode(op, arraysize(nodes), nodes);
+    return MakeNode(op, arraysize(nodes), nodes, false);
   }
 
-  Node* NewNode(const Operator* op, int value_input_count,
-                Node** value_inputs) {
-    return MakeNode(op, value_input_count, value_inputs);
+  Node* NewNode(const Operator* op, int value_input_count, Node** value_inputs,
+                bool incomplete = false) {
+    return MakeNode(op, value_input_count, value_inputs, incomplete);
   }
 
   Graph* graph() const { return graph_; }
@@ -67,7 +69,7 @@ class GraphBuilder {
  protected:
   // Base implementation used by all factory methods.
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) = 0;
+                         Node** value_inputs, bool incomplete) = 0;
 
  private:
   Graph* graph_;
@@ -95,8 +97,8 @@ class StructuredGraphBuilder : public GraphBuilder {
   // Helpers to create new control nodes.
   Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
   Node* NewIfFalse() { return NewNode(common()->IfFalse()); }
-  Node* NewMerge() { return NewNode(common()->Merge(1)); }
-  Node* NewLoop() { return NewNode(common()->Loop(1)); }
+  Node* NewMerge() { return NewNode(common()->Merge(1), true); }
+  Node* NewLoop() { return NewNode(common()->Loop(1), true); }
   Node* NewBranch(Node* condition) {
     return NewNode(common()->Branch(), condition);
   }
@@ -110,7 +112,7 @@ class StructuredGraphBuilder : public GraphBuilder {
   // ensures effect and control dependencies are wired up. The dependencies
   // tracked by the environment might be mutated.
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;
 
   Environment* environment() const { return environment_; }
   void set_environment(Environment* env) { environment_ = env; }
@@ -148,6 +150,10 @@ class StructuredGraphBuilder : public GraphBuilder {
   // Zone local to the builder for data not leaking into the graph.
   Zone* local_zone_;
 
+  // Temporary storage for building node input lists.
+  int input_buffer_size_;
+  Node** input_buffer_;
+
   // Node representing the control dependency for dead code.
   SetOncePointer<Node> dead_control_;
 
@@ -157,6 +163,12 @@ class StructuredGraphBuilder : public GraphBuilder {
   // Merge of all control nodes that exit the function body.
   Node* exit_control_;
 
+  // Growth increment for the temporary buffer used to construct input lists to
+  // new nodes.
+  static const int kInputBufferSizeIncrement = 64;
+
+  Node** EnsureInputBufferSize(int size);
+
   DISALLOW_COPY_AND_ASSIGN(StructuredGraphBuilder);
 };
 
index 19e9c7f..1de712e 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/compiler/node-aux-data-inl.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/node-properties-inl.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator-properties.h"
 #include "src/compiler/operator-properties-inl.h"
 
@@ -29,12 +30,14 @@ void Graph::Decorate(Node* node) {
 }
 
 
-Node* Graph::NewNode(
-    const Operator* op, int input_count, Node** inputs, bool incomplete) {
+Node* Graph::NewNode(const Operator* op, int input_count, Node** inputs,
+                     bool incomplete) {
   DCHECK_LE(op->InputCount(), input_count);
-  Node* result = Node::New(this, input_count, inputs);
+  Node* result = Node::New(this, input_count, inputs, incomplete);
   result->Initialize(op);
-  if (!incomplete) Decorate(result);
+  if (!incomplete) {
+    Decorate(result);
+  }
   return result;
 }
 
index 7c99705..3a5afd2 100644 (file)
@@ -48,8 +48,8 @@ class NodeData {
 // out-of-line indexed by the Node's id.
 class Node FINAL : public GenericNode<NodeData, Node> {
  public:
-  Node(GenericGraphBase* graph, int input_count)
-      : GenericNode<NodeData, Node>(graph, input_count) {}
+  Node(GenericGraphBase* graph, int input_count, int reserve_input_count)
+      : GenericNode<NodeData, Node>(graph, input_count, reserve_input_count) {}
 
   void Initialize(const Operator* op) { set_op(op); }
 
index 39d44f3..ba545c1 100644 (file)
@@ -151,10 +151,10 @@ BasicBlock* RawMachineAssembler::CurrentBlock() {
 
 
 Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
-                                    Node** inputs) {
+                                    Node** inputs, bool incomplete) {
   DCHECK(ScheduleValid());
   DCHECK(current_block_ != NULL);
-  Node* node = graph()->NewNode(op, input_count, inputs);
+  Node* node = graph()->NewNode(op, input_count, inputs, incomplete);
   BasicBlock* block = op->opcode() == IrOpcode::kParameter ? schedule()->start()
                                                            : CurrentBlock();
   schedule()->AddNode(block, node);
index 35f884f..dfe83fa 100644 (file)
@@ -416,8 +416,8 @@ class RawMachineAssembler : public GraphBuilder {
   Schedule* Export();
 
  protected:
-  virtual Node* MakeNode(const Operator* op, int input_count,
-                         Node** inputs) FINAL;
+  virtual Node* MakeNode(const Operator* op, int input_count, Node** inputs,
+                         bool incomplete) FINAL;
 
   bool ScheduleValid() { return schedule_ != NULL; }
 
index df79250..1bc5be7 100644 (file)
@@ -27,8 +27,8 @@ class DirectGraphBuilder : public GraphBuilder {
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL {
-    return graph()->NewNode(op, value_input_count, value_inputs);
+                         Node** value_inputs, bool incomplete) FINAL {
+    return graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   }
 };
 
index c44d5ed..03b4b22 100644 (file)
@@ -45,7 +45,7 @@ void SimplifiedGraphBuilder::End() {
 
 Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
+                                       Node** value_inputs, bool incomplete) {
   DCHECK(op->InputCount() == value_input_count);
 
   DCHECK(!OperatorProperties::HasContextInput(op));
@@ -58,7 +58,7 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
 
   Node* result = NULL;
   if (!has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+    result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_control) ++input_count_with_deps;
@@ -72,7 +72,7 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
     if (has_control) {
       *current_input++ = graph()->start();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+    result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       effect_ = result;
     }
index 82c568b..ad062e6 100644 (file)
@@ -139,7 +139,7 @@ class SimplifiedGraphBuilder : public GraphBuilder {
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;
 
  private:
   Node* effect_;