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 "platform/address_sanitizer.h" | 9 #include "platform/address_sanitizer.h" |
10 | 10 |
11 #include "vm/code_generator.h" | 11 #include "vm/code_generator.h" |
12 #include "vm/code_patcher.h" | 12 #include "vm/code_patcher.h" |
13 #include "vm/compiler.h" | 13 #include "vm/compiler.h" |
14 #include "vm/dart_entry.h" | 14 #include "vm/dart_entry.h" |
15 #include "vm/deopt_instructions.h" | 15 #include "vm/deopt_instructions.h" |
16 #include "vm/flags.h" | 16 #include "vm/flags.h" |
17 #include "vm/globals.h" | 17 #include "vm/globals.h" |
18 #include "vm/longjump.h" | 18 #include "vm/longjump.h" |
19 #include "vm/json_stream.h" | 19 #include "vm/json_stream.h" |
20 #include "vm/message_handler.h" | 20 #include "vm/message_handler.h" |
21 #include "vm/object.h" | 21 #include "vm/object.h" |
22 #include "vm/object_store.h" | 22 #include "vm/object_store.h" |
23 #include "vm/os.h" | 23 #include "vm/os.h" |
24 #include "vm/port.h" | 24 #include "vm/port.h" |
25 #include "vm/service_event.h" | 25 #include "vm/service_event.h" |
26 #include "vm/service_isolate.h" | 26 #include "vm/service_isolate.h" |
27 #include "vm/service.h" | 27 #include "vm/service.h" |
28 #include "vm/stack_frame.h" | 28 #include "vm/stack_frame.h" |
| 29 #include "vm/stack_trace.h" |
29 #include "vm/stub_code.h" | 30 #include "vm/stub_code.h" |
30 #include "vm/symbols.h" | 31 #include "vm/symbols.h" |
31 #include "vm/thread_interrupter.h" | 32 #include "vm/thread_interrupter.h" |
32 #include "vm/timeline.h" | 33 #include "vm/timeline.h" |
33 #include "vm/token_position.h" | 34 #include "vm/token_position.h" |
34 #include "vm/visitor.h" | 35 #include "vm/visitor.h" |
35 | 36 |
36 | 37 |
37 namespace dart { | 38 namespace dart { |
38 | 39 |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 | 238 |
238 | 239 |
239 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 240 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
240 visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); | 241 visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); |
241 #if !defined(TARGET_ARCH_DBC) | 242 #if !defined(TARGET_ARCH_DBC) |
242 visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_)); | 243 visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_)); |
243 #endif | 244 #endif |
244 } | 245 } |
245 | 246 |
246 | 247 |
247 ActivationFrame::ActivationFrame(uword pc, | |
248 uword fp, | |
249 uword sp, | |
250 const Code& code, | |
251 const Array& deopt_frame, | |
252 intptr_t deopt_frame_offset) | |
253 : pc_(pc), | |
254 fp_(fp), | |
255 sp_(sp), | |
256 ctx_(Context::ZoneHandle()), | |
257 code_(Code::ZoneHandle(code.raw())), | |
258 function_(Function::ZoneHandle(code.function())), | |
259 token_pos_initialized_(false), | |
260 token_pos_(TokenPosition::kNoSource), | |
261 try_index_(-1), | |
262 line_number_(-1), | |
263 column_number_(-1), | |
264 context_level_(-1), | |
265 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), | |
266 deopt_frame_offset_(deopt_frame_offset), | |
267 vars_initialized_(false), | |
268 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | |
269 desc_indices_(8), | |
270 pc_desc_(PcDescriptors::ZoneHandle()) {} | |
271 | |
272 | |
273 bool Debugger::NeedsIsolateEvents() { | 248 bool Debugger::NeedsIsolateEvents() { |
274 return ((isolate_ != Dart::vm_isolate()) && | 249 return ((isolate_ != Dart::vm_isolate()) && |
275 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && | 250 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && |
276 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); | 251 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); |
277 } | 252 } |
278 | 253 |
279 | 254 |
280 bool Debugger::NeedsDebugEvents() { | 255 bool Debugger::NeedsDebugEvents() { |
281 ASSERT(isolate_ != Dart::vm_isolate() && | 256 ASSERT(isolate_ != Dart::vm_isolate() && |
282 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); | 257 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); |
(...skipping 28 matching lines...) Expand all Loading... |
311 if (ignore_breakpoints_ || IsPaused()) { | 286 if (ignore_breakpoints_ || IsPaused()) { |
312 // We don't let the isolate get interrupted if we are already | 287 // We don't let the isolate get interrupted if we are already |
313 // paused or ignoring breakpoints. | 288 // paused or ignoring breakpoints. |
314 return Error::null(); | 289 return Error::null(); |
315 } | 290 } |
316 ServiceEvent event(isolate_, kind); | 291 ServiceEvent event(isolate_, kind); |
317 DebuggerStackTrace* trace = CollectStackTrace(); | 292 DebuggerStackTrace* trace = CollectStackTrace(); |
318 if (trace->Length() > 0) { | 293 if (trace->Length() > 0) { |
319 event.set_top_frame(trace->FrameAt(0)); | 294 event.set_top_frame(trace->FrameAt(0)); |
320 } | 295 } |
321 ASSERT(stack_trace_ == NULL); | 296 CacheStackTraces(trace, CollectAsyncStackTrace(), |
322 stack_trace_ = trace; | 297 CollectAsyncReturnCallStack()); |
323 resume_action_ = kContinue; | 298 resume_action_ = kContinue; |
324 Pause(&event); | 299 Pause(&event); |
325 HandleSteppingRequest(trace); | 300 HandleSteppingRequest(trace); |
326 stack_trace_ = NULL; | 301 ClearCachedStackTraces(); |
327 | 302 |
328 // If any error occurred while in the debug message loop, return it here. | 303 // If any error occurred while in the debug message loop, return it here. |
329 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 304 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
330 ASSERT(error.IsNull() || error.IsUnwindError()); | 305 ASSERT(error.IsNull() || error.IsUnwindError()); |
331 Thread::Current()->clear_sticky_error(); | 306 Thread::Current()->clear_sticky_error(); |
332 return error.raw(); | 307 return error.raw(); |
333 } | 308 } |
334 | 309 |
335 | 310 |
336 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, | 311 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 break; | 471 break; |
497 case kPauseOnUnhandledExceptions: | 472 case kPauseOnUnhandledExceptions: |
498 jsobj->AddProperty("_exceptions", "unhandled"); | 473 jsobj->AddProperty("_exceptions", "unhandled"); |
499 break; | 474 break; |
500 default: | 475 default: |
501 UNREACHABLE(); | 476 UNREACHABLE(); |
502 } | 477 } |
503 } | 478 } |
504 | 479 |
505 | 480 |
| 481 ActivationFrame::ActivationFrame(uword pc, |
| 482 uword fp, |
| 483 uword sp, |
| 484 const Code& code, |
| 485 const Array& deopt_frame, |
| 486 intptr_t deopt_frame_offset, |
| 487 ActivationFrame::Kind kind) |
| 488 : pc_(pc), |
| 489 fp_(fp), |
| 490 sp_(sp), |
| 491 ctx_(Context::ZoneHandle()), |
| 492 code_(Code::ZoneHandle(code.raw())), |
| 493 function_(Function::ZoneHandle(code.function())), |
| 494 suspended_frame_(false), |
| 495 token_pos_initialized_(false), |
| 496 token_pos_(TokenPosition::kNoSource), |
| 497 try_index_(-1), |
| 498 line_number_(-1), |
| 499 column_number_(-1), |
| 500 context_level_(-1), |
| 501 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), |
| 502 deopt_frame_offset_(deopt_frame_offset), |
| 503 kind_(kind), |
| 504 vars_initialized_(false), |
| 505 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 506 desc_indices_(8), |
| 507 pc_desc_(PcDescriptors::ZoneHandle()) {} |
| 508 |
| 509 |
| 510 ActivationFrame::ActivationFrame(Kind kind) |
| 511 : pc_(0), |
| 512 fp_(0), |
| 513 sp_(0), |
| 514 ctx_(Context::ZoneHandle()), |
| 515 code_(Code::ZoneHandle()), |
| 516 function_(Function::ZoneHandle()), |
| 517 suspended_frame_(true), |
| 518 token_pos_initialized_(false), |
| 519 token_pos_(TokenPosition::kNoSource), |
| 520 try_index_(-1), |
| 521 line_number_(-1), |
| 522 column_number_(-1), |
| 523 context_level_(-1), |
| 524 deopt_frame_(Array::ZoneHandle()), |
| 525 deopt_frame_offset_(0), |
| 526 kind_(kind), |
| 527 vars_initialized_(false), |
| 528 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 529 desc_indices_(8), |
| 530 pc_desc_(PcDescriptors::ZoneHandle()) {} |
| 531 |
| 532 |
| 533 ActivationFrame::ActivationFrame(const Closure& async_activation) |
| 534 : pc_(0), |
| 535 fp_(0), |
| 536 sp_(0), |
| 537 ctx_(Context::ZoneHandle()), |
| 538 code_(Code::ZoneHandle()), |
| 539 function_(Function::ZoneHandle()), |
| 540 suspended_frame_(true), |
| 541 token_pos_initialized_(false), |
| 542 token_pos_(TokenPosition::kNoSource), |
| 543 try_index_(-1), |
| 544 line_number_(-1), |
| 545 column_number_(-1), |
| 546 context_level_(-1), |
| 547 deopt_frame_(Array::ZoneHandle()), |
| 548 deopt_frame_offset_(0), |
| 549 kind_(kAsyncLive), |
| 550 vars_initialized_(false), |
| 551 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 552 desc_indices_(8), |
| 553 pc_desc_(PcDescriptors::ZoneHandle()) { |
| 554 // Extract the function and the code from the asynchronous activation. |
| 555 function_ = async_activation.function(); |
| 556 code_ = function_.unoptimized_code(); |
| 557 ctx_ = async_activation.context(); |
| 558 } |
| 559 |
| 560 |
506 RawString* ActivationFrame::QualifiedFunctionName() { | 561 RawString* ActivationFrame::QualifiedFunctionName() { |
507 return String::New(Debugger::QualifiedFunctionName(function())); | 562 return String::New(Debugger::QualifiedFunctionName(function())); |
508 } | 563 } |
509 | 564 |
510 | 565 |
511 RawString* ActivationFrame::SourceUrl() { | 566 RawString* ActivationFrame::SourceUrl() { |
512 const Script& script = Script::Handle(SourceScript()); | 567 const Script& script = Script::Handle(SourceScript()); |
513 return script.url(); | 568 return script.url(); |
514 } | 569 } |
515 | 570 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 // Calculate the context level at the current token index of the frame. | 670 // Calculate the context level at the current token index of the frame. |
616 intptr_t ActivationFrame::ContextLevel() { | 671 intptr_t ActivationFrame::ContextLevel() { |
617 const Context& ctx = GetSavedCurrentContext(); | 672 const Context& ctx = GetSavedCurrentContext(); |
618 if (context_level_ < 0 && !ctx.IsNull()) { | 673 if (context_level_ < 0 && !ctx.IsNull()) { |
619 ASSERT(!code_.is_optimized()); | 674 ASSERT(!code_.is_optimized()); |
620 context_level_ = 0; | 675 context_level_ = 0; |
621 // TODO(hausner): What to do if there is no descriptor entry | 676 // TODO(hausner): What to do if there is no descriptor entry |
622 // for the code position of the frame? For now say we are at context | 677 // for the code position of the frame? For now say we are at context |
623 // level 0. | 678 // level 0. |
624 TokenPos(); | 679 TokenPos(); |
625 if (token_pos_ == TokenPosition::kNoSource) { | 680 if (token_pos_.IsClassifying() || token_pos_.IsNoSource()) { |
626 // No PcDescriptor. | 681 // No PcDescriptor. |
627 return context_level_; | 682 return context_level_; |
628 } | 683 } |
629 ASSERT(!pc_desc_.IsNull()); | 684 ASSERT(!pc_desc_.IsNull()); |
630 TokenPosition innermost_begin_pos = TokenPosition::kMinSource; | 685 TokenPosition innermost_begin_pos = TokenPosition::kMinSource; |
631 TokenPosition activation_token_pos = TokenPos(); | 686 TokenPosition activation_token_pos = TokenPos().FromSynthetic(); |
632 ASSERT(activation_token_pos.IsReal()); | 687 ASSERT(activation_token_pos.IsReal()); |
633 GetVarDescriptors(); | 688 GetVarDescriptors(); |
634 intptr_t var_desc_len = var_descriptors_.Length(); | 689 intptr_t var_desc_len = var_descriptors_.Length(); |
635 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { | 690 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { |
636 RawLocalVarDescriptors::VarInfo var_info; | 691 RawLocalVarDescriptors::VarInfo var_info; |
637 var_descriptors_.GetInfo(cur_idx, &var_info); | 692 var_descriptors_.GetInfo(cur_idx, &var_info); |
638 const int8_t kind = var_info.kind(); | 693 const int8_t kind = var_info.kind(); |
639 if ((kind == RawLocalVarDescriptors::kContextLevel) && | 694 if ((kind == RawLocalVarDescriptors::kContextLevel) && |
640 (var_info.begin_pos <= activation_token_pos) && | 695 (var_info.begin_pos <= activation_token_pos) && |
641 (activation_token_pos < var_info.end_pos)) { | 696 (activation_token_pos < var_info.end_pos)) { |
(...skipping 27 matching lines...) Expand all Loading... |
669 var_info.index()); | 724 var_info.index()); |
670 } | 725 } |
671 ctx_ ^= GetStackVar(var_info.index()); | 726 ctx_ ^= GetStackVar(var_info.index()); |
672 return ctx_; | 727 return ctx_; |
673 } | 728 } |
674 } | 729 } |
675 return Context::ZoneHandle(Context::null()); | 730 return Context::ZoneHandle(Context::null()); |
676 } | 731 } |
677 | 732 |
678 | 733 |
| 734 RawObject* ActivationFrame::GetAsyncCompleter() { |
| 735 if (!function_.IsAsyncClosure()) { |
| 736 return Object::null(); |
| 737 } |
| 738 GetVarDescriptors(); |
| 739 intptr_t var_desc_len = var_descriptors_.Length(); |
| 740 if (fp() == 0) { |
| 741 // Not actually on the stack. Pull it out of the closure's context. |
| 742 intptr_t var_desc_len = var_descriptors_.Length(); |
| 743 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 744 RawLocalVarDescriptors::VarInfo var_info; |
| 745 var_descriptors_.GetInfo(i, &var_info); |
| 746 const int8_t kind = var_info.kind(); |
| 747 if (var_descriptors_.GetName(i) == Symbols::AsyncCompleter().raw()) { |
| 748 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 749 ASSERT(!ctx_.IsNull()); |
| 750 return ctx_.At(var_info.index()); |
| 751 } |
| 752 } |
| 753 } else { |
| 754 // On the stack. |
| 755 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 756 RawLocalVarDescriptors::VarInfo var_info; |
| 757 var_descriptors_.GetInfo(i, &var_info); |
| 758 if (var_descriptors_.GetName(i) == Symbols::AsyncCompleter().raw()) { |
| 759 const int8_t kind = var_info.kind(); |
| 760 if (kind == RawLocalVarDescriptors::kStackVar) { |
| 761 return GetStackVar(var_info.index()); |
| 762 } else { |
| 763 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 764 return GetContextVar(var_info.scope_id, var_info.index()); |
| 765 } |
| 766 } |
| 767 } |
| 768 } |
| 769 return Object::null(); |
| 770 } |
| 771 |
| 772 |
| 773 RawObject* ActivationFrame::GetAsyncCompleterAwaiter(const Object& completer) { |
| 774 const Class& sync_completer_cls = Class::Handle(completer.clazz()); |
| 775 ASSERT(!sync_completer_cls.IsNull()); |
| 776 const Class& completer_cls = Class::Handle(sync_completer_cls.SuperClass()); |
| 777 const Field& future_field = |
| 778 Field::Handle(completer_cls.LookupInstanceFieldAllowPrivate( |
| 779 Symbols::CompleterFuture())); |
| 780 ASSERT(!future_field.IsNull()); |
| 781 Instance& future = Instance::Handle(); |
| 782 future ^= Instance::Cast(completer).GetField(future_field); |
| 783 ASSERT(!future.IsNull()); |
| 784 const Class& future_cls = Class::Handle(future.clazz()); |
| 785 ASSERT(!future_cls.IsNull()); |
| 786 const Field& awaiter_field = Field::Handle( |
| 787 future_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter())); |
| 788 ASSERT(!awaiter_field.IsNull()); |
| 789 return future.GetField(awaiter_field); |
| 790 } |
| 791 |
| 792 |
| 793 RawObject* ActivationFrame::GetAsyncStreamControllerStream() { |
| 794 if (!function_.IsAsyncGenClosure()) { |
| 795 return Object::null(); |
| 796 } |
| 797 GetVarDescriptors(); |
| 798 intptr_t var_desc_len = var_descriptors_.Length(); |
| 799 if (fp() == 0) { |
| 800 // Not actually on the stack. Pull it out of the closure's context. |
| 801 intptr_t var_desc_len = var_descriptors_.Length(); |
| 802 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 803 RawLocalVarDescriptors::VarInfo var_info; |
| 804 var_descriptors_.GetInfo(i, &var_info); |
| 805 const int8_t kind = var_info.kind(); |
| 806 if (var_descriptors_.GetName(i) == Symbols::ControllerStream().raw()) { |
| 807 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 808 ASSERT(!ctx_.IsNull()); |
| 809 return ctx_.At(var_info.index()); |
| 810 } |
| 811 } |
| 812 } else { |
| 813 // On the stack. |
| 814 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 815 RawLocalVarDescriptors::VarInfo var_info; |
| 816 var_descriptors_.GetInfo(i, &var_info); |
| 817 if (var_descriptors_.GetName(i) == Symbols::ControllerStream().raw()) { |
| 818 const int8_t kind = var_info.kind(); |
| 819 if (kind == RawLocalVarDescriptors::kStackVar) { |
| 820 return GetStackVar(var_info.index()); |
| 821 } else { |
| 822 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 823 return GetContextVar(var_info.scope_id, var_info.index()); |
| 824 } |
| 825 } |
| 826 } |
| 827 } |
| 828 return Object::null(); |
| 829 } |
| 830 |
| 831 |
| 832 RawObject* ActivationFrame::GetAsyncStreamControllerStreamAwaiter( |
| 833 const Object& stream) { |
| 834 const Class& stream_cls = Class::Handle(stream.clazz()); |
| 835 ASSERT(!stream_cls.IsNull()); |
| 836 const Class& stream_impl_cls = Class::Handle(stream_cls.SuperClass()); |
| 837 const Field& awaiter_field = Field::Handle( |
| 838 stream_impl_cls.LookupInstanceFieldAllowPrivate(Symbols::_Awaiter())); |
| 839 ASSERT(!awaiter_field.IsNull()); |
| 840 return Instance::Cast(stream).GetField(awaiter_field); |
| 841 } |
| 842 |
| 843 |
| 844 RawObject* ActivationFrame::GetAsyncAwaiter() { |
| 845 const Object& completer = Object::Handle(GetAsyncCompleter()); |
| 846 if (!completer.IsNull()) { |
| 847 return GetAsyncCompleterAwaiter(completer); |
| 848 } |
| 849 const Object& async_stream_controller_stream = |
| 850 Object::Handle(GetAsyncStreamControllerStream()); |
| 851 if (!async_stream_controller_stream.IsNull()) { |
| 852 return GetAsyncStreamControllerStreamAwaiter( |
| 853 async_stream_controller_stream); |
| 854 } |
| 855 return Object::null(); |
| 856 } |
| 857 |
| 858 |
| 859 void ActivationFrame::ExtractTokenPositionFromAsyncClosure() { |
| 860 // Attempt to determine the token position from the async closure. |
| 861 ASSERT(function_.IsAsyncGenClosure() || function_.IsAsyncClosure()); |
| 862 // This should only be called on frames that aren't active on the stack. |
| 863 ASSERT(fp() == 0); |
| 864 const Array& await_to_token_map = |
| 865 Array::Handle(code_.await_token_positions()); |
| 866 if (await_to_token_map.IsNull()) { |
| 867 OS::PrintErr("NO await_token_positions MAPPING\n"); |
| 868 // No mapping. |
| 869 return; |
| 870 } |
| 871 GetVarDescriptors(); |
| 872 GetPcDescriptors(); |
| 873 intptr_t var_desc_len = var_descriptors_.Length(); |
| 874 intptr_t await_jump_var = -1; |
| 875 for (intptr_t i = 0; i < var_desc_len; i++) { |
| 876 RawLocalVarDescriptors::VarInfo var_info; |
| 877 var_descriptors_.GetInfo(i, &var_info); |
| 878 const int8_t kind = var_info.kind(); |
| 879 if (var_descriptors_.GetName(i) == Symbols::AwaitJumpVar().raw()) { |
| 880 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 881 ASSERT(!ctx_.IsNull()); |
| 882 Object& await_jump_index = Object::Handle(ctx_.At(var_info.index())); |
| 883 ASSERT(await_jump_index.IsSmi()); |
| 884 await_jump_var = Smi::Cast(await_jump_index).Value(); |
| 885 OS::PrintErr("Extracted await var: %" Pd "\n", await_jump_var); |
| 886 } |
| 887 } |
| 888 if (await_jump_var < 0) { |
| 889 OS::PrintErr("await_jump_var < 0\n"); |
| 890 return; |
| 891 } |
| 892 ASSERT(await_jump_var < await_to_token_map.Length()); |
| 893 const Object& token_pos = |
| 894 Object::Handle(await_to_token_map.At(await_jump_var)); |
| 895 if (token_pos.IsNull()) { |
| 896 OS::PrintErr("token_pos was null\n"); |
| 897 return; |
| 898 } |
| 899 ASSERT(token_pos.IsSmi()); |
| 900 token_pos_ = TokenPosition(Smi::Cast(token_pos).Value()); |
| 901 token_pos_initialized_ = true; |
| 902 OS::PrintErr("async token position: %s\n", token_pos_.ToCString()); |
| 903 // Now that we have the token position, we clear a bunch of frame state that |
| 904 // will repopulated based on the token position. |
| 905 // Clear the context. |
| 906 #if 0 |
| 907 ctx_ ^= Object::null(); |
| 908 context_level_ = -1; |
| 909 // Clear variable descriptors. |
| 910 vars_initialized_ = false; |
| 911 var_descriptors_ ^= Object::null(); |
| 912 desc_indices_.Clear(); |
| 913 #endif |
| 914 } |
| 915 |
| 916 |
679 RawObject* ActivationFrame::GetAsyncOperation() { | 917 RawObject* ActivationFrame::GetAsyncOperation() { |
680 GetVarDescriptors(); | 918 GetVarDescriptors(); |
681 intptr_t var_desc_len = var_descriptors_.Length(); | 919 intptr_t var_desc_len = var_descriptors_.Length(); |
682 for (intptr_t i = 0; i < var_desc_len; i++) { | 920 for (intptr_t i = 0; i < var_desc_len; i++) { |
683 RawLocalVarDescriptors::VarInfo var_info; | 921 RawLocalVarDescriptors::VarInfo var_info; |
684 var_descriptors_.GetInfo(i, &var_info); | 922 var_descriptors_.GetInfo(i, &var_info); |
685 if (var_descriptors_.GetName(i) == Symbols::AsyncOperation().raw()) { | 923 if (var_descriptors_.GetName(i) == Symbols::AsyncOperation().raw()) { |
686 const int8_t kind = var_info.kind(); | 924 const int8_t kind = var_info.kind(); |
687 if (kind == RawLocalVarDescriptors::kStackVar) { | 925 if (kind == RawLocalVarDescriptors::kStackVar) { |
688 return GetStackVar(var_info.index()); | 926 return GetStackVar(var_info.index()); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 } | 971 } |
734 | 972 |
735 | 973 |
736 void ActivationFrame::GetDescIndices() { | 974 void ActivationFrame::GetDescIndices() { |
737 if (vars_initialized_) { | 975 if (vars_initialized_) { |
738 return; | 976 return; |
739 } | 977 } |
740 GetVarDescriptors(); | 978 GetVarDescriptors(); |
741 | 979 |
742 TokenPosition activation_token_pos = TokenPos(); | 980 TokenPosition activation_token_pos = TokenPos(); |
743 if (!activation_token_pos.IsDebugPause()) { | 981 if (!activation_token_pos.IsDebugPause() || suspended_frame_) { |
744 // We don't have a token position for this frame, so can't determine | 982 // We don't have a token position for this frame, so can't determine |
745 // which variables are visible. | 983 // which variables are visible. |
746 vars_initialized_ = true; | 984 vars_initialized_ = true; |
747 return; | 985 return; |
748 } | 986 } |
749 | 987 |
750 GrowableArray<String*> var_names(8); | 988 GrowableArray<String*> var_names(8); |
751 intptr_t var_desc_len = var_descriptors_.Length(); | 989 intptr_t var_desc_len = var_descriptors_.Length(); |
752 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { | 990 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { |
753 ASSERT(var_names.length() == desc_indices_.length()); | 991 ASSERT(var_names.length() == desc_indices_.length()); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 for (int i = 0; i < deopt_frame_.Length(); i++) { | 1102 for (int i = 0; i < deopt_frame_.Length(); i++) { |
865 obj = deopt_frame_.At(i); | 1103 obj = deopt_frame_.At(i); |
866 if (obj.raw() == Symbols::OptimizedOut().raw()) { | 1104 if (obj.raw() == Symbols::OptimizedOut().raw()) { |
867 return false; | 1105 return false; |
868 } | 1106 } |
869 } | 1107 } |
870 return true; | 1108 return true; |
871 } | 1109 } |
872 | 1110 |
873 | 1111 |
| 1112 bool ActivationFrame::IsCompleteOnAsyncReturn() { |
| 1113 const class Library& async_library = Library::Handle(Library::AsyncLibrary()); |
| 1114 ASSERT(!async_library.IsNull()); |
| 1115 |
| 1116 const Function& complete_on_async_return_function = |
| 1117 Function::Handle(async_library.LookupFunctionAllowPrivate( |
| 1118 Symbols::CompleterCompleteOnAsyncReturn())); |
| 1119 ASSERT(!complete_on_async_return_function.IsNull()); |
| 1120 return complete_on_async_return_function.raw() == function_.raw(); |
| 1121 } |
| 1122 |
| 1123 |
| 1124 bool ActivationFrame::IsInAsyncStarStreamController() { |
| 1125 const class Library& async_library = Library::Handle(Library::AsyncLibrary()); |
| 1126 ASSERT(!async_library.IsNull()); |
| 1127 |
| 1128 const Class& async_stream_controller = |
| 1129 Class::Handle(async_library.LookupClassAllowPrivate( |
| 1130 Symbols::_AsyncStarStreamController())); |
| 1131 ASSERT(!async_stream_controller.IsNull()); |
| 1132 return function_.Owner() == async_stream_controller.raw(); |
| 1133 } |
| 1134 |
| 1135 |
| 1136 bool ActivationFrame::IsInAsyncMachinery() { |
| 1137 return IsCompleteOnAsyncReturn() || IsInAsyncStarStreamController(); |
| 1138 } |
| 1139 |
| 1140 |
874 void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, | 1141 void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, |
875 intptr_t frame_ctx_level, | 1142 intptr_t frame_ctx_level, |
876 intptr_t var_ctx_level) { | 1143 intptr_t var_ctx_level) { |
877 OS::PrintErr( | 1144 OS::PrintErr( |
878 "-------------------------\n" | 1145 "-------------------------\n" |
879 "Encountered context mismatch\n" | 1146 "Encountered context mismatch\n" |
880 "\tctx_slot: %" Pd | 1147 "\tctx_slot: %" Pd |
881 "\n" | 1148 "\n" |
882 "\tframe_ctx_level: %" Pd | 1149 "\tframe_ctx_level: %" Pd |
883 "\n" | 1150 "\n" |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1079 "\tline = %" Pd | 1346 "\tline = %" Pd |
1080 "\n" | 1347 "\n" |
1081 "\tcontext = %s\n" | 1348 "\tcontext = %s\n" |
1082 "\tcontext level = %" Pd " ]\n", | 1349 "\tcontext level = %" Pd " ]\n", |
1083 pc(), fp(), sp(), func_name, url.ToCString(), line, ctx_.ToCString(), | 1350 pc(), fp(), sp(), func_name, url.ToCString(), line, ctx_.ToCString(), |
1084 ContextLevel()); | 1351 ContextLevel()); |
1085 } | 1352 } |
1086 | 1353 |
1087 | 1354 |
1088 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { | 1355 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { |
| 1356 if (kind_ == kRegular) { |
| 1357 PrintToJSONObjectRegular(jsobj, full); |
| 1358 } else { |
| 1359 PrintToJSONObjectAsync(jsobj, full); |
| 1360 } |
| 1361 } |
| 1362 |
| 1363 |
| 1364 void ActivationFrame::PrintToJSONObjectAsync(JSONObject* jsobj, bool full) { |
| 1365 jsobj->AddProperty("type", "AsyncFrame"); |
| 1366 jsobj->AddProperty("kind", KindToCString(kind_)); |
| 1367 if (kind_ == kAsyncSuspensionMarker) { |
| 1368 jsobj->AddProperty("marker", "AsynchronousSuspension"); |
| 1369 } else if (kind_ == kAsyncHistorical) { |
| 1370 PrintToJSONObjectHistoricalFrame(jsobj, full); |
| 1371 } else { |
| 1372 PrintToJSONObjectLiveFrame(jsobj, full); |
| 1373 } |
| 1374 } |
| 1375 |
| 1376 |
| 1377 void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj, bool full) { |
| 1378 jsobj->AddProperty("type", "Frame"); |
| 1379 PrintToJSONObjectLiveFrame(jsobj, full); |
| 1380 } |
| 1381 |
| 1382 |
| 1383 void ActivationFrame::PrintToJSONObjectHistoricalFrame(JSONObject* jsobj, |
| 1384 bool full) { |
1089 const Script& script = Script::Handle(SourceScript()); | 1385 const Script& script = Script::Handle(SourceScript()); |
1090 jsobj->AddProperty("type", "Frame"); | |
1091 TokenPosition pos = TokenPos(); | 1386 TokenPosition pos = TokenPos(); |
1092 if (pos.IsSynthetic()) { | 1387 if (pos.IsSynthetic()) { |
1093 pos = pos.FromSynthetic(); | 1388 pos = pos.FromSynthetic(); |
| 1389 } |
| 1390 jsobj->AddLocation(script, pos); |
| 1391 jsobj->AddProperty("function", function(), !full); |
| 1392 jsobj->AddProperty("code", code()); |
| 1393 if (full) { |
| 1394 // TODO(cutch): The old "full" script usage no longer fits |
| 1395 // in the world where we pass the script as part of the |
| 1396 // location. |
| 1397 jsobj->AddProperty("script", script, !full); |
| 1398 } |
| 1399 } |
| 1400 |
| 1401 |
| 1402 void ActivationFrame::PrintToJSONObjectLiveFrame(JSONObject* jsobj, bool full) { |
| 1403 const Script& script = Script::Handle(SourceScript()); |
| 1404 TokenPosition pos = TokenPos(); |
| 1405 if (pos.IsSynthetic()) { |
| 1406 pos = pos.FromSynthetic(); |
1094 } | 1407 } |
1095 jsobj->AddLocation(script, pos); | 1408 jsobj->AddLocation(script, pos); |
1096 jsobj->AddProperty("function", function(), !full); | 1409 jsobj->AddProperty("function", function(), !full); |
1097 jsobj->AddProperty("code", code()); | 1410 jsobj->AddProperty("code", code()); |
1098 if (full) { | 1411 if (full) { |
1099 // TODO(cutch): The old "full" script usage no longer fits | 1412 // TODO(cutch): The old "full" script usage no longer fits |
1100 // in the world where we pass the script as part of the | 1413 // in the world where we pass the script as part of the |
1101 // location. | 1414 // location. |
1102 jsobj->AddProperty("script", script, !full); | 1415 jsobj->AddProperty("script", script, !full); |
1103 } | 1416 } |
1104 { | 1417 { |
1105 JSONArray jsvars(jsobj, "vars"); | 1418 JSONArray jsvars(jsobj, "vars"); |
1106 const int num_vars = NumLocalVariables(); | 1419 const int num_vars = NumLocalVariables(); |
1107 for (intptr_t v = 0; v < num_vars; v++) { | 1420 for (intptr_t v = 0; v < num_vars; v++) { |
1108 String& var_name = String::Handle(); | 1421 String& var_name = String::Handle(); |
1109 Instance& var_value = Instance::Handle(); | 1422 Instance& var_value = Instance::Handle(); |
1110 TokenPosition declaration_token_pos; | 1423 TokenPosition declaration_token_pos; |
1111 TokenPosition visible_start_token_pos; | 1424 TokenPosition visible_start_token_pos; |
1112 TokenPosition visible_end_token_pos; | 1425 TokenPosition visible_end_token_pos; |
1113 VariableAt(v, &var_name, &declaration_token_pos, &visible_start_token_pos, | 1426 VariableAt(v, &var_name, &declaration_token_pos, &visible_start_token_pos, |
1114 &visible_end_token_pos, &var_value); | 1427 &visible_end_token_pos, &var_value); |
1115 if (var_name.raw() != Symbols::AsyncOperation().raw()) { | 1428 if ((var_name.raw() != Symbols::AsyncOperation().raw()) && |
| 1429 (var_name.raw() != Symbols::AsyncCompleter().raw())) { |
1116 JSONObject jsvar(&jsvars); | 1430 JSONObject jsvar(&jsvars); |
1117 jsvar.AddProperty("type", "BoundVariable"); | 1431 jsvar.AddProperty("type", "BoundVariable"); |
1118 var_name = String::ScrubName(var_name); | 1432 var_name = String::ScrubName(var_name); |
1119 jsvar.AddProperty("name", var_name.ToCString()); | 1433 jsvar.AddProperty("name", var_name.ToCString()); |
1120 jsvar.AddProperty("value", var_value, !full); | 1434 jsvar.AddProperty("value", var_value, !full); |
1121 // Where was the variable declared? | 1435 // Where was the variable declared? |
1122 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); | 1436 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); |
1123 // When the variable becomes visible to the scope. | 1437 // When the variable becomes visible to the scope. |
1124 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); | 1438 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); |
1125 // When the variable stops being visible to the scope. | 1439 // When the variable stops being visible to the scope. |
1126 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); | 1440 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); |
1127 } | 1441 } |
1128 } | 1442 } |
1129 } | 1443 } |
1130 } | 1444 } |
1131 | 1445 |
| 1446 |
1132 static bool IsFunctionVisible(const Function& function) { | 1447 static bool IsFunctionVisible(const Function& function) { |
1133 return FLAG_show_invisible_frames || function.is_visible(); | 1448 return FLAG_show_invisible_frames || function.is_visible(); |
1134 } | 1449 } |
1135 | 1450 |
1136 | 1451 |
1137 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { | 1452 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
1138 if (IsFunctionVisible(frame->function())) { | 1453 if (IsFunctionVisible(frame->function())) { |
1139 trace_.Add(frame); | 1454 trace_.Add(frame); |
1140 } | 1455 } |
1141 } | 1456 } |
1142 | 1457 |
1143 | 1458 |
| 1459 void DebuggerStackTrace::AddMarker(ActivationFrame::Kind marker) { |
| 1460 ASSERT((marker >= ActivationFrame::kAsyncSuspensionMarker) && |
| 1461 (marker <= ActivationFrame::kAsyncSuspensionMarker)); |
| 1462 trace_.Add(new ActivationFrame(marker)); |
| 1463 } |
| 1464 |
| 1465 |
| 1466 void DebuggerStackTrace::AddAsyncHistoricalFrame(uword pc, const Code& code) { |
| 1467 trace_.Add(new ActivationFrame(pc, 0, 0, code, Array::Handle(), 0, |
| 1468 ActivationFrame::kAsyncHistorical)); |
| 1469 } |
| 1470 |
| 1471 |
1144 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | | 1472 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | |
1145 RawPcDescriptors::kUnoptStaticCall | | 1473 RawPcDescriptors::kUnoptStaticCall | |
1146 RawPcDescriptors::kRuntimeCall; | 1474 RawPcDescriptors::kRuntimeCall; |
1147 | 1475 |
1148 | 1476 |
1149 CodeBreakpoint::CodeBreakpoint(const Code& code, | 1477 CodeBreakpoint::CodeBreakpoint(const Code& code, |
1150 TokenPosition token_pos, | 1478 TokenPosition token_pos, |
1151 uword pc, | 1479 uword pc, |
1152 RawPcDescriptors::Kind kind) | 1480 RawPcDescriptors::Kind kind) |
1153 : code_(code.raw()), | 1481 : code_(code.raw()), |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1222 | 1550 |
1223 | 1551 |
1224 void CodeBreakpoint::Disable() { | 1552 void CodeBreakpoint::Disable() { |
1225 if (is_enabled_) { | 1553 if (is_enabled_) { |
1226 RestoreCode(); | 1554 RestoreCode(); |
1227 } | 1555 } |
1228 ASSERT(!is_enabled_); | 1556 ASSERT(!is_enabled_); |
1229 } | 1557 } |
1230 | 1558 |
1231 | 1559 |
| 1560 const char* CodeBreakpoint::ToCString() { |
| 1561 Zone* zone = Thread::Current()->zone(); |
| 1562 ASSERT(zone != NULL); |
| 1563 return OS::SCreate(zone, "%s: %" Pd " (token %s)", |
| 1564 String::Handle(SourceUrl()).ToCString(), LineNumber(), |
| 1565 token_pos().ToCString()); |
| 1566 } |
| 1567 |
| 1568 |
1232 RemoteObjectCache::RemoteObjectCache(intptr_t initial_size) { | 1569 RemoteObjectCache::RemoteObjectCache(intptr_t initial_size) { |
1233 objs_ = | 1570 objs_ = |
1234 &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New(initial_size)); | 1571 &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New(initial_size)); |
1235 } | 1572 } |
1236 | 1573 |
1237 | 1574 |
1238 intptr_t RemoteObjectCache::AddObject(const Object& obj) { | 1575 intptr_t RemoteObjectCache::AddObject(const Object& obj) { |
1239 intptr_t len = objs_->Length(); | 1576 intptr_t len = objs_->Length(); |
1240 for (intptr_t i = 0; i < len; i++) { | 1577 for (intptr_t i = 0; i < len; i++) { |
1241 if (objs_->At(i) == obj.raw()) { | 1578 if (objs_->At(i) == obj.raw()) { |
(...skipping 19 matching lines...) Expand all Loading... |
1261 latent_locations_(NULL), | 1598 latent_locations_(NULL), |
1262 breakpoint_locations_(NULL), | 1599 breakpoint_locations_(NULL), |
1263 code_breakpoints_(NULL), | 1600 code_breakpoints_(NULL), |
1264 resume_action_(kContinue), | 1601 resume_action_(kContinue), |
1265 resume_frame_index_(-1), | 1602 resume_frame_index_(-1), |
1266 post_deopt_frame_index_(-1), | 1603 post_deopt_frame_index_(-1), |
1267 ignore_breakpoints_(false), | 1604 ignore_breakpoints_(false), |
1268 pause_event_(NULL), | 1605 pause_event_(NULL), |
1269 obj_cache_(NULL), | 1606 obj_cache_(NULL), |
1270 stack_trace_(NULL), | 1607 stack_trace_(NULL), |
| 1608 async_stack_trace_(NULL), |
| 1609 async_return_call_stack_(NULL), |
1271 stepping_fp_(0), | 1610 stepping_fp_(0), |
| 1611 top_frame_awaiter_(Object::null()), |
| 1612 async_stepping_fp_(0), |
1272 skip_next_step_(false), | 1613 skip_next_step_(false), |
1273 synthetic_async_breakpoint_(NULL), | 1614 synthetic_async_breakpoint_(NULL), |
1274 exc_pause_info_(kNoPauseOnExceptions) {} | 1615 exc_pause_info_(kNoPauseOnExceptions) {} |
1275 | 1616 |
1276 | 1617 |
1277 Debugger::~Debugger() { | 1618 Debugger::~Debugger() { |
1278 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1619 isolate_id_ = ILLEGAL_ISOLATE_ID; |
1279 ASSERT(!IsPaused()); | 1620 ASSERT(!IsPaused()); |
1280 ASSERT(latent_locations_ == NULL); | 1621 ASSERT(latent_locations_ == NULL); |
1281 ASSERT(breakpoint_locations_ == NULL); | 1622 ASSERT(breakpoint_locations_ == NULL); |
1282 ASSERT(code_breakpoints_ == NULL); | 1623 ASSERT(code_breakpoints_ == NULL); |
1283 ASSERT(stack_trace_ == NULL); | 1624 ASSERT(stack_trace_ == NULL); |
| 1625 ASSERT(async_stack_trace_ == NULL); |
1284 ASSERT(obj_cache_ == NULL); | 1626 ASSERT(obj_cache_ == NULL); |
1285 ASSERT(synthetic_async_breakpoint_ == NULL); | 1627 ASSERT(synthetic_async_breakpoint_ == NULL); |
1286 } | 1628 } |
1287 | 1629 |
1288 | 1630 |
1289 void Debugger::Shutdown() { | 1631 void Debugger::Shutdown() { |
1290 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need | 1632 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need |
1291 // them. Then, assert here that isolate_ is not one of those isolates. | 1633 // them. Then, assert here that isolate_ is not one of those isolates. |
1292 if ((isolate_ == Dart::vm_isolate()) || | 1634 if ((isolate_ == Dart::vm_isolate()) || |
1293 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 1635 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { |
(...skipping 26 matching lines...) Expand all Loading... |
1320 const String& fname) { | 1662 const String& fname) { |
1321 ASSERT(!library.IsNull()); | 1663 ASSERT(!library.IsNull()); |
1322 const Object& object = Object::Handle(library.ResolveName(fname)); | 1664 const Object& object = Object::Handle(library.ResolveName(fname)); |
1323 if (!object.IsNull() && object.IsFunction()) { | 1665 if (!object.IsNull() && object.IsFunction()) { |
1324 return Function::Cast(object).raw(); | 1666 return Function::Cast(object).raw(); |
1325 } | 1667 } |
1326 return Function::null(); | 1668 return Function::null(); |
1327 } | 1669 } |
1328 | 1670 |
1329 | 1671 |
| 1672 bool Debugger::SteppedForSyntheticAsyncBreakpoint() const { |
| 1673 return synthetic_async_breakpoint_ != NULL; |
| 1674 } |
| 1675 |
| 1676 |
| 1677 RawError* Debugger::StepForSyntheticAsyncBreakpoint(Breakpoint* bpt) { |
| 1678 ASSERT(bpt->is_synthetic_async()); |
| 1679 |
| 1680 TD_Print("ASYNC: Auto step-over\n"); |
| 1681 CacheStackTraces(CollectStackTrace(), CollectAsyncStackTrace(), |
| 1682 CollectAsyncReturnCallStack()); |
| 1683 |
| 1684 ASSERT(synthetic_async_breakpoint_ == NULL); |
| 1685 synthetic_async_breakpoint_ = bpt; |
| 1686 // We are at the entry of an async closure. |
| 1687 // We issue a step over to resume at the point after the await statement. |
| 1688 SetResumeAction(kStepOver); |
| 1689 // When we single step from a breakpoint, our next stepping point will be at |
| 1690 // the exact same pc. Skip it. |
| 1691 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 1692 ClearCachedStackTraces(); |
| 1693 return Error::null(); |
| 1694 } |
| 1695 |
| 1696 |
| 1697 void Debugger::CleanupSyntheticAsyncBreakpoint() { |
| 1698 if (synthetic_async_breakpoint_ != NULL) { |
| 1699 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
| 1700 synthetic_async_breakpoint_ = NULL; |
| 1701 } |
| 1702 } |
| 1703 |
1330 bool Debugger::SetupStepOverAsyncSuspension(const char** error) { | 1704 bool Debugger::SetupStepOverAsyncSuspension(const char** error) { |
1331 ActivationFrame* top_frame = TopDartFrame(); | 1705 ActivationFrame* top_frame = TopDartFrame(); |
1332 if (!IsAtAsyncJump(top_frame)) { | 1706 if (!IsAtAsyncJump(top_frame)) { |
1333 // Not at an async operation. | 1707 // Not at an async operation. |
1334 if (error) { | 1708 if (error) { |
1335 *error = "Isolate must be paused at an async suspension point"; | 1709 *error = "Isolate must be paused at an async suspension point"; |
1336 } | 1710 } |
1337 return false; | 1711 return false; |
1338 } | 1712 } |
1339 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); | 1713 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); |
1340 ASSERT(!closure.IsNull()); | 1714 ASSERT(!closure.IsNull()); |
1341 ASSERT(closure.IsInstance()); | 1715 ASSERT(closure.IsInstance()); |
1342 ASSERT(Instance::Cast(closure).IsClosure()); | 1716 ASSERT(Instance::Cast(closure).IsClosure()); |
1343 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); | 1717 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); |
1344 if (bpt == NULL) { | 1718 if (bpt == NULL) { |
1345 // Unable to set the breakpoint. | 1719 // Unable to set the breakpoint. |
1346 if (error) { | 1720 if (error) { |
1347 *error = "Unable to set breakpoint at async suspension point"; | 1721 *error = "Unable to set breakpoint at async suspension point"; |
1348 } | 1722 } |
1349 return false; | 1723 return false; |
1350 } | 1724 } |
1351 return true; | 1725 return true; |
1352 } | 1726 } |
1353 | 1727 |
1354 | 1728 |
| 1729 // Returns the stepping frame pointer when stepping into a caller of |
| 1730 // the async activation generator functions. |
| 1731 uword Debugger::GetAsyncActivationGeneratorSteppingFramePointer() { |
| 1732 StackFrameIterator iterator(false); |
| 1733 // Scan until we hit the top Dart frame. |
| 1734 StackFrame* frame = iterator.NextFrame(); |
| 1735 while ((frame != NULL) && !frame->IsDartFrame()) { |
| 1736 frame = iterator.NextFrame(); |
| 1737 } |
| 1738 if (frame != NULL) { |
| 1739 frame = iterator.NextFrame(); |
| 1740 if ((frame != NULL) && frame->IsDartFrame()) { |
| 1741 // Check to see if we are in a callee of the async function. |
| 1742 const Function& function = Function::Handle(frame->LookupDartFunction()); |
| 1743 if (function.IsAsyncFunction() || function.IsAsyncGenerator()) { |
| 1744 // We are, continue until this function has exited. |
| 1745 return frame->fp(); |
| 1746 } |
| 1747 } |
| 1748 } |
| 1749 return 0; |
| 1750 } |
| 1751 |
| 1752 |
1355 bool Debugger::SetResumeAction(ResumeAction action, | 1753 bool Debugger::SetResumeAction(ResumeAction action, |
1356 intptr_t frame_index, | 1754 intptr_t frame_index, |
1357 const char** error) { | 1755 const char** error) { |
1358 if (error) { | 1756 if (error) { |
1359 *error = NULL; | 1757 *error = NULL; |
1360 } | 1758 } |
1361 resume_frame_index_ = -1; | 1759 resume_frame_index_ = -1; |
1362 switch (action) { | 1760 switch (action) { |
1363 case kStepInto: | 1761 case kStepInto: |
1364 case kStepOver: | 1762 case kStepOver: |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1455 } | 1853 } |
1456 } | 1854 } |
1457 } | 1855 } |
1458 | 1856 |
1459 | 1857 |
1460 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1858 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
1461 uword pc, | 1859 uword pc, |
1462 StackFrame* frame, | 1860 StackFrame* frame, |
1463 const Code& code, | 1861 const Code& code, |
1464 const Array& deopt_frame, | 1862 const Array& deopt_frame, |
1465 intptr_t deopt_frame_offset) { | 1863 intptr_t deopt_frame_offset, |
| 1864 ActivationFrame::Kind kind) { |
1466 ASSERT(code.ContainsInstructionAt(pc)); | 1865 ASSERT(code.ContainsInstructionAt(pc)); |
1467 ActivationFrame* activation = new ActivationFrame( | 1866 ActivationFrame* activation = |
1468 pc, frame->fp(), frame->sp(), code, deopt_frame, deopt_frame_offset); | 1867 new ActivationFrame(pc, frame->fp(), frame->sp(), code, deopt_frame, |
| 1868 deopt_frame_offset, kind); |
1469 if (FLAG_trace_debugger_stacktrace) { | 1869 if (FLAG_trace_debugger_stacktrace) { |
1470 const Context& ctx = activation->GetSavedCurrentContext(); | 1870 const Context& ctx = activation->GetSavedCurrentContext(); |
1471 OS::PrintErr("\tUsing saved context: %s\n", ctx.ToCString()); | 1871 OS::PrintErr("\tUsing saved context: %s\n", ctx.ToCString()); |
1472 } | 1872 } |
1473 if (FLAG_trace_debugger_stacktrace) { | 1873 if (FLAG_trace_debugger_stacktrace) { |
1474 OS::PrintErr("\tLine number: %" Pd "\n", activation->LineNumber()); | 1874 OS::PrintErr("\tLine number: %" Pd "\n", activation->LineNumber()); |
1475 } | 1875 } |
1476 return activation; | 1876 return activation; |
1477 } | 1877 } |
1478 | 1878 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1539 } else { | 1939 } else { |
1540 stack_trace->AddActivation(CollectDartFrame( | 1940 stack_trace->AddActivation(CollectDartFrame( |
1541 isolate, frame->pc(), frame, code, Object::null_array(), 0)); | 1941 isolate, frame->pc(), frame, code, Object::null_array(), 0)); |
1542 } | 1942 } |
1543 } | 1943 } |
1544 } | 1944 } |
1545 return stack_trace; | 1945 return stack_trace; |
1546 } | 1946 } |
1547 | 1947 |
1548 | 1948 |
| 1949 DebuggerStackTrace* Debugger::CollectAsyncStackTrace() { |
| 1950 if (!FLAG_sane_async_stacks) { |
| 1951 return CollectStackTrace(); |
| 1952 } |
| 1953 Thread* thread = Thread::Current(); |
| 1954 Zone* zone = thread->zone(); |
| 1955 Isolate* isolate = thread->isolate(); |
| 1956 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 1957 StackFrameIterator iterator(false); |
| 1958 Code& code = Code::Handle(zone); |
| 1959 Smi& offset = Smi::Handle(); |
| 1960 Function& function = Function::Handle(zone); |
| 1961 Code& inlined_code = Code::Handle(zone); |
| 1962 Array& deopt_frame = Array::Handle(zone); |
| 1963 |
| 1964 Function& async_function = Function::Handle(zone); |
| 1965 Array& async_code_array = Array::Handle(zone); |
| 1966 Array& async_pc_offset_array = Array::Handle(zone); |
| 1967 const intptr_t async_stack_trace_length = |
| 1968 StackTraceUtils::ExtractAsyncStackTraceInfo( |
| 1969 thread, &async_function, &async_code_array, &async_pc_offset_array); |
| 1970 |
| 1971 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
| 1972 frame = iterator.NextFrame()) { |
| 1973 ASSERT(frame->IsValid()); |
| 1974 if (FLAG_trace_debugger_stacktrace) { |
| 1975 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", |
| 1976 frame->ToCString()); |
| 1977 } |
| 1978 if (frame->IsDartFrame()) { |
| 1979 code = frame->LookupDartCode(); |
| 1980 if (code.is_optimized() && !FLAG_precompiled_runtime) { |
| 1981 deopt_frame = DeoptimizeToArray(thread, frame, code); |
| 1982 for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); |
| 1983 it.Advance()) { |
| 1984 inlined_code = it.code(); |
| 1985 if (FLAG_trace_debugger_stacktrace) { |
| 1986 const Function& function = |
| 1987 Function::Handle(zone, inlined_code.function()); |
| 1988 ASSERT(!function.IsNull()); |
| 1989 OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n", |
| 1990 function.ToFullyQualifiedCString()); |
| 1991 } |
| 1992 intptr_t deopt_frame_offset = it.GetDeoptFpOffset(); |
| 1993 ActivationFrame* activation_frame = CollectDartFrame( |
| 1994 isolate, it.pc(), frame, inlined_code, deopt_frame, |
| 1995 deopt_frame_offset, ActivationFrame::kAsyncLive); |
| 1996 stack_trace->AddActivation(activation_frame); |
| 1997 } |
| 1998 } else { |
| 1999 ActivationFrame* activation_frame = CollectDartFrame( |
| 2000 isolate, frame->pc(), frame, code, Object::null_array(), 0, |
| 2001 ActivationFrame::kAsyncLive); |
| 2002 stack_trace->AddActivation(activation_frame); |
| 2003 if (async_stack_trace_length > 0) { |
| 2004 // Stop once we hit async closure. |
| 2005 function = code.function(); |
| 2006 if (function.parent_function() == async_function.raw()) { |
| 2007 break; |
| 2008 } |
| 2009 } |
| 2010 } |
| 2011 } |
| 2012 } |
| 2013 ASSERT((async_stack_trace_length == 0) || |
| 2014 (function.parent_function() == async_function.raw())); |
| 2015 // Append the asynchronous stack trace. |
| 2016 for (intptr_t i = 0; i < async_stack_trace_length; i++) { |
| 2017 if (async_code_array.At(i) == Code::null()) { |
| 2018 break; |
| 2019 } |
| 2020 if (async_code_array.At(i) == |
| 2021 StubCode::AsynchronousGapMarker_entry()->code()) { |
| 2022 stack_trace->AddMarker(ActivationFrame::kAsyncSuspensionMarker); |
| 2023 } else { |
| 2024 code = Code::RawCast(async_code_array.At(i)); |
| 2025 offset = Smi::RawCast(async_pc_offset_array.At(i)); |
| 2026 uword pc = code.PayloadStart() + offset.Value(); |
| 2027 if (code.is_optimized()) { |
| 2028 for (InlinedFunctionsIterator it(code, pc); !it.Done(); it.Advance()) { |
| 2029 inlined_code = it.code(); |
| 2030 stack_trace->AddAsyncHistoricalFrame(pc, inlined_code); |
| 2031 } |
| 2032 } else { |
| 2033 stack_trace->AddAsyncHistoricalFrame(pc, code); |
| 2034 } |
| 2035 } |
| 2036 } |
| 2037 return stack_trace; |
| 2038 } |
| 2039 |
| 2040 |
| 2041 DebuggerStackTrace* Debugger::CollectAsyncReturnCallStack() { |
| 2042 Thread* thread = Thread::Current(); |
| 2043 Zone* zone = thread->zone(); |
| 2044 Isolate* isolate = thread->isolate(); |
| 2045 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 2046 StackFrameIterator iterator(false); |
| 2047 Code& code = Code::Handle(zone); |
| 2048 Code& inlined_code = Code::Handle(zone); |
| 2049 Array& deopt_frame = Array::Handle(zone); |
| 2050 Function& function = Function::Handle(zone); |
| 2051 Closure& async_activation = Closure::Handle(zone); |
| 2052 |
| 2053 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
| 2054 frame = iterator.NextFrame()) { |
| 2055 ASSERT(frame->IsValid()); |
| 2056 if (FLAG_trace_debugger_stacktrace) { |
| 2057 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", |
| 2058 frame->ToCString()); |
| 2059 } |
| 2060 if (frame->IsDartFrame()) { |
| 2061 code = frame->LookupDartCode(); |
| 2062 function = code.function(); |
| 2063 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { |
| 2064 ActivationFrame* activation = CollectDartFrame( |
| 2065 isolate, frame->pc(), frame, code, Object::null_array(), 0, |
| 2066 ActivationFrame::kAsyncLive); |
| 2067 ASSERT(activation != NULL); |
| 2068 stack_trace->AddActivation(activation); |
| 2069 // Grab the awaiter. |
| 2070 async_activation ^= activation->GetAsyncAwaiter(); |
| 2071 break; |
| 2072 } |
| 2073 if (code.is_optimized() && !FLAG_precompiled_runtime) { |
| 2074 deopt_frame = DeoptimizeToArray(thread, frame, code); |
| 2075 for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); |
| 2076 it.Advance()) { |
| 2077 inlined_code = it.code(); |
| 2078 if (FLAG_trace_debugger_stacktrace) { |
| 2079 function = inlined_code.function(); |
| 2080 ASSERT(!function.IsNull()); |
| 2081 OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n", |
| 2082 function.ToFullyQualifiedCString()); |
| 2083 } |
| 2084 intptr_t deopt_frame_offset = it.GetDeoptFpOffset(); |
| 2085 stack_trace->AddActivation(CollectDartFrame( |
| 2086 isolate, it.pc(), frame, inlined_code, deopt_frame, |
| 2087 deopt_frame_offset, ActivationFrame::kAsyncLive)); |
| 2088 } |
| 2089 } else { |
| 2090 stack_trace->AddActivation(CollectDartFrame( |
| 2091 isolate, frame->pc(), frame, code, Object::null_array(), 0, |
| 2092 ActivationFrame::kAsyncLive)); |
| 2093 } |
| 2094 } |
| 2095 } |
| 2096 |
| 2097 // Append the asynchronous return call stack. |
| 2098 while (!async_activation.IsNull()) { |
| 2099 ActivationFrame* activation = new ActivationFrame(async_activation); |
| 2100 async_activation ^= activation->GetAsyncAwaiter(); |
| 2101 activation->ExtractTokenPositionFromAsyncClosure(); |
| 2102 stack_trace->AddActivation(activation); |
| 2103 } |
| 2104 |
| 2105 return stack_trace; |
| 2106 } |
| 2107 |
| 2108 |
1549 ActivationFrame* Debugger::TopDartFrame() const { | 2109 ActivationFrame* Debugger::TopDartFrame() const { |
1550 StackFrameIterator iterator(false); | 2110 StackFrameIterator iterator(false); |
1551 StackFrame* frame = iterator.NextFrame(); | 2111 StackFrame* frame = iterator.NextFrame(); |
1552 while ((frame != NULL) && !frame->IsDartFrame()) { | 2112 while ((frame != NULL) && !frame->IsDartFrame()) { |
1553 frame = iterator.NextFrame(); | 2113 frame = iterator.NextFrame(); |
1554 } | 2114 } |
1555 Code& code = Code::Handle(frame->LookupDartCode()); | 2115 Code& code = Code::Handle(frame->LookupDartCode()); |
1556 ActivationFrame* activation = new ActivationFrame( | 2116 ActivationFrame* activation = new ActivationFrame( |
1557 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); | 2117 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); |
1558 return activation; | 2118 return activation; |
1559 } | 2119 } |
1560 | 2120 |
1561 | 2121 |
1562 DebuggerStackTrace* Debugger::StackTrace() { | 2122 DebuggerStackTrace* Debugger::StackTrace() { |
1563 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); | 2123 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); |
1564 } | 2124 } |
1565 | 2125 |
| 2126 |
1566 DebuggerStackTrace* Debugger::CurrentStackTrace() { | 2127 DebuggerStackTrace* Debugger::CurrentStackTrace() { |
1567 return CollectStackTrace(); | 2128 return CollectStackTrace(); |
1568 } | 2129 } |
1569 | 2130 |
| 2131 |
| 2132 DebuggerStackTrace* Debugger::AsyncStackTrace() { |
| 2133 return (async_stack_trace_ != NULL) ? async_stack_trace_ |
| 2134 : CollectAsyncStackTrace(); |
| 2135 } |
| 2136 |
| 2137 |
| 2138 DebuggerStackTrace* Debugger::CurrentAsyncStackTrace() { |
| 2139 return CollectAsyncStackTrace(); |
| 2140 } |
| 2141 |
| 2142 |
| 2143 DebuggerStackTrace* Debugger::AsyncReturnStack() { |
| 2144 return (async_return_call_stack_ != NULL) ? async_return_call_stack_ |
| 2145 : CollectAsyncReturnCallStack(); |
| 2146 } |
| 2147 |
| 2148 |
| 2149 DebuggerStackTrace* Debugger::CurrentAsyncReturnStack() { |
| 2150 return CollectAsyncReturnCallStack(); |
| 2151 } |
| 2152 |
| 2153 |
1570 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { | 2154 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { |
1571 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 2155 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
1572 Function& function = Function::Handle(); | 2156 Function& function = Function::Handle(); |
1573 Code& code = Code::Handle(); | 2157 Code& code = Code::Handle(); |
1574 | 2158 |
1575 const uword fp = 0; | 2159 const uword fp = 0; |
1576 const uword sp = 0; | 2160 const uword sp = 0; |
1577 const Array& deopt_frame = Array::Handle(); | 2161 const Array& deopt_frame = Array::Handle(); |
1578 const intptr_t deopt_frame_offset = -1; | 2162 const intptr_t deopt_frame_offset = -1; |
1579 | 2163 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1652 void Debugger::PauseException(const Instance& exc) { | 2236 void Debugger::PauseException(const Instance& exc) { |
1653 // We ignore this exception event when the VM is executing code invoked | 2237 // We ignore this exception event when the VM is executing code invoked |
1654 // by the debugger to evaluate variables values, when we see a nested | 2238 // by the debugger to evaluate variables values, when we see a nested |
1655 // breakpoint or exception event, or if the debugger is not | 2239 // breakpoint or exception event, or if the debugger is not |
1656 // interested in exception events. | 2240 // interested in exception events. |
1657 if (ignore_breakpoints_ || IsPaused() || | 2241 if (ignore_breakpoints_ || IsPaused() || |
1658 (exc_pause_info_ == kNoPauseOnExceptions)) { | 2242 (exc_pause_info_ == kNoPauseOnExceptions)) { |
1659 return; | 2243 return; |
1660 } | 2244 } |
1661 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2245 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 2246 DebuggerStackTrace* async_stack_trace = CollectAsyncStackTrace(); |
| 2247 DebuggerStackTrace* async_return_call_stack = CollectAsyncReturnCallStack(); |
1662 if (!ShouldPauseOnException(stack_trace, exc)) { | 2248 if (!ShouldPauseOnException(stack_trace, exc)) { |
1663 return; | 2249 return; |
1664 } | 2250 } |
1665 ServiceEvent event(isolate_, ServiceEvent::kPauseException); | 2251 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
1666 event.set_exception(&exc); | 2252 event.set_exception(&exc); |
1667 if (stack_trace->Length() > 0) { | 2253 if (stack_trace->Length() > 0) { |
1668 event.set_top_frame(stack_trace->FrameAt(0)); | 2254 event.set_top_frame(stack_trace->FrameAt(0)); |
1669 } | 2255 } |
1670 ASSERT(stack_trace_ == NULL); | 2256 CacheStackTraces(stack_trace, async_stack_trace, async_return_call_stack); |
1671 stack_trace_ = stack_trace; | |
1672 Pause(&event); | 2257 Pause(&event); |
1673 HandleSteppingRequest(stack_trace_); // we may get a rewind request | 2258 HandleSteppingRequest(stack_trace_); // we may get a rewind request |
1674 stack_trace_ = NULL; | 2259 ClearCachedStackTraces(); |
1675 } | 2260 } |
1676 | 2261 |
1677 | 2262 |
1678 static TokenPosition LastTokenOnLine(Zone* zone, | 2263 static TokenPosition LastTokenOnLine(Zone* zone, |
1679 const TokenStream& tokens, | 2264 const TokenStream& tokens, |
1680 TokenPosition pos) { | 2265 TokenPosition pos) { |
1681 TokenStream::Iterator iter(zone, tokens, pos, | 2266 TokenStream::Iterator iter(zone, tokens, pos, |
1682 TokenStream::Iterator::kAllTokens); | 2267 TokenStream::Iterator::kAllTokens); |
1683 ASSERT(iter.IsValid()); | 2268 ASSERT(iter.IsValid()); |
1684 TokenPosition last_pos = pos; | 2269 TokenPosition last_pos = pos; |
(...skipping 852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2537 bpt = latent_locations_; | 3122 bpt = latent_locations_; |
2538 while (bpt != NULL) { | 3123 while (bpt != NULL) { |
2539 bpt->VisitObjectPointers(visitor); | 3124 bpt->VisitObjectPointers(visitor); |
2540 bpt = bpt->next(); | 3125 bpt = bpt->next(); |
2541 } | 3126 } |
2542 CodeBreakpoint* cbpt = code_breakpoints_; | 3127 CodeBreakpoint* cbpt = code_breakpoints_; |
2543 while (cbpt != NULL) { | 3128 while (cbpt != NULL) { |
2544 cbpt->VisitObjectPointers(visitor); | 3129 cbpt->VisitObjectPointers(visitor); |
2545 cbpt = cbpt->next(); | 3130 cbpt = cbpt->next(); |
2546 } | 3131 } |
| 3132 visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_frame_awaiter_)); |
2547 } | 3133 } |
2548 | 3134 |
2549 | 3135 |
2550 // static | 3136 // static |
2551 void Debugger::SetEventHandler(EventHandler* handler) { | 3137 void Debugger::SetEventHandler(EventHandler* handler) { |
2552 event_handler_ = handler; | 3138 event_handler_ = handler; |
2553 } | 3139 } |
2554 | 3140 |
2555 | 3141 |
2556 void Debugger::Pause(ServiceEvent* event) { | 3142 void Debugger::Pause(ServiceEvent* event) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2596 resume_event.set_top_frame(event->top_frame()); | 3182 resume_event.set_top_frame(event->top_frame()); |
2597 Service::HandleEvent(&resume_event); | 3183 Service::HandleEvent(&resume_event); |
2598 } | 3184 } |
2599 } | 3185 } |
2600 | 3186 |
2601 pause_event_ = NULL; | 3187 pause_event_ = NULL; |
2602 obj_cache_ = NULL; // Zone allocated | 3188 obj_cache_ = NULL; // Zone allocated |
2603 } | 3189 } |
2604 | 3190 |
2605 | 3191 |
| 3192 void Debugger::AsyncContinue() { |
| 3193 SetResumeAction(kContinue); |
| 3194 stepping_fp_ = 0; |
| 3195 async_stepping_fp_ = 0; |
| 3196 isolate_->set_single_step(false); |
| 3197 } |
| 3198 |
| 3199 |
| 3200 void Debugger::AsyncStepInto(const Closure& async_op) { |
| 3201 SetBreakpointAtActivation(async_op, true); |
| 3202 AsyncContinue(); |
| 3203 } |
| 3204 |
| 3205 |
2606 void Debugger::EnterSingleStepMode() { | 3206 void Debugger::EnterSingleStepMode() { |
2607 stepping_fp_ = 0; | 3207 stepping_fp_ = 0; |
2608 DeoptimizeWorld(); | 3208 DeoptimizeWorld(); |
2609 isolate_->set_single_step(true); | 3209 isolate_->set_single_step(true); |
2610 } | 3210 } |
2611 | 3211 |
2612 | 3212 |
2613 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, | 3213 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
2614 bool skip_next_step) { | 3214 bool skip_next_step) { |
| 3215 top_frame_awaiter_ = stack_trace->FrameAt(0)->GetAsyncAwaiter(); |
2615 stepping_fp_ = 0; | 3216 stepping_fp_ = 0; |
| 3217 async_stepping_fp_ = 0; |
2616 if (resume_action_ == kStepInto) { | 3218 if (resume_action_ == kStepInto) { |
2617 // When single stepping, we need to deoptimize because we might be | 3219 // When single stepping, we need to deoptimize because we might be |
2618 // stepping into optimized code. This happens in particular if | 3220 // stepping into optimized code. This happens in particular if |
2619 // the isolate has been interrupted, but can happen in other cases | 3221 // the isolate has been interrupted, but can happen in other cases |
2620 // as well. We need to deoptimize the world in case we are about | 3222 // as well. We need to deoptimize the world in case we are about |
2621 // to call an optimized function. | 3223 // to call an optimized function. |
2622 DeoptimizeWorld(); | 3224 DeoptimizeWorld(); |
2623 isolate_->set_single_step(true); | 3225 isolate_->set_single_step(true); |
2624 skip_next_step_ = skip_next_step; | 3226 skip_next_step_ = skip_next_step; |
| 3227 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() || |
| 3228 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) { |
| 3229 async_stepping_fp_ = stack_trace->FrameAt(0)->fp(); |
| 3230 } |
2625 if (FLAG_verbose_debug) { | 3231 if (FLAG_verbose_debug) { |
2626 OS::Print("HandleSteppingRequest- kStepInto\n"); | 3232 OS::Print("HandleSteppingRequest- kStepInto\n"); |
2627 } | 3233 } |
2628 } else if (resume_action_ == kStepOver) { | 3234 } else if (resume_action_ == kStepOver) { |
2629 DeoptimizeWorld(); | 3235 DeoptimizeWorld(); |
2630 isolate_->set_single_step(true); | 3236 isolate_->set_single_step(true); |
2631 skip_next_step_ = skip_next_step; | 3237 skip_next_step_ = skip_next_step; |
2632 ASSERT(stack_trace->Length() > 0); | 3238 ASSERT(stack_trace->Length() > 0); |
2633 stepping_fp_ = stack_trace->FrameAt(0)->fp(); | 3239 stepping_fp_ = stack_trace->FrameAt(0)->fp(); |
| 3240 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() || |
| 3241 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) { |
| 3242 async_stepping_fp_ = stack_trace->FrameAt(0)->fp(); |
| 3243 } |
2634 if (FLAG_verbose_debug) { | 3244 if (FLAG_verbose_debug) { |
2635 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); | 3245 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); |
2636 } | 3246 } |
2637 } else if (resume_action_ == kStepOut) { | 3247 } else if (resume_action_ == kStepOut) { |
| 3248 // Handle the async case first. |
| 3249 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() || |
| 3250 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) { |
| 3251 if (top_frame_awaiter_ != Object::null()) { |
| 3252 const Object& async_op = Object::Handle(top_frame_awaiter_); |
| 3253 ASSERT(async_op.IsClosure()); |
| 3254 AsyncStepInto(Closure::Cast(async_op)); |
| 3255 return; |
| 3256 } else { |
| 3257 // No awaiter. Just continue execution. |
| 3258 AsyncContinue(); |
| 3259 return; |
| 3260 } |
| 3261 } |
| 3262 // Now the synchronous case. |
2638 DeoptimizeWorld(); | 3263 DeoptimizeWorld(); |
2639 isolate_->set_single_step(true); | 3264 isolate_->set_single_step(true); |
2640 // Find topmost caller that is debuggable. | 3265 // Find topmost caller that is debuggable. |
2641 for (intptr_t i = 1; i < stack_trace->Length(); i++) { | 3266 for (intptr_t i = 1; i < stack_trace->Length(); i++) { |
2642 ActivationFrame* frame = stack_trace->FrameAt(i); | 3267 ActivationFrame* frame = stack_trace->FrameAt(i); |
2643 if (frame->IsDebuggable()) { | 3268 if (frame->IsDebuggable()) { |
2644 stepping_fp_ = frame->fp(); | 3269 stepping_fp_ = frame->fp(); |
2645 break; | 3270 break; |
2646 } | 3271 } |
2647 } | 3272 } |
(...skipping 25 matching lines...) Expand all Loading... |
2673 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { | 3298 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { |
2674 ActivationFrame* frame = stack->FrameAt(i); | 3299 ActivationFrame* frame = stack->FrameAt(i); |
2675 if (frame->IsRewindable()) { | 3300 if (frame->IsRewindable()) { |
2676 return i; | 3301 return i; |
2677 } | 3302 } |
2678 } | 3303 } |
2679 return -1; | 3304 return -1; |
2680 } | 3305 } |
2681 | 3306 |
2682 | 3307 |
| 3308 void Debugger::CacheStackTraces(DebuggerStackTrace* stack_trace, |
| 3309 DebuggerStackTrace* async_stack_trace, |
| 3310 DebuggerStackTrace* async_return_call_stack) { |
| 3311 ASSERT(stack_trace_ == NULL); |
| 3312 stack_trace_ = stack_trace; |
| 3313 ASSERT(async_stack_trace_ == NULL); |
| 3314 async_stack_trace_ = async_stack_trace; |
| 3315 ASSERT(async_return_call_stack_ == NULL); |
| 3316 async_return_call_stack_ = async_return_call_stack; |
| 3317 } |
| 3318 |
| 3319 |
| 3320 void Debugger::ClearCachedStackTraces() { |
| 3321 stack_trace_ = NULL; |
| 3322 async_stack_trace_ = NULL; |
| 3323 async_return_call_stack_ = NULL; |
| 3324 } |
| 3325 |
| 3326 |
2683 // Can the top frame be rewound? | 3327 // Can the top frame be rewound? |
2684 bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const { | 3328 bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const { |
2685 // check rewind pc is found | 3329 // check rewind pc is found |
2686 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); | 3330 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); |
2687 intptr_t num_frames = stack->Length(); | 3331 intptr_t num_frames = stack->Length(); |
2688 if (frame_index < 1 || frame_index >= num_frames) { | 3332 if (frame_index < 1 || frame_index >= num_frames) { |
2689 if (error) { | 3333 if (error) { |
2690 *error = Thread::Current()->zone()->PrintToString( | 3334 *error = Thread::Current()->zone()->PrintToString( |
2691 "Frame must be in bounds [1..%" Pd | 3335 "Frame must be in bounds [1..%" Pd |
2692 "]: " | 3336 "]: " |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2789 } | 3433 } |
2790 } | 3434 } |
2791 } | 3435 } |
2792 UNIMPLEMENTED(); | 3436 UNIMPLEMENTED(); |
2793 } | 3437 } |
2794 | 3438 |
2795 | 3439 |
2796 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { | 3440 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { |
2797 // We will be jumping out of the debugger rather than exiting this | 3441 // We will be jumping out of the debugger rather than exiting this |
2798 // function, so prepare the debugger state. | 3442 // function, so prepare the debugger state. |
2799 stack_trace_ = NULL; | 3443 ClearCachedStackTraces(); |
2800 resume_action_ = kContinue; | 3444 resume_action_ = kContinue; |
2801 resume_frame_index_ = -1; | 3445 resume_frame_index_ = -1; |
2802 EnterSingleStepMode(); | 3446 EnterSingleStepMode(); |
2803 | 3447 |
2804 uword rewind_pc = LookupRewindPc(code, frame->pc()); | 3448 uword rewind_pc = LookupRewindPc(code, frame->pc()); |
2805 if (FLAG_trace_rewind && rewind_pc == 0) { | 3449 if (FLAG_trace_rewind && rewind_pc == 0) { |
2806 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); | 3450 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); |
2807 } | 3451 } |
2808 ASSERT(rewind_pc != 0); | 3452 ASSERT(rewind_pc != 0); |
2809 if (FLAG_trace_rewind) { | 3453 if (FLAG_trace_rewind) { |
(...skipping 11 matching lines...) Expand all Loading... |
2821 } | 3465 } |
2822 | 3466 |
2823 | 3467 |
2824 void Debugger::RewindToOptimizedFrame(StackFrame* frame, | 3468 void Debugger::RewindToOptimizedFrame(StackFrame* frame, |
2825 const Code& optimized_code, | 3469 const Code& optimized_code, |
2826 intptr_t sub_index) { | 3470 intptr_t sub_index) { |
2827 post_deopt_frame_index_ = sub_index; | 3471 post_deopt_frame_index_ = sub_index; |
2828 | 3472 |
2829 // We will be jumping out of the debugger rather than exiting this | 3473 // We will be jumping out of the debugger rather than exiting this |
2830 // function, so prepare the debugger state. | 3474 // function, so prepare the debugger state. |
2831 stack_trace_ = NULL; | 3475 ClearCachedStackTraces(); |
2832 resume_action_ = kContinue; | 3476 resume_action_ = kContinue; |
2833 resume_frame_index_ = -1; | 3477 resume_frame_index_ = -1; |
2834 EnterSingleStepMode(); | 3478 EnterSingleStepMode(); |
2835 | 3479 |
2836 if (FLAG_trace_rewind) { | 3480 if (FLAG_trace_rewind) { |
2837 OS::PrintErr( | 3481 OS::PrintErr( |
2838 "===============================\n" | 3482 "===============================\n" |
2839 "Deoptimizing frame for rewind:\n" | 3483 "Deoptimizing frame for rewind:\n" |
2840 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | 3484 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
2841 ")\n" | 3485 ")\n" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2897 } | 3541 } |
2898 const Class& cls = Class::Handle(func.Owner()); | 3542 const Class& cls = Class::Handle(func.Owner()); |
2899 const Library& lib = Library::Handle(cls.library()); | 3543 const Library& lib = Library::Handle(cls.library()); |
2900 return lib.IsDebuggable(); | 3544 return lib.IsDebuggable(); |
2901 } | 3545 } |
2902 | 3546 |
2903 | 3547 |
2904 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { | 3548 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { |
2905 resume_action_ = kContinue; | 3549 resume_action_ = kContinue; |
2906 stepping_fp_ = 0; | 3550 stepping_fp_ = 0; |
| 3551 async_stepping_fp_ = 0; |
2907 isolate_->set_single_step(false); | 3552 isolate_->set_single_step(false); |
2908 ASSERT(!IsPaused()); | 3553 ASSERT(!IsPaused()); |
2909 ASSERT(obj_cache_ == NULL); | 3554 ASSERT(obj_cache_ == NULL); |
2910 if ((bpt != NULL) && bpt->IsSingleShot()) { | 3555 if ((bpt != NULL) && bpt->IsSingleShot()) { |
2911 RemoveBreakpoint(bpt->id()); | 3556 RemoveBreakpoint(bpt->id()); |
2912 bpt = NULL; | 3557 bpt = NULL; |
2913 } | 3558 } |
2914 | 3559 |
2915 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); | 3560 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); |
2916 event.set_top_frame(top_frame); | 3561 event.set_top_frame(top_frame); |
(...skipping 29 matching lines...) Expand all Loading... |
2946 ASSERT(isolate_->single_step()); | 3591 ASSERT(isolate_->single_step()); |
2947 // Don't pause recursively. | 3592 // Don't pause recursively. |
2948 if (IsPaused()) { | 3593 if (IsPaused()) { |
2949 return Error::null(); | 3594 return Error::null(); |
2950 } | 3595 } |
2951 if (skip_next_step_) { | 3596 if (skip_next_step_) { |
2952 skip_next_step_ = false; | 3597 skip_next_step_ = false; |
2953 return Error::null(); | 3598 return Error::null(); |
2954 } | 3599 } |
2955 | 3600 |
| 3601 ActivationFrame* frame = TopDartFrame(); |
| 3602 ASSERT(frame != NULL); |
| 3603 |
| 3604 OS::PrintErr("top frame: %s\n", frame->ToCString()); |
| 3605 OS::PrintErr("async_stepping_fp: %" Px "\n", async_stepping_fp_); |
| 3606 OS::PrintErr("IsInAsyncMachinery: %d\n", frame->IsInAsyncMachinery()); |
| 3607 |
| 3608 // Check if the user has single stepped out of an asynchronous function |
| 3609 // with an awaiter. If so, the next point of execution will be in the awaiter. |
| 3610 if (async_stepping_fp_ != 0) { |
| 3611 // We have either single stepped into async machinery or we have |
| 3612 // stepped out of the function. |
| 3613 const bool exited_async_function = |
| 3614 (IsCalleeFrameOf(async_stepping_fp_, frame->fp()) && |
| 3615 frame->IsInAsyncMachinery()) || |
| 3616 IsCalleeFrameOf(frame->fp(), async_stepping_fp_); |
| 3617 OS::PrintErr("exited_async_function = %d\n", exited_async_function); |
| 3618 if (exited_async_function) { |
| 3619 // We returned from the asynchronous function. |
| 3620 if (top_frame_awaiter_ == Object::null()) { |
| 3621 AsyncContinue(); |
| 3622 return Error::null(); |
| 3623 } else { |
| 3624 ASSERT(top_frame_awaiter_ != Object::null()); |
| 3625 const Object& async_op = Object::Handle(top_frame_awaiter_); |
| 3626 ASSERT(async_op.IsClosure()); |
| 3627 top_frame_awaiter_ = Object::null(); |
| 3628 AsyncStepInto(Closure::Cast(async_op)); |
| 3629 return Error::null(); |
| 3630 } |
| 3631 } |
| 3632 } |
| 3633 |
2956 // Check whether we are in a Dart function that the user is | 3634 // Check whether we are in a Dart function that the user is |
2957 // interested in. If we saved the frame pointer of a stack frame | 3635 // interested in. If we saved the frame pointer of a stack frame |
2958 // the user is interested in, we ignore the single step if we are | 3636 // the user is interested in, we ignore the single step if we are |
2959 // in a callee of that frame. Note that we assume that the stack | 3637 // in a callee of that frame. Note that we assume that the stack |
2960 // grows towards lower addresses. | 3638 // grows towards lower addresses. |
2961 ActivationFrame* frame = TopDartFrame(); | |
2962 ASSERT(frame != NULL); | |
2963 | |
2964 if (stepping_fp_ != 0) { | 3639 if (stepping_fp_ != 0) { |
2965 // There is an "interesting frame" set. Only pause at appropriate | 3640 // There is an "interesting frame" set. Only pause at appropriate |
2966 // locations in this frame. | 3641 // locations in this frame. |
2967 if (IsCalleeFrameOf(stepping_fp_, frame->fp())) { | 3642 if (IsCalleeFrameOf(stepping_fp_, frame->fp())) { |
2968 // We are in a callee of the frame we're interested in. | 3643 // We are in a callee of the frame we're interested in. |
2969 // Ignore this stepping break. | 3644 // Ignore this stepping break. |
2970 return Error::null(); | 3645 return Error::null(); |
2971 } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) { | 3646 } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) { |
2972 // We returned from the "interesting frame", there can be no more | 3647 // We returned from the "interesting frame", there can be no more |
2973 // stepping breaks for it. Pause at the next appropriate location | 3648 // stepping breaks for it. Pause at the next appropriate location |
2974 // and let the user set the "interesting" frame again. | 3649 // and let the user set the "interesting" frame again. |
2975 stepping_fp_ = 0; | 3650 stepping_fp_ = 0; |
2976 } | 3651 } |
| 3652 } else if (FLAG_sane_async_stacks && !SteppedForSyntheticAsyncBreakpoint()) { |
| 3653 const uword possible_stepping_fp = |
| 3654 GetAsyncActivationGeneratorSteppingFramePointer(); |
| 3655 if (possible_stepping_fp > 0) { |
| 3656 // We are currently executing in a callee of an async activation generator |
| 3657 // function. We do not want the user to see any of this code, so we will |
| 3658 // continue to step until we have exited the async activation generator. |
| 3659 stepping_fp_ = possible_stepping_fp; |
| 3660 return Error::null(); |
| 3661 } |
2977 } | 3662 } |
2978 | 3663 |
2979 if (!frame->IsDebuggable()) { | 3664 if (!frame->IsDebuggable()) { |
2980 return Error::null(); | 3665 return Error::null(); |
2981 } | 3666 } |
2982 if (!frame->TokenPos().IsDebugPause()) { | 3667 if (!frame->TokenPos().IsDebugPause()) { |
2983 return Error::null(); | 3668 return Error::null(); |
2984 } | 3669 } |
2985 | 3670 |
2986 // If there is an active breakpoint at this pc, then we should have | 3671 // If there is an active breakpoint at this pc, then we should have |
2987 // already bailed out of this function in the skip_next_step_ test | 3672 // already bailed out of this function in the skip_next_step_ test |
2988 // above. | 3673 // above. |
2989 ASSERT(!HasActiveBreakpoint(frame->pc())); | 3674 ASSERT(!HasActiveBreakpoint(frame->pc())); |
2990 | 3675 |
2991 if (FLAG_verbose_debug) { | 3676 if (FLAG_verbose_debug) { |
2992 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 3677 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
2993 String::Handle(frame->SourceUrl()).ToCString(), | 3678 String::Handle(frame->SourceUrl()).ToCString(), |
2994 frame->LineNumber(), | 3679 frame->LineNumber(), |
2995 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 3680 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
2996 frame->TokenPos().ToCString()); | 3681 frame->TokenPos().ToCString()); |
2997 } | 3682 } |
2998 | 3683 |
2999 ASSERT(stack_trace_ == NULL); | 3684 CacheStackTraces(CollectStackTrace(), CollectAsyncStackTrace(), |
3000 stack_trace_ = CollectStackTrace(); | 3685 CollectAsyncReturnCallStack()); |
3001 // If this step callback is part of stepping over an await statement, | 3686 if (SteppedForSyntheticAsyncBreakpoint()) { |
3002 // we saved the synthetic async breakpoint in PauseBreakpoint. We report | 3687 CleanupSyntheticAsyncBreakpoint(); |
3003 // that we are paused at that breakpoint and then delete it after continuing. | |
3004 SignalPausedEvent(frame, synthetic_async_breakpoint_); | |
3005 if (synthetic_async_breakpoint_ != NULL) { | |
3006 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | |
3007 synthetic_async_breakpoint_ = NULL; | |
3008 } | 3688 } |
| 3689 SignalPausedEvent(frame, NULL); |
3009 HandleSteppingRequest(stack_trace_); | 3690 HandleSteppingRequest(stack_trace_); |
3010 stack_trace_ = NULL; | 3691 ClearCachedStackTraces(); |
3011 | 3692 |
3012 // If any error occurred while in the debug message loop, return it here. | 3693 // If any error occurred while in the debug message loop, return it here. |
3013 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3694 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
3014 Thread::Current()->clear_sticky_error(); | 3695 Thread::Current()->clear_sticky_error(); |
3015 return error.raw(); | 3696 return error.raw(); |
3016 } | 3697 } |
3017 | 3698 |
3018 | 3699 |
3019 RawError* Debugger::PauseBreakpoint() { | 3700 RawError* Debugger::PauseBreakpoint() { |
3020 // We ignore this breakpoint when the VM is executing code invoked | 3701 // We ignore this breakpoint when the VM is executing code invoked |
3021 // by the debugger to evaluate variables values, or when we see a nested | 3702 // by the debugger to evaluate variables values, or when we see a nested |
3022 // breakpoint or exception event. | 3703 // breakpoint or exception event. |
3023 if (ignore_breakpoints_ || IsPaused()) { | 3704 if (ignore_breakpoints_ || IsPaused()) { |
3024 return Error::null(); | 3705 return Error::null(); |
3025 } | 3706 } |
3026 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3707 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 3708 DebuggerStackTrace* async_stack_trace = CollectAsyncStackTrace(); |
| 3709 DebuggerStackTrace* async_return_call_stack = CollectAsyncReturnCallStack(); |
3027 ASSERT(stack_trace->Length() > 0); | 3710 ASSERT(stack_trace->Length() > 0); |
3028 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 3711 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
3029 ASSERT(top_frame != NULL); | 3712 ASSERT(top_frame != NULL); |
3030 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); | 3713 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); |
3031 ASSERT(cbpt != NULL); | 3714 ASSERT(cbpt != NULL); |
3032 | 3715 |
3033 BreakpointLocation* bpt_location = cbpt->bpt_location_; | 3716 Breakpoint* bpt_hit = FindHitBreakpoint(cbpt->bpt_location_, top_frame); |
3034 Breakpoint* bpt_hit = NULL; | |
3035 | |
3036 // There may be more than one applicable breakpoint at this location, but we | |
3037 // will report only one as reached. If there is a single-shot breakpoint, we | |
3038 // favor it; then a closure-specific breakpoint ; then an general breakpoint. | |
3039 if (bpt_location != NULL) { | |
3040 Breakpoint* bpt = bpt_location->breakpoints(); | |
3041 while (bpt != NULL) { | |
3042 if (bpt->IsSingleShot()) { | |
3043 bpt_hit = bpt; | |
3044 break; | |
3045 } | |
3046 bpt = bpt->next(); | |
3047 } | |
3048 | |
3049 if (bpt_hit == NULL) { | |
3050 bpt = bpt_location->breakpoints(); | |
3051 while (bpt != NULL) { | |
3052 if (bpt->IsPerClosure()) { | |
3053 Object& closure = Object::Handle(top_frame->GetClosure()); | |
3054 ASSERT(closure.IsInstance()); | |
3055 ASSERT(Instance::Cast(closure).IsClosure()); | |
3056 if (closure.raw() == bpt->closure()) { | |
3057 bpt_hit = bpt; | |
3058 break; | |
3059 } | |
3060 } | |
3061 bpt = bpt->next(); | |
3062 } | |
3063 } | |
3064 | |
3065 if (bpt_hit == NULL) { | |
3066 bpt = bpt_location->breakpoints(); | |
3067 while (bpt != NULL) { | |
3068 if (bpt->IsRepeated()) { | |
3069 bpt_hit = bpt; | |
3070 break; | |
3071 } | |
3072 bpt = bpt->next(); | |
3073 } | |
3074 } | |
3075 } | |
3076 | |
3077 if (bpt_hit == NULL) { | 3717 if (bpt_hit == NULL) { |
3078 return Error::null(); | 3718 return Error::null(); |
3079 } | 3719 } |
3080 | 3720 |
3081 if (bpt_hit->is_synthetic_async()) { | 3721 if (bpt_hit->is_synthetic_async()) { |
3082 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3722 TD_Print("ASYNC: hit synthetic breakpoint: %s (address: %#" Px ")\n", |
3083 ASSERT(stack_trace->Length() > 0); | 3723 cbpt->ToCString(), top_frame->pc()); |
3084 ASSERT(stack_trace_ == NULL); | 3724 return StepForSyntheticAsyncBreakpoint(bpt_hit); |
3085 stack_trace_ = stack_trace; | |
3086 | |
3087 // Hit a synthetic async breakpoint. | |
3088 if (FLAG_verbose_debug) { | |
3089 OS::Print(">>> hit synthetic breakpoint at %s:%" Pd | |
3090 " " | |
3091 "(token %s) (address %#" Px ")\n", | |
3092 String::Handle(cbpt->SourceUrl()).ToCString(), | |
3093 cbpt->LineNumber(), cbpt->token_pos().ToCString(), | |
3094 top_frame->pc()); | |
3095 } | |
3096 | |
3097 ASSERT(synthetic_async_breakpoint_ == NULL); | |
3098 synthetic_async_breakpoint_ = bpt_hit; | |
3099 bpt_hit = NULL; | |
3100 | |
3101 // We are at the entry of an async function. | |
3102 // We issue a step over to resume at the point after the await statement. | |
3103 SetResumeAction(kStepOver); | |
3104 // When we single step from a user breakpoint, our next stepping | |
3105 // point will be at the exact same pc. Skip it. | |
3106 HandleSteppingRequest(stack_trace_, true /* skip next step */); | |
3107 stack_trace_ = NULL; | |
3108 return Error::null(); | |
3109 } | 3725 } |
3110 | 3726 |
3111 if (FLAG_verbose_debug) { | 3727 if (FLAG_verbose_debug) { |
3112 OS::Print(">>> hit %s breakpoint at %s:%" Pd | 3728 OS::Print(">>> hit %s breakpoint at %s:%" Pd |
3113 " " | 3729 " " |
3114 "(token %s) (address %#" Px ")\n", | 3730 "(token %s) (address %#" Px ")\n", |
3115 cbpt->IsInternal() ? "internal" : "user", | 3731 cbpt->IsInternal() ? "internal" : "user", |
3116 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), | 3732 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), |
3117 cbpt->token_pos().ToCString(), top_frame->pc()); | 3733 cbpt->token_pos().ToCString(), top_frame->pc()); |
3118 } | 3734 } |
3119 | 3735 |
3120 ASSERT(stack_trace_ == NULL); | 3736 CacheStackTraces(stack_trace, async_stack_trace, async_return_call_stack); |
3121 stack_trace_ = stack_trace; | |
3122 SignalPausedEvent(top_frame, bpt_hit); | 3737 SignalPausedEvent(top_frame, bpt_hit); |
3123 // When we single step from a user breakpoint, our next stepping | 3738 // When we single step from a user breakpoint, our next stepping |
3124 // point will be at the exact same pc. Skip it. | 3739 // point will be at the exact same pc. Skip it. |
3125 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3740 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
3126 stack_trace_ = NULL; | 3741 ClearCachedStackTraces(); |
3127 if (cbpt->IsInternal()) { | 3742 if (cbpt->IsInternal()) { |
3128 RemoveInternalBreakpoints(); | 3743 RemoveInternalBreakpoints(); |
3129 } | 3744 } |
3130 | 3745 |
3131 // If any error occurred while in the debug message loop, return it here. | 3746 // If any error occurred while in the debug message loop, return it here. |
3132 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3747 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
3133 Thread::Current()->clear_sticky_error(); | 3748 Thread::Current()->clear_sticky_error(); |
3134 return error.raw(); | 3749 return error.raw(); |
3135 } | 3750 } |
3136 | 3751 |
3137 | 3752 |
| 3753 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, |
| 3754 ActivationFrame* top_frame) { |
| 3755 if (location == NULL) { |
| 3756 return NULL; |
| 3757 } |
| 3758 // There may be more than one applicable breakpoint at this location, but we |
| 3759 // will report only one as reached. ; then ; then an general breakpoint. |
| 3760 |
| 3761 // First check for a single-shot breakpoint. |
| 3762 Breakpoint* bpt = location->breakpoints(); |
| 3763 while (bpt != NULL) { |
| 3764 if (bpt->IsSingleShot()) { |
| 3765 return bpt; |
| 3766 } |
| 3767 bpt = bpt->next(); |
| 3768 } |
| 3769 |
| 3770 // Now check for a closure-specific breakpoint. |
| 3771 bpt = location->breakpoints(); |
| 3772 while (bpt != NULL) { |
| 3773 if (bpt->IsPerClosure()) { |
| 3774 Object& closure = Object::Handle(top_frame->GetClosure()); |
| 3775 ASSERT(closure.IsInstance()); |
| 3776 ASSERT(Instance::Cast(closure).IsClosure()); |
| 3777 if (closure.raw() == bpt->closure()) { |
| 3778 return bpt; |
| 3779 } |
| 3780 } |
| 3781 bpt = bpt->next(); |
| 3782 } |
| 3783 |
| 3784 // Finally, check for a general breakpoint. |
| 3785 bpt = location->breakpoints(); |
| 3786 while (bpt != NULL) { |
| 3787 if (bpt->IsRepeated()) { |
| 3788 return bpt; |
| 3789 } |
| 3790 bpt = bpt->next(); |
| 3791 } |
| 3792 |
| 3793 return NULL; |
| 3794 } |
| 3795 |
| 3796 |
3138 void Debugger::PauseDeveloper(const String& msg) { | 3797 void Debugger::PauseDeveloper(const String& msg) { |
3139 // We ignore this breakpoint when the VM is executing code invoked | 3798 // We ignore this breakpoint when the VM is executing code invoked |
3140 // by the debugger to evaluate variables values, or when we see a nested | 3799 // by the debugger to evaluate variables values, or when we see a nested |
3141 // breakpoint or exception event. | 3800 // breakpoint or exception event. |
3142 if (ignore_breakpoints_ || IsPaused()) { | 3801 if (ignore_breakpoints_ || IsPaused()) { |
3143 return; | 3802 return; |
3144 } | 3803 } |
3145 | 3804 |
3146 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3805 CacheStackTraces(CollectStackTrace(), CollectAsyncStackTrace(), |
3147 ASSERT(stack_trace->Length() > 0); | 3806 CollectAsyncReturnCallStack()); |
3148 ASSERT(stack_trace_ == NULL); | |
3149 stack_trace_ = stack_trace; | |
3150 | 3807 |
3151 // TODO(johnmccutchan): Send |msg| to Observatory. | 3808 // TODO(johnmccutchan): Send |msg| to Observatory. |
3152 | 3809 |
3153 // We are in the native call to Developer_debugger. the developer | 3810 // We are in the native call to Developer_debugger. the developer |
3154 // gets a better experience by not seeing this call. To accomplish | 3811 // gets a better experience by not seeing this call. To accomplish |
3155 // this, we continue execution until the call exits (step out). | 3812 // this, we continue execution until the call exits (step out). |
3156 SetResumeAction(kStepOut); | 3813 SetResumeAction(kStepOut); |
3157 HandleSteppingRequest(stack_trace_); | 3814 HandleSteppingRequest(stack_trace_); |
3158 | 3815 |
3159 stack_trace_ = NULL; | 3816 ClearCachedStackTraces(); |
3160 } | 3817 } |
3161 | 3818 |
3162 | 3819 |
3163 void Debugger::Initialize(Isolate* isolate) { | 3820 void Debugger::Initialize(Isolate* isolate) { |
3164 if (initialized_) { | 3821 if (initialized_) { |
3165 return; | 3822 return; |
3166 } | 3823 } |
3167 isolate_ = isolate; | 3824 isolate_ = isolate; |
3168 | 3825 |
3169 // Use the isolate's control port as the isolate_id for debugging. | 3826 // Use the isolate's control port as the isolate_id for debugging. |
3170 // This port will be used as a unique ID to represent the isolate in | 3827 // This port will be used as a unique ID to represent the isolate in |
3171 // the debugger embedder api. | 3828 // the debugger embedder api. |
3172 isolate_id_ = isolate_->main_port(); | 3829 isolate_id_ = isolate_->main_port(); |
3173 initialized_ = true; | 3830 initialized_ = true; |
3174 } | 3831 } |
3175 | 3832 |
3176 | 3833 |
| 3834 void Debugger::WhenRunnable() { |
| 3835 // Lookup some internal implementation functions and mark them as |
| 3836 // not-debuggable (so the user never steps into them) and |
| 3837 // not-inlinable (so that we can cheaply detect their presence on the stack). |
| 3838 Thread::EnterIsolate(isolate_); |
| 3839 Thread* thread = Thread::Current(); |
| 3840 ASSERT(thread != NULL); |
| 3841 { |
| 3842 StackZone zone(thread); |
| 3843 HandleScope handle_scope(thread); |
| 3844 |
| 3845 const Library& async_library = |
| 3846 Library::Handle(isolate_->object_store()->async_library()); |
| 3847 ASSERT(!async_library.IsNull()); |
| 3848 |
| 3849 // This function is called when an async function completes their completer. |
| 3850 const Function& complete_on_async_return_function = |
| 3851 Function::Handle(async_library.LookupFunctionAllowPrivate( |
| 3852 Symbols::CompleterCompleteOnAsyncReturn())); |
| 3853 ASSERT(!complete_on_async_return_function.IsNull()); |
| 3854 complete_on_async_return_function.set_is_debuggable(false); |
| 3855 complete_on_async_return_function.set_is_inlinable(false); |
| 3856 |
| 3857 // Class used to implement async* functions. |
| 3858 const Class& async_stream_controller = |
| 3859 Class::Handle(async_library.LookupClassAllowPrivate( |
| 3860 Symbols::_AsyncStarStreamController())); |
| 3861 ASSERT(!async_stream_controller.IsNull()); |
| 3862 const Array& functions = Array::Handle(async_stream_controller.functions()); |
| 3863 ASSERT(!functions.IsNull()); |
| 3864 Function& function = Function::Handle(); |
| 3865 for (intptr_t i = 0; i < functions.Length(); i++) { |
| 3866 function ^= functions.At(i); |
| 3867 if (function.IsNull()) { |
| 3868 // Skip padding. |
| 3869 continue; |
| 3870 } |
| 3871 function.set_is_debuggable(false); |
| 3872 function.set_is_inlinable(false); |
| 3873 } |
| 3874 } |
| 3875 Thread::ExitIsolate(); |
| 3876 } |
| 3877 |
| 3878 |
3177 void Debugger::NotifyIsolateCreated() { | 3879 void Debugger::NotifyIsolateCreated() { |
3178 if (NeedsIsolateEvents()) { | 3880 if (NeedsIsolateEvents()) { |
3179 ServiceEvent event(isolate_, ServiceEvent::kIsolateStart); | 3881 ServiceEvent event(isolate_, ServiceEvent::kIsolateStart); |
3180 InvokeEventHandler(&event); | 3882 InvokeEventHandler(&event); |
3181 } | 3883 } |
3182 } | 3884 } |
3183 | 3885 |
3184 | 3886 |
3185 // Return innermost closure contained in 'function' that contains | 3887 // Return innermost closure contained in 'function' that contains |
3186 // the given token position. | 3888 // the given token position. |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3599 | 4301 |
3600 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 4302 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
3601 ASSERT(bpt->next() == NULL); | 4303 ASSERT(bpt->next() == NULL); |
3602 bpt->set_next(code_breakpoints_); | 4304 bpt->set_next(code_breakpoints_); |
3603 code_breakpoints_ = bpt; | 4305 code_breakpoints_ = bpt; |
3604 } | 4306 } |
3605 | 4307 |
3606 #endif // !PRODUCT | 4308 #endif // !PRODUCT |
3607 | 4309 |
3608 } // namespace dart | 4310 } // namespace dart |
OLD | NEW |