Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Unified Diff: src/compiler/ast-graph-builder.cc

Issue 894073002: [turbofan] Put StructuredGraphBuilder out of its misery and merge its remnants back into the AstGra… (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/ast-graph-builder.h ('k') | src/compiler/control-builders.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/ast-graph-builder.cc
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
index 18475d1dca6d6d1958d998be8dfc299da6f4c0ea..08f0fa2581f7044c2feeec55afd3ca7d99772da1 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -20,15 +20,21 @@ namespace v8 {
namespace internal {
namespace compiler {
+
AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
- : StructuredGraphBuilder(jsgraph->isolate(), local_zone, jsgraph->graph(),
- jsgraph->common()),
+ : local_zone_(local_zone),
info_(info),
jsgraph_(jsgraph),
+ environment_(nullptr),
+ ast_context_(nullptr),
globals_(0, local_zone),
- breakable_(NULL),
- execution_context_(NULL),
+ breakable_(nullptr),
+ execution_context_(nullptr),
+ input_buffer_size_(0),
+ input_buffer_(nullptr),
+ current_context_(nullptr),
+ exit_control_(nullptr),
loop_assignment_analysis_(loop) {
InitializeAstVisitor(info->isolate(), local_zone);
}
@@ -151,21 +157,18 @@ static LhsKind DetermineLhsKind(Expression* expr) {
}
-StructuredGraphBuilder::Environment* AstGraphBuilder::CopyEnvironment(
- StructuredGraphBuilder::Environment* env) {
- return new (zone()) Environment(*reinterpret_cast<Environment*>(env));
-}
-
-
AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
Scope* scope,
Node* control_dependency)
- : StructuredGraphBuilder::Environment(builder, control_dependency),
+ : builder_(builder),
parameters_count_(scope->num_parameters() + 1),
locals_count_(scope->num_stack_slots()),
- parameters_node_(NULL),
- locals_node_(NULL),
- stack_node_(NULL) {
+ values_(builder_->local_zone()),
+ control_dependency_(control_dependency),
+ effect_dependency_(control_dependency),
+ parameters_node_(nullptr),
+ locals_node_(nullptr),
+ stack_node_(nullptr) {
DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
// Bind the receiver variable.
@@ -187,14 +190,21 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
}
-AstGraphBuilder::Environment::Environment(const Environment& copy)
- : StructuredGraphBuilder::Environment(
- static_cast<StructuredGraphBuilder::Environment>(copy)),
- parameters_count_(copy.parameters_count_),
- locals_count_(copy.locals_count_),
- parameters_node_(copy.parameters_node_),
- locals_node_(copy.locals_node_),
- stack_node_(copy.stack_node_) {}
+AstGraphBuilder::Environment::Environment(
+ const AstGraphBuilder::Environment* copy)
+ : builder_(copy->builder_),
+ parameters_count_(copy->parameters_count_),
+ locals_count_(copy->locals_count_),
+ values_(copy->zone()),
+ control_dependency_(copy->control_dependency_),
+ effect_dependency_(copy->effect_dependency_),
+ parameters_node_(copy->parameters_node_),
+ locals_node_(copy->locals_node_),
+ stack_node_(copy->stack_node_) {
+ const size_t kStackEstimate = 7; // optimum from experimentation!
+ values_.reserve(copy->values_.size() + kStackEstimate);
+ values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end());
+}
void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
@@ -229,7 +239,7 @@ Node* AstGraphBuilder::Environment::Checkpoint(
const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
- GetContext(),
+ builder()->current_context(),
builder()->jsgraph()->UndefinedConstant());
}
@@ -518,14 +528,14 @@ void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
- StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable();
+ Environment* env = environment()->CopyAsUnreachable();
breakable()->ContinueTarget(stmt->target());
set_environment(env);
}
void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
- StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable();
+ Environment* env = environment()->CopyAsUnreachable();
breakable()->BreakTarget(stmt->target());
set_environment(env);
}
@@ -1945,7 +1955,7 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
// Sloppy mode functions and builtins need to replace the receiver with the
// global proxy when called as functions (without an explicit receiver
// object). Otherwise there is nothing left to do here.
- if (info()->strict_mode() != SLOPPY || info()->is_native()) return receiver;
+ if (strict_mode() != SLOPPY || info()->is_native()) return receiver;
// There is no need to perform patching if the receiver is never used. Note
// that scope predicates are purely syntactical, a call to eval might still
@@ -2439,6 +2449,243 @@ BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
}
+
+Node** AstGraphBuilder::EnsureInputBufferSize(int size) {
+ if (size > input_buffer_size_) {
+ size = size + kInputBufferSizeIncrement + input_buffer_size_;
+ input_buffer_ = local_zone()->NewArray<Node*>(size);
+ input_buffer_size_ = size;
+ }
+ return input_buffer_;
+}
+
+
+Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
+ Node** value_inputs, bool incomplete) {
+ DCHECK(op->ValueInputCount() == value_input_count);
+
+ bool has_context = OperatorProperties::HasContextInput(op);
+ bool has_framestate = OperatorProperties::HasFrameStateInput(op);
+ bool has_control = op->ControlInputCount() == 1;
+ bool has_effect = op->EffectInputCount() == 1;
+
+ DCHECK(op->ControlInputCount() < 2);
+ DCHECK(op->EffectInputCount() < 2);
+
+ Node* result = NULL;
+ if (!has_context && !has_framestate && !has_control && !has_effect) {
+ 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 = EnsureInputBufferSize(input_count_with_deps);
+ memcpy(buffer, value_inputs, kPointerSize * value_input_count);
+ Node** current_input = buffer + value_input_count;
+ if (has_context) {
+ *current_input++ = current_context();
+ }
+ if (has_framestate) {
+ // The frame state will be inserted later. Here we misuse
+ // the dead_control node as a sentinel to be later overwritten
+ // with the real frame state.
+ *current_input++ = dead_control();
+ }
+ if (has_effect) {
+ *current_input++ = environment_->GetEffectDependency();
+ }
+ if (has_control) {
+ *current_input++ = environment_->GetControlDependency();
+ }
+ result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
+ if (has_effect) {
+ environment_->UpdateEffectDependency(result);
+ }
+ if (result->op()->ControlOutputCount() > 0 &&
+ !environment()->IsMarkedAsUnreachable()) {
+ environment_->UpdateControlDependency(result);
+ }
+ }
+
+ return result;
+}
+
+
+void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
+ if (environment()->IsMarkedAsUnreachable()) return;
+ if (exit_control() != NULL) {
+ exit = MergeControl(exit_control(), exit);
+ }
+ environment()->MarkAsUnreachable();
+ set_exit_control(exit);
+}
+
+
+void AstGraphBuilder::Environment::Merge(Environment* other) {
+ DCHECK(values_.size() == other->values_.size());
+
+ // Nothing to do if the other environment is dead.
+ if (other->IsMarkedAsUnreachable()) return;
+
+ // Resurrect a dead environment by copying the contents of the other one and
+ // placing a singleton merge as the new control dependency.
+ if (this->IsMarkedAsUnreachable()) {
+ Node* other_control = other->control_dependency_;
+ Node* inputs[] = {other_control};
+ control_dependency_ =
+ graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
+ effect_dependency_ = other->effect_dependency_;
+ values_ = other->values_;
+ return;
+ }
+
+ // Create a merge of the control dependencies of both environments and update
+ // the current environment's control dependency accordingly.
+ Node* control = builder_->MergeControl(this->GetControlDependency(),
+ other->GetControlDependency());
+ UpdateControlDependency(control);
+
+ // Create a merge of the effect dependencies of both environments and update
+ // the current environment's effect dependency accordingly.
+ Node* effect = builder_->MergeEffect(this->GetEffectDependency(),
+ other->GetEffectDependency(), control);
+ UpdateEffectDependency(effect);
+
+ // Introduce Phi nodes for values that have differing input at merge points,
+ // potentially extending an existing Phi node if possible.
+ for (int i = 0; i < static_cast<int>(values_.size()); ++i) {
+ values_[i] = builder_->MergeValue(values_[i], other->values_[i], control);
+ }
+}
+
+
+void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned,
+ bool is_osr) {
+ int size = static_cast<int>(values()->size());
+
+ Node* control = builder_->NewLoop();
+ if (assigned == nullptr) {
+ // Assume that everything is updated in the loop.
+ for (int i = 0; i < size; ++i) {
+ Node* phi = builder_->NewPhi(1, values()->at(i), control);
+ values()->at(i) = phi;
+ }
+ } else {
+ // Only build phis for those locals assigned in this loop.
+ for (int i = 0; i < size; ++i) {
+ if (i < assigned->length() && !assigned->Contains(i)) continue;
+ Node* phi = builder_->NewPhi(1, values()->at(i), control);
+ values()->at(i) = phi;
+ }
+ }
+ Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
+ UpdateEffectDependency(effect);
+
+ if (is_osr) {
+ // Merge OSR values as inputs to the phis of the loop.
+ Graph* graph = builder_->graph();
+ Node* osr_loop_entry = builder_->graph()->NewNode(
+ builder_->common()->OsrLoopEntry(), graph->start(), graph->start());
+
+ builder_->MergeControl(control, osr_loop_entry);
+ builder_->MergeEffect(effect, osr_loop_entry, control);
+
+ for (int i = 0; i < size; ++i) {
+ Node* val = values()->at(i);
+ if (!IrOpcode::IsConstantOpcode(val->opcode())) {
+ Node* osr_value =
+ graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry);
+ values()->at(i) = builder_->MergeValue(val, osr_value, control);
+ }
+ }
+ }
+}
+
+
+Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) {
+ const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
+ Node** buffer = EnsureInputBufferSize(count + 1);
+ MemsetPointer(buffer, input, count);
+ buffer[count] = control;
+ return graph()->NewNode(phi_op, count + 1, buffer, true);
+}
+
+
+// TODO(mstarzinger): Revisit this once we have proper effect states.
+Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) {
+ const Operator* phi_op = common()->EffectPhi(count);
+ Node** buffer = EnsureInputBufferSize(count + 1);
+ MemsetPointer(buffer, input, count);
+ buffer[count] = control;
+ return graph()->NewNode(phi_op, count + 1, buffer, true);
+}
+
+
+Node* AstGraphBuilder::MergeControl(Node* control, Node* other) {
+ int inputs = control->op()->ControlInputCount() + 1;
+ if (control->opcode() == IrOpcode::kLoop) {
+ // Control node for loop exists, add input.
+ const Operator* op = common()->Loop(inputs);
+ control->AppendInput(graph_zone(), other);
+ control->set_op(op);
+ } else if (control->opcode() == IrOpcode::kMerge) {
+ // Control node for merge exists, add input.
+ const Operator* op = common()->Merge(inputs);
+ control->AppendInput(graph_zone(), other);
+ control->set_op(op);
+ } else {
+ // Control node is a singleton, introduce a merge.
+ const Operator* op = common()->Merge(inputs);
+ Node* inputs[] = {control, other};
+ control = graph()->NewNode(op, arraysize(inputs), inputs, true);
+ }
+ return control;
+}
+
+
+Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) {
+ int inputs = control->op()->ControlInputCount();
+ if (value->opcode() == IrOpcode::kEffectPhi &&
+ NodeProperties::GetControlInput(value) == control) {
+ // Phi already exists, add input.
+ value->set_op(common()->EffectPhi(inputs));
+ value->InsertInput(graph_zone(), inputs - 1, other);
+ } else if (value != other) {
+ // Phi does not exist yet, introduce one.
+ value = NewEffectPhi(inputs, value, control);
+ value->ReplaceInput(inputs - 1, other);
+ }
+ return value;
+}
+
+
+Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) {
+ int inputs = control->op()->ControlInputCount();
+ if (value->opcode() == IrOpcode::kPhi &&
+ NodeProperties::GetControlInput(value) == control) {
+ // Phi already exists, add input.
+ value->set_op(common()->Phi(kMachAnyTagged, inputs));
+ value->InsertInput(graph_zone(), inputs - 1, other);
+ } else if (value != other) {
+ // Phi does not exist yet, introduce one.
+ value = NewPhi(inputs, value, control);
+ value->ReplaceInput(inputs - 1, other);
+ }
+ return value;
+}
+
+
+Node* AstGraphBuilder::dead_control() {
+ if (!dead_control_.is_set()) {
+ Node* dead_node = graph()->NewNode(common()->Dead());
+ dead_control_.set(dead_node);
+ return dead_node;
+ }
+ return dead_control_.get();
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
« no previous file with comments | « src/compiler/ast-graph-builder.h ('k') | src/compiler/control-builders.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698