| Index: src/compiler/ast-graph-builder.cc
|
| diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
|
| index 63696e45cd2e7f2dbe932a2ac415e1c76e30053e..00d09f3d847c969579b3da6809158557a6ab9bce 100644
|
| --- a/src/compiler/ast-graph-builder.cc
|
| +++ b/src/compiler/ast-graph-builder.cc
|
| @@ -8,6 +8,7 @@
|
| #include "src/compiler/ast-loop-assignment-analyzer.h"
|
| #include "src/compiler/control-builders.h"
|
| #include "src/compiler/linkage.h"
|
| +#include "src/compiler/liveness-analyzer.h"
|
| #include "src/compiler/machine-operator.h"
|
| #include "src/compiler/node-matchers.h"
|
| #include "src/compiler/node-properties.h"
|
| @@ -394,7 +395,9 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
|
| input_buffer_(nullptr),
|
| exit_control_(nullptr),
|
| loop_assignment_analysis_(loop),
|
| - state_values_cache_(jsgraph) {
|
| + state_values_cache_(jsgraph),
|
| + liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
|
| + local_zone) {
|
| InitializeAstVisitor(info->isolate(), local_zone);
|
| }
|
|
|
| @@ -480,6 +483,10 @@ bool AstGraphBuilder::CreateGraph(bool constant_context, bool stack_check) {
|
| // Finish the basic structure of the graph.
|
| graph()->SetEnd(graph()->NewNode(common()->End(), exit_control()));
|
|
|
| + // Compute local variable liveness information and use it to relax
|
| + // frame states.
|
| + ClearNonLiveSlotsInFrameStates();
|
| +
|
| // Failures indicated by stack overflow.
|
| return !HasStackOverflow();
|
| }
|
| @@ -530,6 +537,24 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) {
|
| }
|
|
|
|
|
| +void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
|
| + if (!FLAG_analyze_environment_liveness) return;
|
| +
|
| + NonLiveFrameStateSlotReplacer replacer(
|
| + &state_values_cache_, jsgraph()->UndefinedConstant(),
|
| + liveness_analyzer()->local_count(), local_zone());
|
| + Variable* arguments = info()->scope()->arguments();
|
| + if (arguments != nullptr && arguments->IsStackAllocated()) {
|
| + replacer.MarkPermanentlyLive(arguments->index());
|
| + }
|
| + liveness_analyzer()->Run(&replacer);
|
| + if (FLAG_trace_environment_liveness) {
|
| + OFStream os(stdout);
|
| + liveness_analyzer()->Print(os);
|
| + }
|
| +}
|
| +
|
| +
|
| // Left-hand side can only be a property, a global or a variable slot.
|
| enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
|
|
|
| @@ -552,6 +577,7 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
|
| : builder_(builder),
|
| parameters_count_(scope->num_parameters() + 1),
|
| locals_count_(scope->num_stack_slots()),
|
| + liveness_block_(builder_->liveness_analyzer()->NewBlock()),
|
| values_(builder_->local_zone()),
|
| contexts_(builder_->local_zone()),
|
| control_dependency_(control_dependency),
|
| @@ -580,8 +606,7 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
|
| }
|
|
|
|
|
| -AstGraphBuilder::Environment::Environment(
|
| - const AstGraphBuilder::Environment* copy)
|
| +AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy)
|
| : builder_(copy->builder_),
|
| parameters_count_(copy->parameters_count_),
|
| locals_count_(copy->locals_count_),
|
| @@ -598,6 +623,65 @@ AstGraphBuilder::Environment::Environment(
|
| contexts_.reserve(copy->contexts_.size());
|
| contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
|
| copy->contexts_.end());
|
| +
|
| + if (FLAG_analyze_environment_liveness) {
|
| + // Split the liveness blocks.
|
| + copy->liveness_block_ =
|
| + builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
|
| + liveness_block_ =
|
| + builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
|
| + }
|
| +}
|
| +
|
| +
|
| +void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
|
| + DCHECK(variable->IsStackAllocated());
|
| + if (variable->IsParameter()) {
|
| + // The parameter indices are shifted by 1 (receiver is parameter
|
| + // index -1 but environment index 0).
|
| + values()->at(variable->index() + 1) = node;
|
| + } else {
|
| + DCHECK(variable->IsStackLocal());
|
| + values()->at(variable->index() + parameters_count_) = node;
|
| + if (FLAG_analyze_environment_liveness) {
|
| + liveness_block()->Bind(variable->index());
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
|
| + DCHECK(variable->IsStackAllocated());
|
| + if (variable->IsParameter()) {
|
| + // The parameter indices are shifted by 1 (receiver is parameter
|
| + // index -1 but environment index 0).
|
| + return values()->at(variable->index() + 1);
|
| + } else {
|
| + DCHECK(variable->IsStackLocal());
|
| + if (FLAG_analyze_environment_liveness) {
|
| + liveness_block()->Lookup(variable->index());
|
| + }
|
| + return values()->at(variable->index() + parameters_count_);
|
| + }
|
| +}
|
| +
|
| +
|
| +void AstGraphBuilder::Environment::MarkAllLocalsLive() {
|
| + if (FLAG_analyze_environment_liveness) {
|
| + for (int i = 0; i < locals_count_; i++) {
|
| + liveness_block()->Lookup(i);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +AstGraphBuilder::Environment*
|
| +AstGraphBuilder::Environment::CopyAndShareLiveness() {
|
| + Environment* env = new (zone()) Environment(this);
|
| + if (FLAG_analyze_environment_liveness) {
|
| + env->liveness_block_ = liveness_block();
|
| + }
|
| + return env;
|
| }
|
|
|
|
|
| @@ -642,9 +726,13 @@ Node* AstGraphBuilder::Environment::Checkpoint(
|
|
|
| const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
|
|
|
| - return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
|
| - builder()->current_context(),
|
| - builder()->jsgraph()->UndefinedConstant());
|
| + Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
|
| + stack_node_, builder()->current_context(),
|
| + builder()->jsgraph()->UndefinedConstant());
|
| + if (FLAG_analyze_environment_liveness) {
|
| + liveness_block()->Checkpoint(result);
|
| + }
|
| + return result;
|
| }
|
|
|
|
|
| @@ -1333,6 +1421,7 @@ void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
| // TODO(turbofan): Do we really need a separate reloc-info for this?
|
| Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
|
| PrepareFrameState(node, stmt->DebugBreakId());
|
| + environment()->MarkAllLocalsLive();
|
| }
|
|
|
|
|
| @@ -3174,6 +3263,7 @@ void AstGraphBuilder::Environment::Merge(Environment* other) {
|
| if (this->IsMarkedAsUnreachable()) {
|
| Node* other_control = other->control_dependency_;
|
| Node* inputs[] = {other_control};
|
| + liveness_block_ = other->liveness_block_;
|
| control_dependency_ =
|
| graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
|
| effect_dependency_ = other->effect_dependency_;
|
| @@ -3185,6 +3275,18 @@ void AstGraphBuilder::Environment::Merge(Environment* other) {
|
| return;
|
| }
|
|
|
| + // Record the merge for the local variable liveness calculation.
|
| + // Unfortunately, we have to mirror the logic in the MergeControl method:
|
| + // connect before merge or loop, or create a new merge otherwise.
|
| + if (FLAG_analyze_environment_liveness) {
|
| + if (GetControlDependency()->opcode() != IrOpcode::kLoop &&
|
| + GetControlDependency()->opcode() != IrOpcode::kMerge) {
|
| + liveness_block_ =
|
| + builder_->liveness_analyzer()->NewBlock(liveness_block());
|
| + }
|
| + liveness_block()->AddPredecessor(other->liveness_block());
|
| + }
|
| +
|
| // 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(),
|
|
|