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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 } | 43 } |
44 | 44 |
45 private: | 45 private: |
46 GrowableObjectArray* objs_; | 46 GrowableObjectArray* objs_; |
47 | 47 |
48 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 48 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
49 }; | 49 }; |
50 | 50 |
51 | 51 |
52 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 52 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
53 const Function& func, | 53 const Script& script, |
54 intptr_t token_pos) | 54 intptr_t token_pos) |
55 : id_(id), | 55 : id_(id), |
56 function_(func.raw()), | 56 script_(script.raw()), |
57 token_pos_(token_pos), | 57 token_pos_(token_pos), |
58 line_number_(-1), | 58 is_resolved_(false), |
59 is_enabled_(false), | 59 is_enabled_(false), |
60 next_(NULL) { | 60 next_(NULL), |
61 ASSERT(!func.IsNull()); | 61 function_(Function::null()), |
62 ASSERT((func.token_pos() <= token_pos_) && | 62 line_number_(-1) { |
63 (token_pos_ <= func.end_token_pos())); | 63 ASSERT(id_ > 0); |
| 64 ASSERT(!script.IsNull()); |
| 65 ASSERT(token_pos_ >= 0); |
64 } | 66 } |
65 | 67 |
66 | 68 |
67 void SourceBreakpoint::Enable() { | 69 void SourceBreakpoint::Enable() { |
68 is_enabled_ = true; | 70 is_enabled_ = true; |
69 Isolate::Current()->debugger()->SyncBreakpoint(this); | 71 Isolate::Current()->debugger()->SyncBreakpoint(this); |
70 } | 72 } |
71 | 73 |
72 | 74 |
73 void SourceBreakpoint::Disable() { | 75 void SourceBreakpoint::Disable() { |
74 is_enabled_ = false; | 76 is_enabled_ = false; |
75 Isolate::Current()->debugger()->SyncBreakpoint(this); | 77 Isolate::Current()->debugger()->SyncBreakpoint(this); |
76 } | 78 } |
77 | 79 |
78 | 80 |
79 RawScript* SourceBreakpoint::SourceCode() { | 81 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) { |
80 const Function& func = Function::Handle(function_); | 82 ASSERT(func.script() == script_); |
81 return func.script(); | 83 ASSERT((func.token_pos() <= token_pos) && |
| 84 (token_pos <= func.end_token_pos())); |
| 85 function_ = func.raw(); |
| 86 token_pos_ = token_pos; |
| 87 line_number_ = -1; // Recalcualte lazily. |
| 88 is_resolved_ = true; |
82 } | 89 } |
83 | 90 |
84 | 91 |
| 92 // TODO(hausner): Get rid of library parameter. A source breakpoint location |
| 93 // does not imply a library, since the same source code can be included |
| 94 // in more than one library, e.g. the text location of mixin functions. |
85 void SourceBreakpoint::GetCodeLocation( | 95 void SourceBreakpoint::GetCodeLocation( |
86 Library* lib, | 96 Library* lib, |
87 Script* script, | 97 Script* script, |
88 intptr_t* pos) const { | 98 intptr_t* pos) { |
89 const Function& func = Function::Handle(function_); | 99 *script = this->script(); |
90 const Class& cls = Class::Handle(func.origin()); | 100 *pos = token_pos_; |
91 *lib = cls.library(); | 101 if (IsResolved()) { |
92 *script = func.script(); | 102 const Function& func = Function::Handle(function_); |
93 *pos = token_pos(); | 103 ASSERT(!func.IsNull()); |
| 104 const Class& cls = Class::Handle(func.origin()); |
| 105 *lib = cls.library(); |
| 106 } else { |
| 107 *lib = Library::null(); |
| 108 } |
94 } | 109 } |
95 | 110 |
96 | 111 |
97 RawString* SourceBreakpoint::SourceUrl() { | 112 RawString* SourceBreakpoint::SourceUrl() { |
98 const Script& script = Script::Handle(SourceCode()); | 113 return Script::Handle(script()).url(); |
99 return script.url(); | |
100 } | 114 } |
101 | 115 |
102 | 116 |
103 intptr_t SourceBreakpoint::LineNumber() { | 117 intptr_t SourceBreakpoint::LineNumber() { |
104 // Compute line number lazily since it causes scanning of the script. | 118 // Compute line number lazily since it causes scanning of the script. |
105 if (line_number_ < 0) { | 119 if (line_number_ < 0) { |
106 const Script& script = Script::Handle(SourceCode()); | 120 const Script& script = Script::Handle(this->script()); |
107 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 121 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
108 } | 122 } |
109 return line_number_; | 123 return line_number_; |
110 } | 124 } |
111 | 125 |
112 | 126 |
113 void SourceBreakpoint::set_function(const Function& func) { | |
114 function_ = func.raw(); | |
115 } | |
116 | |
117 | |
118 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 127 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 128 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
119 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 129 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
120 } | 130 } |
121 | 131 |
122 | 132 |
123 void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) const { | 133 void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) { |
124 Isolate* isolate = Isolate::Current(); | 134 Isolate* isolate = Isolate::Current(); |
125 | 135 |
126 JSONObject jsobj(stream); | 136 JSONObject jsobj(stream); |
127 jsobj.AddProperty("type", "Breakpoint"); | 137 jsobj.AddProperty("type", "Breakpoint"); |
128 | 138 |
129 jsobj.AddProperty("id", id()); | 139 jsobj.AddProperty("id", id()); |
130 jsobj.AddProperty("enabled", IsEnabled()); | 140 jsobj.AddProperty("enabled", IsEnabled()); |
131 | 141 jsobj.AddProperty("resolved", IsResolved()); |
132 const Function& func = Function::Handle(function()); | |
133 jsobj.AddProperty("resolved", func.HasCode()); | |
134 | 142 |
135 Library& library = Library::Handle(isolate); | 143 Library& library = Library::Handle(isolate); |
136 Script& script = Script::Handle(isolate); | 144 Script& script = Script::Handle(isolate); |
137 intptr_t token_pos; | 145 intptr_t token_pos; |
138 GetCodeLocation(&library, &script, &token_pos); | 146 GetCodeLocation(&library, &script, &token_pos); |
139 { | 147 { |
140 JSONObject location(&jsobj, "location"); | 148 JSONObject location(&jsobj, "location"); |
141 location.AddProperty("type", "Location"); | 149 location.AddProperty("type", "Location"); |
142 location.AddProperty("libId", library.index()); | |
143 | 150 |
144 const String& url = String::Handle(script.url()); | 151 const String& url = String::Handle(script.url()); |
145 location.AddProperty("script", url.ToCString()); | 152 location.AddProperty("script", url.ToCString()); |
146 location.AddProperty("tokenPos", token_pos); | 153 location.AddProperty("tokenPos", token_pos); |
147 } | 154 } |
148 } | 155 } |
149 | 156 |
150 | 157 |
151 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 158 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
152 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 159 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 len++; // String terminator. | 221 len++; // String terminator. |
215 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); | 222 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); |
216 OS::SNPrint(chars, len, kFormat, | 223 OS::SNPrint(chars, len, kFormat, |
217 func_class.IsTopLevel() ? "" : class_name.ToCString(), | 224 func_class.IsTopLevel() ? "" : class_name.ToCString(), |
218 func_class.IsTopLevel() ? "" : ".", | 225 func_class.IsTopLevel() ? "" : ".", |
219 func_name.ToCString()); | 226 func_name.ToCString()); |
220 return chars; | 227 return chars; |
221 } | 228 } |
222 | 229 |
223 | 230 |
| 231 // Returns true if function contains the token position in the given script. |
| 232 static bool FunctionContains(const Function& func, |
| 233 const Script& script, |
| 234 intptr_t token_pos) { |
| 235 if ((func.token_pos() <= token_pos) && (token_pos <= func.end_token_pos())) { |
| 236 // Check script equality second because it allocates |
| 237 // handles as a side effect. |
| 238 return func.script() == script.raw(); |
| 239 } |
| 240 return false; |
| 241 } |
| 242 |
| 243 |
224 bool Debugger::HasBreakpoint(const Function& func) { | 244 bool Debugger::HasBreakpoint(const Function& func) { |
225 if (!func.HasCode()) { | 245 if (!func.HasCode()) { |
226 // If the function is not compiled yet, just check whether there | 246 // If the function is not compiled yet, just check whether there |
227 // is a user-defined latent breakpoint. | 247 // is a user-defined breakpoint that falls into the token |
| 248 // range of the function. This may be a false positive: the breakpoint |
| 249 // might be inside a local closure. |
| 250 Script& script = Script::Handle(isolate_); |
228 SourceBreakpoint* sbpt = src_breakpoints_; | 251 SourceBreakpoint* sbpt = src_breakpoints_; |
229 while (sbpt != NULL) { | 252 while (sbpt != NULL) { |
230 if (func.raw() == sbpt->function()) { | 253 script = sbpt->script(); |
| 254 if (FunctionContains(func, script, sbpt->token_pos())) { |
231 return true; | 255 return true; |
232 } | 256 } |
233 sbpt = sbpt->next_; | 257 sbpt = sbpt->next_; |
234 } | 258 } |
235 return false; | 259 return false; |
236 } | 260 } |
237 CodeBreakpoint* cbpt = code_breakpoints_; | 261 CodeBreakpoint* cbpt = code_breakpoints_; |
238 while (cbpt != NULL) { | 262 while (cbpt != NULL) { |
239 if (func.raw() == cbpt->function()) { | 263 if (func.raw() == cbpt->function()) { |
240 return true; | 264 return true; |
(...skipping 1037 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1278 } | 1302 } |
1279 DebuggerEvent event(kExceptionThrown); | 1303 DebuggerEvent event(kExceptionThrown); |
1280 event.exception = &exc; | 1304 event.exception = &exc; |
1281 ASSERT(stack_trace_ == NULL); | 1305 ASSERT(stack_trace_ == NULL); |
1282 stack_trace_ = stack_trace; | 1306 stack_trace_ = stack_trace; |
1283 Pause(&event); | 1307 Pause(&event); |
1284 stack_trace_ = NULL; | 1308 stack_trace_ = NULL; |
1285 } | 1309 } |
1286 | 1310 |
1287 | 1311 |
1288 // Given a function and a token position range, return the best fit | 1312 // Given a function and a token position, return the best fit |
1289 // token position to set a breakpoint. | 1313 // token position to set a breakpoint. The best fit is the safe point |
1290 // If multiple possible breakpoint positions are within the given range, | 1314 // with the lowest compiled code address that follows the requsted |
1291 // the one with the lowest machine code address is picked. | 1315 // token position. |
1292 // If no possible breakpoint location exists in the given range, the closest | |
1293 // token position after the range is returned. | |
1294 intptr_t Debugger::ResolveBreakpointPos(const Function& func, | 1316 intptr_t Debugger::ResolveBreakpointPos(const Function& func, |
1295 intptr_t first_token_pos, | 1317 intptr_t requested_token_pos) { |
1296 intptr_t last_token_pos) { | |
1297 ASSERT(func.HasCode()); | 1318 ASSERT(func.HasCode()); |
1298 ASSERT(!func.HasOptimizedCode()); | 1319 ASSERT(!func.HasOptimizedCode()); |
1299 Code& code = Code::Handle(func.unoptimized_code()); | 1320 Code& code = Code::Handle(func.unoptimized_code()); |
1300 ASSERT(!code.IsNull()); | 1321 ASSERT(!code.IsNull()); |
1301 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1322 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
1302 intptr_t best_fit_index = -1; | 1323 intptr_t best_fit_index = -1; |
1303 intptr_t best_fit = INT_MAX; | 1324 intptr_t best_fit_pos = INT_MAX; |
1304 uword lowest_pc = kUwordMax; | 1325 uword lowest_pc = kUwordMax; |
1305 intptr_t lowest_pc_index = -1; | 1326 intptr_t lowest_pc_index = -1; |
1306 for (intptr_t i = 0; i < desc.Length(); i++) { | 1327 for (intptr_t i = 0; i < desc.Length(); i++) { |
1307 intptr_t desc_token_pos = desc.TokenPos(i); | 1328 intptr_t desc_token_pos = desc.TokenPos(i); |
1308 ASSERT(desc_token_pos >= 0); | 1329 ASSERT(desc_token_pos >= 0); |
1309 if (desc_token_pos < first_token_pos) { | 1330 if (desc_token_pos < requested_token_pos) { |
1310 // This descriptor is before the given range. | 1331 // This descriptor is before the first acceptable token position. |
1311 continue; | 1332 continue; |
1312 } | 1333 } |
1313 if (IsSafePoint(desc.DescriptorKind(i))) { | 1334 if (IsSafePoint(desc.DescriptorKind(i))) { |
1314 if ((desc_token_pos - first_token_pos) < best_fit) { | 1335 if (desc_token_pos < best_fit_pos) { |
1315 // So far, this descriptor has the closest token position to the | 1336 // So far, this descriptor has the lowest token position after |
1316 // beginning of the range. | 1337 // the first acceptable token position. |
1317 best_fit = desc_token_pos - first_token_pos; | 1338 best_fit_pos = desc_token_pos; |
1318 ASSERT(best_fit >= 0); | |
1319 best_fit_index = i; | 1339 best_fit_index = i; |
1320 } | 1340 } |
1321 if ((first_token_pos <= desc_token_pos) && | 1341 if (desc.PC(i) < lowest_pc) { |
1322 (desc_token_pos <= last_token_pos) && | 1342 // This descriptor so far has the lowest code address. |
1323 (desc.PC(i) < lowest_pc)) { | |
1324 // This descriptor is within the token position range and so | |
1325 // far has the lowest code address. | |
1326 lowest_pc = desc.PC(i); | 1343 lowest_pc = desc.PC(i); |
1327 lowest_pc_index = i; | 1344 lowest_pc_index = i; |
1328 } | 1345 } |
1329 } | 1346 } |
1330 } | 1347 } |
1331 if (lowest_pc_index >= 0) { | 1348 if (lowest_pc_index >= 0) { |
1332 // We found the the pc descriptor within the given token range that | 1349 // We found the pc descriptor that has the lowest execution address. |
1333 // has the lowest execution address. This is the first possible | 1350 // This is the first possible breakpoint after the requested token |
1334 // breakpoint on the line. We use this instead of the nearest | 1351 // position. We use this instead of the nearest PC descriptor |
1335 // PC descriptor measured in token index distance. | 1352 // measured in token index distance. |
1336 best_fit_index = lowest_pc_index; | 1353 best_fit_index = lowest_pc_index; |
1337 } | 1354 } |
1338 if (best_fit_index >= 0) { | 1355 if (best_fit_index >= 0) { |
1339 return desc.TokenPos(best_fit_index); | 1356 return desc.TokenPos(best_fit_index); |
1340 } | 1357 } |
1341 return -1; | 1358 return -1; |
1342 } | 1359 } |
1343 | 1360 |
1344 | 1361 |
1345 void Debugger::MakeCodeBreakpointsAt(const Function& func, | 1362 void Debugger::MakeCodeBreakpointsAt(const Function& func, |
1346 intptr_t token_pos, | |
1347 SourceBreakpoint* bpt) { | 1363 SourceBreakpoint* bpt) { |
| 1364 ASSERT((bpt != NULL) && bpt->IsResolved()); |
1348 ASSERT(!func.HasOptimizedCode()); | 1365 ASSERT(!func.HasOptimizedCode()); |
1349 Code& code = Code::Handle(func.unoptimized_code()); | 1366 Code& code = Code::Handle(func.unoptimized_code()); |
1350 ASSERT(!code.IsNull()); | 1367 ASSERT(!code.IsNull()); |
1351 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1368 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
1352 for (intptr_t i = 0; i < desc.Length(); i++) { | 1369 for (intptr_t i = 0; i < desc.Length(); i++) { |
1353 intptr_t desc_token_pos = desc.TokenPos(i); | 1370 intptr_t desc_token_pos = desc.TokenPos(i); |
1354 if ((desc_token_pos == token_pos) && IsSafePoint(desc.DescriptorKind(i))) { | 1371 if ((desc_token_pos == bpt->token_pos_) && |
| 1372 IsSafePoint(desc.DescriptorKind(i))) { |
1355 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i)); | 1373 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i)); |
1356 if (code_bpt == NULL) { | 1374 if (code_bpt == NULL) { |
1357 // No code breakpoint for this code exists; create one. | 1375 // No code breakpoint for this code exists; create one. |
1358 code_bpt = new CodeBreakpoint(func, i); | 1376 code_bpt = new CodeBreakpoint(func, i); |
1359 RegisterCodeBreakpoint(code_bpt); | 1377 RegisterCodeBreakpoint(code_bpt); |
1360 } | 1378 } |
1361 code_bpt->set_src_bpt(bpt); | 1379 code_bpt->set_src_bpt(bpt); |
1362 } | 1380 if (bpt->IsEnabled()) { |
1363 } | 1381 code_bpt->Enable(); |
1364 } | 1382 } |
1365 | 1383 } |
1366 | 1384 } |
1367 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, | 1385 } |
1368 intptr_t first_token_pos, | 1386 |
1369 intptr_t last_token_pos) { | 1387 |
1370 if ((last_token_pos < target_function.token_pos()) || | 1388 void Debugger::FindEquivalentFunctions(const Script& script, |
1371 (target_function.end_token_pos() < first_token_pos)) { | 1389 intptr_t start_pos, |
1372 // The given token position is not within the target function. | 1390 intptr_t end_pos, |
| 1391 GrowableObjectArray* function_list) { |
| 1392 Class& cls = Class::Handle(isolate_); |
| 1393 Array& functions = Array::Handle(isolate_); |
| 1394 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_); |
| 1395 Function& function = Function::Handle(isolate_); |
| 1396 |
| 1397 const ClassTable& class_table = *isolate_->class_table(); |
| 1398 const intptr_t num_classes = class_table.NumCids(); |
| 1399 for (intptr_t i = 1; i < num_classes; i++) { |
| 1400 if (class_table.HasValidClassAt(i)) { |
| 1401 cls = class_table.At(i); |
| 1402 // Note: we need to check the functions of this class even if |
| 1403 // the class is defined in a differenct 'script'. There could |
| 1404 // be mixin functions from the given script in this class. |
| 1405 functions = cls.functions(); |
| 1406 if (!functions.IsNull()) { |
| 1407 const intptr_t num_functions = functions.Length(); |
| 1408 for (intptr_t pos = 0; pos < num_functions; pos++) { |
| 1409 function ^= functions.At(pos); |
| 1410 ASSERT(!function.IsNull()); |
| 1411 // Check token position first to avoid unnecessary calls |
| 1412 // to script() which allocates handles. |
| 1413 if ((function.token_pos() == start_pos) |
| 1414 && (function.end_token_pos() == end_pos) |
| 1415 && (function.script() == script.raw())) { |
| 1416 function_list->Add(function); |
| 1417 if (function.HasImplicitClosureFunction()) { |
| 1418 function = function.ImplicitClosureFunction(); |
| 1419 function_list->Add(function); |
| 1420 } |
| 1421 } |
| 1422 } |
| 1423 } |
| 1424 closures = cls.closures(); |
| 1425 if (!closures.IsNull()) { |
| 1426 const intptr_t num_closures = closures.Length(); |
| 1427 for (intptr_t pos = 0; pos < num_closures; pos++) { |
| 1428 function ^= closures.At(pos); |
| 1429 ASSERT(!function.IsNull()); |
| 1430 if ((function.token_pos() == start_pos) |
| 1431 && (function.end_token_pos() == end_pos) |
| 1432 && (function.script() == script.raw())) { |
| 1433 function_list->Add(function); |
| 1434 if (function.HasImplicitClosureFunction()) { |
| 1435 function = function.ImplicitClosureFunction(); |
| 1436 function_list->Add(function); |
| 1437 } |
| 1438 } |
| 1439 } |
| 1440 } |
| 1441 } |
| 1442 } |
| 1443 } |
| 1444 |
| 1445 |
| 1446 static void SelectBestFit(Function* best_fit, Function* func) { |
| 1447 if (best_fit->IsNull()) { |
| 1448 *best_fit = func->raw(); |
| 1449 } |
| 1450 if (func->token_pos() > best_fit->token_pos()) { |
| 1451 if (func->end_token_pos() <= best_fit->end_token_pos()) { |
| 1452 // func is contained within best_fit. Select it even if it |
| 1453 // has not been compiled yet. |
| 1454 *best_fit = func->raw(); |
| 1455 if (func->HasImplicitClosureFunction()) { |
| 1456 *func = func->ImplicitClosureFunction(); |
| 1457 if (func->HasCode()) { |
| 1458 *best_fit = func->raw(); |
| 1459 } |
| 1460 } |
| 1461 } |
| 1462 } else if ((func->token_pos() == best_fit->token_pos()) |
| 1463 && (func->end_token_pos() == best_fit->end_token_pos()) |
| 1464 && func->HasCode()) { |
| 1465 // If func covers the same range, it is considered a better fit if |
| 1466 // it has been compiled. |
| 1467 *best_fit = func->raw(); |
| 1468 } |
| 1469 } |
| 1470 |
| 1471 |
| 1472 RawFunction* Debugger::FindBestFit(const Script& script, |
| 1473 intptr_t token_pos) { |
| 1474 Class& cls = Class::Handle(isolate_); |
| 1475 Array& functions = Array::Handle(isolate_); |
| 1476 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_); |
| 1477 Function& function = Function::Handle(isolate_); |
| 1478 Function& best_fit = Function::Handle(isolate_); |
| 1479 |
| 1480 const ClassTable& class_table = *isolate_->class_table(); |
| 1481 const intptr_t num_classes = class_table.NumCids(); |
| 1482 for (intptr_t i = 1; i < num_classes; i++) { |
| 1483 if (class_table.HasValidClassAt(i)) { |
| 1484 cls = class_table.At(i); |
| 1485 // Note: we need to check the functions of this class even if |
| 1486 // the class is defined in a differenct 'script'. There could |
| 1487 // be mixin functions from the given script in this class. |
| 1488 functions = cls.functions(); |
| 1489 if (!functions.IsNull()) { |
| 1490 const intptr_t num_functions = functions.Length(); |
| 1491 for (intptr_t pos = 0; pos < num_functions; pos++) { |
| 1492 function ^= functions.At(pos); |
| 1493 ASSERT(!function.IsNull()); |
| 1494 if (FunctionContains(function, script, token_pos)) { |
| 1495 SelectBestFit(&best_fit, &function); |
| 1496 } |
| 1497 } |
| 1498 } |
| 1499 |
| 1500 closures = cls.closures(); |
| 1501 if (!closures.IsNull()) { |
| 1502 const intptr_t num_closures = closures.Length(); |
| 1503 for (intptr_t pos = 0; pos < num_closures; pos++) { |
| 1504 function ^= closures.At(pos); |
| 1505 ASSERT(!function.IsNull()); |
| 1506 if (FunctionContains(function, script, token_pos)) { |
| 1507 SelectBestFit(&best_fit, &function); |
| 1508 } |
| 1509 } |
| 1510 } |
| 1511 } |
| 1512 } |
| 1513 return best_fit.raw(); |
| 1514 } |
| 1515 |
| 1516 |
| 1517 SourceBreakpoint* Debugger::SetBreakpoint(const Script& script, |
| 1518 intptr_t token_pos) { |
| 1519 Function& func = Function::Handle(isolate_); |
| 1520 func = FindBestFit(script, token_pos); |
| 1521 if (func.IsNull()) { |
1373 return NULL; | 1522 return NULL; |
1374 } | 1523 } |
1375 intptr_t breakpoint_pos = -1; | 1524 if (!func.IsNull() && func.HasCode()) { |
1376 Function& closure = Function::Handle(isolate_); | 1525 // A function containing this breakpoint location has already |
1377 if (target_function.HasImplicitClosureFunction()) { | 1526 // been compiled. We can resolve the breakpoint now. |
1378 // There is a closurized version of this function. | |
1379 closure = target_function.ImplicitClosureFunction(); | |
1380 } | |
1381 // Determine actual breakpoint location if the function or an | |
1382 // implicit closure of the function has been compiled already. | |
1383 if (target_function.HasCode()) { | |
1384 DeoptimizeWorld(); | 1527 DeoptimizeWorld(); |
1385 ASSERT(!target_function.HasOptimizedCode()); | 1528 intptr_t breakpoint_pos = ResolveBreakpointPos(func, token_pos); |
1386 breakpoint_pos = | 1529 if (breakpoint_pos >= 0) { |
1387 ResolveBreakpointPos(target_function, first_token_pos, last_token_pos); | 1530 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); |
1388 } else if (!closure.IsNull() && closure.HasCode()) { | 1531 if (bpt != NULL) { |
1389 DeoptimizeWorld(); | 1532 // A source breakpoint for this location already exists. |
1390 ASSERT(!closure.HasOptimizedCode()); | 1533 return bpt; |
1391 breakpoint_pos = | 1534 } |
1392 ResolveBreakpointPos(closure, first_token_pos, last_token_pos); | 1535 bpt = new SourceBreakpoint(nextId(), script, token_pos); |
1393 } else { | 1536 bpt->SetResolved(func, breakpoint_pos); |
1394 // This function has not been compiled yet. Set a pending | 1537 RegisterSourceBreakpoint(bpt); |
1395 // breakpoint to be resolved later. | 1538 // There may be more than one function object for a given function |
1396 SourceBreakpoint* source_bpt = | 1539 // in source code. There may be implicit closure functions, and |
1397 GetSourceBreakpoint(target_function, first_token_pos); | 1540 // there may be copies of mixin functions. Collect all functions whose |
1398 if (source_bpt != NULL) { | 1541 // source code range matches exactly the best fit function we |
1399 // A pending source breakpoint for this uncompiled location | 1542 // found. |
1400 // already exists. | 1543 GrowableObjectArray& functions = |
1401 if (FLAG_verbose_debug) { | 1544 GrowableObjectArray::Handle(GrowableObjectArray::New()); |
1402 OS::Print("Pending breakpoint for uncompiled function" | 1545 FindEquivalentFunctions(script, |
1403 " '%s' at line %" Pd " already exists\n", | 1546 func.token_pos(), |
1404 target_function.ToFullyQualifiedCString(), | 1547 func.end_token_pos(), |
1405 source_bpt->LineNumber()); | 1548 &functions); |
1406 } | 1549 const intptr_t num_functions = functions.Length(); |
1407 return source_bpt; | 1550 // We must have found at least one function: func. |
1408 } | 1551 ASSERT(num_functions > 0); |
1409 source_bpt = | 1552 // Create code breakpoints for all compiled functions we found. |
1410 new SourceBreakpoint(nextId(), target_function, first_token_pos); | 1553 for (intptr_t i = 0; i < num_functions; i++) { |
1411 RegisterSourceBreakpoint(source_bpt); | 1554 func ^= functions.At(i); |
1412 if (FLAG_verbose_debug) { | 1555 if (func.HasCode()) { |
1413 OS::Print("Registering pending breakpoint for " | 1556 MakeCodeBreakpointsAt(func, bpt); |
1414 "uncompiled function '%s' at line %" Pd "\n", | 1557 } |
1415 target_function.ToFullyQualifiedCString(), | 1558 } |
1416 source_bpt->LineNumber()); | 1559 bpt->Enable(); |
1417 } | 1560 SignalBpResolved(bpt); |
1418 source_bpt->Enable(); | 1561 return bpt; |
1419 return source_bpt; | 1562 } |
1420 } | 1563 } |
1421 ASSERT(breakpoint_pos != -1); | 1564 // There is no compiled function at this token position. |
1422 SourceBreakpoint* source_bpt = | 1565 // Register an unresolved breakpoint. |
1423 GetSourceBreakpoint(target_function, breakpoint_pos); | 1566 if (FLAG_verbose_debug && !func.IsNull()) { |
1424 if (source_bpt != NULL) { | 1567 intptr_t line_number; |
1425 // A source breakpoint for this location already exists. | 1568 script.GetTokenLocation(token_pos, &line_number, NULL); |
1426 return source_bpt; | 1569 OS::Print("Registering pending breakpoint for " |
1427 } | 1570 "uncompiled function '%s' at line %" Pd "\n", |
1428 source_bpt = new SourceBreakpoint(nextId(), target_function, breakpoint_pos); | 1571 func.ToFullyQualifiedCString(), |
1429 RegisterSourceBreakpoint(source_bpt); | 1572 line_number); |
1430 if (target_function.HasCode()) { | 1573 } |
1431 MakeCodeBreakpointsAt(target_function, breakpoint_pos, source_bpt); | 1574 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); |
1432 } | 1575 if (bpt == NULL) { |
1433 if (!closure.IsNull() && closure.HasCode()) { | 1576 bpt = new SourceBreakpoint(nextId(), script, token_pos); |
1434 MakeCodeBreakpointsAt(closure, breakpoint_pos, source_bpt); | 1577 } |
1435 } | 1578 RegisterSourceBreakpoint(bpt); |
1436 source_bpt->Enable(); | 1579 bpt->Enable(); |
1437 SignalBpResolved(source_bpt); | 1580 return bpt; |
1438 return source_bpt; | 1581 } |
1439 } | 1582 |
1440 | 1583 |
1441 | |
1442 // Synchronize the enabled/disabled state of all code breakpoints | 1584 // Synchronize the enabled/disabled state of all code breakpoints |
1443 // associated with the source breakpoint bpt. | 1585 // associated with the source breakpoint bpt. |
1444 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { | 1586 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
1445 CodeBreakpoint* cbpt = code_breakpoints_; | 1587 CodeBreakpoint* cbpt = code_breakpoints_; |
1446 while (cbpt != NULL) { | 1588 while (cbpt != NULL) { |
1447 if (bpt == cbpt->src_bpt()) { | 1589 if (bpt == cbpt->src_bpt()) { |
1448 if (bpt->IsEnabled()) { | 1590 if (bpt->IsEnabled()) { |
1449 cbpt->Enable(); | 1591 cbpt->Enable(); |
1450 } else { | 1592 } else { |
1451 cbpt->Disable(); | 1593 cbpt->Disable(); |
(...skipping 10 matching lines...) Expand all Loading... |
1462 const Function& closure_func = | 1604 const Function& closure_func = |
1463 Function::Handle(target_function.ImplicitClosureFunction()); | 1605 Function::Handle(target_function.ImplicitClosureFunction()); |
1464 InstrumentForStepping(closure_func); | 1606 InstrumentForStepping(closure_func); |
1465 } | 1607 } |
1466 } | 1608 } |
1467 | 1609 |
1468 | 1610 |
1469 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 1611 SourceBreakpoint* Debugger::SetBreakpointAtEntry( |
1470 const Function& target_function) { | 1612 const Function& target_function) { |
1471 ASSERT(!target_function.IsNull()); | 1613 ASSERT(!target_function.IsNull()); |
1472 return SetBreakpoint(target_function, | 1614 const Script& script = Script::Handle(target_function.script()); |
1473 target_function.token_pos(), | 1615 return SetBreakpoint(script, target_function.token_pos()); |
1474 target_function.end_token_pos()); | |
1475 } | 1616 } |
1476 | 1617 |
1477 | 1618 |
1478 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 1619 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
1479 intptr_t line_number) { | 1620 intptr_t line_number) { |
1480 Library& lib = Library::Handle(isolate_); | 1621 Library& lib = Library::Handle(isolate_); |
1481 Script& script = Script::Handle(isolate_); | 1622 Script& script = Script::Handle(isolate_); |
1482 const GrowableObjectArray& libs = | 1623 const GrowableObjectArray& libs = |
1483 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 1624 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
1484 for (intptr_t i = 0; i < libs.Length(); i++) { | 1625 for (intptr_t i = 0; i < libs.Length(); i++) { |
(...skipping 13 matching lines...) Expand all Loading... |
1498 intptr_t first_token_idx, last_token_idx; | 1639 intptr_t first_token_idx, last_token_idx; |
1499 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); | 1640 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); |
1500 if (first_token_idx < 0) { | 1641 if (first_token_idx < 0) { |
1501 // Script does not contain the given line number. | 1642 // Script does not contain the given line number. |
1502 if (FLAG_verbose_debug) { | 1643 if (FLAG_verbose_debug) { |
1503 OS::Print("Script '%s' does not contain line number %" Pd "\n", | 1644 OS::Print("Script '%s' does not contain line number %" Pd "\n", |
1504 script_url.ToCString(), line_number); | 1645 script_url.ToCString(), line_number); |
1505 } | 1646 } |
1506 return NULL; | 1647 return NULL; |
1507 } else if (last_token_idx < 0) { | 1648 } else if (last_token_idx < 0) { |
1508 // Line does not contain any tokens. first_token_index is the first | 1649 // Line does not contain any tokens. |
1509 // token after the given line. We check whether that token is | |
1510 // part of a function. | |
1511 last_token_idx = first_token_idx; | |
1512 } | |
1513 | |
1514 Function& func = Function::Handle(isolate_); | |
1515 while (first_token_idx <= last_token_idx) { | |
1516 func = lib.LookupFunctionInScript(script, first_token_idx); | |
1517 if (!func.IsNull()) { | |
1518 break; | |
1519 } | |
1520 first_token_idx++; | |
1521 } | |
1522 if (func.IsNull()) { | |
1523 if (FLAG_verbose_debug) { | 1650 if (FLAG_verbose_debug) { |
1524 OS::Print("No executable code at line %" Pd " in '%s'\n", | 1651 OS::Print("No executable code at line %" Pd " in '%s'\n", |
1525 line_number, script_url.ToCString()); | 1652 line_number, script_url.ToCString()); |
1526 } | 1653 } |
1527 return NULL; | 1654 return NULL; |
1528 } | 1655 } |
1529 if (last_token_idx < 0) { | 1656 |
1530 // The token at first_token_index is past the requested source line. | 1657 SourceBreakpoint* bpt = NULL; |
1531 // Set the breakpoint at the closest position after that line. | 1658 ASSERT(first_token_idx <= last_token_idx); |
1532 last_token_idx = func.end_token_pos(); | 1659 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) { |
| 1660 bpt = SetBreakpoint(script, first_token_idx); |
| 1661 first_token_idx++; |
1533 } | 1662 } |
1534 return SetBreakpoint(func, first_token_idx, last_token_idx); | 1663 if ((bpt == NULL) && FLAG_verbose_debug) { |
| 1664 OS::Print("No executable code at line %" Pd " in '%s'\n", |
| 1665 line_number, script_url.ToCString()); |
| 1666 } |
| 1667 return bpt; |
1535 } | 1668 } |
1536 | 1669 |
1537 | 1670 |
1538 intptr_t Debugger::CacheObject(const Object& obj) { | 1671 intptr_t Debugger::CacheObject(const Object& obj) { |
1539 ASSERT(obj_cache_ != NULL); | 1672 ASSERT(obj_cache_ != NULL); |
1540 return obj_cache_->AddObject(obj); | 1673 return obj_cache_->AddObject(obj); |
1541 } | 1674 } |
1542 | 1675 |
1543 | 1676 |
1544 bool Debugger::IsValidObjectId(intptr_t obj_id) { | 1677 bool Debugger::IsValidObjectId(intptr_t obj_id) { |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1916 // This port will be used as a unique ID to represet the isolate in the | 2049 // This port will be used as a unique ID to represet the isolate in the |
1917 // debugger wire protocol messages. | 2050 // debugger wire protocol messages. |
1918 isolate_id_ = isolate->main_port(); | 2051 isolate_id_ = isolate->main_port(); |
1919 initialized_ = true; | 2052 initialized_ = true; |
1920 | 2053 |
1921 // Signal isolate creation event. | 2054 // Signal isolate creation event. |
1922 SignalIsolateEvent(Debugger::kIsolateCreated); | 2055 SignalIsolateEvent(Debugger::kIsolateCreated); |
1923 } | 2056 } |
1924 | 2057 |
1925 | 2058 |
1926 static RawFunction* GetOriginalFunction(const Function& func) { | 2059 // Return innermost closure contained in 'function' that contains |
1927 if (func.IsClosureFunction()) { | 2060 // the given token position. |
1928 // Local functions (closures) in mixin functions do not have | 2061 RawFunction* Debugger::FindInnermostClosure(const Function& function, |
1929 // an original function they were cloned from. | 2062 intptr_t token_pos) { |
1930 // Note: this is a problem when a breakpoint is set in a mixed-in | 2063 const Class& owner = Class::Handle(isolate_, function.Owner()); |
1931 // closure. The breakpoint is linked to the closure attached to the | 2064 if (owner.closures() == GrowableObjectArray::null()) { |
1932 // mixin application class, not the mixin class. When the same | 2065 return Function::null(); |
1933 // closure is compiled for another mixin application class, we | |
1934 // don't find the breakpoint since we'll be looking in the | |
1935 // mixin class. | |
1936 return func.raw(); | |
1937 } | 2066 } |
1938 const Class& origin_class = Class::Handle(func.origin()); | 2067 // Note that we need to check that the closure is in the same |
1939 if (origin_class.is_patch()) { | 2068 // script as the outer function. We could have closures originating |
1940 // Patched functions from patch classes are removed from the | 2069 // in mixin classes whose source code is contained in a different |
1941 // function array of the patch class, so we will not find an | 2070 // script. |
1942 // original function object. | 2071 const Script& outer_origin = Script::Handle(isolate_, function.script()); |
1943 return func.raw(); | 2072 const GrowableObjectArray& closures = |
1944 } | 2073 GrowableObjectArray::Handle(isolate_, owner.closures()); |
1945 const Array& functions = Array::Handle(origin_class.functions()); | 2074 const intptr_t num_closures = closures.Length(); |
1946 Object& orig_func = Object::Handle(); | 2075 Function& closure = Function::Handle(isolate_); |
1947 for (intptr_t i = 0; i < functions.Length(); i++) { | 2076 Function& best_fit = Function::Handle(isolate_); |
1948 orig_func = functions.At(i); | 2077 for (intptr_t i = 0; i < num_closures; i++) { |
1949 // Function names are symbols, so we can compare the raw pointers. | 2078 closure ^= closures.At(i); |
1950 if (func.name() == Function::Cast(orig_func).name()) { | 2079 if ((function.token_pos() < closure.token_pos()) && |
1951 return Function::Cast(orig_func).raw(); | 2080 (closure.end_token_pos() < function.end_token_pos()) && |
| 2081 (closure.token_pos() <= token_pos) && |
| 2082 (token_pos <= closure.end_token_pos()) && |
| 2083 (closure.script() == outer_origin.raw())) { |
| 2084 SelectBestFit(&best_fit, &closure); |
1952 } | 2085 } |
1953 } | 2086 } |
1954 // Uncommon case: not a mixin function. | 2087 return best_fit.raw(); |
1955 ASSERT(!Class::Handle(func.Owner()).IsMixinApplication()); | |
1956 return func.raw(); | |
1957 } | 2088 } |
1958 | 2089 |
1959 | 2090 |
1960 void Debugger::NotifyCompilation(const Function& func) { | 2091 void Debugger::NotifyCompilation(const Function& func) { |
1961 if (src_breakpoints_ == NULL) { | 2092 if (src_breakpoints_ == NULL) { |
1962 // Return with minimal overhead if there are no breakpoints. | 2093 // Return with minimal overhead if there are no breakpoints. |
1963 return; | 2094 return; |
1964 } | 2095 } |
1965 Function& lookup_function = Function::Handle(func.raw()); | 2096 // Iterate over all source breakpoints to check whether breakpoints |
1966 if (func.IsImplicitClosureFunction()) { | 2097 // need to be set in the newly compiled function. |
1967 // If the newly compiled function is a an implicit closure (a closure that | 2098 Script& script = Script::Handle(isolate_); |
1968 // was formed by assigning a static or instance method to a function | 2099 for (SourceBreakpoint* bpt = src_breakpoints_; |
1969 // object), we need to use the closure's parent function to see whether | 2100 bpt != NULL; |
1970 // there are any breakpoints. The parent function is the actual method on | 2101 bpt = bpt->next()) { |
1971 // which the user sets breakpoints. | 2102 script = bpt->script(); |
1972 lookup_function = func.parent_function(); | 2103 if (FunctionContains(func, script, bpt->token_pos())) { |
1973 ASSERT(!lookup_function.IsNull()); | 2104 Function& inner_function = Function::Handle(isolate_); |
1974 } | 2105 inner_function = FindInnermostClosure(func, bpt->token_pos()); |
1975 if (lookup_function.Owner() != lookup_function.origin()) { | 2106 if (!inner_function.IsNull()) { |
1976 // This is a cloned function from a mixin class. If a breakpoint | 2107 // The local function of a function we just compiled cannot |
1977 // was set in this function, it is registered using the function | 2108 // be compiled already. |
1978 // of the origin class. | 2109 ASSERT(!inner_function.HasCode()); |
1979 lookup_function = GetOriginalFunction(lookup_function); | |
1980 } | |
1981 SourceBreakpoint* bpt = src_breakpoints_; | |
1982 while (bpt != NULL) { | |
1983 if (lookup_function.raw() == bpt->function()) { | |
1984 // Check if the breakpoint is inside a closure or local function | |
1985 // within the newly compiled function. Note that we must look | |
1986 // in the owner class of the function that just got compiled | |
1987 // (i.e. func), not the owner class of the function we use to | |
1988 // record the breakpoint (lookup_function). | |
1989 Class& owner = Class::Handle(func.Owner()); | |
1990 Function& closure = | |
1991 Function::Handle(owner.LookupClosureFunction(bpt->token_pos())); | |
1992 if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) { | |
1993 if (FLAG_verbose_debug) { | 2110 if (FLAG_verbose_debug) { |
1994 OS::Print("Resetting pending breakpoint to function %s\n", | 2111 OS::Print("Pending BP remains unresolved in inner function '%s'\n", |
1995 closure.ToFullyQualifiedCString()); | 2112 inner_function.ToFullyQualifiedCString()); |
1996 } | 2113 } |
1997 bpt->set_function(closure); | 2114 continue; |
1998 } else { | 2115 } |
| 2116 |
| 2117 // TODO(hausner): What should we do if function is optimized? |
| 2118 // Can we deoptimize the function? |
| 2119 ASSERT(!func.HasOptimizedCode()); |
| 2120 |
| 2121 // There is no local function within func that contains the |
| 2122 // breakpoint token position. Resolve the breakpoint if necessary |
| 2123 // and set the code breakpoints. |
| 2124 if (!bpt->IsResolved()) { |
| 2125 // Resolve source breakpoint in the newly compiled function. |
| 2126 intptr_t bp_pos = ResolveBreakpointPos(func, bpt->token_pos()); |
| 2127 if (bp_pos < 0) { |
| 2128 if (FLAG_verbose_debug) { |
| 2129 OS::Print("Failed resolving breakpoint for function '%s'\n", |
| 2130 String::Handle(func.name()).ToCString()); |
| 2131 } |
| 2132 continue; |
| 2133 } |
| 2134 intptr_t requested_pos = bpt->token_pos(); |
| 2135 bpt->SetResolved(func, bp_pos); |
1999 if (FLAG_verbose_debug) { | 2136 if (FLAG_verbose_debug) { |
2000 OS::Print("Enable pending breakpoint for function '%s'\n", | 2137 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " |
2001 String::Handle(lookup_function.name()).ToCString()); | 2138 "function '%s' (requested pos %" Pd ")\n", |
| 2139 bpt->id(), |
| 2140 bpt->token_pos(), |
| 2141 bpt->LineNumber(), |
| 2142 func.ToFullyQualifiedCString(), |
| 2143 requested_pos); |
2002 } | 2144 } |
2003 const Script& script= Script::Handle(func.script()); | |
2004 intptr_t first_pos, last_pos; | |
2005 script.TokenRangeAtLine(bpt->LineNumber(), &first_pos, &last_pos); | |
2006 intptr_t bp_pos = | |
2007 ResolveBreakpointPos(func, bpt->token_pos(), last_pos); | |
2008 bpt->set_token_pos(bp_pos); | |
2009 MakeCodeBreakpointsAt(func, bp_pos, bpt); | |
2010 SignalBpResolved(bpt); | 2145 SignalBpResolved(bpt); |
2011 } | 2146 } |
2012 bpt->Enable(); // Enables the code breakpoint as well. | 2147 ASSERT(bpt->IsResolved()); |
| 2148 if (FLAG_verbose_debug) { |
| 2149 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", |
| 2150 bpt->id(), |
| 2151 bpt->LineNumber(), |
| 2152 func.IsClosureFunction() ? "closure" : "function", |
| 2153 String::Handle(func.name()).ToCString()); |
| 2154 } |
| 2155 MakeCodeBreakpointsAt(func, bpt); |
2013 } | 2156 } |
2014 bpt = bpt->next(); | |
2015 } | 2157 } |
2016 } | 2158 } |
2017 | 2159 |
2018 | 2160 |
2019 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 2161 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
2020 CodeBreakpoint* bpt = code_breakpoints_; | 2162 CodeBreakpoint* bpt = code_breakpoints_; |
2021 while (bpt != NULL) { | 2163 while (bpt != NULL) { |
2022 if (bpt->pc() == breakpoint_address) { | 2164 if (bpt->pc() == breakpoint_address) { |
2023 return bpt; | 2165 return bpt; |
2024 } | 2166 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2098 temp_bpt->Disable(); | 2240 temp_bpt->Disable(); |
2099 delete temp_bpt; | 2241 delete temp_bpt; |
2100 } else { | 2242 } else { |
2101 prev_bpt = curr_bpt; | 2243 prev_bpt = curr_bpt; |
2102 curr_bpt = curr_bpt->next(); | 2244 curr_bpt = curr_bpt->next(); |
2103 } | 2245 } |
2104 } | 2246 } |
2105 } | 2247 } |
2106 | 2248 |
2107 | 2249 |
2108 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func, | 2250 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Script& script, |
2109 intptr_t token_pos) { | 2251 intptr_t token_pos) { |
2110 SourceBreakpoint* bpt = src_breakpoints_; | 2252 SourceBreakpoint* bpt = src_breakpoints_; |
2111 while (bpt != NULL) { | 2253 while (bpt != NULL) { |
2112 if ((bpt->function() == func.raw()) && | 2254 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { |
2113 (bpt->token_pos() == token_pos)) { | |
2114 return bpt; | 2255 return bpt; |
2115 } | 2256 } |
2116 bpt = bpt->next(); | 2257 bpt = bpt->next(); |
2117 } | 2258 } |
2118 return NULL; | 2259 return NULL; |
2119 } | 2260 } |
2120 | 2261 |
2121 | 2262 |
2122 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { | 2263 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { |
2123 SourceBreakpoint* bpt = src_breakpoints_; | 2264 SourceBreakpoint* bpt = src_breakpoints_; |
(...skipping 14 matching lines...) Expand all Loading... |
2138 } | 2279 } |
2139 | 2280 |
2140 | 2281 |
2141 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2282 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
2142 ASSERT(bpt->next() == NULL); | 2283 ASSERT(bpt->next() == NULL); |
2143 bpt->set_next(code_breakpoints_); | 2284 bpt->set_next(code_breakpoints_); |
2144 code_breakpoints_ = bpt; | 2285 code_breakpoints_ = bpt; |
2145 } | 2286 } |
2146 | 2287 |
2147 } // namespace dart | 2288 } // namespace dart |
OLD | NEW |