| 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.
|
|
|