Index: runtime/vm/debugger.cc |
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc |
index 82511db787418fe52421c7147296fead76518912..4b97085301aab831d6701a583163317825da7026 100644 |
--- a/runtime/vm/debugger.cc |
+++ b/runtime/vm/debugger.cc |
@@ -218,6 +218,9 @@ void Breakpoint::PrintJSON(JSONStream* stream) { |
jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); |
jsobj.AddProperty("breakpointNumber", id()); |
+ if (is_synthetic_async()) { |
+ jsobj.AddProperty("isSyntheticAsyncBreakpoint", is_synthetic_async()); |
+ } |
jsobj.AddProperty("resolved", bpt_location_->IsResolved()); |
if (bpt_location_->IsResolved()) { |
jsobj.AddLocation(bpt_location_); |
@@ -430,7 +433,8 @@ Breakpoint* BreakpointLocation::AddSingleShot(Debugger* dbg) { |
Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, |
- const Instance& closure) { |
+ const Instance& closure, |
+ bool for_over_await) { |
Breakpoint* bpt = breakpoints(); |
while (bpt != NULL) { |
if (bpt->IsPerClosure() && bpt->closure() == closure.raw()) break; |
@@ -439,6 +443,7 @@ Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, |
if (bpt == NULL) { |
bpt = new Breakpoint(dbg->nextId(), this); |
bpt->SetIsPerClosure(closure); |
+ bpt->set_is_synthetic_async(for_over_await); |
AddBreakpoint(bpt, dbg); |
} |
return bpt; |
@@ -1326,6 +1331,26 @@ static RawFunction* ResolveLibraryFunction( |
} |
+bool Debugger::SetupStepOverAwait() { |
+ ActivationFrame* top_frame = TopDartFrame(); |
+ Object& closure_or_null = Object::Handle(top_frame->GetAsyncOperation()); |
+ if (closure_or_null.IsNull()) { |
+ // Not at an async operation. |
+ return false; |
+ } |
+ // Add a break point at the async continuation closure. |
+ ASSERT(closure_or_null.IsInstance()); |
+ ASSERT(Instance::Cast(closure_or_null).IsClosure()); |
+ Breakpoint* bpt = |
+ SetBreakpointAtActivation(Instance::Cast(closure_or_null), true); |
+ if (bpt == NULL) { |
+ // Unable to set the breakpoint. |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+ |
void Debugger::SetSingleStep() { |
resume_action_ = kSingleStep; |
} |
@@ -2155,7 +2180,8 @@ Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, |
} |
-Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) { |
+Breakpoint* Debugger::SetBreakpointAtActivation( |
+ const Instance& closure, bool for_over_await) { |
if (!closure.IsClosure()) { |
return NULL; |
} |
@@ -2165,7 +2191,7 @@ Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) { |
func.token_pos(), |
func.end_token_pos(), |
-1, -1 /* no line/col */); |
- return bpt_location->AddPerClosure(this, closure); |
+ return bpt_location->AddPerClosure(this, closure, for_over_await); |
} |
@@ -2764,6 +2790,35 @@ RawError* Debugger::SignalBpReached() { |
return Error::null(); |
} |
+ if (bpt_hit->is_synthetic_async()) { |
+ DebuggerStackTrace* stack_trace = CollectStackTrace(); |
+ ASSERT(stack_trace->Length() > 0); |
+ ASSERT(stack_trace_ == NULL); |
+ stack_trace_ = stack_trace; |
+ |
+ // Hit a synthetic async breakpoint. |
+ if (FLAG_verbose_debug) { |
+ OS::Print(">>> hit synthetic breakpoint at %s:%" Pd " " |
+ "(token %s) (address %#" Px ")\n", |
+ String::Handle(cbpt->SourceUrl()).ToCString(), |
+ cbpt->LineNumber(), |
+ cbpt->token_pos().ToCString(), |
+ top_frame->pc()); |
+ } |
+ |
+ RemoveBreakpoint(bpt_hit->id()); |
+ bpt_hit = NULL; |
rmacnak
2016/02/16 21:21:58
It would clearer from the client's perspective if
Cutch
2016/02/17 18:24:21
Done.
|
+ |
+ // We are at the entry of an async function. |
+ // We issue a step over to resume at the point after the await statement. |
+ 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 */); |
+ stack_trace_ = NULL; |
+ return Error::null(); |
+ } |
+ |
if (FLAG_verbose_debug) { |
OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
"(token %s) (address %#" Px ")\n", |