Commit 16928e28 authored by danno@chromium.org's avatar danno@chromium.org

[turbofan] Reduce memory consumption of graph building

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
parent 16e25a11
......@@ -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 =
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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);
};
......
......@@ -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;
}
......
......@@ -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); }
......
......@@ -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);
......
......@@ -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; }
......
......@@ -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);
}
};
......
......@@ -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;
}
......
......@@ -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_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment