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

Side by Side Diff: runtime/vm/debugger.cc

Issue 2785243003: Implement support for single stepping out of an async function. (Closed)
Patch Set: fschneider review Created 3 years, 8 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 unified diff | Download patch
« no previous file with comments | « runtime/vm/debugger.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/debugger.h" 5 #include "vm/debugger.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 8
9 #include "platform/address_sanitizer.h" 9 #include "platform/address_sanitizer.h"
10 10
(...skipping 891 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) { 902 if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) {
903 if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) { 903 if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) {
904 try_index_ = iter.TryIndex(); 904 try_index_ = iter.TryIndex();
905 } 905 }
906 } 906 }
907 } 907 }
908 } 908 }
909 } 909 }
910 910
911 911
912 bool ActivationFrame::IsAsyncMachinery() const {
913 Isolate* isolate = Isolate::Current();
914 if (function_.raw() == isolate->object_store()->complete_on_async_return()) {
915 // We are completing an async function's completer.
916 return true;
917 }
918 if (function_.Owner() ==
919 isolate->object_store()->async_star_stream_controller()) {
920 // We are inside the async* stream controller code.
921 return true;
922 }
923 return false;
924 }
925
926
912 // Get the saved current context of this activation. 927 // Get the saved current context of this activation.
913 const Context& ActivationFrame::GetSavedCurrentContext() { 928 const Context& ActivationFrame::GetSavedCurrentContext() {
914 if (!ctx_.IsNull()) return ctx_; 929 if (!ctx_.IsNull()) return ctx_;
915 GetVarDescriptors(); 930 GetVarDescriptors();
916 intptr_t var_desc_len = var_descriptors_.Length(); 931 intptr_t var_desc_len = var_descriptors_.Length();
917 for (intptr_t i = 0; i < var_desc_len; i++) { 932 for (intptr_t i = 0; i < var_desc_len; i++) {
918 RawLocalVarDescriptors::VarInfo var_info; 933 RawLocalVarDescriptors::VarInfo var_info;
919 var_descriptors_.GetInfo(i, &var_info); 934 var_descriptors_.GetInfo(i, &var_info);
920 const int8_t kind = var_info.kind(); 935 const int8_t kind = var_info.kind();
921 if (kind == RawLocalVarDescriptors::kSavedCurrentContext) { 936 if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 resume_action_(kContinue), 1583 resume_action_(kContinue),
1569 resume_frame_index_(-1), 1584 resume_frame_index_(-1),
1570 post_deopt_frame_index_(-1), 1585 post_deopt_frame_index_(-1),
1571 ignore_breakpoints_(false), 1586 ignore_breakpoints_(false),
1572 pause_event_(NULL), 1587 pause_event_(NULL),
1573 obj_cache_(NULL), 1588 obj_cache_(NULL),
1574 stack_trace_(NULL), 1589 stack_trace_(NULL),
1575 async_causal_stack_trace_(NULL), 1590 async_causal_stack_trace_(NULL),
1576 awaiter_stack_trace_(NULL), 1591 awaiter_stack_trace_(NULL),
1577 stepping_fp_(0), 1592 stepping_fp_(0),
1593 async_stepping_fp_(0),
1594 top_frame_awaiter_(Object::null()),
1578 skip_next_step_(false), 1595 skip_next_step_(false),
1579 needs_breakpoint_cleanup_(false), 1596 needs_breakpoint_cleanup_(false),
1580 synthetic_async_breakpoint_(NULL), 1597 synthetic_async_breakpoint_(NULL),
1581 exc_pause_info_(kNoPauseOnExceptions) {} 1598 exc_pause_info_(kNoPauseOnExceptions) {}
1582 1599
1583 1600
1584 Debugger::~Debugger() { 1601 Debugger::~Debugger() {
1585 isolate_id_ = ILLEGAL_ISOLATE_ID; 1602 isolate_id_ = ILLEGAL_ISOLATE_ID;
1586 ASSERT(!IsPaused()); 1603 ASSERT(!IsPaused());
1587 ASSERT(latent_locations_ == NULL); 1604 ASSERT(latent_locations_ == NULL);
(...skipping 1542 matching lines...) Expand 10 before | Expand all | Expand 10 after
3130 bpt = latent_locations_; 3147 bpt = latent_locations_;
3131 while (bpt != NULL) { 3148 while (bpt != NULL) {
3132 bpt->VisitObjectPointers(visitor); 3149 bpt->VisitObjectPointers(visitor);
3133 bpt = bpt->next(); 3150 bpt = bpt->next();
3134 } 3151 }
3135 CodeBreakpoint* cbpt = code_breakpoints_; 3152 CodeBreakpoint* cbpt = code_breakpoints_;
3136 while (cbpt != NULL) { 3153 while (cbpt != NULL) {
3137 cbpt->VisitObjectPointers(visitor); 3154 cbpt->VisitObjectPointers(visitor);
3138 cbpt = cbpt->next(); 3155 cbpt = cbpt->next();
3139 } 3156 }
3157 visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_frame_awaiter_));
3140 } 3158 }
3141 3159
3142 3160
3143 // static 3161 // static
3144 void Debugger::SetEventHandler(EventHandler* handler) { 3162 void Debugger::SetEventHandler(EventHandler* handler) {
3145 event_handler_ = handler; 3163 event_handler_ = handler;
3146 } 3164 }
3147 3165
3148 3166
3149 void Debugger::Pause(ServiceEvent* event) { 3167 void Debugger::Pause(ServiceEvent* event) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
3193 3211
3194 if (needs_breakpoint_cleanup_) { 3212 if (needs_breakpoint_cleanup_) {
3195 RemoveUnlinkedCodeBreakpoints(); 3213 RemoveUnlinkedCodeBreakpoints();
3196 } 3214 }
3197 pause_event_ = NULL; 3215 pause_event_ = NULL;
3198 obj_cache_ = NULL; // Zone allocated 3216 obj_cache_ = NULL; // Zone allocated
3199 } 3217 }
3200 3218
3201 3219
3202 void Debugger::EnterSingleStepMode() { 3220 void Debugger::EnterSingleStepMode() {
3203 stepping_fp_ = 0; 3221 ResetSteppingFramePointers();
3204 DeoptimizeWorld(); 3222 DeoptimizeWorld();
3205 isolate_->set_single_step(true); 3223 isolate_->set_single_step(true);
3206 } 3224 }
3207 3225
3208 3226
3227 void Debugger::ResetSteppingFramePointers() {
3228 stepping_fp_ = 0;
3229 async_stepping_fp_ = 0;
3230 }
3231
3232
3233 bool Debugger::SteppedForSyntheticAsyncBreakpoint() const {
3234 return synthetic_async_breakpoint_ != NULL;
3235 }
3236
3237
3238 void Debugger::CleanupSyntheticAsyncBreakpoint() {
3239 if (synthetic_async_breakpoint_ != NULL) {
3240 RemoveBreakpoint(synthetic_async_breakpoint_->id());
3241 synthetic_async_breakpoint_ = NULL;
3242 }
3243 }
3244
3245
3246 void Debugger::RememberTopFrameAwaiter() {
3247 if (!FLAG_async_debugger_stepping) {
3248 return;
3249 }
3250 if (stack_trace_->Length() > 0) {
3251 top_frame_awaiter_ = stack_trace_->FrameAt(0)->GetAsyncAwaiter();
3252 } else {
3253 top_frame_awaiter_ = Object::null();
3254 }
3255 }
3256
3257
3258 void Debugger::SetAsyncSteppingFramePointer() {
3259 if (!FLAG_async_debugger_stepping) {
3260 return;
3261 }
3262 if (stack_trace_->FrameAt(0)->function().IsAsyncClosure() ||
3263 stack_trace_->FrameAt(0)->function().IsAsyncGenClosure()) {
3264 async_stepping_fp_ = stack_trace_->FrameAt(0)->fp();
3265 } else {
3266 async_stepping_fp_ = 0;
3267 }
3268 }
3269
3270
3209 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, 3271 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace,
3210 bool skip_next_step) { 3272 bool skip_next_step) {
3211 stepping_fp_ = 0; 3273 ResetSteppingFramePointers();
3274 RememberTopFrameAwaiter();
3212 if (resume_action_ == kStepInto) { 3275 if (resume_action_ == kStepInto) {
3213 // When single stepping, we need to deoptimize because we might be 3276 // When single stepping, we need to deoptimize because we might be
3214 // stepping into optimized code. This happens in particular if 3277 // stepping into optimized code. This happens in particular if
3215 // the isolate has been interrupted, but can happen in other cases 3278 // the isolate has been interrupted, but can happen in other cases
3216 // as well. We need to deoptimize the world in case we are about 3279 // as well. We need to deoptimize the world in case we are about
3217 // to call an optimized function. 3280 // to call an optimized function.
3218 DeoptimizeWorld(); 3281 DeoptimizeWorld();
3219 isolate_->set_single_step(true); 3282 isolate_->set_single_step(true);
3220 skip_next_step_ = skip_next_step; 3283 skip_next_step_ = skip_next_step;
3284 SetAsyncSteppingFramePointer();
3221 if (FLAG_verbose_debug) { 3285 if (FLAG_verbose_debug) {
3222 OS::Print("HandleSteppingRequest- kStepInto\n"); 3286 OS::Print("HandleSteppingRequest- kStepInto\n");
3223 } 3287 }
3224 } else if (resume_action_ == kStepOver) { 3288 } else if (resume_action_ == kStepOver) {
3225 DeoptimizeWorld(); 3289 DeoptimizeWorld();
3226 isolate_->set_single_step(true); 3290 isolate_->set_single_step(true);
3227 skip_next_step_ = skip_next_step; 3291 skip_next_step_ = skip_next_step;
3228 ASSERT(stack_trace->Length() > 0); 3292 ASSERT(stack_trace->Length() > 0);
3229 stepping_fp_ = stack_trace->FrameAt(0)->fp(); 3293 stepping_fp_ = stack_trace->FrameAt(0)->fp();
3294 SetAsyncSteppingFramePointer();
3230 if (FLAG_verbose_debug) { 3295 if (FLAG_verbose_debug) {
3231 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); 3296 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_);
3232 } 3297 }
3233 } else if (resume_action_ == kStepOut) { 3298 } else if (resume_action_ == kStepOut) {
3234 if (FLAG_async_debugger_stepping) { 3299 if (FLAG_async_debugger_stepping) {
3235 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() || 3300 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() ||
3236 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) { 3301 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) {
3237 // Request to step out of an async/async* closure. 3302 // Request to step out of an async/async* closure.
3238 const Object& async_op = 3303 const Object& async_op =
3239 Object::Handle(stack_trace->FrameAt(0)->GetAsyncAwaiter()); 3304 Object::Handle(stack_trace->FrameAt(0)->GetAsyncAwaiter());
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
3526 return false; 3591 return false;
3527 } 3592 }
3528 const Class& cls = Class::Handle(func.Owner()); 3593 const Class& cls = Class::Handle(func.Owner());
3529 const Library& lib = Library::Handle(cls.library()); 3594 const Library& lib = Library::Handle(cls.library());
3530 return lib.IsDebuggable(); 3595 return lib.IsDebuggable();
3531 } 3596 }
3532 3597
3533 3598
3534 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { 3599 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) {
3535 resume_action_ = kContinue; 3600 resume_action_ = kContinue;
3536 stepping_fp_ = 0; 3601 ResetSteppingFramePointers();
3537 isolate_->set_single_step(false); 3602 isolate_->set_single_step(false);
3538 ASSERT(!IsPaused()); 3603 ASSERT(!IsPaused());
3539 ASSERT(obj_cache_ == NULL); 3604 ASSERT(obj_cache_ == NULL);
3540 if ((bpt != NULL) && bpt->IsSingleShot()) { 3605 if ((bpt != NULL) && bpt->IsSingleShot()) {
3541 RemoveBreakpoint(bpt->id()); 3606 RemoveBreakpoint(bpt->id());
3542 bpt = NULL; 3607 bpt = NULL;
3543 } 3608 }
3544 3609
3545 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); 3610 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint);
3546 event.set_top_frame(top_frame); 3611 event.set_top_frame(top_frame);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
3592 } 3657 }
3593 3658
3594 // Check whether we are in a Dart function that the user is 3659 // Check whether we are in a Dart function that the user is
3595 // interested in. If we saved the frame pointer of a stack frame 3660 // interested in. If we saved the frame pointer of a stack frame
3596 // the user is interested in, we ignore the single step if we are 3661 // the user is interested in, we ignore the single step if we are
3597 // in a callee of that frame. Note that we assume that the stack 3662 // in a callee of that frame. Note that we assume that the stack
3598 // grows towards lower addresses. 3663 // grows towards lower addresses.
3599 ActivationFrame* frame = TopDartFrame(); 3664 ActivationFrame* frame = TopDartFrame();
3600 ASSERT(frame != NULL); 3665 ASSERT(frame != NULL);
3601 3666
3667 if (FLAG_async_debugger_stepping) {
3668 if ((async_stepping_fp_ != 0) && (top_frame_awaiter_ != Object::null())) {
3669 // Check if the user has single stepped out of an async function with
3670 // an awaiter. The first check handles the case of calling into the
3671 // async machinery as we finish the async function. The second check
3672 // handles the case of returning from an async function.
3673 const bool exited_async_function =
3674 (IsCalleeFrameOf(async_stepping_fp_, frame->fp()) &&
3675 frame->IsAsyncMachinery()) ||
3676 IsCalleeFrameOf(frame->fp(), async_stepping_fp_);
3677 if (exited_async_function) {
3678 // Step to the top frame awaiter.
3679 const Object& async_op = Object::Handle(top_frame_awaiter_);
3680 top_frame_awaiter_ = Object::null();
3681 AsyncStepInto(Closure::Cast(async_op));
3682 return Error::null();
3683 }
3684 }
3685 }
3686
3602 if (stepping_fp_ != 0) { 3687 if (stepping_fp_ != 0) {
3603 // There is an "interesting frame" set. Only pause at appropriate 3688 // There is an "interesting frame" set. Only pause at appropriate
3604 // locations in this frame. 3689 // locations in this frame.
3605 if (IsCalleeFrameOf(stepping_fp_, frame->fp())) { 3690 if (IsCalleeFrameOf(stepping_fp_, frame->fp())) {
3606 // We are in a callee of the frame we're interested in. 3691 // We are in a callee of the frame we're interested in.
3607 // Ignore this stepping break. 3692 // Ignore this stepping break.
3608 return Error::null(); 3693 return Error::null();
3609 } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) { 3694 } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) {
3610 // We returned from the "interesting frame", there can be no more 3695 // We returned from the "interesting frame", there can be no more
3611 // stepping breaks for it. Pause at the next appropriate location 3696 // stepping breaks for it. Pause at the next appropriate location
3612 // and let the user set the "interesting" frame again. 3697 // and let the user set the "interesting" frame again.
3613 stepping_fp_ = 0; 3698 ResetSteppingFramePointers();
3614 } 3699 }
3615 } 3700 }
3616 3701
3617 if (!frame->IsDebuggable()) { 3702 if (!frame->IsDebuggable()) {
3618 return Error::null(); 3703 return Error::null();
3619 } 3704 }
3620 if (!frame->TokenPos().IsDebugPause()) { 3705 if (!frame->TokenPos().IsDebugPause()) {
3621 return Error::null(); 3706 return Error::null();
3622 } 3707 }
3623 3708
3624 // If there is an active breakpoint at this pc, then we should have 3709 // If there is an active breakpoint at this pc, then we should have
3625 // already bailed out of this function in the skip_next_step_ test 3710 // already bailed out of this function in the skip_next_step_ test
3626 // above. 3711 // above.
3627 ASSERT(!HasActiveBreakpoint(frame->pc())); 3712 ASSERT(!HasActiveBreakpoint(frame->pc()));
3628 3713
3629 if (FLAG_verbose_debug) { 3714 if (FLAG_verbose_debug) {
3630 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", 3715 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n",
3631 String::Handle(frame->SourceUrl()).ToCString(), 3716 String::Handle(frame->SourceUrl()).ToCString(),
3632 frame->LineNumber(), 3717 frame->LineNumber(),
3633 String::Handle(frame->QualifiedFunctionName()).ToCString(), 3718 String::Handle(frame->QualifiedFunctionName()).ToCString(),
3634 frame->TokenPos().ToCString()); 3719 frame->TokenPos().ToCString());
3635 } 3720 }
3636 3721
3637 3722
3638 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace(), 3723 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace(),
3639 CollectAwaiterReturnStackTrace()); 3724 CollectAwaiterReturnStackTrace());
3640 // If this step callback is part of stepping over an await statement, 3725 if (SteppedForSyntheticAsyncBreakpoint()) {
3641 // we saved the synthetic async breakpoint in PauseBreakpoint. We report 3726 CleanupSyntheticAsyncBreakpoint();
3642 // that we are paused at that breakpoint and then delete it after continuing.
3643 SignalPausedEvent(frame, synthetic_async_breakpoint_);
3644 if (synthetic_async_breakpoint_ != NULL) {
3645 RemoveBreakpoint(synthetic_async_breakpoint_->id());
3646 synthetic_async_breakpoint_ = NULL;
3647 } 3727 }
3728 SignalPausedEvent(frame, NULL);
3648 HandleSteppingRequest(stack_trace_); 3729 HandleSteppingRequest(stack_trace_);
3649 ClearCachedStackTraces(); 3730 ClearCachedStackTraces();
3650 3731
3651 // If any error occurred while in the debug message loop, return it here. 3732 // If any error occurred while in the debug message loop, return it here.
3652 const Error& error = Error::Handle(Thread::Current()->sticky_error()); 3733 const Error& error = Error::Handle(Thread::Current()->sticky_error());
3653 Thread::Current()->clear_sticky_error(); 3734 Thread::Current()->clear_sticky_error();
3654 return error.raw(); 3735 return error.raw();
3655 } 3736 }
3656 3737
3657 3738
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after
4230 4311
4231 void Debugger::AsyncStepInto(const Closure& async_op) { 4312 void Debugger::AsyncStepInto(const Closure& async_op) {
4232 SetBreakpointAtActivation(async_op, true); 4313 SetBreakpointAtActivation(async_op, true);
4233 Continue(); 4314 Continue();
4234 } 4315 }
4235 4316
4236 4317
4237 void Debugger::Continue() { 4318 void Debugger::Continue() {
4238 SetResumeAction(kContinue); 4319 SetResumeAction(kContinue);
4239 stepping_fp_ = 0; 4320 stepping_fp_ = 0;
4321 async_stepping_fp_ = 0;
4240 isolate_->set_single_step(false); 4322 isolate_->set_single_step(false);
4241 } 4323 }
4242 4324
4243 4325
4244 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, 4326 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url,
4245 intptr_t line, 4327 intptr_t line,
4246 intptr_t column) { 4328 intptr_t column) {
4247 BreakpointLocation* bpt = latent_locations_; 4329 BreakpointLocation* bpt = latent_locations_;
4248 String& bpt_url = String::Handle(); 4330 String& bpt_url = String::Handle();
4249 while (bpt != NULL) { 4331 while (bpt != NULL) {
(...skipping 21 matching lines...) Expand all
4271 4353
4272 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { 4354 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
4273 ASSERT(bpt->next() == NULL); 4355 ASSERT(bpt->next() == NULL);
4274 bpt->set_next(code_breakpoints_); 4356 bpt->set_next(code_breakpoints_);
4275 code_breakpoints_ = bpt; 4357 code_breakpoints_ = bpt;
4276 } 4358 }
4277 4359
4278 #endif // !PRODUCT 4360 #endif // !PRODUCT
4279 4361
4280 } // namespace dart 4362 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/debugger.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698