Commit 09525c8f authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Implement frame inspection for interpreted frames

Frame inspection is currently limited to locations of execution.
Further details like local variables or stack content will follow later.

The FrameInspector now stores a pointer to the interpreted wasm frame,
and redirects certain requests there, just as for deoptimized frames.
Hitting breakpoints is now also supported for wasm frames.

R=yangguo@chromium.org, titzer@chromium.org
BUG=v8:5822

Review-Url: https://codereview.chromium.org/2629823003
Cr-Commit-Position: refs/heads/master@{#42551}
parent 4714bc15
...@@ -15,7 +15,6 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index, ...@@ -15,7 +15,6 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index,
Isolate* isolate) Isolate* isolate)
: frame_(frame), : frame_(frame),
frame_summary_(FrameSummary::Get(frame, inlined_frame_index)), frame_summary_(FrameSummary::Get(frame, inlined_frame_index)),
deoptimized_frame_(nullptr),
isolate_(isolate) { isolate_(isolate) {
JavaScriptFrame* js_frame = JavaScriptFrame* js_frame =
frame->is_java_script() ? javascript_frame() : nullptr; frame->is_java_script() ? javascript_frame() : nullptr;
...@@ -35,21 +34,28 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index, ...@@ -35,21 +34,28 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index,
return; return;
} }
deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( deoptimized_frame_.reset(Deoptimizer::DebuggerInspectableFrame(
js_frame, inlined_frame_index, isolate); js_frame, inlined_frame_index, isolate));
} else if (frame_->is_wasm_interpreter_entry()) {
wasm_interpreted_frame_ =
frame_summary_.AsWasm()
.wasm_instance()
->debug_info()
->GetInterpretedFrame(frame_->fp(), inlined_frame_index);
DCHECK(wasm_interpreted_frame_);
} }
} }
FrameInspector::~FrameInspector() { FrameInspector::~FrameInspector() {
// Get rid of the calculated deoptimized frame if any. // Destructor needs to be defined in the .cc file, because it instantiates
if (deoptimized_frame_ != nullptr) { // std::unique_ptr destructors but the types are not known in the header.
delete deoptimized_frame_;
}
} }
int FrameInspector::GetParametersCount() { int FrameInspector::GetParametersCount() {
return is_optimized_ ? deoptimized_frame_->parameters_count() if (is_optimized_) return deoptimized_frame_->parameters_count();
: frame_->ComputeParametersCount(); if (wasm_interpreted_frame_)
return wasm_interpreted_frame_->GetParameterCount();
return frame_->ComputeParametersCount();
} }
Handle<Script> FrameInspector::GetScript() { Handle<Script> FrameInspector::GetScript() {
...@@ -61,8 +67,9 @@ Handle<JSFunction> FrameInspector::GetFunction() { ...@@ -61,8 +67,9 @@ Handle<JSFunction> FrameInspector::GetFunction() {
} }
Handle<Object> FrameInspector::GetParameter(int index) { Handle<Object> FrameInspector::GetParameter(int index) {
return is_optimized_ ? deoptimized_frame_->GetParameter(index) if (is_optimized_) return deoptimized_frame_->GetParameter(index);
: handle(frame_->GetParameter(index), isolate_); // TODO(clemensh): Handle wasm_interpreted_frame_.
return handle(frame_->GetParameter(index), isolate_);
} }
Handle<Object> FrameInspector::GetExpression(int index) { Handle<Object> FrameInspector::GetExpression(int index) {
......
...@@ -13,6 +13,11 @@ ...@@ -13,6 +13,11 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Forward declaration:
namespace wasm {
class InterpretedFrame;
}
class FrameInspector { class FrameInspector {
public: public:
FrameInspector(StandardFrame* frame, int inlined_frame_index, FrameInspector(StandardFrame* frame, int inlined_frame_index,
...@@ -54,7 +59,8 @@ class FrameInspector { ...@@ -54,7 +59,8 @@ class FrameInspector {
StandardFrame* frame_; StandardFrame* frame_;
FrameSummary frame_summary_; FrameSummary frame_summary_;
DeoptimizedFrameInfo* deoptimized_frame_; std::unique_ptr<DeoptimizedFrameInfo> deoptimized_frame_;
std::unique_ptr<wasm::InterpretedFrame> wasm_interpreted_frame_;
Isolate* isolate_; Isolate* isolate_;
bool is_optimized_; bool is_optimized_;
bool is_interpreted_; bool is_interpreted_;
......
...@@ -2317,9 +2317,9 @@ void Debug::ProcessDebugMessages(bool debug_command_only) { ...@@ -2317,9 +2317,9 @@ void Debug::ProcessDebugMessages(bool debug_command_only) {
void Debug::PrintBreakLocation() { void Debug::PrintBreakLocation() {
if (!FLAG_print_break_location) return; if (!FLAG_print_break_location) return;
HandleScope scope(isolate_); HandleScope scope(isolate_);
JavaScriptFrameIterator iterator(isolate_); StackTraceFrameIterator iterator(isolate_);
if (iterator.done()) return; if (iterator.done()) return;
JavaScriptFrame* frame = iterator.frame(); StandardFrame* frame = iterator.frame();
FrameSummary summary = FrameSummary::GetTop(frame); FrameSummary summary = FrameSummary::GetTop(frame);
int source_position = summary.SourcePosition(); int source_position = summary.SourcePosition();
Handle<Object> script_obj = summary.script(); Handle<Object> script_obj = summary.script();
...@@ -2372,8 +2372,6 @@ DebugScope::DebugScope(Debug* debug) ...@@ -2372,8 +2372,6 @@ DebugScope::DebugScope(Debug* debug)
// frame id. // frame id.
StackTraceFrameIterator it(isolate()); StackTraceFrameIterator it(isolate());
bool has_frames = !it.done(); bool has_frames = !it.done();
// We don't currently support breaking inside wasm framess.
DCHECK(!has_frames || !it.is_wasm());
debug_->thread_local_.break_frame_id_ = debug_->thread_local_.break_frame_id_ =
has_frames ? it.frame()->id() : StackFrame::NO_ID; has_frames ? it.frame()->id() : StackFrame::NO_ID;
debug_->SetNextBreakId(); debug_->SetNextBreakId();
......
...@@ -1763,7 +1763,7 @@ void WasmInterpreterEntryFrame::Iterate(ObjectVisitor* v) const { ...@@ -1763,7 +1763,7 @@ void WasmInterpreterEntryFrame::Iterate(ObjectVisitor* v) const {
void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode, void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode,
int index) const { int index) const {
PrintIndex(accumulator, mode, index); PrintIndex(accumulator, mode, index);
accumulator->Add("WASM TO INTERPRETER ["); accumulator->Add("WASM INTERPRETER ENTRY [");
Script* script = this->script(); Script* script = this->script();
accumulator->PrintName(script->name()); accumulator->PrintName(script->name());
accumulator->Add("]"); accumulator->Add("]");
...@@ -1772,8 +1772,15 @@ void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode, ...@@ -1772,8 +1772,15 @@ void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode,
void WasmInterpreterEntryFrame::Summarize(List<FrameSummary>* functions, void WasmInterpreterEntryFrame::Summarize(List<FrameSummary>* functions,
FrameSummary::Mode mode) const { FrameSummary::Mode mode) const {
// TODO(clemensh): Implement this. Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
UNIMPLEMENTED(); std::vector<std::pair<uint32_t, int>> interpreted_stack =
instance->debug_info()->GetInterpretedStack(fp());
for (auto& e : interpreted_stack) {
FrameSummary::WasmInterpretedFrameSummary summary(isolate(), instance,
e.first, e.second);
functions->Add(summary);
}
} }
Code* WasmInterpreterEntryFrame::unchecked_code() const { Code* WasmInterpreterEntryFrame::unchecked_code() const {
......
...@@ -159,6 +159,8 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { ...@@ -159,6 +159,8 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]); CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]);
CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 2); CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 2);
CHECK(WasmInstanceObject::IsWasmInstanceObject(*instance_obj)); CHECK(WasmInstanceObject::IsWasmInstanceObject(*instance_obj));
Handle<WasmInstanceObject> instance =
Handle<WasmInstanceObject>::cast(instance_obj);
// The arg buffer is the raw pointer to the caller's stack. It looks like a // The arg buffer is the raw pointer to the caller's stack. It looks like a
// Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
...@@ -167,11 +169,7 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { ...@@ -167,11 +169,7 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
CHECK(arg_buffer_obj->IsSmi()); CHECK(arg_buffer_obj->IsSmi());
uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj); uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj);
Handle<WasmInstanceObject> instance = instance->debug_info()->RunInterpreter(func_index, arg_buffer);
Handle<WasmInstanceObject>::cast(instance_obj);
Handle<WasmDebugInfo> debug_info =
WasmInstanceObject::GetOrCreateDebugInfo(instance);
WasmDebugInfo::RunInterpreter(debug_info, func_index, arg_buffer);
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
......
...@@ -22,12 +22,15 @@ class Managed : public Foreign { ...@@ -22,12 +22,15 @@ class Managed : public Foreign {
return reinterpret_cast<CppType*>(foreign_address()); return reinterpret_cast<CppType*>(foreign_address());
} }
static Managed<CppType>* cast(Object* obj) {
SLOW_DCHECK(obj->IsForeign());
return reinterpret_cast<Managed<CppType>*>(obj);
}
static Handle<Managed<CppType>> New(Isolate* isolate, CppType* ptr, static Handle<Managed<CppType>> New(Isolate* isolate, CppType* ptr,
bool delete_on_gc = true) { bool delete_on_gc = true) {
Handle<Foreign> foreign = Handle<Managed<CppType>> handle = Handle<Managed<CppType>>::cast(
isolate->factory()->NewForeign(reinterpret_cast<Address>(ptr)); isolate->factory()->NewForeign(reinterpret_cast<Address>(ptr)));
Handle<Managed<CppType>> handle(
reinterpret_cast<Managed<CppType>*>(*foreign), isolate);
if (delete_on_gc) { if (delete_on_gc) {
RegisterWeakCallbackForDelete(isolate, handle); RegisterWeakCallbackForDelete(isolate, handle);
} }
......
...@@ -21,17 +21,23 @@ using namespace v8::internal::wasm; ...@@ -21,17 +21,23 @@ using namespace v8::internal::wasm;
namespace { namespace {
// Forward declaration.
class InterpreterHandle;
InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info);
class InterpreterHandle { class InterpreterHandle {
AccountingAllocator allocator_; AccountingAllocator allocator_;
WasmInstance instance_; WasmInstance instance_;
WasmInterpreter interpreter_; WasmInterpreter interpreter_;
Isolate* isolate_;
public: public:
// Initialize in the right order, using helper methods to make this possible. // Initialize in the right order, using helper methods to make this possible.
// WasmInterpreter has to be allocated in place, since it is not movable. // WasmInterpreter has to be allocated in place, since it is not movable.
InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info) InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info)
: instance_(debug_info->wasm_instance()->compiled_module()->module()), : instance_(debug_info->wasm_instance()->compiled_module()->module()),
interpreter_(GetBytesEnv(&instance_, debug_info), &allocator_) { interpreter_(GetBytesEnv(&instance_, debug_info), &allocator_),
isolate_(isolate) {
Handle<JSArrayBuffer> mem_buffer = Handle<JSArrayBuffer> mem_buffer =
handle(debug_info->wasm_instance()->memory_buffer(), isolate); handle(debug_info->wasm_instance()->memory_buffer(), isolate);
if (mem_buffer->IsUndefined(isolate)) { if (mem_buffer->IsUndefined(isolate)) {
...@@ -95,10 +101,9 @@ class InterpreterHandle { ...@@ -95,10 +101,9 @@ class InterpreterHandle {
do { do {
state = thread->Run(); state = thread->Run();
switch (state) { switch (state) {
case WasmInterpreter::State::PAUSED: { case WasmInterpreter::State::PAUSED:
// We hit a breakpoint. NotifyDebugEventListeners();
// TODO(clemensh): Handle this. break;
} break;
case WasmInterpreter::State::FINISHED: case WasmInterpreter::State::FINISHED:
// Perfect, just break the switch and exit the loop. // Perfect, just break the switch and exit the loop.
break; break;
...@@ -136,6 +141,83 @@ class InterpreterHandle { ...@@ -136,6 +141,83 @@ class InterpreterHandle {
} }
} }
} }
Handle<WasmInstanceObject> GetInstanceObject() {
StackTraceFrameIterator it(isolate_);
WasmInterpreterEntryFrame* frame =
WasmInterpreterEntryFrame::cast(it.frame());
Handle<WasmInstanceObject> instance_obj(frame->wasm_instance(), isolate_);
DCHECK_EQ(this, GetInterpreterHandle(instance_obj->debug_info()));
return instance_obj;
}
void NotifyDebugEventListeners() {
// Enter the debugger.
DebugScope debug_scope(isolate_->debug());
if (debug_scope.failed()) return;
// Postpone interrupt during breakpoint processing.
PostponeInterruptsScope postpone(isolate_);
// If we are paused on a breakpoint, clear all stepping and notify the
// listeners.
Handle<WasmCompiledModule> compiled_module(
GetInstanceObject()->compiled_module(), isolate_);
int position = GetTopPosition(compiled_module);
MaybeHandle<FixedArray> hit_breakpoints;
if (isolate_->debug()->break_points_active()) {
hit_breakpoints = compiled_module->CheckBreakPoints(position);
}
// If we hit a breakpoint, pass a JSArray with all breakpoints, otherwise
// pass undefined.
Handle<Object> hit_breakpoints_js;
if (hit_breakpoints.is_null()) {
hit_breakpoints_js = isolate_->factory()->undefined_value();
} else {
hit_breakpoints_js = isolate_->factory()->NewJSArrayWithElements(
hit_breakpoints.ToHandleChecked());
}
isolate_->debug()->OnDebugBreak(hit_breakpoints_js, false);
}
int GetTopPosition(Handle<WasmCompiledModule> compiled_module) {
DCHECK_EQ(1, interpreter()->GetThreadCount());
WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
DCHECK_LT(0, thread->GetFrameCount());
wasm::InterpretedFrame frame =
thread->GetFrame(thread->GetFrameCount() - 1);
return compiled_module->GetFunctionOffset(frame.function()->func_index) +
frame.pc();
}
std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
Address frame_pointer) {
// TODO(clemensh): Use frame_pointer.
USE(frame_pointer);
DCHECK_EQ(1, interpreter()->GetThreadCount());
WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
std::vector<std::pair<uint32_t, int>> stack(thread->GetFrameCount());
for (int i = 0, e = thread->GetFrameCount(); i < e; ++i) {
wasm::InterpretedFrame frame = thread->GetFrame(i);
stack[i] = {frame.function()->func_index, frame.pc()};
}
return stack;
}
std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
Address frame_pointer, int idx) {
// TODO(clemensh): Use frame_pointer.
USE(frame_pointer);
DCHECK_EQ(1, interpreter()->GetThreadCount());
WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
return std::unique_ptr<wasm::InterpretedFrame>(
new wasm::InterpretedFrame(thread->GetMutableFrame(idx)));
}
}; };
InterpreterHandle* GetOrCreateInterpreterHandle( InterpreterHandle* GetOrCreateInterpreterHandle(
...@@ -151,6 +233,12 @@ InterpreterHandle* GetOrCreateInterpreterHandle( ...@@ -151,6 +233,12 @@ InterpreterHandle* GetOrCreateInterpreterHandle(
return Handle<Managed<InterpreterHandle>>::cast(handle)->get(); return Handle<Managed<InterpreterHandle>>::cast(handle)->get();
} }
InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info) {
Object* handle_obj = debug_info->get(WasmDebugInfo::kInterpreterHandle);
DCHECK(!handle_obj->IsUndefined(debug_info->GetIsolate()));
return Managed<InterpreterHandle>::cast(handle_obj)->get();
}
int GetNumFunctions(WasmInstanceObject* instance) { int GetNumFunctions(WasmInstanceObject* instance) {
size_t num_functions = size_t num_functions =
instance->compiled_module()->module()->functions.size(); instance->compiled_module()->module()->functions.size();
...@@ -265,10 +353,18 @@ void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info, ...@@ -265,10 +353,18 @@ void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
EnsureRedirectToInterpreter(isolate, debug_info, func_index); EnsureRedirectToInterpreter(isolate, debug_info, func_index);
} }
void WasmDebugInfo::RunInterpreter(Handle<WasmDebugInfo> debug_info, void WasmDebugInfo::RunInterpreter(int func_index, uint8_t* arg_buffer) {
int func_index, uint8_t* arg_buffer) {
DCHECK_LE(0, func_index); DCHECK_LE(0, func_index);
InterpreterHandle* interp_handle = GetInterpreterHandle(this)->Execute(static_cast<uint32_t>(func_index),
GetOrCreateInterpreterHandle(debug_info->GetIsolate(), debug_info); arg_buffer);
interp_handle->Execute(static_cast<uint32_t>(func_index), arg_buffer); }
std::vector<std::pair<uint32_t, int>> WasmDebugInfo::GetInterpretedStack(
Address frame_pointer) {
return GetInterpreterHandle(this)->GetInterpretedStack(frame_pointer);
}
std::unique_ptr<wasm::InterpretedFrame> WasmDebugInfo::GetInterpretedFrame(
Address frame_pointer, int idx) {
return GetInterpreterHandle(this)->GetInterpretedFrame(frame_pointer, idx);
} }
...@@ -985,16 +985,22 @@ class ThreadImpl { ...@@ -985,16 +985,22 @@ class ThreadImpl {
possible_nondeterminism_ = false; possible_nondeterminism_ = false;
} }
int GetFrameCount() { return static_cast<int>(frames_.size()); } int GetFrameCount() {
DCHECK_GE(kMaxInt, frames_.size());
const WasmFrame* GetFrame(int index) { return static_cast<int>(frames_.size());
UNIMPLEMENTED();
return nullptr;
} }
WasmFrame* GetMutableFrame(int index) { template <typename FrameCons>
UNIMPLEMENTED(); InterpretedFrame GetMutableFrame(int index, FrameCons frame_cons) {
return nullptr; DCHECK_LE(0, index);
DCHECK_GT(frames_.size(), index);
Frame* frame = &frames_[index];
DCHECK_GE(kMaxInt, frame->ret_pc);
DCHECK_GE(kMaxInt, frame->sp);
DCHECK_GE(kMaxInt, frame->llimit());
return frame_cons(frame->code->function, static_cast<int>(frame->ret_pc),
static_cast<int>(frame->sp),
static_cast<int>(frame->llimit()));
} }
WasmVal GetReturnValue(int index) { WasmVal GetReturnValue(int index) {
...@@ -1747,11 +1753,16 @@ pc_t WasmInterpreter::Thread::GetBreakpointPc() { ...@@ -1747,11 +1753,16 @@ pc_t WasmInterpreter::Thread::GetBreakpointPc() {
int WasmInterpreter::Thread::GetFrameCount() { int WasmInterpreter::Thread::GetFrameCount() {
return ToImpl(this)->GetFrameCount(); return ToImpl(this)->GetFrameCount();
} }
const WasmFrame* WasmInterpreter::Thread::GetFrame(int index) { const InterpretedFrame WasmInterpreter::Thread::GetFrame(int index) {
return ToImpl(this)->GetFrame(index); return GetMutableFrame(index);
} }
WasmFrame* WasmInterpreter::Thread::GetMutableFrame(int index) { InterpretedFrame WasmInterpreter::Thread::GetMutableFrame(int index) {
return ToImpl(this)->GetMutableFrame(index); // We have access to the constructor of InterpretedFrame, but ThreadImpl has
// not. So pass it as a lambda (should all get inlined).
auto frame_cons = [](const WasmFunction* function, int pc, int fp, int sp) {
return InterpretedFrame(function, pc, fp, sp);
};
return ToImpl(this)->GetMutableFrame(index, frame_cons);
} }
WasmVal WasmInterpreter::Thread::GetReturnValue(int index) { WasmVal WasmInterpreter::Thread::GetReturnValue(int index) {
return ToImpl(this)->GetReturnValue(index); return ToImpl(this)->GetReturnValue(index);
...@@ -1844,29 +1855,6 @@ WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) { ...@@ -1844,29 +1855,6 @@ WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
return ToThread(&internals_->threads_[id]); return ToThread(&internals_->threads_[id]);
} }
WasmVal WasmInterpreter::GetLocalVal(const WasmFrame* frame, int index) {
CHECK_GE(index, 0);
UNIMPLEMENTED();
WasmVal none;
none.type = kWasmStmt;
return none;
}
WasmVal WasmInterpreter::GetExprVal(const WasmFrame* frame, int pc) {
UNIMPLEMENTED();
WasmVal none;
none.type = kWasmStmt;
return none;
}
void WasmInterpreter::SetLocalVal(WasmFrame* frame, int index, WasmVal val) {
UNIMPLEMENTED();
}
void WasmInterpreter::SetExprVal(WasmFrame* frame, int pc, WasmVal val) {
UNIMPLEMENTED();
}
size_t WasmInterpreter::GetMemorySize() { size_t WasmInterpreter::GetMemorySize() {
return internals_->instance_->mem_size; return internals_->instance_->mem_size;
} }
...@@ -1896,6 +1884,35 @@ ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting( ...@@ -1896,6 +1884,35 @@ ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
return targets.map_; return targets.map_;
} }
//============================================================================
// Implementation of the frame inspection interface.
//============================================================================
int InterpretedFrame::GetParameterCount() const {
USE(fp_);
USE(sp_);
// TODO(clemensh): Return the correct number of parameters.
return 0;
}
WasmVal InterpretedFrame::GetLocalVal(int index) const {
CHECK_GE(index, 0);
UNIMPLEMENTED();
WasmVal none;
none.type = kWasmStmt;
return none;
}
WasmVal InterpretedFrame::GetExprVal(int pc) const {
UNIMPLEMENTED();
WasmVal none;
none.type = kWasmStmt;
return none;
}
void InterpretedFrame::SetLocalVal(int index, WasmVal val) { UNIMPLEMENTED(); }
void InterpretedFrame::SetExprVal(int pc, WasmVal val) { UNIMPLEMENTED(); }
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -80,20 +80,24 @@ FOREACH_UNION_MEMBER(DECLARE_CAST) ...@@ -80,20 +80,24 @@ FOREACH_UNION_MEMBER(DECLARE_CAST)
#undef DECLARE_CAST #undef DECLARE_CAST
// Representation of frames within the interpreter. // Representation of frames within the interpreter.
class WasmFrame { class InterpretedFrame {
public: public:
const WasmFunction* function() const { return function_; } const WasmFunction* function() const { return function_; }
int pc() const { int pc() const { return pc_; }
// TODO(wasm): Remove USE once we actually use them.
USE(fp_); //==========================================================================
USE(sp_); // Stack frame inspection.
return pc_; //==========================================================================
} int GetParameterCount() const;
WasmVal GetLocalVal(int index) const;
WasmVal GetExprVal(int pc) const;
void SetLocalVal(int index, WasmVal val);
void SetExprVal(int pc, WasmVal val);
private: private:
friend class WasmInterpreter; friend class WasmInterpreter;
WasmFrame(const WasmFunction* function, int pc, int fp, int sp) InterpretedFrame(const WasmFunction* function, int pc, int fp, int sp)
: function_(function), pc_(pc), fp_(fp), sp_(sp) {} : function_(function), pc_(pc), fp_(fp), sp_(sp) {}
const WasmFunction* function_; const WasmFunction* function_;
...@@ -134,8 +138,8 @@ class V8_EXPORT_PRIVATE WasmInterpreter { ...@@ -134,8 +138,8 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
// Stack inspection and modification. // Stack inspection and modification.
pc_t GetBreakpointPc(); pc_t GetBreakpointPc();
int GetFrameCount(); int GetFrameCount();
const WasmFrame* GetFrame(int index); const InterpretedFrame GetFrame(int index);
WasmFrame* GetMutableFrame(int index); InterpretedFrame GetMutableFrame(int index);
WasmVal GetReturnValue(int index = 0); WasmVal GetReturnValue(int index = 0);
// Returns true if the thread executed an instruction which may produce // Returns true if the thread executed an instruction which may produce
// nondeterministic results, e.g. float div, float sqrt, and float mul, // nondeterministic results, e.g. float div, float sqrt, and float mul,
...@@ -173,14 +177,6 @@ class V8_EXPORT_PRIVATE WasmInterpreter { ...@@ -173,14 +177,6 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
int GetThreadCount(); int GetThreadCount();
Thread* GetThread(int id); Thread* GetThread(int id);
//==========================================================================
// Stack frame inspection.
//==========================================================================
WasmVal GetLocalVal(const WasmFrame* frame, int index);
WasmVal GetExprVal(const WasmFrame* frame, int pc);
void SetLocalVal(WasmFrame* frame, int index, WasmVal val);
void SetExprVal(WasmFrame* frame, int pc, WasmVal val);
//========================================================================== //==========================================================================
// Memory access. // Memory access.
//========================================================================== //==========================================================================
......
...@@ -863,15 +863,17 @@ std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& name) { ...@@ -863,15 +863,17 @@ std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& name) {
} }
WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) { WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) {
DCHECK(code->kind() == Code::WASM_FUNCTION);
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
DCHECK(code->kind() == Code::WASM_FUNCTION ||
code->kind() == Code::WASM_INTERPRETER_ENTRY);
FixedArray* deopt_data = code->deoptimization_data(); FixedArray* deopt_data = code->deoptimization_data();
DCHECK_NOT_NULL(deopt_data); DCHECK_NOT_NULL(deopt_data);
DCHECK_EQ(2, deopt_data->length()); DCHECK_EQ(code->kind() == Code::WASM_INTERPRETER_ENTRY ? 1 : 2,
deopt_data->length());
Object* weak_link = deopt_data->get(0); Object* weak_link = deopt_data->get(0);
DCHECK(weak_link->IsWeakCell()); DCHECK(weak_link->IsWeakCell());
WeakCell* cell = WeakCell::cast(weak_link); WeakCell* cell = WeakCell::cast(weak_link);
if (!cell->value()) return nullptr; if (cell->cleared()) return nullptr;
return WasmInstanceObject::cast(cell->value()); return WasmInstanceObject::cast(cell->value());
} }
......
...@@ -1133,6 +1133,27 @@ bool WasmCompiledModule::SetBreakPoint( ...@@ -1133,6 +1133,27 @@ bool WasmCompiledModule::SetBreakPoint(
return true; return true;
} }
MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) {
Isolate* isolate = GetIsolate();
if (!shared()->has_breakpoint_infos()) return {};
Handle<FixedArray> breakpoint_infos(shared()->breakpoint_infos(), isolate);
int insert_pos =
FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
if (insert_pos >= breakpoint_infos->length()) return {};
Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
isolate);
if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
Handle<BreakPointInfo> breakpoint_info =
Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
if (breakpoint_info->source_position() != position) return {};
Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
isolate);
return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
}
Handle<WasmInstanceWrapper> WasmInstanceWrapper::New( Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
Isolate* isolate, Handle<WasmInstanceObject> instance) { Isolate* isolate, Handle<WasmInstanceObject> instance) {
Handle<FixedArray> array = Handle<FixedArray> array =
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace wasm { namespace wasm {
class InterpretedFrame;
struct WasmModule; struct WasmModule;
} }
...@@ -395,6 +396,10 @@ class WasmCompiledModule : public FixedArray { ...@@ -395,6 +396,10 @@ class WasmCompiledModule : public FixedArray {
static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position, static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position,
Handle<Object> break_point_object); Handle<Object> break_point_object);
// Return an empty handle if no breakpoint is hit at that location, or a
// FixedArray with all hit breakpoint objects.
MaybeHandle<FixedArray> CheckBreakPoints(int position);
private: private:
void InitId(); void InitId();
...@@ -417,8 +422,15 @@ class WasmDebugInfo : public FixedArray { ...@@ -417,8 +422,15 @@ class WasmDebugInfo : public FixedArray {
static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset); static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset);
static void RunInterpreter(Handle<WasmDebugInfo>, int func_index, void RunInterpreter(int func_index, uint8_t* arg_buffer);
uint8_t* arg_buffer);
// Get the stack of the wasm interpreter as pairs of <function index, byte
// offset>. The list is ordered bottom-to-top, i.e. caller before callee.
std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
Address frame_pointer);
std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
Address frame_pointer, int idx);
DECLARE_GETTER(wasm_instance, WasmInstanceObject); DECLARE_GETTER(wasm_instance, WasmInstanceObject);
}; };
......
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