Commit ca3abde2 authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Variable liveness analysis for deopt.

This change introduces a liveness analyzer for local variables in frame states.

The main idea is to use the AstGraphBuilder::Environment class to build the control flow graph, and record local variable loads, stores and checkpoints in the CFG basic blocks (LivenessAnalyzerBlock class).

After the graph building finishes, we run a simple data flow analysis over the CFG to figure out liveness of each local variable at each checkpoint. Finally, we run a pass over all the checkpoints and replace dead local variables in the frame states with the 'undefined' value.

Performance numbers for Embenchen are below.

----------- box2d.js
Current --turbo-deoptimization: EmbenchenBox2d(RunTime): 11265 ms.
d8-master --turbo-deoptimization: EmbenchenBox2d(RunTime): 11768 ms.
d8-master: EmbenchenBox2d(RunTime): 10996 ms.
----------- bullet.js
Current --turbo-deoptimization: EmbenchenBullet(RunTime): 17049 ms.
d8-master --turbo-deoptimization: EmbenchenBullet(RunTime): 17384 ms.
d8-master: EmbenchenBullet(RunTime): 16153 ms.
----------- copy.js
Current --turbo-deoptimization: EmbenchenCopy(RunTime): 4877 ms.
d8-master --turbo-deoptimization: EmbenchenCopy(RunTime): 4938 ms.
d8-master: EmbenchenCopy(RunTime): 4940 ms.
----------- corrections.js
Current --turbo-deoptimization: EmbenchenCorrections(RunTime): 7068 ms.
d8-master --turbo-deoptimization: EmbenchenCorrections(RunTime): 6718 ms.
d8-master: EmbenchenCorrections(RunTime): 6858 ms.
----------- fannkuch.js
Current --turbo-deoptimization: EmbenchenFannkuch(RunTime): 4167 ms.
d8-master --turbo-deoptimization: EmbenchenFannkuch(RunTime): 4608 ms.
d8-master: EmbenchenFannkuch(RunTime): 4149 ms.
----------- fasta.js
Current --turbo-deoptimization: EmbenchenFasta(RunTime): 9981 ms.
d8-master --turbo-deoptimization: EmbenchenFasta(RunTime): 9848 ms.
d8-master: EmbenchenFasta(RunTime): 9640 ms.
----------- lua_binarytrees.js
Current --turbo-deoptimization: EmbenchenLuaBinaryTrees(RunTime): 11571 ms.
d8-master --turbo-deoptimization: EmbenchenLuaBinaryTrees(RunTime): 13089 ms.
d8-master: EmbenchenLuaBinaryTrees(RunTime): 10957 ms.
----------- memops.js
Current --turbo-deoptimization: EmbenchenMemOps(RunTime): 7766 ms.
d8-master --turbo-deoptimization: EmbenchenMemOps(RunTime): 7346 ms.
d8-master: EmbenchenMemOps(RunTime): 7738 ms.
----------- primes.js
Current --turbo-deoptimization: EmbenchenPrimes(RunTime): 7459 ms.
d8-master --turbo-deoptimization: EmbenchenPrimes(RunTime): 7453 ms.
d8-master: EmbenchenPrimes(RunTime): 7451 ms.
----------- skinning.js
Current --turbo-deoptimization: EmbenchenSkinning(RunTime): 15564 ms.
d8-master --turbo-deoptimization: EmbenchenSkinning(RunTime): 15611 ms.
d8-master: EmbenchenSkinning(RunTime): 15583 ms.
----------- zlib.js
Current --turbo-deoptimization: EmbenchenZLib(RunTime): 10825 ms.
d8-master --turbo-deoptimization: EmbenchenZLib(RunTime): 11180 ms.
d8-master: EmbenchenZLib(RunTime): 10823 ms.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#27232}
parent 55d05404
......@@ -594,6 +594,8 @@ source_set("v8_base") {
"src/compiler/linkage-impl.h",
"src/compiler/linkage.cc",
"src/compiler/linkage.h",
"src/compiler/liveness-analyzer.cc",
"src/compiler/liveness-analyzer.h",
"src/compiler/load-elimination.cc",
"src/compiler/load-elimination.h",
"src/compiler/loop-peeling.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(),
......
......@@ -7,6 +7,7 @@
#include "src/ast.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/liveness-analyzer.h"
#include "src/compiler/state-values-utils.h"
namespace v8 {
......@@ -101,6 +102,9 @@ class AstGraphBuilder : public AstVisitor {
// Cache for StateValues nodes for frame states.
StateValuesCache state_values_cache_;
// Analyzer of local variable liveness.
LivenessAnalyzer liveness_analyzer_;
// Growth increment for the temporary buffer used to construct input lists to
// new nodes.
static const int kInputBufferSizeIncrement = 64;
......@@ -121,6 +125,7 @@ class AstGraphBuilder : public AstVisitor {
Scope* current_scope() const;
Node* current_context() const;
Node* exit_control() const { return exit_control_; }
LivenessAnalyzer* liveness_analyzer() { return &liveness_analyzer_; }
void set_environment(Environment* env) { environment_ = env; }
void set_ast_context(AstContext* ctx) { ast_context_ = ctx; }
......@@ -212,6 +217,10 @@ class AstGraphBuilder : public AstVisitor {
// If so, record the stack height into the compilation and return {true}.
bool CheckOsrEntry(IterationStatement* stmt);
// Computes local variable liveness and replaces dead variables in
// frame states with the undefined values.
void ClearNonLiveSlotsInFrameStates();
// Helper to wrap a Handle<T> into a Unique<T>.
template <class T>
Unique<T> MakeUnique(Handle<T> object) {
......@@ -372,26 +381,10 @@ class AstGraphBuilder::Environment : public ZoneObject {
locals_count_;
}
// Operations on parameter or local variables. The parameter indices are
// shifted by 1 (receiver is parameter index -1 but environment index 0).
void Bind(Variable* variable, Node* node) {
DCHECK(variable->IsStackAllocated());
if (variable->IsParameter()) {
values()->at(variable->index() + 1) = node;
} else {
DCHECK(variable->IsStackLocal());
values()->at(variable->index() + parameters_count_) = node;
}
}
Node* Lookup(Variable* variable) {
DCHECK(variable->IsStackAllocated());
if (variable->IsParameter()) {
return values()->at(variable->index() + 1);
} else {
DCHECK(variable->IsStackLocal());
return values()->at(variable->index() + parameters_count_);
}
}
// Operations on parameter or local variables.
void Bind(Variable* variable, Node* node);
Node* Lookup(Variable* variable);
void MarkAllLocalsLive();
Node* Context() const { return contexts_.back(); }
void PushContext(Node* context) { contexts()->push_back(context); }
......@@ -474,7 +467,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
// Copies this environment at a loop header control-flow point.
Environment* CopyForLoop(BitVector* assigned, bool is_osr = false) {
PrepareForLoop(assigned, is_osr);
return Copy();
return CopyAndShareLiveness();
}
int ContextStackDepth() { return static_cast<int>(contexts_.size()); }
......@@ -483,6 +476,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
AstGraphBuilder* builder_;
int parameters_count_;
int locals_count_;
LivenessAnalyzerBlock* liveness_block_;
NodeVector values_;
NodeVector contexts_;
Node* control_dependency_;
......@@ -491,8 +485,9 @@ class AstGraphBuilder::Environment : public ZoneObject {
Node* locals_node_;
Node* stack_node_;
explicit Environment(const Environment* copy);
explicit Environment(Environment* copy);
Environment* Copy() { return new (zone()) Environment(this); }
Environment* CopyAndShareLiveness();
void UpdateStateValues(Node** state_values, int offset, int count);
void UpdateStateValuesWithCache(Node** state_values, int offset, int count);
Zone* zone() const { return builder_->local_zone(); }
......@@ -501,6 +496,7 @@ class AstGraphBuilder::Environment : public ZoneObject {
CommonOperatorBuilder* common() { return builder_->common(); }
NodeVector* values() { return &values_; }
NodeVector* contexts() { return &contexts_; }
LivenessAnalyzerBlock* liveness_block() { return liveness_block_; }
// Prepare environment to be used as loop header.
void PrepareForLoop(BitVector* assigned, bool is_osr = false);
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/liveness-analyzer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/state-values-utils.h"
namespace v8 {
namespace internal {
namespace compiler {
LivenessAnalyzer::LivenessAnalyzer(size_t local_count, Zone* zone)
: zone_(zone), blocks_(zone), local_count_(local_count), queue_(zone) {}
void LivenessAnalyzer::Print(std::ostream& os) {
for (auto block : blocks_) {
block->Print(os);
os << std::endl;
}
}
LivenessAnalyzerBlock* LivenessAnalyzer::NewBlock() {
LivenessAnalyzerBlock* result =
new (zone()->New(sizeof(LivenessAnalyzerBlock)))
LivenessAnalyzerBlock(blocks_.size(), local_count_, zone());
blocks_.push_back(result);
return result;
}
LivenessAnalyzerBlock* LivenessAnalyzer::NewBlock(
LivenessAnalyzerBlock* predecessor) {
LivenessAnalyzerBlock* result = NewBlock();
result->AddPredecessor(predecessor);
return result;
}
void LivenessAnalyzer::Queue(LivenessAnalyzerBlock* block) {
if (!block->IsQueued()) {
block->SetQueued();
queue_.push(block);
}
}
void LivenessAnalyzer::Run(NonLiveFrameStateSlotReplacer* replacer) {
if (local_count_ == 0) {
// No local variables => nothing to do.
return;
}
// Put all blocks into the queue.
DCHECK(queue_.empty());
for (auto block : blocks_) {
Queue(block);
}
// Compute the fix-point.
BitVector working_area(static_cast<int>(local_count_), zone_);
while (!queue_.empty()) {
LivenessAnalyzerBlock* block = queue_.front();
queue_.pop();
block->Process(&working_area, nullptr);
for (auto i = block->pred_begin(); i != block->pred_end(); i++) {
if ((*i)->UpdateLive(&working_area)) {
Queue(*i);
}
}
}
// Update the frame states according to the liveness.
for (auto block : blocks_) {
block->Process(&working_area, replacer);
}
}
LivenessAnalyzerBlock::LivenessAnalyzerBlock(size_t id, size_t local_count,
Zone* zone)
: entries_(zone),
predecessors_(zone),
live_(local_count == 0 ? 1 : static_cast<int>(local_count), zone),
queued_(false),
id_(id) {}
void LivenessAnalyzerBlock::Process(BitVector* result,
NonLiveFrameStateSlotReplacer* replacer) {
queued_ = false;
// Copy the bitvector to the target bit vector.
result->CopyFrom(live_);
for (auto i = entries_.rbegin(); i != entries_.rend(); i++) {
auto entry = *i;
switch (entry.kind()) {
case Entry::kLookup:
result->Add(entry.var());
break;
case Entry::kBind:
result->Remove(entry.var());
break;
case Entry::kCheckpoint:
if (replacer != nullptr) {
replacer->ClearNonLiveFrameStateSlots(entry.node(), result);
}
break;
}
}
}
bool LivenessAnalyzerBlock::UpdateLive(BitVector* working_area) {
return live_.UnionIsChanged(*working_area);
}
void NonLiveFrameStateSlotReplacer::ClearNonLiveFrameStateSlots(
Node* frame_state, BitVector* liveness) {
DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
Node* locals_state = frame_state->InputAt(1);
DCHECK_EQ(locals_state->opcode(), IrOpcode::kStateValues);
int count = static_cast<int>(StateValuesAccess(locals_state).size());
DCHECK_EQ(count == 0 ? 1 : count, liveness->length());
for (int i = 0; i < count; i++) {
bool live = liveness->Contains(i) || permanently_live_.Contains(i);
if (!live || locals_state->InputAt(i) != replacement_node_) {
Node* new_values = ClearNonLiveStateValues(locals_state, liveness);
frame_state->ReplaceInput(1, new_values);
break;
}
}
}
Node* NonLiveFrameStateSlotReplacer::ClearNonLiveStateValues(
Node* values, BitVector* liveness) {
DCHECK(inputs_buffer_.empty());
for (Node* node : StateValuesAccess(values)) {
// Index of the next variable is its furure index in the inputs buffer,
// i.e., the buffer's size.
int var = static_cast<int>(inputs_buffer_.size());
bool live = liveness->Contains(var) || permanently_live_.Contains(var);
inputs_buffer_.push_back(live ? node : replacement_node_);
}
Node* result = state_values_cache()->GetNodeForValues(
inputs_buffer_.empty() ? nullptr : &(inputs_buffer_.front()),
inputs_buffer_.size());
inputs_buffer_.clear();
return result;
}
void LivenessAnalyzerBlock::Print(std::ostream& os) {
os << "Block " << id();
bool first = true;
for (LivenessAnalyzerBlock* pred : predecessors_) {
if (!first) {
os << ", ";
} else {
os << "; predecessors: ";
first = false;
}
os << pred->id();
}
os << std::endl;
for (auto entry : entries_) {
os << " ";
switch (entry.kind()) {
case Entry::kLookup:
os << "- Lookup " << entry.var() << std::endl;
break;
case Entry::kBind:
os << "- Bind " << entry.var() << std::endl;
break;
case Entry::kCheckpoint:
os << "- Checkpoint " << entry.node()->id() << std::endl;
break;
}
}
if (live_.length() > 0) {
os << " Live set: ";
for (int i = 0; i < live_.length(); i++) {
os << (live_.Contains(i) ? "L" : ".");
}
os << std::endl;
}
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_LIVENESS_ANAYZER_H_
#define V8_COMPILER_LIVENESS_ANAYZER_H_
#include "src/bit-vector.h"
#include "src/compiler/node.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
namespace compiler {
class LivenessAnalyzerBlock;
class Node;
class StateValuesCache;
class NonLiveFrameStateSlotReplacer {
public:
void ClearNonLiveFrameStateSlots(Node* frame_state, BitVector* liveness);
NonLiveFrameStateSlotReplacer(StateValuesCache* state_values_cache,
Node* replacement, size_t local_count,
Zone* local_zone)
: replacement_node_(replacement),
state_values_cache_(state_values_cache),
local_zone_(local_zone),
permanently_live_(local_count == 0 ? 1 : static_cast<int>(local_count),
local_zone),
inputs_buffer_(local_zone) {}
void MarkPermanentlyLive(int var) { permanently_live_.Add(var); }
private:
Node* ClearNonLiveStateValues(Node* frame_state, BitVector* liveness);
StateValuesCache* state_values_cache() { return state_values_cache_; }
Zone* local_zone() { return local_zone_; }
// Node that replaces dead values.
Node* replacement_node_;
// Reference to state values cache so that we can create state values
// nodes.
StateValuesCache* state_values_cache_;
Zone* local_zone_;
BitVector permanently_live_;
NodeVector inputs_buffer_;
};
class LivenessAnalyzer {
public:
LivenessAnalyzer(size_t local_count, Zone* zone);
LivenessAnalyzerBlock* NewBlock();
LivenessAnalyzerBlock* NewBlock(LivenessAnalyzerBlock* predecessor);
void Run(NonLiveFrameStateSlotReplacer* relaxer);
Zone* zone() { return zone_; }
void Print(std::ostream& os);
size_t local_count() { return local_count_; }
private:
void Queue(LivenessAnalyzerBlock* block);
Zone* zone_;
ZoneDeque<LivenessAnalyzerBlock*> blocks_;
size_t local_count_;
ZoneQueue<LivenessAnalyzerBlock*> queue_;
};
class LivenessAnalyzerBlock {
public:
friend class LivenessAnalyzer;
void Lookup(int var) { entries_.push_back(Entry(Entry::kLookup, var)); }
void Bind(int var) { entries_.push_back(Entry(Entry::kBind, var)); }
void Checkpoint(Node* node) { entries_.push_back(Entry(node)); }
void AddPredecessor(LivenessAnalyzerBlock* b) { predecessors_.push_back(b); }
private:
class Entry {
public:
enum Kind { kBind, kLookup, kCheckpoint };
Kind kind() const { return kind_; }
Node* node() const {
DCHECK(kind() == kCheckpoint);
return node_;
}
int var() const {
DCHECK(kind() != kCheckpoint);
return var_;
}
explicit Entry(Node* node) : kind_(kCheckpoint), var_(-1), node_(node) {}
Entry(Kind kind, int var) : kind_(kind), var_(var), node_(nullptr) {
DCHECK(kind != kCheckpoint);
}
private:
Kind kind_;
int var_;
Node* node_;
};
LivenessAnalyzerBlock(size_t id, size_t local_count, Zone* zone);
void Process(BitVector* result, NonLiveFrameStateSlotReplacer* relaxer);
bool UpdateLive(BitVector* working_area);
void SetQueued() { queued_ = true; }
bool IsQueued() { return queued_; }
ZoneDeque<LivenessAnalyzerBlock*>::const_iterator pred_begin() {
return predecessors_.begin();
}
ZoneDeque<LivenessAnalyzerBlock*>::const_iterator pred_end() {
return predecessors_.end();
}
size_t id() { return id_; }
void Print(std::ostream& os);
ZoneDeque<Entry> entries_;
ZoneDeque<LivenessAnalyzerBlock*> predecessors_;
BitVector live_;
bool queued_;
size_t id_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_AST_GRAPH_BUILDER_H_
......@@ -170,6 +170,11 @@ Node* StateValuesCache::BuildTree(ValueArrayIterator* it, size_t max_height) {
Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) {
#if DEBUG
for (size_t i = 0; i < count; i++) {
DCHECK_NE(values[i]->opcode(), IrOpcode::kStateValues);
}
#endif
if (count == 0) {
return GetEmptyStateValues();
}
......
......@@ -297,6 +297,8 @@ DEFINE_BOOL(collect_megamorphic_maps_from_stub_cache, true,
"crankshaft harvests type feedback from stub cache")
DEFINE_BOOL(hydrogen_stats, false, "print statistics for hydrogen")
DEFINE_BOOL(trace_check_elimination, false, "trace check elimination phase")
DEFINE_BOOL(trace_environment_liveness, false,
"trace liveness of local variable slots")
DEFINE_BOOL(trace_hydrogen, false, "trace generated hydrogen to file")
DEFINE_STRING(trace_hydrogen_filter, "*", "hydrogen tracing filter")
DEFINE_BOOL(trace_hydrogen_stubs, false, "trace generated hydrogen for stubs")
......
This diff is collapsed.
......@@ -57,6 +57,7 @@
'compiler/js-intrinsic-lowering-unittest.cc',
'compiler/js-operator-unittest.cc',
'compiler/js-typed-lowering-unittest.cc',
'compiler/liveness-analyzer-unittest.cc',
'compiler/load-elimination-unittest.cc',
'compiler/loop-peeling-unittest.cc',
'compiler/machine-operator-reducer-unittest.cc',
......
......@@ -478,6 +478,8 @@
'../../src/compiler/linkage-impl.h',
'../../src/compiler/linkage.cc',
'../../src/compiler/linkage.h',
'../../src/compiler/liveness-analyzer.cc',
'../../src/compiler/liveness-analyzer.h',
'../../src/compiler/load-elimination.cc',
'../../src/compiler/load-elimination.h',
'../../src/compiler/loop-analysis.cc',
......
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