[interpreter] Use VisitForTest for loop conditions
Changes the control flow builder classes to make use of the BytecodeLabels helper class. BUG=v8:4280 LOG=n Review-Url: https://codereview.chromium.org/2254493002 Cr-Commit-Position: refs/heads/master@{#38744}
This commit is contained in:
parent
a305726686
commit
e4c67d3f70
@ -18,11 +18,14 @@ BytecodeLoopAnalysis::BytecodeLoopAnalysis(
|
|||||||
: bytecode_array_(bytecode_array),
|
: bytecode_array_(bytecode_array),
|
||||||
branch_analysis_(branch_analysis),
|
branch_analysis_(branch_analysis),
|
||||||
zone_(zone),
|
zone_(zone),
|
||||||
|
current_loop_offset_(-1),
|
||||||
|
found_current_backedge_(false),
|
||||||
backedge_to_header_(zone),
|
backedge_to_header_(zone),
|
||||||
loop_header_to_parent_(zone) {}
|
loop_header_to_parent_(zone) {}
|
||||||
|
|
||||||
void BytecodeLoopAnalysis::Analyze() {
|
void BytecodeLoopAnalysis::Analyze() {
|
||||||
current_loop_offset_ = -1;
|
current_loop_offset_ = -1;
|
||||||
|
found_current_backedge_ = false;
|
||||||
interpreter::BytecodeArrayIterator iterator(bytecode_array());
|
interpreter::BytecodeArrayIterator iterator(bytecode_array());
|
||||||
while (!iterator.done()) {
|
while (!iterator.done()) {
|
||||||
interpreter::Bytecode bytecode = iterator.current_bytecode();
|
interpreter::Bytecode bytecode = iterator.current_bytecode();
|
||||||
@ -37,18 +40,36 @@ void BytecodeLoopAnalysis::Analyze() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeLoopAnalysis::AddLoopEntry(int entry_offset) {
|
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_;
|
loop_header_to_parent_[entry_offset] = current_loop_offset_;
|
||||||
current_loop_offset_ = entry_offset;
|
current_loop_offset_ = entry_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeLoopAnalysis::AddBranch(int origin_offset, int target_offset) {
|
void BytecodeLoopAnalysis::AddBranch(int origin_offset, int target_offset) {
|
||||||
// If this is a backedge, record it and update the current loop to the parent.
|
// If this is a backedge, record it.
|
||||||
if (target_offset < origin_offset) {
|
if (target_offset < origin_offset) {
|
||||||
backedge_to_header_[origin_offset] = target_offset;
|
backedge_to_header_[origin_offset] = target_offset;
|
||||||
// Check that we are finishing the current loop. This assumes that
|
// Check whether this is actually a backedge of the outer loop and we have
|
||||||
// there is one backedge for each loop.
|
// 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_);
|
DCHECK_EQ(target_offset, current_loop_offset_);
|
||||||
current_loop_offset_ = loop_header_to_parent_[target_offset];
|
found_current_backedge_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +47,10 @@ class BytecodeLoopAnalysis BASE_EMBEDDED {
|
|||||||
Zone* zone_;
|
Zone* zone_;
|
||||||
|
|
||||||
int current_loop_offset_;
|
int current_loop_offset_;
|
||||||
|
bool found_current_backedge_;
|
||||||
|
|
||||||
// Map from the offset of a backedge jump to the offset of the corresponding
|
// Map from the offset of a backedge jump to the offset of the corresponding
|
||||||
// loop header. Since we assume exactly one backedge per loop, the map will
|
// loop header. There might be multiple backedges for do-while loops.
|
||||||
// have as many entries as there are loops.
|
|
||||||
ZoneMap<int, int> backedge_to_header_;
|
ZoneMap<int, int> backedge_to_header_;
|
||||||
// Map from the offset of a loop header to the offset of its parent's loop
|
// 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
|
// header. This map will have as many entries as there are loops in the
|
||||||
|
@ -1119,7 +1119,6 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
Register tag = VisitForRegisterValue(stmt->tag());
|
Register tag = VisitForRegisterValue(stmt->tag());
|
||||||
|
|
||||||
// Iterate over all cases and create nodes for label comparison.
|
// Iterate over all cases and create nodes for label comparison.
|
||||||
BytecodeLabel done_label;
|
|
||||||
for (int i = 0; i < clauses->length(); i++) {
|
for (int i = 0; i < clauses->length(); i++) {
|
||||||
CaseClause* clause = clauses->at(i);
|
CaseClause* clause = clauses->at(i);
|
||||||
|
|
||||||
@ -1140,8 +1139,8 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
switch_builder.DefaultAt(default_index);
|
switch_builder.DefaultAt(default_index);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise if we have reached here none of the cases matched, so jump to
|
// Otherwise if we have reached here none of the cases matched, so jump to
|
||||||
// done.
|
// the end.
|
||||||
builder()->Jump(&done_label);
|
switch_builder.Break();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all cases and create the case bodies.
|
// Iterate over all cases and create the case bodies.
|
||||||
@ -1150,9 +1149,7 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
switch_builder.SetCaseTarget(i);
|
switch_builder.SetCaseTarget(i);
|
||||||
VisitStatements(clause->statements());
|
VisitStatements(clause->statements());
|
||||||
}
|
}
|
||||||
builder()->Bind(&done_label);
|
switch_builder.BindBreakTarget();
|
||||||
|
|
||||||
switch_builder.SetBreakTarget(done_label);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
|
void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
|
||||||
@ -1165,7 +1162,7 @@ void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
|
|||||||
ControlScopeForIteration execution_control(this, stmt, loop_builder);
|
ControlScopeForIteration execution_control(this, stmt, loop_builder);
|
||||||
builder()->StackCheck(stmt->position());
|
builder()->StackCheck(stmt->position());
|
||||||
Visit(stmt->body());
|
Visit(stmt->body());
|
||||||
loop_builder->SetContinueTarget();
|
loop_builder->BindContinueTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
||||||
@ -1180,9 +1177,8 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
|||||||
VisitIterationHeader(stmt, &loop_builder);
|
VisitIterationHeader(stmt, &loop_builder);
|
||||||
VisitIterationBody(stmt, &loop_builder);
|
VisitIterationBody(stmt, &loop_builder);
|
||||||
builder()->SetExpressionAsStatementPosition(stmt->cond());
|
builder()->SetExpressionAsStatementPosition(stmt->cond());
|
||||||
// TODO(klaasb) VisitForTest for loop conditions
|
VisitForTest(stmt->cond(), loop_builder.header_labels(),
|
||||||
VisitForAccumulatorValue(stmt->cond());
|
loop_builder.break_labels(), TestFallthrough::kElse);
|
||||||
loop_builder.JumpToHeaderIfTrue();
|
|
||||||
}
|
}
|
||||||
loop_builder.EndLoop();
|
loop_builder.EndLoop();
|
||||||
}
|
}
|
||||||
@ -1197,9 +1193,10 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
|||||||
VisitIterationHeader(stmt, &loop_builder);
|
VisitIterationHeader(stmt, &loop_builder);
|
||||||
if (!stmt->cond()->ToBooleanIsTrue()) {
|
if (!stmt->cond()->ToBooleanIsTrue()) {
|
||||||
builder()->SetExpressionAsStatementPosition(stmt->cond());
|
builder()->SetExpressionAsStatementPosition(stmt->cond());
|
||||||
// TODO(klaasb) VisitForTest for loop conditions
|
BytecodeLabels loop_body(zone());
|
||||||
VisitForAccumulatorValue(stmt->cond());
|
VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
|
||||||
loop_builder.BreakIfFalse();
|
TestFallthrough::kThen);
|
||||||
|
loop_body.Bind(builder());
|
||||||
}
|
}
|
||||||
VisitIterationBody(stmt, &loop_builder);
|
VisitIterationBody(stmt, &loop_builder);
|
||||||
loop_builder.JumpToHeader();
|
loop_builder.JumpToHeader();
|
||||||
@ -1220,9 +1217,10 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
|
|||||||
VisitIterationHeader(stmt, &loop_builder);
|
VisitIterationHeader(stmt, &loop_builder);
|
||||||
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
|
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
|
||||||
builder()->SetExpressionAsStatementPosition(stmt->cond());
|
builder()->SetExpressionAsStatementPosition(stmt->cond());
|
||||||
// TODO(klaasb) VisitForTest for loop conditions
|
BytecodeLabels loop_body(zone());
|
||||||
VisitForAccumulatorValue(stmt->cond());
|
VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
|
||||||
loop_builder.BreakIfFalse();
|
TestFallthrough::kThen);
|
||||||
|
loop_body.Bind(builder());
|
||||||
}
|
}
|
||||||
VisitIterationBody(stmt, &loop_builder);
|
VisitIterationBody(stmt, &loop_builder);
|
||||||
if (stmt->next() != nullptr) {
|
if (stmt->next() != nullptr) {
|
||||||
|
@ -11,16 +11,24 @@ namespace internal {
|
|||||||
namespace interpreter {
|
namespace interpreter {
|
||||||
|
|
||||||
BytecodeLabel* BytecodeLabels::New() {
|
BytecodeLabel* BytecodeLabels::New() {
|
||||||
|
DCHECK(!is_bound());
|
||||||
labels_.push_back(BytecodeLabel());
|
labels_.push_back(BytecodeLabel());
|
||||||
return &labels_.back();
|
return &labels_.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BytecodeLabels::Bind(BytecodeArrayBuilder* builder) {
|
void BytecodeLabels::Bind(BytecodeArrayBuilder* builder) {
|
||||||
for (auto label : labels_) {
|
for (auto& label : labels_) {
|
||||||
builder->Bind(&label);
|
builder->Bind(&label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BytecodeLabels::BindToLabel(BytecodeArrayBuilder* builder,
|
||||||
|
const BytecodeLabel& target) {
|
||||||
|
for (auto& label : labels_) {
|
||||||
|
builder->Bind(target, &label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace interpreter
|
} // namespace interpreter
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -62,6 +62,18 @@ class BytecodeLabels {
|
|||||||
|
|
||||||
void Bind(BytecodeArrayBuilder* builder);
|
void Bind(BytecodeArrayBuilder* builder);
|
||||||
|
|
||||||
|
void BindToLabel(BytecodeArrayBuilder* builder, const BytecodeLabel& target);
|
||||||
|
|
||||||
|
bool is_bound() const {
|
||||||
|
bool is_bound = !labels_.empty() && labels_.at(0).is_bound();
|
||||||
|
DCHECK(!is_bound ||
|
||||||
|
std::all_of(labels_.begin(), labels_.end(),
|
||||||
|
[](const BytecodeLabel& l) { return l.is_bound(); }));
|
||||||
|
return is_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return labels_.empty(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ZoneVector<BytecodeLabel> labels_;
|
ZoneVector<BytecodeLabel> labels_;
|
||||||
|
|
||||||
|
@ -10,95 +10,53 @@ namespace interpreter {
|
|||||||
|
|
||||||
|
|
||||||
BreakableControlFlowBuilder::~BreakableControlFlowBuilder() {
|
BreakableControlFlowBuilder::~BreakableControlFlowBuilder() {
|
||||||
DCHECK(break_sites_.empty());
|
DCHECK(break_labels_.empty() || break_labels_.is_bound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakableControlFlowBuilder::BindBreakTarget() {
|
||||||
void BreakableControlFlowBuilder::SetBreakTarget(const BytecodeLabel& target) {
|
break_labels_.Bind(builder());
|
||||||
BindLabels(target, &break_sites_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakableControlFlowBuilder::EmitJump(BytecodeLabels* sites) {
|
||||||
void BreakableControlFlowBuilder::EmitJump(ZoneVector<BytecodeLabel>* sites) {
|
builder()->Jump(sites->New());
|
||||||
sites->push_back(BytecodeLabel());
|
|
||||||
builder()->Jump(&sites->back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakableControlFlowBuilder::EmitJumpIfTrue(BytecodeLabels* sites) {
|
||||||
void BreakableControlFlowBuilder::EmitJumpIfTrue(
|
builder()->JumpIfTrue(sites->New());
|
||||||
ZoneVector<BytecodeLabel>* sites) {
|
|
||||||
sites->push_back(BytecodeLabel());
|
|
||||||
builder()->JumpIfTrue(&sites->back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakableControlFlowBuilder::EmitJumpIfFalse(BytecodeLabels* sites) {
|
||||||
void BreakableControlFlowBuilder::EmitJumpIfFalse(
|
builder()->JumpIfFalse(sites->New());
|
||||||
ZoneVector<BytecodeLabel>* sites) {
|
|
||||||
sites->push_back(BytecodeLabel());
|
|
||||||
builder()->JumpIfFalse(&sites->back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakableControlFlowBuilder::EmitJumpIfUndefined(BytecodeLabels* sites) {
|
||||||
void BreakableControlFlowBuilder::EmitJumpIfUndefined(
|
builder()->JumpIfUndefined(sites->New());
|
||||||
ZoneVector<BytecodeLabel>* sites) {
|
|
||||||
sites->push_back(BytecodeLabel());
|
|
||||||
builder()->JumpIfUndefined(&sites->back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakableControlFlowBuilder::EmitJumpIfNull(BytecodeLabels* sites) {
|
||||||
void BreakableControlFlowBuilder::EmitJumpIfNull(
|
builder()->JumpIfNull(sites->New());
|
||||||
ZoneVector<BytecodeLabel>* sites) {
|
|
||||||
sites->push_back(BytecodeLabel());
|
|
||||||
builder()->JumpIfNull(&sites->back());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BreakableControlFlowBuilder::EmitJump(ZoneVector<BytecodeLabel>* sites,
|
|
||||||
int index) {
|
|
||||||
builder()->Jump(&sites->at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BreakableControlFlowBuilder::EmitJumpIfTrue(
|
|
||||||
ZoneVector<BytecodeLabel>* sites, int index) {
|
|
||||||
builder()->JumpIfTrue(&sites->at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BreakableControlFlowBuilder::EmitJumpIfFalse(
|
|
||||||
ZoneVector<BytecodeLabel>* sites, int index) {
|
|
||||||
builder()->JumpIfFalse(&sites->at(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BreakableControlFlowBuilder::BindLabels(const BytecodeLabel& target,
|
|
||||||
ZoneVector<BytecodeLabel>* sites) {
|
|
||||||
for (size_t i = 0; i < sites->size(); i++) {
|
|
||||||
BytecodeLabel& site = sites->at(i);
|
|
||||||
builder()->Bind(target, &site);
|
|
||||||
}
|
|
||||||
sites->clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BlockBuilder::EndBlock() {
|
void BlockBuilder::EndBlock() {
|
||||||
builder()->Bind(&block_end_);
|
builder()->Bind(&block_end_);
|
||||||
SetBreakTarget(block_end_);
|
BindBreakTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoopBuilder::~LoopBuilder() {
|
||||||
LoopBuilder::~LoopBuilder() { DCHECK(continue_sites_.empty()); }
|
DCHECK(continue_labels_.empty() || continue_labels_.is_bound());
|
||||||
|
DCHECK(header_labels_.empty() || header_labels_.is_bound());
|
||||||
|
}
|
||||||
|
|
||||||
void LoopBuilder::LoopHeader(ZoneVector<BytecodeLabel>* additional_labels) {
|
void LoopBuilder::LoopHeader(ZoneVector<BytecodeLabel>* additional_labels) {
|
||||||
// Jumps from before the loop header into the loop violate ordering
|
// Jumps from before the loop header into the loop violate ordering
|
||||||
// requirements of bytecode basic blocks. The only entry into a loop
|
// requirements of bytecode basic blocks. The only entry into a loop
|
||||||
// must be the loop header. Surely breaks is okay? Not if nested
|
// must be the loop header. Surely breaks is okay? Not if nested
|
||||||
// and misplaced between the headers.
|
// and misplaced between the headers.
|
||||||
DCHECK(break_sites_.empty() && continue_sites_.empty());
|
DCHECK(break_labels_.empty() && continue_labels_.empty());
|
||||||
builder()->Bind(&loop_header_);
|
builder()->Bind(&loop_header_);
|
||||||
for (auto& label : *additional_labels) {
|
for (auto& label : *additional_labels) {
|
||||||
builder()->Bind(loop_header_, &label);
|
builder()->Bind(&label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,16 +75,11 @@ void LoopBuilder::JumpToHeaderIfTrue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LoopBuilder::EndLoop() {
|
void LoopBuilder::EndLoop() {
|
||||||
builder()->Bind(&loop_end_);
|
BindBreakTarget();
|
||||||
SetBreakTarget(loop_end_);
|
header_labels_.BindToLabel(builder(), loop_header_);
|
||||||
}
|
|
||||||
|
|
||||||
void LoopBuilder::SetContinueTarget() {
|
|
||||||
BytecodeLabel target;
|
|
||||||
builder()->Bind(&target);
|
|
||||||
BindLabels(target, &continue_sites_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoopBuilder::BindContinueTarget() { continue_labels_.Bind(builder()); }
|
||||||
|
|
||||||
SwitchBuilder::~SwitchBuilder() {
|
SwitchBuilder::~SwitchBuilder() {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -165,8 +118,7 @@ void TryFinallyBuilder::BeginTry(Register context) {
|
|||||||
|
|
||||||
|
|
||||||
void TryFinallyBuilder::LeaveTry() {
|
void TryFinallyBuilder::LeaveTry() {
|
||||||
finalization_sites_.push_back(BytecodeLabel());
|
builder()->Jump(finalization_sites_.New());
|
||||||
builder()->Jump(&finalization_sites_.back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -180,14 +132,7 @@ void TryFinallyBuilder::BeginHandler() {
|
|||||||
builder()->MarkHandler(handler_id_, catch_prediction_);
|
builder()->MarkHandler(handler_id_, catch_prediction_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TryFinallyBuilder::BeginFinally() { finalization_sites_.Bind(builder()); }
|
||||||
void TryFinallyBuilder::BeginFinally() {
|
|
||||||
for (size_t i = 0; i < finalization_sites_.size(); i++) {
|
|
||||||
BytecodeLabel& site = finalization_sites_.at(i);
|
|
||||||
builder()->Bind(&site);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TryFinallyBuilder::EndFinally() {
|
void TryFinallyBuilder::EndFinally() {
|
||||||
// Nothing to be done here.
|
// Nothing to be done here.
|
||||||
|
@ -32,37 +32,33 @@ class ControlFlowBuilder BASE_EMBEDDED {
|
|||||||
class BreakableControlFlowBuilder : public ControlFlowBuilder {
|
class BreakableControlFlowBuilder : public ControlFlowBuilder {
|
||||||
public:
|
public:
|
||||||
explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
|
explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
|
||||||
: ControlFlowBuilder(builder),
|
: ControlFlowBuilder(builder), break_labels_(builder->zone()) {}
|
||||||
break_sites_(builder->zone()) {}
|
|
||||||
virtual ~BreakableControlFlowBuilder();
|
virtual ~BreakableControlFlowBuilder();
|
||||||
|
|
||||||
// This method should be called by the control flow owner before
|
// This method should be called by the control flow owner before
|
||||||
// destruction to update sites that emit jumps for break.
|
// destruction to update sites that emit jumps for break.
|
||||||
void SetBreakTarget(const BytecodeLabel& break_target);
|
void BindBreakTarget();
|
||||||
|
|
||||||
// This method is called when visiting break statements in the AST.
|
// This method is called when visiting break statements in the AST.
|
||||||
// Inserts a jump to a unbound label that is patched when the corresponding
|
// Inserts a jump to an unbound label that is patched when the corresponding
|
||||||
// SetBreakTarget is called.
|
// BindBreakTarget is called.
|
||||||
void Break() { EmitJump(&break_sites_); }
|
void Break() { EmitJump(&break_labels_); }
|
||||||
void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
|
void BreakIfTrue() { EmitJumpIfTrue(&break_labels_); }
|
||||||
void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
|
void BreakIfFalse() { EmitJumpIfFalse(&break_labels_); }
|
||||||
void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
|
void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
|
||||||
void BreakIfNull() { EmitJumpIfNull(&break_sites_); }
|
void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
|
||||||
|
|
||||||
|
BytecodeLabels* break_labels() { return &break_labels_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void EmitJump(ZoneVector<BytecodeLabel>* labels);
|
void EmitJump(BytecodeLabels* labels);
|
||||||
void EmitJump(ZoneVector<BytecodeLabel>* labels, int index);
|
void EmitJumpIfTrue(BytecodeLabels* labels);
|
||||||
void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels);
|
void EmitJumpIfFalse(BytecodeLabels* labels);
|
||||||
void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels, int index);
|
void EmitJumpIfUndefined(BytecodeLabels* labels);
|
||||||
void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels);
|
void EmitJumpIfNull(BytecodeLabels* labels);
|
||||||
void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels, int index);
|
|
||||||
void EmitJumpIfUndefined(ZoneVector<BytecodeLabel>* labels);
|
|
||||||
void EmitJumpIfNull(ZoneVector<BytecodeLabel>* labels);
|
|
||||||
|
|
||||||
void BindLabels(const BytecodeLabel& target, ZoneVector<BytecodeLabel>* site);
|
|
||||||
|
|
||||||
// Unbound labels that identify jumps for break statements in the code.
|
// Unbound labels that identify jumps for break statements in the code.
|
||||||
ZoneVector<BytecodeLabel> break_sites_;
|
BytecodeLabels break_labels_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -85,29 +81,34 @@ class LoopBuilder final : public BreakableControlFlowBuilder {
|
|||||||
public:
|
public:
|
||||||
explicit LoopBuilder(BytecodeArrayBuilder* builder)
|
explicit LoopBuilder(BytecodeArrayBuilder* builder)
|
||||||
: BreakableControlFlowBuilder(builder),
|
: BreakableControlFlowBuilder(builder),
|
||||||
continue_sites_(builder->zone()) {}
|
continue_labels_(builder->zone()),
|
||||||
|
header_labels_(builder->zone()) {}
|
||||||
~LoopBuilder();
|
~LoopBuilder();
|
||||||
|
|
||||||
void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
|
void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
|
||||||
void JumpToHeader();
|
void JumpToHeader();
|
||||||
void JumpToHeaderIfTrue();
|
void JumpToHeaderIfTrue();
|
||||||
void SetContinueTarget();
|
void BindContinueTarget();
|
||||||
void EndLoop();
|
void EndLoop();
|
||||||
|
|
||||||
// This method is called when visiting continue statements in the AST.
|
// This method is called when visiting continue statements in the AST.
|
||||||
// Inserts a jump to an unbound label that is patched when SetContinueTarget
|
// Inserts a jump to an unbound label that is patched when BindContinueTarget
|
||||||
// is called.
|
// is called.
|
||||||
void Continue() { EmitJump(&continue_sites_); }
|
void Continue() { EmitJump(&continue_labels_); }
|
||||||
void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); }
|
void ContinueIfTrue() { EmitJumpIfTrue(&continue_labels_); }
|
||||||
void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); }
|
void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
|
||||||
void ContinueIfNull() { EmitJumpIfNull(&continue_sites_); }
|
void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
|
||||||
|
|
||||||
|
BytecodeLabels* header_labels() { return &header_labels_; }
|
||||||
|
BytecodeLabels* continue_labels() { return &continue_labels_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BytecodeLabel loop_header_;
|
BytecodeLabel loop_header_;
|
||||||
BytecodeLabel loop_end_;
|
|
||||||
|
|
||||||
// Unbound labels that identify jumps for continue statements in the code.
|
// Unbound labels that identify jumps for continue statements in the code and
|
||||||
ZoneVector<BytecodeLabel> continue_sites_;
|
// jumps from checking the loop condition to the header for do-while loops.
|
||||||
|
BytecodeLabels continue_labels_;
|
||||||
|
BytecodeLabels header_labels_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -128,12 +129,12 @@ class SwitchBuilder final : public BreakableControlFlowBuilder {
|
|||||||
// This method is called when visiting case comparison operation for |index|.
|
// This method is called when visiting case comparison operation for |index|.
|
||||||
// Inserts a JumpIfTrue to a unbound label that is patched when the
|
// Inserts a JumpIfTrue to a unbound label that is patched when the
|
||||||
// corresponding SetCaseTarget is called.
|
// corresponding SetCaseTarget is called.
|
||||||
void Case(int index) { EmitJumpIfTrue(&case_sites_, index); }
|
void Case(int index) { builder()->JumpIfTrue(&case_sites_.at(index)); }
|
||||||
|
|
||||||
// This method is called when all cases comparisons have been emitted if there
|
// This method is called when all cases comparisons have been emitted if there
|
||||||
// is a default case statement. Inserts a Jump to a unbound label that is
|
// is a default case statement. Inserts a Jump to a unbound label that is
|
||||||
// patched when the corresponding SetCaseTarget is called.
|
// patched when the corresponding SetCaseTarget is called.
|
||||||
void DefaultAt(int index) { EmitJump(&case_sites_, index); }
|
void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Unbound labels that identify jumps for case statements in the code.
|
// Unbound labels that identify jumps for case statements in the code.
|
||||||
@ -185,7 +186,7 @@ class TryFinallyBuilder final : public ControlFlowBuilder {
|
|||||||
BytecodeLabel handler_;
|
BytecodeLabel handler_;
|
||||||
|
|
||||||
// Unbound labels that identify jumps to the finally block in the code.
|
// Unbound labels that identify jumps to the finally block in the code.
|
||||||
ZoneVector<BytecodeLabel> finalization_sites_;
|
BytecodeLabels finalization_sites_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace interpreter
|
} // namespace interpreter
|
||||||
|
@ -2332,7 +2332,19 @@ TEST(BytecodeGraphBuilderDo) {
|
|||||||
" if (x == 4) break;\n"
|
" if (x == 4) break;\n"
|
||||||
"} while (x < 7);\n"
|
"} while (x < 7);\n"
|
||||||
"return y;",
|
"return y;",
|
||||||
{factory->NewNumberFromInt(16)}}};
|
{factory->NewNumberFromInt(16)}},
|
||||||
|
{"var x = 0, sum = 0;\n"
|
||||||
|
"do {\n"
|
||||||
|
" do {\n"
|
||||||
|
" ++sum;\n"
|
||||||
|
" ++x;\n"
|
||||||
|
" } while (sum < 1 || x < 2)\n"
|
||||||
|
" do {\n"
|
||||||
|
" ++x;\n"
|
||||||
|
" } while (x < 1)\n"
|
||||||
|
"} while (sum < 3)\n"
|
||||||
|
"return sum;",
|
||||||
|
{factory->NewNumber(3)}}};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||||
ScopedVector<char> script(1024);
|
ScopedVector<char> script(1024);
|
||||||
@ -2413,6 +2425,19 @@ TEST(BytecodeGraphBuilderFor) {
|
|||||||
"}\n"
|
"}\n"
|
||||||
"return sum;",
|
"return sum;",
|
||||||
{factory->NewNumberFromInt(385)}},
|
{factory->NewNumberFromInt(385)}},
|
||||||
|
{"var sum = 0;\n"
|
||||||
|
"for (var x = 0; x < 5; x++) {\n"
|
||||||
|
" for (var y = 0; y < 5; y++) {\n"
|
||||||
|
" ++sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
"for (var x = 0; x < 5; x++) {\n"
|
||||||
|
" for (var y = 0; y < 5; y++) {\n"
|
||||||
|
" ++sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
"return sum;",
|
||||||
|
{factory->NewNumberFromInt(50)}},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||||
|
@ -165,7 +165,7 @@ snippet: "
|
|||||||
"
|
"
|
||||||
frame size: 1
|
frame size: 1
|
||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 39
|
bytecode array length: 37
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 30 E> */ B(StackCheck),
|
/* 30 E> */ B(StackCheck),
|
||||||
/* 42 S> */ B(LdaZero),
|
/* 42 S> */ B(LdaZero),
|
||||||
@ -184,8 +184,7 @@ bytecodes: [
|
|||||||
B(Jump), U8(-20),
|
B(Jump), U8(-20),
|
||||||
/* 122 S> */ B(AddSmi), U8(1), R(0),
|
/* 122 S> */ B(AddSmi), U8(1), R(0),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
/* 135 S> */ B(Jump), U8(4),
|
/* 135 S> */ B(Jump), U8(2),
|
||||||
B(Jump), U8(-30),
|
|
||||||
/* 144 S> */ B(Ldar), R(0),
|
/* 144 S> */ B(Ldar), R(0),
|
||||||
/* 154 S> */ B(Return),
|
/* 154 S> */ B(Return),
|
||||||
]
|
]
|
||||||
@ -287,7 +286,7 @@ snippet: "
|
|||||||
"
|
"
|
||||||
frame size: 2
|
frame size: 2
|
||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 29
|
bytecode array length: 27
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 30 E> */ B(StackCheck),
|
/* 30 E> */ B(StackCheck),
|
||||||
/* 42 S> */ B(LdaSmi), U8(10),
|
/* 42 S> */ B(LdaSmi), U8(10),
|
||||||
@ -300,8 +299,7 @@ bytecodes: [
|
|||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
/* 78 S> */ B(SubSmi), U8(1), R(0),
|
/* 78 S> */ B(SubSmi), U8(1), R(0),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
/* 98 S> */ B(Ldar), R(0),
|
/* 98 S> */ B(JumpIfToBooleanTrue), U8(-13),
|
||||||
B(JumpIfToBooleanTrue), U8(-15),
|
|
||||||
/* 102 S> */ B(Ldar), R(1),
|
/* 102 S> */ B(Ldar), R(1),
|
||||||
/* 112 S> */ B(Return),
|
/* 112 S> */ B(Return),
|
||||||
]
|
]
|
||||||
|
@ -54,7 +54,7 @@ snippet: "
|
|||||||
"
|
"
|
||||||
frame size: 2
|
frame size: 2
|
||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 18
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 30 E> */ B(StackCheck),
|
/* 30 E> */ B(StackCheck),
|
||||||
/* 34 E> */ B(StackCheck),
|
/* 34 E> */ B(StackCheck),
|
||||||
@ -63,8 +63,7 @@ bytecodes: [
|
|||||||
/* 69 S> */ B(Inc), U8(1),
|
/* 69 S> */ B(Inc), U8(1),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
/* 74 S> */ B(Jump), U8(4),
|
/* 74 S> */ B(Jump), U8(2),
|
||||||
B(Jump), U8(-13),
|
|
||||||
B(LdaUndefined),
|
B(LdaUndefined),
|
||||||
/* 94 S> */ B(Return),
|
/* 94 S> */ B(Return),
|
||||||
]
|
]
|
||||||
|
@ -149,7 +149,7 @@ snippet: "
|
|||||||
"
|
"
|
||||||
frame size: 16
|
frame size: 16
|
||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 281
|
bytecode array length: 279
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 30 E> */ B(StackCheck),
|
/* 30 E> */ B(StackCheck),
|
||||||
/* 42 S> */ B(LdaConstant), U8(0),
|
/* 42 S> */ B(LdaConstant), U8(0),
|
||||||
@ -170,7 +170,7 @@ bytecodes: [
|
|||||||
B(JumpIfFalse), U8(7),
|
B(JumpIfFalse), U8(7),
|
||||||
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(2), U8(1),
|
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(2), U8(1),
|
||||||
B(LdaNamedProperty), R(2), U8(3), U8(9),
|
B(LdaNamedProperty), R(2), U8(3), U8(9),
|
||||||
B(JumpIfToBooleanTrue), U8(28),
|
B(JumpIfToBooleanTrue), U8(26),
|
||||||
B(LdrNamedProperty), R(2), U8(4), U8(11), R(4),
|
B(LdrNamedProperty), R(2), U8(4), U8(11), R(4),
|
||||||
B(LdaSmi), U8(2),
|
B(LdaSmi), U8(2),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
@ -180,8 +180,7 @@ bytecodes: [
|
|||||||
/* 73 S> */ B(LdaZero),
|
/* 73 S> */ B(LdaZero),
|
||||||
B(Star), R(10),
|
B(Star), R(10),
|
||||||
B(Mov), R(0), R(11),
|
B(Mov), R(0), R(11),
|
||||||
B(Jump), U8(50),
|
B(Jump), U8(48),
|
||||||
B(Jump), U8(-54),
|
|
||||||
B(Jump), U8(34),
|
B(Jump), U8(34),
|
||||||
B(Star), R(14),
|
B(Star), R(14),
|
||||||
B(Ldar), R(closure),
|
B(Ldar), R(closure),
|
||||||
@ -280,9 +279,9 @@ constant pool: [
|
|||||||
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
||||||
]
|
]
|
||||||
handlers: [
|
handlers: [
|
||||||
[11, 117, 123],
|
[11, 115, 121],
|
||||||
[14, 83, 85],
|
[14, 81, 83],
|
||||||
[196, 206, 208],
|
[194, 204, 206],
|
||||||
]
|
]
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -438,7 +437,7 @@ snippet: "
|
|||||||
"
|
"
|
||||||
frame size: 14
|
frame size: 14
|
||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 294
|
bytecode array length: 292
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 30 E> */ B(StackCheck),
|
/* 30 E> */ B(StackCheck),
|
||||||
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8),
|
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8),
|
||||||
@ -461,7 +460,7 @@ bytecodes: [
|
|||||||
B(JumpIfFalse), U8(7),
|
B(JumpIfFalse), U8(7),
|
||||||
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(1), U8(1),
|
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(1), U8(1),
|
||||||
B(LdaNamedProperty), R(1), U8(4), U8(9),
|
B(LdaNamedProperty), R(1), U8(4), U8(9),
|
||||||
B(JumpIfToBooleanTrue), U8(31),
|
B(JumpIfToBooleanTrue), U8(29),
|
||||||
/* 67 E> */ B(LdrNamedProperty), R(1), U8(5), U8(11), R(3),
|
/* 67 E> */ B(LdrNamedProperty), R(1), U8(5), U8(11), R(3),
|
||||||
B(LdaSmi), U8(2),
|
B(LdaSmi), U8(2),
|
||||||
B(Star), R(2),
|
B(Star), R(2),
|
||||||
@ -472,8 +471,7 @@ bytecodes: [
|
|||||||
/* 96 E> */ B(LdrNamedProperty), R(6), U8(6), U8(15), R(9),
|
/* 96 E> */ B(LdrNamedProperty), R(6), U8(6), U8(15), R(9),
|
||||||
B(LdaZero),
|
B(LdaZero),
|
||||||
B(Star), R(8),
|
B(Star), R(8),
|
||||||
B(Jump), U8(50),
|
B(Jump), U8(48),
|
||||||
B(Jump), U8(-57),
|
|
||||||
B(Jump), U8(34),
|
B(Jump), U8(34),
|
||||||
B(Star), R(12),
|
B(Star), R(12),
|
||||||
B(Ldar), R(closure),
|
B(Ldar), R(closure),
|
||||||
@ -574,8 +572,8 @@ constant pool: [
|
|||||||
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
||||||
]
|
]
|
||||||
handlers: [
|
handlers: [
|
||||||
[15, 130, 136],
|
[15, 128, 134],
|
||||||
[18, 96, 98],
|
[18, 94, 96],
|
||||||
[209, 219, 221],
|
[207, 217, 219],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -17,19 +17,18 @@ snippet: "
|
|||||||
"
|
"
|
||||||
frame size: 1
|
frame size: 1
|
||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 22
|
bytecode array length: 21
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 30 E> */ B(StackCheck),
|
/* 30 E> */ B(StackCheck),
|
||||||
/* 42 S> */ B(LdaZero),
|
/* 42 S> */ B(LdaZero),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
/* 54 S> */ B(LdaSmi), U8(10),
|
/* 54 S> */ B(LdaSmi), U8(10),
|
||||||
/* 54 E> */ B(TestEqual), R(0),
|
/* 54 E> */ B(TestEqual), R(0),
|
||||||
B(LogicalNot),
|
B(JumpIfTrue), U8(10),
|
||||||
B(JumpIfFalse), U8(10),
|
|
||||||
/* 45 E> */ B(StackCheck),
|
/* 45 E> */ B(StackCheck),
|
||||||
/* 65 S> */ B(AddSmi), U8(10), R(0),
|
/* 65 S> */ B(AddSmi), U8(10), R(0),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
B(Jump), U8(-13),
|
B(Jump), U8(-12),
|
||||||
/* 79 S> */ B(Ldar), R(0),
|
/* 79 S> */ B(Ldar), R(0),
|
||||||
/* 89 S> */ B(Return),
|
/* 89 S> */ B(Return),
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user