Commit ee5b58d9 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[interpreter] Simplify graph builder control flow simulation.

This simplifies how the BytecodeGraphBuilder simulates control flow by
reversing the propagation direction to forwards propagation. This is the
same direction as the data flow which is also a forward propagation. In
this way the analysis information needed at merge points is drastically
reduced while still retaining the same simulation power.

In short: We push down environments instead of pulling them.

R=oth@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#33633}
parent 077d70f0
......@@ -111,13 +111,6 @@ const ZoneVector<int>* BytecodeBranchAnalysis::ForwardBranchesTargetting(
}
}
void BytecodeBranchAnalysis::AddExceptionalBranch(int throw_offset,
int handler_offset) {
DCHECK(is_reachable(handler_offset)); // Handler was marked reachable.
DCHECK_LT(throw_offset, handler_offset); // Always a forward branch.
AddBranch(throw_offset, handler_offset);
}
void BytecodeBranchAnalysis::AddBranch(int source_offset, int target_offset) {
BytecodeBranchInfo* branch_info = nullptr;
auto iterator = branch_infos_.find(target_offset);
......
......@@ -34,12 +34,6 @@ class BytecodeBranchAnalysis BASE_EMBEDDED {
// until this has been called.
void Analyze();
// Offsets of bytecodes having a backward branch to the bytecode at |offset|.
const ZoneVector<int>* BackwardBranchesTargetting(int offset) const;
// Offsets of bytecodes having a forward branch to the bytecode at |offset|.
const ZoneVector<int>* ForwardBranchesTargetting(int offset) const;
// Returns true if the bytecode at |offset| is reachable.
bool is_reachable(int offset) const { return reachable_.Contains(offset); }
......@@ -57,15 +51,16 @@ class BytecodeBranchAnalysis BASE_EMBEDDED {
return sites != nullptr && sites->size() > 0;
}
// Adds an additional implicit branch from a throw-site at {throw_offset} to
// the corresponding exception handler at {handler_offset}. Note that such a
// branch must be a forward branch and has to target a known handler.
void AddExceptionalBranch(int throw_offset, int handler_offset);
private:
void AddBranch(int origin_offset, int target_offset);
void AnalyzeExceptionHandlers();
// Offsets of bytecodes having a backward branch to the bytecode at |offset|.
const ZoneVector<int>* BackwardBranchesTargetting(int offset) const;
// Offsets of bytecodes having a forward branch to the bytecode at |offset|.
const ZoneVector<int>* ForwardBranchesTargetting(int offset) const;
Zone* zone() const { return zone_; }
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
......
......@@ -478,7 +478,6 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
bytecode_array()->register_count(), info()->shared_info(),
CALL_MAINTAINS_NATIVE_CONTEXT)),
merge_environments_(local_zone),
loop_header_environments_(local_zone),
exception_handlers_(local_zone),
current_exception_handler_(0),
input_buffer_size_(0),
......@@ -618,8 +617,8 @@ void BytecodeGraphBuilder::VisitBytecodes() {
int current_offset = iterator.current_offset();
if (analysis.is_reachable(current_offset)) {
EnterAndExitExceptionHandlers(current_offset);
MergeEnvironmentsOfForwardBranches(current_offset);
BuildLoopHeaderForBackwardBranches(current_offset);
SwitchToMergeEnvironment(current_offset);
BuildLoopHeaderEnvironment(current_offset);
switch (iterator.current_bytecode()) {
#define BYTECODE_CASE(name, ...) \
......@@ -1602,86 +1601,48 @@ void BytecodeGraphBuilder::VisitForInStep() {
environment()->BindAccumulator(index, &states);
}
void BytecodeGraphBuilder::MergeEnvironmentsOfBackwardBranches(
int source_offset, int target_offset) {
DCHECK_GE(source_offset, target_offset);
const ZoneVector<int>* branch_sites =
branch_analysis()->BackwardBranchesTargetting(target_offset);
if (branch_sites->back() == source_offset) {
// The set of back branches is complete, merge them.
DCHECK_GE(branch_sites->at(0), target_offset);
Environment* merged = merge_environments_[branch_sites->at(0)];
for (size_t i = 1; i < branch_sites->size(); i++) {
DCHECK_GE(branch_sites->at(i), target_offset);
merged->Merge(merge_environments_[branch_sites->at(i)]);
}
// And now merge with loop header environment created when loop
// header was visited.
loop_header_environments_[target_offset]->Merge(merged);
}
}
void BytecodeGraphBuilder::MergeEnvironmentsOfForwardBranches(
int source_offset) {
if (branch_analysis()->forward_branches_target(source_offset)) {
// Merge environments of branches that reach this bytecode.
auto branch_sites =
branch_analysis()->ForwardBranchesTargetting(source_offset);
DCHECK_LT(branch_sites->at(0), source_offset);
Environment* merged = merge_environments_[branch_sites->at(0)];
for (size_t i = 1; i < branch_sites->size(); i++) {
DCHECK_LT(branch_sites->at(i), source_offset);
merged->Merge(merge_environments_[branch_sites->at(i)]);
}
if (environment()) {
merged->Merge(environment());
void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
if (merge_environments_[current_offset] != nullptr) {
if (environment() != nullptr) {
merge_environments_[current_offset]->Merge(environment());
}
set_environment(merged);
set_environment(merge_environments_[current_offset]);
}
}
void BytecodeGraphBuilder::BuildLoopHeaderForBackwardBranches(
int source_offset) {
if (branch_analysis()->backward_branches_target(source_offset)) {
void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
if (branch_analysis()->backward_branches_target(current_offset)) {
// Add loop header and store a copy so we can connect merged back
// edge inputs to the loop header.
loop_header_environments_[source_offset] = environment()->CopyForLoop();
merge_environments_[current_offset] = environment()->CopyForLoop();
}
}
void BytecodeGraphBuilder::BuildJump(int source_offset, int target_offset) {
DCHECK_NULL(merge_environments_[source_offset]);
// Append merge nodes to the environment. We may merge here with another
// environment. So add a place holder for merge nodes. We may add redundant
// but will be eliminated in a later pass.
// TODO(mstarzinger): This can be simplified by propagating environment
// forward along the direction of the dataflow.
NewMerge();
merge_environments_[source_offset] = environment();
if (source_offset >= target_offset) {
MergeEnvironmentsOfBackwardBranches(source_offset, target_offset);
void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) {
if (merge_environments_[target_offset] == nullptr) {
// Append merge nodes to the environment. We may merge here with another
// environment. So add a place holder for merge nodes. We may add redundant
// but will be eliminated in a later pass.
// TODO(mstarzinger): Be smarter about this!
NewMerge();
merge_environments_[target_offset] = environment();
} else {
merge_environments_[target_offset]->Merge(environment());
}
set_environment(nullptr);
}
void BytecodeGraphBuilder::BuildJump() {
int source_offset = bytecode_iterator().current_offset();
int target_offset = bytecode_iterator().GetJumpTargetOffset();
BuildJump(source_offset, target_offset);
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) {
int source_offset = bytecode_iterator().current_offset();
NewBranch(condition);
Environment* if_false_environment = environment()->CopyForConditional();
NewIfTrue();
BuildJump(source_offset, bytecode_iterator().GetJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
set_environment(if_false_environment);
NewIfFalse();
}
......@@ -1797,15 +1758,9 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
}
// Add implicit exception continuation for throwing nodes.
if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) {
int throw_offset = bytecode_iterator().current_offset();
int handler_offset = exception_handlers_.top().handler_offset_;
// TODO(mstarzinger): Thread through correct prediction!
IfExceptionHint hint = IfExceptionHint::kLocallyCaught;
// TODO(mstarzinger): For now we mutate the branch analysis result and
// add the artificial control flow from throw-site to handler-entry.
// This can be simplified by pushing environment forward along the
// direction of the data-flow.
branch_analysis_->AddExceptionalBranch(throw_offset, handler_offset);
Environment* success_env = environment()->CopyForConditional();
const Operator* op = common()->IfException(hint);
Node* effect = environment()->GetEffectDependency();
......@@ -1813,7 +1768,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
environment()->UpdateControlDependency(on_exception);
environment()->UpdateEffectDependency(on_exception);
environment()->BindAccumulator(on_exception);
BuildJump(throw_offset, handler_offset);
MergeIntoSuccessorEnvironment(handler_offset);
set_environment(success_env);
}
// Add implicit success continuation for throwing nodes.
......
......@@ -147,17 +147,15 @@ class BytecodeGraphBuilder {
void BuildForInNext();
// Control flow plumbing.
void BuildJump(int source_offset, int target_offset);
void BuildJump();
void BuildConditionalJump(Node* condition);
void BuildJumpIfEqual(Node* comperand);
void BuildJumpIfToBooleanEqual(Node* boolean_comperand);
// Constructing merge and loop headers.
void MergeEnvironmentsOfBackwardBranches(int source_offset,
int target_offset);
void MergeEnvironmentsOfForwardBranches(int source_offset);
void BuildLoopHeaderForBackwardBranches(int source_offset);
// Simulates control flow by forward-propagating environments.
void MergeIntoSuccessorEnvironment(int target_offset);
void BuildLoopHeaderEnvironment(int current_offset);
void SwitchToMergeEnvironment(int current_offset);
// Simulates entry and exit of exception handlers.
void EnterAndExitExceptionHandlers(int current_offset);
......@@ -233,14 +231,11 @@ class BytecodeGraphBuilder {
BytecodeBranchAnalysis* branch_analysis_; // TODO(mstarzinger): Make const.
Environment* environment_;
// Merge environments are snapshots of the environment at a particular
// bytecode offset to be merged into a later environment.
// Merge environments are snapshots of the environment at points where the
// control flow merges. This models a forward data flow propagation of all
// values from all predecessors of the merge in question.
ZoneMap<int, Environment*> merge_environments_;
// Loop header environments are environments created for bytecodes
// where it is known there are back branches, ie a loop header.
ZoneMap<int, Environment*> loop_header_environments_;
// Exception handlers currently entered by the iteration.
ZoneStack<ExceptionHandler> exception_handlers_;
int current_exception_handler_;
......
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