Chromium Code Reviews| 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); |
|
ahaas
2016/09/16 13:48:19
pcdiff_t is hardly any longer than auto.
|
| + 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_; |
| } |