Commit 2bf71f88 authored by leszeks's avatar leszeks Committed by Commit bot

[ignition/turbo] Perform liveness analysis on the bytecodes

Replaces the graph-based liveness analyzer in the bytecode graph builder
with an initial bytecode-based liveness analysis pass, which is added to
the existing loop extent analysis.

Now the StateValues in the graph have their inputs initialised to
optimized_out, rather than being modified after the graph is built.

Review-Url: https://codereview.chromium.org/2523893003
Cr-Commit-Position: refs/heads/master@{#41355}
parent 5fd2b712
......@@ -1024,6 +1024,8 @@ v8_source_set("v8_base") {
"src/compiler/bytecode-analysis.h",
"src/compiler/bytecode-graph-builder.cc",
"src/compiler/bytecode-graph-builder.h",
"src/compiler/bytecode-liveness-map.cc",
"src/compiler/bytecode-liveness-map.h",
"src/compiler/c-linkage.cc",
"src/compiler/checkpoint-elimination.cc",
"src/compiler/checkpoint-elimination.h",
......
......@@ -10,6 +10,7 @@ include_rules = [
"+src/heap/heap-inl.h",
"-src/inspector",
"-src/interpreter",
"+src/interpreter/bytecode-array-accessor.h",
"+src/interpreter/bytecode-array-iterator.h",
"+src/interpreter/bytecode-array-reverse-iterator.h",
"+src/interpreter/bytecode-decoder.h",
......
This diff is collapsed.
......@@ -5,6 +5,9 @@
#ifndef V8_COMPILER_BYTECODE_ANALYSIS_H_
#define V8_COMPILER_BYTECODE_ANALYSIS_H_
#include "src/base/hashmap.h"
#include "src/bit-vector.h"
#include "src/compiler/bytecode-liveness-map.h"
#include "src/handles.h"
#include "src/zone/zone-containers.h"
......@@ -15,9 +18,10 @@ class BytecodeArray;
namespace compiler {
class BytecodeAnalysis BASE_EMBEDDED {
class V8_EXPORT_PRIVATE BytecodeAnalysis BASE_EMBEDDED {
public:
BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, Zone* zone);
BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, Zone* zone,
bool do_liveness_analysis);
// Analyze the bytecodes to find the loop ranges and nesting. No other
// methods in this class return valid information until this has been called.
......@@ -32,13 +36,33 @@ class BytecodeAnalysis BASE_EMBEDDED {
// at {header_offset}, or -1 for outer-most loops.
int GetParentLoopFor(int header_offset) const;
// Gets the in-liveness for the bytecode at {offset}. The liveness bit vector
// represents the liveness of the registers and the accumulator, with the last
// bit being the accumulator liveness bit, and so is (register count + 1) bits
// long.
const BitVector* GetInLivenessFor(int offset) const;
// Gets the out-liveness for the bytecode at {offset}. The liveness bit vector
// represents the liveness of the registers and the accumulator, with the last
// bit being the accumulator liveness bit, and so is (register count + 1) bits
// long.
const BitVector* GetOutLivenessFor(int offset) const;
std::ostream& PrintLivenessTo(std::ostream& os) const;
private:
void PushLoop(int loop_header, int loop_end);
#if DEBUG
bool LivenessIsValid();
#endif
Zone* zone() const { return zone_; }
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
private:
Handle<BytecodeArray> bytecode_array_;
bool do_liveness_analysis_;
Zone* zone_;
ZoneStack<int> loop_stack_;
......@@ -46,6 +70,8 @@ class BytecodeAnalysis BASE_EMBEDDED {
ZoneMap<int, int> end_to_header_;
ZoneMap<int, int> header_to_parent_;
BytecodeLivenessMap liveness_map_;
DISALLOW_COPY_AND_ASSIGN(BytecodeAnalysis);
};
......
This diff is collapsed.
......@@ -135,10 +135,6 @@ class BytecodeGraphBuilder {
// Conceptually this frame state is "after" a given operation.
void PrepareFrameState(Node* node, OutputFrameStateCombine combine);
// Computes register liveness and replaces dead ones in frame states with the
// undefined values.
void ClearNonLiveSlotsInFrameStates();
void BuildCreateArguments(CreateArgumentsType type);
Node* BuildLoadGlobal(Handle<Name> name, uint32_t feedback_slot_index,
TypeofMode typeof_mode);
......@@ -260,8 +256,6 @@ class BytecodeGraphBuilder {
bytecode_analysis_ = bytecode_analysis;
}
LivenessAnalyzer* liveness_analyzer() { return &liveness_analyzer_; }
bool IsLivenessAnalysisEnabled() const {
return this->is_liveness_analysis_enabled_;
}
......@@ -307,9 +301,6 @@ class BytecodeGraphBuilder {
StateValuesCache state_values_cache_;
// Analyzer of register liveness.
LivenessAnalyzer liveness_analyzer_;
// The Turbofan source position table, to be populated.
SourcePositionTable* source_positions_;
......
// Copyright 2016 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/bytecode-liveness-map.h"
namespace v8 {
namespace internal {
namespace compiler {
Liveness::Liveness(int size, Zone* zone)
: in(new (zone) BitVector(size, zone)),
out(new (zone) BitVector(size, zone)) {}
BytecodeLivenessMap::BytecodeLivenessMap(int bytecode_size, Zone* zone)
: liveness_map_(base::bits::RoundUpToPowerOfTwo32(bytecode_size / 4 + 1),
base::KeyEqualityMatcher<int>(),
ZoneAllocationPolicy(zone)) {}
uint32_t OffsetHash(int offset) { return offset; }
Liveness& BytecodeLivenessMap::InitializeLiveness(int offset, int size,
Zone* zone) {
return liveness_map_
.LookupOrInsert(offset, OffsetHash(offset),
[&]() { return Liveness(size, zone); },
ZoneAllocationPolicy(zone))
->value;
}
Liveness& BytecodeLivenessMap::GetLiveness(int offset) {
return liveness_map_.Lookup(offset, OffsetHash(offset))->value;
}
const Liveness& BytecodeLivenessMap::GetLiveness(int offset) const {
return liveness_map_.Lookup(offset, OffsetHash(offset))->value;
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2016 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_BYTECODE_LIVENESS_MAP_H_
#define V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
#include "src/base/hashmap.h"
#include "src/bit-vector.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
class Zone;
namespace compiler {
struct Liveness {
BitVector* in;
BitVector* out;
Liveness(int size, Zone* zone);
};
class V8_EXPORT_PRIVATE BytecodeLivenessMap {
public:
BytecodeLivenessMap(int size, Zone* zone);
Liveness& InitializeLiveness(int offset, int size, Zone* zone);
Liveness& GetLiveness(int offset);
const Liveness& GetLiveness(int offset) const;
BitVector* GetInLiveness(int offset) { return GetLiveness(offset).in; }
const BitVector* GetInLiveness(int offset) const {
return GetLiveness(offset).in;
}
BitVector* GetOutLiveness(int offset) { return GetLiveness(offset).out; }
const BitVector* GetOutLiveness(int offset) const {
return GetLiveness(offset).out;
}
private:
base::TemplateHashMapImpl<int, Liveness, base::KeyEqualityMatcher<int>,
ZoneAllocationPolicy>
liveness_map_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
......@@ -189,6 +189,12 @@ int BytecodeArrayAccessor::GetJumpTargetOffset() const {
}
}
std::ostream& BytecodeArrayAccessor::PrintTo(std::ostream& os) const {
return BytecodeDecoder::Decode(
os, bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_,
bytecode_array()->parameter_count());
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -48,6 +48,8 @@ class V8_EXPORT_PRIVATE BytecodeArrayAccessor {
// not for a jump or conditional jump.
int GetJumpTargetOffset() const;
std::ostream& PrintTo(std::ostream& os) const;
private:
bool OffsetInBounds() const;
......
......@@ -722,22 +722,25 @@ void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt,
LoopBuilder* loop_builder) {
// Recall that stmt->yield_count() is always zero inside ordinary
// (i.e. non-generator) functions.
if (stmt->yield_count() == 0) {
loop_builder->LoopHeader();
} else {
// Collect all labels for generator resume points within the loop (if any)
// so that they can be bound to the loop header below. Also create fresh
// labels for these resume points, to be used inside the loop.
ZoneVector<BytecodeLabel> resume_points_in_loop(zone());
size_t first_yield = stmt->first_yield_id();
DCHECK_LE(first_yield + stmt->yield_count(),
generator_resume_points_.size());
for (size_t id = first_yield; id < first_yield + stmt->yield_count();
id++) {
auto& label = generator_resume_points_[id];
resume_points_in_loop.push_back(label);
generator_resume_points_[id] = BytecodeLabel();
}
loop_builder->LoopHeader(&resume_points_in_loop);
// Collect all labels for generator resume points within the loop (if any) so
// that they can be bound to the loop header below. Also create fresh labels
// for these resume points, to be used inside the loop.
ZoneVector<BytecodeLabel> resume_points_in_loop(zone());
size_t first_yield = stmt->first_yield_id();
DCHECK_LE(first_yield + stmt->yield_count(), generator_resume_points_.size());
for (size_t id = first_yield; id < first_yield + stmt->yield_count(); id++) {
auto& label = generator_resume_points_[id];
resume_points_in_loop.push_back(label);
generator_resume_points_[id] = BytecodeLabel();
}
loop_builder->LoopHeader(&resume_points_in_loop);
if (stmt->yield_count() > 0) {
// If we are not resuming, fall through to loop body.
// If we are resuming, perform state dispatch.
BytecodeLabel not_resuming;
......
......@@ -17,7 +17,7 @@ class BytecodeArrayBuilder;
// label is bound, it represents a known position in the bytecode
// array. For labels that are forward references there can be at most
// one reference whilst it is unbound.
class BytecodeLabel final {
class V8_EXPORT_PRIVATE BytecodeLabel final {
public:
BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
......@@ -54,7 +54,7 @@ class BytecodeLabel final {
};
// Class representing a branch target of multiple jumps.
class BytecodeLabels {
class V8_EXPORT_PRIVATE BytecodeLabels {
public:
explicit BytecodeLabels(Zone* zone) : labels_(zone) {}
......
......@@ -471,6 +471,12 @@ class V8_EXPORT_PRIVATE Bytecodes final {
IsConditionalJumpConstant(bytecode);
}
// Returns true if the bytecode is an unconditional jump.
static CONSTEXPR bool IsUnconditionalJump(Bytecode bytecode) {
return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpConstant ||
bytecode == Bytecode::kJumpLoop;
}
// Returns true if the bytecode is a jump or a conditional jump taking
// an immediate byte operand (OperandType::kImm).
static CONSTEXPR bool IsJumpImmediate(Bytecode bytecode) {
......@@ -500,6 +506,12 @@ class V8_EXPORT_PRIVATE Bytecodes final {
return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode);
}
// Returns true if the bytecode is a forward jump or conditional jump taking
// any kind of operand.
static CONSTEXPR bool IsForwardJump(Bytecode bytecode) {
return bytecode != Bytecode::kJumpLoop && IsJump(bytecode);
}
// Returns true if the bytecode is a conditional jump, a jump, or a return.
static CONSTEXPR bool IsJumpOrReturn(Bytecode bytecode) {
return bytecode == Bytecode::kReturn || IsJump(bytecode);
......
......@@ -55,8 +55,10 @@ void LoopBuilder::LoopHeader(ZoneVector<BytecodeLabel>* additional_labels) {
// and misplaced between the headers.
DCHECK(break_labels_.empty() && continue_labels_.empty());
builder()->Bind(&loop_header_);
for (auto& label : *additional_labels) {
builder()->Bind(&label);
if (additional_labels != nullptr) {
for (auto& label : *additional_labels) {
builder()->Bind(&label);
}
}
}
......
......@@ -14,7 +14,7 @@ namespace v8 {
namespace internal {
namespace interpreter {
class ControlFlowBuilder BASE_EMBEDDED {
class V8_EXPORT_PRIVATE ControlFlowBuilder BASE_EMBEDDED {
public:
explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
: builder_(builder) {}
......@@ -29,7 +29,8 @@ class ControlFlowBuilder BASE_EMBEDDED {
DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
};
class BreakableControlFlowBuilder : public ControlFlowBuilder {
class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
: public ControlFlowBuilder {
public:
explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
: ControlFlowBuilder(builder), break_labels_(builder->zone()) {}
......@@ -63,7 +64,8 @@ class BreakableControlFlowBuilder : public ControlFlowBuilder {
// Class to track control flow for block statements (which can break in JS).
class BlockBuilder final : public BreakableControlFlowBuilder {
class V8_EXPORT_PRIVATE BlockBuilder final
: public BreakableControlFlowBuilder {
public:
explicit BlockBuilder(BytecodeArrayBuilder* builder)
: BreakableControlFlowBuilder(builder) {}
......@@ -77,7 +79,7 @@ class BlockBuilder final : public BreakableControlFlowBuilder {
// A class to help with co-ordinating break and continue statements with
// their loop.
class LoopBuilder final : public BreakableControlFlowBuilder {
class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
public:
explicit LoopBuilder(BytecodeArrayBuilder* builder)
: BreakableControlFlowBuilder(builder),
......@@ -85,7 +87,7 @@ class LoopBuilder final : public BreakableControlFlowBuilder {
header_labels_(builder->zone()) {}
~LoopBuilder();
void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels = nullptr);
void JumpToHeader(int loop_depth);
void BindContinueTarget();
void EndLoop();
......@@ -109,7 +111,8 @@ class LoopBuilder final : public BreakableControlFlowBuilder {
// A class to help with co-ordinating break statements with their switch.
class SwitchBuilder final : public BreakableControlFlowBuilder {
class V8_EXPORT_PRIVATE SwitchBuilder final
: public BreakableControlFlowBuilder {
public:
explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
: BreakableControlFlowBuilder(builder),
......@@ -139,7 +142,7 @@ class SwitchBuilder final : public BreakableControlFlowBuilder {
// A class to help with co-ordinating control flow in try-catch statements.
class TryCatchBuilder final : public ControlFlowBuilder {
class V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder {
public:
explicit TryCatchBuilder(BytecodeArrayBuilder* builder,
HandlerTable::CatchPrediction catch_prediction)
......@@ -160,7 +163,7 @@ class TryCatchBuilder final : public ControlFlowBuilder {
// A class to help with co-ordinating control flow in try-finally statements.
class TryFinallyBuilder final : public ControlFlowBuilder {
class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
public:
explicit TryFinallyBuilder(BytecodeArrayBuilder* builder,
HandlerTable::CatchPrediction catch_prediction)
......
......@@ -19,7 +19,7 @@ class Isolate;
namespace interpreter {
// A helper class for constructing exception handler tables for the interpreter.
class HandlerTableBuilder final BASE_EMBEDDED {
class V8_EXPORT_PRIVATE HandlerTableBuilder final BASE_EMBEDDED {
public:
explicit HandlerTableBuilder(Zone* zone);
......
......@@ -550,10 +550,12 @@
'compiler/basic-block-instrumentor.h',
'compiler/branch-elimination.cc',
'compiler/branch-elimination.h',
'compiler/bytecode-graph-builder.cc',
'compiler/bytecode-graph-builder.h',
'compiler/bytecode-analysis.cc',
'compiler/bytecode-analysis.h',
'compiler/bytecode-graph-builder.cc',
'compiler/bytecode-graph-builder.h',
'compiler/bytecode-liveness-map.cc',
'compiler/bytecode-liveness-map.h',
'compiler/c-linkage.cc',
'compiler/checkpoint-elimination.cc',
'compiler/checkpoint-elimination.h',
......
......@@ -24,6 +24,8 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Flags: --noanalyze-environment-liveness
Debug = debug.Debug
......
......@@ -24,6 +24,8 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Flags: --noanalyze-environment-liveness
Debug = debug.Debug
......
// 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.
//
// Flags: --noanalyze-environment-liveness
Debug = debug.Debug
......
// Copyright 2012 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.
//
// Flags: --noanalyze-environment-liveness
'use strict';
......
......@@ -24,6 +24,8 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Flags: --noanalyze-environment-liveness
// Test that a variable in the local scope that shadows a context-allocated
......
// Copyright 2016 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.
//
// Flags: --noanalyze-environment-liveness
var Debug = debug.Debug;
......
......@@ -24,7 +24,8 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Flags: --noanalyze-environment-liveness
Debug = debug.Debug
......
......@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-debug-as debug
// Flags: --expose-debug-as debug --noanalyze-environment-liveness
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
......
......@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-debug-as debug
// Flags: --expose-debug-as debug --noanalyze-environment-liveness
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
......
......@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-debug-as debug --allow-natives-syntax
// Flags: --expose-debug-as debug --allow-natives-syntax --noanalyze-environment-liveness
// The functions used for testing backtraces. They are at the top to make the
// testing of source line/column easier.
......
......@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-debug-as debug --allow-natives-syntax
// Flags: --expose-debug-as debug --allow-natives-syntax --noanalyze-environment-liveness
// The functions used for testing backtraces. They are at the top to make the
// testing of source line/column easier.
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
// Flags: --expose-debug-as debug --noanalyze-environment-liveness
var Debug = debug.Debug;
......
......@@ -3,7 +3,7 @@
// found in the LICENSE file.
// MODULE
// Flags: --expose-debug-as debug --allow-natives-syntax
// Flags: --expose-debug-as debug --allow-natives-syntax --noanalyze-environment-liveness
// These tests are copied from mjsunit/debug-scopes.js and adapted for modules.
......
......@@ -31,6 +31,7 @@ v8_executable("unittests") {
"compiler-dispatcher/compiler-dispatcher-job-unittest.cc",
"compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc",
"compiler/branch-elimination-unittest.cc",
"compiler/bytecode-analysis-unittest.cc",
"compiler/checkpoint-elimination-unittest.cc",
"compiler/common-operator-reducer-unittest.cc",
"compiler/common-operator-unittest.cc",
......
This diff is collapsed.
......@@ -27,6 +27,7 @@
'cancelable-tasks-unittest.cc',
'char-predicates-unittest.cc',
'compiler/branch-elimination-unittest.cc',
'compiler/bytecode-analysis-unittest.cc',
'compiler/checkpoint-elimination-unittest.cc',
'compiler/common-operator-reducer-unittest.cc',
'compiler/common-operator-unittest.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