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

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

Issue 119673004: Version 1.1.0-dev.5.2 (Closed) Base URL: http://dart.googlecode.com/svn/trunk/
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « dart/runtime/vm/debugger.h ('k') | dart/runtime/vm/debugger_api_impl_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/debugger.h" 5 #include "vm/debugger.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 8
9 #include "vm/code_generator.h" 9 #include "vm/code_generator.h"
10 #include "vm/code_patcher.h" 10 #include "vm/code_patcher.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 } 43 }
44 44
45 private: 45 private:
46 GrowableObjectArray* objs_; 46 GrowableObjectArray* objs_;
47 47
48 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); 48 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache);
49 }; 49 };
50 50
51 51
52 SourceBreakpoint::SourceBreakpoint(intptr_t id, 52 SourceBreakpoint::SourceBreakpoint(intptr_t id,
53 const Function& func, 53 const Script& script,
54 intptr_t token_pos) 54 intptr_t token_pos)
55 : id_(id), 55 : id_(id),
56 function_(func.raw()), 56 script_(script.raw()),
57 token_pos_(token_pos), 57 token_pos_(token_pos),
58 line_number_(-1), 58 is_resolved_(false),
59 is_enabled_(false), 59 is_enabled_(false),
60 next_(NULL) { 60 next_(NULL),
61 ASSERT(!func.IsNull()); 61 function_(Function::null()),
62 ASSERT((func.token_pos() <= token_pos_) && 62 line_number_(-1) {
63 (token_pos_ <= func.end_token_pos())); 63 ASSERT(id_ > 0);
64 ASSERT(!script.IsNull());
65 ASSERT(token_pos_ >= 0);
64 } 66 }
65 67
66 68
67 void SourceBreakpoint::Enable() { 69 void SourceBreakpoint::Enable() {
68 is_enabled_ = true; 70 is_enabled_ = true;
69 Isolate::Current()->debugger()->SyncBreakpoint(this); 71 Isolate::Current()->debugger()->SyncBreakpoint(this);
70 } 72 }
71 73
72 74
73 void SourceBreakpoint::Disable() { 75 void SourceBreakpoint::Disable() {
74 is_enabled_ = false; 76 is_enabled_ = false;
75 Isolate::Current()->debugger()->SyncBreakpoint(this); 77 Isolate::Current()->debugger()->SyncBreakpoint(this);
76 } 78 }
77 79
78 80
79 RawScript* SourceBreakpoint::SourceCode() { 81 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) {
80 const Function& func = Function::Handle(function_); 82 ASSERT(func.script() == script_);
81 return func.script(); 83 ASSERT((func.token_pos() <= token_pos) &&
84 (token_pos <= func.end_token_pos()));
85 function_ = func.raw();
86 token_pos_ = token_pos;
87 line_number_ = -1; // Recalcualte lazily.
88 is_resolved_ = true;
82 } 89 }
83 90
84 91
92 // TODO(hausner): Get rid of library parameter. A source breakpoint location
93 // does not imply a library, since the same source code can be included
94 // in more than one library, e.g. the text location of mixin functions.
85 void SourceBreakpoint::GetCodeLocation( 95 void SourceBreakpoint::GetCodeLocation(
86 Library* lib, 96 Library* lib,
87 Script* script, 97 Script* script,
88 intptr_t* pos) const { 98 intptr_t* pos) {
89 const Function& func = Function::Handle(function_); 99 *script = this->script();
90 const Class& cls = Class::Handle(func.origin()); 100 *pos = token_pos_;
91 *lib = cls.library(); 101 if (IsResolved()) {
92 *script = func.script(); 102 const Function& func = Function::Handle(function_);
93 *pos = token_pos(); 103 ASSERT(!func.IsNull());
104 const Class& cls = Class::Handle(func.origin());
105 *lib = cls.library();
106 } else {
107 *lib = Library::null();
108 }
94 } 109 }
95 110
96 111
97 RawString* SourceBreakpoint::SourceUrl() { 112 RawString* SourceBreakpoint::SourceUrl() {
98 const Script& script = Script::Handle(SourceCode()); 113 return Script::Handle(script()).url();
99 return script.url();
100 } 114 }
101 115
102 116
103 intptr_t SourceBreakpoint::LineNumber() { 117 intptr_t SourceBreakpoint::LineNumber() {
104 // Compute line number lazily since it causes scanning of the script. 118 // Compute line number lazily since it causes scanning of the script.
105 if (line_number_ < 0) { 119 if (line_number_ < 0) {
106 const Script& script = Script::Handle(SourceCode()); 120 const Script& script = Script::Handle(this->script());
107 script.GetTokenLocation(token_pos_, &line_number_, NULL); 121 script.GetTokenLocation(token_pos_, &line_number_, NULL);
108 } 122 }
109 return line_number_; 123 return line_number_;
110 } 124 }
111 125
112 126
113 void SourceBreakpoint::set_function(const Function& func) {
114 function_ = func.raw();
115 }
116
117
118 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { 127 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
128 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_));
119 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); 129 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
120 } 130 }
121 131
122 132
123 void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) const { 133 void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) {
124 Isolate* isolate = Isolate::Current(); 134 Isolate* isolate = Isolate::Current();
125 135
126 JSONObject jsobj(stream); 136 JSONObject jsobj(stream);
127 jsobj.AddProperty("type", "Breakpoint"); 137 jsobj.AddProperty("type", "Breakpoint");
128 138
129 jsobj.AddProperty("id", id()); 139 jsobj.AddProperty("id", id());
130 jsobj.AddProperty("enabled", IsEnabled()); 140 jsobj.AddProperty("enabled", IsEnabled());
131 141 jsobj.AddProperty("resolved", IsResolved());
132 const Function& func = Function::Handle(function());
133 jsobj.AddProperty("resolved", func.HasCode());
134 142
135 Library& library = Library::Handle(isolate); 143 Library& library = Library::Handle(isolate);
136 Script& script = Script::Handle(isolate); 144 Script& script = Script::Handle(isolate);
137 intptr_t token_pos; 145 intptr_t token_pos;
138 GetCodeLocation(&library, &script, &token_pos); 146 GetCodeLocation(&library, &script, &token_pos);
139 { 147 {
140 JSONObject location(&jsobj, "location"); 148 JSONObject location(&jsobj, "location");
141 location.AddProperty("type", "Location"); 149 location.AddProperty("type", "Location");
142 location.AddProperty("libId", library.index());
143 150
144 const String& url = String::Handle(script.url()); 151 const String& url = String::Handle(script.url());
145 location.AddProperty("script", url.ToCString()); 152 location.AddProperty("script", url.ToCString());
146 location.AddProperty("tokenPos", token_pos); 153 location.AddProperty("tokenPos", token_pos);
147 } 154 }
148 } 155 }
149 156
150 157
151 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { 158 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
152 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); 159 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
(...skipping 29 matching lines...) Expand all
182 if (event_handler_ != NULL) { 189 if (event_handler_ != NULL) {
183 Debugger* debugger = Isolate::Current()->debugger(); 190 Debugger* debugger = Isolate::Current()->debugger();
184 ASSERT(debugger != NULL); 191 ASSERT(debugger != NULL);
185 DebuggerEvent event(type); 192 DebuggerEvent event(type);
186 event.isolate_id = debugger->GetIsolateId(); 193 event.isolate_id = debugger->GetIsolateId();
187 ASSERT(event.isolate_id != ILLEGAL_ISOLATE_ID); 194 ASSERT(event.isolate_id != ILLEGAL_ISOLATE_ID);
188 if (type == kIsolateInterrupted) { 195 if (type == kIsolateInterrupted) {
189 DebuggerStackTrace* stack_trace = debugger->CollectStackTrace(); 196 DebuggerStackTrace* stack_trace = debugger->CollectStackTrace();
190 ASSERT(stack_trace->Length() > 0); 197 ASSERT(stack_trace->Length() > 0);
191 ASSERT(debugger->stack_trace_ == NULL); 198 ASSERT(debugger->stack_trace_ == NULL);
192 ASSERT(debugger->obj_cache_ == NULL);
193 debugger->obj_cache_ = new RemoteObjectCache(64);
194 debugger->stack_trace_ = stack_trace; 199 debugger->stack_trace_ = stack_trace;
195 (*event_handler_)(&event); 200 debugger->Pause(&event);
196 debugger->stack_trace_ = NULL; 201 debugger->stack_trace_ = NULL;
197 debugger->obj_cache_ = NULL; // Remote object cache is zone allocated.
198 // TODO(asiva): Need some work here to be able to single step after 202 // TODO(asiva): Need some work here to be able to single step after
199 // an interrupt. 203 // an interrupt.
200 } else { 204 } else {
201 (*event_handler_)(&event); 205 (*event_handler_)(&event);
202 } 206 }
203 } 207 }
204 } 208 }
205 209
206 210
207 const char* Debugger::QualifiedFunctionName(const Function& func) { 211 const char* Debugger::QualifiedFunctionName(const Function& func) {
208 const String& func_name = String::Handle(func.name()); 212 const String& func_name = String::Handle(func.name());
209 Class& func_class = Class::Handle(func.Owner()); 213 Class& func_class = Class::Handle(func.Owner());
210 String& class_name = String::Handle(func_class.Name()); 214 String& class_name = String::Handle(func_class.Name());
211 215
212 const char* kFormat = "%s%s%s"; 216 const char* kFormat = "%s%s%s";
213 intptr_t len = OS::SNPrint(NULL, 0, kFormat, 217 intptr_t len = OS::SNPrint(NULL, 0, kFormat,
214 func_class.IsTopLevel() ? "" : class_name.ToCString(), 218 func_class.IsTopLevel() ? "" : class_name.ToCString(),
215 func_class.IsTopLevel() ? "" : ".", 219 func_class.IsTopLevel() ? "" : ".",
216 func_name.ToCString()); 220 func_name.ToCString());
217 len++; // String terminator. 221 len++; // String terminator.
218 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 222 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
219 OS::SNPrint(chars, len, kFormat, 223 OS::SNPrint(chars, len, kFormat,
220 func_class.IsTopLevel() ? "" : class_name.ToCString(), 224 func_class.IsTopLevel() ? "" : class_name.ToCString(),
221 func_class.IsTopLevel() ? "" : ".", 225 func_class.IsTopLevel() ? "" : ".",
222 func_name.ToCString()); 226 func_name.ToCString());
223 return chars; 227 return chars;
224 } 228 }
225 229
226 230
231 // Returns true if function contains the token position in the given script.
232 static bool FunctionContains(const Function& func,
233 const Script& script,
234 intptr_t token_pos) {
235 if ((func.token_pos() <= token_pos) && (token_pos <= func.end_token_pos())) {
236 // Check script equality second because it allocates
237 // handles as a side effect.
238 return func.script() == script.raw();
239 }
240 return false;
241 }
242
243
227 bool Debugger::HasBreakpoint(const Function& func) { 244 bool Debugger::HasBreakpoint(const Function& func) {
228 if (!func.HasCode()) { 245 if (!func.HasCode()) {
229 // If the function is not compiled yet, just check whether there 246 // If the function is not compiled yet, just check whether there
230 // is a user-defined latent breakpoint. 247 // is a user-defined breakpoint that falls into the token
248 // range of the function. This may be a false positive: the breakpoint
249 // might be inside a local closure.
250 Script& script = Script::Handle(isolate_);
231 SourceBreakpoint* sbpt = src_breakpoints_; 251 SourceBreakpoint* sbpt = src_breakpoints_;
232 while (sbpt != NULL) { 252 while (sbpt != NULL) {
233 if (func.raw() == sbpt->function()) { 253 script = sbpt->script();
254 if (FunctionContains(func, script, sbpt->token_pos())) {
234 return true; 255 return true;
235 } 256 }
236 sbpt = sbpt->next_; 257 sbpt = sbpt->next_;
237 } 258 }
238 return false; 259 return false;
239 } 260 }
240 CodeBreakpoint* cbpt = code_breakpoints_; 261 CodeBreakpoint* cbpt = code_breakpoints_;
241 while (cbpt != NULL) { 262 while (cbpt != NULL) {
242 if (func.raw() == cbpt->function()) { 263 if (func.raw() == cbpt->function()) {
243 return true; 264 return true;
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 ASSERT(!code_.is_optimized()); 385 ASSERT(!code_.is_optimized());
365 context_level_ = 0; 386 context_level_ = 0;
366 intptr_t pc_desc_idx = PcDescIndex(); 387 intptr_t pc_desc_idx = PcDescIndex();
367 // TODO(hausner): What to do if there is no descriptor entry 388 // TODO(hausner): What to do if there is no descriptor entry
368 // for the code position of the frame? For now say we are at context 389 // for the code position of the frame? For now say we are at context
369 // level 0. 390 // level 0.
370 if (pc_desc_idx < 0) { 391 if (pc_desc_idx < 0) {
371 return context_level_; 392 return context_level_;
372 } 393 }
373 ASSERT(!pc_desc_.IsNull()); 394 ASSERT(!pc_desc_.IsNull());
374 if (pc_desc_.DescriptorKind(pc_desc_idx) == PcDescriptors::kReturn) {
375 // Special case: the context chain has already been deallocated.
376 // The context level is 0.
377 return context_level_;
378 }
379 intptr_t innermost_begin_pos = 0; 395 intptr_t innermost_begin_pos = 0;
380 intptr_t activation_token_pos = TokenPos(); 396 intptr_t activation_token_pos = TokenPos();
381 ASSERT(activation_token_pos >= 0); 397 ASSERT(activation_token_pos >= 0);
382 GetVarDescriptors(); 398 GetVarDescriptors();
383 intptr_t var_desc_len = var_descriptors_.Length(); 399 intptr_t var_desc_len = var_descriptors_.Length();
384 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { 400 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
385 RawLocalVarDescriptors::VarInfo var_info; 401 RawLocalVarDescriptors::VarInfo var_info;
386 var_descriptors_.GetInfo(cur_idx, &var_info); 402 var_descriptors_.GetInfo(cur_idx, &var_info);
387 if ((var_info.kind == RawLocalVarDescriptors::kContextLevel) && 403 if ((var_info.kind == RawLocalVarDescriptors::kContextLevel) &&
388 (var_info.begin_pos <= activation_token_pos) && 404 (var_info.begin_pos <= activation_token_pos) &&
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 589
574 590
575 RawInstance* ActivationFrame::GetLocalInstanceVar(intptr_t slot_index) { 591 RawInstance* ActivationFrame::GetLocalInstanceVar(intptr_t slot_index) {
576 Instance& instance = Instance::Handle(); 592 Instance& instance = Instance::Handle();
577 instance ^= GetLocalVar(slot_index); 593 instance ^= GetLocalVar(slot_index);
578 return instance.raw(); 594 return instance.raw();
579 } 595 }
580 596
581 597
582 RawContext* ActivationFrame::GetLocalContextVar(intptr_t slot_index) { 598 RawContext* ActivationFrame::GetLocalContextVar(intptr_t slot_index) {
583 Context& context = Context::Handle(); 599 Object& context = Object::Handle(GetLocalVar(slot_index));
584 context ^= GetLocalVar(slot_index); 600 if (context.IsContext()) {
585 return context.raw(); 601 return Context::Cast(context).raw();
602 }
603 return Context::null();
586 } 604 }
587 605
588 606
589 void ActivationFrame::VariableAt(intptr_t i, 607 void ActivationFrame::VariableAt(intptr_t i,
590 String* name, 608 String* name,
591 intptr_t* token_pos, 609 intptr_t* token_pos,
592 intptr_t* end_pos, 610 intptr_t* end_pos,
593 Instance* value) { 611 Instance* value) {
594 GetDescIndices(); 612 GetDescIndices();
595 ASSERT(i < desc_indices_.length()); 613 ASSERT(i < desc_indices_.length());
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 case PcDescriptors::kUnoptStaticCall: { 773 case PcDescriptors::kUnoptStaticCall: {
756 const Code& code = 774 const Code& code =
757 Code::Handle(Function::Handle(function_).unoptimized_code()); 775 Code::Handle(Function::Handle(function_).unoptimized_code());
758 saved_bytes_.target_address_ = 776 saved_bytes_.target_address_ =
759 CodePatcher::GetStaticCallTargetAt(pc_, code); 777 CodePatcher::GetStaticCallTargetAt(pc_, code);
760 CodePatcher::PatchStaticCallAt(pc_, code, 778 CodePatcher::PatchStaticCallAt(pc_, code,
761 StubCode::BreakpointStaticEntryPoint()); 779 StubCode::BreakpointStaticEntryPoint());
762 break; 780 break;
763 } 781 }
764 case PcDescriptors::kRuntimeCall: 782 case PcDescriptors::kRuntimeCall:
765 case PcDescriptors::kClosureCall: { 783 case PcDescriptors::kClosureCall:
784 case PcDescriptors::kReturn: {
766 const Code& code = 785 const Code& code =
767 Code::Handle(Function::Handle(function_).unoptimized_code()); 786 Code::Handle(Function::Handle(function_).unoptimized_code());
768 saved_bytes_.target_address_ = 787 saved_bytes_.target_address_ =
769 CodePatcher::GetStaticCallTargetAt(pc_, code); 788 CodePatcher::GetStaticCallTargetAt(pc_, code);
770 CodePatcher::PatchStaticCallAt(pc_, code, 789 CodePatcher::PatchStaticCallAt(pc_, code,
771 StubCode::BreakpointRuntimeEntryPoint()); 790 StubCode::BreakpointRuntimeEntryPoint());
772 break; 791 break;
773 } 792 }
774 case PcDescriptors::kReturn:
775 PatchFunctionReturn();
776 break;
777 default: 793 default:
778 UNREACHABLE(); 794 UNREACHABLE();
779 } 795 }
780 is_enabled_ = true; 796 is_enabled_ = true;
781 } 797 }
782 798
783 799
784 void CodeBreakpoint::RestoreCode() { 800 void CodeBreakpoint::RestoreCode() {
785 ASSERT(is_enabled_); 801 ASSERT(is_enabled_);
786 switch (breakpoint_kind_) { 802 switch (breakpoint_kind_) {
787 case PcDescriptors::kIcCall: { 803 case PcDescriptors::kIcCall: {
788 const Code& code = 804 const Code& code =
789 Code::Handle(Function::Handle(function_).unoptimized_code()); 805 Code::Handle(Function::Handle(function_).unoptimized_code());
790 CodePatcher::PatchInstanceCallAt(pc_, code, 806 CodePatcher::PatchInstanceCallAt(pc_, code,
791 saved_bytes_.target_address_); 807 saved_bytes_.target_address_);
792 break; 808 break;
793 } 809 }
794 case PcDescriptors::kUnoptStaticCall: 810 case PcDescriptors::kUnoptStaticCall:
795 case PcDescriptors::kClosureCall: 811 case PcDescriptors::kClosureCall:
796 case PcDescriptors::kRuntimeCall: { 812 case PcDescriptors::kRuntimeCall:
813 case PcDescriptors::kReturn: {
797 const Code& code = 814 const Code& code =
798 Code::Handle(Function::Handle(function_).unoptimized_code()); 815 Code::Handle(Function::Handle(function_).unoptimized_code());
799 CodePatcher::PatchStaticCallAt(pc_, code, 816 CodePatcher::PatchStaticCallAt(pc_, code,
800 saved_bytes_.target_address_); 817 saved_bytes_.target_address_);
801 break; 818 break;
802 } 819 }
803 case PcDescriptors::kReturn:
804 RestoreFunctionReturn();
805 break;
806 default: 820 default:
807 UNREACHABLE(); 821 UNREACHABLE();
808 } 822 }
809 is_enabled_ = false; 823 is_enabled_ = false;
810 } 824 }
811 825
812 826
813 void CodeBreakpoint::Enable() { 827 void CodeBreakpoint::Enable() {
814 if (!is_enabled_) { 828 if (!is_enabled_) {
815 PatchCode(); 829 PatchCode();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 ASSERT(IsValidId(obj_id)); 862 ASSERT(IsValidId(obj_id));
849 return objs_->At(obj_id); 863 return objs_->At(obj_id);
850 } 864 }
851 865
852 866
853 Debugger::Debugger() 867 Debugger::Debugger()
854 : isolate_(NULL), 868 : isolate_(NULL),
855 isolate_id_(ILLEGAL_ISOLATE_ID), 869 isolate_id_(ILLEGAL_ISOLATE_ID),
856 initialized_(false), 870 initialized_(false),
857 next_id_(1), 871 next_id_(1),
858 stack_trace_(NULL),
859 obj_cache_(NULL),
860 src_breakpoints_(NULL), 872 src_breakpoints_(NULL),
861 code_breakpoints_(NULL), 873 code_breakpoints_(NULL),
862 resume_action_(kContinue), 874 resume_action_(kContinue),
863 ignore_breakpoints_(false), 875 ignore_breakpoints_(false),
864 in_event_notification_(false), 876 pause_event_(NULL),
877 obj_cache_(NULL),
878 stack_trace_(NULL),
865 exc_pause_info_(kNoPauseOnExceptions) { 879 exc_pause_info_(kNoPauseOnExceptions) {
866 } 880 }
867 881
868 882
869 Debugger::~Debugger() { 883 Debugger::~Debugger() {
870 isolate_id_ = ILLEGAL_ISOLATE_ID; 884 isolate_id_ = ILLEGAL_ISOLATE_ID;
871 ASSERT(!in_event_notification_); 885 ASSERT(!IsPaused());
872 ASSERT(src_breakpoints_ == NULL); 886 ASSERT(src_breakpoints_ == NULL);
873 ASSERT(code_breakpoints_ == NULL); 887 ASSERT(code_breakpoints_ == NULL);
874 ASSERT(stack_trace_ == NULL); 888 ASSERT(stack_trace_ == NULL);
875 ASSERT(obj_cache_ == NULL); 889 ASSERT(obj_cache_ == NULL);
876 } 890 }
877 891
878 892
879 void Debugger::Shutdown() { 893 void Debugger::Shutdown() {
880 while (src_breakpoints_ != NULL) { 894 while (src_breakpoints_ != NULL) {
881 SourceBreakpoint* bpt = src_breakpoints_; 895 SourceBreakpoint* bpt = src_breakpoints_;
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
1263 return false; 1277 return false;
1264 } 1278 }
1265 1279
1266 1280
1267 void Debugger::SignalExceptionThrown(const Instance& exc) { 1281 void Debugger::SignalExceptionThrown(const Instance& exc) {
1268 // We ignore this exception event when the VM is executing code invoked 1282 // We ignore this exception event when the VM is executing code invoked
1269 // by the debugger to evaluate variables values, when we see a nested 1283 // by the debugger to evaluate variables values, when we see a nested
1270 // breakpoint or exception event, or if the debugger is not 1284 // breakpoint or exception event, or if the debugger is not
1271 // interested in exception events. 1285 // interested in exception events.
1272 if (ignore_breakpoints_ || 1286 if (ignore_breakpoints_ ||
1273 in_event_notification_ || 1287 IsPaused() ||
1274 (event_handler_ == NULL) || 1288 (event_handler_ == NULL) ||
1275 (exc_pause_info_ == kNoPauseOnExceptions)) { 1289 (exc_pause_info_ == kNoPauseOnExceptions)) {
1276 return; 1290 return;
1277 } 1291 }
1278 DebuggerStackTrace* stack_trace = CollectStackTrace(); 1292 DebuggerStackTrace* stack_trace = CollectStackTrace();
1279 if (!ShouldPauseOnException(stack_trace, exc)) { 1293 if (!ShouldPauseOnException(stack_trace, exc)) {
1280 return; 1294 return;
1281 } 1295 }
1296 DebuggerEvent event(kExceptionThrown);
1297 event.exception = &exc;
1282 ASSERT(stack_trace_ == NULL); 1298 ASSERT(stack_trace_ == NULL);
1283 stack_trace_ = stack_trace; 1299 stack_trace_ = stack_trace;
1284 ASSERT(obj_cache_ == NULL); 1300 Pause(&event);
1285 in_event_notification_ = true;
1286 obj_cache_ = new RemoteObjectCache(64);
1287 DebuggerEvent event(kExceptionThrown);
1288 event.exception = &exc;
1289 (*event_handler_)(&event);
1290 in_event_notification_ = false;
1291 stack_trace_ = NULL; 1301 stack_trace_ = NULL;
1292 obj_cache_ = NULL; // Remote object cache is zone allocated.
1293 } 1302 }
1294 1303
1295 1304
1296 // Given a function and a token position range, return the best fit 1305 // Given a function and a token position, return the best fit
1297 // token position to set a breakpoint. 1306 // token position to set a breakpoint. The best fit is the safe point
1298 // If multiple possible breakpoint positions are within the given range, 1307 // with the lowest compiled code address that follows the requsted
1299 // the one with the lowest machine code address is picked. 1308 // token position.
1300 // If no possible breakpoint location exists in the given range, the closest
1301 // token position after the range is returned.
1302 intptr_t Debugger::ResolveBreakpointPos(const Function& func, 1309 intptr_t Debugger::ResolveBreakpointPos(const Function& func,
1303 intptr_t first_token_pos, 1310 intptr_t requested_token_pos) {
1304 intptr_t last_token_pos) {
1305 ASSERT(func.HasCode()); 1311 ASSERT(func.HasCode());
1306 ASSERT(!func.HasOptimizedCode()); 1312 ASSERT(!func.HasOptimizedCode());
1307 Code& code = Code::Handle(func.unoptimized_code()); 1313 Code& code = Code::Handle(func.unoptimized_code());
1308 ASSERT(!code.IsNull()); 1314 ASSERT(!code.IsNull());
1309 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); 1315 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
1310 intptr_t best_fit_index = -1; 1316 intptr_t best_fit_index = -1;
1311 intptr_t best_fit = INT_MAX; 1317 intptr_t best_fit_pos = INT_MAX;
1312 uword lowest_pc = kUwordMax; 1318 uword lowest_pc = kUwordMax;
1313 intptr_t lowest_pc_index = -1; 1319 intptr_t lowest_pc_index = -1;
1314 for (intptr_t i = 0; i < desc.Length(); i++) { 1320 for (intptr_t i = 0; i < desc.Length(); i++) {
1315 intptr_t desc_token_pos = desc.TokenPos(i); 1321 intptr_t desc_token_pos = desc.TokenPos(i);
1316 ASSERT(desc_token_pos >= 0); 1322 ASSERT(desc_token_pos >= 0);
1317 if (desc_token_pos < first_token_pos) { 1323 if (desc_token_pos < requested_token_pos) {
1318 // This descriptor is before the given range. 1324 // This descriptor is before the first acceptable token position.
1319 continue; 1325 continue;
1320 } 1326 }
1321 if (IsSafePoint(desc.DescriptorKind(i))) { 1327 if (IsSafePoint(desc.DescriptorKind(i))) {
1322 if ((desc_token_pos - first_token_pos) < best_fit) { 1328 if (desc_token_pos < best_fit_pos) {
1323 // So far, this descriptor has the closest token position to the 1329 // So far, this descriptor has the lowest token position after
1324 // beginning of the range. 1330 // the first acceptable token position.
1325 best_fit = desc_token_pos - first_token_pos; 1331 best_fit_pos = desc_token_pos;
1326 ASSERT(best_fit >= 0);
1327 best_fit_index = i; 1332 best_fit_index = i;
1328 } 1333 }
1329 if ((first_token_pos <= desc_token_pos) && 1334 if (desc.PC(i) < lowest_pc) {
1330 (desc_token_pos <= last_token_pos) && 1335 // This descriptor so far has the lowest code address.
1331 (desc.PC(i) < lowest_pc)) {
1332 // This descriptor is within the token position range and so
1333 // far has the lowest code address.
1334 lowest_pc = desc.PC(i); 1336 lowest_pc = desc.PC(i);
1335 lowest_pc_index = i; 1337 lowest_pc_index = i;
1336 } 1338 }
1337 } 1339 }
1338 } 1340 }
1339 if (lowest_pc_index >= 0) { 1341 if (lowest_pc_index >= 0) {
1340 // We found the the pc descriptor within the given token range that 1342 // We found the pc descriptor that has the lowest execution address.
1341 // has the lowest execution address. This is the first possible 1343 // This is the first possible breakpoint after the requested token
1342 // breakpoint on the line. We use this instead of the nearest 1344 // position. We use this instead of the nearest PC descriptor
1343 // PC descriptor measured in token index distance. 1345 // measured in token index distance.
1344 best_fit_index = lowest_pc_index; 1346 best_fit_index = lowest_pc_index;
1345 } 1347 }
1346 if (best_fit_index >= 0) { 1348 if (best_fit_index >= 0) {
1347 return desc.TokenPos(best_fit_index); 1349 return desc.TokenPos(best_fit_index);
1348 } 1350 }
1349 return -1; 1351 return -1;
1350 } 1352 }
1351 1353
1352 1354
1353 void Debugger::MakeCodeBreakpointsAt(const Function& func, 1355 void Debugger::MakeCodeBreakpointsAt(const Function& func,
1354 intptr_t token_pos,
1355 SourceBreakpoint* bpt) { 1356 SourceBreakpoint* bpt) {
1357 ASSERT((bpt != NULL) && bpt->IsResolved());
1356 ASSERT(!func.HasOptimizedCode()); 1358 ASSERT(!func.HasOptimizedCode());
1357 Code& code = Code::Handle(func.unoptimized_code()); 1359 Code& code = Code::Handle(func.unoptimized_code());
1358 ASSERT(!code.IsNull()); 1360 ASSERT(!code.IsNull());
1359 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); 1361 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
1360 for (intptr_t i = 0; i < desc.Length(); i++) { 1362 for (intptr_t i = 0; i < desc.Length(); i++) {
1361 intptr_t desc_token_pos = desc.TokenPos(i); 1363 intptr_t desc_token_pos = desc.TokenPos(i);
1362 if ((desc_token_pos == token_pos) && IsSafePoint(desc.DescriptorKind(i))) { 1364 if ((desc_token_pos == bpt->token_pos_) &&
1365 IsSafePoint(desc.DescriptorKind(i))) {
1363 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i)); 1366 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i));
1364 if (code_bpt == NULL) { 1367 if (code_bpt == NULL) {
1365 // No code breakpoint for this code exists; create one. 1368 // No code breakpoint for this code exists; create one.
1366 code_bpt = new CodeBreakpoint(func, i); 1369 code_bpt = new CodeBreakpoint(func, i);
1367 RegisterCodeBreakpoint(code_bpt); 1370 RegisterCodeBreakpoint(code_bpt);
1368 } 1371 }
1369 code_bpt->set_src_bpt(bpt); 1372 code_bpt->set_src_bpt(bpt);
1370 } 1373 if (bpt->IsEnabled()) {
1371 } 1374 code_bpt->Enable();
1372 } 1375 }
1373 1376 }
1374 1377 }
1375 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, 1378 }
1376 intptr_t first_token_pos, 1379
1377 intptr_t last_token_pos) { 1380
1378 if ((last_token_pos < target_function.token_pos()) || 1381 void Debugger::FindEquivalentFunctions(const Script& script,
1379 (target_function.end_token_pos() < first_token_pos)) { 1382 intptr_t start_pos,
1380 // The given token position is not within the target function. 1383 intptr_t end_pos,
1384 GrowableObjectArray* function_list) {
1385 Class& cls = Class::Handle(isolate_);
1386 Array& functions = Array::Handle(isolate_);
1387 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_);
1388 Function& function = Function::Handle(isolate_);
1389
1390 const ClassTable& class_table = *isolate_->class_table();
1391 const intptr_t num_classes = class_table.NumCids();
1392 for (intptr_t i = 1; i < num_classes; i++) {
1393 if (class_table.HasValidClassAt(i)) {
1394 cls = class_table.At(i);
1395 // If the class is not finalized, e.g. if it hasn't been parsed
1396 // yet entirely, we can ignore it. If it contains a function with
1397 // a latent breakpoint, we will detect it if and when the function
1398 // gets compiled.
1399 if (!cls.is_finalized()) {
1400 continue;
1401 }
1402 // Note: we need to check the functions of this class even if
1403 // the class is defined in a differenct 'script'. There could
1404 // be mixin functions from the given script in this class.
1405 functions = cls.functions();
1406 if (!functions.IsNull()) {
1407 const intptr_t num_functions = functions.Length();
1408 for (intptr_t pos = 0; pos < num_functions; pos++) {
1409 function ^= functions.At(pos);
1410 ASSERT(!function.IsNull());
1411 // Check token position first to avoid unnecessary calls
1412 // to script() which allocates handles.
1413 if ((function.token_pos() == start_pos)
1414 && (function.end_token_pos() == end_pos)
1415 && (function.script() == script.raw())) {
1416 function_list->Add(function);
1417 if (function.HasImplicitClosureFunction()) {
1418 function = function.ImplicitClosureFunction();
1419 function_list->Add(function);
1420 }
1421 }
1422 }
1423 }
1424 closures = cls.closures();
1425 if (!closures.IsNull()) {
1426 const intptr_t num_closures = closures.Length();
1427 for (intptr_t pos = 0; pos < num_closures; pos++) {
1428 function ^= closures.At(pos);
1429 ASSERT(!function.IsNull());
1430 if ((function.token_pos() == start_pos)
1431 && (function.end_token_pos() == end_pos)
1432 && (function.script() == script.raw())) {
1433 function_list->Add(function);
1434 if (function.HasImplicitClosureFunction()) {
1435 function = function.ImplicitClosureFunction();
1436 function_list->Add(function);
1437 }
1438 }
1439 }
1440 }
1441 }
1442 }
1443 }
1444
1445
1446 static void SelectBestFit(Function* best_fit, Function* func) {
1447 if (best_fit->IsNull()) {
1448 *best_fit = func->raw();
1449 }
1450 if (func->token_pos() > best_fit->token_pos()) {
1451 if (func->end_token_pos() <= best_fit->end_token_pos()) {
1452 // func is contained within best_fit. Select it even if it
1453 // has not been compiled yet.
1454 *best_fit = func->raw();
1455 if (func->HasImplicitClosureFunction()) {
1456 *func = func->ImplicitClosureFunction();
1457 if (func->HasCode()) {
1458 *best_fit = func->raw();
1459 }
1460 }
1461 }
1462 } else if ((func->token_pos() == best_fit->token_pos())
1463 && (func->end_token_pos() == best_fit->end_token_pos())
1464 && func->HasCode()) {
1465 // If func covers the same range, it is considered a better fit if
1466 // it has been compiled.
1467 *best_fit = func->raw();
1468 }
1469 }
1470
1471
1472 RawFunction* Debugger::FindBestFit(const Script& script,
1473 intptr_t token_pos) {
1474 Class& cls = Class::Handle(isolate_);
1475 Array& functions = Array::Handle(isolate_);
1476 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_);
1477 Function& function = Function::Handle(isolate_);
1478 Function& best_fit = Function::Handle(isolate_);
1479
1480 const ClassTable& class_table = *isolate_->class_table();
1481 const intptr_t num_classes = class_table.NumCids();
1482 for (intptr_t i = 1; i < num_classes; i++) {
1483 if (class_table.HasValidClassAt(i)) {
1484 cls = class_table.At(i);
1485 // Note: if this class has been parsed and finalized already,
1486 // we need to check the functions of this class even if
1487 // it is defined in a differenct 'script'. There could
1488 // be mixin functions from the given script in this class.
1489 // However, if this class is not parsed yet (not finalized),
1490 // we can ignore it and avoid the side effect of parsing it.
1491 if ((cls.script() != script.raw()) && !cls.is_finalized()) {
1492 continue;
1493 }
1494 // Parse class definition if not done yet.
1495 cls.EnsureIsFinalized(isolate_);
1496 functions = cls.functions();
1497 if (!functions.IsNull()) {
1498 const intptr_t num_functions = functions.Length();
1499 for (intptr_t pos = 0; pos < num_functions; pos++) {
1500 function ^= functions.At(pos);
1501 ASSERT(!function.IsNull());
1502 if (FunctionContains(function, script, token_pos)) {
1503 SelectBestFit(&best_fit, &function);
1504 }
1505 }
1506 }
1507
1508 closures = cls.closures();
1509 if (!closures.IsNull()) {
1510 const intptr_t num_closures = closures.Length();
1511 for (intptr_t pos = 0; pos < num_closures; pos++) {
1512 function ^= closures.At(pos);
1513 ASSERT(!function.IsNull());
1514 if (FunctionContains(function, script, token_pos)) {
1515 SelectBestFit(&best_fit, &function);
1516 }
1517 }
1518 }
1519 }
1520 }
1521 return best_fit.raw();
1522 }
1523
1524
1525 SourceBreakpoint* Debugger::SetBreakpoint(const Script& script,
1526 intptr_t token_pos) {
1527 Function& func = Function::Handle(isolate_);
1528 func = FindBestFit(script, token_pos);
1529 if (func.IsNull()) {
1381 return NULL; 1530 return NULL;
1382 } 1531 }
1383 intptr_t breakpoint_pos = -1; 1532 if (!func.IsNull() && func.HasCode()) {
1384 Function& closure = Function::Handle(isolate_); 1533 // A function containing this breakpoint location has already
1385 if (target_function.HasImplicitClosureFunction()) { 1534 // been compiled. We can resolve the breakpoint now.
1386 // There is a closurized version of this function.
1387 closure = target_function.ImplicitClosureFunction();
1388 }
1389 // Determine actual breakpoint location if the function or an
1390 // implicit closure of the function has been compiled already.
1391 if (target_function.HasCode()) {
1392 DeoptimizeWorld(); 1535 DeoptimizeWorld();
1393 ASSERT(!target_function.HasOptimizedCode()); 1536 intptr_t breakpoint_pos = ResolveBreakpointPos(func, token_pos);
1394 breakpoint_pos = 1537 if (breakpoint_pos >= 0) {
1395 ResolveBreakpointPos(target_function, first_token_pos, last_token_pos); 1538 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos);
1396 } else if (!closure.IsNull() && closure.HasCode()) { 1539 if (bpt != NULL) {
1397 DeoptimizeWorld(); 1540 // A source breakpoint for this location already exists.
1398 ASSERT(!closure.HasOptimizedCode()); 1541 return bpt;
1399 breakpoint_pos = 1542 }
1400 ResolveBreakpointPos(closure, first_token_pos, last_token_pos); 1543 bpt = new SourceBreakpoint(nextId(), script, token_pos);
1401 } else { 1544 bpt->SetResolved(func, breakpoint_pos);
1402 // This function has not been compiled yet. Set a pending 1545 RegisterSourceBreakpoint(bpt);
1403 // breakpoint to be resolved later. 1546 // There may be more than one function object for a given function
1404 SourceBreakpoint* source_bpt = 1547 // in source code. There may be implicit closure functions, and
1405 GetSourceBreakpoint(target_function, first_token_pos); 1548 // there may be copies of mixin functions. Collect all functions whose
1406 if (source_bpt != NULL) { 1549 // source code range matches exactly the best fit function we
1407 // A pending source breakpoint for this uncompiled location 1550 // found.
1408 // already exists. 1551 GrowableObjectArray& functions =
1409 if (FLAG_verbose_debug) { 1552 GrowableObjectArray::Handle(GrowableObjectArray::New());
1410 OS::Print("Pending breakpoint for uncompiled function" 1553 FindEquivalentFunctions(script,
1411 " '%s' at line %" Pd " already exists\n", 1554 func.token_pos(),
1412 target_function.ToFullyQualifiedCString(), 1555 func.end_token_pos(),
1413 source_bpt->LineNumber()); 1556 &functions);
1414 } 1557 const intptr_t num_functions = functions.Length();
1415 return source_bpt; 1558 // We must have found at least one function: func.
1416 } 1559 ASSERT(num_functions > 0);
1417 source_bpt = 1560 // Create code breakpoints for all compiled functions we found.
1418 new SourceBreakpoint(nextId(), target_function, first_token_pos); 1561 for (intptr_t i = 0; i < num_functions; i++) {
1419 RegisterSourceBreakpoint(source_bpt); 1562 func ^= functions.At(i);
1420 if (FLAG_verbose_debug) { 1563 if (func.HasCode()) {
1421 OS::Print("Registering pending breakpoint for " 1564 MakeCodeBreakpointsAt(func, bpt);
1422 "uncompiled function '%s' at line %" Pd "\n", 1565 }
1423 target_function.ToFullyQualifiedCString(), 1566 }
1424 source_bpt->LineNumber()); 1567 bpt->Enable();
1425 } 1568 SignalBpResolved(bpt);
1426 source_bpt->Enable(); 1569 return bpt;
1427 return source_bpt; 1570 }
1428 } 1571 }
1429 ASSERT(breakpoint_pos != -1); 1572 // There is no compiled function at this token position.
1430 SourceBreakpoint* source_bpt = 1573 // Register an unresolved breakpoint.
1431 GetSourceBreakpoint(target_function, breakpoint_pos); 1574 if (FLAG_verbose_debug && !func.IsNull()) {
1432 if (source_bpt != NULL) { 1575 intptr_t line_number;
1433 // A source breakpoint for this location already exists. 1576 script.GetTokenLocation(token_pos, &line_number, NULL);
1434 return source_bpt; 1577 OS::Print("Registering pending breakpoint for "
1435 } 1578 "uncompiled function '%s' at line %" Pd "\n",
1436 source_bpt = new SourceBreakpoint(nextId(), target_function, breakpoint_pos); 1579 func.ToFullyQualifiedCString(),
1437 RegisterSourceBreakpoint(source_bpt); 1580 line_number);
1438 if (target_function.HasCode()) { 1581 }
1439 MakeCodeBreakpointsAt(target_function, breakpoint_pos, source_bpt); 1582 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos);
1440 } 1583 if (bpt == NULL) {
1441 if (!closure.IsNull() && closure.HasCode()) { 1584 bpt = new SourceBreakpoint(nextId(), script, token_pos);
1442 MakeCodeBreakpointsAt(closure, breakpoint_pos, source_bpt); 1585 }
1443 } 1586 RegisterSourceBreakpoint(bpt);
1444 source_bpt->Enable(); 1587 bpt->Enable();
1445 SignalBpResolved(source_bpt); 1588 return bpt;
1446 return source_bpt; 1589 }
1447 } 1590
1448 1591
1449
1450 // Synchronize the enabled/disabled state of all code breakpoints 1592 // Synchronize the enabled/disabled state of all code breakpoints
1451 // associated with the source breakpoint bpt. 1593 // associated with the source breakpoint bpt.
1452 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { 1594 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) {
1453 CodeBreakpoint* cbpt = code_breakpoints_; 1595 CodeBreakpoint* cbpt = code_breakpoints_;
1454 while (cbpt != NULL) { 1596 while (cbpt != NULL) {
1455 if (bpt == cbpt->src_bpt()) { 1597 if (bpt == cbpt->src_bpt()) {
1456 if (bpt->IsEnabled()) { 1598 if (bpt->IsEnabled()) {
1457 cbpt->Enable(); 1599 cbpt->Enable();
1458 } else { 1600 } else {
1459 cbpt->Disable(); 1601 cbpt->Disable();
(...skipping 10 matching lines...) Expand all
1470 const Function& closure_func = 1612 const Function& closure_func =
1471 Function::Handle(target_function.ImplicitClosureFunction()); 1613 Function::Handle(target_function.ImplicitClosureFunction());
1472 InstrumentForStepping(closure_func); 1614 InstrumentForStepping(closure_func);
1473 } 1615 }
1474 } 1616 }
1475 1617
1476 1618
1477 SourceBreakpoint* Debugger::SetBreakpointAtEntry( 1619 SourceBreakpoint* Debugger::SetBreakpointAtEntry(
1478 const Function& target_function) { 1620 const Function& target_function) {
1479 ASSERT(!target_function.IsNull()); 1621 ASSERT(!target_function.IsNull());
1480 return SetBreakpoint(target_function, 1622 const Script& script = Script::Handle(target_function.script());
1481 target_function.token_pos(), 1623 return SetBreakpoint(script, target_function.token_pos());
1482 target_function.end_token_pos());
1483 } 1624 }
1484 1625
1485 1626
1486 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, 1627 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
1487 intptr_t line_number) { 1628 intptr_t line_number) {
1488 Library& lib = Library::Handle(isolate_); 1629 Library& lib = Library::Handle(isolate_);
1489 Script& script = Script::Handle(isolate_); 1630 Script& script = Script::Handle(isolate_);
1490 const GrowableObjectArray& libs = 1631 const GrowableObjectArray& libs =
1491 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); 1632 GrowableObjectArray::Handle(isolate_->object_store()->libraries());
1492 for (intptr_t i = 0; i < libs.Length(); i++) { 1633 for (intptr_t i = 0; i < libs.Length(); i++) {
(...skipping 13 matching lines...) Expand all
1506 intptr_t first_token_idx, last_token_idx; 1647 intptr_t first_token_idx, last_token_idx;
1507 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); 1648 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx);
1508 if (first_token_idx < 0) { 1649 if (first_token_idx < 0) {
1509 // Script does not contain the given line number. 1650 // Script does not contain the given line number.
1510 if (FLAG_verbose_debug) { 1651 if (FLAG_verbose_debug) {
1511 OS::Print("Script '%s' does not contain line number %" Pd "\n", 1652 OS::Print("Script '%s' does not contain line number %" Pd "\n",
1512 script_url.ToCString(), line_number); 1653 script_url.ToCString(), line_number);
1513 } 1654 }
1514 return NULL; 1655 return NULL;
1515 } else if (last_token_idx < 0) { 1656 } else if (last_token_idx < 0) {
1516 // Line does not contain any tokens. first_token_index is the first 1657 // Line does not contain any tokens.
1517 // token after the given line. We check whether that token is
1518 // part of a function.
1519 last_token_idx = first_token_idx;
1520 }
1521
1522 Function& func = Function::Handle(isolate_);
1523 while (first_token_idx <= last_token_idx) {
1524 func = lib.LookupFunctionInScript(script, first_token_idx);
1525 if (!func.IsNull()) {
1526 break;
1527 }
1528 first_token_idx++;
1529 }
1530 if (func.IsNull()) {
1531 if (FLAG_verbose_debug) { 1658 if (FLAG_verbose_debug) {
1532 OS::Print("No executable code at line %" Pd " in '%s'\n", 1659 OS::Print("No executable code at line %" Pd " in '%s'\n",
1533 line_number, script_url.ToCString()); 1660 line_number, script_url.ToCString());
1534 } 1661 }
1535 return NULL; 1662 return NULL;
1536 } 1663 }
1537 if (last_token_idx < 0) { 1664
1538 // The token at first_token_index is past the requested source line. 1665 SourceBreakpoint* bpt = NULL;
1539 // Set the breakpoint at the closest position after that line. 1666 ASSERT(first_token_idx <= last_token_idx);
1540 last_token_idx = func.end_token_pos(); 1667 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) {
1668 bpt = SetBreakpoint(script, first_token_idx);
1669 first_token_idx++;
1541 } 1670 }
1542 return SetBreakpoint(func, first_token_idx, last_token_idx); 1671 if ((bpt == NULL) && FLAG_verbose_debug) {
1672 OS::Print("No executable code at line %" Pd " in '%s'\n",
1673 line_number, script_url.ToCString());
1674 }
1675 return bpt;
1543 } 1676 }
1544 1677
1545 1678
1546 intptr_t Debugger::CacheObject(const Object& obj) { 1679 intptr_t Debugger::CacheObject(const Object& obj) {
1547 ASSERT(obj_cache_ != NULL); 1680 ASSERT(obj_cache_ != NULL);
1548 return obj_cache_->AddObject(obj); 1681 return obj_cache_->AddObject(obj);
1549 } 1682 }
1550 1683
1551 1684
1552 bool Debugger::IsValidObjectId(intptr_t obj_id) { 1685 bool Debugger::IsValidObjectId(intptr_t obj_id) {
(...skipping 10 matching lines...) Expand all
1563 // TODO(hausner): Merge some of this functionality with the code in 1696 // TODO(hausner): Merge some of this functionality with the code in
1564 // dart_api_impl.cc. 1697 // dart_api_impl.cc.
1565 RawObject* Debugger::GetInstanceField(const Class& cls, 1698 RawObject* Debugger::GetInstanceField(const Class& cls,
1566 const String& field_name, 1699 const String& field_name,
1567 const Instance& object) { 1700 const Instance& object) {
1568 const Function& getter_func = 1701 const Function& getter_func =
1569 Function::Handle(cls.LookupGetterFunction(field_name)); 1702 Function::Handle(cls.LookupGetterFunction(field_name));
1570 ASSERT(!getter_func.IsNull()); 1703 ASSERT(!getter_func.IsNull());
1571 1704
1572 Object& result = Object::Handle(); 1705 Object& result = Object::Handle();
1573 LongJump* base = isolate_->long_jump_base();
1574 LongJump jump;
1575 isolate_->set_long_jump_base(&jump);
1576 bool saved_ignore_flag = ignore_breakpoints_; 1706 bool saved_ignore_flag = ignore_breakpoints_;
1577 ignore_breakpoints_ = true; 1707 ignore_breakpoints_ = true;
1708
1709 LongJumpScope jump;
1578 if (setjmp(*jump.Set()) == 0) { 1710 if (setjmp(*jump.Set()) == 0) {
1579 const Array& args = Array::Handle(Array::New(1)); 1711 const Array& args = Array::Handle(Array::New(1));
1580 args.SetAt(0, object); 1712 args.SetAt(0, object);
1581 result = DartEntry::InvokeFunction(getter_func, args); 1713 result = DartEntry::InvokeFunction(getter_func, args);
1582 } else { 1714 } else {
1583 result = isolate_->object_store()->sticky_error(); 1715 result = isolate_->object_store()->sticky_error();
1584 } 1716 }
1585 ignore_breakpoints_ = saved_ignore_flag; 1717 ignore_breakpoints_ = saved_ignore_flag;
1586 isolate_->set_long_jump_base(base);
1587 return result.raw(); 1718 return result.raw();
1588 } 1719 }
1589 1720
1590 1721
1591 RawObject* Debugger::GetStaticField(const Class& cls, 1722 RawObject* Debugger::GetStaticField(const Class& cls,
1592 const String& field_name) { 1723 const String& field_name) {
1593 const Field& fld = Field::Handle(cls.LookupStaticField(field_name)); 1724 const Field& fld = Field::Handle(cls.LookupStaticField(field_name));
1594 if (!fld.IsNull()) { 1725 if (!fld.IsNull()) {
1595 // Return the value in the field if it has been initialized already. 1726 // Return the value in the field if it has been initialized already.
1596 const Instance& value = Instance::Handle(fld.value()); 1727 const Instance& value = Instance::Handle(fld.value());
1597 ASSERT(value.raw() != Object::transition_sentinel().raw()); 1728 ASSERT(value.raw() != Object::transition_sentinel().raw());
1598 if (value.raw() != Object::sentinel().raw()) { 1729 if (value.raw() != Object::sentinel().raw()) {
1599 return value.raw(); 1730 return value.raw();
1600 } 1731 }
1601 } 1732 }
1602 // There is no field or the field has not been initialized yet. 1733 // There is no field or the field has not been initialized yet.
1603 // We must have a getter. Run the getter. 1734 // We must have a getter. Run the getter.
1604 const Function& getter_func = 1735 const Function& getter_func =
1605 Function::Handle(cls.LookupGetterFunction(field_name)); 1736 Function::Handle(cls.LookupGetterFunction(field_name));
1606 ASSERT(!getter_func.IsNull()); 1737 ASSERT(!getter_func.IsNull());
1607 if (getter_func.IsNull()) { 1738 if (getter_func.IsNull()) {
1608 return Object::null(); 1739 return Object::null();
1609 } 1740 }
1610 1741
1611 Object& result = Object::Handle(); 1742 Object& result = Object::Handle();
1612 LongJump* base = isolate_->long_jump_base();
1613 LongJump jump;
1614 isolate_->set_long_jump_base(&jump);
1615 bool saved_ignore_flag = ignore_breakpoints_; 1743 bool saved_ignore_flag = ignore_breakpoints_;
1616 ignore_breakpoints_ = true; 1744 ignore_breakpoints_ = true;
1745 LongJumpScope jump;
1617 if (setjmp(*jump.Set()) == 0) { 1746 if (setjmp(*jump.Set()) == 0) {
1618 result = DartEntry::InvokeFunction(getter_func, Object::empty_array()); 1747 result = DartEntry::InvokeFunction(getter_func, Object::empty_array());
1619 } else { 1748 } else {
1620 result = isolate_->object_store()->sticky_error(); 1749 result = isolate_->object_store()->sticky_error();
1621 } 1750 }
1622 ignore_breakpoints_ = saved_ignore_flag; 1751 ignore_breakpoints_ = saved_ignore_flag;
1623 isolate_->set_long_jump_base(base);
1624 return result.raw(); 1752 return result.raw();
1625 } 1753 }
1626 1754
1627 1755
1628 RawArray* Debugger::GetInstanceFields(const Instance& obj) { 1756 RawArray* Debugger::GetInstanceFields(const Instance& obj) {
1629 Class& cls = Class::Handle(obj.clazz()); 1757 Class& cls = Class::Handle(obj.clazz());
1630 Array& fields = Array::Handle(); 1758 Array& fields = Array::Handle();
1631 Field& field = Field::Handle(); 1759 Field& field = Field::Handle();
1632 const GrowableObjectArray& field_list = 1760 const GrowableObjectArray& field_list =
1633 GrowableObjectArray::Handle(GrowableObjectArray::New(8)); 1761 GrowableObjectArray::Handle(GrowableObjectArray::New(8));
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1752 cbpt = cbpt->next(); 1880 cbpt = cbpt->next();
1753 } 1881 }
1754 } 1882 }
1755 1883
1756 1884
1757 void Debugger::SetEventHandler(EventHandler* handler) { 1885 void Debugger::SetEventHandler(EventHandler* handler) {
1758 event_handler_ = handler; 1886 event_handler_ = handler;
1759 } 1887 }
1760 1888
1761 1889
1890 void Debugger::Pause(DebuggerEvent* event) {
1891 ASSERT(!IsPaused()); // No recursive pausing.
1892 ASSERT(obj_cache_ == NULL);
1893
1894 pause_event_ = event;
1895 obj_cache_ = new RemoteObjectCache(64);
1896
1897 (*event_handler_)(event);
1898
1899 pause_event_ = NULL;
1900 obj_cache_ = NULL; // Zone allocated
1901 }
1902
1903
1762 bool Debugger::IsDebuggable(const Function& func) { 1904 bool Debugger::IsDebuggable(const Function& func) {
1763 RawFunction::Kind fkind = func.kind(); 1905 RawFunction::Kind fkind = func.kind();
1764 if ((fkind == RawFunction::kImplicitGetter) || 1906 if ((fkind == RawFunction::kImplicitGetter) ||
1765 (fkind == RawFunction::kImplicitSetter) || 1907 (fkind == RawFunction::kImplicitSetter) ||
1766 (fkind == RawFunction::kImplicitStaticFinalGetter) || 1908 (fkind == RawFunction::kImplicitStaticFinalGetter) ||
1767 (fkind == RawFunction::kStaticInitializer) || 1909 (fkind == RawFunction::kStaticInitializer) ||
1768 (fkind == RawFunction::kMethodExtractor) || 1910 (fkind == RawFunction::kMethodExtractor) ||
1769 (fkind == RawFunction::kNoSuchMethodDispatcher) || 1911 (fkind == RawFunction::kNoSuchMethodDispatcher) ||
1770 (fkind == RawFunction::kInvokeFieldDispatcher)) { 1912 (fkind == RawFunction::kInvokeFieldDispatcher)) {
1771 return false; 1913 return false;
1772 } 1914 }
1773 const Class& cls = Class::Handle(func.Owner()); 1915 const Class& cls = Class::Handle(func.Owner());
1774 const Library& lib = Library::Handle(cls.library()); 1916 const Library& lib = Library::Handle(cls.library());
1775 return lib.IsDebuggable(); 1917 return lib.IsDebuggable();
1776 } 1918 }
1777 1919
1778 1920
1779 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, 1921 void Debugger::SignalPausedEvent(ActivationFrame* top_frame,
1780 SourceBreakpoint* bpt) { 1922 SourceBreakpoint* bpt) {
1781 resume_action_ = kContinue; 1923 resume_action_ = kContinue;
1782 isolate_->set_single_step(false); 1924 isolate_->set_single_step(false);
1783 ASSERT(!in_event_notification_); 1925 ASSERT(!IsPaused());
1784 ASSERT(obj_cache_ == NULL); 1926 ASSERT(obj_cache_ == NULL);
1785 in_event_notification_ = true;
1786 obj_cache_ = new RemoteObjectCache(64);
1787 DebuggerEvent event(kBreakpointReached); 1927 DebuggerEvent event(kBreakpointReached);
1788 event.top_frame = top_frame; 1928 event.top_frame = top_frame;
1789 event.breakpoint = bpt; 1929 event.breakpoint = bpt;
1790 (*event_handler_)(&event); 1930 Pause(&event);
1791 in_event_notification_ = false;
1792 obj_cache_ = NULL; // Remote object cache is zone allocated.
1793 } 1931 }
1794 1932
1795 1933
1796 void Debugger::SingleStepCallback() { 1934 void Debugger::SingleStepCallback() {
1797 ASSERT(resume_action_ == kSingleStep); 1935 ASSERT(resume_action_ == kSingleStep);
1798 ASSERT(isolate_->single_step()); 1936 ASSERT(isolate_->single_step());
1799 // We can't get here unless the debugger event handler enabled 1937 // We can't get here unless the debugger event handler enabled
1800 // single stepping. 1938 // single stepping.
1801 ASSERT(event_handler_ != NULL); 1939 ASSERT(event_handler_ != NULL);
1802 // Don't pause recursively. 1940 // Don't pause recursively.
1803 if (in_event_notification_) return; 1941 if (IsPaused()) return;
1804 1942
1805 // Check whether we are in a Dart function that the user is 1943 // Check whether we are in a Dart function that the user is
1806 // interested in. 1944 // interested in.
1807 ActivationFrame* frame = TopDartFrame(); 1945 ActivationFrame* frame = TopDartFrame();
1808 ASSERT(frame != NULL); 1946 ASSERT(frame != NULL);
1809 const Function& func = frame->function(); 1947 const Function& func = frame->function();
1810 if (!IsDebuggable(func)) { 1948 if (!IsDebuggable(func)) {
1811 return; 1949 return;
1812 } 1950 }
1813 if (frame->TokenPos() == Scanner::kDummyTokenIndex) { 1951 if (frame->TokenPos() == Scanner::kDummyTokenIndex) {
1814 return; 1952 return;
1815 } 1953 }
1816 1954
1817 if (FLAG_verbose_debug) { 1955 if (FLAG_verbose_debug) {
1818 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", 1956 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n",
1819 String::Handle(frame->SourceUrl()).ToCString(), 1957 String::Handle(frame->SourceUrl()).ToCString(),
1820 frame->LineNumber(), 1958 frame->LineNumber(),
1821 String::Handle(frame->QualifiedFunctionName()).ToCString(), 1959 String::Handle(frame->QualifiedFunctionName()).ToCString(),
1822 frame->TokenPos()); 1960 frame->TokenPos());
1823 } 1961 }
1824 1962
1963 ASSERT(stack_trace_ == NULL);
1825 stack_trace_ = CollectStackTrace(); 1964 stack_trace_ = CollectStackTrace();
1826 SignalPausedEvent(frame, NULL); 1965 SignalPausedEvent(frame, NULL);
1827 1966
1828 RemoveInternalBreakpoints(); 1967 RemoveInternalBreakpoints();
1829 if (resume_action_ == kStepOver) { 1968 if (resume_action_ == kStepOver) {
1830 InstrumentForStepping(func); 1969 InstrumentForStepping(func);
1831 } else if (resume_action_ == kStepOut) { 1970 } else if (resume_action_ == kStepOut) {
1832 if (stack_trace_->Length() > 1) { 1971 if (stack_trace_->Length() > 1) {
1833 ActivationFrame* caller_frame = stack_trace_->FrameAt(1); 1972 ActivationFrame* caller_frame = stack_trace_->FrameAt(1);
1834 InstrumentForStepping(caller_frame->function()); 1973 InstrumentForStepping(caller_frame->function());
1835 } 1974 }
1836 } 1975 }
1837 stack_trace_ = NULL; 1976 stack_trace_ = NULL;
1838 } 1977 }
1839 1978
1840 1979
1841 void Debugger::SignalBpReached() { 1980 void Debugger::SignalBpReached() {
1842 // We ignore this breakpoint when the VM is executing code invoked 1981 // We ignore this breakpoint when the VM is executing code invoked
1843 // by the debugger to evaluate variables values, or when we see a nested 1982 // by the debugger to evaluate variables values, or when we see a nested
1844 // breakpoint or exception event. 1983 // breakpoint or exception event.
1845 if (ignore_breakpoints_ || in_event_notification_) { 1984 if (ignore_breakpoints_ || IsPaused()) {
1846 return; 1985 return;
1847 } 1986 }
1848 DebuggerStackTrace* stack_trace = CollectStackTrace(); 1987 DebuggerStackTrace* stack_trace = CollectStackTrace();
1849 ASSERT(stack_trace->Length() > 0); 1988 ASSERT(stack_trace->Length() > 0);
1850 ActivationFrame* top_frame = stack_trace->FrameAt(0); 1989 ActivationFrame* top_frame = stack_trace->FrameAt(0);
1851 ASSERT(top_frame != NULL); 1990 ASSERT(top_frame != NULL);
1852 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); 1991 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc());
1853 ASSERT(bpt != NULL); 1992 ASSERT(bpt != NULL);
1854 1993
1855 bool report_bp = true; 1994 bool report_bp = true;
1856 if (bpt->IsInternal() && !IsDebuggable(top_frame->function())) { 1995 if (bpt->IsInternal() && !IsDebuggable(top_frame->function())) {
1857 report_bp = false; 1996 report_bp = false;
1858 } 1997 }
1859 if (FLAG_verbose_debug) { 1998 if (FLAG_verbose_debug) {
1860 OS::Print(">>> %s %s breakpoint at %s:%" Pd " " 1999 OS::Print(">>> %s %s breakpoint at %s:%" Pd " "
1861 "(token %" Pd ") (address %#" Px ")\n", 2000 "(token %" Pd ") (address %#" Px ")\n",
1862 report_bp ? "hit" : "ignore", 2001 report_bp ? "hit" : "ignore",
1863 bpt->IsInternal() ? "internal" : "user", 2002 bpt->IsInternal() ? "internal" : "user",
1864 String::Handle(bpt->SourceUrl()).ToCString(), 2003 String::Handle(bpt->SourceUrl()).ToCString(),
1865 bpt->LineNumber(), 2004 bpt->LineNumber(),
1866 bpt->token_pos(), 2005 bpt->token_pos(),
1867 top_frame->pc()); 2006 top_frame->pc());
1868 } 2007 }
1869 2008
1870 if (report_bp && (event_handler_ != NULL)) { 2009 if (report_bp && (event_handler_ != NULL)) {
2010 ASSERT(stack_trace_ == NULL);
1871 stack_trace_ = stack_trace; 2011 stack_trace_ = stack_trace;
1872 SignalPausedEvent(top_frame, bpt->src_bpt_); 2012 SignalPausedEvent(top_frame, bpt->src_bpt_);
1873 stack_trace_ = NULL; 2013 stack_trace_ = NULL;
1874 } 2014 }
1875 2015
1876 Function& func_to_instrument = Function::Handle(); 2016 Function& func_to_instrument = Function::Handle();
2017 if ((resume_action_ == kStepOver) &&
2018 (bpt->breakpoint_kind_ == PcDescriptors::kReturn)) {
2019 resume_action_ = kStepOut;
2020 }
1877 if (resume_action_ == kStepOver) { 2021 if (resume_action_ == kStepOver) {
1878 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { 2022 ASSERT(bpt->breakpoint_kind_ != PcDescriptors::kReturn);
1879 // Step over return is converted into a single step so we break at 2023 func_to_instrument = bpt->function();
1880 // the caller.
1881 SetSingleStep();
1882 } else {
1883 func_to_instrument = bpt->function();
1884 }
1885 } else if (resume_action_ == kStepOut) { 2024 } else if (resume_action_ == kStepOut) {
1886 if (stack_trace->Length() > 1) { 2025 if (stack_trace->Length() > 1) {
1887 ActivationFrame* caller_frame = stack_trace->FrameAt(1); 2026 ActivationFrame* caller_frame = stack_trace->FrameAt(1);
1888 func_to_instrument = caller_frame->function().raw(); 2027 func_to_instrument = caller_frame->function().raw();
1889 } 2028 }
1890 } else { 2029 } else {
1891 ASSERT((resume_action_ == kContinue) || (resume_action_ == kSingleStep)); 2030 ASSERT((resume_action_ == kContinue) || (resume_action_ == kSingleStep));
1892 // Nothing to do here. Any potential instrumentation will be removed 2031 // Nothing to do here. Any potential instrumentation will be removed
1893 // below. Single stepping is handled by the single step callback. 2032 // below. Single stepping is handled by the single step callback.
1894 } 2033 }
(...skipping 17 matching lines...) Expand all
1912 // This port will be used as a unique ID to represet the isolate in the 2051 // This port will be used as a unique ID to represet the isolate in the
1913 // debugger wire protocol messages. 2052 // debugger wire protocol messages.
1914 isolate_id_ = isolate->main_port(); 2053 isolate_id_ = isolate->main_port();
1915 initialized_ = true; 2054 initialized_ = true;
1916 2055
1917 // Signal isolate creation event. 2056 // Signal isolate creation event.
1918 SignalIsolateEvent(Debugger::kIsolateCreated); 2057 SignalIsolateEvent(Debugger::kIsolateCreated);
1919 } 2058 }
1920 2059
1921 2060
1922 static RawFunction* GetOriginalFunction(const Function& func) { 2061 // Return innermost closure contained in 'function' that contains
1923 if (func.IsClosureFunction()) { 2062 // the given token position.
1924 // Local functions (closures) in mixin functions do not have 2063 RawFunction* Debugger::FindInnermostClosure(const Function& function,
1925 // an original function they were cloned from. 2064 intptr_t token_pos) {
1926 // Note: this is a problem when a breakpoint is set in a mixed-in 2065 const Class& owner = Class::Handle(isolate_, function.Owner());
1927 // closure. The breakpoint is linked to the closure attached to the 2066 if (owner.closures() == GrowableObjectArray::null()) {
1928 // mixin application class, not the mixin class. When the same 2067 return Function::null();
1929 // closure is compiled for another mixin application class, we
1930 // don't find the breakpoint since we'll be looking in the
1931 // mixin class.
1932 return func.raw();
1933 } 2068 }
1934 const Class& origin_class = Class::Handle(func.origin()); 2069 // Note that we need to check that the closure is in the same
1935 if (origin_class.is_patch()) { 2070 // script as the outer function. We could have closures originating
1936 // Patched functions from patch classes are removed from the 2071 // in mixin classes whose source code is contained in a different
1937 // function array of the patch class, so we will not find an 2072 // script.
1938 // original function object. 2073 const Script& outer_origin = Script::Handle(isolate_, function.script());
1939 return func.raw(); 2074 const GrowableObjectArray& closures =
1940 } 2075 GrowableObjectArray::Handle(isolate_, owner.closures());
1941 const Array& functions = Array::Handle(origin_class.functions()); 2076 const intptr_t num_closures = closures.Length();
1942 Object& orig_func = Object::Handle(); 2077 Function& closure = Function::Handle(isolate_);
1943 for (intptr_t i = 0; i < functions.Length(); i++) { 2078 Function& best_fit = Function::Handle(isolate_);
1944 orig_func = functions.At(i); 2079 for (intptr_t i = 0; i < num_closures; i++) {
1945 // Function names are symbols, so we can compare the raw pointers. 2080 closure ^= closures.At(i);
1946 if (func.name() == Function::Cast(orig_func).name()) { 2081 if ((function.token_pos() < closure.token_pos()) &&
1947 return Function::Cast(orig_func).raw(); 2082 (closure.end_token_pos() < function.end_token_pos()) &&
2083 (closure.token_pos() <= token_pos) &&
2084 (token_pos <= closure.end_token_pos()) &&
2085 (closure.script() == outer_origin.raw())) {
2086 SelectBestFit(&best_fit, &closure);
1948 } 2087 }
1949 } 2088 }
1950 // Uncommon case: not a mixin function. 2089 return best_fit.raw();
1951 ASSERT(!Class::Handle(func.Owner()).IsMixinApplication());
1952 return func.raw();
1953 } 2090 }
1954 2091
1955 2092
1956 void Debugger::NotifyCompilation(const Function& func) { 2093 void Debugger::NotifyCompilation(const Function& func) {
1957 if (src_breakpoints_ == NULL) { 2094 if (src_breakpoints_ == NULL) {
1958 // Return with minimal overhead if there are no breakpoints. 2095 // Return with minimal overhead if there are no breakpoints.
1959 return; 2096 return;
1960 } 2097 }
1961 Function& lookup_function = Function::Handle(func.raw()); 2098 // Iterate over all source breakpoints to check whether breakpoints
1962 if (func.IsImplicitClosureFunction()) { 2099 // need to be set in the newly compiled function.
1963 // If the newly compiled function is a an implicit closure (a closure that 2100 Script& script = Script::Handle(isolate_);
1964 // was formed by assigning a static or instance method to a function 2101 for (SourceBreakpoint* bpt = src_breakpoints_;
1965 // object), we need to use the closure's parent function to see whether 2102 bpt != NULL;
1966 // there are any breakpoints. The parent function is the actual method on 2103 bpt = bpt->next()) {
1967 // which the user sets breakpoints. 2104 script = bpt->script();
1968 lookup_function = func.parent_function(); 2105 if (FunctionContains(func, script, bpt->token_pos())) {
1969 ASSERT(!lookup_function.IsNull()); 2106 Function& inner_function = Function::Handle(isolate_);
1970 } 2107 inner_function = FindInnermostClosure(func, bpt->token_pos());
1971 if (lookup_function.Owner() != lookup_function.origin()) { 2108 if (!inner_function.IsNull()) {
1972 // This is a cloned function from a mixin class. If a breakpoint 2109 // The local function of a function we just compiled cannot
1973 // was set in this function, it is registered using the function 2110 // be compiled already.
1974 // of the origin class. 2111 ASSERT(!inner_function.HasCode());
1975 lookup_function = GetOriginalFunction(lookup_function);
1976 }
1977 SourceBreakpoint* bpt = src_breakpoints_;
1978 while (bpt != NULL) {
1979 if (lookup_function.raw() == bpt->function()) {
1980 // Check if the breakpoint is inside a closure or local function
1981 // within the newly compiled function. Note that we must look
1982 // in the owner class of the function that just got compiled
1983 // (i.e. func), not the owner class of the function we use to
1984 // record the breakpoint (lookup_function).
1985 Class& owner = Class::Handle(func.Owner());
1986 Function& closure =
1987 Function::Handle(owner.LookupClosureFunction(bpt->token_pos()));
1988 if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) {
1989 if (FLAG_verbose_debug) { 2112 if (FLAG_verbose_debug) {
1990 OS::Print("Resetting pending breakpoint to function %s\n", 2113 OS::Print("Pending BP remains unresolved in inner function '%s'\n",
1991 closure.ToFullyQualifiedCString()); 2114 inner_function.ToFullyQualifiedCString());
1992 } 2115 }
1993 bpt->set_function(closure); 2116 continue;
1994 } else { 2117 }
2118
2119 // TODO(hausner): What should we do if function is optimized?
2120 // Can we deoptimize the function?
2121 ASSERT(!func.HasOptimizedCode());
2122
2123 // There is no local function within func that contains the
2124 // breakpoint token position. Resolve the breakpoint if necessary
2125 // and set the code breakpoints.
2126 if (!bpt->IsResolved()) {
2127 // Resolve source breakpoint in the newly compiled function.
2128 intptr_t bp_pos = ResolveBreakpointPos(func, bpt->token_pos());
2129 if (bp_pos < 0) {
2130 if (FLAG_verbose_debug) {
2131 OS::Print("Failed resolving breakpoint for function '%s'\n",
2132 String::Handle(func.name()).ToCString());
2133 }
2134 continue;
2135 }
2136 intptr_t requested_pos = bpt->token_pos();
2137 bpt->SetResolved(func, bp_pos);
1995 if (FLAG_verbose_debug) { 2138 if (FLAG_verbose_debug) {
1996 OS::Print("Enable pending breakpoint for function '%s'\n", 2139 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", "
1997 String::Handle(lookup_function.name()).ToCString()); 2140 "function '%s' (requested pos %" Pd ")\n",
2141 bpt->id(),
2142 bpt->token_pos(),
2143 bpt->LineNumber(),
2144 func.ToFullyQualifiedCString(),
2145 requested_pos);
1998 } 2146 }
1999 const Script& script= Script::Handle(func.script());
2000 intptr_t first_pos, last_pos;
2001 script.TokenRangeAtLine(bpt->LineNumber(), &first_pos, &last_pos);
2002 intptr_t bp_pos =
2003 ResolveBreakpointPos(func, bpt->token_pos(), last_pos);
2004 bpt->set_token_pos(bp_pos);
2005 MakeCodeBreakpointsAt(func, bp_pos, bpt);
2006 SignalBpResolved(bpt); 2147 SignalBpResolved(bpt);
2007 } 2148 }
2008 bpt->Enable(); // Enables the code breakpoint as well. 2149 ASSERT(bpt->IsResolved());
2150 if (FLAG_verbose_debug) {
2151 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n",
2152 bpt->id(),
2153 bpt->LineNumber(),
2154 func.IsClosureFunction() ? "closure" : "function",
2155 String::Handle(func.name()).ToCString());
2156 }
2157 MakeCodeBreakpointsAt(func, bpt);
2009 } 2158 }
2010 bpt = bpt->next();
2011 } 2159 }
2012 } 2160 }
2013 2161
2014 2162
2015 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { 2163 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) {
2016 CodeBreakpoint* bpt = code_breakpoints_; 2164 CodeBreakpoint* bpt = code_breakpoints_;
2017 while (bpt != NULL) { 2165 while (bpt != NULL) {
2018 if (bpt->pc() == breakpoint_address) { 2166 if (bpt->pc() == breakpoint_address) {
2019 return bpt; 2167 return bpt;
2020 } 2168 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
2094 temp_bpt->Disable(); 2242 temp_bpt->Disable();
2095 delete temp_bpt; 2243 delete temp_bpt;
2096 } else { 2244 } else {
2097 prev_bpt = curr_bpt; 2245 prev_bpt = curr_bpt;
2098 curr_bpt = curr_bpt->next(); 2246 curr_bpt = curr_bpt->next();
2099 } 2247 }
2100 } 2248 }
2101 } 2249 }
2102 2250
2103 2251
2104 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func, 2252 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Script& script,
2105 intptr_t token_pos) { 2253 intptr_t token_pos) {
2106 SourceBreakpoint* bpt = src_breakpoints_; 2254 SourceBreakpoint* bpt = src_breakpoints_;
2107 while (bpt != NULL) { 2255 while (bpt != NULL) {
2108 if ((bpt->function() == func.raw()) && 2256 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) {
2109 (bpt->token_pos() == token_pos)) {
2110 return bpt; 2257 return bpt;
2111 } 2258 }
2112 bpt = bpt->next(); 2259 bpt = bpt->next();
2113 } 2260 }
2114 return NULL; 2261 return NULL;
2115 } 2262 }
2116 2263
2117 2264
2118 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { 2265 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) {
2119 SourceBreakpoint* bpt = src_breakpoints_; 2266 SourceBreakpoint* bpt = src_breakpoints_;
(...skipping 14 matching lines...) Expand all
2134 } 2281 }
2135 2282
2136 2283
2137 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { 2284 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
2138 ASSERT(bpt->next() == NULL); 2285 ASSERT(bpt->next() == NULL);
2139 bpt->set_next(code_breakpoints_); 2286 bpt->set_next(code_breakpoints_);
2140 code_breakpoints_ = bpt; 2287 code_breakpoints_ = bpt;
2141 } 2288 }
2142 2289
2143 } // namespace dart 2290 } // namespace dart
OLDNEW
« no previous file with comments | « dart/runtime/vm/debugger.h ('k') | dart/runtime/vm/debugger_api_impl_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698