[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:
parent
368d04bd1b
commit
080fa87143
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
30
test/mjsunit/regress/regress-9022.js
Normal file
30
test/mjsunit/regress/regress-9022.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user