| 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 return obj_id < objs_->Length(); | 47 return obj_id < objs_->Length(); |
| 48 } | 48 } |
| 49 | 49 |
| 50 private: | 50 private: |
| 51 GrowableObjectArray* objs_; | 51 GrowableObjectArray* objs_; |
| 52 | 52 |
| 53 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 53 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 | 56 |
| 57 // Create an unresolved breakpoint in given token range and script. |
| 57 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 58 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
| 58 const Script& script, | 59 const Script& script, |
| 59 intptr_t token_pos, | 60 intptr_t token_pos, |
| 60 intptr_t end_token_pos) | 61 intptr_t end_token_pos) |
| 61 : id_(id), | 62 : id_(id), |
| 62 script_(script.raw()), | 63 script_(script.raw()), |
| 64 url_(script.url()), |
| 63 token_pos_(token_pos), | 65 token_pos_(token_pos), |
| 64 end_token_pos_(end_token_pos), | 66 end_token_pos_(end_token_pos), |
| 65 is_resolved_(false), | 67 is_resolved_(false), |
| 66 is_enabled_(false), | 68 is_enabled_(false), |
| 67 is_one_shot_(false), | 69 is_one_shot_(false), |
| 68 next_(NULL), | 70 next_(NULL), |
| 69 function_(Function::null()), | 71 function_(Function::null()), |
| 70 line_number_(-1) { | 72 line_number_(-1) { |
| 71 ASSERT(id_ > 0); | 73 ASSERT(id_ > 0); |
| 72 ASSERT(!script.IsNull()); | 74 ASSERT(!script.IsNull()); |
| 73 ASSERT(token_pos_ >= 0); | 75 ASSERT(token_pos_ >= 0); |
| 74 } | 76 } |
| 75 | 77 |
| 78 // Create a latent breakpoint at given url and line number. |
| 79 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
| 80 const String& url, |
| 81 intptr_t line_number) |
| 82 : id_(id), |
| 83 script_(Script::null()), |
| 84 url_(url.raw()), |
| 85 token_pos_(-1), |
| 86 end_token_pos_(-1), |
| 87 is_resolved_(false), |
| 88 is_enabled_(false), |
| 89 is_one_shot_(false), |
| 90 next_(NULL), |
| 91 function_(Function::null()), |
| 92 line_number_(line_number) { |
| 93 ASSERT(id >= 0); |
| 94 ASSERT(line_number_ >= 0); |
| 95 } |
| 76 | 96 |
| 77 void SourceBreakpoint::Enable() { | 97 void SourceBreakpoint::Enable() { |
| 78 is_enabled_ = true; | 98 is_enabled_ = true; |
| 79 Isolate::Current()->debugger()->SyncBreakpoint(this); | 99 Isolate::Current()->debugger()->SyncBreakpoint(this); |
| 80 } | 100 } |
| 81 | 101 |
| 82 | 102 |
| 83 void SourceBreakpoint::Disable() { | 103 void SourceBreakpoint::Disable() { |
| 84 is_enabled_ = false; | 104 is_enabled_ = false; |
| 85 Isolate::Current()->debugger()->SyncBreakpoint(this); | 105 Isolate::Current()->debugger()->SyncBreakpoint(this); |
| 86 } | 106 } |
| 87 | 107 |
| 88 | 108 |
| 89 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) { | 109 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) { |
| 110 ASSERT(!IsLatent()); |
| 90 ASSERT(func.script() == script_); | 111 ASSERT(func.script() == script_); |
| 91 ASSERT((func.token_pos() <= token_pos) && | 112 ASSERT((func.token_pos() <= token_pos) && |
| 92 (token_pos <= func.end_token_pos())); | 113 (token_pos <= func.end_token_pos())); |
| 93 function_ = func.raw(); | 114 function_ = func.raw(); |
| 94 token_pos_ = token_pos; | 115 token_pos_ = token_pos; |
| 95 end_token_pos_ = token_pos; | 116 end_token_pos_ = token_pos; |
| 96 line_number_ = -1; // Recalcualte lazily. | 117 line_number_ = -1; // Recalcualte lazily. |
| 97 is_resolved_ = true; | 118 is_resolved_ = true; |
| 98 } | 119 } |
| 99 | 120 |
| 100 | 121 |
| 101 // TODO(hausner): Get rid of library parameter. A source breakpoint location | 122 // TODO(hausner): Get rid of library parameter. A source breakpoint location |
| 102 // does not imply a library, since the same source code can be included | 123 // does not imply a library, since the same source code can be included |
| 103 // in more than one library, e.g. the text location of mixin functions. | 124 // in more than one library, e.g. the text location of mixin functions. |
| 104 void SourceBreakpoint::GetCodeLocation(Library* lib, | 125 void SourceBreakpoint::GetCodeLocation(Library* lib, |
| 105 Script* script, | 126 Script* script, |
| 106 intptr_t* pos) { | 127 intptr_t* pos) { |
| 107 *script = this->script(); | 128 if (IsLatent()) { |
| 108 *pos = token_pos_; | 129 *lib = Library::null(); |
| 109 if (IsResolved()) { | 130 *script = Script::null(); |
| 110 const Function& func = Function::Handle(function_); | 131 *pos = -1; |
| 111 ASSERT(!func.IsNull()); | |
| 112 const Class& cls = Class::Handle(func.origin()); | |
| 113 *lib = cls.library(); | |
| 114 } else { | 132 } else { |
| 115 *lib = Library::null(); | 133 *script = this->script(); |
| 134 *pos = token_pos_; |
| 135 if (IsResolved()) { |
| 136 const Function& func = Function::Handle(function_); |
| 137 ASSERT(!func.IsNull()); |
| 138 const Class& cls = Class::Handle(func.origin()); |
| 139 *lib = cls.library(); |
| 140 } else { |
| 141 *lib = Library::null(); |
| 142 } |
| 116 } | 143 } |
| 117 } | 144 } |
| 118 | 145 |
| 119 | 146 |
| 120 RawString* SourceBreakpoint::SourceUrl() { | |
| 121 return Script::Handle(script()).url(); | |
| 122 } | |
| 123 | |
| 124 | |
| 125 intptr_t SourceBreakpoint::LineNumber() { | 147 intptr_t SourceBreakpoint::LineNumber() { |
| 148 // Latent breakpoints must have a requested line number >= 0. |
| 149 ASSERT(!IsLatent() || line_number_ >= 0); |
| 126 // Compute line number lazily since it causes scanning of the script. | 150 // Compute line number lazily since it causes scanning of the script. |
| 127 if (line_number_ < 0) { | 151 if (line_number_ < 0) { |
| 128 const Script& script = Script::Handle(this->script()); | 152 const Script& script = Script::Handle(this->script()); |
| 129 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 153 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
| 130 } | 154 } |
| 131 return line_number_; | 155 return line_number_; |
| 132 } | 156 } |
| 133 | 157 |
| 134 | 158 |
| 135 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 159 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 136 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | 160 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
| 161 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); |
| 137 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 162 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 138 } | 163 } |
| 139 | 164 |
| 140 | 165 |
| 141 void SourceBreakpoint::PrintJSON(JSONStream* stream) { | 166 void SourceBreakpoint::PrintJSON(JSONStream* stream) { |
| 142 Isolate* isolate = Isolate::Current(); | 167 Isolate* isolate = Isolate::Current(); |
| 143 | 168 |
| 144 JSONObject jsobj(stream); | 169 JSONObject jsobj(stream); |
| 145 jsobj.AddProperty("type", "Breakpoint"); | 170 jsobj.AddProperty("type", "Breakpoint"); |
| 146 | 171 |
| (...skipping 843 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 ASSERT(IsValidId(obj_id)); | 1015 ASSERT(IsValidId(obj_id)); |
| 991 return objs_->At(obj_id); | 1016 return objs_->At(obj_id); |
| 992 } | 1017 } |
| 993 | 1018 |
| 994 | 1019 |
| 995 Debugger::Debugger() | 1020 Debugger::Debugger() |
| 996 : isolate_(NULL), | 1021 : isolate_(NULL), |
| 997 isolate_id_(ILLEGAL_ISOLATE_ID), | 1022 isolate_id_(ILLEGAL_ISOLATE_ID), |
| 998 initialized_(false), | 1023 initialized_(false), |
| 999 next_id_(1), | 1024 next_id_(1), |
| 1025 latent_breakpoints_(NULL), |
| 1000 src_breakpoints_(NULL), | 1026 src_breakpoints_(NULL), |
| 1001 code_breakpoints_(NULL), | 1027 code_breakpoints_(NULL), |
| 1002 resume_action_(kContinue), | 1028 resume_action_(kContinue), |
| 1003 ignore_breakpoints_(false), | 1029 ignore_breakpoints_(false), |
| 1004 pause_event_(NULL), | 1030 pause_event_(NULL), |
| 1005 obj_cache_(NULL), | 1031 obj_cache_(NULL), |
| 1006 stack_trace_(NULL), | 1032 stack_trace_(NULL), |
| 1007 stepping_fp_(0), | 1033 stepping_fp_(0), |
| 1008 exc_pause_info_(kNoPauseOnExceptions) { | 1034 exc_pause_info_(kNoPauseOnExceptions) { |
| 1009 } | 1035 } |
| 1010 | 1036 |
| 1011 | 1037 |
| 1012 Debugger::~Debugger() { | 1038 Debugger::~Debugger() { |
| 1013 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1039 isolate_id_ = ILLEGAL_ISOLATE_ID; |
| 1014 ASSERT(!IsPaused()); | 1040 ASSERT(!IsPaused()); |
| 1041 ASSERT(latent_breakpoints_ == NULL); |
| 1015 ASSERT(src_breakpoints_ == NULL); | 1042 ASSERT(src_breakpoints_ == NULL); |
| 1016 ASSERT(code_breakpoints_ == NULL); | 1043 ASSERT(code_breakpoints_ == NULL); |
| 1017 ASSERT(stack_trace_ == NULL); | 1044 ASSERT(stack_trace_ == NULL); |
| 1018 ASSERT(obj_cache_ == NULL); | 1045 ASSERT(obj_cache_ == NULL); |
| 1019 } | 1046 } |
| 1020 | 1047 |
| 1021 | 1048 |
| 1022 void Debugger::Shutdown() { | 1049 void Debugger::Shutdown() { |
| 1023 while (src_breakpoints_ != NULL) { | 1050 while (src_breakpoints_ != NULL) { |
| 1024 SourceBreakpoint* bpt = src_breakpoints_; | 1051 SourceBreakpoint* bpt = src_breakpoints_; |
| 1025 src_breakpoints_ = src_breakpoints_->next(); | 1052 src_breakpoints_ = src_breakpoints_->next(); |
| 1026 delete bpt; | 1053 delete bpt; |
| 1027 } | 1054 } |
| 1055 while (latent_breakpoints_ != NULL) { |
| 1056 SourceBreakpoint* bpt = latent_breakpoints_; |
| 1057 latent_breakpoints_ = latent_breakpoints_->next(); |
| 1058 delete bpt; |
| 1059 } |
| 1028 while (code_breakpoints_ != NULL) { | 1060 while (code_breakpoints_ != NULL) { |
| 1029 CodeBreakpoint* bpt = code_breakpoints_; | 1061 CodeBreakpoint* bpt = code_breakpoints_; |
| 1030 code_breakpoints_ = code_breakpoints_->next(); | 1062 code_breakpoints_ = code_breakpoints_->next(); |
| 1031 bpt->Disable(); | 1063 bpt->Disable(); |
| 1032 delete bpt; | 1064 delete bpt; |
| 1033 } | 1065 } |
| 1034 // Signal isolate shutdown event. | 1066 // Signal isolate shutdown event. |
| 1035 SignalIsolateEvent(DebuggerEvent::kIsolateShutdown); | 1067 SignalIsolateEvent(DebuggerEvent::kIsolateShutdown); |
| 1036 } | 1068 } |
| 1037 | 1069 |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1507 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_); | 1539 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_); |
| 1508 Function& function = Function::Handle(isolate_); | 1540 Function& function = Function::Handle(isolate_); |
| 1509 | 1541 |
| 1510 const ClassTable& class_table = *isolate_->class_table(); | 1542 const ClassTable& class_table = *isolate_->class_table(); |
| 1511 const intptr_t num_classes = class_table.NumCids(); | 1543 const intptr_t num_classes = class_table.NumCids(); |
| 1512 for (intptr_t i = 1; i < num_classes; i++) { | 1544 for (intptr_t i = 1; i < num_classes; i++) { |
| 1513 if (class_table.HasValidClassAt(i)) { | 1545 if (class_table.HasValidClassAt(i)) { |
| 1514 cls = class_table.At(i); | 1546 cls = class_table.At(i); |
| 1515 // If the class is not finalized, e.g. if it hasn't been parsed | 1547 // If the class is not finalized, e.g. if it hasn't been parsed |
| 1516 // yet entirely, we can ignore it. If it contains a function with | 1548 // yet entirely, we can ignore it. If it contains a function with |
| 1517 // a latent breakpoint, we will detect it if and when the function | 1549 // an unresolved breakpoint, we will detect it if and when the |
| 1518 // gets compiled. | 1550 // function gets compiled. |
| 1519 if (!cls.is_finalized()) { | 1551 if (!cls.is_finalized()) { |
| 1520 continue; | 1552 continue; |
| 1521 } | 1553 } |
| 1522 // Note: we need to check the functions of this class even if | 1554 // Note: we need to check the functions of this class even if |
| 1523 // the class is defined in a differenct 'script'. There could | 1555 // the class is defined in a differenct 'script'. There could |
| 1524 // be mixin functions from the given script in this class. | 1556 // be mixin functions from the given script in this class. |
| 1525 functions = cls.functions(); | 1557 functions = cls.functions(); |
| 1526 if (!functions.IsNull()) { | 1558 if (!functions.IsNull()) { |
| 1527 const intptr_t num_functions = functions.Length(); | 1559 const intptr_t num_functions = functions.Length(); |
| 1528 for (intptr_t pos = 0; pos < num_functions; pos++) { | 1560 for (intptr_t pos = 0; pos < num_functions; pos++) { |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1776 const GrowableObjectArray& scripts = | 1808 const GrowableObjectArray& scripts = |
| 1777 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); | 1809 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); |
| 1778 for (intptr_t i = 0; i < libs.Length(); i++) { | 1810 for (intptr_t i = 0; i < libs.Length(); i++) { |
| 1779 lib ^= libs.At(i); | 1811 lib ^= libs.At(i); |
| 1780 script = lib.LookupScript(script_url); | 1812 script = lib.LookupScript(script_url); |
| 1781 if (!script.IsNull()) { | 1813 if (!script.IsNull()) { |
| 1782 scripts.Add(script); | 1814 scripts.Add(script); |
| 1783 } | 1815 } |
| 1784 } | 1816 } |
| 1785 if (scripts.Length() == 0) { | 1817 if (scripts.Length() == 0) { |
| 1818 // No script found with given url. Create a latent breakpoint which |
| 1819 // will be set if the url is loaded later. |
| 1820 SourceBreakpoint* latent_bpt = GetLatentBreakpoint(script_url, line_number); |
| 1786 if (FLAG_verbose_debug) { | 1821 if (FLAG_verbose_debug) { |
| 1787 OS::Print("Failed to find script with url '%s'\n", | 1822 OS::Print("Set latent breakpoint in url '%s' at line %" Pd "\n", |
| 1788 script_url.ToCString()); | 1823 script_url.ToCString(), |
| 1824 line_number); |
| 1789 } | 1825 } |
| 1790 return NULL; | 1826 return latent_bpt; |
| 1791 } | 1827 } |
| 1792 if (scripts.Length() > 1) { | 1828 if (scripts.Length() > 1) { |
| 1793 if (FLAG_verbose_debug) { | 1829 if (FLAG_verbose_debug) { |
| 1794 OS::Print("Multiple scripts match url '%s'\n", script_url.ToCString()); | 1830 OS::Print("Multiple scripts match url '%s'\n", script_url.ToCString()); |
| 1795 } | 1831 } |
| 1796 return NULL; | 1832 return NULL; |
| 1797 } | 1833 } |
| 1798 script ^= scripts.At(0); | 1834 script ^= scripts.At(0); |
| 1799 intptr_t first_token_idx, last_token_idx; | 1835 intptr_t first_token_idx, last_token_idx; |
| 1800 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); | 1836 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2026 | 2062 |
| 2027 | 2063 |
| 2028 // static | 2064 // static |
| 2029 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 2065 void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 2030 ASSERT(visitor != NULL); | 2066 ASSERT(visitor != NULL); |
| 2031 SourceBreakpoint* bpt = src_breakpoints_; | 2067 SourceBreakpoint* bpt = src_breakpoints_; |
| 2032 while (bpt != NULL) { | 2068 while (bpt != NULL) { |
| 2033 bpt->VisitObjectPointers(visitor); | 2069 bpt->VisitObjectPointers(visitor); |
| 2034 bpt = bpt->next(); | 2070 bpt = bpt->next(); |
| 2035 } | 2071 } |
| 2072 bpt = latent_breakpoints_; |
| 2073 while (bpt != NULL) { |
| 2074 bpt->VisitObjectPointers(visitor); |
| 2075 bpt = bpt->next(); |
| 2076 } |
| 2036 CodeBreakpoint* cbpt = code_breakpoints_; | 2077 CodeBreakpoint* cbpt = code_breakpoints_; |
| 2037 while (cbpt != NULL) { | 2078 while (cbpt != NULL) { |
| 2038 cbpt->VisitObjectPointers(visitor); | 2079 cbpt->VisitObjectPointers(visitor); |
| 2039 cbpt = cbpt->next(); | 2080 cbpt = cbpt->next(); |
| 2040 } | 2081 } |
| 2041 } | 2082 } |
| 2042 | 2083 |
| 2043 | 2084 |
| 2044 // static | 2085 // static |
| 2045 void Debugger::SetEventHandler(EventHandler* handler) { | 2086 void Debugger::SetEventHandler(EventHandler* handler) { |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2307 intptr_t bp_pos = | 2348 intptr_t bp_pos = |
| 2308 ResolveBreakpointPos(func, bpt->token_pos(), bpt->end_token_pos()); | 2349 ResolveBreakpointPos(func, bpt->token_pos(), bpt->end_token_pos()); |
| 2309 if (bp_pos < 0) { | 2350 if (bp_pos < 0) { |
| 2310 if (FLAG_verbose_debug) { | 2351 if (FLAG_verbose_debug) { |
| 2311 OS::Print("Failed resolving breakpoint for function '%s'\n", | 2352 OS::Print("Failed resolving breakpoint for function '%s'\n", |
| 2312 String::Handle(func.name()).ToCString()); | 2353 String::Handle(func.name()).ToCString()); |
| 2313 } | 2354 } |
| 2314 continue; | 2355 continue; |
| 2315 } | 2356 } |
| 2316 intptr_t requested_pos = bpt->token_pos(); | 2357 intptr_t requested_pos = bpt->token_pos(); |
| 2358 intptr_t requested_end_pos = bpt->end_token_pos(); |
| 2317 bpt->SetResolved(func, bp_pos); | 2359 bpt->SetResolved(func, bp_pos); |
| 2318 if (FLAG_verbose_debug) { | 2360 if (FLAG_verbose_debug) { |
| 2319 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " | 2361 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " |
| 2320 "function '%s' (requested pos %" Pd ")\n", | 2362 "function '%s' (requested range %" Pd "-%" Pd ")\n", |
| 2321 bpt->id(), | 2363 bpt->id(), |
| 2322 bpt->token_pos(), | 2364 bpt->token_pos(), |
| 2323 bpt->LineNumber(), | 2365 bpt->LineNumber(), |
| 2324 func.ToFullyQualifiedCString(), | 2366 func.ToFullyQualifiedCString(), |
| 2325 requested_pos); | 2367 requested_pos, |
| 2368 requested_end_pos); |
| 2326 } | 2369 } |
| 2327 SignalBpResolved(bpt); | 2370 SignalBpResolved(bpt); |
| 2328 } | 2371 } |
| 2329 ASSERT(bpt->IsResolved()); | 2372 ASSERT(bpt->IsResolved()); |
| 2330 if (FLAG_verbose_debug) { | 2373 if (FLAG_verbose_debug) { |
| 2331 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", | 2374 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", |
| 2332 bpt->id(), | 2375 bpt->id(), |
| 2333 bpt->LineNumber(), | 2376 bpt->LineNumber(), |
| 2334 func.IsClosureFunction() ? "closure" : "function", | 2377 func.IsClosureFunction() ? "closure" : "function", |
| 2335 String::Handle(func.name()).ToCString()); | 2378 String::Handle(func.name()).ToCString()); |
| 2336 } | 2379 } |
| 2337 MakeCodeBreakpointAt(func, bpt); | 2380 MakeCodeBreakpointAt(func, bpt); |
| 2338 } | 2381 } |
| 2339 } | 2382 } |
| 2340 } | 2383 } |
| 2341 | 2384 |
| 2342 | 2385 |
| 2386 void Debugger::NotifyDoneLoading() { |
| 2387 if (latent_breakpoints_ == NULL) { |
| 2388 // Common, fast path. |
| 2389 return; |
| 2390 } |
| 2391 Library& lib = Library::Handle(isolate_); |
| 2392 Script& script = Script::Handle(isolate_); |
| 2393 String& url = String::Handle(isolate_); |
| 2394 SourceBreakpoint* bpt = latent_breakpoints_; |
| 2395 SourceBreakpoint* prev_bpt = NULL; |
| 2396 const GrowableObjectArray& libs = |
| 2397 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 2398 while (bpt != NULL) { |
| 2399 url = bpt->url(); |
| 2400 for (intptr_t i = 0; i < libs.Length(); i++) { |
| 2401 lib ^= libs.At(i); |
| 2402 script = lib.LookupScript(url); |
| 2403 if (!script.IsNull()) { |
| 2404 // Found a script with matching url for this latent breakpoint. |
| 2405 // Unlink the latent breakpoint from the list. |
| 2406 SourceBreakpoint* matched_bpt = bpt; |
| 2407 bpt = bpt->next(); |
| 2408 if (prev_bpt == NULL) { |
| 2409 latent_breakpoints_ = bpt; |
| 2410 } else { |
| 2411 prev_bpt->set_next(bpt); |
| 2412 } |
| 2413 // Now find the token range at the requested line and make a |
| 2414 // new unresolved source breakpoint. |
| 2415 intptr_t line_number = matched_bpt->LineNumber(); |
| 2416 ASSERT(line_number >= 0); |
| 2417 intptr_t first_token_pos, last_token_pos; |
| 2418 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); |
| 2419 if ((first_token_pos < 0) || |
| 2420 (last_token_pos < 0)) { |
| 2421 // Script does not contain the given line number or there are no |
| 2422 // tokens on the line. Drop the breakpoint silently. |
| 2423 if (FLAG_verbose_debug) { |
| 2424 OS::Print("No code found at line %" Pd ": " |
| 2425 "dropping latent breakpoint %" Pd " in '%s'\n", |
| 2426 line_number, |
| 2427 matched_bpt->id(), |
| 2428 url.ToCString()); |
| 2429 } |
| 2430 delete matched_bpt; |
| 2431 } else { |
| 2432 // We don't expect to already have a breakpoint for this location. |
| 2433 // If there is one, assert in debug build but silently drop |
| 2434 // the latent breakpoint in release build. |
| 2435 SourceBreakpoint* existing_bpt = |
| 2436 GetSourceBreakpoint(script, first_token_pos); |
| 2437 ASSERT(existing_bpt == NULL); |
| 2438 if (existing_bpt == NULL) { |
| 2439 // Create and register a new source breakpoint for the |
| 2440 // latent breakpoint. |
| 2441 SourceBreakpoint* unresolved_bpt = |
| 2442 new SourceBreakpoint(matched_bpt->id(), |
| 2443 script, |
| 2444 first_token_pos, |
| 2445 last_token_pos); |
| 2446 RegisterSourceBreakpoint(unresolved_bpt); |
| 2447 unresolved_bpt->Enable(); |
| 2448 if (FLAG_verbose_debug) { |
| 2449 OS::Print("Converted latent breakpoint " |
| 2450 "%" Pd " in '%s' at line %" Pd "\n", |
| 2451 matched_bpt->id(), |
| 2452 url.ToCString(), |
| 2453 line_number); |
| 2454 } |
| 2455 } |
| 2456 delete matched_bpt; |
| 2457 // Break out of the iteration over loaded libraries. If the |
| 2458 // same url has been loaded into more than one library, we |
| 2459 // only set a breakpoint in the first one. |
| 2460 // TODO(hausner): There is one possible pitfall here. |
| 2461 // If the user sets a latent breakpoint using a partial url that |
| 2462 // ends up matching more than one script, the breakpoint might |
| 2463 // get set in the wrong script. |
| 2464 // It would be better if we could warn the user if multiple |
| 2465 // scripts are matching. |
| 2466 break; |
| 2467 } |
| 2468 } |
| 2469 } |
| 2470 } |
| 2471 } |
| 2472 |
| 2473 |
| 2343 // TODO(hausner): Could potentially make this faster by checking | 2474 // TODO(hausner): Could potentially make this faster by checking |
| 2344 // whether the call target at pc is a debugger stub. | 2475 // whether the call target at pc is a debugger stub. |
| 2345 bool Debugger::HasActiveBreakpoint(uword pc) { | 2476 bool Debugger::HasActiveBreakpoint(uword pc) { |
| 2346 CodeBreakpoint* bpt = GetCodeBreakpoint(pc); | 2477 CodeBreakpoint* bpt = GetCodeBreakpoint(pc); |
| 2347 return (bpt != NULL) && (bpt->IsEnabled()); | 2478 return (bpt != NULL) && (bpt->IsEnabled()); |
| 2348 } | 2479 } |
| 2349 | 2480 |
| 2350 | 2481 |
| 2351 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 2482 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
| 2352 CodeBreakpoint* bpt = code_breakpoints_; | 2483 CodeBreakpoint* bpt = code_breakpoints_; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2463 while (bpt != NULL) { | 2594 while (bpt != NULL) { |
| 2464 if (bpt->id() == id) { | 2595 if (bpt->id() == id) { |
| 2465 return bpt; | 2596 return bpt; |
| 2466 } | 2597 } |
| 2467 bpt = bpt->next(); | 2598 bpt = bpt->next(); |
| 2468 } | 2599 } |
| 2469 return NULL; | 2600 return NULL; |
| 2470 } | 2601 } |
| 2471 | 2602 |
| 2472 | 2603 |
| 2604 SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url, |
| 2605 intptr_t line) { |
| 2606 SourceBreakpoint* bpt = latent_breakpoints_; |
| 2607 String& bpt_url = String::Handle(isolate_); |
| 2608 while (bpt != NULL) { |
| 2609 bpt_url = bpt->url(); |
| 2610 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { |
| 2611 return bpt; |
| 2612 } |
| 2613 bpt = bpt->next(); |
| 2614 } |
| 2615 // No breakpint for this url and line requested. Allocate new one. |
| 2616 bpt = new SourceBreakpoint(nextId(), url, line); |
| 2617 bpt->set_next(latent_breakpoints_); |
| 2618 latent_breakpoints_ = bpt; |
| 2619 return bpt; |
| 2620 } |
| 2621 |
| 2622 |
| 2473 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { | 2623 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { |
| 2474 ASSERT(bpt->next() == NULL); | 2624 ASSERT(bpt->next() == NULL); |
| 2475 bpt->set_next(src_breakpoints_); | 2625 bpt->set_next(src_breakpoints_); |
| 2476 src_breakpoints_ = bpt; | 2626 src_breakpoints_ = bpt; |
| 2477 } | 2627 } |
| 2478 | 2628 |
| 2479 | 2629 |
| 2480 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2630 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 2481 ASSERT(bpt->next() == NULL); | 2631 ASSERT(bpt->next() == NULL); |
| 2482 bpt->set_next(code_breakpoints_); | 2632 bpt->set_next(code_breakpoints_); |
| 2483 code_breakpoints_ = bpt; | 2633 code_breakpoints_ = bpt; |
| 2484 } | 2634 } |
| 2485 | 2635 |
| 2486 } // namespace dart | 2636 } // namespace dart |
| OLD | NEW |