[ignition] Replace branch+loop analysis with a single pass
Now that we have a JumpLoop bytecode, we can heavily simplify the branch/loop analysis by assuming that only JumpLoop bytecodes are backwards edges, and performing the loop analysis as a single (backwards) pass. This allows us to get rid of the branch analysis entirely, and builds a framework to do liveness analysis in the same pass. Review-Url: https://codereview.chromium.org/2519983002 Cr-Commit-Position: refs/heads/master@{#41194}
This commit is contained in:
parent
7a1ad0c581
commit
292c4a0a2a
6
BUILD.gn
6
BUILD.gn
@ -1018,12 +1018,10 @@ v8_source_set("v8_base") {
|
|||||||
"src/compiler/basic-block-instrumentor.h",
|
"src/compiler/basic-block-instrumentor.h",
|
||||||
"src/compiler/branch-elimination.cc",
|
"src/compiler/branch-elimination.cc",
|
||||||
"src/compiler/branch-elimination.h",
|
"src/compiler/branch-elimination.h",
|
||||||
"src/compiler/bytecode-branch-analysis.cc",
|
"src/compiler/bytecode-analysis.cc",
|
||||||
"src/compiler/bytecode-branch-analysis.h",
|
"src/compiler/bytecode-analysis.h",
|
||||||
"src/compiler/bytecode-graph-builder.cc",
|
"src/compiler/bytecode-graph-builder.cc",
|
||||||
"src/compiler/bytecode-graph-builder.h",
|
"src/compiler/bytecode-graph-builder.h",
|
||||||
"src/compiler/bytecode-loop-analysis.cc",
|
|
||||||
"src/compiler/bytecode-loop-analysis.h",
|
|
||||||
"src/compiler/c-linkage.cc",
|
"src/compiler/c-linkage.cc",
|
||||||
"src/compiler/checkpoint-elimination.cc",
|
"src/compiler/checkpoint-elimination.cc",
|
||||||
"src/compiler/checkpoint-elimination.h",
|
"src/compiler/checkpoint-elimination.h",
|
||||||
|
1
src/DEPS
1
src/DEPS
@ -11,6 +11,7 @@ include_rules = [
|
|||||||
"-src/inspector",
|
"-src/inspector",
|
||||||
"-src/interpreter",
|
"-src/interpreter",
|
||||||
"+src/interpreter/bytecode-array-iterator.h",
|
"+src/interpreter/bytecode-array-iterator.h",
|
||||||
|
"+src/interpreter/bytecode-array-reverse-iterator.h",
|
||||||
"+src/interpreter/bytecode-decoder.h",
|
"+src/interpreter/bytecode-decoder.h",
|
||||||
"+src/interpreter/bytecode-flags.h",
|
"+src/interpreter/bytecode-flags.h",
|
||||||
"+src/interpreter/bytecode-register.h",
|
"+src/interpreter/bytecode-register.h",
|
||||||
|
97
src/compiler/bytecode-analysis.cc
Normal file
97
src/compiler/bytecode-analysis.cc
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// 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-analysis.h"
|
||||||
|
|
||||||
|
#include "src/interpreter/bytecode-array-reverse-iterator.h"
|
||||||
|
#include "src/objects-inl.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
namespace compiler {
|
||||||
|
|
||||||
|
BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
|
||||||
|
Zone* zone)
|
||||||
|
: bytecode_array_(bytecode_array),
|
||||||
|
zone_(zone),
|
||||||
|
loop_stack_(zone),
|
||||||
|
end_to_header_(zone),
|
||||||
|
header_to_parent_(zone) {}
|
||||||
|
|
||||||
|
void BytecodeAnalysis::Analyze() {
|
||||||
|
loop_stack_.push(-1);
|
||||||
|
|
||||||
|
interpreter::BytecodeArrayReverseIterator iterator(bytecode_array(), zone());
|
||||||
|
while (!iterator.done()) {
|
||||||
|
interpreter::Bytecode bytecode = iterator.current_bytecode();
|
||||||
|
if (bytecode == interpreter::Bytecode::kJumpLoop) {
|
||||||
|
PushLoop(iterator.GetJumpTargetOffset(), iterator.current_offset());
|
||||||
|
} else if (iterator.current_offset() == loop_stack_.top()) {
|
||||||
|
loop_stack_.pop();
|
||||||
|
}
|
||||||
|
iterator.Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_EQ(loop_stack_.size(), 1u);
|
||||||
|
DCHECK_EQ(loop_stack_.top(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) {
|
||||||
|
DCHECK(loop_header < loop_end);
|
||||||
|
DCHECK(loop_stack_.top() < loop_header);
|
||||||
|
DCHECK(end_to_header_.find(loop_end) == end_to_header_.end());
|
||||||
|
DCHECK(header_to_parent_.find(loop_header) == header_to_parent_.end());
|
||||||
|
|
||||||
|
end_to_header_.insert(ZoneMap<int, int>::value_type(loop_end, loop_header));
|
||||||
|
header_to_parent_.insert(
|
||||||
|
ZoneMap<int, int>::value_type(loop_header, loop_stack_.top()));
|
||||||
|
loop_stack_.push(loop_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BytecodeAnalysis::IsLoopHeader(int offset) const {
|
||||||
|
return header_to_parent_.find(offset) != header_to_parent_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
int BytecodeAnalysis::GetLoopOffsetFor(int offset) const {
|
||||||
|
auto loop_end_to_header = end_to_header_.lower_bound(offset);
|
||||||
|
// If there is no next end => offset is not in a loop.
|
||||||
|
if (loop_end_to_header == end_to_header_.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// If the header preceeds the offset, this is the loop
|
||||||
|
//
|
||||||
|
// .> header <--loop_end_to_header
|
||||||
|
// |
|
||||||
|
// | <--offset
|
||||||
|
// |
|
||||||
|
// `- end
|
||||||
|
if (loop_end_to_header->second <= offset) {
|
||||||
|
return loop_end_to_header->second;
|
||||||
|
}
|
||||||
|
// Otherwise there is a (potentially nested) loop after this offset.
|
||||||
|
//
|
||||||
|
// <--offset
|
||||||
|
//
|
||||||
|
// .> header
|
||||||
|
// |
|
||||||
|
// | .> header <--loop_end_to_header
|
||||||
|
// | |
|
||||||
|
// | `- end
|
||||||
|
// |
|
||||||
|
// `- end
|
||||||
|
// We just return the parent of the next loop header (might be -1).
|
||||||
|
DCHECK(header_to_parent_.upper_bound(offset) != header_to_parent_.end());
|
||||||
|
|
||||||
|
return header_to_parent_.upper_bound(offset)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BytecodeAnalysis::GetParentLoopFor(int header_offset) const {
|
||||||
|
DCHECK(IsLoopHeader(header_offset));
|
||||||
|
|
||||||
|
return header_to_parent_.find(header_offset)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
56
src/compiler/bytecode-analysis.h
Normal file
56
src/compiler/bytecode-analysis.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// 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_ANALYSIS_H_
|
||||||
|
#define V8_COMPILER_BYTECODE_ANALYSIS_H_
|
||||||
|
|
||||||
|
#include "src/handles.h"
|
||||||
|
#include "src/zone/zone-containers.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class BytecodeArray;
|
||||||
|
|
||||||
|
namespace compiler {
|
||||||
|
|
||||||
|
class BytecodeAnalysis BASE_EMBEDDED {
|
||||||
|
public:
|
||||||
|
BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, Zone* zone);
|
||||||
|
|
||||||
|
// Analyze the bytecodes to find the loop ranges and nesting. No other
|
||||||
|
// methods in this class return valid information until this has been called.
|
||||||
|
void Analyze();
|
||||||
|
|
||||||
|
// Return true if the given offset is a loop header
|
||||||
|
bool IsLoopHeader(int offset) const;
|
||||||
|
// Get the loop header offset of the containing loop for arbitrary
|
||||||
|
// {offset}, or -1 if the {offset} is not inside any loop.
|
||||||
|
int GetLoopOffsetFor(int offset) const;
|
||||||
|
// Gets the loop header offset of the parent loop of the loop header
|
||||||
|
// at {header_offset}, or -1 for outer-most loops.
|
||||||
|
int GetParentLoopFor(int header_offset) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void PushLoop(int loop_header, int loop_end);
|
||||||
|
|
||||||
|
Zone* zone() const { return zone_; }
|
||||||
|
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
|
||||||
|
|
||||||
|
Handle<BytecodeArray> bytecode_array_;
|
||||||
|
Zone* zone_;
|
||||||
|
|
||||||
|
ZoneStack<int> loop_stack_;
|
||||||
|
|
||||||
|
ZoneMap<int, int> end_to_header_;
|
||||||
|
ZoneMap<int, int> header_to_parent_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(BytecodeAnalysis);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
|
#endif // V8_COMPILER_BYTECODE_ANALYSIS_H_
|
@ -1,43 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
#include "src/compiler/bytecode-branch-analysis.h"
|
|
||||||
|
|
||||||
#include "src/interpreter/bytecode-array-iterator.h"
|
|
||||||
#include "src/objects-inl.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
|
||||||
namespace internal {
|
|
||||||
namespace compiler {
|
|
||||||
|
|
||||||
BytecodeBranchAnalysis::BytecodeBranchAnalysis(
|
|
||||||
Handle<BytecodeArray> bytecode_array, Zone* zone)
|
|
||||||
: bytecode_array_(bytecode_array),
|
|
||||||
is_backward_target_(bytecode_array->length(), zone),
|
|
||||||
is_forward_target_(bytecode_array->length(), zone),
|
|
||||||
zone_(zone) {}
|
|
||||||
|
|
||||||
void BytecodeBranchAnalysis::Analyze() {
|
|
||||||
interpreter::BytecodeArrayIterator iterator(bytecode_array());
|
|
||||||
while (!iterator.done()) {
|
|
||||||
interpreter::Bytecode bytecode = iterator.current_bytecode();
|
|
||||||
int current_offset = iterator.current_offset();
|
|
||||||
if (interpreter::Bytecodes::IsJump(bytecode)) {
|
|
||||||
AddBranch(current_offset, iterator.GetJumpTargetOffset());
|
|
||||||
}
|
|
||||||
iterator.Advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BytecodeBranchAnalysis::AddBranch(int source_offset, int target_offset) {
|
|
||||||
if (source_offset < target_offset) {
|
|
||||||
is_forward_target_.Add(target_offset);
|
|
||||||
} else {
|
|
||||||
is_backward_target_.Add(target_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace compiler
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace v8
|
|
@ -1,65 +0,0 @@
|
|||||||
// 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_BYTECODE_BRANCH_ANALYSIS_H_
|
|
||||||
#define V8_COMPILER_BYTECODE_BRANCH_ANALYSIS_H_
|
|
||||||
|
|
||||||
#include "src/bit-vector.h"
|
|
||||||
#include "src/handles.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
class BytecodeArray;
|
|
||||||
|
|
||||||
namespace compiler {
|
|
||||||
|
|
||||||
// A class for identifying branch targets within a bytecode array.
|
|
||||||
// This information can be used to construct the local control flow
|
|
||||||
// logic for high-level IR graphs built from bytecode.
|
|
||||||
//
|
|
||||||
// N.B. If this class is used to determine loop headers, then such a
|
|
||||||
// usage relies on the only backwards branches in bytecode being jumps
|
|
||||||
// back to loop headers.
|
|
||||||
class BytecodeBranchAnalysis BASE_EMBEDDED {
|
|
||||||
public:
|
|
||||||
BytecodeBranchAnalysis(Handle<BytecodeArray> bytecode_array, Zone* zone);
|
|
||||||
|
|
||||||
// Analyze the bytecodes to find the branch sites and their
|
|
||||||
// targets. No other methods in this class return valid information
|
|
||||||
// until this has been called.
|
|
||||||
void Analyze();
|
|
||||||
|
|
||||||
// Returns true if there are any forward branches to the bytecode at
|
|
||||||
// |offset|.
|
|
||||||
bool forward_branches_target(int offset) const {
|
|
||||||
return is_forward_target_.Contains(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if there are any backward branches to the bytecode
|
|
||||||
// at |offset|.
|
|
||||||
bool backward_branches_target(int offset) const {
|
|
||||||
return is_backward_target_.Contains(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void AddBranch(int origin_offset, int target_offset);
|
|
||||||
|
|
||||||
Zone* zone() const { return zone_; }
|
|
||||||
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
|
|
||||||
|
|
||||||
Handle<BytecodeArray> bytecode_array_;
|
|
||||||
BitVector is_backward_target_;
|
|
||||||
BitVector is_forward_target_;
|
|
||||||
Zone* zone_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(BytecodeBranchAnalysis);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace compiler
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace v8
|
|
||||||
|
|
||||||
#endif // V8_COMPILER_BYTECODE_BRANCH_ANALYSIS_H_
|
|
@ -7,7 +7,6 @@
|
|||||||
#include "src/ast/ast.h"
|
#include "src/ast/ast.h"
|
||||||
#include "src/ast/scopes.h"
|
#include "src/ast/scopes.h"
|
||||||
#include "src/compilation-info.h"
|
#include "src/compilation-info.h"
|
||||||
#include "src/compiler/bytecode-branch-analysis.h"
|
|
||||||
#include "src/compiler/compiler-source-position-table.h"
|
#include "src/compiler/compiler-source-position-table.h"
|
||||||
#include "src/compiler/linkage.h"
|
#include "src/compiler/linkage.h"
|
||||||
#include "src/compiler/operator-properties.h"
|
#include "src/compiler/operator-properties.h"
|
||||||
@ -638,12 +637,9 @@ void BytecodeGraphBuilder::ClearNonLiveSlotsInFrameStates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) {
|
void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) {
|
||||||
BytecodeBranchAnalysis analysis(bytecode_array(), local_zone());
|
BytecodeAnalysis bytecode_analysis(bytecode_array(), local_zone());
|
||||||
BytecodeLoopAnalysis loop_analysis(bytecode_array(), &analysis, local_zone());
|
bytecode_analysis.Analyze();
|
||||||
analysis.Analyze();
|
set_bytecode_analysis(&bytecode_analysis);
|
||||||
loop_analysis.Analyze();
|
|
||||||
set_branch_analysis(&analysis);
|
|
||||||
set_loop_analysis(&loop_analysis);
|
|
||||||
|
|
||||||
interpreter::BytecodeArrayIterator iterator(bytecode_array());
|
interpreter::BytecodeArrayIterator iterator(bytecode_array());
|
||||||
set_bytecode_iterator(&iterator);
|
set_bytecode_iterator(&iterator);
|
||||||
@ -677,8 +673,7 @@ void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
set_bytecode_analysis(nullptr);
|
||||||
set_branch_analysis(nullptr);
|
|
||||||
set_bytecode_iterator(nullptr);
|
set_bytecode_iterator(nullptr);
|
||||||
DCHECK(exception_handlers_.empty());
|
DCHECK(exception_handlers_.empty());
|
||||||
}
|
}
|
||||||
@ -1905,7 +1900,7 @@ void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
|
void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
|
||||||
if (branch_analysis()->backward_branches_target(current_offset)) {
|
if (bytecode_analysis()->IsLoopHeader(current_offset)) {
|
||||||
// Add loop header and store a copy so we can connect merged back
|
// Add loop header and store a copy so we can connect merged back
|
||||||
// edge inputs to the loop header.
|
// edge inputs to the loop header.
|
||||||
merge_environments_[current_offset] = environment()->CopyForLoop();
|
merge_environments_[current_offset] = environment()->CopyForLoop();
|
||||||
@ -1948,9 +1943,8 @@ void BytecodeGraphBuilder::BuildOSRNormalEntryPoint() {
|
|||||||
// For OSR add an {OsrNormalEntry} as the the top-level environment start.
|
// For OSR add an {OsrNormalEntry} as the the top-level environment start.
|
||||||
// It will be replaced with {Dead} by the OSR deconstruction.
|
// It will be replaced with {Dead} by the OSR deconstruction.
|
||||||
NewNode(common()->OsrNormalEntry());
|
NewNode(common()->OsrNormalEntry());
|
||||||
// Note that the requested OSR entry point must be the target of a backward
|
// Note that the requested OSR entry point must be the header of a loop.
|
||||||
// branch, otherwise there will not be a proper loop header available.
|
DCHECK(bytecode_analysis()->IsLoopHeader(osr_ast_id_.ToInt()));
|
||||||
DCHECK(branch_analysis()->backward_branches_target(osr_ast_id_.ToInt()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1958,17 +1952,18 @@ void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) {
|
|||||||
int origin_offset = bytecode_iterator().current_offset();
|
int origin_offset = bytecode_iterator().current_offset();
|
||||||
// Only build loop exits for forward edges.
|
// Only build loop exits for forward edges.
|
||||||
if (target_offset > origin_offset) {
|
if (target_offset > origin_offset) {
|
||||||
BuildLoopExitsUntilLoop(loop_analysis()->GetLoopOffsetFor(target_offset));
|
BuildLoopExitsUntilLoop(
|
||||||
|
bytecode_analysis()->GetLoopOffsetFor(target_offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) {
|
void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) {
|
||||||
int origin_offset = bytecode_iterator().current_offset();
|
int origin_offset = bytecode_iterator().current_offset();
|
||||||
int current_loop = loop_analysis()->GetLoopOffsetFor(origin_offset);
|
int current_loop = bytecode_analysis()->GetLoopOffsetFor(origin_offset);
|
||||||
while (loop_offset < current_loop) {
|
while (loop_offset < current_loop) {
|
||||||
Node* loop_node = merge_environments_[current_loop]->GetControlDependency();
|
Node* loop_node = merge_environments_[current_loop]->GetControlDependency();
|
||||||
environment()->PrepareForLoopExit(loop_node);
|
environment()->PrepareForLoopExit(loop_node);
|
||||||
current_loop = loop_analysis()->GetParentLoopFor(current_loop);
|
current_loop = bytecode_analysis()->GetParentLoopFor(current_loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
#ifndef V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|
#ifndef V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|
||||||
#define V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|
#define V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|
||||||
|
|
||||||
#include "src/compiler/bytecode-branch-analysis.h"
|
#include "src/compiler/bytecode-analysis.h"
|
||||||
#include "src/compiler/bytecode-loop-analysis.h"
|
|
||||||
#include "src/compiler/js-graph.h"
|
#include "src/compiler/js-graph.h"
|
||||||
#include "src/compiler/liveness-analyzer.h"
|
#include "src/compiler/liveness-analyzer.h"
|
||||||
#include "src/compiler/state-values-utils.h"
|
#include "src/compiler/state-values-utils.h"
|
||||||
@ -254,18 +253,12 @@ class BytecodeGraphBuilder {
|
|||||||
bytecode_iterator_ = bytecode_iterator;
|
bytecode_iterator_ = bytecode_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BytecodeBranchAnalysis* branch_analysis() const {
|
const BytecodeAnalysis* bytecode_analysis() const {
|
||||||
return branch_analysis_;
|
return bytecode_analysis_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_branch_analysis(const BytecodeBranchAnalysis* branch_analysis) {
|
void set_bytecode_analysis(const BytecodeAnalysis* bytecode_analysis) {
|
||||||
branch_analysis_ = branch_analysis;
|
bytecode_analysis_ = bytecode_analysis;
|
||||||
}
|
|
||||||
|
|
||||||
const BytecodeLoopAnalysis* loop_analysis() const { return loop_analysis_; }
|
|
||||||
|
|
||||||
void set_loop_analysis(const BytecodeLoopAnalysis* loop_analysis) {
|
|
||||||
loop_analysis_ = loop_analysis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LivenessAnalyzer* liveness_analyzer() { return &liveness_analyzer_; }
|
LivenessAnalyzer* liveness_analyzer() { return &liveness_analyzer_; }
|
||||||
@ -286,8 +279,7 @@ class BytecodeGraphBuilder {
|
|||||||
Handle<TypeFeedbackVector> feedback_vector_;
|
Handle<TypeFeedbackVector> feedback_vector_;
|
||||||
const FrameStateFunctionInfo* frame_state_function_info_;
|
const FrameStateFunctionInfo* frame_state_function_info_;
|
||||||
const interpreter::BytecodeArrayIterator* bytecode_iterator_;
|
const interpreter::BytecodeArrayIterator* bytecode_iterator_;
|
||||||
const BytecodeBranchAnalysis* branch_analysis_;
|
const BytecodeAnalysis* bytecode_analysis_;
|
||||||
const BytecodeLoopAnalysis* loop_analysis_;
|
|
||||||
Environment* environment_;
|
Environment* environment_;
|
||||||
BailoutId osr_ast_id_;
|
BailoutId osr_ast_id_;
|
||||||
|
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
// 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-loop-analysis.h"
|
|
||||||
|
|
||||||
#include "src/compiler/bytecode-branch-analysis.h"
|
|
||||||
#include "src/interpreter/bytecode-array-iterator.h"
|
|
||||||
#include "src/objects-inl.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
|
||||||
namespace internal {
|
|
||||||
namespace compiler {
|
|
||||||
|
|
||||||
BytecodeLoopAnalysis::BytecodeLoopAnalysis(
|
|
||||||
Handle<BytecodeArray> bytecode_array,
|
|
||||||
const BytecodeBranchAnalysis* branch_analysis, Zone* zone)
|
|
||||||
: bytecode_array_(bytecode_array),
|
|
||||||
branch_analysis_(branch_analysis),
|
|
||||||
zone_(zone),
|
|
||||||
current_loop_offset_(-1),
|
|
||||||
found_current_backedge_(false),
|
|
||||||
backedge_to_header_(zone),
|
|
||||||
loop_header_to_parent_(zone) {}
|
|
||||||
|
|
||||||
void BytecodeLoopAnalysis::Analyze() {
|
|
||||||
current_loop_offset_ = -1;
|
|
||||||
found_current_backedge_ = false;
|
|
||||||
interpreter::BytecodeArrayIterator iterator(bytecode_array());
|
|
||||||
while (!iterator.done()) {
|
|
||||||
interpreter::Bytecode bytecode = iterator.current_bytecode();
|
|
||||||
int current_offset = iterator.current_offset();
|
|
||||||
if (branch_analysis_->backward_branches_target(current_offset)) {
|
|
||||||
AddLoopEntry(current_offset);
|
|
||||||
} else if (interpreter::Bytecodes::IsJump(bytecode)) {
|
|
||||||
AddBranch(current_offset, iterator.GetJumpTargetOffset());
|
|
||||||
}
|
|
||||||
iterator.Advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BytecodeLoopAnalysis::AddLoopEntry(int entry_offset) {
|
|
||||||
if (found_current_backedge_) {
|
|
||||||
// We assume that all backedges of a loop must occur together and before
|
|
||||||
// another loop entry or an outer loop backedge.
|
|
||||||
// This is guaranteed by the invariants from AddBranch, such that every
|
|
||||||
// backedge must either go to the current loop or be the first of the
|
|
||||||
// backedges to the parent loop.
|
|
||||||
// Thus here, the current loop actually ended before and we have a loop
|
|
||||||
// with the same parent.
|
|
||||||
current_loop_offset_ = loop_header_to_parent_[current_loop_offset_];
|
|
||||||
found_current_backedge_ = false;
|
|
||||||
}
|
|
||||||
loop_header_to_parent_[entry_offset] = current_loop_offset_;
|
|
||||||
current_loop_offset_ = entry_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BytecodeLoopAnalysis::AddBranch(int origin_offset, int target_offset) {
|
|
||||||
// If this is a backedge, record it.
|
|
||||||
if (target_offset < origin_offset) {
|
|
||||||
backedge_to_header_[origin_offset] = target_offset;
|
|
||||||
// Check whether this is actually a backedge of the outer loop and we have
|
|
||||||
// already finished the current loop.
|
|
||||||
if (target_offset < current_loop_offset_) {
|
|
||||||
DCHECK(found_current_backedge_);
|
|
||||||
int parent_offset = loop_header_to_parent_[current_loop_offset_];
|
|
||||||
DCHECK_EQ(target_offset, parent_offset);
|
|
||||||
current_loop_offset_ = parent_offset;
|
|
||||||
} else {
|
|
||||||
DCHECK_EQ(target_offset, current_loop_offset_);
|
|
||||||
found_current_backedge_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int BytecodeLoopAnalysis::GetLoopOffsetFor(int offset) const {
|
|
||||||
auto next_backedge = backedge_to_header_.lower_bound(offset);
|
|
||||||
// If there is no next backedge => offset is not in a loop.
|
|
||||||
if (next_backedge == backedge_to_header_.end()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// If the header preceeds the offset, it is the backedge of the containing
|
|
||||||
// loop.
|
|
||||||
if (next_backedge->second <= offset) {
|
|
||||||
return next_backedge->second;
|
|
||||||
}
|
|
||||||
// Otherwise there is a nested loop after this offset. We just return the
|
|
||||||
// parent of the next nested loop.
|
|
||||||
return loop_header_to_parent_.upper_bound(offset)->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BytecodeLoopAnalysis::GetParentLoopFor(int header_offset) const {
|
|
||||||
auto parent = loop_header_to_parent_.find(header_offset);
|
|
||||||
DCHECK(parent != loop_header_to_parent_.end());
|
|
||||||
return parent->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace compiler
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace v8
|
|
@ -1,67 +0,0 @@
|
|||||||
// 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_LOOP_ANALYSIS_H_
|
|
||||||
#define V8_COMPILER_BYTECODE_LOOP_ANALYSIS_H_
|
|
||||||
|
|
||||||
#include "src/handles.h"
|
|
||||||
#include "src/zone/zone-containers.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
class BytecodeArray;
|
|
||||||
|
|
||||||
namespace compiler {
|
|
||||||
|
|
||||||
class BytecodeBranchAnalysis;
|
|
||||||
|
|
||||||
class BytecodeLoopAnalysis BASE_EMBEDDED {
|
|
||||||
public:
|
|
||||||
BytecodeLoopAnalysis(Handle<BytecodeArray> bytecode_array,
|
|
||||||
const BytecodeBranchAnalysis* branch_analysis,
|
|
||||||
Zone* zone);
|
|
||||||
|
|
||||||
// Analyze the bytecodes to find the branch sites and their
|
|
||||||
// targets. No other methods in this class return valid information
|
|
||||||
// until this has been called.
|
|
||||||
void Analyze();
|
|
||||||
|
|
||||||
// Get the loop header offset of the containing loop for arbitrary
|
|
||||||
// {offset}, or -1 if the {offset} is not inside any loop.
|
|
||||||
int GetLoopOffsetFor(int offset) const;
|
|
||||||
// Gets the loop header offset of the parent loop of the loop header
|
|
||||||
// at {header_offset}, or -1 for outer-most loops.
|
|
||||||
int GetParentLoopFor(int header_offset) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void AddLoopEntry(int entry_offset);
|
|
||||||
void AddBranch(int origin_offset, int target_offset);
|
|
||||||
|
|
||||||
Zone* zone() const { return zone_; }
|
|
||||||
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
|
|
||||||
|
|
||||||
Handle<BytecodeArray> bytecode_array_;
|
|
||||||
const BytecodeBranchAnalysis* branch_analysis_;
|
|
||||||
Zone* zone_;
|
|
||||||
|
|
||||||
int current_loop_offset_;
|
|
||||||
bool found_current_backedge_;
|
|
||||||
|
|
||||||
// Map from the offset of a backedge jump to the offset of the corresponding
|
|
||||||
// loop header. There might be multiple backedges for do-while loops.
|
|
||||||
ZoneMap<int, int> backedge_to_header_;
|
|
||||||
// Map from the offset of a loop header to the offset of its parent's loop
|
|
||||||
// header. This map will have as many entries as there are loops in the
|
|
||||||
// function.
|
|
||||||
ZoneMap<int, int> loop_header_to_parent_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(BytecodeLoopAnalysis);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace compiler
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace v8
|
|
||||||
|
|
||||||
#endif // V8_COMPILER_BYTECODE_LOOP_ANALYSIS_H_
|
|
@ -548,12 +548,10 @@
|
|||||||
'compiler/basic-block-instrumentor.h',
|
'compiler/basic-block-instrumentor.h',
|
||||||
'compiler/branch-elimination.cc',
|
'compiler/branch-elimination.cc',
|
||||||
'compiler/branch-elimination.h',
|
'compiler/branch-elimination.h',
|
||||||
'compiler/bytecode-branch-analysis.cc',
|
|
||||||
'compiler/bytecode-branch-analysis.h',
|
|
||||||
'compiler/bytecode-graph-builder.cc',
|
'compiler/bytecode-graph-builder.cc',
|
||||||
'compiler/bytecode-graph-builder.h',
|
'compiler/bytecode-graph-builder.h',
|
||||||
'compiler/bytecode-loop-analysis.cc',
|
'compiler/bytecode-analysis.cc',
|
||||||
'compiler/bytecode-loop-analysis.h',
|
'compiler/bytecode-analysis.h',
|
||||||
'compiler/c-linkage.cc',
|
'compiler/c-linkage.cc',
|
||||||
'compiler/checkpoint-elimination.cc',
|
'compiler/checkpoint-elimination.cc',
|
||||||
'compiler/checkpoint-elimination.h',
|
'compiler/checkpoint-elimination.h',
|
||||||
|
Loading…
Reference in New Issue
Block a user