Commit 213d1fa6 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] [interpreter] Avoid redundant stack limit checks

The interpreter used a ZoneVector<WasmVal> to model the value stack.
Thus, at each single pop to the stack, a bounds check was performed,
and the storage was potentially extended.
This CL changes this to pre-allocate enough space for the stack of a
function when a new frame is entered. This avoids any checks for pushs
and pops.
Instead of storing a ZoneVector<WasmVal>, we store WasmVal* directly.
The maximum value stack size is precomputed together with the control
transfer side table.

This CL speeds up interpreted execution by 15% on average (measured
locally on a Z840).

R=ahaas@chromium.org
BUG=v8:5822

Change-Id: If949f7ee5233d874cd6a04b7dde2d7b4a95e45ea
Reviewed-on: https://chromium-review.googlesource.com/488061
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44902}
parent 23bb8fa9
......@@ -694,7 +694,7 @@ Handle<HeapObject> UnwrapWasmToJSWrapper(Isolate* isolate,
return Handle<HeapObject>::null();
}
class ControlTransfers;
class SideTable;
// Code and metadata needed to execute a function.
struct InterpreterCode {
......@@ -704,7 +704,7 @@ struct InterpreterCode {
const byte* orig_end; // end of original code
byte* start; // start of (maybe altered) code
byte* end; // end of (maybe altered) code
ControlTransfers* targets; // helper for control flow.
SideTable* side_table; // precomputed side table for control flow.
const byte* at(pc_t pc) { return start + pc; }
};
......@@ -712,12 +712,13 @@ struct InterpreterCode {
// A helper class to compute the control transfers for each bytecode offset.
// Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to
// be directly executed without the need to dynamically track blocks.
class ControlTransfers : public ZoneObject {
class SideTable : public ZoneObject {
public:
ControlTransferMap map_;
uint32_t max_stack_height_;
ControlTransfers(Zone* zone, const WasmModule* module, InterpreterCode* code)
: map_(zone) {
SideTable(Zone* zone, const WasmModule* module, InterpreterCode* code)
: map_(zone), max_stack_height_(0) {
// Create a zone for all temporary objects.
Zone control_transfer_zone(zone->allocator(), ZONE_NAME);
......@@ -808,7 +809,10 @@ class ControlTransfers : public ZoneObject {
WasmOpcodes::OpcodeName(opcode), stack_height, stack_effect.first,
stack_effect.second);
DCHECK_GE(stack_height, stack_effect.first);
DCHECK_GE(kMaxUInt32, static_cast<uint64_t>(stack_height) -
stack_effect.first + stack_effect.second);
stack_height = stack_height - stack_effect.first + stack_effect.second;
if (stack_height > max_stack_height_) max_stack_height_ = stack_height;
switch (opcode) {
case kExprBlock:
case kExprLoop: {
......@@ -1022,9 +1026,9 @@ class CodeMap {
InterpreterCode* Preprocess(InterpreterCode* code) {
DCHECK_EQ(code->function->imported, code->start == nullptr);
if (code->targets == nullptr && code->start != nullptr) {
if (!code->side_table && code->start) {
// Compute the control targets map and the local declarations.
code->targets = new (zone_) ControlTransfers(zone_, module_, code);
code->side_table = new (zone_) SideTable(zone_, module_, code);
}
return code;
}
......@@ -1045,11 +1049,11 @@ class CodeMap {
DCHECK_LT(function->func_index, interpreter_code_.size());
InterpreterCode* code = &interpreter_code_[function->func_index];
DCHECK_EQ(function, code->function);
code->targets = nullptr;
code->orig_start = start;
code->orig_end = end;
code->start = const_cast<byte*>(start);
code->end = const_cast<byte*>(end);
code->side_table = nullptr;
Preprocess(code);
}
......@@ -1153,15 +1157,15 @@ WasmVal ToWebAssemblyValue(Isolate* isolate, Handle<Object> value,
class ThreadImpl {
struct Activation {
uint32_t fp;
uint32_t sp;
Activation(uint32_t fp, uint32_t sp) : fp(fp), sp(sp) {}
sp_t sp;
Activation(uint32_t fp, sp_t sp) : fp(fp), sp(sp) {}
};
public:
ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance)
: codemap_(codemap),
instance_(instance),
stack_(zone),
zone_(zone),
frames_(zone),
activations_(zone) {}
......@@ -1174,9 +1178,9 @@ class ThreadImpl {
void InitFrame(const WasmFunction* function, WasmVal* args) {
DCHECK_EQ(current_activation().fp, frames_.size());
InterpreterCode* code = codemap()->GetCode(function);
for (size_t i = 0; i < function->sig->parameter_count(); ++i) {
stack_.push_back(args[i]);
}
size_t num_params = function->sig->parameter_count();
EnsureStackSpace(num_params);
Push(args, num_params);
PushFrame(code);
}
......@@ -1203,7 +1207,7 @@ class ThreadImpl {
void Reset() {
TRACE("----- RESET -----\n");
stack_.clear();
sp_ = stack_start_;
frames_.clear();
state_ = WasmInterpreter::STOPPED;
trap_reason_ = kTrapCount;
......@@ -1221,13 +1225,17 @@ class ThreadImpl {
Activation act = current_activation();
// Current activation must be finished.
DCHECK_EQ(act.fp, frames_.size());
DCHECK_GT(stack_.size(), act.sp + index);
return stack_[act.sp + index];
return GetStackValue(act.sp + index);
}
WasmVal GetStackValue(uint32_t index) {
DCHECK_GT(stack_.size(), index);
return stack_[index];
WasmVal GetStackValue(sp_t index) {
DCHECK_GT(StackHeight(), index);
return stack_start_[index];
}
void SetStackValue(sp_t index, WasmVal value) {
DCHECK_GT(StackHeight(), index);
stack_start_[index] = value;
}
TrapReason GetTrapReason() { return trap_reason_; }
......@@ -1250,10 +1258,10 @@ class ThreadImpl {
TRACE("----- START ACTIVATION %zu -----\n", activations_.size());
// If you use activations, use them consistently:
DCHECK_IMPLIES(activations_.empty(), frames_.empty());
DCHECK_IMPLIES(activations_.empty(), stack_.empty());
DCHECK_IMPLIES(activations_.empty(), StackHeight() == 0);
uint32_t activation_id = static_cast<uint32_t>(activations_.size());
activations_.emplace_back(static_cast<uint32_t>(frames_.size()),
static_cast<uint32_t>(stack_.size()));
StackHeight());
state_ = WasmInterpreter::STOPPED;
return activation_id;
}
......@@ -1265,8 +1273,8 @@ class ThreadImpl {
// Stack height must match the start of this activation (otherwise unwind
// first).
DCHECK_EQ(activations_.back().fp, frames_.size());
DCHECK_LE(activations_.back().sp, stack_.size());
stack_.resize(activations_.back().sp);
DCHECK_LE(activations_.back().sp, StackHeight());
sp_ = stack_start_ + activations_.back().sp;
activations_.pop_back();
}
......@@ -1287,8 +1295,8 @@ class ThreadImpl {
Activation& act = activations_.back();
DCHECK_LE(act.fp, frames_.size());
frames_.resize(act.fp);
DCHECK_LE(act.sp, stack_.size());
stack_.resize(act.sp);
DCHECK_LE(act.sp, StackHeight());
sp_ = stack_start_ + act.sp;
state_ = WasmInterpreter::STOPPED;
return WasmInterpreter::Thread::UNWOUND;
}
......@@ -1317,7 +1325,10 @@ class ThreadImpl {
CodeMap* codemap_;
WasmInstance* instance_;
ZoneVector<WasmVal> stack_;
Zone* zone_;
WasmVal* stack_start_ = nullptr; // Start of allocated stack space.
WasmVal* stack_limit_ = nullptr; // End of allocated stack space.
WasmVal* sp_ = nullptr; // Current stack pointer.
ZoneVector<Frame> frames_;
WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
pc_t break_pc_ = kInvalidPc;
......@@ -1342,11 +1353,15 @@ class ThreadImpl {
// Push a frame with arguments already on the stack.
void PushFrame(InterpreterCode* code) {
DCHECK_NOT_NULL(code);
DCHECK_NOT_NULL(code->side_table);
EnsureStackSpace(code->side_table->max_stack_height_ +
code->locals.type_list.size());
++num_interpreted_calls_;
size_t arity = code->function->sig->parameter_count();
// The parameters will overlap the arguments already on the stack.
DCHECK_GE(stack_.size(), arity);
frames_.push_back({code, 0, stack_.size() - arity});
DCHECK_GE(StackHeight(), arity);
frames_.push_back({code, 0, StackHeight() - arity});
frames_.back().pc = InitLocals(code);
TRACE(" => PushFrame #%zu (#%u @%zu)\n", frames_.size() - 1,
code->function->func_index, frames_.back().pc);
......@@ -1366,7 +1381,7 @@ class ThreadImpl {
UNREACHABLE();
break;
}
stack_.push_back(val);
Push(val);
}
return code->locals.encoded_size;
}
......@@ -1386,12 +1401,12 @@ class ThreadImpl {
}
int LookupTargetDelta(InterpreterCode* code, pc_t pc) {
return static_cast<int>(code->targets->Lookup(pc).pc_diff);
return static_cast<int>(code->side_table->Lookup(pc).pc_diff);
}
int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) {
ControlTransferEntry& control_transfer_entry = code->targets->Lookup(pc);
DoStackTransfer(stack_.size() - control_transfer_entry.sp_diff,
ControlTransferEntry& control_transfer_entry = code->side_table->Lookup(pc);
DoStackTransfer(sp_ - control_transfer_entry.sp_diff,
control_transfer_entry.target_arity);
return control_transfer_entry.pc_diff;
}
......@@ -1415,12 +1430,12 @@ class ThreadImpl {
bool DoReturn(Decoder* decoder, InterpreterCode** code, pc_t* pc, pc_t* limit,
size_t arity) {
DCHECK_GT(frames_.size(), 0);
sp_t dest = frames_.back().sp;
WasmVal* sp_dest = stack_start_ + frames_.back().sp;
frames_.pop_back();
if (frames_.size() == current_activation().fp) {
// A return from the last frame terminates the execution.
state_ = WasmInterpreter::FINISHED;
DoStackTransfer(dest, arity);
DoStackTransfer(sp_dest, arity);
TRACE(" => finish\n");
return false;
} else {
......@@ -1432,7 +1447,7 @@ class ThreadImpl {
*limit = top->code->end - top->code->start;
TRACE(" => Return to #%zu (#%u @%zu)\n", frames_.size() - 1,
(*code)->function->func_index, *pc);
DoStackTransfer(dest, arity);
DoStackTransfer(sp_dest, arity);
return true;
}
}
......@@ -1452,19 +1467,16 @@ class ThreadImpl {
// 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) {
void DoStackTransfer(WasmVal* dest, size_t arity) {
// before: |---------------| pop_count | arity |
// ^ 0 ^ dest ^ stack_.size()
// ^ 0 ^ dest ^ sp_
//
// 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];
}
stack_.resize(stack_.size() - pop_count);
// ^ 0 ^ sp_
DCHECK_LE(dest, sp_);
DCHECK_LE(dest + arity, sp_);
if (arity) memcpy(dest, sp_ - arity, arity * sizeof(*sp_));
sp_ = dest + arity;
}
template <typename mtype>
......@@ -1484,7 +1496,7 @@ class ThreadImpl {
byte* addr = instance()->mem_start + operand.offset + index;
WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr)));
Push(pc, result);
Push(result);
len = 1 + operand.length;
return true;
}
......@@ -1537,6 +1549,15 @@ class ThreadImpl {
}
void Execute(InterpreterCode* code, pc_t pc, int max) {
DCHECK_NOT_NULL(code->side_table);
DCHECK(!frames_.empty());
// There must be enough space on the stack to hold the arguments, locals,
// and the value stack.
DCHECK_LE(code->function->sig->parameter_count() +
code->locals.type_list.size() +
code->side_table->max_stack_height_,
stack_limit_ - stack_start_ - frames_.back().sp);
Decoder decoder(code->start, code->end);
pc_t limit = code->end - code->start;
bool hit_break = false;
......@@ -1587,9 +1608,8 @@ class ThreadImpl {
std::pair<uint32_t, uint32_t> stack_effect = wasm::StackEffect(
codemap_->module(), frames_.back().code->function->sig,
code->orig_start + pc, code->orig_end);
uint32_t expected_new_stack_height =
static_cast<uint32_t>(stack_.size()) - stack_effect.first +
stack_effect.second;
sp_t expected_new_stack_height =
StackHeight() - stack_effect.first + stack_effect.second;
#endif
switch (orig) {
......@@ -1628,7 +1648,7 @@ class ThreadImpl {
WasmVal cond = Pop();
WasmVal fval = Pop();
WasmVal tval = Pop();
Push(pc, cond.to<int32_t>() != 0 ? tval : fval);
Push(cond.to<int32_t>() != 0 ? tval : fval);
break;
}
case kExprBr: {
......@@ -1678,46 +1698,46 @@ class ThreadImpl {
}
case kExprI32Const: {
ImmI32Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
Push(WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprI64Const: {
ImmI64Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
Push(WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprF32Const: {
ImmF32Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
Push(WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprF64Const: {
ImmF64Operand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(operand.value));
Push(WasmVal(operand.value));
len = 1 + operand.length;
break;
}
case kExprGetLocal: {
LocalIndexOperand<false> operand(&decoder, code->at(pc));
Push(pc, stack_[frames_.back().sp + operand.index]);
Push(GetStackValue(frames_.back().sp + operand.index));
len = 1 + operand.length;
break;
}
case kExprSetLocal: {
LocalIndexOperand<false> operand(&decoder, code->at(pc));
WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val;
SetStackValue(frames_.back().sp + operand.index, val);
len = 1 + operand.length;
break;
}
case kExprTeeLocal: {
LocalIndexOperand<false> operand(&decoder, code->at(pc));
WasmVal val = Pop();
stack_[frames_.back().sp + operand.index] = val;
Push(pc, val);
SetStackValue(frames_.back().sp + operand.index, val);
Push(val);
len = 1 + operand.length;
break;
}
......@@ -1799,7 +1819,7 @@ class ThreadImpl {
default:
UNREACHABLE();
}
Push(pc, val);
Push(val);
len = 1 + operand.length;
break;
}
......@@ -1872,7 +1892,7 @@ class ThreadImpl {
/* TODO(titzer): alignment for asmjs load mem? */ \
result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
} \
Push(pc, WasmVal(result)); \
Push(WasmVal(result)); \
break; \
}
ASMJS_LOAD_CASE(I32AsmjsLoadMem8S, int32_t, int8_t, 0);
......@@ -1895,7 +1915,7 @@ class ThreadImpl {
/* TODO(titzer): alignment for asmjs store mem? */ \
*(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
} \
Push(pc, val); \
Push(val); \
break; \
}
......@@ -1908,14 +1928,14 @@ class ThreadImpl {
case kExprGrowMemory: {
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
uint32_t delta_pages = Pop().to<uint32_t>();
Push(pc, WasmVal(ExecuteGrowMemory(
Push(WasmVal(ExecuteGrowMemory(
delta_pages, codemap_->maybe_instance(), instance())));
len = 1 + operand.length;
break;
}
case kExprMemorySize: {
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size /
Push(WasmVal(static_cast<uint32_t>(instance()->mem_size /
WasmModule::kPageSize)));
len = 1 + operand.length;
break;
......@@ -1925,15 +1945,13 @@ class ThreadImpl {
// ia32 by the reinterpret casts.
case kExprI32ReinterpretF32: {
WasmVal val = Pop();
WasmVal result(ExecuteI32ReinterpretF32(val));
Push(pc, result);
Push(WasmVal(ExecuteI32ReinterpretF32(val)));
possible_nondeterminism_ |= std::isnan(val.to<float>());
break;
}
case kExprI64ReinterpretF64: {
WasmVal val = Pop();
WasmVal result(ExecuteI64ReinterpretF64(val));
Push(pc, result);
Push(WasmVal(ExecuteI64ReinterpretF64(val)));
possible_nondeterminism_ |= std::isnan(val.to<double>());
break;
}
......@@ -1942,7 +1960,7 @@ class ThreadImpl {
WasmVal rval = Pop(); \
WasmVal lval = Pop(); \
WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \
Push(pc, result); \
Push(result); \
break; \
}
FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP)
......@@ -1955,7 +1973,7 @@ class ThreadImpl {
volatile ctype lval = Pop().to<ctype>(); \
WasmVal result(Execute##name(lval, rval, &trap)); \
if (trap != kTrapCount) return DoTrap(trap, pc); \
Push(pc, result); \
Push(result); \
break; \
}
FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP)
......@@ -1968,7 +1986,7 @@ class ThreadImpl {
volatile float rval = Pop().to<float>();
volatile float lval = Pop().to<float>();
WasmVal result(ExecuteF32CopySign(lval, rval, &trap));
Push(pc, result);
Push(result);
possible_nondeterminism_ |= std::isnan(rval);
break;
}
......@@ -1979,7 +1997,7 @@ class ThreadImpl {
volatile double rval = Pop().to<double>();
volatile double lval = Pop().to<double>();
WasmVal result(ExecuteF64CopySign(lval, rval, &trap));
Push(pc, result);
Push(result);
possible_nondeterminism_ |= std::isnan(rval);
break;
}
......@@ -1989,7 +2007,7 @@ class ThreadImpl {
volatile ctype val = Pop().to<ctype>(); \
WasmVal result(Execute##name(val, &trap)); \
if (trap != kTrapCount) return DoTrap(trap, pc); \
Push(pc, result); \
Push(result); \
break; \
}
FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP)
......@@ -2003,7 +2021,7 @@ class ThreadImpl {
#ifdef DEBUG
if (!WasmOpcodes::IsControlOpcode(static_cast<WasmOpcode>(opcode))) {
DCHECK_EQ(expected_new_stack_height, stack_.size());
DCHECK_EQ(expected_new_stack_height, StackHeight());
}
#endif
......@@ -2024,20 +2042,17 @@ class ThreadImpl {
}
WasmVal Pop() {
DCHECK_GT(stack_.size(), 0);
DCHECK_GT(frames_.size(), 0);
DCHECK_GT(stack_.size(), frames_.back().llimit()); // can't pop into locals
WasmVal val = stack_.back();
stack_.pop_back();
return val;
DCHECK_GT(StackHeight(), frames_.back().llimit()); // can't pop into locals
return *--sp_;
}
void PopN(int n) {
DCHECK_GE(stack_.size(), n);
DCHECK_GE(StackHeight(), n);
DCHECK_GT(frames_.size(), 0);
size_t nsize = stack_.size() - n;
DCHECK_GE(nsize, frames_.back().llimit()); // can't pop into locals
stack_.resize(nsize);
// Check that we don't pop into locals.
DCHECK_GE(StackHeight() - n, frames_.back().llimit());
sp_ -= n;
}
WasmVal PopArity(size_t arity) {
......@@ -2046,12 +2061,38 @@ class ThreadImpl {
return Pop();
}
void Push(pc_t pc, WasmVal val) {
// TODO(titzer): store PC as well?
void Push(WasmVal val) {
DCHECK_NE(kWasmStmt, val.type);
stack_.push_back(val);
DCHECK_LE(1, stack_limit_ - sp_);
*sp_++ = val;
}
void Push(WasmVal* vals, size_t arity) {
DCHECK_LE(arity, stack_limit_ - sp_);
for (WasmVal *val = vals, *end = vals + arity; val != end; ++val) {
DCHECK_NE(kWasmStmt, val->type);
}
memcpy(sp_, vals, arity * sizeof(*sp_));
sp_ += arity;
}
void EnsureStackSpace(size_t size) {
if (V8_LIKELY(static_cast<size_t>(stack_limit_ - sp_) >= size)) return;
size_t old_size = stack_limit_ - stack_start_;
size_t new_size = Max(size_t{8}, 2 * old_size);
while (new_size < (sp_ - stack_start_) + size) {
DCHECK_GE(std::numeric_limits<decltype(new_size)>::max() / 4, new_size);
new_size *= 2;
}
WasmVal* new_stack = zone_->NewArray<WasmVal>(new_size);
memcpy(new_stack, stack_start_, old_size * sizeof(*sp_));
sp_ = new_stack + (sp_ - stack_start_);
stack_start_ = new_stack;
stack_limit_ = new_stack + new_size;
}
sp_t StackHeight() { return sp_ - stack_start_; }
void TraceStack(const char* phase, pc_t pc) {
if (FLAG_trace_wasm_interpreter) {
PrintF("%s @%zu", phase, pc);
......@@ -2062,19 +2103,19 @@ class ThreadImpl {
void TraceValueStack() {
#ifdef DEBUG
if (!FLAG_trace_wasm_interpreter) return;
Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
sp_t sp = top ? top->sp : 0;
sp_t plimit = top ? top->plimit() : 0;
sp_t llimit = top ? top->llimit() : 0;
if (FLAG_trace_wasm_interpreter) {
for (size_t i = sp; i < stack_.size(); ++i) {
for (size_t i = sp; i < StackHeight(); ++i) {
if (i < plimit)
PrintF(" p%zu:", i);
else if (i < llimit)
PrintF(" l%zu:", i);
else
PrintF(" s%zu:", i);
WasmVal val = stack_[i];
WasmVal val = GetStackValue(i);
switch (val.type) {
case kWasmI32:
PrintF("i32:%d", val.to<int32_t>());
......@@ -2096,7 +2137,6 @@ class ThreadImpl {
break;
}
}
}
#endif // DEBUG
}
......@@ -2147,7 +2187,7 @@ class ThreadImpl {
// Get all arguments as JS values.
std::vector<Handle<Object>> args;
args.reserve(num_args);
WasmVal* wasm_args = stack_.data() + (stack_.size() - num_args);
WasmVal* wasm_args = sp_ - num_args;
for (int i = 0; i < num_args; ++i) {
args.push_back(WasmValToNumber(isolate->factory(), wasm_args[i],
signature->GetParam(i)));
......@@ -2167,12 +2207,11 @@ class ThreadImpl {
Handle<Object> retval = maybe_retval.ToHandleChecked();
// Pop arguments off the stack.
stack_.resize(stack_.size() - num_args);
sp_ -= num_args;
if (signature->return_count() > 0) {
// TODO(wasm): Handle multiple returns.
DCHECK_EQ(1, signature->return_count());
stack_.push_back(
ToWebAssemblyValue(isolate, retval, signature->GetReturn()));
Push(ToWebAssemblyValue(isolate, retval, signature->GetReturn()));
}
return {ExternalCallResult::EXTERNAL_RETURNED};
}
......@@ -2300,7 +2339,7 @@ class InterpretedFrameImpl {
bool is_top_frame =
static_cast<size_t>(index_) + 1 == thread_->frames_.size();
size_t stack_limit =
is_top_frame ? thread_->stack_.size() : thread_->frames_[index_ + 1].sp;
is_top_frame ? thread_->StackHeight() : thread_->frames_[index_ + 1].sp;
DCHECK_LE(frame()->sp, stack_limit);
size_t frame_size = stack_limit - frame()->sp;
DCHECK_LE(GetLocalCount(), frame_size);
......@@ -2536,8 +2575,8 @@ ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
&function, BodyLocalDecls(zone), start, end, nullptr, nullptr, nullptr};
// Now compute and return the control transfers.
ControlTransfers targets(zone, module, &code);
return targets.map_;
SideTable side_table(zone, module, &code);
return side_table.map_;
}
//============================================================================
......
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