[asm.js] Fix break depth calculation for named blocks.

The target of a 'break' statement without a provided label must be a
regular block belonging to a surrounding loop or switch statement, named
blocks (i.e. the one that just define a label) on the other hand must be
targeted specifically with the provided label (and not implicitly). This
fixes the behavior by introducing a dedicated {BlockKind::kNamed} for
this purpose.

R=clemensh@chromium.org
TEST=mjsunit/regress/regress-9022
BUG=v8:9022

Change-Id: I94c3d5b1196ed94b8b1b31f6eb3b68070cf324e8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1538126
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60445}
This commit is contained in:
Michael Starzinger 2019-03-25 14:21:13 +01:00 committed by Commit Bot
parent 368d04bd1b
commit 080fa87143
4 changed files with 57 additions and 7 deletions

View File

@ -320,6 +320,9 @@ int AsmJsParser::FindContinueLabelDepth(AsmJsScanner::token_t label) {
int count = 0;
for (auto it = block_stack_.rbegin(); it != block_stack_.rend();
++it, ++count) {
// A 'continue' statement targets ...
// - The innermost {kLoop} block if no label is given.
// - The matching {kLoop} block (when a label is provided).
if (it->kind == BlockKind::kLoop &&
(label == kTokenNone || it->label == label)) {
return count;
@ -332,8 +335,12 @@ int AsmJsParser::FindBreakLabelDepth(AsmJsScanner::token_t label) {
int count = 0;
for (auto it = block_stack_.rbegin(); it != block_stack_.rend();
++it, ++count) {
if (it->kind == BlockKind::kRegular &&
(label == kTokenNone || it->label == label)) {
// A 'break' statement targets ...
// - The innermost {kRegular} block if no label is given.
// - The matching {kRegular} or {kNamed} block (when a label is provided).
if ((it->kind == BlockKind::kRegular &&
(label == kTokenNone || it->label == label)) ||
(it->kind == BlockKind::kNamed && it->label == label)) {
return count;
}
}
@ -1042,7 +1049,8 @@ void AsmJsParser::ValidateStatement() {
void AsmJsParser::Block() {
bool can_break_to_block = pending_label_ != 0;
if (can_break_to_block) {
Begin(pending_label_);
BareBegin(BlockKind::kNamed, pending_label_);
current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
}
pending_label_ = 0;
EXPECT_TOKEN('{');
@ -1084,8 +1092,8 @@ void AsmJsParser::IfStatement() {
EXPECT_TOKEN('(');
RECURSE(Expression(AsmType::Int()));
EXPECT_TOKEN(')');
BareBegin(BlockKind::kOther);
current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
BareBegin();
RECURSE(ValidateStatement());
if (Check(TOK(else))) {
current_function_builder_->Emit(kExprElse);

View File

@ -107,8 +107,20 @@ class AsmJsParser {
VarInfo* var_info;
};
enum class BlockKind { kRegular, kLoop, kOther };
// Distinguish different kinds of blocks participating in {block_stack}. Each
// entry on that stack represents one block in the wasm code, and determines
// which block 'break' and 'continue' target in the current context:
// - kRegular: The target of a 'break' (with & without identifier).
// Pushed by an IterationStatement and a SwitchStatement.
// - kLoop : The target of a 'continue' (with & without identifier).
// Pushed by an IterationStatement.
// - kNamed : The target of a 'break' with a specific identifier.
// Pushed by a BlockStatement.
// - kOther : Only used for internal blocks, can never be targeted.
enum class BlockKind { kRegular, kLoop, kNamed, kOther };
// One entry in the {block_stack}, see {BlockKind} above for details. Blocks
// without a label have {kTokenNone} set as their label.
struct BlockInfo {
BlockKind kind;
AsmJsScanner::token_t label;
@ -312,8 +324,7 @@ class AsmJsParser {
// Use to set up block stack layers (including synthetic ones for if-else).
// Begin/Loop/End below are implemented with these plus code generation.
void BareBegin(BlockKind kind = BlockKind::kOther,
AsmJsScanner::token_t label = 0);
void BareBegin(BlockKind kind, AsmJsScanner::token_t label = 0);
void BareEnd();
int FindContinueLabelDepth(AsmJsScanner::token_t label);
int FindBreakLabelDepth(AsmJsScanner::token_t label);

View File

@ -370,6 +370,7 @@
'regress/regress-6700': [SKIP],
'regress/regress-6838-2': [SKIP],
'regress/regress-6838-3': [SKIP],
'regress/regress-9022': [SKIP],
'regress/regress-crbug-934138': [SKIP],
# Timeouts in lite / jitless mode.

View File

@ -0,0 +1,30 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --validate-asm --allow-natives-syntax
function Module(stdlib, ffi) {
"use asm";
var log = ffi.log;
function boom() {
while (1) {
label: {
break;
}
log(1);
break;
}
log(2);
}
return { boom: boom }
}
var log_value = 0;
function log(i) {
log_value += i;
}
Module({}, { log: log }).boom();
assertTrue(%IsAsmWasmCode(Module));
assertEquals(2, log_value);