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