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