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