Index: src/wasm/wasm-interpreter.cc |
diff --git a/src/wasm/wasm-interpreter.cc b/src/wasm/wasm-interpreter.cc |
index 2db5e8cd92d3b1ccafa38bbd29d93c493d0f4870..2ac681eff293dbb1a640ebb16bf6c6e1347323a6 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,104 @@ 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); |
- 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); |
+ BranchTableIterator iterator(&i, operand); |
+ TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(), |
+ operand.table_count); |
+ while (iterator.has_next()) { |
+ uint32_t j = iterator.cur_index(); |
+ uint32_t target = iterator.next(); |
+ 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 +931,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 +972,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 +993,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 +1044,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 +1072,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 +1108,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 +1149,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_.empty() && 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 +1189,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 +1201,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 +1231,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 +1265,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 +1308,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 +1344,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 +1387,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 +1412,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 +1427,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 +1465,6 @@ class ThreadImpl : public WasmInterpreter::Thread { |
} else { |
UNREACHABLE(); |
} |
- Push(pc, val); |
len = 1 + operand.length; |
break; |
} |
@@ -1528,7 +1513,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; \ |
} |
@@ -1594,7 +1578,8 @@ class ThreadImpl : public WasmInterpreter::Thread { |
break; |
} |
case kExprMemorySize: { |
- Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size))); |
+ Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size / |
+ WasmModule::kPageSize))); |
break; |
} |
#define EXECUTE_SIMPLE_BINOP(name, ctype, op) \ |
@@ -1669,7 +1654,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 +1835,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_; |
} |