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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 } | 55 } |
56 | 56 |
57 private: | 57 private: |
58 GrowableObjectArray* objs_; | 58 GrowableObjectArray* objs_; |
59 | 59 |
60 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 60 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
61 }; | 61 }; |
62 | 62 |
63 | 63 |
64 // Create an unresolved breakpoint in given token range and script. | 64 // Create an unresolved breakpoint in given token range and script. |
65 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 65 SourceBreakpoint::SourceBreakpoint(const Script& script, |
66 const Script& script, | |
67 intptr_t token_pos, | 66 intptr_t token_pos, |
68 intptr_t end_token_pos) | 67 intptr_t end_token_pos) |
69 : id_(id), | 68 : script_(script.raw()), |
70 script_(script.raw()), | |
71 url_(script.url()), | 69 url_(script.url()), |
72 token_pos_(token_pos), | 70 token_pos_(token_pos), |
73 end_token_pos_(end_token_pos), | 71 end_token_pos_(end_token_pos), |
74 is_resolved_(false), | 72 is_resolved_(false), |
75 is_enabled_(false), | 73 is_enabled_(false), |
76 is_one_shot_(false), | |
77 next_(NULL), | 74 next_(NULL), |
75 conditions_(NULL), | |
78 function_(Function::null()), | 76 function_(Function::null()), |
79 line_number_(-1) { | 77 line_number_(-1) { |
80 ASSERT(id_ > 0); | |
81 ASSERT(!script.IsNull()); | 78 ASSERT(!script.IsNull()); |
82 ASSERT(token_pos_ >= 0); | 79 ASSERT(token_pos_ >= 0); |
83 } | 80 } |
84 | 81 |
85 // Create a latent breakpoint at given url and line number. | 82 // Create a latent breakpoint at given url and line number. |
86 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 83 SourceBreakpoint::SourceBreakpoint(const String& url, |
87 const String& url, | |
88 intptr_t line_number) | 84 intptr_t line_number) |
89 : id_(id), | 85 : script_(Script::null()), |
90 script_(Script::null()), | |
91 url_(url.raw()), | 86 url_(url.raw()), |
92 token_pos_(-1), | 87 token_pos_(-1), |
93 end_token_pos_(-1), | 88 end_token_pos_(-1), |
94 is_resolved_(false), | 89 is_resolved_(false), |
95 is_enabled_(false), | 90 is_enabled_(false), |
96 is_one_shot_(false), | |
97 next_(NULL), | 91 next_(NULL), |
92 conditions_(NULL), | |
98 function_(Function::null()), | 93 function_(Function::null()), |
99 line_number_(line_number) { | 94 line_number_(line_number) { |
100 ASSERT(id >= 0); | |
101 ASSERT(line_number_ >= 0); | 95 ASSERT(line_number_ >= 0); |
102 } | 96 } |
103 | 97 |
104 void SourceBreakpoint::Enable() { | 98 void SourceBreakpoint::Enable() { |
105 is_enabled_ = true; | 99 is_enabled_ = true; |
106 Isolate::Current()->debugger()->SyncBreakpoint(this); | 100 Isolate::Current()->debugger()->SyncBreakpoint(this); |
107 } | 101 } |
108 | 102 |
109 | 103 |
110 void SourceBreakpoint::Disable() { | 104 void SourceBreakpoint::Disable() { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 ASSERT(!IsLatent() || line_number_ >= 0); | 151 ASSERT(!IsLatent() || line_number_ >= 0); |
158 // Compute line number lazily since it causes scanning of the script. | 152 // Compute line number lazily since it causes scanning of the script. |
159 if (line_number_ < 0) { | 153 if (line_number_ < 0) { |
160 const Script& script = Script::Handle(this->script()); | 154 const Script& script = Script::Handle(this->script()); |
161 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 155 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
162 } | 156 } |
163 return line_number_; | 157 return line_number_; |
164 } | 158 } |
165 | 159 |
166 | 160 |
161 void BreakpointCondition::set_src_bpt(SourceBreakpoint* new_src_bpt) { | |
162 ASSERT(src_bpt_->IsLatent()); // Only reason to move. | |
163 src_bpt_ = new_src_bpt; | |
164 } | |
165 | |
166 | |
167 void BreakpointCondition::VisitObjectPointers(ObjectPointerVisitor* visitor) { | |
168 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); | |
169 } | |
170 | |
171 | |
167 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 172 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
168 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | 173 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
169 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); | 174 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); |
170 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 175 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
176 | |
177 BreakpointCondition* cond = conditions_; | |
178 while (cond != NULL) { | |
179 cond -> VisitObjectPointers(visitor); | |
180 cond = cond->next(); | |
181 } | |
171 } | 182 } |
172 | 183 |
173 | 184 |
174 void SourceBreakpoint::PrintJSON(JSONStream* stream) { | 185 void BreakpointCondition::PrintJSON(JSONStream* stream) { |
175 Isolate* isolate = Isolate::Current(); | 186 Isolate* isolate = Isolate::Current(); |
176 | 187 |
177 JSONObject jsobj(stream); | 188 JSONObject jsobj(stream); |
178 jsobj.AddProperty("type", "Breakpoint"); | 189 jsobj.AddProperty("type", "Breakpoint"); |
179 | 190 |
180 jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id()); | 191 jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id()); |
181 jsobj.AddProperty("breakpointNumber", id()); | 192 jsobj.AddProperty("breakpointNumber", id()); |
182 jsobj.AddProperty("resolved", IsResolved()); | 193 jsobj.AddProperty("resolved", src_bpt_->IsResolved()); |
183 | 194 |
184 Library& library = Library::Handle(isolate); | 195 Library& library = Library::Handle(isolate); |
185 Script& script = Script::Handle(isolate); | 196 Script& script = Script::Handle(isolate); |
186 intptr_t token_pos; | 197 intptr_t token_pos; |
187 GetCodeLocation(&library, &script, &token_pos); | 198 src_bpt_->GetCodeLocation(&library, &script, &token_pos); |
188 { | 199 { |
189 JSONObject location(&jsobj, "location"); | 200 JSONObject location(&jsobj, "location"); |
190 location.AddProperty("type", "Location"); | 201 location.AddProperty("type", "Location"); |
191 location.AddProperty("script", script); | 202 location.AddProperty("script", script); |
192 location.AddProperty("tokenPos", token_pos); | 203 location.AddProperty("tokenPos", token_pos); |
193 } | 204 } |
194 } | 205 } |
195 | 206 |
196 | 207 |
197 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 208 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
286 Debugger* debugger = Isolate::Current()->debugger(); | 297 Debugger* debugger = Isolate::Current()->debugger(); |
287 ASSERT(debugger != NULL); | 298 ASSERT(debugger != NULL); |
288 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); | 299 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); |
289 } | 300 } |
290 } | 301 } |
291 | 302 |
292 | 303 |
293 // The vm service handles breakpoint notifications in a different way | 304 // The vm service handles breakpoint notifications in a different way |
294 // than the regular debugger breakpoint notifications. | 305 // than the regular debugger breakpoint notifications. |
295 static void SendServiceBreakpointEvent(ServiceEvent::EventType type, | 306 static void SendServiceBreakpointEvent(ServiceEvent::EventType type, |
296 SourceBreakpoint* bpt) { | 307 BreakpointCondition* bpt) { |
297 if (Service::NeedsEvents()) { | 308 if (Service::NeedsEvents()) { |
298 ServiceEvent service_event(Isolate::Current(), type); | 309 ServiceEvent service_event(Isolate::Current(), type); |
299 service_event.set_breakpoint(bpt); | 310 service_event.set_breakpoint(bpt); |
300 Service::HandleEvent(&service_event); | 311 Service::HandleEvent(&service_event); |
301 } | 312 } |
302 } | 313 } |
303 | 314 |
304 | 315 |
316 BreakpointCondition* SourceBreakpoint::AddRepeated(Debugger* dbg) { | |
317 BreakpointCondition* cond = conditions(); | |
318 while (cond != NULL) { | |
319 if (cond->IsRepeated()) break; | |
320 cond = cond->next(); | |
321 } | |
322 if (cond == NULL) { | |
323 cond = new BreakpointCondition(dbg->nextId(), this); | |
324 cond->SetIsRepeated(); | |
325 cond->set_next(conditions()); | |
326 set_conditions(cond); | |
327 | |
328 if (IsResolved()) { | |
329 dbg->SignalBpResolved(cond); | |
330 } | |
331 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond); | |
332 } | |
333 return cond; | |
334 } | |
335 | |
336 | |
337 BreakpointCondition* SourceBreakpoint::AddSingleShot(Debugger* dbg) { | |
338 BreakpointCondition* cond = conditions(); | |
339 while (cond != NULL) { | |
340 if (cond->IsSingleShot()) break; | |
341 cond = cond->next(); | |
342 } | |
343 if (cond == NULL) { | |
344 cond = new BreakpointCondition(dbg->nextId(), this); | |
345 cond->SetIsSingleShot(); | |
346 cond->set_next(conditions()); | |
347 set_conditions(cond); | |
348 | |
349 if (IsResolved()) { | |
350 dbg->SignalBpResolved(cond); | |
351 } | |
352 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond); | |
353 } | |
354 return cond; | |
355 } | |
356 | |
357 | |
358 BreakpointCondition* SourceBreakpoint::AddPerClosure(Debugger* dbg, | |
359 const Instance& closure) { | |
360 BreakpointCondition* cond = conditions(); | |
361 while (cond != NULL) { | |
362 if (cond->IsPerClosure() && cond->closure() == closure.raw()) break; | |
363 cond = cond->next(); | |
364 } | |
365 if (cond == NULL) { | |
366 cond = new BreakpointCondition(dbg->nextId(), this); | |
367 cond->SetIsPerClosure(closure); | |
368 cond->set_next(conditions()); | |
369 set_conditions(cond); | |
370 | |
371 if (IsResolved()) { | |
372 dbg->SignalBpResolved(cond); | |
373 } | |
374 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond); | |
375 } | |
376 return cond; | |
377 } | |
378 | |
379 | |
305 const char* Debugger::QualifiedFunctionName(const Function& func) { | 380 const char* Debugger::QualifiedFunctionName(const Function& func) { |
306 const String& func_name = String::Handle(func.name()); | 381 const String& func_name = String::Handle(func.name()); |
307 Class& func_class = Class::Handle(func.Owner()); | 382 Class& func_class = Class::Handle(func.Owner()); |
308 String& class_name = String::Handle(func_class.Name()); | 383 String& class_name = String::Handle(func_class.Name()); |
309 | 384 |
310 const char* kFormat = "%s%s%s"; | 385 const char* kFormat = "%s%s%s"; |
311 intptr_t len = OS::SNPrint(NULL, 0, kFormat, | 386 intptr_t len = OS::SNPrint(NULL, 0, kFormat, |
312 func_class.IsTopLevel() ? "" : class_name.ToCString(), | 387 func_class.IsTopLevel() ? "" : class_name.ToCString(), |
313 func_class.IsTopLevel() ? "" : ".", | 388 func_class.IsTopLevel() ? "" : ".", |
314 func_name.ToCString()); | 389 func_name.ToCString()); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 } | 446 } |
372 cbpt = cbpt->next_; | 447 cbpt = cbpt->next_; |
373 } | 448 } |
374 return false; | 449 return false; |
375 } | 450 } |
376 | 451 |
377 | 452 |
378 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { | 453 void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const { |
379 SourceBreakpoint* sbpt = src_breakpoints_; | 454 SourceBreakpoint* sbpt = src_breakpoints_; |
380 while (sbpt != NULL) { | 455 while (sbpt != NULL) { |
381 jsarr->AddValue(sbpt); | 456 BreakpointCondition* cond = sbpt->conditions(); |
457 while (cond != NULL) { | |
458 jsarr->AddValue(cond); | |
459 cond = cond->next(); | |
460 } | |
382 sbpt = sbpt->next_; | 461 sbpt = sbpt->next_; |
383 } | 462 } |
384 } | 463 } |
385 | 464 |
386 | 465 |
387 RawString* ActivationFrame::QualifiedFunctionName() { | 466 RawString* ActivationFrame::QualifiedFunctionName() { |
388 return String::New(Debugger::QualifiedFunctionName(function())); | 467 return String::New(Debugger::QualifiedFunctionName(function())); |
389 } | 468 } |
390 | 469 |
391 | 470 |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
668 vars_initialized_ = true; | 747 vars_initialized_ = true; |
669 } | 748 } |
670 | 749 |
671 | 750 |
672 intptr_t ActivationFrame::NumLocalVariables() { | 751 intptr_t ActivationFrame::NumLocalVariables() { |
673 GetDescIndices(); | 752 GetDescIndices(); |
674 return desc_indices_.length(); | 753 return desc_indices_.length(); |
675 } | 754 } |
676 | 755 |
677 | 756 |
757 RawObject* ActivationFrame::GetParameter(intptr_t index) { | |
758 intptr_t num_parameters = function().num_fixed_parameters(); | |
759 ASSERT(0 <= index && index < num_parameters); | |
760 intptr_t reverse_index = num_parameters - index; | |
761 | |
762 if (function().NumOptionalParameters() > 0) { | |
763 // If the function has optional parameters, the first positional parameter | |
764 // can be in a number of places in the caller's frame depending on how many | |
765 // were actually supplied at the call site, but they are copied to a fixed | |
766 // place in the callee's frame. | |
767 uword var_address = fp() + ((kFirstLocalSlotFromFp - index) * kWordSize); | |
768 return reinterpret_cast<RawObject*>( | |
769 *reinterpret_cast<uword*>(var_address)); | |
770 } else { | |
771 uword var_address = fp() + (kParamEndSlotFromFp * kWordSize) | |
772 + (reverse_index * kWordSize); | |
773 return reinterpret_cast<RawObject*>( | |
774 *reinterpret_cast<uword*>(var_address)); | |
775 } | |
776 } | |
777 | |
778 | |
779 RawObject* ActivationFrame::GetClosure() { | |
780 ASSERT(function().IsClosureFunction()); | |
781 return GetParameter(0); | |
782 } | |
783 | |
784 | |
678 RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) { | 785 RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) { |
679 if (deopt_frame_.IsNull()) { | 786 if (deopt_frame_.IsNull()) { |
680 uword var_address = fp() + slot_index * kWordSize; | 787 uword var_address = fp() + slot_index * kWordSize; |
681 return reinterpret_cast<RawObject*>( | 788 return reinterpret_cast<RawObject*>( |
682 *reinterpret_cast<uword*>(var_address)); | 789 *reinterpret_cast<uword*>(var_address)); |
683 } else { | 790 } else { |
684 return deopt_frame_.At(deopt_frame_offset_ + slot_index); | 791 return deopt_frame_.At(deopt_frame_offset_ + slot_index); |
685 } | 792 } |
686 } | 793 } |
687 | 794 |
(...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1185 if (function.HasOptimizedCode()) { | 1292 if (function.HasOptimizedCode()) { |
1186 function.SwitchToUnoptimizedCode(); | 1293 function.SwitchToUnoptimizedCode(); |
1187 } | 1294 } |
1188 } | 1295 } |
1189 } | 1296 } |
1190 } | 1297 } |
1191 } | 1298 } |
1192 } | 1299 } |
1193 | 1300 |
1194 | 1301 |
1195 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { | 1302 void Debugger::SignalBpResolved(BreakpointCondition* cond) { |
1196 if (HasEventHandler() && !bpt->IsOneShot()) { | 1303 if (HasEventHandler()) { |
1197 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); | 1304 if (!cond->IsSingleShot()) { |
1198 event.set_breakpoint(bpt); | 1305 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); |
1199 InvokeEventHandler(&event); | 1306 event.set_breakpoint(cond); |
1307 InvokeEventHandler(&event); | |
1308 } | |
1200 } | 1309 } |
1201 } | 1310 } |
1202 | 1311 |
1203 | 1312 |
1204 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1313 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
1205 uword pc, | 1314 uword pc, |
1206 StackFrame* frame, | 1315 StackFrame* frame, |
1207 const Code& code, | 1316 const Code& code, |
1208 const Array& deopt_frame, | 1317 const Array& deopt_frame, |
1209 intptr_t deopt_frame_offset) { | 1318 intptr_t deopt_frame_offset) { |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1721 DeoptimizeWorld(); | 1830 DeoptimizeWorld(); |
1722 func ^= functions.At(0); | 1831 func ^= functions.At(0); |
1723 intptr_t breakpoint_pos = | 1832 intptr_t breakpoint_pos = |
1724 ResolveBreakpointPos(func, token_pos, last_token_pos); | 1833 ResolveBreakpointPos(func, token_pos, last_token_pos); |
1725 if (breakpoint_pos >= 0) { | 1834 if (breakpoint_pos >= 0) { |
1726 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); | 1835 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); |
1727 if (bpt != NULL) { | 1836 if (bpt != NULL) { |
1728 // A source breakpoint for this location already exists. | 1837 // A source breakpoint for this location already exists. |
1729 return bpt; | 1838 return bpt; |
1730 } | 1839 } |
1731 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos); | 1840 bpt = new SourceBreakpoint(script, token_pos, last_token_pos); |
1732 bpt->SetResolved(func, breakpoint_pos); | 1841 bpt->SetResolved(func, breakpoint_pos); |
1733 RegisterSourceBreakpoint(bpt); | 1842 RegisterSourceBreakpoint(bpt); |
1734 | 1843 |
1735 // Create code breakpoints for all compiled functions we found. | 1844 // Create code breakpoints for all compiled functions we found. |
1736 const intptr_t num_functions = functions.Length(); | 1845 const intptr_t num_functions = functions.Length(); |
1737 for (intptr_t i = 0; i < num_functions; i++) { | 1846 for (intptr_t i = 0; i < num_functions; i++) { |
1738 func ^= functions.At(i); | 1847 func ^= functions.At(i); |
1739 ASSERT(func.HasCode()); | 1848 ASSERT(func.HasCode()); |
1740 MakeCodeBreakpointAt(func, bpt); | 1849 MakeCodeBreakpointAt(func, bpt); |
1741 } | 1850 } |
1742 bpt->Enable(); | 1851 bpt->Enable(); |
1743 if (FLAG_verbose_debug) { | 1852 if (FLAG_verbose_debug) { |
1744 intptr_t line_number; | 1853 intptr_t line_number; |
1745 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); | 1854 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); |
1746 OS::Print("Resolved BP for " | 1855 OS::Print("Resolved BP for " |
1747 "function '%s' at line %" Pd "\n", | 1856 "function '%s' at line %" Pd "\n", |
1748 func.ToFullyQualifiedCString(), | 1857 func.ToFullyQualifiedCString(), |
1749 line_number); | 1858 line_number); |
1750 } | 1859 } |
1751 SignalBpResolved(bpt); | |
1752 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
1753 return bpt; | 1860 return bpt; |
1754 } | 1861 } |
1755 } | 1862 } |
1756 // There is no compiled function at this token position. | 1863 // There is no compiled function at this token position. |
1757 // Register an unresolved breakpoint. | 1864 // Register an unresolved breakpoint. |
1758 if (FLAG_verbose_debug && !func.IsNull()) { | 1865 if (FLAG_verbose_debug && !func.IsNull()) { |
1759 intptr_t line_number; | 1866 intptr_t line_number; |
1760 script.GetTokenLocation(token_pos, &line_number, NULL); | 1867 script.GetTokenLocation(token_pos, &line_number, NULL); |
1761 OS::Print("Registering pending breakpoint for " | 1868 OS::Print("Registering pending breakpoint for " |
1762 "uncompiled function '%s' at line %" Pd "\n", | 1869 "uncompiled function '%s' at line %" Pd "\n", |
1763 func.ToFullyQualifiedCString(), | 1870 func.ToFullyQualifiedCString(), |
1764 line_number); | 1871 line_number); |
1765 } | 1872 } |
1766 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); | 1873 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); |
1767 if (bpt == NULL) { | 1874 if (bpt == NULL) { |
1768 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos); | 1875 bpt = new SourceBreakpoint(script, token_pos, last_token_pos); |
1769 RegisterSourceBreakpoint(bpt); | 1876 RegisterSourceBreakpoint(bpt); |
1770 SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt); | |
1771 } | 1877 } |
1772 bpt->Enable(); | 1878 bpt->Enable(); |
1773 return bpt; | 1879 return bpt; |
1774 } | 1880 } |
1775 | 1881 |
1776 | 1882 |
1777 // Synchronize the enabled/disabled state of all code breakpoints | 1883 // Synchronize the enabled/disabled state of all code breakpoints |
1778 // associated with the source breakpoint bpt. | 1884 // associated with the source breakpoint bpt. |
1779 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { | 1885 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
1780 CodeBreakpoint* cbpt = code_breakpoints_; | 1886 CodeBreakpoint* cbpt = code_breakpoints_; |
1781 while (cbpt != NULL) { | 1887 while (cbpt != NULL) { |
1782 if (bpt == cbpt->src_bpt()) { | 1888 if (bpt == cbpt->src_bpt()) { |
1783 if (bpt->IsEnabled()) { | 1889 if (bpt->IsEnabled()) { |
1784 cbpt->Enable(); | 1890 cbpt->Enable(); |
1785 } else { | 1891 } else { |
1786 cbpt->Disable(); | 1892 cbpt->Disable(); |
1787 } | 1893 } |
1788 } | 1894 } |
1789 cbpt = cbpt->next(); | 1895 cbpt = cbpt->next(); |
1790 } | 1896 } |
1791 } | 1897 } |
1792 | 1898 |
1793 | 1899 |
1794 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { | 1900 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { |
1795 LongJumpScope jump; | 1901 LongJumpScope jump; |
1796 if (setjmp(*jump.Set()) == 0) { | 1902 if (setjmp(*jump.Set()) == 0) { |
1797 SourceBreakpoint* bpt = SetBreakpointAtEntry(target_function); | 1903 SetBreakpointAtEntry(target_function, true); |
1798 if (bpt != NULL) { | |
1799 bpt->SetIsOneShot(); | |
1800 } | |
1801 return Error::null(); | 1904 return Error::null(); |
1802 } else { | 1905 } else { |
1803 return isolate_->object_store()->sticky_error(); | 1906 return isolate_->object_store()->sticky_error(); |
1804 } | 1907 } |
1805 } | 1908 } |
1806 | 1909 |
1807 | 1910 |
1808 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 1911 BreakpointCondition* Debugger::SetBreakpointAtEntry( |
1809 const Function& target_function) { | 1912 const Function& target_function, |
1913 bool single_shot) { | |
1810 ASSERT(!target_function.IsNull()); | 1914 ASSERT(!target_function.IsNull()); |
1811 if (!target_function.is_debuggable()) { | 1915 if (!target_function.is_debuggable()) { |
1812 return NULL; | 1916 return NULL; |
1813 } | 1917 } |
1814 const Script& script = Script::Handle(target_function.script()); | 1918 const Script& script = Script::Handle(target_function.script()); |
1815 return SetBreakpoint(script, | 1919 SourceBreakpoint* src_bpt = SetBreakpoint(script, |
1816 target_function.token_pos(), | 1920 target_function.token_pos(), |
1817 target_function.end_token_pos()); | 1921 target_function.end_token_pos()); |
1922 if (single_shot) { | |
1923 return src_bpt->AddSingleShot(this); | |
1924 } else { | |
1925 return src_bpt->AddRepeated(this); | |
1926 } | |
1818 } | 1927 } |
1819 | 1928 |
1820 | 1929 |
1821 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 1930 BreakpointCondition* Debugger::SetBreakpointAtActivation( |
1822 intptr_t line_number) { | 1931 const Instance& closure) { |
1932 if (!closure.IsClosure()) { | |
1933 return NULL; | |
1934 } | |
1935 const Function& func = Function::Handle(Closure::function(closure)); | |
1936 const Script& script = Script::Handle(func.script()); | |
1937 SourceBreakpoint* bpt = SetBreakpoint(script, | |
1938 func.token_pos(), | |
1939 func.end_token_pos()); | |
1940 return bpt->AddPerClosure(this, closure); | |
1941 } | |
1942 | |
1943 | |
1944 BreakpointCondition* Debugger::SetBreakpointAtLine(const String& script_url, | |
1945 intptr_t line_number) { | |
1946 SourceBreakpoint* bpt = SourceBreakpointAtLine(script_url, line_number); | |
1947 return bpt->AddRepeated(this); | |
1948 } | |
1949 | |
1950 | |
1951 SourceBreakpoint* Debugger::SourceBreakpointAtLine(const String& script_url, | |
1952 intptr_t line_number) { | |
1823 Library& lib = Library::Handle(isolate_); | 1953 Library& lib = Library::Handle(isolate_); |
1824 Script& script = Script::Handle(isolate_); | 1954 Script& script = Script::Handle(isolate_); |
1825 const GrowableObjectArray& libs = | 1955 const GrowableObjectArray& libs = |
1826 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 1956 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
1827 const GrowableObjectArray& scripts = | 1957 const GrowableObjectArray& scripts = |
1828 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); | 1958 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); |
1829 for (intptr_t i = 0; i < libs.Length(); i++) { | 1959 for (intptr_t i = 0; i < libs.Length(); i++) { |
1830 lib ^= libs.At(i); | 1960 lib ^= libs.At(i); |
1831 script = lib.LookupScript(script_url); | 1961 script = lib.LookupScript(script_url); |
1832 if (!script.IsNull()) { | 1962 if (!script.IsNull()) { |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2159 if (ServiceIsolate::IsRunning()) { | 2289 if (ServiceIsolate::IsRunning()) { |
2160 return true; | 2290 return true; |
2161 } | 2291 } |
2162 const Class& cls = Class::Handle(func.Owner()); | 2292 const Class& cls = Class::Handle(func.Owner()); |
2163 const Library& lib = Library::Handle(cls.library()); | 2293 const Library& lib = Library::Handle(cls.library()); |
2164 return lib.IsDebuggable(); | 2294 return lib.IsDebuggable(); |
2165 } | 2295 } |
2166 | 2296 |
2167 | 2297 |
2168 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, | 2298 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, |
2169 SourceBreakpoint* bpt) { | 2299 BreakpointCondition* bpt) { |
2170 resume_action_ = kContinue; | 2300 resume_action_ = kContinue; |
2171 stepping_fp_ = 0; | 2301 stepping_fp_ = 0; |
2172 isolate_->set_single_step(false); | 2302 isolate_->set_single_step(false); |
2173 ASSERT(!IsPaused()); | 2303 ASSERT(!IsPaused()); |
2174 ASSERT(obj_cache_ == NULL); | 2304 ASSERT(obj_cache_ == NULL); |
2175 if ((bpt != NULL) && bpt->IsOneShot()) { | 2305 if ((bpt != NULL) && bpt->IsSingleShot()) { |
2176 RemoveBreakpoint(bpt->id()); | 2306 RemoveBreakpoint(bpt->id()); |
2177 bpt = NULL; | 2307 bpt = NULL; |
2178 } | 2308 } |
2179 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2309 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); |
2180 event.set_top_frame(top_frame); | 2310 event.set_top_frame(top_frame); |
2181 event.set_breakpoint(bpt); | 2311 event.set_breakpoint(bpt); |
2182 Pause(&event); | 2312 Pause(&event); |
2183 } | 2313 } |
2184 | 2314 |
2185 | 2315 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2250 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { | 2380 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { |
2251 return; | 2381 return; |
2252 } | 2382 } |
2253 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2383 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
2254 ASSERT(stack_trace->Length() > 0); | 2384 ASSERT(stack_trace->Length() > 0); |
2255 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 2385 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
2256 ASSERT(top_frame != NULL); | 2386 ASSERT(top_frame != NULL); |
2257 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); | 2387 CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc()); |
2258 ASSERT(bpt != NULL); | 2388 ASSERT(bpt != NULL); |
2259 | 2389 |
2390 SourceBreakpoint* src_bpt = bpt->src_bpt_; | |
2391 BreakpointCondition* condition_met = NULL; | |
2392 if (src_bpt != NULL) { | |
2393 BreakpointCondition* cond = src_bpt->conditions(); | |
2394 while (cond != NULL) { | |
2395 if (cond->IsPerClosure()) { | |
2396 Object& closure = Object::Handle(top_frame->GetClosure()); | |
2397 ASSERT(closure.IsInstance()); | |
2398 ASSERT(Instance::Cast(closure).IsClosure()); | |
2399 if (closure.raw() == cond->closure()) { | |
2400 condition_met = cond; | |
2401 break; | |
2402 } | |
2403 } else { | |
2404 condition_met = cond; | |
hausner
2015/05/21 18:23:55
This is subtly wrong. If you have a one-shot break
rmacnak
2015/05/21 21:59:35
As discussed, we should not send a series of break
| |
2405 break; | |
2406 } | |
2407 cond = cond->next(); | |
2408 } | |
2409 } | |
2410 if (condition_met == NULL) { | |
2411 return; | |
2412 } | |
2413 | |
2414 | |
2260 if (FLAG_verbose_debug) { | 2415 if (FLAG_verbose_debug) { |
2261 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " | 2416 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
2262 "(token %" Pd ") (address %#" Px ")\n", | 2417 "(token %" Pd ") (address %#" Px ")\n", |
2263 bpt->IsInternal() ? "internal" : "user", | 2418 bpt->IsInternal() ? "internal" : "user", |
2264 String::Handle(bpt->SourceUrl()).ToCString(), | 2419 String::Handle(bpt->SourceUrl()).ToCString(), |
2265 bpt->LineNumber(), | 2420 bpt->LineNumber(), |
2266 bpt->token_pos(), | 2421 bpt->token_pos(), |
2267 top_frame->pc()); | 2422 top_frame->pc()); |
2268 } | 2423 } |
2269 | 2424 |
2270 ASSERT(stack_trace_ == NULL); | 2425 ASSERT(stack_trace_ == NULL); |
2271 stack_trace_ = stack_trace; | 2426 stack_trace_ = stack_trace; |
2272 SignalPausedEvent(top_frame, bpt->src_bpt_); | 2427 SignalPausedEvent(top_frame, condition_met); |
2273 HandleSteppingRequest(stack_trace_); | 2428 HandleSteppingRequest(stack_trace_); |
2274 stack_trace_ = NULL; | 2429 stack_trace_ = NULL; |
2275 if (bpt->IsInternal()) { | 2430 if (bpt->IsInternal()) { |
2276 RemoveInternalBreakpoints(); | 2431 RemoveInternalBreakpoints(); |
2277 } | 2432 } |
2278 } | 2433 } |
2279 | 2434 |
2280 | 2435 |
2281 void Debugger::BreakHere(const String& msg) { | 2436 void Debugger::BreakHere(const String& msg) { |
2282 // We ignore this breakpoint when the VM is executing code invoked | 2437 // We ignore this breakpoint when the VM is executing code invoked |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2403 if (bp_pos < 0) { | 2558 if (bp_pos < 0) { |
2404 if (FLAG_verbose_debug) { | 2559 if (FLAG_verbose_debug) { |
2405 OS::Print("Failed resolving breakpoint for function '%s'\n", | 2560 OS::Print("Failed resolving breakpoint for function '%s'\n", |
2406 String::Handle(func.name()).ToCString()); | 2561 String::Handle(func.name()).ToCString()); |
2407 } | 2562 } |
2408 continue; | 2563 continue; |
2409 } | 2564 } |
2410 intptr_t requested_pos = bpt->token_pos(); | 2565 intptr_t requested_pos = bpt->token_pos(); |
2411 intptr_t requested_end_pos = bpt->end_token_pos(); | 2566 intptr_t requested_end_pos = bpt->end_token_pos(); |
2412 bpt->SetResolved(func, bp_pos); | 2567 bpt->SetResolved(func, bp_pos); |
2413 if (FLAG_verbose_debug) { | 2568 BreakpointCondition* cond = bpt->conditions(); |
2414 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " | 2569 while (cond != NULL) { |
2415 "function '%s' (requested range %" Pd "-%" Pd ")\n", | 2570 if (FLAG_verbose_debug) { |
2416 bpt->id(), | 2571 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " |
2417 bpt->token_pos(), | 2572 "function '%s' (requested range %" Pd "-%" Pd ")\n", |
2418 bpt->LineNumber(), | 2573 cond->id(), |
2419 func.ToFullyQualifiedCString(), | 2574 bpt->token_pos(), |
2420 requested_pos, | 2575 bpt->LineNumber(), |
2421 requested_end_pos); | 2576 func.ToFullyQualifiedCString(), |
2577 requested_pos, | |
2578 requested_end_pos); | |
2579 } | |
2580 SignalBpResolved(cond); | |
2581 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, cond); | |
2582 cond = cond->next(); | |
2422 } | 2583 } |
2423 SignalBpResolved(bpt); | |
2424 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); | |
2425 } | 2584 } |
2426 ASSERT(bpt->IsResolved()); | 2585 ASSERT(bpt->IsResolved()); |
2427 if (FLAG_verbose_debug) { | 2586 if (FLAG_verbose_debug) { |
2428 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", | 2587 BreakpointCondition* cond = bpt->conditions(); |
2429 bpt->id(), | 2588 while (cond != NULL) { |
2430 bpt->LineNumber(), | 2589 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", |
2431 func.IsClosureFunction() ? "closure" : "function", | 2590 cond->id(), |
2432 String::Handle(func.name()).ToCString()); | 2591 bpt->LineNumber(), |
2592 func.IsClosureFunction() ? "closure" : "function", | |
2593 String::Handle(func.name()).ToCString()); | |
2594 cond = cond->next(); | |
2595 } | |
2433 } | 2596 } |
2434 MakeCodeBreakpointAt(func, bpt); | 2597 MakeCodeBreakpointAt(func, bpt); |
2435 } | 2598 } |
2436 } | 2599 } |
2437 } | 2600 } |
2438 | 2601 |
2439 | 2602 |
2440 void Debugger::NotifyDoneLoading() { | 2603 void Debugger::NotifyDoneLoading() { |
2441 if (latent_breakpoints_ == NULL) { | 2604 if (latent_breakpoints_ == NULL) { |
2442 // Common, fast path. | 2605 // Common, fast path. |
(...skipping 26 matching lines...) Expand all Loading... | |
2469 // Now find the token range at the requested line and make a | 2632 // Now find the token range at the requested line and make a |
2470 // new unresolved source breakpoint. | 2633 // new unresolved source breakpoint. |
2471 intptr_t line_number = matched_bpt->LineNumber(); | 2634 intptr_t line_number = matched_bpt->LineNumber(); |
2472 ASSERT(line_number >= 0); | 2635 ASSERT(line_number >= 0); |
2473 intptr_t first_token_pos, last_token_pos; | 2636 intptr_t first_token_pos, last_token_pos; |
2474 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); | 2637 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); |
2475 if ((first_token_pos < 0) || | 2638 if ((first_token_pos < 0) || |
2476 (last_token_pos < 0)) { | 2639 (last_token_pos < 0)) { |
2477 // Script does not contain the given line number or there are no | 2640 // Script does not contain the given line number or there are no |
2478 // tokens on the line. Drop the breakpoint silently. | 2641 // tokens on the line. Drop the breakpoint silently. |
2479 if (FLAG_verbose_debug) { | 2642 BreakpointCondition* cond = matched_bpt->conditions(); |
2480 OS::Print("No code found at line %" Pd ": " | 2643 while (cond != NULL) { |
2481 "dropping latent breakpoint %" Pd " in '%s'\n", | 2644 if (FLAG_verbose_debug) { |
2482 line_number, | 2645 OS::Print("No code found at line %" Pd ": " |
2483 matched_bpt->id(), | 2646 "dropping latent breakpoint %" Pd " in '%s'\n", |
2484 url.ToCString()); | 2647 line_number, |
2648 cond->id(), | |
2649 url.ToCString()); | |
2650 } | |
2651 BreakpointCondition* prev = cond; | |
2652 cond = cond->next(); | |
2653 delete prev; | |
2485 } | 2654 } |
2486 delete matched_bpt; | 2655 delete matched_bpt; |
2487 } else { | 2656 } else { |
2488 // We don't expect to already have a breakpoint for this location. | 2657 // We don't expect to already have a breakpoint for this location. |
2489 // If there is one, assert in debug build but silently drop | 2658 // If there is one, assert in debug build but silently drop |
2490 // the latent breakpoint in release build. | 2659 // the latent breakpoint in release build. |
2491 SourceBreakpoint* existing_bpt = | 2660 SourceBreakpoint* existing_bpt = |
2492 GetSourceBreakpoint(script, first_token_pos); | 2661 GetSourceBreakpoint(script, first_token_pos); |
2493 ASSERT(existing_bpt == NULL); | 2662 ASSERT(existing_bpt == NULL); |
2494 if (existing_bpt == NULL) { | 2663 if (existing_bpt == NULL) { |
2495 // Create and register a new source breakpoint for the | 2664 // Create and register a new source breakpoint for the |
2496 // latent breakpoint. | 2665 // latent breakpoint. |
2497 SourceBreakpoint* unresolved_bpt = | 2666 SourceBreakpoint* unresolved_bpt = |
2498 new SourceBreakpoint(matched_bpt->id(), | 2667 new SourceBreakpoint(script, |
2499 script, | |
2500 first_token_pos, | 2668 first_token_pos, |
2501 last_token_pos); | 2669 last_token_pos); |
2502 RegisterSourceBreakpoint(unresolved_bpt); | 2670 RegisterSourceBreakpoint(unresolved_bpt); |
2503 unresolved_bpt->Enable(); | 2671 unresolved_bpt->Enable(); |
2504 if (FLAG_verbose_debug) { | 2672 |
2505 OS::Print("Converted latent breakpoint " | 2673 // Move conditions over. |
2506 "%" Pd " in '%s' at line %" Pd "\n", | 2674 BreakpointCondition* cond = existing_bpt->conditions(); |
2507 matched_bpt->id(), | 2675 unresolved_bpt->set_conditions(cond); |
2508 url.ToCString(), | 2676 existing_bpt->set_conditions(NULL); |
2509 line_number); | 2677 while (cond != NULL) { |
2678 cond->set_src_bpt(unresolved_bpt); | |
2679 if (FLAG_verbose_debug) { | |
2680 OS::Print("Converted latent breakpoint " | |
2681 "%" Pd " in '%s' at line %" Pd "\n", | |
2682 cond->id(), | |
2683 url.ToCString(), | |
2684 line_number); | |
2685 } | |
2686 cond = cond->next(); | |
2510 } | 2687 } |
2511 } | 2688 } |
2512 delete matched_bpt; | 2689 delete matched_bpt; |
2513 // Break out of the iteration over loaded libraries. If the | 2690 // Break out of the iteration over loaded libraries. If the |
2514 // same url has been loaded into more than one library, we | 2691 // same url has been loaded into more than one library, we |
2515 // only set a breakpoint in the first one. | 2692 // only set a breakpoint in the first one. |
2516 // TODO(hausner): There is one possible pitfall here. | 2693 // TODO(hausner): There is one possible pitfall here. |
2517 // If the user sets a latent breakpoint using a partial url that | 2694 // If the user sets a latent breakpoint using a partial url that |
2518 // ends up matching more than one script, the breakpoint might | 2695 // ends up matching more than one script, the breakpoint might |
2519 // get set in the wrong script. | 2696 // get set in the wrong script. |
2520 // It would be better if we could warn the user if multiple | 2697 // It would be better if we could warn the user if multiple |
2521 // scripts are matching. | 2698 // scripts are matching. |
2522 break; | 2699 break; |
2523 } | 2700 } |
2524 } | 2701 } |
2525 } | 2702 } |
2526 if (!found_match) { | 2703 if (!found_match) { |
2527 // No matching url found in any of the libraries. | 2704 // No matching url found in any of the libraries. |
2528 if (FLAG_verbose_debug) { | 2705 if (FLAG_verbose_debug) { |
2529 OS::Print("No match found for latent breakpoint id " | 2706 BreakpointCondition* cond = bpt->conditions(); |
2530 "%" Pd " with url '%s'\n", | 2707 while (cond != NULL) { |
2531 bpt->id(), | 2708 OS::Print("No match found for latent breakpoint id " |
2532 url.ToCString()); | 2709 "%" Pd " with url '%s'\n", |
2710 cond->id(), | |
2711 url.ToCString()); | |
2712 cond = cond->next(); | |
2713 } | |
2533 } | 2714 } |
2534 bpt = bpt->next(); | 2715 bpt = bpt->next(); |
2535 } | 2716 } |
2536 } | 2717 } |
2537 } | 2718 } |
2538 | 2719 |
2539 | 2720 |
2540 // TODO(hausner): Could potentially make this faster by checking | 2721 // TODO(hausner): Could potentially make this faster by checking |
2541 // whether the call target at pc is a debugger stub. | 2722 // whether the call target at pc is a debugger stub. |
2542 bool Debugger::HasActiveBreakpoint(uword pc) { | 2723 bool Debugger::HasActiveBreakpoint(uword pc) { |
(...skipping 23 matching lines...) Expand all Loading... | |
2566 return 0L; | 2747 return 0L; |
2567 } | 2748 } |
2568 | 2749 |
2569 | 2750 |
2570 // Remove and delete the source breakpoint bpt and its associated | 2751 // Remove and delete the source breakpoint bpt and its associated |
2571 // code breakpoints. | 2752 // code breakpoints. |
2572 void Debugger::RemoveBreakpoint(intptr_t bp_id) { | 2753 void Debugger::RemoveBreakpoint(intptr_t bp_id) { |
2573 SourceBreakpoint* prev_bpt = NULL; | 2754 SourceBreakpoint* prev_bpt = NULL; |
2574 SourceBreakpoint* curr_bpt = src_breakpoints_; | 2755 SourceBreakpoint* curr_bpt = src_breakpoints_; |
2575 while (curr_bpt != NULL) { | 2756 while (curr_bpt != NULL) { |
2576 if (curr_bpt->id() == bp_id) { | 2757 BreakpointCondition* prev_cond = NULL; |
2758 BreakpointCondition* curr_cond = curr_bpt->conditions(); | |
2759 while (curr_cond != NULL) { | |
2760 if (curr_cond->id() == bp_id) { | |
2761 if (prev_cond == NULL) { | |
2762 curr_bpt->set_conditions(curr_cond->next()); | |
2763 } else { | |
2764 prev_cond->set_next(curr_cond->next()); | |
2765 } | |
2766 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_cond); | |
2767 | |
2768 // Remove references from the current debugger pause event. | |
2769 if (pause_event_ != NULL && | |
2770 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
2771 pause_event_->breakpoint() == curr_cond) { | |
2772 pause_event_->set_breakpoint(NULL); | |
2773 } | |
2774 return; | |
2775 } | |
2776 | |
2777 prev_cond = curr_cond; | |
2778 curr_cond = curr_cond->next(); | |
2779 } | |
2780 | |
2781 if (curr_bpt->conditions() == NULL) { | |
2577 if (prev_bpt == NULL) { | 2782 if (prev_bpt == NULL) { |
2578 src_breakpoints_ = src_breakpoints_->next(); | 2783 src_breakpoints_ = src_breakpoints_->next(); |
2579 } else { | 2784 } else { |
2580 prev_bpt->set_next(curr_bpt->next()); | 2785 prev_bpt->set_next(curr_bpt->next()); |
2581 } | 2786 } |
2582 SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); | |
2583 | 2787 |
2584 // Remove references from code breakpoints to this source breakpoint, | 2788 // Remove references from code breakpoints to this source breakpoint, |
2585 // and disable the code breakpoints. | 2789 // and disable the code breakpoints. |
2586 UnlinkCodeBreakpoints(curr_bpt); | 2790 UnlinkCodeBreakpoints(curr_bpt); |
2587 delete curr_bpt; | 2791 delete curr_bpt; |
2792 } | |
2588 | 2793 |
2589 // Remove references from the current debugger pause event. | |
2590 if (pause_event_ != NULL && | |
2591 pause_event_->type() == DebuggerEvent::kBreakpointReached && | |
2592 pause_event_->breakpoint() == curr_bpt) { | |
2593 pause_event_->set_breakpoint(NULL); | |
2594 } | |
2595 return; | |
2596 } | |
2597 prev_bpt = curr_bpt; | 2794 prev_bpt = curr_bpt; |
2598 curr_bpt = curr_bpt->next(); | 2795 curr_bpt = curr_bpt->next(); |
2599 } | 2796 } |
2600 // bpt is not a registered breakpoint, nothing to do. | 2797 // bpt is not a registered breakpoint, nothing to do. |
2601 } | 2798 } |
2602 | 2799 |
2603 | 2800 |
2604 // Turn code breakpoints associated with the given source breakpoint into | 2801 // Turn code breakpoints associated with the given source breakpoint into |
2605 // internal breakpoints. They will later be deleted when control | 2802 // internal breakpoints. They will later be deleted when control |
2606 // returns from the user-defined breakpoint callback. Also, disable the | 2803 // returns from the user-defined breakpoint callback. Also, disable the |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2649 while (bpt != NULL) { | 2846 while (bpt != NULL) { |
2650 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { | 2847 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { |
2651 return bpt; | 2848 return bpt; |
2652 } | 2849 } |
2653 bpt = bpt->next(); | 2850 bpt = bpt->next(); |
2654 } | 2851 } |
2655 return NULL; | 2852 return NULL; |
2656 } | 2853 } |
2657 | 2854 |
2658 | 2855 |
2659 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { | 2856 BreakpointCondition* Debugger::GetBreakpointById(intptr_t id) { |
2660 SourceBreakpoint* bpt = src_breakpoints_; | 2857 SourceBreakpoint* bpt = src_breakpoints_; |
2661 while (bpt != NULL) { | 2858 while (bpt != NULL) { |
2662 if (bpt->id() == id) { | 2859 BreakpointCondition* cond = bpt->conditions(); |
2663 return bpt; | 2860 while (cond != NULL) { |
2861 if (cond->id() == id) { | |
2862 return cond; | |
2863 } | |
2864 cond = cond->next(); | |
2664 } | 2865 } |
2665 bpt = bpt->next(); | 2866 bpt = bpt->next(); |
2666 } | 2867 } |
2667 return NULL; | 2868 return NULL; |
2668 } | 2869 } |
2669 | 2870 |
2670 | 2871 |
2671 SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url, | 2872 SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url, |
2672 intptr_t line) { | 2873 intptr_t line) { |
2673 SourceBreakpoint* bpt = latent_breakpoints_; | 2874 SourceBreakpoint* bpt = latent_breakpoints_; |
2674 String& bpt_url = String::Handle(isolate_); | 2875 String& bpt_url = String::Handle(isolate_); |
2675 while (bpt != NULL) { | 2876 while (bpt != NULL) { |
2676 bpt_url = bpt->url(); | 2877 bpt_url = bpt->url(); |
2677 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { | 2878 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { |
2678 return bpt; | 2879 return bpt; |
2679 } | 2880 } |
2680 bpt = bpt->next(); | 2881 bpt = bpt->next(); |
2681 } | 2882 } |
2682 // No breakpint for this url and line requested. Allocate new one. | 2883 // No breakpint for this url and line requested. Allocate new one. |
2683 bpt = new SourceBreakpoint(nextId(), url, line); | 2884 bpt = new SourceBreakpoint(url, line); |
2684 bpt->set_next(latent_breakpoints_); | 2885 bpt->set_next(latent_breakpoints_); |
2685 latent_breakpoints_ = bpt; | 2886 latent_breakpoints_ = bpt; |
2686 return bpt; | 2887 return bpt; |
2687 } | 2888 } |
2688 | 2889 |
2689 | 2890 |
2690 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { | 2891 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { |
2691 ASSERT(bpt->next() == NULL); | 2892 ASSERT(bpt->next() == NULL); |
2692 bpt->set_next(src_breakpoints_); | 2893 bpt->set_next(src_breakpoints_); |
2693 src_breakpoints_ = bpt; | 2894 src_breakpoints_ = bpt; |
2694 } | 2895 } |
2695 | 2896 |
2696 | 2897 |
2697 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2898 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
2698 ASSERT(bpt->next() == NULL); | 2899 ASSERT(bpt->next() == NULL); |
2699 bpt->set_next(code_breakpoints_); | 2900 bpt->set_next(code_breakpoints_); |
2700 code_breakpoints_ = bpt; | 2901 code_breakpoints_ = bpt; |
2701 } | 2902 } |
2702 | 2903 |
2703 } // namespace dart | 2904 } // namespace dart |
OLD | NEW |