[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}
This commit is contained in:
parent
4714bc15e8
commit
09525c8f90
@ -15,7 +15,6 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index,
|
||||
Isolate* isolate)
|
||||
: frame_(frame),
|
||||
frame_summary_(FrameSummary::Get(frame, inlined_frame_index)),
|
||||
deoptimized_frame_(nullptr),
|
||||
isolate_(isolate) {
|
||||
JavaScriptFrame* js_frame =
|
||||
frame->is_java_script() ? javascript_frame() : nullptr;
|
||||
@ -35,21 +34,28 @@ FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index,
|
||||
return;
|
||||
}
|
||||
|
||||
deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
|
||||
js_frame, inlined_frame_index, isolate);
|
||||
deoptimized_frame_.reset(Deoptimizer::DebuggerInspectableFrame(
|
||||
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() {
|
||||
// Get rid of the calculated deoptimized frame if any.
|
||||
if (deoptimized_frame_ != nullptr) {
|
||||
delete deoptimized_frame_;
|
||||
}
|
||||
// Destructor needs to be defined in the .cc file, because it instantiates
|
||||
// std::unique_ptr destructors but the types are not known in the header.
|
||||
}
|
||||
|
||||
int FrameInspector::GetParametersCount() {
|
||||
return is_optimized_ ? deoptimized_frame_->parameters_count()
|
||||
: frame_->ComputeParametersCount();
|
||||
if (is_optimized_) return deoptimized_frame_->parameters_count();
|
||||
if (wasm_interpreted_frame_)
|
||||
return wasm_interpreted_frame_->GetParameterCount();
|
||||
return frame_->ComputeParametersCount();
|
||||
}
|
||||
|
||||
Handle<Script> FrameInspector::GetScript() {
|
||||
@ -61,8 +67,9 @@ Handle<JSFunction> FrameInspector::GetFunction() {
|
||||
}
|
||||
|
||||
Handle<Object> FrameInspector::GetParameter(int index) {
|
||||
return is_optimized_ ? deoptimized_frame_->GetParameter(index)
|
||||
: handle(frame_->GetParameter(index), isolate_);
|
||||
if (is_optimized_) return deoptimized_frame_->GetParameter(index);
|
||||
// TODO(clemensh): Handle wasm_interpreted_frame_.
|
||||
return handle(frame_->GetParameter(index), isolate_);
|
||||
}
|
||||
|
||||
Handle<Object> FrameInspector::GetExpression(int index) {
|
||||
|
@ -13,6 +13,11 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Forward declaration:
|
||||
namespace wasm {
|
||||
class InterpretedFrame;
|
||||
}
|
||||
|
||||
class FrameInspector {
|
||||
public:
|
||||
FrameInspector(StandardFrame* frame, int inlined_frame_index,
|
||||
@ -54,7 +59,8 @@ class FrameInspector {
|
||||
|
||||
StandardFrame* frame_;
|
||||
FrameSummary frame_summary_;
|
||||
DeoptimizedFrameInfo* deoptimized_frame_;
|
||||
std::unique_ptr<DeoptimizedFrameInfo> deoptimized_frame_;
|
||||
std::unique_ptr<wasm::InterpretedFrame> wasm_interpreted_frame_;
|
||||
Isolate* isolate_;
|
||||
bool is_optimized_;
|
||||
bool is_interpreted_;
|
||||
|
@ -2317,9 +2317,9 @@ void Debug::ProcessDebugMessages(bool debug_command_only) {
|
||||
void Debug::PrintBreakLocation() {
|
||||
if (!FLAG_print_break_location) return;
|
||||
HandleScope scope(isolate_);
|
||||
JavaScriptFrameIterator iterator(isolate_);
|
||||
StackTraceFrameIterator iterator(isolate_);
|
||||
if (iterator.done()) return;
|
||||
JavaScriptFrame* frame = iterator.frame();
|
||||
StandardFrame* frame = iterator.frame();
|
||||
FrameSummary summary = FrameSummary::GetTop(frame);
|
||||
int source_position = summary.SourcePosition();
|
||||
Handle<Object> script_obj = summary.script();
|
||||
@ -2372,8 +2372,6 @@ DebugScope::DebugScope(Debug* debug)
|
||||
// frame id.
|
||||
StackTraceFrameIterator it(isolate());
|
||||
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_ =
|
||||
has_frames ? it.frame()->id() : StackFrame::NO_ID;
|
||||
debug_->SetNextBreakId();
|
||||
|
@ -1763,7 +1763,7 @@ void WasmInterpreterEntryFrame::Iterate(ObjectVisitor* v) const {
|
||||
void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode,
|
||||
int index) const {
|
||||
PrintIndex(accumulator, mode, index);
|
||||
accumulator->Add("WASM TO INTERPRETER [");
|
||||
accumulator->Add("WASM INTERPRETER ENTRY [");
|
||||
Script* script = this->script();
|
||||
accumulator->PrintName(script->name());
|
||||
accumulator->Add("]");
|
||||
@ -1772,8 +1772,15 @@ void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode,
|
||||
|
||||
void WasmInterpreterEntryFrame::Summarize(List<FrameSummary>* functions,
|
||||
FrameSummary::Mode mode) const {
|
||||
// TODO(clemensh): Implement this.
|
||||
UNIMPLEMENTED();
|
||||
Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
|
||||
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 {
|
||||
|
@ -159,6 +159,8 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
|
||||
CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 2);
|
||||
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
|
||||
// Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
|
||||
@ -167,11 +169,7 @@ RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
|
||||
CHECK(arg_buffer_obj->IsSmi());
|
||||
uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj);
|
||||
|
||||
Handle<WasmInstanceObject> instance =
|
||||
Handle<WasmInstanceObject>::cast(instance_obj);
|
||||
Handle<WasmDebugInfo> debug_info =
|
||||
WasmInstanceObject::GetOrCreateDebugInfo(instance);
|
||||
WasmDebugInfo::RunInterpreter(debug_info, func_index, arg_buffer);
|
||||
instance->debug_info()->RunInterpreter(func_index, arg_buffer);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,15 @@ class Managed : public Foreign {
|
||||
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,
|
||||
bool delete_on_gc = true) {
|
||||
Handle<Foreign> foreign =
|
||||
isolate->factory()->NewForeign(reinterpret_cast<Address>(ptr));
|
||||
Handle<Managed<CppType>> handle(
|
||||
reinterpret_cast<Managed<CppType>*>(*foreign), isolate);
|
||||
Handle<Managed<CppType>> handle = Handle<Managed<CppType>>::cast(
|
||||
isolate->factory()->NewForeign(reinterpret_cast<Address>(ptr)));
|
||||
if (delete_on_gc) {
|
||||
RegisterWeakCallbackForDelete(isolate, handle);
|
||||
}
|
||||
|
@ -21,17 +21,23 @@ using namespace v8::internal::wasm;
|
||||
|
||||
namespace {
|
||||
|
||||
// Forward declaration.
|
||||
class InterpreterHandle;
|
||||
InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info);
|
||||
|
||||
class InterpreterHandle {
|
||||
AccountingAllocator allocator_;
|
||||
WasmInstance instance_;
|
||||
WasmInterpreter interpreter_;
|
||||
Isolate* isolate_;
|
||||
|
||||
public:
|
||||
// Initialize in the right order, using helper methods to make this possible.
|
||||
// WasmInterpreter has to be allocated in place, since it is not movable.
|
||||
InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info)
|
||||
: 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(debug_info->wasm_instance()->memory_buffer(), isolate);
|
||||
if (mem_buffer->IsUndefined(isolate)) {
|
||||
@ -95,10 +101,9 @@ class InterpreterHandle {
|
||||
do {
|
||||
state = thread->Run();
|
||||
switch (state) {
|
||||
case WasmInterpreter::State::PAUSED: {
|
||||
// We hit a breakpoint.
|
||||
// TODO(clemensh): Handle this.
|
||||
} break;
|
||||
case WasmInterpreter::State::PAUSED:
|
||||
NotifyDebugEventListeners();
|
||||
break;
|
||||
case WasmInterpreter::State::FINISHED:
|
||||
// Perfect, just break the switch and exit the loop.
|
||||
break;
|
||||
@ -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(
|
||||
@ -151,6 +233,12 @@ InterpreterHandle* GetOrCreateInterpreterHandle(
|
||||
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) {
|
||||
size_t num_functions =
|
||||
instance->compiled_module()->module()->functions.size();
|
||||
@ -265,10 +353,18 @@ void WasmDebugInfo::SetBreakpoint(Handle<WasmDebugInfo> debug_info,
|
||||
EnsureRedirectToInterpreter(isolate, debug_info, func_index);
|
||||
}
|
||||
|
||||
void WasmDebugInfo::RunInterpreter(Handle<WasmDebugInfo> debug_info,
|
||||
int func_index, uint8_t* arg_buffer) {
|
||||
void WasmDebugInfo::RunInterpreter(int func_index, uint8_t* arg_buffer) {
|
||||
DCHECK_LE(0, func_index);
|
||||
InterpreterHandle* interp_handle =
|
||||
GetOrCreateInterpreterHandle(debug_info->GetIsolate(), debug_info);
|
||||
interp_handle->Execute(static_cast<uint32_t>(func_index), arg_buffer);
|
||||
GetInterpreterHandle(this)->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 {
|
||||
possible_nondeterminism_ = false;
|
||||
}
|
||||
|
||||
int GetFrameCount() { return static_cast<int>(frames_.size()); }
|
||||
|
||||
const WasmFrame* GetFrame(int index) {
|
||||
UNIMPLEMENTED();
|
||||
return nullptr;
|
||||
int GetFrameCount() {
|
||||
DCHECK_GE(kMaxInt, frames_.size());
|
||||
return static_cast<int>(frames_.size());
|
||||
}
|
||||
|
||||
WasmFrame* GetMutableFrame(int index) {
|
||||
UNIMPLEMENTED();
|
||||
return nullptr;
|
||||
template <typename FrameCons>
|
||||
InterpretedFrame GetMutableFrame(int index, FrameCons frame_cons) {
|
||||
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) {
|
||||
@ -1747,11 +1753,16 @@ pc_t WasmInterpreter::Thread::GetBreakpointPc() {
|
||||
int WasmInterpreter::Thread::GetFrameCount() {
|
||||
return ToImpl(this)->GetFrameCount();
|
||||
}
|
||||
const WasmFrame* WasmInterpreter::Thread::GetFrame(int index) {
|
||||
return ToImpl(this)->GetFrame(index);
|
||||
const InterpretedFrame WasmInterpreter::Thread::GetFrame(int index) {
|
||||
return GetMutableFrame(index);
|
||||
}
|
||||
WasmFrame* WasmInterpreter::Thread::GetMutableFrame(int index) {
|
||||
return ToImpl(this)->GetMutableFrame(index);
|
||||
InterpretedFrame WasmInterpreter::Thread::GetMutableFrame(int 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) {
|
||||
return ToImpl(this)->GetReturnValue(index);
|
||||
@ -1844,29 +1855,6 @@ WasmInterpreter::Thread* WasmInterpreter::GetThread(int 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() {
|
||||
return internals_->instance_->mem_size;
|
||||
}
|
||||
@ -1896,6 +1884,35 @@ ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
@ -80,20 +80,24 @@ FOREACH_UNION_MEMBER(DECLARE_CAST)
|
||||
#undef DECLARE_CAST
|
||||
|
||||
// Representation of frames within the interpreter.
|
||||
class WasmFrame {
|
||||
class InterpretedFrame {
|
||||
public:
|
||||
const WasmFunction* function() const { return function_; }
|
||||
int pc() const {
|
||||
// TODO(wasm): Remove USE once we actually use them.
|
||||
USE(fp_);
|
||||
USE(sp_);
|
||||
return pc_;
|
||||
}
|
||||
int pc() const { return pc_; }
|
||||
|
||||
//==========================================================================
|
||||
// Stack frame inspection.
|
||||
//==========================================================================
|
||||
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:
|
||||
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) {}
|
||||
|
||||
const WasmFunction* function_;
|
||||
@ -134,8 +138,8 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
// Stack inspection and modification.
|
||||
pc_t GetBreakpointPc();
|
||||
int GetFrameCount();
|
||||
const WasmFrame* GetFrame(int index);
|
||||
WasmFrame* GetMutableFrame(int index);
|
||||
const InterpretedFrame GetFrame(int index);
|
||||
InterpretedFrame GetMutableFrame(int index);
|
||||
WasmVal GetReturnValue(int index = 0);
|
||||
// Returns true if the thread executed an instruction which may produce
|
||||
// nondeterministic results, e.g. float div, float sqrt, and float mul,
|
||||
@ -173,14 +177,6 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
int GetThreadCount();
|
||||
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.
|
||||
//==========================================================================
|
||||
|
@ -863,15 +863,17 @@ std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& name) {
|
||||
}
|
||||
|
||||
WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) {
|
||||
DCHECK(code->kind() == Code::WASM_FUNCTION);
|
||||
DisallowHeapAllocation no_gc;
|
||||
DCHECK(code->kind() == Code::WASM_FUNCTION ||
|
||||
code->kind() == Code::WASM_INTERPRETER_ENTRY);
|
||||
FixedArray* deopt_data = code->deoptimization_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);
|
||||
DCHECK(weak_link->IsWeakCell());
|
||||
WeakCell* cell = WeakCell::cast(weak_link);
|
||||
if (!cell->value()) return nullptr;
|
||||
if (cell->cleared()) return nullptr;
|
||||
return WasmInstanceObject::cast(cell->value());
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1133,27 @@ bool WasmCompiledModule::SetBreakPoint(
|
||||
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(
|
||||
Isolate* isolate, Handle<WasmInstanceObject> instance) {
|
||||
Handle<FixedArray> array =
|
||||
|
@ -15,6 +15,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
class InterpretedFrame;
|
||||
struct WasmModule;
|
||||
}
|
||||
|
||||
@ -395,6 +396,10 @@ class WasmCompiledModule : public FixedArray {
|
||||
static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position,
|
||||
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:
|
||||
void InitId();
|
||||
|
||||
@ -417,8 +422,15 @@ class WasmDebugInfo : public FixedArray {
|
||||
|
||||
static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset);
|
||||
|
||||
static void RunInterpreter(Handle<WasmDebugInfo>, int func_index,
|
||||
uint8_t* arg_buffer);
|
||||
void RunInterpreter(int func_index, 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);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user