| Index: src/wasm/wasm-interpreter.cc
|
| diff --git a/src/wasm/wasm-interpreter.cc b/src/wasm/wasm-interpreter.cc
|
| index 8c23bb2fd8872150f414fcec3e4bfd520b80ea0c..a2134734990cece9d719644c06a16cb260aaaaaa 100644
|
| --- a/src/wasm/wasm-interpreter.cc
|
| +++ b/src/wasm/wasm-interpreter.cc
|
| @@ -722,54 +722,38 @@ class ControlTransfers : public ZoneObject {
|
| public:
|
| ControlTransferMap map_;
|
|
|
| - ControlTransfers(Zone* zone, size_t locals_encoded_size, const byte* start,
|
| - const byte* end)
|
| + ControlTransfers(Zone* zone, ModuleEnv* env, AstLocalDecls* locals,
|
| + const byte* start, const byte* end)
|
| : map_(zone) {
|
| - // A control reference including from PC, from value depth, and whether
|
| - // a value is explicitly passed (e.g. br/br_if/br_table with value).
|
| - struct CRef {
|
| - const byte* pc;
|
| - sp_t value_depth;
|
| - bool explicit_value;
|
| - };
|
| -
|
| // Represents a control flow label.
|
| struct CLabel : public ZoneObject {
|
| const byte* target;
|
| - size_t value_depth;
|
| - ZoneVector<CRef> refs;
|
| + ZoneVector<const byte*> refs;
|
|
|
| - CLabel(Zone* zone, size_t v)
|
| - : target(nullptr), value_depth(v), refs(zone) {}
|
| + explicit CLabel(Zone* zone) : target(nullptr), refs(zone) {}
|
|
|
| // Bind this label to the given PC.
|
| - void Bind(ControlTransferMap* map, const byte* start, const byte* pc,
|
| - bool expect_value) {
|
| + void Bind(ControlTransferMap* map, const byte* start, const byte* pc) {
|
| DCHECK_NULL(target);
|
| target = pc;
|
| - for (auto from : refs) {
|
| - auto pcdiff = static_cast<pcdiff_t>(target - from.pc);
|
| - auto spdiff = static_cast<spdiff_t>(from.value_depth - value_depth);
|
| - ControlTransfer::StackAction action = ControlTransfer::kNoAction;
|
| - if (expect_value && !from.explicit_value) {
|
| - action = spdiff == 0 ? ControlTransfer::kPushVoid
|
| - : ControlTransfer::kPopAndRepush;
|
| - }
|
| - pc_t offset = static_cast<size_t>(from.pc - start);
|
| - (*map)[offset] = {pcdiff, spdiff, action};
|
| + for (auto from_pc : refs) {
|
| + auto pcdiff = static_cast<pcdiff_t>(target - from_pc);
|
| + size_t offset = static_cast<size_t>(from_pc - start);
|
| + (*map)[offset] = pcdiff;
|
| }
|
| }
|
|
|
| // Reference this label from the given location.
|
| - void Ref(ControlTransferMap* map, const byte* start, CRef from) {
|
| - DCHECK_GE(from.value_depth, value_depth);
|
| + void Ref(ControlTransferMap* map, const byte* start,
|
| + const byte* from_pc) {
|
| if (target) {
|
| - auto pcdiff = static_cast<pcdiff_t>(target - from.pc);
|
| - auto spdiff = static_cast<spdiff_t>(from.value_depth - value_depth);
|
| - pc_t offset = static_cast<size_t>(from.pc - start);
|
| - (*map)[offset] = {pcdiff, spdiff, ControlTransfer::kNoAction};
|
| + // Target being bound before a reference means this is a loop.
|
| + DCHECK_EQ(kExprLoop, *target);
|
| + auto pcdiff = static_cast<pcdiff_t>(target - from_pc);
|
| + size_t offset = static_cast<size_t>(from_pc - start);
|
| + (*map)[offset] = pcdiff;
|
| } else {
|
| - refs.push_back(from);
|
| + refs.push_back(from_pc);
|
| }
|
| }
|
| };
|
| @@ -780,122 +764,102 @@ class ControlTransfers : public ZoneObject {
|
| CLabel* end_label;
|
| CLabel* else_label;
|
|
|
| - void Ref(ControlTransferMap* map, const byte* start, const byte* from_pc,
|
| - size_t from_value_depth, bool explicit_value) {
|
| - end_label->Ref(map, start, {from_pc, from_value_depth, explicit_value});
|
| + void Ref(ControlTransferMap* map, const byte* start,
|
| + const byte* from_pc) {
|
| + end_label->Ref(map, start, from_pc);
|
| }
|
| };
|
|
|
| // Compute the ControlTransfer map.
|
| - // This works by maintaining a stack of control constructs similar to the
|
| + // This algorithm maintains a stack of control constructs similar to the
|
| // AST decoder. The {control_stack} allows matching {br,br_if,br_table}
|
| // bytecodes with their target, as well as determining whether the current
|
| // bytecodes are within the true or false block of an else.
|
| - // The value stack depth is tracked as {value_depth} and is needed to
|
| - // determine how many values to pop off the stack for explicit and
|
| - // implicit control flow.
|
| -
|
| std::vector<Control> control_stack;
|
| - size_t value_depth = 0;
|
| - for (BytecodeIterator i(start + locals_encoded_size, end); i.has_next();
|
| - i.next()) {
|
| + CLabel* func_label = new (zone) CLabel(zone);
|
| + control_stack.push_back({start, func_label, nullptr});
|
| + for (BytecodeIterator i(start, end, locals); i.has_next(); i.next()) {
|
| WasmOpcode opcode = i.current();
|
| - TRACE("@%u: control %s (depth = %zu)\n", i.pc_offset(),
|
| - WasmOpcodes::OpcodeName(opcode), value_depth);
|
| + TRACE("@%u: control %s\n", i.pc_offset(),
|
| + WasmOpcodes::OpcodeName(opcode));
|
| switch (opcode) {
|
| case kExprBlock: {
|
| - TRACE("control @%u $%zu: Block\n", i.pc_offset(), value_depth);
|
| - CLabel* label = new (zone) CLabel(zone, value_depth);
|
| + TRACE("control @%u: Block\n", i.pc_offset());
|
| + CLabel* label = new (zone) CLabel(zone);
|
| control_stack.push_back({i.pc(), label, nullptr});
|
| break;
|
| }
|
| case kExprLoop: {
|
| - TRACE("control @%u $%zu: Loop\n", i.pc_offset(), value_depth);
|
| - CLabel* label1 = new (zone) CLabel(zone, value_depth);
|
| - CLabel* label2 = new (zone) CLabel(zone, value_depth);
|
| - control_stack.push_back({i.pc(), label1, nullptr});
|
| - control_stack.push_back({i.pc(), label2, nullptr});
|
| - label2->Bind(&map_, start, i.pc(), false);
|
| + TRACE("control @%u: Loop\n", i.pc_offset());
|
| + CLabel* label = new (zone) CLabel(zone);
|
| + control_stack.push_back({i.pc(), label, nullptr});
|
| + label->Bind(&map_, start, i.pc());
|
| break;
|
| }
|
| case kExprIf: {
|
| - TRACE("control @%u $%zu: If\n", i.pc_offset(), value_depth);
|
| - value_depth--;
|
| - CLabel* end_label = new (zone) CLabel(zone, value_depth);
|
| - CLabel* else_label = new (zone) CLabel(zone, value_depth);
|
| + TRACE("control @%u: If\n", i.pc_offset());
|
| + CLabel* end_label = new (zone) CLabel(zone);
|
| + CLabel* else_label = new (zone) CLabel(zone);
|
| control_stack.push_back({i.pc(), end_label, else_label});
|
| - else_label->Ref(&map_, start, {i.pc(), value_depth, false});
|
| + else_label->Ref(&map_, start, i.pc());
|
| break;
|
| }
|
| case kExprElse: {
|
| Control* c = &control_stack.back();
|
| - TRACE("control @%u $%zu: Else\n", i.pc_offset(), value_depth);
|
| - c->end_label->Ref(&map_, start, {i.pc(), value_depth, false});
|
| - value_depth = c->end_label->value_depth;
|
| + TRACE("control @%u: Else\n", i.pc_offset());
|
| + c->end_label->Ref(&map_, start, i.pc());
|
| DCHECK_NOT_NULL(c->else_label);
|
| - c->else_label->Bind(&map_, start, i.pc() + 1, false);
|
| + c->else_label->Bind(&map_, start, i.pc() + 1);
|
| c->else_label = nullptr;
|
| break;
|
| }
|
| case kExprEnd: {
|
| Control* c = &control_stack.back();
|
| - TRACE("control @%u $%zu: End\n", i.pc_offset(), value_depth);
|
| + TRACE("control @%u: End\n", i.pc_offset());
|
| if (c->end_label->target) {
|
| // only loops have bound labels.
|
| DCHECK_EQ(kExprLoop, *c->pc);
|
| - control_stack.pop_back();
|
| - c = &control_stack.back();
|
| + } else {
|
| + if (c->else_label) c->else_label->Bind(&map_, start, i.pc());
|
| + c->end_label->Bind(&map_, start, i.pc() + 1);
|
| }
|
| - if (c->else_label)
|
| - c->else_label->Bind(&map_, start, i.pc() + 1, true);
|
| - c->end_label->Ref(&map_, start, {i.pc(), value_depth, false});
|
| - c->end_label->Bind(&map_, start, i.pc() + 1, true);
|
| - value_depth = c->end_label->value_depth + 1;
|
| control_stack.pop_back();
|
| break;
|
| }
|
| case kExprBr: {
|
| BreakDepthOperand operand(&i, i.pc());
|
| - TRACE("control @%u $%zu: Br[arity=%u, depth=%u]\n", i.pc_offset(),
|
| - value_depth, operand.arity, operand.depth);
|
| - value_depth -= operand.arity;
|
| - control_stack[control_stack.size() - operand.depth - 1].Ref(
|
| - &map_, start, i.pc(), value_depth, operand.arity > 0);
|
| - value_depth++;
|
| + TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth);
|
| + Control* c = &control_stack[control_stack.size() - operand.depth - 1];
|
| + c->Ref(&map_, start, i.pc());
|
| break;
|
| }
|
| case kExprBrIf: {
|
| BreakDepthOperand operand(&i, i.pc());
|
| - TRACE("control @%u $%zu: BrIf[arity=%u, depth=%u]\n", i.pc_offset(),
|
| - value_depth, operand.arity, operand.depth);
|
| - value_depth -= (operand.arity + 1);
|
| - control_stack[control_stack.size() - operand.depth - 1].Ref(
|
| - &map_, start, i.pc(), value_depth, operand.arity > 0);
|
| - value_depth++;
|
| + TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth);
|
| + Control* c = &control_stack[control_stack.size() - operand.depth - 1];
|
| + c->Ref(&map_, start, i.pc());
|
| break;
|
| }
|
| case kExprBrTable: {
|
| BranchTableOperand operand(&i, i.pc());
|
| - TRACE("control @%u $%zu: BrTable[arity=%u count=%u]\n", i.pc_offset(),
|
| - value_depth, operand.arity, operand.table_count);
|
| - value_depth -= (operand.arity + 1);
|
| + TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
|
| + operand.table_count);
|
| for (uint32_t j = 0; j < operand.table_count + 1; ++j) {
|
| uint32_t target = operand.read_entry(&i, j);
|
| - control_stack[control_stack.size() - target - 1].Ref(
|
| - &map_, start, i.pc() + j, value_depth, operand.arity > 0);
|
| + Control* c = &control_stack[control_stack.size() - target - 1];
|
| + c->Ref(&map_, start, i.pc() + j);
|
| }
|
| - value_depth++;
|
| break;
|
| }
|
| default: {
|
| - value_depth = value_depth - OpcodeArity(i.pc(), end) + 1;
|
| break;
|
| }
|
| }
|
| }
|
| + if (!func_label->target) func_label->Bind(&map_, start, end);
|
| }
|
|
|
| - ControlTransfer Lookup(pc_t from) {
|
| + pcdiff_t Lookup(pc_t from) {
|
| auto result = map_.find(from);
|
| if (result == map_.end()) {
|
| V8_Fatal(__FILE__, __LINE__, "no control target for pc %zu", from);
|
| @@ -965,9 +929,9 @@ class CodeMap {
|
| if (code->targets == nullptr && code->start) {
|
| // Compute the control targets map and the local declarations.
|
| CHECK(DecodeLocalDecls(code->locals, code->start, code->end));
|
| - code->targets =
|
| - new (zone_) ControlTransfers(zone_, code->locals.decls_encoded_size,
|
| - code->orig_start, code->orig_end);
|
| + ModuleEnv env = {module_, nullptr, kWasmOrigin};
|
| + code->targets = new (zone_) ControlTransfers(
|
| + zone_, &env, &code->locals, code->orig_start, code->orig_end);
|
| }
|
| return code;
|
| }
|
| @@ -1006,6 +970,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| instance_(instance),
|
| stack_(zone),
|
| frames_(zone),
|
| + blocks_(zone),
|
| state_(WasmInterpreter::STOPPED),
|
| break_pc_(kInvalidPc),
|
| trap_reason_(kTrapCount) {}
|
| @@ -1026,6 +991,9 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| stack_.push_back(args[i]);
|
| }
|
| frames_.back().ret_pc = InitLocals(code);
|
| + blocks_.push_back(
|
| + {0, stack_.size(), frames_.size(),
|
| + static_cast<uint32_t>(code->function->sig->return_count())});
|
| TRACE(" => PushFrame(#%u @%zu)\n", code->function->func_index,
|
| frames_.back().ret_pc);
|
| }
|
| @@ -1074,11 +1042,11 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| return nullptr;
|
| }
|
|
|
| - virtual WasmVal GetReturnValue() {
|
| + virtual WasmVal GetReturnValue(int index) {
|
| if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef);
|
| CHECK_EQ(WasmInterpreter::FINISHED, state_);
|
| - CHECK_EQ(1, stack_.size());
|
| - return stack_[0];
|
| + CHECK_LT(static_cast<size_t>(index), stack_.size());
|
| + return stack_[index];
|
| }
|
|
|
| virtual pc_t GetBreakpointPc() { return break_pc_; }
|
| @@ -1102,10 +1070,18 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| sp_t llimit() { return plimit() + code->locals.total_local_count; }
|
| };
|
|
|
| + struct Block {
|
| + pc_t pc;
|
| + sp_t sp;
|
| + size_t fp;
|
| + unsigned arity;
|
| + };
|
| +
|
| CodeMap* codemap_;
|
| WasmModuleInstance* instance_;
|
| ZoneVector<WasmVal> stack_;
|
| ZoneVector<Frame> frames_;
|
| + ZoneVector<Block> blocks_;
|
| WasmInterpreter::State state_;
|
| pc_t break_pc_;
|
| TrapReason trap_reason_;
|
| @@ -1130,6 +1106,9 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| DCHECK_GE(stack_.size(), arity);
|
| // The parameters will overlap the arguments already on the stack.
|
| frames_.push_back({code, 0, 0, stack_.size() - arity});
|
| + blocks_.push_back(
|
| + {0, stack_.size(), frames_.size(),
|
| + static_cast<uint32_t>(code->function->sig->return_count())});
|
| frames_.back().ret_pc = InitLocals(code);
|
| TRACE(" => push func#%u @%zu\n", code->function->func_index,
|
| frames_.back().ret_pc);
|
| @@ -1168,21 +1147,38 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
|
|
| bool SkipBreakpoint(InterpreterCode* code, pc_t pc) {
|
| if (pc == break_pc_) {
|
| + // Skip the previously hit breakpoint when resuming.
|
| break_pc_ = kInvalidPc;
|
| return true;
|
| }
|
| return false;
|
| }
|
|
|
| - bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, WasmVal val) {
|
| + int LookupTarget(InterpreterCode* code, pc_t pc) {
|
| + return static_cast<int>(code->targets->Lookup(pc));
|
| + }
|
| +
|
| + int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) {
|
| + size_t bp = blocks_.size() - depth - 1;
|
| + Block* target = &blocks_[bp];
|
| + DoStackTransfer(target->sp, target->arity);
|
| + blocks_.resize(bp);
|
| + return LookupTarget(code, pc);
|
| + }
|
| +
|
| + bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, size_t arity) {
|
| DCHECK_GT(frames_.size(), 0u);
|
| - stack_.resize(frames_.back().sp);
|
| + // Pop all blocks for this frame.
|
| + while (blocks_.size() > 0 && blocks_.back().fp == frames_.size()) {
|
| + blocks_.pop_back();
|
| + }
|
| +
|
| + sp_t dest = frames_.back().sp;
|
| frames_.pop_back();
|
| if (frames_.size() == 0) {
|
| - // A return from the top frame terminates the execution.
|
| + // A return from the last frame terminates the execution.
|
| state_ = WasmInterpreter::FINISHED;
|
| - stack_.clear();
|
| - stack_.push_back(val);
|
| + DoStackTransfer(0, arity);
|
| TRACE(" => finish\n");
|
| return false;
|
| } else {
|
| @@ -1191,16 +1187,8 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| *code = top->code;
|
| *pc = top->ret_pc;
|
| *limit = top->code->end - top->code->start;
|
| - if (top->code->start[top->call_pc] == kExprCallIndirect ||
|
| - (top->code->orig_start &&
|
| - top->code->orig_start[top->call_pc] == kExprCallIndirect)) {
|
| - // UGLY: An indirect call has the additional function index on the
|
| - // stack.
|
| - stack_.pop_back();
|
| - }
|
| TRACE(" => pop func#%u @%zu\n", (*code)->function->func_index, *pc);
|
| -
|
| - stack_.push_back(val);
|
| + DoStackTransfer(dest, arity);
|
| return true;
|
| }
|
| }
|
| @@ -1211,31 +1199,21 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| *limit = target->end - target->start;
|
| }
|
|
|
| - // Adjust the program counter {pc} and the stack contents according to the
|
| - // code's precomputed control transfer map. Returns the different between
|
| - // the new pc and the old pc.
|
| - int DoControlTransfer(InterpreterCode* code, pc_t pc) {
|
| - auto target = code->targets->Lookup(pc);
|
| - switch (target.action) {
|
| - case ControlTransfer::kNoAction:
|
| - TRACE(" action [sp-%u]\n", target.spdiff);
|
| - PopN(target.spdiff);
|
| - break;
|
| - case ControlTransfer::kPopAndRepush: {
|
| - WasmVal val = Pop();
|
| - TRACE(" action [pop x, sp-%u, push x]\n", target.spdiff - 1);
|
| - DCHECK_GE(target.spdiff, 1u);
|
| - PopN(target.spdiff - 1);
|
| - Push(pc, val);
|
| - break;
|
| - }
|
| - case ControlTransfer::kPushVoid:
|
| - TRACE(" action [sp-%u, push void]\n", target.spdiff);
|
| - PopN(target.spdiff);
|
| - Push(pc, WasmVal());
|
| - break;
|
| + // Copies {arity} values on the top of the stack down the stack to {dest},
|
| + // dropping the values in-between.
|
| + void DoStackTransfer(sp_t dest, size_t arity) {
|
| + // before: |---------------| pop_count | arity |
|
| + // ^ 0 ^ dest ^ stack_.size()
|
| + //
|
| + // after: |---------------| arity |
|
| + // ^ 0 ^ stack_.size()
|
| + DCHECK_LE(dest, stack_.size());
|
| + DCHECK_LE(dest + arity, stack_.size());
|
| + size_t pop_count = stack_.size() - dest - arity;
|
| + for (size_t i = 0; i < arity; i++) {
|
| + stack_[dest + i] = stack_[dest + pop_count + i];
|
| }
|
| - return target.pcdiff;
|
| + stack_.resize(stack_.size() - pop_count);
|
| }
|
|
|
| void Execute(InterpreterCode* code, pc_t pc, int max) {
|
| @@ -1251,8 +1229,8 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| if (pc >= limit) {
|
| // Fell off end of code; do an implicit return.
|
| TRACE("@%-3zu: ImplicitReturn\n", pc);
|
| - WasmVal val = PopArity(code->function->sig->return_count());
|
| - if (!DoReturn(&code, &pc, &limit, val)) return;
|
| + if (!DoReturn(&code, &pc, &limit, code->function->sig->return_count()))
|
| + return;
|
| decoder.Reset(code->start, code->end);
|
| continue;
|
| }
|
| @@ -1285,27 +1263,37 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
|
|
| switch (orig) {
|
| case kExprNop:
|
| - Push(pc, WasmVal());
|
| break;
|
| - case kExprBlock:
|
| + case kExprBlock: {
|
| + BlockTypeOperand operand(&decoder, code->at(pc));
|
| + blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
|
| + len = 1 + operand.length;
|
| + break;
|
| + }
|
| case kExprLoop: {
|
| - // Do nothing.
|
| + BlockTypeOperand operand(&decoder, code->at(pc));
|
| + blocks_.push_back({pc, stack_.size(), frames_.size(), 0});
|
| + len = 1 + operand.length;
|
| break;
|
| }
|
| case kExprIf: {
|
| + BlockTypeOperand operand(&decoder, code->at(pc));
|
| WasmVal cond = Pop();
|
| bool is_true = cond.to<uint32_t>() != 0;
|
| + blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
|
| if (is_true) {
|
| // fall through to the true block.
|
| + len = 1 + operand.length;
|
| TRACE(" true => fallthrough\n");
|
| } else {
|
| - len = DoControlTransfer(code, pc);
|
| + len = LookupTarget(code, pc);
|
| TRACE(" false => @%zu\n", pc + len);
|
| }
|
| break;
|
| }
|
| case kExprElse: {
|
| - len = DoControlTransfer(code, pc);
|
| + blocks_.pop_back();
|
| + len = LookupTarget(code, pc);
|
| TRACE(" end => @%zu\n", pc + len);
|
| break;
|
| }
|
| @@ -1318,42 +1306,34 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| }
|
| case kExprBr: {
|
| BreakDepthOperand operand(&decoder, code->at(pc));
|
| - WasmVal val = PopArity(operand.arity);
|
| - len = DoControlTransfer(code, pc);
|
| + len = DoBreak(code, pc, operand.depth);
|
| TRACE(" br => @%zu\n", pc + len);
|
| - if (operand.arity > 0) Push(pc, val);
|
| break;
|
| }
|
| case kExprBrIf: {
|
| BreakDepthOperand operand(&decoder, code->at(pc));
|
| WasmVal cond = Pop();
|
| - WasmVal val = PopArity(operand.arity);
|
| bool is_true = cond.to<uint32_t>() != 0;
|
| if (is_true) {
|
| - len = DoControlTransfer(code, pc);
|
| + len = DoBreak(code, pc, operand.depth);
|
| TRACE(" br_if => @%zu\n", pc + len);
|
| - if (operand.arity > 0) Push(pc, val);
|
| } else {
|
| TRACE(" false => fallthrough\n");
|
| len = 1 + operand.length;
|
| - Push(pc, WasmVal());
|
| }
|
| break;
|
| }
|
| case kExprBrTable: {
|
| BranchTableOperand operand(&decoder, code->at(pc));
|
| uint32_t key = Pop().to<uint32_t>();
|
| - WasmVal val = PopArity(operand.arity);
|
| if (key >= operand.table_count) key = operand.table_count;
|
| - len = DoControlTransfer(code, pc + key) + key;
|
| - TRACE(" br[%u] => @%zu\n", key, pc + len);
|
| - if (operand.arity > 0) Push(pc, val);
|
| + len = key + DoBreak(code, pc + key, operand.table[key]);
|
| + TRACE(" br[%u] => @%zu\n", key, pc + key + len);
|
| break;
|
| }
|
| case kExprReturn: {
|
| - ReturnArityOperand operand(&decoder, code->at(pc));
|
| - WasmVal val = PopArity(operand.arity);
|
| - if (!DoReturn(&code, &pc, &limit, val)) return;
|
| + size_t arity = code->function->sig->return_count();
|
| + if (!DoReturn(&code, &pc, &limit, arity)) return;
|
| decoder.Reset(code->start, code->end);
|
| continue;
|
| }
|
| @@ -1362,8 +1342,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| return CommitPc(pc);
|
| }
|
| case kExprEnd: {
|
| - len = DoControlTransfer(code, pc);
|
| - DCHECK_EQ(1, len);
|
| + blocks_.pop_back();
|
| break;
|
| }
|
| case kExprI8Const: {
|
| @@ -1406,10 +1385,21 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| LocalIndexOperand operand(&decoder, code->at(pc));
|
| WasmVal val = Pop();
|
| stack_[frames_.back().sp + operand.index] = val;
|
| + len = 1 + operand.length;
|
| + break;
|
| + }
|
| + case kExprTeeLocal: {
|
| + LocalIndexOperand operand(&decoder, code->at(pc));
|
| + WasmVal val = Pop();
|
| + stack_[frames_.back().sp + operand.index] = val;
|
| Push(pc, val);
|
| len = 1 + operand.length;
|
| break;
|
| }
|
| + case kExprDrop: {
|
| + Pop();
|
| + break;
|
| + }
|
| case kExprCallFunction: {
|
| CallFunctionOperand operand(&decoder, code->at(pc));
|
| InterpreterCode* target = codemap()->GetCode(operand.index);
|
| @@ -1420,9 +1410,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| }
|
| case kExprCallIndirect: {
|
| CallIndirectOperand operand(&decoder, code->at(pc));
|
| - size_t index = stack_.size() - operand.arity - 1;
|
| - DCHECK_LT(index, stack_.size());
|
| - uint32_t entry_index = stack_[index].to<uint32_t>();
|
| + uint32_t entry_index = Pop().to<uint32_t>();
|
| // Assume only one table for now.
|
| DCHECK_LE(module()->function_tables.size(), 1u);
|
| InterpreterCode* target = codemap()->GetIndirectCode(0, entry_index);
|
| @@ -1437,10 +1425,6 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| decoder.Reset(code->start, code->end);
|
| continue;
|
| }
|
| - case kExprCallImport: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| case kExprGetGlobal: {
|
| GlobalIndexOperand operand(&decoder, code->at(pc));
|
| const WasmGlobal* global = &module()->globals[operand.index];
|
| @@ -1479,7 +1463,6 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| } else {
|
| UNREACHABLE();
|
| }
|
| - Push(pc, val);
|
| len = 1 + operand.length;
|
| break;
|
| }
|
| @@ -1528,7 +1511,6 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| } \
|
| byte* addr = instance()->mem_start + operand.offset + index; \
|
| WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \
|
| - Push(pc, val); \
|
| len = 1 + operand.length; \
|
| break; \
|
| }
|
| @@ -1669,7 +1651,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
|
|
| void Push(pc_t pc, WasmVal val) {
|
| // TODO(titzer): store PC as well?
|
| - stack_.push_back(val);
|
| + if (val.type != kAstStmt) stack_.push_back(val);
|
| }
|
|
|
| void TraceStack(const char* phase, pc_t pc) {
|
| @@ -1850,7 +1832,7 @@ bool WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
|
|
|
| ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
|
| Zone* zone, const byte* start, const byte* end) {
|
| - ControlTransfers targets(zone, 0, start, end);
|
| + ControlTransfers targets(zone, nullptr, nullptr, start, end);
|
| return targets.map_;
|
| }
|
|
|
|
|