OLD | NEW |
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 "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 } | 211 } |
212 } | 212 } |
213 | 213 |
214 | 214 |
215 void Breakpoint::PrintJSON(JSONStream* stream) { | 215 void Breakpoint::PrintJSON(JSONStream* stream) { |
216 JSONObject jsobj(stream); | 216 JSONObject jsobj(stream); |
217 jsobj.AddProperty("type", "Breakpoint"); | 217 jsobj.AddProperty("type", "Breakpoint"); |
218 | 218 |
219 jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); | 219 jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); |
220 jsobj.AddProperty("breakpointNumber", id()); | 220 jsobj.AddProperty("breakpointNumber", id()); |
| 221 if (is_synthetic_async()) { |
| 222 jsobj.AddProperty("isSyntheticAsyncContinuation", is_synthetic_async()); |
| 223 } |
221 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); | 224 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); |
222 if (bpt_location_->IsResolved()) { | 225 if (bpt_location_->IsResolved()) { |
223 jsobj.AddLocation(bpt_location_); | 226 jsobj.AddLocation(bpt_location_); |
224 } else { | 227 } else { |
225 jsobj.AddUnresolvedLocation(bpt_location_); | 228 jsobj.AddUnresolvedLocation(bpt_location_); |
226 } | 229 } |
227 } | 230 } |
228 | 231 |
229 | 232 |
230 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 233 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 if (bpt == NULL) { | 426 if (bpt == NULL) { |
424 bpt = new Breakpoint(dbg->nextId(), this); | 427 bpt = new Breakpoint(dbg->nextId(), this); |
425 bpt->SetIsSingleShot(); | 428 bpt->SetIsSingleShot(); |
426 AddBreakpoint(bpt, dbg); | 429 AddBreakpoint(bpt, dbg); |
427 } | 430 } |
428 return bpt; | 431 return bpt; |
429 } | 432 } |
430 | 433 |
431 | 434 |
432 Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, | 435 Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, |
433 const Instance& closure) { | 436 const Instance& closure, |
| 437 bool for_over_await) { |
434 Breakpoint* bpt = breakpoints(); | 438 Breakpoint* bpt = breakpoints(); |
435 while (bpt != NULL) { | 439 while (bpt != NULL) { |
436 if (bpt->IsPerClosure() && bpt->closure() == closure.raw()) break; | 440 if (bpt->IsPerClosure() && bpt->closure() == closure.raw()) break; |
437 bpt = bpt->next(); | 441 bpt = bpt->next(); |
438 } | 442 } |
439 if (bpt == NULL) { | 443 if (bpt == NULL) { |
440 bpt = new Breakpoint(dbg->nextId(), this); | 444 bpt = new Breakpoint(dbg->nextId(), this); |
441 bpt->SetIsPerClosure(closure); | 445 bpt->SetIsPerClosure(closure); |
| 446 bpt->set_is_synthetic_async(for_over_await); |
442 AddBreakpoint(bpt, dbg); | 447 AddBreakpoint(bpt, dbg); |
443 } | 448 } |
444 return bpt; | 449 return bpt; |
445 } | 450 } |
446 | 451 |
447 | 452 |
448 const char* Debugger::QualifiedFunctionName(const Function& func) { | 453 const char* Debugger::QualifiedFunctionName(const Function& func) { |
449 const String& func_name = String::Handle(func.name()); | 454 const String& func_name = String::Handle(func.name()); |
450 Class& func_class = Class::Handle(func.Owner()); | 455 Class& func_class = Class::Handle(func.Owner()); |
451 String& class_name = String::Handle(func_class.Name()); | 456 String& class_name = String::Handle(func_class.Name()); |
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1261 latent_locations_(NULL), | 1266 latent_locations_(NULL), |
1262 breakpoint_locations_(NULL), | 1267 breakpoint_locations_(NULL), |
1263 code_breakpoints_(NULL), | 1268 code_breakpoints_(NULL), |
1264 resume_action_(kContinue), | 1269 resume_action_(kContinue), |
1265 ignore_breakpoints_(false), | 1270 ignore_breakpoints_(false), |
1266 pause_event_(NULL), | 1271 pause_event_(NULL), |
1267 obj_cache_(NULL), | 1272 obj_cache_(NULL), |
1268 stack_trace_(NULL), | 1273 stack_trace_(NULL), |
1269 stepping_fp_(0), | 1274 stepping_fp_(0), |
1270 skip_next_step_(false), | 1275 skip_next_step_(false), |
| 1276 synthetic_async_breakpoint_(NULL), |
1271 exc_pause_info_(kNoPauseOnExceptions) { | 1277 exc_pause_info_(kNoPauseOnExceptions) { |
1272 } | 1278 } |
1273 | 1279 |
1274 | 1280 |
1275 Debugger::~Debugger() { | 1281 Debugger::~Debugger() { |
1276 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1282 isolate_id_ = ILLEGAL_ISOLATE_ID; |
1277 ASSERT(!IsPaused()); | 1283 ASSERT(!IsPaused()); |
1278 ASSERT(latent_locations_ == NULL); | 1284 ASSERT(latent_locations_ == NULL); |
1279 ASSERT(breakpoint_locations_ == NULL); | 1285 ASSERT(breakpoint_locations_ == NULL); |
1280 ASSERT(code_breakpoints_ == NULL); | 1286 ASSERT(code_breakpoints_ == NULL); |
1281 ASSERT(stack_trace_ == NULL); | 1287 ASSERT(stack_trace_ == NULL); |
1282 ASSERT(obj_cache_ == NULL); | 1288 ASSERT(obj_cache_ == NULL); |
| 1289 ASSERT(synthetic_async_breakpoint_ == NULL); |
1283 } | 1290 } |
1284 | 1291 |
1285 | 1292 |
1286 void Debugger::Shutdown() { | 1293 void Debugger::Shutdown() { |
1287 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need | 1294 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need |
1288 // them. Then, assert here that isolate_ is not one of those isolates. | 1295 // them. Then, assert here that isolate_ is not one of those isolates. |
1289 if ((isolate_ == Dart::vm_isolate()) || | 1296 if ((isolate_ == Dart::vm_isolate()) || |
1290 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 1297 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { |
1291 return; | 1298 return; |
1292 } | 1299 } |
(...skipping 26 matching lines...) Expand all Loading... |
1319 const String& fname) { | 1326 const String& fname) { |
1320 ASSERT(!library.IsNull()); | 1327 ASSERT(!library.IsNull()); |
1321 const Object& object = Object::Handle(library.ResolveName(fname)); | 1328 const Object& object = Object::Handle(library.ResolveName(fname)); |
1322 if (!object.IsNull() && object.IsFunction()) { | 1329 if (!object.IsNull() && object.IsFunction()) { |
1323 return Function::Cast(object).raw(); | 1330 return Function::Cast(object).raw(); |
1324 } | 1331 } |
1325 return Function::null(); | 1332 return Function::null(); |
1326 } | 1333 } |
1327 | 1334 |
1328 | 1335 |
| 1336 bool Debugger::SetupStepOverAsyncSuspension() { |
| 1337 ActivationFrame* top_frame = TopDartFrame(); |
| 1338 if (!IsAtAsyncJump(top_frame)) { |
| 1339 // Not at an async operation. |
| 1340 return false; |
| 1341 } |
| 1342 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); |
| 1343 ASSERT(!closure.IsNull()); |
| 1344 ASSERT(closure.IsInstance()); |
| 1345 ASSERT(Instance::Cast(closure).IsClosure()); |
| 1346 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); |
| 1347 if (bpt == NULL) { |
| 1348 // Unable to set the breakpoint. |
| 1349 return false; |
| 1350 } |
| 1351 return true; |
| 1352 } |
| 1353 |
| 1354 |
1329 void Debugger::SetSingleStep() { | 1355 void Debugger::SetSingleStep() { |
1330 resume_action_ = kSingleStep; | 1356 resume_action_ = kSingleStep; |
1331 } | 1357 } |
1332 | 1358 |
1333 | 1359 |
1334 void Debugger::SetStepOver() { | 1360 void Debugger::SetStepOver() { |
1335 resume_action_ = kStepOver; | 1361 resume_action_ = kStepOver; |
1336 } | 1362 } |
1337 | 1363 |
1338 | 1364 |
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2148 target_function.end_token_pos(), | 2174 target_function.end_token_pos(), |
2149 -1, -1 /* no requested line/col */); | 2175 -1, -1 /* no requested line/col */); |
2150 if (single_shot) { | 2176 if (single_shot) { |
2151 return bpt_location->AddSingleShot(this); | 2177 return bpt_location->AddSingleShot(this); |
2152 } else { | 2178 } else { |
2153 return bpt_location->AddRepeated(this); | 2179 return bpt_location->AddRepeated(this); |
2154 } | 2180 } |
2155 } | 2181 } |
2156 | 2182 |
2157 | 2183 |
2158 Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) { | 2184 Breakpoint* Debugger::SetBreakpointAtActivation( |
| 2185 const Instance& closure, bool for_over_await) { |
2159 if (!closure.IsClosure()) { | 2186 if (!closure.IsClosure()) { |
2160 return NULL; | 2187 return NULL; |
2161 } | 2188 } |
2162 const Function& func = Function::Handle(Closure::Cast(closure).function()); | 2189 const Function& func = Function::Handle(Closure::Cast(closure).function()); |
2163 const Script& script = Script::Handle(func.script()); | 2190 const Script& script = Script::Handle(func.script()); |
2164 BreakpointLocation* bpt_location = SetBreakpoint(script, | 2191 BreakpointLocation* bpt_location = SetBreakpoint(script, |
2165 func.token_pos(), | 2192 func.token_pos(), |
2166 func.end_token_pos(), | 2193 func.end_token_pos(), |
2167 -1, -1 /* no line/col */); | 2194 -1, -1 /* no line/col */); |
2168 return bpt_location->AddPerClosure(this, closure); | 2195 return bpt_location->AddPerClosure(this, closure, for_over_await); |
2169 } | 2196 } |
2170 | 2197 |
2171 | 2198 |
2172 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) { | 2199 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) { |
2173 if (!closure.IsClosure()) { | 2200 if (!closure.IsClosure()) { |
2174 return NULL; | 2201 return NULL; |
2175 } | 2202 } |
2176 | 2203 |
2177 BreakpointLocation* loc = breakpoint_locations_; | 2204 BreakpointLocation* loc = breakpoint_locations_; |
2178 while (loc != NULL) { | 2205 while (loc != NULL) { |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2610 ASSERT(!IsPaused()); | 2637 ASSERT(!IsPaused()); |
2611 ASSERT(obj_cache_ == NULL); | 2638 ASSERT(obj_cache_ == NULL); |
2612 if ((bpt != NULL) && bpt->IsSingleShot()) { | 2639 if ((bpt != NULL) && bpt->IsSingleShot()) { |
2613 RemoveBreakpoint(bpt->id()); | 2640 RemoveBreakpoint(bpt->id()); |
2614 bpt = NULL; | 2641 bpt = NULL; |
2615 } | 2642 } |
2616 | 2643 |
2617 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2644 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); |
2618 event.set_top_frame(top_frame); | 2645 event.set_top_frame(top_frame); |
2619 event.set_breakpoint(bpt); | 2646 event.set_breakpoint(bpt); |
| 2647 event.set_at_async_jump(IsAtAsyncJump(top_frame)); |
| 2648 Pause(&event); |
| 2649 } |
| 2650 |
| 2651 |
| 2652 bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) { |
2620 Object& closure_or_null = Object::Handle(top_frame->GetAsyncOperation()); | 2653 Object& closure_or_null = Object::Handle(top_frame->GetAsyncOperation()); |
2621 if (!closure_or_null.IsNull()) { | 2654 if (!closure_or_null.IsNull()) { |
2622 ASSERT(closure_or_null.IsInstance()); | 2655 ASSERT(closure_or_null.IsInstance()); |
2623 ASSERT(Instance::Cast(closure_or_null).IsClosure()); | 2656 ASSERT(Instance::Cast(closure_or_null).IsClosure()); |
2624 event.set_async_continuation(&closure_or_null); | |
2625 const Script& script = Script::Handle(top_frame->SourceScript()); | 2657 const Script& script = Script::Handle(top_frame->SourceScript()); |
2626 const TokenStream& tokens = TokenStream::Handle(script.tokens()); | 2658 const TokenStream& tokens = TokenStream::Handle(script.tokens()); |
2627 TokenStream::Iterator iter(tokens, top_frame->TokenPos()); | 2659 TokenStream::Iterator iter(tokens, top_frame->TokenPos()); |
2628 if ((iter.CurrentTokenKind() == Token::kIDENT) && | 2660 if ((iter.CurrentTokenKind() == Token::kIDENT) && |
2629 ((iter.CurrentLiteral() == Symbols::Await().raw()) || | 2661 ((iter.CurrentLiteral() == Symbols::Await().raw()) || |
2630 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { | 2662 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { |
2631 event.set_at_async_jump(true); | 2663 return true; |
2632 } | 2664 } |
2633 } | 2665 } |
2634 Pause(&event); | 2666 return false; |
2635 } | 2667 } |
2636 | 2668 |
2637 | |
2638 RawError* Debugger::DebuggerStepCallback() { | 2669 RawError* Debugger::DebuggerStepCallback() { |
2639 ASSERT(isolate_->single_step()); | 2670 ASSERT(isolate_->single_step()); |
2640 // Don't pause recursively. | 2671 // Don't pause recursively. |
2641 if (IsPaused()) { | 2672 if (IsPaused()) { |
2642 return Error::null(); | 2673 return Error::null(); |
2643 } | 2674 } |
2644 if (skip_next_step_) { | 2675 if (skip_next_step_) { |
2645 skip_next_step_ = false; | 2676 skip_next_step_ = false; |
2646 return Error::null(); | 2677 return Error::null(); |
2647 } | 2678 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2684 if (FLAG_verbose_debug) { | 2715 if (FLAG_verbose_debug) { |
2685 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 2716 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
2686 String::Handle(frame->SourceUrl()).ToCString(), | 2717 String::Handle(frame->SourceUrl()).ToCString(), |
2687 frame->LineNumber(), | 2718 frame->LineNumber(), |
2688 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 2719 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
2689 frame->TokenPos().ToCString()); | 2720 frame->TokenPos().ToCString()); |
2690 } | 2721 } |
2691 | 2722 |
2692 ASSERT(stack_trace_ == NULL); | 2723 ASSERT(stack_trace_ == NULL); |
2693 stack_trace_ = CollectStackTrace(); | 2724 stack_trace_ = CollectStackTrace(); |
2694 SignalPausedEvent(frame, NULL); | 2725 // If this step callback is part of stepping over an await statement, |
| 2726 // we saved the synthetic async breakpoint in SignalBpReached. We report |
| 2727 // that we are paused at that breakpoint and then delete it after continuing. |
| 2728 SignalPausedEvent(frame, synthetic_async_breakpoint_); |
| 2729 if (synthetic_async_breakpoint_ != NULL) { |
| 2730 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
| 2731 synthetic_async_breakpoint_ = NULL; |
| 2732 } |
2695 HandleSteppingRequest(stack_trace_); | 2733 HandleSteppingRequest(stack_trace_); |
2696 stack_trace_ = NULL; | 2734 stack_trace_ = NULL; |
2697 | 2735 |
2698 // If any error occurred while in the debug message loop, return it here. | 2736 // If any error occurred while in the debug message loop, return it here. |
2699 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 2737 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
2700 Thread::Current()->clear_sticky_error(); | 2738 Thread::Current()->clear_sticky_error(); |
2701 return error.raw(); | 2739 return error.raw(); |
2702 } | 2740 } |
2703 | 2741 |
2704 | 2742 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2757 } | 2795 } |
2758 bpt = bpt->next(); | 2796 bpt = bpt->next(); |
2759 } | 2797 } |
2760 } | 2798 } |
2761 } | 2799 } |
2762 | 2800 |
2763 if (bpt_hit == NULL) { | 2801 if (bpt_hit == NULL) { |
2764 return Error::null(); | 2802 return Error::null(); |
2765 } | 2803 } |
2766 | 2804 |
| 2805 if (bpt_hit->is_synthetic_async()) { |
| 2806 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 2807 ASSERT(stack_trace->Length() > 0); |
| 2808 ASSERT(stack_trace_ == NULL); |
| 2809 stack_trace_ = stack_trace; |
| 2810 |
| 2811 // Hit a synthetic async breakpoint. |
| 2812 if (FLAG_verbose_debug) { |
| 2813 OS::Print(">>> hit synthetic breakpoint at %s:%" Pd " " |
| 2814 "(token %s) (address %#" Px ")\n", |
| 2815 String::Handle(cbpt->SourceUrl()).ToCString(), |
| 2816 cbpt->LineNumber(), |
| 2817 cbpt->token_pos().ToCString(), |
| 2818 top_frame->pc()); |
| 2819 } |
| 2820 |
| 2821 ASSERT(synthetic_async_breakpoint_ == NULL); |
| 2822 synthetic_async_breakpoint_ = bpt_hit; |
| 2823 bpt_hit = NULL; |
| 2824 |
| 2825 // We are at the entry of an async function. |
| 2826 // We issue a step over to resume at the point after the await statement. |
| 2827 SetStepOver(); |
| 2828 // When we single step from a user breakpoint, our next stepping |
| 2829 // point will be at the exact same pc. Skip it. |
| 2830 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 2831 stack_trace_ = NULL; |
| 2832 return Error::null(); |
| 2833 } |
| 2834 |
2767 if (FLAG_verbose_debug) { | 2835 if (FLAG_verbose_debug) { |
2768 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " | 2836 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
2769 "(token %s) (address %#" Px ")\n", | 2837 "(token %s) (address %#" Px ")\n", |
2770 cbpt->IsInternal() ? "internal" : "user", | 2838 cbpt->IsInternal() ? "internal" : "user", |
2771 String::Handle(cbpt->SourceUrl()).ToCString(), | 2839 String::Handle(cbpt->SourceUrl()).ToCString(), |
2772 cbpt->LineNumber(), | 2840 cbpt->LineNumber(), |
2773 cbpt->token_pos().ToCString(), | 2841 cbpt->token_pos().ToCString(), |
2774 top_frame->pc()); | 2842 top_frame->pc()); |
2775 } | 2843 } |
2776 | 2844 |
(...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3274 | 3342 |
3275 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3343 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
3276 ASSERT(bpt->next() == NULL); | 3344 ASSERT(bpt->next() == NULL); |
3277 bpt->set_next(code_breakpoints_); | 3345 bpt->set_next(code_breakpoints_); |
3278 code_breakpoints_ = bpt; | 3346 code_breakpoints_ = bpt; |
3279 } | 3347 } |
3280 | 3348 |
3281 #endif // !PRODUCT | 3349 #endif // !PRODUCT |
3282 | 3350 |
3283 } // namespace dart | 3351 } // namespace dart |
OLD | NEW |