Index: runtime/vm/debugger.cc |
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc |
index 5c54271bc56aefaeca52be2ef11e299e17a169e9..3cdf810c8d678527f68328de0fa065be6d01b0e1 100644 |
--- a/runtime/vm/debugger.cc |
+++ b/runtime/vm/debugger.cc |
@@ -6,8 +6,6 @@ |
#include "include/dart_api.h" |
-#include "platform/address_sanitizer.h" |
- |
#include "vm/code_generator.h" |
#include "vm/code_patcher.h" |
#include "vm/compiler.h" |
@@ -44,7 +42,6 @@ DEFINE_FLAG(bool, |
trace_debugger_stacktrace, |
false, |
"Trace debugger stacktrace collection"); |
-DEFINE_FLAG(bool, trace_rewind, false, "Trace frame rewind"); |
DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); |
DEFINE_FLAG(bool, |
steal_breakpoints, |
@@ -853,24 +850,6 @@ RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) { |
} |
-bool ActivationFrame::IsRewindable() const { |
- if (deopt_frame_.IsNull()) { |
- return true; |
- } |
- // TODO(turnidge): This is conservative. It looks at all values in |
- // the deopt_frame_ even though some of them may correspond to other |
- // inlined frames. |
- Object& obj = Object::Handle(); |
- for (int i = 0; i < deopt_frame_.Length(); i++) { |
- obj = deopt_frame_.At(i); |
- if (obj.raw() == Symbols::OptimizedOut().raw()) { |
- return false; |
- } |
- } |
- return true; |
-} |
- |
- |
void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, |
intptr_t frame_ctx_level, |
intptr_t var_ctx_level) { |
@@ -1129,13 +1108,9 @@ void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { |
} |
} |
-static bool IsFunctionVisible(const Function& function) { |
- return FLAG_show_invisible_frames || function.is_visible(); |
-} |
- |
void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
- if (IsFunctionVisible(frame->function())) { |
+ if (FLAG_show_invisible_frames || frame->function().is_visible()) { |
trace_.Add(frame); |
} |
} |
@@ -1262,8 +1237,6 @@ Debugger::Debugger() |
breakpoint_locations_(NULL), |
code_breakpoints_(NULL), |
resume_action_(kContinue), |
- resume_frame_index_(-1), |
- post_deopt_frame_index_(-1), |
ignore_breakpoints_(false), |
pause_event_(NULL), |
obj_cache_(NULL), |
@@ -1327,13 +1300,10 @@ static RawFunction* ResolveLibraryFunction(const Library& library, |
} |
-bool Debugger::SetupStepOverAsyncSuspension(const char** error) { |
+bool Debugger::SetupStepOverAsyncSuspension() { |
ActivationFrame* top_frame = TopDartFrame(); |
if (!IsAtAsyncJump(top_frame)) { |
// Not at an async operation. |
- if (error) { |
- *error = "Isolate must be paused at an async suspension point"; |
- } |
return false; |
} |
Object& closure = Object::Handle(top_frame->GetAsyncOperation()); |
@@ -1343,42 +1313,24 @@ bool Debugger::SetupStepOverAsyncSuspension(const char** error) { |
Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); |
if (bpt == NULL) { |
// Unable to set the breakpoint. |
- if (error) { |
- *error = "Unable to set breakpoint at async suspension point"; |
- } |
return false; |
} |
return true; |
} |
-bool Debugger::SetResumeAction(ResumeAction action, |
- intptr_t frame_index, |
- const char** error) { |
- if (error) { |
- *error = NULL; |
- } |
- resume_frame_index_ = -1; |
- switch (action) { |
- case kStepInto: |
- case kStepOver: |
- case kStepOut: |
- case kContinue: |
- resume_action_ = action; |
- return true; |
- case kStepRewind: |
- if (!CanRewindFrame(frame_index, error)) { |
- return false; |
- } |
- resume_action_ = kStepRewind; |
- resume_frame_index_ = frame_index; |
- return true; |
- case kStepOverAsyncSuspension: |
- return SetupStepOverAsyncSuspension(error); |
- default: |
- UNREACHABLE(); |
- return false; |
- } |
+void Debugger::SetSingleStep() { |
+ resume_action_ = kSingleStep; |
+} |
+ |
+ |
+void Debugger::SetStepOver() { |
+ resume_action_ = kStepOver; |
+} |
+ |
+ |
+void Debugger::SetStepOut() { |
+ resume_action_ = kStepOut; |
} |
@@ -1670,7 +1622,6 @@ void Debugger::PauseException(const Instance& exc) { |
ASSERT(stack_trace_ == NULL); |
stack_trace_ = stack_trace; |
Pause(&event); |
- HandleSteppingRequest(stack_trace_); // we may get a rewind request |
stack_trace_ = NULL; |
} |
@@ -2596,7 +2547,7 @@ void Debugger::EnterSingleStepMode() { |
void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
bool skip_next_step) { |
stepping_fp_ = 0; |
- if (resume_action_ == kStepInto) { |
+ if (resume_action_ == kSingleStep) { |
// When single stepping, we need to deoptimize because we might be |
// stepping into optimized code. This happens in particular if |
// the isolate has been interrupted, but can happen in other cases |
@@ -2606,7 +2557,7 @@ void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
isolate_->set_single_step(true); |
skip_next_step_ = skip_next_step; |
if (FLAG_verbose_debug) { |
- OS::Print("HandleSteppingRequest- kStepInto\n"); |
+ OS::Print("HandleSteppingRequest- kSingleStep\n"); |
} |
} else if (resume_action_ == kStepOver) { |
DeoptimizeWorld(); |
@@ -2631,244 +2582,6 @@ void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
if (FLAG_verbose_debug) { |
OS::Print("HandleSteppingRequest- kStepOut %" Px "\n", stepping_fp_); |
} |
- } else if (resume_action_ == kStepRewind) { |
- if (FLAG_trace_rewind) { |
- OS::PrintErr("Rewinding to frame %" Pd "\n", resume_frame_index_); |
- OS::PrintErr( |
- "-------------------------\n" |
- "All frames...\n\n"); |
- StackFrameIterator iterator(false); |
- StackFrame* frame = iterator.NextFrame(); |
- intptr_t num = 0; |
- while ((frame != NULL)) { |
- OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); |
- frame = iterator.NextFrame(); |
- } |
- } |
- RewindToFrame(resume_frame_index_); |
- UNREACHABLE(); |
- } |
-} |
- |
- |
-static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, |
- intptr_t frame_index) { |
- for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { |
- ActivationFrame* frame = stack->FrameAt(i); |
- if (frame->IsRewindable()) { |
- return i; |
- } |
- } |
- return -1; |
-} |
- |
- |
-// Can the top frame be rewound? |
-bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const { |
- // check rewind pc is found |
- DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); |
- intptr_t num_frames = stack->Length(); |
- if (frame_index < 1 || frame_index >= num_frames) { |
- if (error) { |
- *error = Thread::Current()->zone()->PrintToString( |
- "Frame must be in bounds [1..%" Pd |
- "]: " |
- "saw %" Pd "", |
- num_frames - 1, frame_index); |
- } |
- return false; |
- } |
- ActivationFrame* frame = stack->FrameAt(frame_index); |
- if (!frame->IsRewindable()) { |
- intptr_t next_index = FindNextRewindFrameIndex(stack, frame_index); |
- if (next_index > 0) { |
- *error = Thread::Current()->zone()->PrintToString( |
- "Cannot rewind to frame %" Pd |
- " due to conflicting compiler " |
- "optimizations. " |
- "Run the vm with --no-prune-dead-locals to disallow these " |
- "optimizations. " |
- "Next valid rewind frame is %" Pd ".", |
- frame_index, next_index); |
- } else { |
- *error = Thread::Current()->zone()->PrintToString( |
- "Cannot rewind to frame %" Pd |
- " due to conflicting compiler " |
- "optimizations. " |
- "Run the vm with --no-prune-dead-locals to disallow these " |
- "optimizations.", |
- frame_index); |
- } |
- return false; |
- } |
- return true; |
-} |
- |
- |
-// Given a return address pc, find the "rewind" pc, which is the pc |
-// before the corresponding call. |
-static uword LookupRewindPc(const Code& code, uword pc) { |
- ASSERT(!code.is_optimized()); |
- ASSERT(code.ContainsInstructionAt(pc)); |
- |
- uword pc_offset = pc - code.PayloadStart(); |
- const PcDescriptors& descriptors = |
- PcDescriptors::Handle(code.pc_descriptors()); |
- PcDescriptors::Iterator iter( |
- descriptors, RawPcDescriptors::kRewind | RawPcDescriptors::kIcCall | |
- RawPcDescriptors::kUnoptStaticCall); |
- intptr_t rewind_deopt_id = -1; |
- uword rewind_pc = 0; |
- while (iter.MoveNext()) { |
- if (iter.Kind() == RawPcDescriptors::kRewind) { |
- // Remember the last rewind so we don't need to iterator twice. |
- rewind_pc = code.PayloadStart() + iter.PcOffset(); |
- rewind_deopt_id = iter.DeoptId(); |
- } |
- if ((pc_offset == iter.PcOffset()) && (iter.DeoptId() == rewind_deopt_id)) { |
- return rewind_pc; |
- } |
- } |
- return 0; |
-} |
- |
- |
-void Debugger::RewindToFrame(intptr_t frame_index) { |
- Thread* thread = Thread::Current(); |
- Zone* zone = thread->zone(); |
- Code& code = Code::Handle(zone); |
- Function& function = Function::Handle(zone); |
- |
- // Find the requested frame. |
- StackFrameIterator iterator(false); |
- intptr_t current_frame = 0; |
- for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
- frame = iterator.NextFrame()) { |
- ASSERT(frame->IsValid()); |
- if (frame->IsDartFrame()) { |
- code = frame->LookupDartCode(); |
- function = code.function(); |
- if (!IsFunctionVisible(function)) { |
- continue; |
- } |
- if (code.is_optimized()) { |
- intptr_t sub_index = 0; |
- for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); |
- it.Advance()) { |
- if (current_frame == frame_index) { |
- RewindToOptimizedFrame(frame, code, sub_index); |
- UNREACHABLE(); |
- } |
- current_frame++; |
- sub_index++; |
- } |
- } else { |
- if (current_frame == frame_index) { |
- // We are rewinding to an unoptimized frame. |
- RewindToUnoptimizedFrame(frame, code); |
- UNREACHABLE(); |
- } |
- current_frame++; |
- } |
- } |
- } |
- UNIMPLEMENTED(); |
-} |
- |
- |
-void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { |
- // We will be jumping out of the debugger rather than exiting this |
- // function, so prepare the debugger state. |
- stack_trace_ = NULL; |
- resume_action_ = kContinue; |
- resume_frame_index_ = -1; |
- EnterSingleStepMode(); |
- |
- uword rewind_pc = LookupRewindPc(code, frame->pc()); |
- if (FLAG_trace_rewind && rewind_pc == 0) { |
- OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); |
- } |
- ASSERT(rewind_pc != 0); |
- if (FLAG_trace_rewind) { |
- OS::PrintErr( |
- "===============================\n" |
- "Rewinding to unoptimized frame:\n" |
- " rewind_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
- ")\n" |
- "===============================\n", |
- rewind_pc, frame->sp(), frame->fp()); |
- } |
- Exceptions::JumpToFrame(Thread::Current(), rewind_pc, frame->sp(), |
- frame->fp(), true /* clear lazy deopt at target */); |
- UNREACHABLE(); |
-} |
- |
- |
-void Debugger::RewindToOptimizedFrame(StackFrame* frame, |
- const Code& optimized_code, |
- intptr_t sub_index) { |
- post_deopt_frame_index_ = sub_index; |
- |
- // We will be jumping out of the debugger rather than exiting this |
- // function, so prepare the debugger state. |
- stack_trace_ = NULL; |
- resume_action_ = kContinue; |
- resume_frame_index_ = -1; |
- EnterSingleStepMode(); |
- |
- if (FLAG_trace_rewind) { |
- OS::PrintErr( |
- "===============================\n" |
- "Deoptimizing frame for rewind:\n" |
- " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
- ")\n" |
- "===============================\n", |
- frame->pc(), frame->sp(), frame->fp()); |
- } |
- Thread* thread = Thread::Current(); |
- thread->set_resume_pc(frame->pc()); |
- uword deopt_stub_pc = StubCode::DeoptForRewind_entry()->EntryPoint(); |
- Exceptions::JumpToFrame(thread, deopt_stub_pc, frame->sp(), frame->fp(), |
- true /* clear lazy deopt at target */); |
- UNREACHABLE(); |
-} |
- |
- |
-void Debugger::RewindPostDeopt() { |
- intptr_t rewind_frame = post_deopt_frame_index_; |
- post_deopt_frame_index_ = -1; |
- if (FLAG_trace_rewind) { |
- OS::PrintErr("Post deopt, jumping to frame %" Pd "\n", rewind_frame); |
- OS::PrintErr( |
- "-------------------------\n" |
- "All frames...\n\n"); |
- StackFrameIterator iterator(false); |
- StackFrame* frame = iterator.NextFrame(); |
- intptr_t num = 0; |
- while ((frame != NULL)) { |
- OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); |
- frame = iterator.NextFrame(); |
- } |
- } |
- |
- Thread* thread = Thread::Current(); |
- Zone* zone = thread->zone(); |
- Code& code = Code::Handle(zone); |
- |
- StackFrameIterator iterator(false); |
- intptr_t current_frame = 0; |
- for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
- frame = iterator.NextFrame()) { |
- ASSERT(frame->IsValid()); |
- if (frame->IsDartFrame()) { |
- code = frame->LookupDartCode(); |
- ASSERT(!code.is_optimized()); |
- if (current_frame == rewind_frame) { |
- RewindToUnoptimizedFrame(frame, code); |
- UNREACHABLE(); |
- } |
- current_frame++; |
- } |
} |
} |
@@ -3080,7 +2793,7 @@ RawError* Debugger::PauseBreakpoint() { |
// We are at the entry of an async function. |
// We issue a step over to resume at the point after the await statement. |
- SetResumeAction(kStepOver); |
+ SetStepOver(); |
// When we single step from a user breakpoint, our next stepping |
// point will be at the exact same pc. Skip it. |
HandleSteppingRequest(stack_trace_, true /* skip next step */); |
@@ -3133,7 +2846,7 @@ void Debugger::PauseDeveloper(const String& msg) { |
// We are in the native call to Developer_debugger. the developer |
// gets a better experience by not seeing this call. To accomplish |
// this, we continue execution until the call exits (step out). |
- SetResumeAction(kStepOut); |
+ SetStepOut(); |
HandleSteppingRequest(stack_trace_); |
stack_trace_ = NULL; |