OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/debugger.h" | 5 #include "vm/debugger.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 | 8 |
9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 } | 56 } |
57 | 57 |
58 private: | 58 private: |
59 GrowableObjectArray* objs_; | 59 GrowableObjectArray* objs_; |
60 | 60 |
61 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 61 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
62 }; | 62 }; |
63 | 63 |
64 | 64 |
65 // Create an unresolved breakpoint in given token range and script. | 65 // Create an unresolved breakpoint in given token range and script. |
66 BreakpointLocation::BreakpointLocation(const Script& script, | 66 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
67 intptr_t token_pos, | 67 const Script& script, |
68 intptr_t end_token_pos) | 68 intptr_t token_pos, |
69 : script_(script.raw()), | 69 intptr_t end_token_pos) |
| 70 : id_(id), |
| 71 script_(script.raw()), |
70 url_(script.url()), | 72 url_(script.url()), |
71 token_pos_(token_pos), | 73 token_pos_(token_pos), |
72 end_token_pos_(end_token_pos), | 74 end_token_pos_(end_token_pos), |
73 is_resolved_(false), | 75 is_resolved_(false), |
| 76 is_enabled_(false), |
| 77 is_one_shot_(false), |
74 next_(NULL), | 78 next_(NULL), |
75 conditions_(NULL), | |
76 function_(Function::null()), | 79 function_(Function::null()), |
77 line_number_(-1) { | 80 line_number_(-1) { |
| 81 ASSERT(id_ > 0); |
78 ASSERT(!script.IsNull()); | 82 ASSERT(!script.IsNull()); |
79 ASSERT(token_pos_ >= 0); | 83 ASSERT(token_pos_ >= 0); |
80 } | 84 } |
81 | 85 |
82 // Create a latent breakpoint at given url and line number. | 86 // Create a latent breakpoint at given url and line number. |
83 BreakpointLocation::BreakpointLocation(const String& url, | 87 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
84 intptr_t line_number) | 88 const String& url, |
85 : script_(Script::null()), | 89 intptr_t line_number) |
| 90 : id_(id), |
| 91 script_(Script::null()), |
86 url_(url.raw()), | 92 url_(url.raw()), |
87 token_pos_(-1), | 93 token_pos_(-1), |
88 end_token_pos_(-1), | 94 end_token_pos_(-1), |
89 is_resolved_(false), | 95 is_resolved_(false), |
| 96 is_enabled_(false), |
| 97 is_one_shot_(false), |
90 next_(NULL), | 98 next_(NULL), |
91 conditions_(NULL), | |
92 function_(Function::null()), | 99 function_(Function::null()), |
93 line_number_(line_number) { | 100 line_number_(line_number) { |
| 101 ASSERT(id >= 0); |
94 ASSERT(line_number_ >= 0); | 102 ASSERT(line_number_ >= 0); |
95 } | 103 } |
96 | 104 |
97 | 105 void SourceBreakpoint::Enable() { |
98 BreakpointLocation::~BreakpointLocation() { | 106 is_enabled_ = true; |
99 Breakpoint* bpt = breakpoints(); | 107 Isolate::Current()->debugger()->SyncBreakpoint(this); |
100 while (bpt != NULL) { | |
101 Breakpoint* temp = bpt; | |
102 bpt = bpt->next(); | |
103 delete temp; | |
104 } | |
105 } | 108 } |
106 | 109 |
107 | 110 |
108 bool BreakpointLocation::AnyEnabled() const { | 111 void SourceBreakpoint::Disable() { |
109 return breakpoints() != NULL; | 112 is_enabled_ = false; |
| 113 Isolate::Current()->debugger()->SyncBreakpoint(this); |
110 } | 114 } |
111 | 115 |
112 | 116 |
113 void BreakpointLocation::SetResolved(const Function& func, intptr_t token_pos) { | 117 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) { |
114 ASSERT(!IsLatent()); | 118 ASSERT(!IsLatent()); |
115 ASSERT(func.script() == script_); | 119 ASSERT(func.script() == script_); |
116 ASSERT((func.token_pos() <= token_pos) && | 120 ASSERT((func.token_pos() <= token_pos) && |
117 (token_pos <= func.end_token_pos())); | 121 (token_pos <= func.end_token_pos())); |
118 ASSERT(func.is_debuggable()); | 122 ASSERT(func.is_debuggable()); |
119 function_ = func.raw(); | 123 function_ = func.raw(); |
120 token_pos_ = token_pos; | 124 token_pos_ = token_pos; |
121 end_token_pos_ = token_pos; | 125 end_token_pos_ = token_pos; |
122 line_number_ = -1; // Recalculate lazily. | 126 line_number_ = -1; // Recalculate lazily. |
123 is_resolved_ = true; | 127 is_resolved_ = true; |
124 } | 128 } |
125 | 129 |
126 | 130 |
127 // TODO(hausner): Get rid of library parameter. A source breakpoint location | 131 // TODO(hausner): Get rid of library parameter. A source breakpoint location |
128 // does not imply a library, since the same source code can be included | 132 // does not imply a library, since the same source code can be included |
129 // in more than one library, e.g. the text location of mixin functions. | 133 // in more than one library, e.g. the text location of mixin functions. |
130 void BreakpointLocation::GetCodeLocation(Library* lib, | 134 void SourceBreakpoint::GetCodeLocation(Library* lib, |
131 Script* script, | 135 Script* script, |
132 intptr_t* pos) { | 136 intptr_t* pos) { |
133 if (IsLatent()) { | 137 if (IsLatent()) { |
134 *lib = Library::null(); | 138 *lib = Library::null(); |
135 *script = Script::null(); | 139 *script = Script::null(); |
136 *pos = -1; | 140 *pos = -1; |
137 } else { | 141 } else { |
138 *script = this->script(); | 142 *script = this->script(); |
139 *pos = token_pos_; | 143 *pos = token_pos_; |
140 if (IsResolved()) { | 144 if (IsResolved()) { |
141 const Function& func = Function::Handle(function_); | 145 const Function& func = Function::Handle(function_); |
142 ASSERT(!func.IsNull()); | 146 ASSERT(!func.IsNull()); |
143 const Class& cls = Class::Handle(func.origin()); | 147 const Class& cls = Class::Handle(func.origin()); |
144 *lib = cls.library(); | 148 *lib = cls.library(); |
145 } else { | 149 } else { |
146 *lib = Library::null(); | 150 *lib = Library::null(); |
147 } | 151 } |
148 } | 152 } |
149 } | 153 } |
150 | 154 |
151 | 155 |
152 intptr_t BreakpointLocation::LineNumber() { | 156 intptr_t SourceBreakpoint::LineNumber() { |
153 // Latent breakpoints must have a requested line number >= 0. | 157 // Latent breakpoints must have a requested line number >= 0. |
154 ASSERT(!IsLatent() || line_number_ >= 0); | 158 ASSERT(!IsLatent() || line_number_ >= 0); |
155 // Compute line number lazily since it causes scanning of the script. | 159 // Compute line number lazily since it causes scanning of the script. |
156 if (line_number_ < 0) { | 160 if (line_number_ < 0) { |
157 const Script& script = Script::Handle(this->script()); | 161 const Script& script = Script::Handle(this->script()); |
158 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 162 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
159 } | 163 } |
160 return line_number_; | 164 return line_number_; |
161 } | 165 } |
162 | 166 |
163 | 167 |
164 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { | 168 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
165 ASSERT(bpt_location_->IsLatent()); // Only reason to move. | 169 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
166 bpt_location_ = new_bpt_location; | 170 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); |
| 171 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
167 } | 172 } |
168 | 173 |
169 | 174 |
170 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 175 void SourceBreakpoint::PrintJSON(JSONStream* stream) { |
171 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); | |
172 } | |
173 | |
174 | |
175 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { | |
176 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | |
177 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); | |
178 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | |
179 | |
180 Breakpoint* bpt = conditions_; | |
181 while (bpt != NULL) { | |
182 bpt -> VisitObjectPointers(visitor); | |
183 bpt = bpt->next(); | |
184 } | |
185 } | |
186 | |
187 | |
188 void Breakpoint::PrintJSON(JSONStream* stream) { | |
189 Isolate* isolate = Isolate::Current(); | 176 Isolate* isolate = Isolate::Current(); |
190 | 177 |
191 JSONObject jsobj(stream); | 178 JSONObject jsobj(stream); |
192 jsobj.AddProperty("type", "Breakpoint"); | 179 jsobj.AddProperty("type", "Breakpoint"); |
193 | 180 |
194 jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id()); | 181 jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id()); |
195 jsobj.AddProperty("breakpointNumber", id()); | 182 jsobj.AddProperty("breakpointNumber", id()); |
196 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); | 183 jsobj.AddProperty("resolved", IsResolved()); |
197 | 184 |
198 Library& library = Library::Handle(isolate); | 185 Library& library = Library::Handle(isolate); |
199 Script& script = Script::Handle(isolate); | 186 Script& script = Script::Handle(isolate); |
200 intptr_t token_pos; | 187 intptr_t token_pos; |
201 bpt_location_->GetCodeLocation(&library, &script, &token_pos); | 188 GetCodeLocation(&library, &script, &token_pos); |
202 { | 189 { |
203 JSONObject location(&jsobj, "location"); | 190 JSONObject location(&jsobj, "location"); |
204 location.AddProperty("type", "Location"); | 191 location.AddProperty("type", "Location"); |
205 location.AddProperty("script", script); | 192 location.AddProperty("script", script); |
206 location.AddProperty("tokenPos", token_pos); | 193 location.AddProperty("tokenPos", token_pos); |
207 } | 194 } |
208 } | 195 } |
209 | 196 |
210 | 197 |
211 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 198 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 Debugger* debugger = Isolate::Current()->debugger(); | 287 Debugger* debugger = Isolate::Current()->debugger(); |
301 ASSERT(debugger != NULL); | 288 ASSERT(debugger != NULL); |
302 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); | 289 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); |
303 } | 290 } |
304 } | 291 } |
305 | 292 |
306 | 293 |
307 // The vm service handles breakpoint notifications in a different way | 294 // The vm service handles breakpoint notifications in a different way |
308 // than the regular debugger breakpoint notifications. | 295 // than the regular debugger breakpoint notifications. |
309 static void SendServiceBreakpointEvent(ServiceEvent::EventType type, | 296 static void SendServiceBreakpointEvent(ServiceEvent::EventType type, |
310 Breakpoint* bpt) { | 297 SourceBreakpoint* bpt) { |
311 if (Service::NeedsEvents()) { | 298 if (Service::NeedsEvents()) { |
312 ServiceEvent service_event(Isolate::Current(), type); | 299 ServiceEvent service_event(Isolate::Current(), type); |
313 service_event.set_breakpoint(bpt); | 300 service_event.set_breakpoint(bpt); |
314 Service::HandleEvent(&service_event); | 301 Service::HandleEvent(&service_event); |
315 } | 302 } |
316 } | 303 } |
317 | 304 |
318 | 305 |
319 void BreakpointLocation::AddBreakpoint(Breakpoint* bpt, Debugger* dbg) { | |
320 bpt->set_next(breakpoints()); | |
321 set_breakpoints(bpt); | |
322 | |
323 dbg->SyncBreakpointLocation(this); | |
324 | |
325 if (IsResolved()) { | |
326 dbg->SignalBpResolved(bpt); | |
327 } | |
328 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
329 } | |
330 | |
331 | |
332 Breakpoint* BreakpointLocation::AddRepeated(Debugger* dbg) { | |
333 Breakpoint* bpt = breakpoints(); | |
334 while (bpt != NULL) { | |
335 if (bpt->IsRepeated()) break; | |
336 bpt = bpt->next(); | |
337 } | |
338 if (bpt == NULL) { | |
339 bpt = new Breakpoint(dbg->nextId(), this); | |
340 bpt->SetIsRepeated(); | |
341 AddBreakpoint(bpt, dbg); | |
342 } | |
343 return bpt; | |
344 } | |
345 | |
346 | |
347 Breakpoint* BreakpointLocation::AddSingleShot(Debugger* dbg) { | |
348 Breakpoint* bpt = breakpoints(); | |
349 while (bpt != NULL) { | |
350 if (bpt->IsSingleShot()) break; | |
351 bpt = bpt->next(); | |
352 } | |
353 if (bpt == NULL) { | |
354 bpt = new Breakpoint(dbg->nextId(), this); | |
355 bpt->SetIsSingleShot(); | |
356 AddBreakpoint(bpt, dbg); | |
357 } | |
358 return bpt; | |
359 } | |
360 | |
361 | |
362 Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg, | |
363 const Instance& closure) { | |
364 Breakpoint* bpt = breakpoints(); | |
365 while (bpt != NULL) { | |
366 if (bpt->IsPerClosure() && bpt->closure() == closure.raw()) break; | |
367 bpt = bpt->next(); | |
368 } | |
369 if (bpt == NULL) { | |
370 bpt = new Breakpoint(dbg->nextId(), this); | |
371 bpt->SetIsPerClosure(closure); | |
372 AddBreakpoint(bpt, dbg); | |
373 } | |
374 return bpt; | |
375 } | |
376 | |
377 | |
378 const char* Debugger::QualifiedFunctionName(const Function& func) { | 306 const char* Debugger::QualifiedFunctionName(const Function& func) { |
379 const String& func_name = String::Handle(func.name()); | 307 const String& func_name = String::Handle(func.name()); |
380 Class& func_class = Class::Handle(func.Owner()); | 308 Class& func_class = Class::Handle(func.Owner()); |
381 String& class_name = String::Handle(func_class.Name()); | 309 String& class_name = String::Handle(func_class.Name()); |
382 | 310 |
383 const char* kFormat = "%s%s%s"; | 311 const char* kFormat = "%s%s%s"; |
384 intptr_t len = OS::SNPrint(NULL, 0, kFormat, | 312 intptr_t len = OS::SNPrint(NULL, 0, kFormat, |
385 func_class.IsTopLevel() ? "" : class_name.ToCString(), | 313 func_class.IsTopLevel() ? "" : class_name.ToCString(), |
386 func_class.IsTopLevel() ? "" : ".", | 314 func_class.IsTopLevel() ? "" : ".", |
387 func_name.ToCString()); | 315 func_name.ToCString()); |
(...skipping 20 matching lines...) Expand all Loading... |
408 } | 336 } |
409 | 337 |
410 | 338 |
411 bool Debugger::HasBreakpoint(const Function& func) { | 339 bool Debugger::HasBreakpoint(const Function& func) { |
412 if (!func.HasCode()) { | 340 if (!func.HasCode()) { |
413 // If the function is not compiled yet, just check whether there | 341 // If the function is not compiled yet, just check whether there |
414 // is a user-defined breakpoint that falls into the token | 342 // is a user-defined breakpoint that falls into the token |
415 // range of the function. This may be a false positive: the breakpoint | 343 // range of the function. This may be a false positive: the breakpoint |
416 // might be inside a local closure. | 344 // might be inside a local closure. |
417 Script& script = Script::Handle(isolate_); | 345 Script& script = Script::Handle(isolate_); |
418 BreakpointLocation* sbpt = breakpoint_locations_; | 346 SourceBreakpoint* sbpt = src_breakpoints_; |
419 while (sbpt != NULL) { | 347 while (sbpt != NULL) { |
420 script = sbpt->script(); | 348 script = sbpt->script(); |
421 if (FunctionContains(func, script, sbpt->token_pos())) { | 349 if (FunctionContains(func, script, sbpt->token_pos())) { |
422 return true; | 350 return true; |
423 } | 351 } |
424 sbpt = sbpt->next_; | 352 sbpt = sbpt->next_; |
425 } | 353 } |
426 return false; | 354 return false; |
427 } | 355 } |
428 CodeBreakpoint* cbpt = code_breakpoints_; | 356 CodeBreakpoint* cbpt = code_breakpoints_; |
(...skipping 13 matching lines...) Expand all Loading... |
442 if (code.raw() == cbpt->code_) { | 370 if (code.raw() == cbpt->code_) { |
443 return true; | 371 return true; |
444 } | 372 } |
445 cbpt = cbpt->next_; | 373 cbpt = cbpt->next_; |
446 } | 374 } |
447 return false; | 375 return false; |
448 } | 376 } |
449 | 377 |
450 | 378 |
451 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { | 379 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { |
452 BreakpointLocation* sbpt = breakpoint_locations_; | 380 SourceBreakpoint* sbpt = src_breakpoints_; |
453 while (sbpt != NULL) { | 381 while (sbpt != NULL) { |
454 Breakpoint* bpt = sbpt->breakpoints(); | 382 jsarr->AddValue(sbpt); |
455 while (bpt != NULL) { | |
456 jsarr->AddValue(bpt); | |
457 bpt = bpt->next(); | |
458 } | |
459 sbpt = sbpt->next_; | 383 sbpt = sbpt->next_; |
460 } | 384 } |
461 } | 385 } |
462 | 386 |
463 | 387 |
464 RawString* ActivationFrame::QualifiedFunctionName() { | 388 RawString* ActivationFrame::QualifiedFunctionName() { |
465 return String::New(Debugger::QualifiedFunctionName(function())); | 389 return String::New(Debugger::QualifiedFunctionName(function())); |
466 } | 390 } |
467 | 391 |
468 | 392 |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 vars_initialized_ = true; | 669 vars_initialized_ = true; |
746 } | 670 } |
747 | 671 |
748 | 672 |
749 intptr_t ActivationFrame::NumLocalVariables() { | 673 intptr_t ActivationFrame::NumLocalVariables() { |
750 GetDescIndices(); | 674 GetDescIndices(); |
751 return desc_indices_.length(); | 675 return desc_indices_.length(); |
752 } | 676 } |
753 | 677 |
754 | 678 |
755 RawObject* ActivationFrame::GetParameter(intptr_t index) { | |
756 intptr_t num_parameters = function().num_fixed_parameters(); | |
757 ASSERT(0 <= index && index < num_parameters); | |
758 intptr_t reverse_index = num_parameters - index; | |
759 | |
760 if (function().NumOptionalParameters() > 0) { | |
761 // If the function has optional parameters, the first positional parameter | |
762 // can be in a number of places in the caller's frame depending on how many | |
763 // were actually supplied at the call site, but they are copied to a fixed | |
764 // place in the callee's frame. | |
765 uword var_address = fp() + ((kFirstLocalSlotFromFp - index) * kWordSize); | |
766 return reinterpret_cast<RawObject*>( | |
767 *reinterpret_cast<uword*>(var_address)); | |
768 } else { | |
769 uword var_address = fp() + (kParamEndSlotFromFp * kWordSize) | |
770 + (reverse_index * kWordSize); | |
771 return reinterpret_cast<RawObject*>( | |
772 *reinterpret_cast<uword*>(var_address)); | |
773 } | |
774 } | |
775 | |
776 | |
777 RawObject* ActivationFrame::GetClosure() { | |
778 ASSERT(function().IsClosureFunction()); | |
779 return GetParameter(0); | |
780 } | |
781 | |
782 | |
783 RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) { | 679 RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) { |
784 if (deopt_frame_.IsNull()) { | 680 if (deopt_frame_.IsNull()) { |
785 uword var_address = fp() + slot_index * kWordSize; | 681 uword var_address = fp() + slot_index * kWordSize; |
786 return reinterpret_cast<RawObject*>( | 682 return reinterpret_cast<RawObject*>( |
787 *reinterpret_cast<uword*>(var_address)); | 683 *reinterpret_cast<uword*>(var_address)); |
788 } else { | 684 } else { |
789 return deopt_frame_.At(deopt_frame_offset_ + slot_index); | 685 return deopt_frame_.At(deopt_frame_offset_ + slot_index); |
790 } | 686 } |
791 } | 687 } |
792 | 688 |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 | 939 |
1044 CodeBreakpoint::CodeBreakpoint(const Code& code, | 940 CodeBreakpoint::CodeBreakpoint(const Code& code, |
1045 intptr_t token_pos, | 941 intptr_t token_pos, |
1046 uword pc, | 942 uword pc, |
1047 RawPcDescriptors::Kind kind) | 943 RawPcDescriptors::Kind kind) |
1048 : code_(code.raw()), | 944 : code_(code.raw()), |
1049 token_pos_(token_pos), | 945 token_pos_(token_pos), |
1050 pc_(pc), | 946 pc_(pc), |
1051 line_number_(-1), | 947 line_number_(-1), |
1052 is_enabled_(false), | 948 is_enabled_(false), |
1053 bpt_location_(NULL), | 949 src_bpt_(NULL), |
1054 next_(NULL), | 950 next_(NULL), |
1055 breakpoint_kind_(kind), | 951 breakpoint_kind_(kind), |
1056 saved_value_(0) { | 952 saved_value_(0) { |
1057 ASSERT(!code.IsNull()); | 953 ASSERT(!code.IsNull()); |
1058 ASSERT(token_pos_ > 0); | 954 ASSERT(token_pos_ > 0); |
1059 ASSERT(pc_ != 0); | 955 ASSERT(pc_ != 0); |
1060 ASSERT((breakpoint_kind_ & kSafepointKind) != 0); | 956 ASSERT((breakpoint_kind_ & kSafepointKind) != 0); |
1061 } | 957 } |
1062 | 958 |
1063 | 959 |
1064 CodeBreakpoint::~CodeBreakpoint() { | 960 CodeBreakpoint::~CodeBreakpoint() { |
1065 // Make sure we don't leave patched code behind. | 961 // Make sure we don't leave patched code behind. |
1066 ASSERT(!IsEnabled()); | 962 ASSERT(!IsEnabled()); |
1067 // Poison the data so we catch use after free errors. | 963 // Poison the data so we catch use after free errors. |
1068 #ifdef DEBUG | 964 #ifdef DEBUG |
1069 code_ = Code::null(); | 965 code_ = Code::null(); |
1070 pc_ = 0ul; | 966 pc_ = 0ul; |
1071 bpt_location_ = NULL; | 967 src_bpt_ = NULL; |
1072 next_ = NULL; | 968 next_ = NULL; |
1073 breakpoint_kind_ = RawPcDescriptors::kOther; | 969 breakpoint_kind_ = RawPcDescriptors::kOther; |
1074 #endif | 970 #endif |
1075 } | 971 } |
1076 | 972 |
1077 | 973 |
1078 RawFunction* CodeBreakpoint::function() const { | 974 RawFunction* CodeBreakpoint::function() const { |
1079 return Code::Handle(code_).function(); | 975 return Code::Handle(code_).function(); |
1080 } | 976 } |
1081 | 977 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 ASSERT(IsValidId(obj_id)); | 1036 ASSERT(IsValidId(obj_id)); |
1141 return objs_->At(obj_id); | 1037 return objs_->At(obj_id); |
1142 } | 1038 } |
1143 | 1039 |
1144 | 1040 |
1145 Debugger::Debugger() | 1041 Debugger::Debugger() |
1146 : isolate_(NULL), | 1042 : isolate_(NULL), |
1147 isolate_id_(ILLEGAL_ISOLATE_ID), | 1043 isolate_id_(ILLEGAL_ISOLATE_ID), |
1148 initialized_(false), | 1044 initialized_(false), |
1149 next_id_(1), | 1045 next_id_(1), |
1150 latent_locations_(NULL), | 1046 latent_breakpoints_(NULL), |
1151 breakpoint_locations_(NULL), | 1047 src_breakpoints_(NULL), |
1152 code_breakpoints_(NULL), | 1048 code_breakpoints_(NULL), |
1153 resume_action_(kContinue), | 1049 resume_action_(kContinue), |
1154 ignore_breakpoints_(false), | 1050 ignore_breakpoints_(false), |
1155 pause_event_(NULL), | 1051 pause_event_(NULL), |
1156 obj_cache_(NULL), | 1052 obj_cache_(NULL), |
1157 stack_trace_(NULL), | 1053 stack_trace_(NULL), |
1158 stepping_fp_(0), | 1054 stepping_fp_(0), |
1159 exc_pause_info_(kNoPauseOnExceptions) { | 1055 exc_pause_info_(kNoPauseOnExceptions) { |
1160 } | 1056 } |
1161 | 1057 |
1162 | 1058 |
1163 Debugger::~Debugger() { | 1059 Debugger::~Debugger() { |
1164 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1060 isolate_id_ = ILLEGAL_ISOLATE_ID; |
1165 ASSERT(!IsPaused()); | 1061 ASSERT(!IsPaused()); |
1166 ASSERT(latent_locations_ == NULL); | 1062 ASSERT(latent_breakpoints_ == NULL); |
1167 ASSERT(breakpoint_locations_ == NULL); | 1063 ASSERT(src_breakpoints_ == NULL); |
1168 ASSERT(code_breakpoints_ == NULL); | 1064 ASSERT(code_breakpoints_ == NULL); |
1169 ASSERT(stack_trace_ == NULL); | 1065 ASSERT(stack_trace_ == NULL); |
1170 ASSERT(obj_cache_ == NULL); | 1066 ASSERT(obj_cache_ == NULL); |
1171 } | 1067 } |
1172 | 1068 |
1173 | 1069 |
1174 void Debugger::Shutdown() { | 1070 void Debugger::Shutdown() { |
1175 while (breakpoint_locations_ != NULL) { | 1071 while (src_breakpoints_ != NULL) { |
1176 BreakpointLocation* bpt = breakpoint_locations_; | 1072 SourceBreakpoint* bpt = src_breakpoints_; |
1177 breakpoint_locations_ = breakpoint_locations_->next(); | 1073 src_breakpoints_ = src_breakpoints_->next(); |
1178 delete bpt; | 1074 delete bpt; |
1179 } | 1075 } |
1180 while (latent_locations_ != NULL) { | 1076 while (latent_breakpoints_ != NULL) { |
1181 BreakpointLocation* bpt = latent_locations_; | 1077 SourceBreakpoint* bpt = latent_breakpoints_; |
1182 latent_locations_ = latent_locations_->next(); | 1078 latent_breakpoints_ = latent_breakpoints_->next(); |
1183 delete bpt; | 1079 delete bpt; |
1184 } | 1080 } |
1185 while (code_breakpoints_ != NULL) { | 1081 while (code_breakpoints_ != NULL) { |
1186 CodeBreakpoint* bpt = code_breakpoints_; | 1082 CodeBreakpoint* bpt = code_breakpoints_; |
1187 code_breakpoints_ = code_breakpoints_->next(); | 1083 code_breakpoints_ = code_breakpoints_->next(); |
1188 bpt->Disable(); | 1084 bpt->Disable(); |
1189 delete bpt; | 1085 delete bpt; |
1190 } | 1086 } |
1191 // Signal isolate shutdown event. | 1087 // Signal isolate shutdown event. |
1192 if (!ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 1088 if (!ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1290 if (function.HasOptimizedCode()) { | 1186 if (function.HasOptimizedCode()) { |
1291 function.SwitchToUnoptimizedCode(); | 1187 function.SwitchToUnoptimizedCode(); |
1292 } | 1188 } |
1293 } | 1189 } |
1294 } | 1190 } |
1295 } | 1191 } |
1296 } | 1192 } |
1297 } | 1193 } |
1298 | 1194 |
1299 | 1195 |
1300 void Debugger::SignalBpResolved(Breakpoint* bpt) { | 1196 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { |
1301 if (HasEventHandler() && !bpt->IsSingleShot()) { | 1197 if (HasEventHandler() && !bpt->IsOneShot()) { |
1302 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); | 1198 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); |
1303 event.set_breakpoint(bpt); | 1199 event.set_breakpoint(bpt); |
1304 InvokeEventHandler(&event); | 1200 InvokeEventHandler(&event); |
1305 } | 1201 } |
1306 } | 1202 } |
1307 | 1203 |
1308 | 1204 |
1309 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1205 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
1310 uword pc, | 1206 uword pc, |
1311 StackFrame* frame, | 1207 StackFrame* frame, |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1609 // We didn't find a safe point in the given token range. Try and find | 1505 // We didn't find a safe point in the given token range. Try and find |
1610 // a safe point in the remaining source code of the function. | 1506 // a safe point in the remaining source code of the function. |
1611 if (last_token_pos < func.end_token_pos()) { | 1507 if (last_token_pos < func.end_token_pos()) { |
1612 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos()); | 1508 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos()); |
1613 } | 1509 } |
1614 return -1; | 1510 return -1; |
1615 } | 1511 } |
1616 | 1512 |
1617 | 1513 |
1618 void Debugger::MakeCodeBreakpointAt(const Function& func, | 1514 void Debugger::MakeCodeBreakpointAt(const Function& func, |
1619 BreakpointLocation* loc) { | 1515 SourceBreakpoint* bpt) { |
1620 ASSERT(loc->token_pos_ != Scanner::kNoSourcePos); | 1516 ASSERT(bpt->token_pos_ != Scanner::kNoSourcePos); |
1621 ASSERT((loc != NULL) && loc->IsResolved()); | 1517 ASSERT((bpt != NULL) && bpt->IsResolved()); |
1622 ASSERT(!func.HasOptimizedCode()); | 1518 ASSERT(!func.HasOptimizedCode()); |
1623 Code& code = Code::Handle(func.unoptimized_code()); | 1519 Code& code = Code::Handle(func.unoptimized_code()); |
1624 ASSERT(!code.IsNull()); | 1520 ASSERT(!code.IsNull()); |
1625 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1521 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
1626 uword lowest_pc_offset = kUwordMax; | 1522 uword lowest_pc_offset = kUwordMax; |
1627 RawPcDescriptors::Kind lowest_kind = RawPcDescriptors::kAnyKind; | 1523 RawPcDescriptors::Kind lowest_kind = RawPcDescriptors::kAnyKind; |
1628 // Find the safe point with the lowest compiled code address | 1524 // Find the safe point with the lowest compiled code address |
1629 // that maps to the token position of the source breakpoint. | 1525 // that maps to the token position of the source breakpoint. |
1630 PcDescriptors::Iterator iter(desc, kSafepointKind); | 1526 PcDescriptors::Iterator iter(desc, kSafepointKind); |
1631 while (iter.MoveNext()) { | 1527 while (iter.MoveNext()) { |
1632 if (iter.TokenPos() == loc->token_pos_) { | 1528 if (iter.TokenPos() == bpt->token_pos_) { |
1633 if (iter.PcOffset() < lowest_pc_offset) { | 1529 if (iter.PcOffset() < lowest_pc_offset) { |
1634 lowest_pc_offset = iter.PcOffset(); | 1530 lowest_pc_offset = iter.PcOffset(); |
1635 lowest_kind = iter.Kind(); | 1531 lowest_kind = iter.Kind(); |
1636 } | 1532 } |
1637 } | 1533 } |
1638 } | 1534 } |
1639 if (lowest_pc_offset == kUwordMax) { | 1535 if (lowest_pc_offset == kUwordMax) { |
1640 return; | 1536 return; |
1641 } | 1537 } |
1642 uword lowest_pc = code.EntryPoint() + lowest_pc_offset; | 1538 uword lowest_pc = code.EntryPoint() + lowest_pc_offset; |
1643 CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_pc); | 1539 CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_pc); |
1644 if (code_bpt == NULL) { | 1540 if (code_bpt == NULL) { |
1645 // No code breakpoint for this code exists; create one. | 1541 // No code breakpoint for this code exists; create one. |
1646 code_bpt = new CodeBreakpoint(code, loc->token_pos_, | 1542 code_bpt = new CodeBreakpoint(code, bpt->token_pos_, |
1647 lowest_pc, lowest_kind); | 1543 lowest_pc, lowest_kind); |
1648 RegisterCodeBreakpoint(code_bpt); | 1544 RegisterCodeBreakpoint(code_bpt); |
1649 } | 1545 } |
1650 code_bpt->set_bpt_location(loc); | 1546 code_bpt->set_src_bpt(bpt); |
1651 if (loc->AnyEnabled()) { | 1547 if (bpt->IsEnabled()) { |
1652 code_bpt->Enable(); | 1548 code_bpt->Enable(); |
1653 } | 1549 } |
1654 } | 1550 } |
1655 | 1551 |
1656 | 1552 |
1657 void Debugger::FindCompiledFunctions(const Script& script, | 1553 void Debugger::FindCompiledFunctions(const Script& script, |
1658 intptr_t start_pos, | 1554 intptr_t start_pos, |
1659 intptr_t end_pos, | 1555 intptr_t end_pos, |
1660 GrowableObjectArray* function_list) { | 1556 GrowableObjectArray* function_list) { |
1661 Class& cls = Class::Handle(isolate_); | 1557 Class& cls = Class::Handle(isolate_); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1793 SelectBestFit(&best_fit, &function); | 1689 SelectBestFit(&best_fit, &function); |
1794 } | 1690 } |
1795 } | 1691 } |
1796 } | 1692 } |
1797 } | 1693 } |
1798 } | 1694 } |
1799 return best_fit.raw(); | 1695 return best_fit.raw(); |
1800 } | 1696 } |
1801 | 1697 |
1802 | 1698 |
1803 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, | 1699 SourceBreakpoint* Debugger::SetBreakpoint(const Script& script, |
1804 intptr_t token_pos, | 1700 intptr_t token_pos, |
1805 intptr_t last_token_pos) { | 1701 intptr_t last_token_pos) { |
1806 Function& func = Function::Handle(isolate_); | 1702 Function& func = Function::Handle(isolate_); |
1807 func = FindBestFit(script, token_pos); | 1703 func = FindBestFit(script, token_pos); |
1808 if (func.IsNull()) { | 1704 if (func.IsNull()) { |
1809 return NULL; | 1705 return NULL; |
1810 } | 1706 } |
1811 // There may be more than one function object for a given function | 1707 // There may be more than one function object for a given function |
1812 // in source code. There may be implicit closure functions, and | 1708 // in source code. There may be implicit closure functions, and |
1813 // there may be copies of mixin functions. Collect all compiled | 1709 // there may be copies of mixin functions. Collect all compiled |
1814 // functions whose source code range matches exactly the best fit | 1710 // functions whose source code range matches exactly the best fit |
1815 // function we found. | 1711 // function we found. |
1816 GrowableObjectArray& functions = | 1712 GrowableObjectArray& functions = |
1817 GrowableObjectArray::Handle(GrowableObjectArray::New()); | 1713 GrowableObjectArray::Handle(GrowableObjectArray::New()); |
1818 FindCompiledFunctions(script, | 1714 FindCompiledFunctions(script, |
1819 func.token_pos(), | 1715 func.token_pos(), |
1820 func.end_token_pos(), | 1716 func.end_token_pos(), |
1821 &functions); | 1717 &functions); |
1822 | 1718 |
1823 if (functions.Length() > 0) { | 1719 if (functions.Length() > 0) { |
1824 // One or more function object containing this breakpoint location | 1720 // One or more function object containing this breakpoint location |
1825 // have already been compiled. We can resolve the breakpoint now. | 1721 // have already been compiled. We can resolve the breakpoint now. |
1826 DeoptimizeWorld(); | 1722 DeoptimizeWorld(); |
1827 func ^= functions.At(0); | 1723 func ^= functions.At(0); |
1828 intptr_t breakpoint_pos = | 1724 intptr_t breakpoint_pos = |
1829 ResolveBreakpointPos(func, token_pos, last_token_pos); | 1725 ResolveBreakpointPos(func, token_pos, last_token_pos); |
1830 if (breakpoint_pos >= 0) { | 1726 if (breakpoint_pos >= 0) { |
1831 BreakpointLocation* bpt = GetBreakpointLocation(script, breakpoint_pos); | 1727 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); |
1832 if (bpt != NULL) { | 1728 if (bpt != NULL) { |
1833 // A source breakpoint for this location already exists. | 1729 // A source breakpoint for this location already exists. |
1834 return bpt; | 1730 return bpt; |
1835 } | 1731 } |
1836 bpt = new BreakpointLocation(script, token_pos, last_token_pos); | 1732 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos); |
1837 bpt->SetResolved(func, breakpoint_pos); | 1733 bpt->SetResolved(func, breakpoint_pos); |
1838 RegisterBreakpointLocation(bpt); | 1734 RegisterSourceBreakpoint(bpt); |
1839 | 1735 |
1840 // Create code breakpoints for all compiled functions we found. | 1736 // Create code breakpoints for all compiled functions we found. |
1841 const intptr_t num_functions = functions.Length(); | 1737 const intptr_t num_functions = functions.Length(); |
1842 for (intptr_t i = 0; i < num_functions; i++) { | 1738 for (intptr_t i = 0; i < num_functions; i++) { |
1843 func ^= functions.At(i); | 1739 func ^= functions.At(i); |
1844 ASSERT(func.HasCode()); | 1740 ASSERT(func.HasCode()); |
1845 MakeCodeBreakpointAt(func, bpt); | 1741 MakeCodeBreakpointAt(func, bpt); |
1846 } | 1742 } |
| 1743 bpt->Enable(); |
1847 if (FLAG_verbose_debug) { | 1744 if (FLAG_verbose_debug) { |
1848 intptr_t line_number; | 1745 intptr_t line_number; |
1849 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); | 1746 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); |
1850 OS::Print("Resolved BP for " | 1747 OS::Print("Resolved BP for " |
1851 "function '%s' at line %" Pd "\n", | 1748 "function '%s' at line %" Pd "\n", |
1852 func.ToFullyQualifiedCString(), | 1749 func.ToFullyQualifiedCString(), |
1853 line_number); | 1750 line_number); |
1854 } | 1751 } |
| 1752 SignalBpResolved(bpt); |
| 1753 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); |
1855 return bpt; | 1754 return bpt; |
1856 } | 1755 } |
1857 } | 1756 } |
1858 // There is no compiled function at this token position. | 1757 // There is no compiled function at this token position. |
1859 // Register an unresolved breakpoint. | 1758 // Register an unresolved breakpoint. |
1860 if (FLAG_verbose_debug && !func.IsNull()) { | 1759 if (FLAG_verbose_debug && !func.IsNull()) { |
1861 intptr_t line_number; | 1760 intptr_t line_number; |
1862 script.GetTokenLocation(token_pos, &line_number, NULL); | 1761 script.GetTokenLocation(token_pos, &line_number, NULL); |
1863 OS::Print("Registering pending breakpoint for " | 1762 OS::Print("Registering pending breakpoint for " |
1864 "uncompiled function '%s' at line %" Pd "\n", | 1763 "uncompiled function '%s' at line %" Pd "\n", |
1865 func.ToFullyQualifiedCString(), | 1764 func.ToFullyQualifiedCString(), |
1866 line_number); | 1765 line_number); |
1867 } | 1766 } |
1868 BreakpointLocation* bpt = GetBreakpointLocation(script, token_pos); | 1767 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); |
1869 if (bpt == NULL) { | 1768 if (bpt == NULL) { |
1870 bpt = new BreakpointLocation(script, token_pos, last_token_pos); | 1769 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos); |
1871 RegisterBreakpointLocation(bpt); | 1770 RegisterSourceBreakpoint(bpt); |
| 1771 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); |
1872 } | 1772 } |
| 1773 bpt->Enable(); |
1873 return bpt; | 1774 return bpt; |
1874 } | 1775 } |
1875 | 1776 |
1876 | 1777 |
1877 // Synchronize the enabled/disabled state of all code breakpoints | 1778 // Synchronize the enabled/disabled state of all code breakpoints |
1878 // associated with the breakpoint location loc. | 1779 // associated with the source breakpoint bpt. |
1879 void Debugger::SyncBreakpointLocation(BreakpointLocation* loc) { | 1780 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
1880 bool any_enabled = loc->AnyEnabled(); | |
1881 | |
1882 CodeBreakpoint* cbpt = code_breakpoints_; | 1781 CodeBreakpoint* cbpt = code_breakpoints_; |
1883 while (cbpt != NULL) { | 1782 while (cbpt != NULL) { |
1884 if (loc == cbpt->bpt_location()) { | 1783 if (bpt == cbpt->src_bpt()) { |
1885 if (any_enabled) { | 1784 if (bpt->IsEnabled()) { |
1886 cbpt->Enable(); | 1785 cbpt->Enable(); |
1887 } else { | 1786 } else { |
1888 cbpt->Disable(); | 1787 cbpt->Disable(); |
1889 } | 1788 } |
1890 } | 1789 } |
1891 cbpt = cbpt->next(); | 1790 cbpt = cbpt->next(); |
1892 } | 1791 } |
1893 } | 1792 } |
1894 | 1793 |
1895 | 1794 |
1896 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { | 1795 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { |
1897 LongJumpScope jump; | 1796 LongJumpScope jump; |
1898 if (setjmp(*jump.Set()) == 0) { | 1797 if (setjmp(*jump.Set()) == 0) { |
1899 SetBreakpointAtEntry(target_function, true); | 1798 SourceBreakpoint* bpt = SetBreakpointAtEntry(target_function); |
| 1799 if (bpt != NULL) { |
| 1800 bpt->SetIsOneShot(); |
| 1801 } |
1900 return Error::null(); | 1802 return Error::null(); |
1901 } else { | 1803 } else { |
1902 return isolate_->object_store()->sticky_error(); | 1804 return isolate_->object_store()->sticky_error(); |
1903 } | 1805 } |
1904 } | 1806 } |
1905 | 1807 |
1906 | 1808 |
1907 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, | 1809 SourceBreakpoint* Debugger::SetBreakpointAtEntry( |
1908 bool single_shot) { | 1810 const Function& target_function) { |
1909 ASSERT(!target_function.IsNull()); | 1811 ASSERT(!target_function.IsNull()); |
1910 if (!target_function.is_debuggable()) { | 1812 if (!target_function.is_debuggable()) { |
1911 return NULL; | 1813 return NULL; |
1912 } | 1814 } |
1913 const Script& script = Script::Handle(target_function.script()); | 1815 const Script& script = Script::Handle(target_function.script()); |
1914 BreakpointLocation* bpt_location = | 1816 return SetBreakpoint(script, |
1915 SetBreakpoint(script, | 1817 target_function.token_pos(), |
1916 target_function.token_pos(), | 1818 target_function.end_token_pos()); |
1917 target_function.end_token_pos()); | |
1918 if (single_shot) { | |
1919 return bpt_location->AddSingleShot(this); | |
1920 } else { | |
1921 return bpt_location->AddRepeated(this); | |
1922 } | |
1923 } | 1819 } |
1924 | 1820 |
1925 | 1821 |
1926 Breakpoint* Debugger::SetBreakpointAtActivation( | 1822 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
1927 const Instance& closure) { | 1823 intptr_t line_number) { |
1928 if (!closure.IsClosure()) { | |
1929 return NULL; | |
1930 } | |
1931 const Function& func = Function::Handle(Closure::function(closure)); | |
1932 const Script& script = Script::Handle(func.script()); | |
1933 BreakpointLocation* bpt = SetBreakpoint(script, | |
1934 func.token_pos(), | |
1935 func.end_token_pos()); | |
1936 return bpt->AddPerClosure(this, closure); | |
1937 } | |
1938 | |
1939 | |
1940 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | |
1941 intptr_t line_number) { | |
1942 BreakpointLocation* bpt = BreakpointLocationAtLine(script_url, line_number); | |
1943 return bpt->AddRepeated(this); | |
1944 } | |
1945 | |
1946 | |
1947 BreakpointLocation* Debugger::BreakpointLocationAtLine(const String& script_url, | |
1948 intptr_t line_number) { | |
1949 Library& lib = Library::Handle(isolate_); | 1824 Library& lib = Library::Handle(isolate_); |
1950 Script& script = Script::Handle(isolate_); | 1825 Script& script = Script::Handle(isolate_); |
1951 const GrowableObjectArray& libs = | 1826 const GrowableObjectArray& libs = |
1952 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 1827 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
1953 const GrowableObjectArray& scripts = | 1828 const GrowableObjectArray& scripts = |
1954 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); | 1829 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); |
1955 for (intptr_t i = 0; i < libs.Length(); i++) { | 1830 for (intptr_t i = 0; i < libs.Length(); i++) { |
1956 lib ^= libs.At(i); | 1831 lib ^= libs.At(i); |
1957 script = lib.LookupScript(script_url); | 1832 script = lib.LookupScript(script_url); |
1958 if (!script.IsNull()) { | 1833 if (!script.IsNull()) { |
1959 scripts.Add(script); | 1834 scripts.Add(script); |
1960 } | 1835 } |
1961 } | 1836 } |
1962 if (scripts.Length() == 0) { | 1837 if (scripts.Length() == 0) { |
1963 // No script found with given url. Create a latent breakpoint which | 1838 // No script found with given url. Create a latent breakpoint which |
1964 // will be set if the url is loaded later. | 1839 // will be set if the url is loaded later. |
1965 BreakpointLocation* latent_bpt = GetLatentBreakpoint(script_url, | 1840 SourceBreakpoint* latent_bpt = GetLatentBreakpoint(script_url, line_number); |
1966 line_number); | |
1967 if (FLAG_verbose_debug) { | 1841 if (FLAG_verbose_debug) { |
1968 OS::Print("Set latent breakpoint in url '%s' at line %" Pd "\n", | 1842 OS::Print("Set latent breakpoint in url '%s' at line %" Pd "\n", |
1969 script_url.ToCString(), | 1843 script_url.ToCString(), |
1970 line_number); | 1844 line_number); |
1971 } | 1845 } |
1972 return latent_bpt; | 1846 return latent_bpt; |
1973 } | 1847 } |
1974 if (scripts.Length() > 1) { | 1848 if (scripts.Length() > 1) { |
1975 if (FLAG_verbose_debug) { | 1849 if (FLAG_verbose_debug) { |
1976 OS::Print("Multiple scripts match url '%s'\n", script_url.ToCString()); | 1850 OS::Print("Multiple scripts match url '%s'\n", script_url.ToCString()); |
(...skipping 12 matching lines...) Expand all Loading... |
1989 return NULL; | 1863 return NULL; |
1990 } else if (last_token_idx < 0) { | 1864 } else if (last_token_idx < 0) { |
1991 // Line does not contain any tokens. | 1865 // Line does not contain any tokens. |
1992 if (FLAG_verbose_debug) { | 1866 if (FLAG_verbose_debug) { |
1993 OS::Print("No executable code at line %" Pd " in '%s'\n", | 1867 OS::Print("No executable code at line %" Pd " in '%s'\n", |
1994 line_number, script_url.ToCString()); | 1868 line_number, script_url.ToCString()); |
1995 } | 1869 } |
1996 return NULL; | 1870 return NULL; |
1997 } | 1871 } |
1998 | 1872 |
1999 BreakpointLocation* bpt = NULL; | 1873 SourceBreakpoint* bpt = NULL; |
2000 ASSERT(first_token_idx <= last_token_idx); | 1874 ASSERT(first_token_idx <= last_token_idx); |
2001 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) { | 1875 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) { |
2002 bpt = SetBreakpoint(script, first_token_idx, last_token_idx); | 1876 bpt = SetBreakpoint(script, first_token_idx, last_token_idx); |
2003 first_token_idx++; | 1877 first_token_idx++; |
2004 } | 1878 } |
2005 if ((bpt == NULL) && FLAG_verbose_debug) { | 1879 if ((bpt == NULL) && FLAG_verbose_debug) { |
2006 OS::Print("No executable code at line %" Pd " in '%s'\n", | 1880 OS::Print("No executable code at line %" Pd " in '%s'\n", |
2007 line_number, script_url.ToCString()); | 1881 line_number, script_url.ToCString()); |
2008 } | 1882 } |
2009 return bpt; | 1883 return bpt; |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2203 CollectLibraryFields(field_list, imported, prefix_name, false); | 2077 CollectLibraryFields(field_list, imported, prefix_name, false); |
2204 } | 2078 } |
2205 } | 2079 } |
2206 return Array::MakeArray(field_list); | 2080 return Array::MakeArray(field_list); |
2207 } | 2081 } |
2208 | 2082 |
2209 | 2083 |
2210 // static | 2084 // static |
2211 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 2085 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
2212 ASSERT(visitor != NULL); | 2086 ASSERT(visitor != NULL); |
2213 BreakpointLocation* bpt = breakpoint_locations_; | 2087 SourceBreakpoint* bpt = src_breakpoints_; |
2214 while (bpt != NULL) { | 2088 while (bpt != NULL) { |
2215 bpt->VisitObjectPointers(visitor); | 2089 bpt->VisitObjectPointers(visitor); |
2216 bpt = bpt->next(); | 2090 bpt = bpt->next(); |
2217 } | 2091 } |
2218 bpt = latent_locations_; | 2092 bpt = latent_breakpoints_; |
2219 while (bpt != NULL) { | 2093 while (bpt != NULL) { |
2220 bpt->VisitObjectPointers(visitor); | 2094 bpt->VisitObjectPointers(visitor); |
2221 bpt = bpt->next(); | 2095 bpt = bpt->next(); |
2222 } | 2096 } |
2223 CodeBreakpoint* cbpt = code_breakpoints_; | 2097 CodeBreakpoint* cbpt = code_breakpoints_; |
2224 while (cbpt != NULL) { | 2098 while (cbpt != NULL) { |
2225 cbpt->VisitObjectPointers(visitor); | 2099 cbpt->VisitObjectPointers(visitor); |
2226 cbpt = cbpt->next(); | 2100 cbpt = cbpt->next(); |
2227 } | 2101 } |
2228 } | 2102 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2291 if (ServiceIsolate::IsRunning()) { | 2165 if (ServiceIsolate::IsRunning()) { |
2292 return true; | 2166 return true; |
2293 } | 2167 } |
2294 const Class& cls = Class::Handle(func.Owner()); | 2168 const Class& cls = Class::Handle(func.Owner()); |
2295 const Library& lib = Library::Handle(cls.library()); | 2169 const Library& lib = Library::Handle(cls.library()); |
2296 return lib.IsDebuggable(); | 2170 return lib.IsDebuggable(); |
2297 } | 2171 } |
2298 | 2172 |
2299 | 2173 |
2300 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, | 2174 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, |
2301 Breakpoint* bpt) { | 2175 SourceBreakpoint* bpt) { |
2302 resume_action_ = kContinue; | 2176 resume_action_ = kContinue; |
2303 stepping_fp_ = 0; | 2177 stepping_fp_ = 0; |
2304 isolate_->set_single_step(false); | 2178 isolate_->set_single_step(false); |
2305 ASSERT(!IsPaused()); | 2179 ASSERT(!IsPaused()); |
2306 ASSERT(obj_cache_ == NULL); | 2180 ASSERT(obj_cache_ == NULL); |
2307 if ((bpt != NULL) && bpt->IsSingleShot()) { | 2181 if ((bpt != NULL) && bpt->IsOneShot()) { |
2308 RemoveBreakpoint(bpt->id()); | 2182 RemoveBreakpoint(bpt->id()); |
2309 bpt = NULL; | 2183 bpt = NULL; |
2310 } | 2184 } |
2311 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2185 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); |
2312 event.set_top_frame(top_frame); | 2186 event.set_top_frame(top_frame); |
2313 event.set_breakpoint(bpt); | 2187 event.set_breakpoint(bpt); |
2314 Pause(&event); | 2188 Pause(&event); |
2315 } | 2189 } |
2316 | 2190 |
2317 | 2191 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2379 // We ignore this breakpoint when the VM is executing code invoked | 2253 // We ignore this breakpoint when the VM is executing code invoked |
2380 // by the debugger to evaluate variables values, or when we see a nested | 2254 // by the debugger to evaluate variables values, or when we see a nested |
2381 // breakpoint or exception event. | 2255 // breakpoint or exception event. |
2382 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { | 2256 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { |
2383 return; | 2257 return; |
2384 } | 2258 } |
2385 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2259 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
2386 ASSERT(stack_trace->Length() > 0); | 2260 ASSERT(stack_trace->Length() > 0); |
2387 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 2261 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
2388 ASSERT(top_frame != NULL); | 2262 ASSERT(top_frame != NULL); |
2389 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); | 2263 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); |
2390 ASSERT(cbpt != NULL); | 2264 ASSERT(bpt != NULL); |
2391 | |
2392 BreakpointLocation* bpt_location = cbpt->bpt_location_; | |
2393 Breakpoint* bpt_hit = NULL; | |
2394 | |
2395 // There may be more than one applicable breakpoint at this location, but we | |
2396 // will report only one as reached. If there is a single-shot breakpoint, we | |
2397 // favor it; then a closure-specific breakpoint ; then an general breakpoint. | |
2398 if (bpt_location != NULL) { | |
2399 Breakpoint* bpt = bpt_location->breakpoints(); | |
2400 while (bpt != NULL) { | |
2401 if (bpt->IsSingleShot()) { | |
2402 bpt_hit = bpt; | |
2403 break; | |
2404 } | |
2405 bpt = bpt->next(); | |
2406 } | |
2407 | |
2408 if (bpt_hit == NULL) { | |
2409 bpt = bpt_location->breakpoints(); | |
2410 while (bpt != NULL) { | |
2411 if (bpt->IsPerClosure()) { | |
2412 Object& closure = Object::Handle(top_frame->GetClosure()); | |
2413 ASSERT(closure.IsInstance()); | |
2414 ASSERT(Instance::Cast(closure).IsClosure()); | |
2415 if (closure.raw() == bpt->closure()) { | |
2416 bpt_hit = bpt; | |
2417 break; | |
2418 } | |
2419 } | |
2420 bpt = bpt->next(); | |
2421 } | |
2422 } | |
2423 | |
2424 if (bpt_hit == NULL) { | |
2425 bpt = bpt_location->breakpoints(); | |
2426 while (bpt != NULL) { | |
2427 if (bpt->IsRepeated()) { | |
2428 bpt_hit = bpt; | |
2429 break; | |
2430 } | |
2431 bpt = bpt->next(); | |
2432 } | |
2433 } | |
2434 } | |
2435 | |
2436 if (bpt_hit == NULL) { | |
2437 return; | |
2438 } | |
2439 | 2265 |
2440 if (FLAG_verbose_debug) { | 2266 if (FLAG_verbose_debug) { |
2441 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " | 2267 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
2442 "(token %" Pd ") (address %#" Px ")\n", | 2268 "(token %" Pd ") (address %#" Px ")\n", |
2443 cbpt->IsInternal() ? "internal" : "user", | 2269 bpt->IsInternal() ? "internal" : "user", |
2444 String::Handle(cbpt->SourceUrl()).ToCString(), | 2270 String::Handle(bpt->SourceUrl()).ToCString(), |
2445 cbpt->LineNumber(), | 2271 bpt->LineNumber(), |
2446 cbpt->token_pos(), | 2272 bpt->token_pos(), |
2447 top_frame->pc()); | 2273 top_frame->pc()); |
2448 } | 2274 } |
2449 | 2275 |
2450 ASSERT(stack_trace_ == NULL); | 2276 ASSERT(stack_trace_ == NULL); |
2451 stack_trace_ = stack_trace; | 2277 stack_trace_ = stack_trace; |
2452 SignalPausedEvent(top_frame, bpt_hit); | 2278 SignalPausedEvent(top_frame, bpt->src_bpt_); |
2453 HandleSteppingRequest(stack_trace_); | 2279 HandleSteppingRequest(stack_trace_); |
2454 stack_trace_ = NULL; | 2280 stack_trace_ = NULL; |
2455 if (cbpt->IsInternal()) { | 2281 if (bpt->IsInternal()) { |
2456 RemoveInternalBreakpoints(); | 2282 RemoveInternalBreakpoints(); |
2457 } | 2283 } |
2458 } | 2284 } |
2459 | 2285 |
2460 | 2286 |
2461 void Debugger::BreakHere(const String& msg) { | 2287 void Debugger::BreakHere(const String& msg) { |
2462 // We ignore this breakpoint when the VM is executing code invoked | 2288 // We ignore this breakpoint when the VM is executing code invoked |
2463 // by the debugger to evaluate variables values, or when we see a nested | 2289 // by the debugger to evaluate variables values, or when we see a nested |
2464 // breakpoint or exception event. | 2290 // breakpoint or exception event. |
2465 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { | 2291 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2531 (token_pos <= closure.end_token_pos()) && | 2357 (token_pos <= closure.end_token_pos()) && |
2532 (closure.script() == outer_origin.raw())) { | 2358 (closure.script() == outer_origin.raw())) { |
2533 SelectBestFit(&best_fit, &closure); | 2359 SelectBestFit(&best_fit, &closure); |
2534 } | 2360 } |
2535 } | 2361 } |
2536 return best_fit.raw(); | 2362 return best_fit.raw(); |
2537 } | 2363 } |
2538 | 2364 |
2539 | 2365 |
2540 void Debugger::NotifyCompilation(const Function& func) { | 2366 void Debugger::NotifyCompilation(const Function& func) { |
2541 if (breakpoint_locations_ == NULL) { | 2367 if (src_breakpoints_ == NULL) { |
2542 // Return with minimal overhead if there are no breakpoints. | 2368 // Return with minimal overhead if there are no breakpoints. |
2543 return; | 2369 return; |
2544 } | 2370 } |
2545 if (!func.is_debuggable()) { | 2371 if (!func.is_debuggable()) { |
2546 // Nothing to do if the function is not debuggable. If there is | 2372 // Nothing to do if the function is not debuggable. If there is |
2547 // a pending breakpoint in an inner function (that is debuggable), | 2373 // a pending breakpoint in an inner function (that is debuggable), |
2548 // we'll resolve the breakpoint when the inner function is compiled. | 2374 // we'll resolve the breakpoint when the inner function is compiled. |
2549 return; | 2375 return; |
2550 } | 2376 } |
2551 // Iterate over all source breakpoints to check whether breakpoints | 2377 // Iterate over all source breakpoints to check whether breakpoints |
2552 // need to be set in the newly compiled function. | 2378 // need to be set in the newly compiled function. |
2553 Script& script = Script::Handle(isolate_); | 2379 Script& script = Script::Handle(isolate_); |
2554 for (BreakpointLocation* loc = breakpoint_locations_; | 2380 for (SourceBreakpoint* bpt = src_breakpoints_; |
2555 loc != NULL; | 2381 bpt != NULL; |
2556 loc = loc->next()) { | 2382 bpt = bpt->next()) { |
2557 script = loc->script(); | 2383 script = bpt->script(); |
2558 if (FunctionContains(func, script, loc->token_pos())) { | 2384 if (FunctionContains(func, script, bpt->token_pos())) { |
2559 Function& inner_function = Function::Handle(isolate_); | 2385 Function& inner_function = Function::Handle(isolate_); |
2560 inner_function = FindInnermostClosure(func, loc->token_pos()); | 2386 inner_function = FindInnermostClosure(func, bpt->token_pos()); |
2561 if (!inner_function.IsNull()) { | 2387 if (!inner_function.IsNull()) { |
2562 // The local function of a function we just compiled cannot | 2388 // The local function of a function we just compiled cannot |
2563 // be compiled already. | 2389 // be compiled already. |
2564 ASSERT(!inner_function.HasCode()); | 2390 ASSERT(!inner_function.HasCode()); |
2565 if (FLAG_verbose_debug) { | 2391 if (FLAG_verbose_debug) { |
2566 OS::Print("Pending BP remains unresolved in inner function '%s'\n", | 2392 OS::Print("Pending BP remains unresolved in inner function '%s'\n", |
2567 inner_function.ToFullyQualifiedCString()); | 2393 inner_function.ToFullyQualifiedCString()); |
2568 } | 2394 } |
2569 continue; | 2395 continue; |
2570 } | 2396 } |
2571 | 2397 |
2572 // TODO(hausner): What should we do if function is optimized? | 2398 // TODO(hausner): What should we do if function is optimized? |
2573 // Can we deoptimize the function? | 2399 // Can we deoptimize the function? |
2574 ASSERT(!func.HasOptimizedCode()); | 2400 ASSERT(!func.HasOptimizedCode()); |
2575 | 2401 |
2576 // There is no local function within func that contains the | 2402 // There is no local function within func that contains the |
2577 // breakpoint token position. Resolve the breakpoint if necessary | 2403 // breakpoint token position. Resolve the breakpoint if necessary |
2578 // and set the code breakpoints. | 2404 // and set the code breakpoints. |
2579 if (!loc->IsResolved()) { | 2405 if (!bpt->IsResolved()) { |
2580 // Resolve source breakpoint in the newly compiled function. | 2406 // Resolve source breakpoint in the newly compiled function. |
2581 intptr_t bp_pos = | 2407 intptr_t bp_pos = |
2582 ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos()); | 2408 ResolveBreakpointPos(func, bpt->token_pos(), bpt->end_token_pos()); |
2583 if (bp_pos < 0) { | 2409 if (bp_pos < 0) { |
2584 if (FLAG_verbose_debug) { | 2410 if (FLAG_verbose_debug) { |
2585 OS::Print("Failed resolving breakpoint for function '%s'\n", | 2411 OS::Print("Failed resolving breakpoint for function '%s'\n", |
2586 String::Handle(func.name()).ToCString()); | 2412 String::Handle(func.name()).ToCString()); |
2587 } | 2413 } |
2588 continue; | 2414 continue; |
2589 } | 2415 } |
2590 intptr_t requested_pos = loc->token_pos(); | 2416 intptr_t requested_pos = bpt->token_pos(); |
2591 intptr_t requested_end_pos = loc->end_token_pos(); | 2417 intptr_t requested_end_pos = bpt->end_token_pos(); |
2592 loc->SetResolved(func, bp_pos); | 2418 bpt->SetResolved(func, bp_pos); |
2593 Breakpoint* bpt = loc->breakpoints(); | 2419 if (FLAG_verbose_debug) { |
2594 while (bpt != NULL) { | 2420 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " |
2595 if (FLAG_verbose_debug) { | 2421 "function '%s' (requested range %" Pd "-%" Pd ")\n", |
2596 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " | 2422 bpt->id(), |
2597 "function '%s' (requested range %" Pd "-%" Pd ")\n", | 2423 bpt->token_pos(), |
2598 bpt->id(), | 2424 bpt->LineNumber(), |
2599 loc->token_pos(), | 2425 func.ToFullyQualifiedCString(), |
2600 loc->LineNumber(), | 2426 requested_pos, |
2601 func.ToFullyQualifiedCString(), | 2427 requested_end_pos); |
2602 requested_pos, | |
2603 requested_end_pos); | |
2604 } | |
2605 SignalBpResolved(bpt); | |
2606 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); | |
2607 bpt = bpt->next(); | |
2608 } | 2428 } |
| 2429 SignalBpResolved(bpt); |
| 2430 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); |
2609 } | 2431 } |
2610 ASSERT(loc->IsResolved()); | 2432 ASSERT(bpt->IsResolved()); |
2611 if (FLAG_verbose_debug) { | 2433 if (FLAG_verbose_debug) { |
2612 Breakpoint* bpt = loc->breakpoints(); | 2434 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", |
2613 while (bpt != NULL) { | 2435 bpt->id(), |
2614 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", | 2436 bpt->LineNumber(), |
2615 bpt->id(), | 2437 func.IsClosureFunction() ? "closure" : "function", |
2616 loc->LineNumber(), | 2438 String::Handle(func.name()).ToCString()); |
2617 func.IsClosureFunction() ? "closure" : "function", | |
2618 String::Handle(func.name()).ToCString()); | |
2619 bpt = bpt->next(); | |
2620 } | |
2621 } | 2439 } |
2622 MakeCodeBreakpointAt(func, loc); | 2440 MakeCodeBreakpointAt(func, bpt); |
2623 } | 2441 } |
2624 } | 2442 } |
2625 } | 2443 } |
2626 | 2444 |
2627 | 2445 |
2628 void Debugger::NotifyDoneLoading() { | 2446 void Debugger::NotifyDoneLoading() { |
2629 if (latent_locations_ == NULL) { | 2447 if (latent_breakpoints_ == NULL) { |
2630 // Common, fast path. | 2448 // Common, fast path. |
2631 return; | 2449 return; |
2632 } | 2450 } |
2633 Library& lib = Library::Handle(isolate_); | 2451 Library& lib = Library::Handle(isolate_); |
2634 Script& script = Script::Handle(isolate_); | 2452 Script& script = Script::Handle(isolate_); |
2635 String& url = String::Handle(isolate_); | 2453 String& url = String::Handle(isolate_); |
2636 BreakpointLocation* loc = latent_locations_; | 2454 SourceBreakpoint* bpt = latent_breakpoints_; |
2637 BreakpointLocation* prev_loc = NULL; | 2455 SourceBreakpoint* prev_bpt = NULL; |
2638 const GrowableObjectArray& libs = | 2456 const GrowableObjectArray& libs = |
2639 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 2457 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
2640 while (loc != NULL) { | 2458 while (bpt != NULL) { |
2641 url = loc->url(); | 2459 url = bpt->url(); |
2642 bool found_match = false; | 2460 bool found_match = false; |
2643 for (intptr_t i = 0; i < libs.Length(); i++) { | 2461 for (intptr_t i = 0; i < libs.Length(); i++) { |
2644 lib ^= libs.At(i); | 2462 lib ^= libs.At(i); |
2645 script = lib.LookupScript(url); | 2463 script = lib.LookupScript(url); |
2646 if (!script.IsNull()) { | 2464 if (!script.IsNull()) { |
2647 // Found a script with matching url for this latent breakpoint. | 2465 // Found a script with matching url for this latent breakpoint. |
2648 // Unlink the latent breakpoint from the list. | 2466 // Unlink the latent breakpoint from the list. |
2649 found_match = true; | 2467 found_match = true; |
2650 BreakpointLocation* matched_loc = loc; | 2468 SourceBreakpoint* matched_bpt = bpt; |
2651 loc = loc->next(); | 2469 bpt = bpt->next(); |
2652 if (prev_loc == NULL) { | 2470 if (prev_bpt == NULL) { |
2653 latent_locations_ = loc; | 2471 latent_breakpoints_ = bpt; |
2654 } else { | 2472 } else { |
2655 prev_loc->set_next(loc); | 2473 prev_bpt->set_next(bpt); |
2656 } | 2474 } |
2657 // Now find the token range at the requested line and make a | 2475 // Now find the token range at the requested line and make a |
2658 // new unresolved source breakpoint. | 2476 // new unresolved source breakpoint. |
2659 intptr_t line_number = matched_loc->LineNumber(); | 2477 intptr_t line_number = matched_bpt->LineNumber(); |
2660 ASSERT(line_number >= 0); | 2478 ASSERT(line_number >= 0); |
2661 intptr_t first_token_pos, last_token_pos; | 2479 intptr_t first_token_pos, last_token_pos; |
2662 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); | 2480 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); |
2663 if ((first_token_pos < 0) || | 2481 if ((first_token_pos < 0) || |
2664 (last_token_pos < 0)) { | 2482 (last_token_pos < 0)) { |
2665 // Script does not contain the given line number or there are no | 2483 // Script does not contain the given line number or there are no |
2666 // tokens on the line. Drop the breakpoint silently. | 2484 // tokens on the line. Drop the breakpoint silently. |
2667 Breakpoint* bpt = matched_loc->breakpoints(); | 2485 if (FLAG_verbose_debug) { |
2668 while (bpt != NULL) { | 2486 OS::Print("No code found at line %" Pd ": " |
2669 if (FLAG_verbose_debug) { | 2487 "dropping latent breakpoint %" Pd " in '%s'\n", |
2670 OS::Print("No code found at line %" Pd ": " | 2488 line_number, |
2671 "dropping latent breakpoint %" Pd " in '%s'\n", | 2489 matched_bpt->id(), |
2672 line_number, | 2490 url.ToCString()); |
2673 bpt->id(), | |
2674 url.ToCString()); | |
2675 } | |
2676 Breakpoint* prev = bpt; | |
2677 bpt = bpt->next(); | |
2678 delete prev; | |
2679 } | 2491 } |
2680 delete matched_loc; | 2492 delete matched_bpt; |
2681 } else { | 2493 } else { |
2682 // We don't expect to already have a breakpoint for this location. | 2494 // We don't expect to already have a breakpoint for this location. |
2683 // If there is one, assert in debug build but silently drop | 2495 // If there is one, assert in debug build but silently drop |
2684 // the latent breakpoint in release build. | 2496 // the latent breakpoint in release build. |
2685 BreakpointLocation* existing_loc = | 2497 SourceBreakpoint* existing_bpt = |
2686 GetBreakpointLocation(script, first_token_pos); | 2498 GetSourceBreakpoint(script, first_token_pos); |
2687 ASSERT(existing_loc == NULL); | 2499 ASSERT(existing_bpt == NULL); |
2688 if (existing_loc == NULL) { | 2500 if (existing_bpt == NULL) { |
2689 // Create and register a new source breakpoint for the | 2501 // Create and register a new source breakpoint for the |
2690 // latent breakpoint. | 2502 // latent breakpoint. |
2691 BreakpointLocation* unresolved_loc = | 2503 SourceBreakpoint* unresolved_bpt = |
2692 new BreakpointLocation(script, | 2504 new SourceBreakpoint(matched_bpt->id(), |
2693 first_token_pos, | 2505 script, |
2694 last_token_pos); | 2506 first_token_pos, |
2695 RegisterBreakpointLocation(unresolved_loc); | 2507 last_token_pos); |
2696 | 2508 RegisterSourceBreakpoint(unresolved_bpt); |
2697 // Move breakpoints over. | 2509 unresolved_bpt->Enable(); |
2698 Breakpoint* bpt = existing_loc->breakpoints(); | 2510 if (FLAG_verbose_debug) { |
2699 unresolved_loc->set_breakpoints(bpt); | 2511 OS::Print("Converted latent breakpoint " |
2700 existing_loc->set_breakpoints(NULL); | 2512 "%" Pd " in '%s' at line %" Pd "\n", |
2701 while (bpt != NULL) { | 2513 matched_bpt->id(), |
2702 bpt->set_bpt_location(unresolved_loc); | 2514 url.ToCString(), |
2703 if (FLAG_verbose_debug) { | 2515 line_number); |
2704 OS::Print("Converted latent breakpoint " | |
2705 "%" Pd " in '%s' at line %" Pd "\n", | |
2706 bpt->id(), | |
2707 url.ToCString(), | |
2708 line_number); | |
2709 } | |
2710 bpt = bpt->next(); | |
2711 } | 2516 } |
2712 SyncBreakpointLocation(unresolved_loc); | |
2713 } | 2517 } |
2714 delete matched_loc; | 2518 delete matched_bpt; |
2715 // Break out of the iteration over loaded libraries. If the | 2519 // Break out of the iteration over loaded libraries. If the |
2716 // same url has been loaded into more than one library, we | 2520 // same url has been loaded into more than one library, we |
2717 // only set a breakpoint in the first one. | 2521 // only set a breakpoint in the first one. |
2718 // TODO(hausner): There is one possible pitfall here. | 2522 // TODO(hausner): There is one possible pitfall here. |
2719 // If the user sets a latent breakpoint using a partial url that | 2523 // If the user sets a latent breakpoint using a partial url that |
2720 // ends up matching more than one script, the breakpoint might | 2524 // ends up matching more than one script, the breakpoint might |
2721 // get set in the wrong script. | 2525 // get set in the wrong script. |
2722 // It would be better if we could warn the user if multiple | 2526 // It would be better if we could warn the user if multiple |
2723 // scripts are matching. | 2527 // scripts are matching. |
2724 break; | 2528 break; |
2725 } | 2529 } |
2726 } | 2530 } |
2727 } | 2531 } |
2728 if (!found_match) { | 2532 if (!found_match) { |
2729 // No matching url found in any of the libraries. | 2533 // No matching url found in any of the libraries. |
2730 if (FLAG_verbose_debug) { | 2534 if (FLAG_verbose_debug) { |
2731 Breakpoint* bpt = loc->breakpoints(); | 2535 OS::Print("No match found for latent breakpoint id " |
2732 while (bpt != NULL) { | 2536 "%" Pd " with url '%s'\n", |
2733 OS::Print("No match found for latent breakpoint id " | 2537 bpt->id(), |
2734 "%" Pd " with url '%s'\n", | 2538 url.ToCString()); |
2735 bpt->id(), | |
2736 url.ToCString()); | |
2737 bpt = bpt->next(); | |
2738 } | |
2739 } | 2539 } |
2740 loc = loc->next(); | 2540 bpt = bpt->next(); |
2741 } | 2541 } |
2742 } | 2542 } |
2743 } | 2543 } |
2744 | 2544 |
2745 | 2545 |
2746 // TODO(hausner): Could potentially make this faster by checking | 2546 // TODO(hausner): Could potentially make this faster by checking |
2747 // whether the call target at pc is a debugger stub. | 2547 // whether the call target at pc is a debugger stub. |
2748 bool Debugger::HasActiveBreakpoint(uword pc) { | 2548 bool Debugger::HasActiveBreakpoint(uword pc) { |
2749 CodeBreakpoint* bpt = GetCodeBreakpoint(pc); | 2549 CodeBreakpoint* bpt = GetCodeBreakpoint(pc); |
2750 return (bpt != NULL) && (bpt->IsEnabled()); | 2550 return (bpt != NULL) && (bpt->IsEnabled()); |
(...skipping 18 matching lines...) Expand all Loading... |
2769 return bpt->OrigStubAddress(); | 2569 return bpt->OrigStubAddress(); |
2770 } | 2570 } |
2771 UNREACHABLE(); | 2571 UNREACHABLE(); |
2772 return 0L; | 2572 return 0L; |
2773 } | 2573 } |
2774 | 2574 |
2775 | 2575 |
2776 // Remove and delete the source breakpoint bpt and its associated | 2576 // Remove and delete the source breakpoint bpt and its associated |
2777 // code breakpoints. | 2577 // code breakpoints. |
2778 void Debugger::RemoveBreakpoint(intptr_t bp_id) { | 2578 void Debugger::RemoveBreakpoint(intptr_t bp_id) { |
2779 BreakpointLocation* prev_loc = NULL; | 2579 SourceBreakpoint* prev_bpt = NULL; |
2780 BreakpointLocation* curr_loc = breakpoint_locations_; | 2580 SourceBreakpoint* curr_bpt = src_breakpoints_; |
2781 while (curr_loc != NULL) { | 2581 while (curr_bpt != NULL) { |
2782 Breakpoint* prev_bpt = NULL; | 2582 if (curr_bpt->id() == bp_id) { |
2783 Breakpoint* curr_bpt = curr_loc->breakpoints(); | 2583 if (prev_bpt == NULL) { |
2784 while (curr_bpt != NULL) { | 2584 src_breakpoints_ = src_breakpoints_->next(); |
2785 if (curr_bpt->id() == bp_id) { | 2585 } else { |
2786 if (prev_bpt == NULL) { | 2586 prev_bpt->set_next(curr_bpt->next()); |
2787 curr_loc->set_breakpoints(curr_bpt->next()); | |
2788 } else { | |
2789 prev_bpt->set_next(curr_bpt->next()); | |
2790 } | |
2791 | |
2792 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); | |
2793 | |
2794 // Remove references from the current debugger pause event. | |
2795 if (pause_event_ != NULL && | |
2796 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
2797 pause_event_->breakpoint() == curr_bpt) { | |
2798 pause_event_->set_breakpoint(NULL); | |
2799 } | |
2800 return; | |
2801 } | 2587 } |
2802 | 2588 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); |
2803 prev_bpt = curr_bpt; | |
2804 curr_bpt = curr_bpt->next(); | |
2805 } | |
2806 | |
2807 if (curr_loc->breakpoints() == NULL) { | |
2808 if (prev_loc == NULL) { | |
2809 breakpoint_locations_ = breakpoint_locations_->next(); | |
2810 } else { | |
2811 prev_loc->set_next(curr_loc->next()); | |
2812 } | |
2813 | 2589 |
2814 // Remove references from code breakpoints to this source breakpoint, | 2590 // Remove references from code breakpoints to this source breakpoint, |
2815 // and disable the code breakpoints. | 2591 // and disable the code breakpoints. |
2816 UnlinkCodeBreakpoints(curr_loc); | 2592 UnlinkCodeBreakpoints(curr_bpt); |
2817 delete curr_loc; | 2593 delete curr_bpt; |
| 2594 |
| 2595 // Remove references from the current debugger pause event. |
| 2596 if (pause_event_ != NULL && |
| 2597 pause_event_->type() == DebuggerEvent::kBreakpointReached && |
| 2598 pause_event_->breakpoint() == curr_bpt) { |
| 2599 pause_event_->set_breakpoint(NULL); |
| 2600 } |
| 2601 return; |
2818 } | 2602 } |
2819 | 2603 prev_bpt = curr_bpt; |
2820 prev_loc = curr_loc; | 2604 curr_bpt = curr_bpt->next(); |
2821 curr_loc = curr_loc->next(); | |
2822 } | 2605 } |
2823 // bpt is not a registered breakpoint, nothing to do. | 2606 // bpt is not a registered breakpoint, nothing to do. |
2824 } | 2607 } |
2825 | 2608 |
2826 | 2609 |
2827 // Turn code breakpoints associated with the given source breakpoint into | 2610 // Turn code breakpoints associated with the given source breakpoint into |
2828 // internal breakpoints. They will later be deleted when control | 2611 // internal breakpoints. They will later be deleted when control |
2829 // returns from the user-defined breakpoint callback. Also, disable the | 2612 // returns from the user-defined breakpoint callback. Also, disable the |
2830 // breakpoint so it no longer fires if it should be hit before it gets | 2613 // breakpoint so it no longer fires if it should be hit before it gets |
2831 // deleted. | 2614 // deleted. |
2832 void Debugger::UnlinkCodeBreakpoints(BreakpointLocation* bpt_location) { | 2615 void Debugger::UnlinkCodeBreakpoints(SourceBreakpoint* src_bpt) { |
2833 ASSERT(bpt_location != NULL); | 2616 ASSERT(src_bpt != NULL); |
2834 CodeBreakpoint* curr_bpt = code_breakpoints_; | 2617 CodeBreakpoint* curr_bpt = code_breakpoints_; |
2835 while (curr_bpt != NULL) { | 2618 while (curr_bpt != NULL) { |
2836 if (curr_bpt->bpt_location() == bpt_location) { | 2619 if (curr_bpt->src_bpt() == src_bpt) { |
2837 curr_bpt->Disable(); | 2620 curr_bpt->Disable(); |
2838 curr_bpt->set_bpt_location(NULL); | 2621 curr_bpt->set_src_bpt(NULL); |
2839 } | 2622 } |
2840 curr_bpt = curr_bpt->next(); | 2623 curr_bpt = curr_bpt->next(); |
2841 } | 2624 } |
2842 } | 2625 } |
2843 | 2626 |
2844 | 2627 |
2845 // Remove and delete internal breakpoints, i.e. breakpoints that | 2628 // Remove and delete internal breakpoints, i.e. breakpoints that |
2846 // are not associated with a source breakpoint. | 2629 // are not associated with a source breakpoint. |
2847 void Debugger::RemoveInternalBreakpoints() { | 2630 void Debugger::RemoveInternalBreakpoints() { |
2848 CodeBreakpoint* prev_bpt = NULL; | 2631 CodeBreakpoint* prev_bpt = NULL; |
2849 CodeBreakpoint* curr_bpt = code_breakpoints_; | 2632 CodeBreakpoint* curr_bpt = code_breakpoints_; |
2850 while (curr_bpt != NULL) { | 2633 while (curr_bpt != NULL) { |
2851 if (curr_bpt->bpt_location() == NULL) { | 2634 if (curr_bpt->src_bpt() == NULL) { |
2852 if (prev_bpt == NULL) { | 2635 if (prev_bpt == NULL) { |
2853 code_breakpoints_ = code_breakpoints_->next(); | 2636 code_breakpoints_ = code_breakpoints_->next(); |
2854 } else { | 2637 } else { |
2855 prev_bpt->set_next(curr_bpt->next()); | 2638 prev_bpt->set_next(curr_bpt->next()); |
2856 } | 2639 } |
2857 CodeBreakpoint* temp_bpt = curr_bpt; | 2640 CodeBreakpoint* temp_bpt = curr_bpt; |
2858 curr_bpt = curr_bpt->next(); | 2641 curr_bpt = curr_bpt->next(); |
2859 temp_bpt->Disable(); | 2642 temp_bpt->Disable(); |
2860 delete temp_bpt; | 2643 delete temp_bpt; |
2861 } else { | 2644 } else { |
2862 prev_bpt = curr_bpt; | 2645 prev_bpt = curr_bpt; |
2863 curr_bpt = curr_bpt->next(); | 2646 curr_bpt = curr_bpt->next(); |
2864 } | 2647 } |
2865 } | 2648 } |
2866 } | 2649 } |
2867 | 2650 |
2868 | 2651 |
2869 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, | 2652 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Script& script, |
2870 intptr_t token_pos) { | 2653 intptr_t token_pos) { |
2871 BreakpointLocation* bpt = breakpoint_locations_; | 2654 SourceBreakpoint* bpt = src_breakpoints_; |
2872 while (bpt != NULL) { | 2655 while (bpt != NULL) { |
2873 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { | 2656 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { |
2874 return bpt; | 2657 return bpt; |
2875 } | 2658 } |
2876 bpt = bpt->next(); | 2659 bpt = bpt->next(); |
2877 } | 2660 } |
2878 return NULL; | 2661 return NULL; |
2879 } | 2662 } |
2880 | 2663 |
2881 | 2664 |
2882 Breakpoint* Debugger::GetBreakpointById(intptr_t id) { | 2665 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { |
2883 BreakpointLocation* loc = breakpoint_locations_; | 2666 SourceBreakpoint* bpt = src_breakpoints_; |
2884 while (loc != NULL) { | 2667 while (bpt != NULL) { |
2885 Breakpoint* bpt = loc->breakpoints(); | 2668 if (bpt->id() == id) { |
2886 while (bpt != NULL) { | 2669 return bpt; |
2887 if (bpt->id() == id) { | |
2888 return bpt; | |
2889 } | |
2890 bpt = bpt->next(); | |
2891 } | 2670 } |
2892 loc = loc->next(); | 2671 bpt = bpt->next(); |
2893 } | 2672 } |
2894 return NULL; | 2673 return NULL; |
2895 } | 2674 } |
2896 | 2675 |
2897 | 2676 |
2898 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, | 2677 SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url, |
2899 intptr_t line) { | 2678 intptr_t line) { |
2900 BreakpointLocation* bpt = latent_locations_; | 2679 SourceBreakpoint* bpt = latent_breakpoints_; |
2901 String& bpt_url = String::Handle(isolate_); | 2680 String& bpt_url = String::Handle(isolate_); |
2902 while (bpt != NULL) { | 2681 while (bpt != NULL) { |
2903 bpt_url = bpt->url(); | 2682 bpt_url = bpt->url(); |
2904 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { | 2683 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { |
2905 return bpt; | 2684 return bpt; |
2906 } | 2685 } |
2907 bpt = bpt->next(); | 2686 bpt = bpt->next(); |
2908 } | 2687 } |
2909 // No breakpint for this url and line requested. Allocate new one. | 2688 // No breakpint for this url and line requested. Allocate new one. |
2910 bpt = new BreakpointLocation(url, line); | 2689 bpt = new SourceBreakpoint(nextId(), url, line); |
2911 bpt->set_next(latent_locations_); | 2690 bpt->set_next(latent_breakpoints_); |
2912 latent_locations_ = bpt; | 2691 latent_breakpoints_ = bpt; |
2913 return bpt; | 2692 return bpt; |
2914 } | 2693 } |
2915 | 2694 |
2916 | 2695 |
2917 void Debugger::RegisterBreakpointLocation(BreakpointLocation* bpt) { | 2696 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { |
2918 ASSERT(bpt->next() == NULL); | 2697 ASSERT(bpt->next() == NULL); |
2919 bpt->set_next(breakpoint_locations_); | 2698 bpt->set_next(src_breakpoints_); |
2920 breakpoint_locations_ = bpt; | 2699 src_breakpoints_ = bpt; |
2921 } | 2700 } |
2922 | 2701 |
2923 | 2702 |
2924 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2703 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
2925 ASSERT(bpt->next() == NULL); | 2704 ASSERT(bpt->next() == NULL); |
2926 bpt->set_next(code_breakpoints_); | 2705 bpt->set_next(code_breakpoints_); |
2927 code_breakpoints_ = bpt; | 2706 code_breakpoints_ = bpt; |
2928 } | 2707 } |
2929 | 2708 |
2930 } // namespace dart | 2709 } // namespace dart |
OLD | NEW |