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(); |
} |