Commit 0b287bd4 authored by clemensh's avatar clemensh Committed by Commit bot

[asm-wasm] Fix continue target of do-while loops

See associated bug: A continue if a do-while loop did jump back to the
loop header, instead of jumping to the condition.
This CL fixes this and adds a test case.

R=bradnelson@chromium.org, titzer@chromium.org
BUG=v8:5912

Review-Url: https://codereview.chromium.org/2693993002
Cr-Commit-Position: refs/heads/master@{#43178}
parent db558210
......@@ -36,6 +36,8 @@ namespace wasm {
if (HasStackOverflow()) return; \
} while (false)
namespace {
enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
enum ValueFate { kDrop, kLeaveOnStack };
......@@ -45,6 +47,10 @@ struct ForeignVariable {
ValueType type;
};
enum TargetType : uint8_t { NoTarget, BreakTarget, ContinueTarget };
} // namespace
class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
public:
AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, CompilationInfo* info,
......@@ -231,7 +237,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
}
}
if (scope_ == kFuncScope) {
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock);
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
BreakTarget);
RECURSE(VisitStatements(stmt->statements()));
} else {
RECURSE(VisitStatements(stmt->statements()));
......@@ -244,10 +251,9 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
public:
BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
WasmOpcode opcode)
WasmOpcode opcode, TargetType target_type = NoTarget)
: builder_(builder) {
builder_->breakable_blocks_.push_back(
std::make_pair(stmt, opcode == kExprLoop));
builder_->breakable_blocks_.emplace_back(stmt, target_type);
// block and loops have a type immediate.
builder_->current_function_builder_->EmitWithU8(opcode, kLocalVoid);
}
......@@ -295,9 +301,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
void VisitIfStatement(IfStatement* stmt) {
DCHECK_EQ(kFuncScope, scope_);
RECURSE(Visit(stmt->condition()));
current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
// WASM ifs come with implement blocks for both arms.
breakable_blocks_.push_back(std::make_pair(nullptr, false));
// Wasm ifs come with implicit blocks for both arms.
BlockVisitor block(this, nullptr, kExprIf);
if (stmt->HasThenStatement()) {
RECURSE(Visit(stmt->then_statement()));
}
......@@ -305,18 +310,15 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
current_function_builder_->Emit(kExprElse);
RECURSE(Visit(stmt->else_statement()));
}
current_function_builder_->Emit(kExprEnd);
breakable_blocks_.pop_back();
}
void DoBreakOrContinue(BreakableStatement* target, bool is_continue) {
void DoBreakOrContinue(BreakableStatement* target, TargetType type) {
DCHECK_EQ(kFuncScope, scope_);
for (int i = static_cast<int>(breakable_blocks_.size()) - 1; i >= 0; --i) {
auto elem = breakable_blocks_.at(i);
if (elem.first == target && elem.second == is_continue) {
if (elem.first == target && elem.second == type) {
int block_distance = static_cast<int>(breakable_blocks_.size() - i - 1);
current_function_builder_->Emit(kExprBr);
current_function_builder_->EmitVarInt(block_distance);
current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
return;
}
}
......@@ -324,11 +326,11 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
}
void VisitContinueStatement(ContinueStatement* stmt) {
DoBreakOrContinue(stmt->target(), true);
DoBreakOrContinue(stmt->target(), ContinueTarget);
}
void VisitBreakStatement(BreakStatement* stmt) {
DoBreakOrContinue(stmt->target(), false);
DoBreakOrContinue(stmt->target(), BreakTarget);
}
void VisitReturnStatement(ReturnStatement* stmt) {
......@@ -366,7 +368,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
current_function_builder_->Emit(kExprI32LtS);
current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
if_depth++;
breakable_blocks_.push_back(std::make_pair(nullptr, false));
breakable_blocks_.emplace_back(nullptr, NoTarget);
HandleCase(node->left, case_to_block, tag, default_block, if_depth);
current_function_builder_->Emit(kExprElse);
}
......@@ -376,7 +378,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
current_function_builder_->Emit(kExprI32GtS);
current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
if_depth++;
breakable_blocks_.push_back(std::make_pair(nullptr, false));
breakable_blocks_.emplace_back(nullptr, NoTarget);
HandleCase(node->right, case_to_block, tag, default_block, if_depth);
current_function_builder_->Emit(kExprElse);
}
......@@ -430,7 +432,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
if (case_count == 0) {
return;
}
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock);
BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
BreakTarget);
ZoneVector<BlockVisitor*> blocks(zone_);
ZoneVector<int32_t> cases(zone_);
ZoneMap<int, unsigned int> case_to_block(zone_);
......@@ -476,26 +479,28 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
void VisitDoWhileStatement(DoWhileStatement* stmt) {
DCHECK_EQ(kFuncScope, scope_);
BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock);
BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
BreakTarget);
BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
RECURSE(Visit(stmt->body()));
{
BlockVisitor inner_block(this, stmt->AsBreakableStatement(), kExprBlock,
ContinueTarget);
RECURSE(Visit(stmt->body()));
}
RECURSE(Visit(stmt->cond()));
current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
current_function_builder_->EmitWithU8(kExprBr, 1);
current_function_builder_->Emit(kExprEnd);
current_function_builder_->EmitWithU8(kExprBrIf, 0);
}
void VisitWhileStatement(WhileStatement* stmt) {
DCHECK_EQ(kFuncScope, scope_);
BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock);
BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
BreakTarget);
BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop,
ContinueTarget);
RECURSE(Visit(stmt->cond()));
breakable_blocks_.push_back(std::make_pair(nullptr, false));
current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
BlockVisitor if_block(this, nullptr, kExprIf);
RECURSE(Visit(stmt->body()));
current_function_builder_->EmitWithU8(kExprBr, 1);
current_function_builder_->Emit(kExprEnd);
breakable_blocks_.pop_back();
}
void VisitForStatement(ForStatement* stmt) {
......@@ -503,8 +508,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
if (stmt->init() != nullptr) {
RECURSE(Visit(stmt->init()));
}
BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock);
BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
BreakTarget);
BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop,
ContinueTarget);
if (stmt->cond() != nullptr) {
RECURSE(Visit(stmt->cond()));
current_function_builder_->Emit(kExprI32Eqz);
......@@ -562,8 +569,8 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
void VisitConditional(Conditional* expr) {
DCHECK_EQ(kFuncScope, scope_);
RECURSE(Visit(expr->condition()));
// WASM ifs come with implicit blocks for both arms.
breakable_blocks_.push_back(std::make_pair(nullptr, false));
// Wasm ifs come with implicit blocks for both arms.
breakable_blocks_.emplace_back(nullptr, NoTarget);
ValueTypeCode type;
switch (TypeOf(expr)) {
case kWasmI32:
......@@ -1969,7 +1976,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
AsmTyper* typer_;
bool typer_failed_;
bool typer_finished_;
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
ZoneVector<std::pair<BreakableStatement*, TargetType>> breakable_blocks_;
ZoneVector<ForeignVariable> foreign_variables_;
WasmFunctionBuilder* init_function_;
WasmFunctionBuilder* foreign_init_function_;
......
......@@ -410,6 +410,22 @@ function TestContinueInNamedWhile() {
assertWasm(20, TestContinueInNamedWhile);
function TestContinueInDoWhileFalse() {
"use asm";
function caller() {
do {
continue;
} while (false);
return 47;
}
return {caller: caller};
}
assertWasm(47, TestContinueInDoWhileFalse);
function TestNot() {
"use asm";
......
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