| Index: src/wasm/ast-decoder.cc
|
| diff --git a/src/wasm/ast-decoder.cc b/src/wasm/ast-decoder.cc
|
| index b4af1b388fcefd6f467db1393d391db524de8d2d..e56991a482e8e2dafc9037c11ed2d6b92730490b 100644
|
| --- a/src/wasm/ast-decoder.cc
|
| +++ b/src/wasm/ast-decoder.cc
|
| @@ -195,26 +195,14 @@ class WasmDecoder : public Decoder {
|
| return false;
|
| }
|
|
|
| - bool Validate(const byte* pc, TableSwitchOperand& operand,
|
| + bool Validate(const byte* pc, BranchTableOperand& operand,
|
| size_t block_depth) {
|
| - if (operand.table_count == 0) {
|
| - error(pc, "tableswitch with 0 entries");
|
| - return false;
|
| - }
|
| // Verify table.
|
| - for (uint32_t i = 0; i < operand.table_count; i++) {
|
| + for (uint32_t i = 0; i < operand.table_count + 1; i++) {
|
| uint16_t target = operand.read_entry(this, i);
|
| - if (target >= 0x8000) {
|
| - size_t depth = target - 0x8000;
|
| - if (depth > block_depth) {
|
| - error(operand.table + i * 2, "improper branch in tableswitch");
|
| - return false;
|
| - }
|
| - } else {
|
| - if (target >= operand.case_count) {
|
| - error(operand.table + i * 2, "invalid case target in tableswitch");
|
| - return false;
|
| - }
|
| + if (target >= block_depth) {
|
| + error(operand.table + i * 2, "improper branch in br_table");
|
| + return false;
|
| }
|
| }
|
| return true;
|
| @@ -280,9 +268,8 @@ class WasmDecoder : public Decoder {
|
| case kExprReturn: {
|
| return static_cast<int>(function_env_->sig->return_count());
|
| }
|
| - case kExprTableSwitch: {
|
| - TableSwitchOperand operand(this, pc);
|
| - return 1 + operand.case_count;
|
| + case kExprBrTable: {
|
| + return 1;
|
| }
|
|
|
| #define DECLARE_OPCODE_CASE(name, opcode, sig) \
|
| @@ -344,8 +331,8 @@ class WasmDecoder : public Decoder {
|
| LocalIndexOperand operand(this, pc);
|
| return 1 + operand.length;
|
| }
|
| - case kExprTableSwitch: {
|
| - TableSwitchOperand operand(this, pc);
|
| + case kExprBrTable: {
|
| + BranchTableOperand operand(this, pc);
|
| return 1 + operand.length;
|
| }
|
| case kExprI8Const:
|
| @@ -656,10 +643,10 @@ class LR_WasmDecoder : public WasmDecoder {
|
| len = 1 + operand.length;
|
| break;
|
| }
|
| - case kExprTableSwitch: {
|
| - TableSwitchOperand operand(this, pc_);
|
| + case kExprBrTable: {
|
| + BranchTableOperand operand(this, pc_);
|
| if (Validate(pc_, operand, blocks_.size())) {
|
| - Shift(kAstEnd, 1 + operand.case_count);
|
| + Shift(kAstEnd, 1);
|
| }
|
| len = 1 + operand.length;
|
| break;
|
| @@ -1044,68 +1031,37 @@ class LR_WasmDecoder : public WasmDecoder {
|
| }
|
| break;
|
| }
|
| - case kExprTableSwitch: {
|
| + case kExprBrTable: {
|
| if (p->index == 1) {
|
| // Switch key finished.
|
| TypeCheckLast(p, kAstI32);
|
| if (failed()) break;
|
|
|
| - TableSwitchOperand operand(this, p->pc());
|
| + BranchTableOperand operand(this, p->pc());
|
| DCHECK(Validate(p->pc(), operand, blocks_.size()));
|
|
|
| - // Build the switch only if it has more than just a default target.
|
| - bool build_switch = operand.table_count > 1;
|
| + // Build a switch only if it has more than just a default target.
|
| + bool build_switch = operand.table_count > 0;
|
| TFNode* sw = nullptr;
|
| - if (build_switch)
|
| - sw = BUILD(Switch, operand.table_count, p->last()->node);
|
| -
|
| - // Allocate environments for each case.
|
| - SsaEnv** case_envs = zone_->NewArray<SsaEnv*>(operand.case_count);
|
| - for (uint32_t i = 0; i < operand.case_count; i++) {
|
| - case_envs[i] = UnreachableEnv();
|
| + if (build_switch) {
|
| + sw = BUILD(Switch, operand.table_count + 1, p->last()->node);
|
| }
|
|
|
| - ifs_.push_back({nullptr, nullptr, case_envs});
|
| - SsaEnv* break_env = ssa_env_;
|
| - PushBlock(break_env);
|
| - SsaEnv* copy = Steal(break_env);
|
| - ssa_env_ = copy;
|
| -
|
| - // Build the environments for each case based on the table.
|
| - for (uint32_t i = 0; i < operand.table_count; i++) {
|
| + // Process the targets of the break table.
|
| + SsaEnv* prev = ssa_env_;
|
| + SsaEnv* copy = Steal(prev);
|
| + for (uint32_t i = 0; i < operand.table_count + 1; i++) {
|
| uint16_t target = operand.read_entry(this, i);
|
| SsaEnv* env = copy;
|
| if (build_switch) {
|
| - env = Split(env);
|
| - env->control = (i == operand.table_count - 1)
|
| - ? BUILD(IfDefault, sw)
|
| - : BUILD(IfValue, i, sw);
|
| - }
|
| - if (target >= 0x8000) {
|
| - // Targets an outer block.
|
| - int depth = target - 0x8000;
|
| - SsaEnv* tenv = blocks_[blocks_.size() - depth - 1].ssa_env;
|
| - Goto(env, tenv);
|
| - } else {
|
| - // Targets a case.
|
| - Goto(env, case_envs[target]);
|
| + ssa_env_ = env = Split(env);
|
| + env->control = i == operand.table_count ? BUILD(IfDefault, sw)
|
| + : BUILD(IfValue, i, sw);
|
| }
|
| + SsaEnv* tenv = blocks_[blocks_.size() - target - 1].ssa_env;
|
| + Goto(env, tenv);
|
| }
|
| - }
|
| -
|
| - 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 {
|
| - // 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);
|
| + ssa_env_ = prev;
|
| }
|
| break;
|
| }
|
|
|