Commit d51398fe authored by titzer's avatar titzer Committed by Commit bot

[wasm] Fix decoding failures for tableswitch.

R=ahaas@chromium.org, bradnelson@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1642043002

Cr-Commit-Position: refs/heads/master@{#33581}
parent 8bfa1ea3
......@@ -907,36 +907,22 @@ class LR_WasmDecoder : public WasmDecoder {
break;
}
case kExprTableSwitch: {
uint16_t table_count = *reinterpret_cast<const uint16_t*>(p->pc() + 3);
if (table_count == 1) {
// Degenerate switch with only a default target.
if (p->index == 1) {
SsaEnv* break_env = ssa_env_;
PushBlock(break_env);
SetEnv("switch:default", Steal(break_env));
}
if (p->done()) {
Block* block = &blocks_.back();
// fall through to the end.
ReduceBreakToExprBlock(p, block);
SetEnv("switch:end", block->ssa_env);
blocks_.pop_back();
}
break;
}
if (p->index == 1) {
// Switch key finished.
TypeCheckLast(p, kAstI32);
TFNode* sw = BUILD(Switch, table_count, p->last()->node);
uint16_t table_count =
*reinterpret_cast<const uint16_t*>(p->pc() + 3);
// Build the switch only if it has more than just a default target.
bool build_switch = table_count > 1;
TFNode* sw = nullptr;
if (build_switch) sw = BUILD(Switch, table_count, p->last()->node);
// Allocate environments for each case.
uint16_t case_count = *reinterpret_cast<const uint16_t*>(p->pc() + 1);
SsaEnv** case_envs = zone_->NewArray<SsaEnv*>(case_count);
for (int i = 0; i < case_count; i++) {
case_envs[i] = UnreachableEnv();
}
for (int i = 0; i < case_count; i++) case_envs[i] = UnreachableEnv();
ifs_.push_back({nullptr, nullptr, case_envs});
SsaEnv* break_env = ssa_env_;
......@@ -949,9 +935,12 @@ class LR_WasmDecoder : public WasmDecoder {
reinterpret_cast<const uint16_t*>(p->pc() + 5);
for (int i = 0; i < table_count; i++) {
uint16_t target = table[i];
SsaEnv* env = Split(copy);
env->control = (i == table_count - 1) ? BUILD(IfDefault, sw)
: BUILD(IfValue, i, sw);
SsaEnv* env = copy;
if (build_switch) {
env = Split(env);
env->control = (i == table_count - 1) ? BUILD(IfDefault, sw)
: BUILD(IfValue, i, sw);
}
if (target >= 0x8000) {
// Targets an outer block.
int depth = target - 0x8000;
......@@ -962,25 +951,21 @@ class LR_WasmDecoder : public WasmDecoder {
Goto(env, case_envs[target]);
}
}
}
// Switch to the environment for the first case.
SetEnv("switch:case", case_envs[0]);
if (p->done()) {
// Last case. Fall through to the end.
Block* block = &blocks_.back();
if (p->index > 1) ReduceBreakToExprBlock(p, block);
SsaEnv* next = block->ssa_env;
blocks_.pop_back();
ifs_.pop_back();
SetEnv("switch:end", next);
} else {
// Switch case finished.
if (p->done()) {
// Last case. Fall through to the end.
Block* block = &blocks_.back();
ReduceBreakToExprBlock(p, block);
SsaEnv* next = block->ssa_env;
blocks_.pop_back();
ifs_.pop_back();
SetEnv("switch:end", next);
} else {
// Interior case. Maybe fall through to the next case.
SsaEnv* next = ifs_.back().case_envs[p->index - 1];
if (ssa_env_->go()) Goto(ssa_env_, next);
SetEnv("switch:case", next);
}
// Interior case. Maybe fall through to the next case.
SsaEnv* next = ifs_.back().case_envs[p->index - 1];
if (p->index > 1 && ssa_env_->go()) Goto(ssa_env_, next);
SetEnv("switch:case", next);
}
break;
}
......
......@@ -1002,6 +1002,34 @@ TEST(Run_Wasm_BrIf_strict) {
FOR_INT32_INPUTS(i) { CHECK_EQ(99, r.Call(*i)); }
}
TEST(Run_Wasm_TableSwitch0a) {
WasmRunner<int32_t> r(MachineType::Int32());
BUILD(r, WASM_BLOCK(2, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(0)),
WASM_TABLESWITCH_BODY0(WASM_GET_LOCAL(0)), WASM_I8(91)));
FOR_INT32_INPUTS(i) { CHECK_EQ(91, r.Call(*i)); }
}
TEST(Run_Wasm_TableSwitch0b) {
WasmRunner<int32_t> r(MachineType::Int32());
BUILD(r, WASM_BLOCK(
2, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0), WASM_CASE_BR(0)),
WASM_TABLESWITCH_BODY0(WASM_GET_LOCAL(0)), WASM_I8(92)));
FOR_INT32_INPUTS(i) { CHECK_EQ(92, r.Call(*i)); }
}
TEST(Run_Wasm_TableSwitch0c) {
WasmRunner<int32_t> r(MachineType::Int32());
BUILD(r,
WASM_BLOCK(2, WASM_BLOCK(2, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0),
WASM_CASE_BR(1)),
WASM_TABLESWITCH_BODY0(WASM_GET_LOCAL(0)),
WASM_RETURN(WASM_I8(76))),
WASM_I8(77)));
FOR_INT32_INPUTS(i) {
int32_t expected = *i == 0 ? 76 : 77;
CHECK_EQ(expected, r.Call(*i));
}
}
TEST(Run_Wasm_TableSwitch1) {
WasmRunner<int32_t> r(MachineType::Int32());
......
......@@ -1798,6 +1798,12 @@ TEST_F(WasmDecoderTest, TableSwitch0c) {
EXPECT_VERIFIES(&env_v_v, code);
}
TEST_F(WasmDecoderTest, TableSwitch0d) {
static byte code[] = {
WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0), WASM_CASE_BR(1)),
WASM_I8(67))};
EXPECT_VERIFIES(&env_v_v, code);
}
TEST_F(WasmDecoderTest, TableSwitch1) {
static byte code[] = {WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)),
......@@ -1845,27 +1851,25 @@ TEST_F(WasmDecoderTest, TableSwitch1b) {
#endif
TEST_F(WasmDecoderTest, TableSwitch_br) {
EXPECT_VERIFIES_INLINE(&env_i_i, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(0)),
WASM_GET_LOCAL(0));
TEST_F(WasmDecoderTest, TableSwitch_br1) {
for (int depth = 0; depth < 2; depth++) {
EXPECT_VERIFIES_INLINE(
&env_i_i, WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)),
WASM_GET_LOCAL(0)));
byte code[] = {WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)),
WASM_GET_LOCAL(0))};
EXPECT_VERIFIES(&env_v_i, code);
EXPECT_FAILURE(&env_i_i, code);
}
}
TEST_F(WasmDecoderTest, TableSwitch_invalid_br) {
for (int depth = 1; depth < 4; depth++) {
EXPECT_FAILURE_INLINE(&env_i_i,
EXPECT_FAILURE_INLINE(&env_v_i,
WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)),
WASM_GET_LOCAL(0));
EXPECT_FAILURE_INLINE(
&env_i_i,
WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth + 1)),
WASM_GET_LOCAL(0)));
&env_v_i,
WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(depth), WASM_CASE_BR(depth)),
WASM_GET_LOCAL(0));
}
}
......
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