| Index: src/wasm/wasm-interpreter.cc
|
| diff --git a/src/wasm/wasm-interpreter.cc b/src/wasm/wasm-interpreter.cc
|
| index a88fa93f06df0fc95d18d60594744981546d90f6..9eaff7492803462e82ef550667cc74ec4cd699ad 100644
|
| --- a/src/wasm/wasm-interpreter.cc
|
| +++ b/src/wasm/wasm-interpreter.cc
|
| @@ -851,17 +851,29 @@ class ControlTransfers : public ZoneObject {
|
|
|
| // Code and metadata needed to execute a function.
|
| struct InterpreterCode {
|
| - const WasmFunction* function; // wasm function
|
| - AstLocalDecls locals; // local declarations
|
| - const byte* orig_start; // start of original code
|
| - 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.
|
| + const WasmFunction* function; // wasm function
|
| + AstLocalDecls locals; // local declarations
|
| + const byte* orig_start; // start of original code
|
| + 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.
|
| + BoolVector instruction_offsets; // valid instruction offsets
|
|
|
| const byte* at(pc_t pc) { return start + pc; }
|
| };
|
|
|
| +namespace {
|
| +
|
| +pc_t FindPreviousInstruction(InterpreterCode* code, pc_t pc) {
|
| + BoolVector& offsets = code->instruction_offsets;
|
| + DCHECK(offsets[pc]);
|
| + while (!offsets[--pc]) DCHECK_LE(0U, pc);
|
| + return pc;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| // The main storage for interpreter code. It maps {WasmFunction} to the
|
| // metadata needed to execute each function.
|
| class CodeMap {
|
| @@ -910,16 +922,29 @@ class CodeMap {
|
| code->targets =
|
| new (zone_) ControlTransfers(zone_, code->locals.decls_encoded_size,
|
| code->orig_start, code->orig_end);
|
| +
|
| + // Initialize the instruction_offsets bitset.
|
| + DCHECK(code->instruction_offsets.empty());
|
| + code->instruction_offsets.resize(code->end - code->start);
|
| + const byte* pc = code->orig_start + code->locals.decls_encoded_size;
|
| + while (pc < code->orig_end) {
|
| + code->instruction_offsets[pc - code->orig_start] = 1;
|
| + pc += OpcodeLength(pc, code->orig_end);
|
| + }
|
| }
|
| return code;
|
| }
|
|
|
| int AddFunction(const WasmFunction* function, const byte* code_start,
|
| const byte* code_end) {
|
| - InterpreterCode code = {
|
| - function, AstLocalDecls(zone_), code_start,
|
| - code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end),
|
| - nullptr};
|
| + InterpreterCode code = {function,
|
| + AstLocalDecls(zone_),
|
| + code_start,
|
| + code_end,
|
| + const_cast<byte*>(code_start),
|
| + const_cast<byte*>(code_end),
|
| + nullptr,
|
| + BoolVector(zone_)};
|
|
|
| DCHECK_EQ(interpreter_code_.size(), function->func_index);
|
| interpreter_code_.push_back(code);
|
| @@ -963,6 +988,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| virtual void PushFrame(const WasmFunction* function, WasmVal* args) {
|
| InterpreterCode* code = codemap()->FindCode(function);
|
| CHECK_NOT_NULL(code);
|
| + codemap()->Preprocess(code);
|
| frames_.push_back({code, 0, 0, stack_.size()});
|
| for (size_t i = 0; i < function->sig->parameter_count(); ++i) {
|
| stack_.push_back(args[i]);
|
| @@ -1006,12 +1032,21 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
|
|
| virtual int GetFrameCount() { return static_cast<int>(frames_.size()); }
|
|
|
| - virtual const WasmFrame* GetFrame(int index) {
|
| - UNIMPLEMENTED();
|
| - return nullptr;
|
| - }
|
| -
|
| - virtual WasmFrame* GetMutableFrame(int index) {
|
| + virtual const WasmInterpreterFrame* GetFrame(int index) {
|
| + Frame* frame = &frames_[index];
|
| + DCHECK_LE(frame->sp, stack_.size());
|
| + DCHECK_LE(stack_.size(), static_cast<size_t>(kMaxInt));
|
| + // For all but the top frame, the pc is one behine the call instruction.
|
| + bool top_frame = static_cast<size_t>(index) == frames_.size() - 1;
|
| + pc_t pc = top_frame ? frame->ret_pc
|
| + : FindPreviousInstruction(frame->code, frame->ret_pc);
|
| + return new WasmInterpreterFrame(frame->code->function, // wasm function
|
| + static_cast<int>(pc), // pc
|
| + static_cast<int>(frame->sp), // fp
|
| + static_cast<int>(stack_.size())); // sp
|
| + }
|
| +
|
| + virtual WasmInterpreterFrame* GetMutableFrame(int index) {
|
| UNIMPLEMENTED();
|
| return nullptr;
|
| }
|
| @@ -1652,6 +1687,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| }
|
|
|
| void TraceValueStack() {
|
| +#if DEBUG
|
| Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
|
| sp_t sp = top ? top->sp : 0;
|
| sp_t plimit = top ? top->plimit() : 0;
|
| @@ -1687,6 +1723,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
|
| }
|
| }
|
| }
|
| +#endif
|
| }
|
| };
|
|
|
| @@ -1716,10 +1753,9 @@ class WasmInterpreterInternals : public ZoneObject {
|
| //============================================================================
|
| // Implementation of the public interface of the interpreter.
|
| //============================================================================
|
| -WasmInterpreter::WasmInterpreter(WasmModuleInstance* instance,
|
| - base::AccountingAllocator* allocator)
|
| - : zone_(allocator),
|
| - internals_(new (&zone_) WasmInterpreterInternals(&zone_, instance)) {}
|
| +WasmInterpreter::WasmInterpreter(WasmModuleInstance* instance, Zone* zone)
|
| + : zone_(zone),
|
| + internals_(new (zone_) WasmInterpreterInternals(zone_, instance)) {}
|
|
|
| WasmInterpreter::~WasmInterpreter() { internals_->Delete(); }
|
|
|
| @@ -1727,34 +1763,38 @@ void WasmInterpreter::Run() { internals_->threads_[0]->Run(); }
|
|
|
| void WasmInterpreter::Pause() { internals_->threads_[0]->Pause(); }
|
|
|
| -bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, pc_t pc,
|
| +bool WasmInterpreter::SetBreakpoint(uint32_t function_index, pc_t pc,
|
| bool enabled) {
|
| - InterpreterCode* code = internals_->codemap_.FindCode(function);
|
| - if (!code) return false;
|
| + auto interpreter_code = internals_->codemap_.interpreter_code_;
|
| + if (function_index > interpreter_code.size()) return false;
|
| + InterpreterCode* code = internals_->codemap_.GetCode(function_index);
|
| size_t size = static_cast<size_t>(code->end - code->start);
|
| // Check bounds for {pc}.
|
| - if (pc < code->locals.decls_encoded_size || pc >= size) return false;
|
| + if (pc >= size) return false;
|
| + // Check that it's a valid instruction offset.
|
| + DCHECK_LE(pc, code->instruction_offsets.size());
|
| + if (!code->instruction_offsets[pc]) return false;
|
| // Make a copy of the code before enabling a breakpoint.
|
| if (enabled && code->orig_start == code->start) {
|
| - code->start = reinterpret_cast<byte*>(zone_.New(size));
|
| + code->start = reinterpret_cast<byte*>(zone_->New(size));
|
| memcpy(code->start, code->orig_start, size);
|
| code->end = code->start + size;
|
| }
|
| bool prev = code->start[pc] == kInternalBreakpoint;
|
| - if (enabled) {
|
| - code->start[pc] = kInternalBreakpoint;
|
| - } else {
|
| - code->start[pc] = code->orig_start[pc];
|
| - }
|
| + code->start[pc] = enabled ? kInternalBreakpoint : code->orig_start[pc];
|
| return prev;
|
| }
|
|
|
| -bool WasmInterpreter::GetBreakpoint(const WasmFunction* function, pc_t pc) {
|
| - InterpreterCode* code = internals_->codemap_.FindCode(function);
|
| - if (!code) return false;
|
| +bool WasmInterpreter::GetBreakpoint(uint32_t function_index, pc_t pc) {
|
| + auto interpreter_code = internals_->codemap_.interpreter_code_;
|
| + if (function_index > interpreter_code.size()) return false;
|
| + InterpreterCode* code = internals_->codemap_.GetCode(function_index);
|
| size_t size = static_cast<size_t>(code->end - code->start);
|
| // Check bounds for {pc}.
|
| - if (pc < code->locals.decls_encoded_size || pc >= size) return false;
|
| + if (pc >= size) return false;
|
| + // Check that it's a valid instruction offset.
|
| + DCHECK_LE(pc, code->instruction_offsets.size());
|
| + if (!code->instruction_offsets[pc]) return false;
|
| // Check if a breakpoint is present at that place in the code.
|
| return code->start[pc] == kInternalBreakpoint;
|
| }
|
| @@ -1773,26 +1813,31 @@ WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
|
| return internals_->threads_[id];
|
| }
|
|
|
| -WasmVal WasmInterpreter::GetLocalVal(const WasmFrame* frame, int index) {
|
| +WasmVal WasmInterpreter::GetLocalVal(const WasmInterpreterFrame* frame,
|
| + int index) {
|
| CHECK_GE(index, 0);
|
| UNIMPLEMENTED();
|
| + USE(frame->fp_);
|
| + USE(frame->sp_);
|
| WasmVal none;
|
| none.type = kAstStmt;
|
| return none;
|
| }
|
|
|
| -WasmVal WasmInterpreter::GetExprVal(const WasmFrame* frame, int pc) {
|
| +WasmVal WasmInterpreter::GetExprVal(const WasmInterpreterFrame* frame, int pc) {
|
| UNIMPLEMENTED();
|
| WasmVal none;
|
| none.type = kAstStmt;
|
| return none;
|
| }
|
|
|
| -void WasmInterpreter::SetLocalVal(WasmFrame* frame, int index, WasmVal val) {
|
| +void WasmInterpreter::SetLocalVal(WasmInterpreterFrame* frame, int index,
|
| + WasmVal val) {
|
| UNIMPLEMENTED();
|
| }
|
|
|
| -void WasmInterpreter::SetExprVal(WasmFrame* frame, int pc, WasmVal val) {
|
| +void WasmInterpreter::SetExprVal(WasmInterpreterFrame* frame, int pc,
|
| + WasmVal val) {
|
| UNIMPLEMENTED();
|
| }
|
|
|
|
|