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