Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Unified Diff: runtime/vm/debugger.h

Issue 2603383004: Sane asynchronous debugging and stack traces (Closed)
Patch Set: rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/compiler.cc ('k') | runtime/vm/debugger.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/debugger.h
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index fa9c3a61466776e9cf319922d508f8806b11296c..53e98d2a8bf7a75ccfa4c86671ac477e80c57d62 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -11,6 +11,17 @@
#include "vm/port.h"
#include "vm/service_event.h"
+DECLARE_FLAG(bool, verbose_debug);
+
+// 'Trace Debugger' TD_Print.
+#if defined(_MSC_VER)
+#define TD_Print(format, ...) \
+ if (FLAG_verbose_debug) Log::Current()->Print(format, __VA_ARGS__)
+#else
+#define TD_Print(format, ...) \
+ if (FLAG_verbose_debug) Log::Current()->Print(format, ##__VA_ARGS__)
+#endif
+
namespace dart {
class CodeBreakpoint;
@@ -204,6 +215,8 @@ class CodeBreakpoint {
RawCode* OrigStubAddress() const;
+ const char* ToCString();
+
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -245,12 +258,26 @@ class CodeBreakpoint {
// on the call stack.
class ActivationFrame : public ZoneAllocated {
public:
+ enum Kind {
+ kRegular,
+ kAsyncLive,
+ kAsyncSuspensionMarker,
+ kAsyncHistorical,
+ };
+
ActivationFrame(uword pc,
uword fp,
uword sp,
const Code& code,
const Array& deopt_frame,
- intptr_t deopt_frame_offset);
+ intptr_t deopt_frame_offset,
+ Kind kind = kRegular);
+
+ ActivationFrame(uword pc, const Code& code);
+
+ explicit ActivationFrame(Kind kind);
+
+ explicit ActivationFrame(const Closure& async_activation);
uword pc() const { return pc_; }
uword fp() const { return fp_; }
@@ -272,6 +299,10 @@ class ActivationFrame : public ZoneAllocated {
intptr_t LineNumber();
intptr_t ColumnNumber();
+ bool IsLiveFrame() const {
+ return (kind_ == kRegular) || (kind_ == kAsyncLive);
+ }
+
// Returns true if this frame is for a function that is visible
// to the user and can be debugged.
bool IsDebuggable() const;
@@ -279,6 +310,17 @@ class ActivationFrame : public ZoneAllocated {
// Returns true if it is possible to rewind the debugger to this frame.
bool IsRewindable() const;
+ // Returns true if this function is _SyncCompleter._completeOnAsyncReturn
+ // from the async library.
+ bool IsCompleteOnAsyncReturn();
+
+ // Returns true if this function is from the AsyncStartStreamController class.
+ bool IsInAsyncStarStreamController();
+
+ // Returns true if this function is part of the async implementation
+ // machinery.
+ bool IsInAsyncMachinery();
+
// The context level of a frame is the context level at the
// PC/token index of the frame. It determines the depth of the context
// chain that belongs to the function of this activation frame.
@@ -302,6 +344,15 @@ class ActivationFrame : public ZoneAllocated {
const Context& GetSavedCurrentContext();
RawObject* GetAsyncOperation();
+ RawObject* GetAsyncCompleter();
+ RawObject* GetAsyncCompleterAwaiter(const Object& completer);
+
+ void ExtractTokenPositionFromAsyncClosure();
+
+ RawObject* GetAsyncStreamControllerStream();
+ RawObject* GetAsyncStreamControllerStreamAwaiter(const Object& stream);
+
+ RawObject* GetAsyncAwaiter();
RawObject* Evaluate(const String& expr);
@@ -311,6 +362,12 @@ class ActivationFrame : public ZoneAllocated {
void PrintToJSONObject(JSONObject* jsobj, bool full = false);
private:
+ void PrintToJSONObjectAsync(JSONObject* jsobj, bool full = false);
+ void PrintToJSONObjectRegular(JSONObject* jsobj, bool full = false);
+ void PrintToJSONObjectHistoricalFrame(JSONObject* jsobj, bool full = false);
+
+ void PrintToJSONObjectLiveFrame(JSONObject* jsobj, bool full = false);
+
void PrintContextMismatchError(intptr_t ctx_slot,
intptr_t frame_ctx_level,
intptr_t var_ctx_level);
@@ -320,6 +377,22 @@ class ActivationFrame : public ZoneAllocated {
void GetVarDescriptors();
void GetDescIndices();
+ static const char* KindToCString(Kind kind) {
+ switch (kind) {
+ case kRegular:
+ return "kRegular";
+ case kAsyncLive:
+ return "kAsyncLive";
+ case kAsyncSuspensionMarker:
+ return "kMarker";
+ case kAsyncHistorical:
+ return "kAsyncHistorical";
+ default:
+ UNREACHABLE();
+ return "";
+ }
+ }
+
RawObject* GetStackVar(intptr_t slot_index);
RawObject* GetContextVar(intptr_t ctxt_level, intptr_t slot_index);
@@ -329,8 +402,9 @@ class ActivationFrame : public ZoneAllocated {
// The anchor of the context chain for this function.
Context& ctx_;
- const Code& code_;
- const Function& function_;
+ Code& code_;
+ Function& function_;
+ bool suspended_frame_;
bool token_pos_initialized_;
TokenPosition token_pos_;
intptr_t try_index_;
@@ -343,6 +417,8 @@ class ActivationFrame : public ZoneAllocated {
const Array& deopt_frame_;
const intptr_t deopt_frame_offset_;
+ Kind kind_;
+
bool vars_initialized_;
LocalVarDescriptors& var_descriptors_;
ZoneGrowableArray<intptr_t> desc_indices_;
@@ -367,6 +443,9 @@ class DebuggerStackTrace : public ZoneAllocated {
private:
void AddActivation(ActivationFrame* frame);
+ void AddMarker(ActivationFrame::Kind marker);
+ void AddAsyncHistoricalFrame(uword pc, const Code& code);
+
ZoneGrowableArray<ActivationFrame*> trace_;
friend class Debugger;
@@ -394,6 +473,8 @@ class Debugger {
void NotifyIsolateCreated();
void Shutdown();
+ void WhenRunnable();
+
void NotifyCompilation(const Function& func);
void NotifyDoneLoading();
@@ -430,8 +511,13 @@ class Debugger {
bool IsStepping() const { return resume_action_ != kContinue; }
+ bool IsSingleStepping() const { return resume_action_ == kStepInto; }
+
bool IsPaused() const { return pause_event_ != NULL; }
+ void AsyncStepInto(const Closure& async_op);
+ void AsyncContinue();
+
// Put the isolate into single stepping mode when Dart code next runs.
//
// This is used by the vm service to allow the user to step while
@@ -470,6 +556,17 @@ class Debugger {
DebuggerStackTrace* StackTrace();
DebuggerStackTrace* CurrentStackTrace();
+ // Returns a stack trace with frames corresponding to invisible functions
+ // omitted. CurrentAsyncStackTrace always returns a new trace on the current
+ // stack. The trace returned by AsyncStackTrace may have been cached; it is
+ // suitable for use when stepping, but otherwise may be out of sync with the
+ // current stack.
+ DebuggerStackTrace* AsyncStackTrace();
+ DebuggerStackTrace* CurrentAsyncStackTrace();
+
+ DebuggerStackTrace* AsyncReturnStack();
+ DebuggerStackTrace* CurrentAsyncReturnStack();
+
// Returns a debugger stack trace corresponding to a dart.core.StackTrace.
// Frames corresponding to invisible functions are omitted. It is not valid
// to query local variables in the returned stack.
@@ -530,9 +627,23 @@ class Debugger {
private:
RawError* PauseRequest(ServiceEvent::EventKind kind);
+ /// Finds the breakpoint we hit at |location|.
+ Breakpoint* FindHitBreakpoint(BreakpointLocation* location,
+ ActivationFrame* top_frame);
+
+ // Returns true if the debugger had just taken a step after hitting a
+ // synthetic async breakpoint.
+ bool SteppedForSyntheticAsyncBreakpoint() const;
+
+ RawError* StepForSyntheticAsyncBreakpoint(Breakpoint* bpt);
+
+ void CleanupSyntheticAsyncBreakpoint();
+
// Will return false if we are not at an await.
bool SetupStepOverAsyncSuspension(const char** error);
+ uword GetAsyncActivationGeneratorSteppingFramePointer();
+
bool NeedsIsolateEvents();
bool NeedsDebugEvents();
void InvokeEventHandler(ServiceEvent* event);
@@ -574,16 +685,21 @@ class Debugger {
void SyncBreakpointLocation(BreakpointLocation* loc);
ActivationFrame* TopDartFrame() const;
- static ActivationFrame* CollectDartFrame(Isolate* isolate,
- uword pc,
- StackFrame* frame,
- const Code& code,
- const Array& deopt_frame,
- intptr_t deopt_frame_offset);
+ static ActivationFrame* CollectDartFrame(
+ Isolate* isolate,
+ uword pc,
+ StackFrame* frame,
+ const Code& code,
+ const Array& deopt_frame,
+ intptr_t deopt_frame_offset,
+ ActivationFrame::Kind kind = ActivationFrame::kRegular);
static RawArray* DeoptimizeToArray(Thread* thread,
StackFrame* frame,
const Code& code);
+ static DebuggerStackTrace* CollectAsyncStackTrace();
static DebuggerStackTrace* CollectStackTrace();
+ static DebuggerStackTrace* CollectAsyncReturnCallStack();
+
void SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt);
intptr_t nextId() { return next_id_++; }
@@ -603,6 +719,11 @@ class Debugger {
void HandleSteppingRequest(DebuggerStackTrace* stack_trace,
bool skip_next_step = false);
+ void CacheStackTraces(DebuggerStackTrace* stack_trace,
+ DebuggerStackTrace* async_stack_trace,
+ DebuggerStackTrace* async_return_stack_trace);
+ void ClearCachedStackTraces();
+
// Can we rewind to the indicated frame?
bool CanRewindFrame(intptr_t frame_index, const char** error) const;
@@ -645,11 +766,25 @@ class Debugger {
// Current stack trace. Valid only while IsPaused().
DebuggerStackTrace* stack_trace_;
+ // Current async stack trace. Valid only while IsPaused().
+ DebuggerStackTrace* async_stack_trace_;
+
+ // Current async return call trace. Valid only while IsPaused().
+ DebuggerStackTrace* async_return_call_stack_;
+
// When stepping through code, only pause the program if the top
// frame corresponds to this fp value, or if the top frame is
// lower on the stack.
uword stepping_fp_;
+ // In order to support automatic step-out behaviour for asynchronous functions
+ // we track the top frame's awaiter. This is where execution should begin
+ // once we've left the current function. We keep track of the
+ // async_stepping_fp_ and use it to determine if we have single stepped our
+ // way out of the asynchronous function.
+ RawObject* top_frame_awaiter_;
+ uword async_stepping_fp_;
+
// If we step while at a breakpoint, we would hit the same pc twice.
// We use this field to let us skip the next single-step after a
// breakpoint.
« no previous file with comments | « runtime/vm/compiler.cc ('k') | runtime/vm/debugger.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698