Chromium Code Reviews| 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 range_start, |
| 55 intptr_t range_end) | |
| 55 : id_(id), | 56 : id_(id), |
| 56 function_(func.raw()), | 57 script_(script.raw()), |
| 57 token_pos_(token_pos), | 58 range_start_(range_start), |
| 58 line_number_(-1), | 59 range_end_(range_end), |
| 59 is_enabled_(false), | 60 is_enabled_(false), |
| 60 next_(NULL) { | 61 next_(NULL), |
| 61 ASSERT(!func.IsNull()); | 62 token_pos_(-1), |
| 62 ASSERT((func.token_pos() <= token_pos_) && | 63 line_number_(-1) { |
| 63 (token_pos_ <= func.end_token_pos())); | 64 ASSERT(id_ > 0); |
| 65 ASSERT(!script.IsNull()); | |
| 66 ASSERT((range_start_ >= 0) && (range_start_ <= range_end_)); | |
|
turnidge
2013/12/19 22:31:59
Should this <= be a <? It depends whether the ran
hausner
2013/12/21 00:08:32
obsolete
| |
| 64 } | 67 } |
| 65 | 68 |
| 66 | 69 |
| 67 void SourceBreakpoint::Enable() { | 70 void SourceBreakpoint::Enable() { |
| 68 is_enabled_ = true; | 71 is_enabled_ = true; |
| 69 Isolate::Current()->debugger()->SyncBreakpoint(this); | 72 Isolate::Current()->debugger()->SyncBreakpoint(this); |
| 70 } | 73 } |
| 71 | 74 |
| 72 | 75 |
| 73 void SourceBreakpoint::Disable() { | 76 void SourceBreakpoint::Disable() { |
| 74 is_enabled_ = false; | 77 is_enabled_ = false; |
| 75 Isolate::Current()->debugger()->SyncBreakpoint(this); | 78 Isolate::Current()->debugger()->SyncBreakpoint(this); |
| 76 } | 79 } |
| 77 | 80 |
| 78 | 81 |
| 79 RawScript* SourceBreakpoint::SourceCode() { | 82 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) { |
|
turnidge
2013/12/19 22:31:59
What do you think of renaming "SetResolved" to "Re
hausner
2013/12/21 00:08:32
I like SetResolved better. The actual resolving (c
| |
| 80 const Function& func = Function::Handle(function_); | 83 ASSERT(func.script() == script_); |
| 81 return func.script(); | 84 function_ = func.raw(); |
| 85 token_pos_ = token_pos; | |
| 82 } | 86 } |
| 83 | 87 |
| 84 | 88 |
| 89 // TODO(hausner): Get rid of library parameter. A source breakpoint location | |
| 90 // does not imply a library, since the same source code can be included | |
| 91 // in more than one library, e.g. the text location of mixin functions. | |
| 85 void SourceBreakpoint::GetCodeLocation( | 92 void SourceBreakpoint::GetCodeLocation( |
| 86 Library* lib, | 93 Library* lib, |
| 87 Script* script, | 94 Script* script, |
| 88 intptr_t* pos) const { | 95 intptr_t* pos) { |
| 89 const Function& func = Function::Handle(function_); | 96 *script = this->script(); |
| 90 const Class& cls = Class::Handle(func.origin()); | 97 if (IsResolved()) { |
| 91 *lib = cls.library(); | 98 const Function& func = Function::Handle(function_); |
| 92 *script = func.script(); | 99 ASSERT(!func.IsNull()); |
| 93 *pos = token_pos(); | 100 const Class& cls = Class::Handle(func.origin()); |
| 101 *lib = cls.library(); | |
| 102 *pos = token_pos_; | |
| 103 } else { | |
| 104 *lib = Library::null(); | |
| 105 *pos = range_start_; | |
| 106 } | |
| 94 } | 107 } |
| 95 | 108 |
| 96 | 109 |
| 97 RawString* SourceBreakpoint::SourceUrl() { | 110 RawString* SourceBreakpoint::SourceUrl() { |
| 98 const Script& script = Script::Handle(SourceCode()); | 111 return Script::Handle(script()).url(); |
| 99 return script.url(); | |
| 100 } | 112 } |
| 101 | 113 |
| 102 | 114 |
| 103 intptr_t SourceBreakpoint::LineNumber() { | 115 intptr_t SourceBreakpoint::LineNumber() { |
| 104 // Compute line number lazily since it causes scanning of the script. | 116 // Compute line number lazily since it causes scanning of the script. |
| 117 ASSERT(IsResolved()); | |
| 105 if (line_number_ < 0) { | 118 if (line_number_ < 0) { |
| 106 const Script& script = Script::Handle(SourceCode()); | 119 const Script& script = Script::Handle(this->script()); |
| 107 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 120 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
| 108 } | 121 } |
| 109 return line_number_; | 122 return line_number_; |
| 110 } | 123 } |
| 111 | 124 |
| 112 | 125 |
| 113 void SourceBreakpoint::set_function(const Function& func) { | |
| 114 function_ = func.raw(); | |
| 115 } | |
| 116 | |
| 117 | |
| 118 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 126 void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 127 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | |
| 119 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 128 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 120 } | 129 } |
| 121 | 130 |
| 122 | 131 |
| 123 void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) const { | 132 void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) { |
| 124 Isolate* isolate = Isolate::Current(); | 133 Isolate* isolate = Isolate::Current(); |
| 125 | 134 |
| 126 JSONObject jsobj(stream); | 135 JSONObject jsobj(stream); |
| 127 jsobj.AddProperty("type", "Breakpoint"); | 136 jsobj.AddProperty("type", "Breakpoint"); |
| 128 | 137 |
| 129 jsobj.AddProperty("id", id()); | 138 jsobj.AddProperty("id", id()); |
| 130 jsobj.AddProperty("enabled", IsEnabled()); | 139 jsobj.AddProperty("enabled", IsEnabled()); |
| 131 | 140 jsobj.AddProperty("resolved", IsResolved()); |
| 132 const Function& func = Function::Handle(function()); | |
| 133 jsobj.AddProperty("resolved", func.HasCode()); | |
| 134 | 141 |
| 135 Library& library = Library::Handle(isolate); | 142 Library& library = Library::Handle(isolate); |
| 136 Script& script = Script::Handle(isolate); | 143 Script& script = Script::Handle(isolate); |
| 137 intptr_t token_pos; | 144 intptr_t token_pos; |
| 138 GetCodeLocation(&library, &script, &token_pos); | 145 GetCodeLocation(&library, &script, &token_pos); |
| 139 { | 146 { |
| 140 JSONObject location(&jsobj, "location"); | 147 JSONObject location(&jsobj, "location"); |
| 141 location.AddProperty("type", "Location"); | 148 location.AddProperty("type", "Location"); |
| 142 location.AddProperty("libId", library.index()); | |
| 143 | 149 |
| 144 const String& url = String::Handle(script.url()); | 150 const String& url = String::Handle(script.url()); |
| 145 location.AddProperty("script", url.ToCString()); | 151 location.AddProperty("script", url.ToCString()); |
| 146 location.AddProperty("tokenPos", token_pos); | 152 location.AddProperty("tokenPos", token_pos); |
| 147 } | 153 } |
| 148 } | 154 } |
| 149 | 155 |
| 150 | 156 |
| 151 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 157 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 152 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 158 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 return chars; | 229 return chars; |
| 224 } | 230 } |
| 225 | 231 |
| 226 | 232 |
| 227 bool Debugger::HasBreakpoint(const Function& func) { | 233 bool Debugger::HasBreakpoint(const Function& func) { |
| 228 if (!func.HasCode()) { | 234 if (!func.HasCode()) { |
| 229 // If the function is not compiled yet, just check whether there | 235 // If the function is not compiled yet, just check whether there |
| 230 // is a user-defined latent breakpoint. | 236 // is a user-defined latent breakpoint. |
| 231 SourceBreakpoint* sbpt = src_breakpoints_; | 237 SourceBreakpoint* sbpt = src_breakpoints_; |
| 232 while (sbpt != NULL) { | 238 while (sbpt != NULL) { |
| 233 if (func.raw() == sbpt->function()) { | 239 if (sbpt->IsResolved() && (func.raw() == sbpt->function())) { |
|
turnidge
2013/12/19 22:31:59
So this function has no code, has not been compile
hausner
2013/12/21 00:08:32
Yes that seems fishy. Changed so it returns true i
| |
| 234 return true; | 240 return true; |
| 235 } | 241 } |
| 236 sbpt = sbpt->next_; | 242 sbpt = sbpt->next_; |
| 237 } | 243 } |
| 238 return false; | 244 return false; |
| 239 } | 245 } |
| 240 CodeBreakpoint* cbpt = code_breakpoints_; | 246 CodeBreakpoint* cbpt = code_breakpoints_; |
| 241 while (cbpt != NULL) { | 247 while (cbpt != NULL) { |
| 242 if (func.raw() == cbpt->function()) { | 248 if (func.raw() == cbpt->function()) { |
| 243 return true; | 249 return true; |
| (...skipping 1086 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1330 (desc_token_pos <= last_token_pos) && | 1336 (desc_token_pos <= last_token_pos) && |
| 1331 (desc.PC(i) < lowest_pc)) { | 1337 (desc.PC(i) < lowest_pc)) { |
| 1332 // This descriptor is within the token position range and so | 1338 // This descriptor is within the token position range and so |
| 1333 // far has the lowest code address. | 1339 // far has the lowest code address. |
| 1334 lowest_pc = desc.PC(i); | 1340 lowest_pc = desc.PC(i); |
| 1335 lowest_pc_index = i; | 1341 lowest_pc_index = i; |
| 1336 } | 1342 } |
| 1337 } | 1343 } |
| 1338 } | 1344 } |
| 1339 if (lowest_pc_index >= 0) { | 1345 if (lowest_pc_index >= 0) { |
| 1340 // We found the the pc descriptor within the given token range that | 1346 // We found the pc descriptor within the given token range that |
| 1341 // has the lowest execution address. This is the first possible | 1347 // has the lowest execution address. This is the first possible |
| 1342 // breakpoint on the line. We use this instead of the nearest | 1348 // breakpoint on the line. We use this instead of the nearest |
| 1343 // PC descriptor measured in token index distance. | 1349 // PC descriptor measured in token index distance. |
| 1344 best_fit_index = lowest_pc_index; | 1350 best_fit_index = lowest_pc_index; |
| 1345 } | 1351 } |
| 1346 if (best_fit_index >= 0) { | 1352 if (best_fit_index >= 0) { |
| 1347 return desc.TokenPos(best_fit_index); | 1353 return desc.TokenPos(best_fit_index); |
| 1348 } | 1354 } |
| 1349 return -1; | 1355 return -1; |
| 1350 } | 1356 } |
| 1351 | 1357 |
| 1352 | 1358 |
| 1359 void Debugger::FindAllFunctions(const Script& script, | |
|
turnidge
2013/12/19 22:31:59
I find the name confusing -- it seems to be trying
hausner
2013/12/21 00:08:32
Name changed.
| |
| 1360 intptr_t start_pos, | |
| 1361 intptr_t end_pos, | |
| 1362 GrowableObjectArray* function_list) { | |
|
turnidge
2013/12/19 22:31:59
This function belongs lower in the file, nearer to
hausner
2013/12/21 00:08:32
Done.
| |
| 1363 Class& cls = Class::Handle(isolate_); | |
| 1364 Array& functions = Array::Handle(isolate_); | |
| 1365 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_); | |
| 1366 Function& function = Function::Handle(isolate_); | |
| 1367 | |
| 1368 const ClassTable& class_table = *isolate_->class_table(); | |
| 1369 const intptr_t num_classes = class_table.NumCids(); | |
| 1370 for (intptr_t i = 1; i < num_classes; i++) { | |
| 1371 if (class_table.HasValidClassAt(i)) { | |
| 1372 cls = class_table.At(i); | |
| 1373 // Note: we need to check the functions of this class even if | |
| 1374 // the class is defined in a differenct 'script'. There could | |
| 1375 // be mixin functions from the given script in this class. | |
| 1376 functions = cls.functions(); | |
| 1377 if (!functions.IsNull()) { | |
| 1378 const intptr_t num_functions = functions.Length(); | |
| 1379 for (intptr_t pos = 0; pos < num_functions; pos++) { | |
| 1380 function ^= functions.At(pos); | |
| 1381 ASSERT(!function.IsNull()); | |
| 1382 // Check token position first to avoid unnecessary calls | |
| 1383 // to script() which allocates handles. | |
| 1384 if ((function.token_pos() == start_pos) | |
| 1385 && (function.end_token_pos() == end_pos) | |
| 1386 && (function.script() == script.raw())) { | |
| 1387 function_list->Add(function); | |
| 1388 if (function.HasImplicitClosureFunction()) { | |
| 1389 function = function.ImplicitClosureFunction(); | |
| 1390 function_list->Add(function); | |
| 1391 } | |
| 1392 } | |
| 1393 } | |
| 1394 } | |
| 1395 | |
| 1396 closures = cls.closures(); | |
| 1397 if (!closures.IsNull()) { | |
| 1398 const intptr_t num_closures = closures.Length(); | |
| 1399 for (intptr_t pos = 0; pos < num_closures; pos++) { | |
| 1400 function ^= closures.At(pos); | |
| 1401 ASSERT(!function.IsNull()); | |
| 1402 if ((function.token_pos() == start_pos) | |
| 1403 && (function.end_token_pos() == end_pos) | |
| 1404 && (function.script() == script.raw())) { | |
| 1405 function_list->Add(function); | |
| 1406 if (function.HasImplicitClosureFunction()) { | |
| 1407 function = function.ImplicitClosureFunction(); | |
| 1408 function_list->Add(function); | |
| 1409 } | |
| 1410 } | |
| 1411 } | |
| 1412 } | |
| 1413 } | |
| 1414 } | |
| 1415 } | |
| 1416 | |
| 1417 | |
| 1353 void Debugger::MakeCodeBreakpointsAt(const Function& func, | 1418 void Debugger::MakeCodeBreakpointsAt(const Function& func, |
| 1354 intptr_t token_pos, | |
| 1355 SourceBreakpoint* bpt) { | 1419 SourceBreakpoint* bpt) { |
| 1420 ASSERT((bpt != NULL) && bpt->IsResolved()); | |
| 1356 ASSERT(!func.HasOptimizedCode()); | 1421 ASSERT(!func.HasOptimizedCode()); |
| 1357 Code& code = Code::Handle(func.unoptimized_code()); | 1422 Code& code = Code::Handle(func.unoptimized_code()); |
| 1358 ASSERT(!code.IsNull()); | 1423 ASSERT(!code.IsNull()); |
| 1359 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1424 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 1360 for (intptr_t i = 0; i < desc.Length(); i++) { | 1425 for (intptr_t i = 0; i < desc.Length(); i++) { |
| 1361 intptr_t desc_token_pos = desc.TokenPos(i); | 1426 intptr_t desc_token_pos = desc.TokenPos(i); |
| 1362 if ((desc_token_pos == token_pos) && IsSafePoint(desc.DescriptorKind(i))) { | 1427 if ((desc_token_pos == bpt->token_pos_) && |
| 1428 IsSafePoint(desc.DescriptorKind(i))) { | |
| 1363 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i)); | 1429 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i)); |
| 1364 if (code_bpt == NULL) { | 1430 if (code_bpt == NULL) { |
| 1365 // No code breakpoint for this code exists; create one. | 1431 // No code breakpoint for this code exists; create one. |
| 1366 code_bpt = new CodeBreakpoint(func, i); | 1432 code_bpt = new CodeBreakpoint(func, i); |
| 1367 RegisterCodeBreakpoint(code_bpt); | 1433 RegisterCodeBreakpoint(code_bpt); |
| 1368 } | 1434 } |
| 1369 code_bpt->set_src_bpt(bpt); | 1435 code_bpt->set_src_bpt(bpt); |
| 1436 if (bpt->IsEnabled()) { | |
| 1437 code_bpt->Enable(); | |
| 1438 } | |
| 1370 } | 1439 } |
| 1371 } | 1440 } |
| 1372 } | 1441 } |
| 1373 | 1442 |
| 1374 | 1443 |
| 1375 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, | 1444 static void SelectBestFit(Function* best_fit, Function* func) { |
| 1376 intptr_t first_token_pos, | 1445 if (best_fit->IsNull()) { |
| 1377 intptr_t last_token_pos) { | 1446 *best_fit = func->raw(); |
| 1378 if ((last_token_pos < target_function.token_pos()) || | |
| 1379 (target_function.end_token_pos() < first_token_pos)) { | |
| 1380 // The given token position is not within the target function. | |
| 1381 return NULL; | |
| 1382 } | 1447 } |
| 1383 intptr_t breakpoint_pos = -1; | 1448 if (func->token_pos() > best_fit->token_pos()) { |
| 1384 Function& closure = Function::Handle(isolate_); | 1449 if (func->end_token_pos() <= best_fit->end_token_pos()) { |
| 1385 if (target_function.HasImplicitClosureFunction()) { | 1450 // func is contained within best_fit. Select it even if it |
| 1386 // There is a closurized version of this function. | 1451 // has not been compiled yet. |
| 1387 closure = target_function.ImplicitClosureFunction(); | 1452 *best_fit = func->raw(); |
| 1453 if (func->HasImplicitClosureFunction()) { | |
| 1454 *func = func->ImplicitClosureFunction(); | |
| 1455 if (func->HasCode()) { | |
| 1456 *best_fit = func->raw(); | |
| 1457 } | |
| 1458 } | |
| 1459 } | |
| 1460 } else if ((func->token_pos() == best_fit->token_pos()) | |
| 1461 && (func->end_token_pos() == best_fit->end_token_pos()) | |
| 1462 && func->HasCode()) { | |
| 1463 // If func covers the same range, it is considered a better fit if | |
| 1464 // it has been compiled. | |
| 1465 *best_fit = func->raw(); | |
| 1388 } | 1466 } |
| 1389 // Determine actual breakpoint location if the function or an | |
| 1390 // implicit closure of the function has been compiled already. | |
| 1391 if (target_function.HasCode()) { | |
| 1392 DeoptimizeWorld(); | |
| 1393 ASSERT(!target_function.HasOptimizedCode()); | |
| 1394 breakpoint_pos = | |
| 1395 ResolveBreakpointPos(target_function, first_token_pos, last_token_pos); | |
| 1396 } else if (!closure.IsNull() && closure.HasCode()) { | |
| 1397 DeoptimizeWorld(); | |
| 1398 ASSERT(!closure.HasOptimizedCode()); | |
| 1399 breakpoint_pos = | |
| 1400 ResolveBreakpointPos(closure, first_token_pos, last_token_pos); | |
| 1401 } else { | |
| 1402 // This function has not been compiled yet. Set a pending | |
| 1403 // breakpoint to be resolved later. | |
| 1404 SourceBreakpoint* source_bpt = | |
| 1405 GetSourceBreakpoint(target_function, first_token_pos); | |
| 1406 if (source_bpt != NULL) { | |
| 1407 // A pending source breakpoint for this uncompiled location | |
| 1408 // already exists. | |
| 1409 if (FLAG_verbose_debug) { | |
| 1410 OS::Print("Pending breakpoint for uncompiled function" | |
| 1411 " '%s' at line %" Pd " already exists\n", | |
| 1412 target_function.ToFullyQualifiedCString(), | |
| 1413 source_bpt->LineNumber()); | |
| 1414 } | |
| 1415 return source_bpt; | |
| 1416 } | |
| 1417 source_bpt = | |
| 1418 new SourceBreakpoint(nextId(), target_function, first_token_pos); | |
| 1419 RegisterSourceBreakpoint(source_bpt); | |
| 1420 if (FLAG_verbose_debug) { | |
| 1421 OS::Print("Registering pending breakpoint for " | |
| 1422 "uncompiled function '%s' at line %" Pd "\n", | |
| 1423 target_function.ToFullyQualifiedCString(), | |
| 1424 source_bpt->LineNumber()); | |
| 1425 } | |
| 1426 source_bpt->Enable(); | |
| 1427 return source_bpt; | |
| 1428 } | |
| 1429 ASSERT(breakpoint_pos != -1); | |
| 1430 SourceBreakpoint* source_bpt = | |
| 1431 GetSourceBreakpoint(target_function, breakpoint_pos); | |
| 1432 if (source_bpt != NULL) { | |
| 1433 // A source breakpoint for this location already exists. | |
| 1434 return source_bpt; | |
| 1435 } | |
| 1436 source_bpt = new SourceBreakpoint(nextId(), target_function, breakpoint_pos); | |
| 1437 RegisterSourceBreakpoint(source_bpt); | |
| 1438 if (target_function.HasCode()) { | |
| 1439 MakeCodeBreakpointsAt(target_function, breakpoint_pos, source_bpt); | |
| 1440 } | |
| 1441 if (!closure.IsNull() && closure.HasCode()) { | |
| 1442 MakeCodeBreakpointsAt(closure, breakpoint_pos, source_bpt); | |
| 1443 } | |
| 1444 source_bpt->Enable(); | |
| 1445 SignalBpResolved(source_bpt); | |
| 1446 return source_bpt; | |
| 1447 } | 1467 } |
| 1448 | 1468 |
| 1449 | 1469 |
| 1470 // Returns true if function is at least partially overlapping | |
| 1471 // the given token range in a script. | |
| 1472 static bool RangeOverlaps(const Function& func, | |
| 1473 const Script& script, | |
| 1474 intptr_t range_start, | |
| 1475 intptr_t range_end) { | |
| 1476 if ((func.end_token_pos() > range_start) && (func.token_pos() < range_end)) { | |
| 1477 // Check script equality second because it allocates | |
| 1478 // handles as a side effect. | |
| 1479 return func.script() == script.raw(); | |
| 1480 } | |
| 1481 return false; | |
|
turnidge
2013/12/19 22:31:59
This cl contains a lot of range math that could ha
hausner
2013/12/21 00:08:32
Range math simplified and test added (not unit tes
| |
| 1482 } | |
| 1483 | |
| 1484 | |
|
turnidge
2013/12/19 22:31:59
Could use a comment saying what it means for one f
hausner
2013/12/21 00:08:32
I think the comments you suggest are inside the fu
| |
| 1485 RawFunction* Debugger::FindBestFit(const Script& script, | |
| 1486 intptr_t range_start, | |
| 1487 intptr_t range_end) { | |
|
turnidge
2013/12/19 22:31:59
Out of curiousity, could this function be static?
hausner
2013/12/21 00:08:32
Yes, but then I could not use the debugger object'
| |
| 1488 Class& cls = Class::Handle(isolate_); | |
| 1489 Array& functions = Array::Handle(isolate_); | |
| 1490 GrowableObjectArray& closures = GrowableObjectArray::Handle(isolate_); | |
| 1491 Function& function = Function::Handle(isolate_); | |
| 1492 Function& best_fit = Function::Handle(isolate_); | |
| 1493 | |
| 1494 const ClassTable& class_table = *isolate_->class_table(); | |
| 1495 const intptr_t num_classes = class_table.NumCids(); | |
| 1496 for (intptr_t i = 1; i < num_classes; i++) { | |
| 1497 if (class_table.HasValidClassAt(i)) { | |
| 1498 cls = class_table.At(i); | |
| 1499 // Note: we need to check the functions of this class even if | |
| 1500 // the class is defined in a differenct 'script'. There could | |
| 1501 // be mixin functions from the given script in this class. | |
| 1502 functions = cls.functions(); | |
| 1503 if (!functions.IsNull()) { | |
| 1504 const intptr_t num_functions = functions.Length(); | |
| 1505 for (intptr_t pos = 0; pos < num_functions; pos++) { | |
| 1506 function ^= functions.At(pos); | |
| 1507 ASSERT(!function.IsNull()); | |
| 1508 if (RangeOverlaps(function, script, range_start, range_end)) { | |
| 1509 SelectBestFit(&best_fit, &function); | |
| 1510 } | |
| 1511 } | |
| 1512 } | |
| 1513 | |
| 1514 closures = cls.closures(); | |
| 1515 if (!closures.IsNull()) { | |
| 1516 const intptr_t num_closures = closures.Length(); | |
| 1517 for (intptr_t pos = 0; pos < num_closures; pos++) { | |
| 1518 function ^= closures.At(pos); | |
| 1519 ASSERT(!function.IsNull()); | |
| 1520 if (RangeOverlaps(function, script, range_start, range_end)) { | |
| 1521 SelectBestFit(&best_fit, &function); | |
|
turnidge
2013/12/19 22:31:59
If we were to change SelectBestFit to return the R
hausner
2013/12/21 00:08:32
I wanted to reuse the handles so that SelectBestFi
| |
| 1522 } | |
| 1523 } | |
| 1524 } | |
| 1525 } | |
| 1526 } | |
| 1527 return best_fit.raw(); | |
| 1528 } | |
| 1529 | |
| 1530 | |
| 1531 SourceBreakpoint* Debugger::SetBreakpoint(const Script& script, | |
| 1532 intptr_t range_start, | |
| 1533 intptr_t range_end) { | |
| 1534 Function& func = Function::Handle(isolate_); | |
| 1535 func = FindBestFit(script, range_start, range_end); | |
| 1536 if (func.IsNull()) { | |
| 1537 return NULL; | |
| 1538 } | |
| 1539 if (!func.IsNull() && func.HasCode()) { | |
| 1540 // A function containing this breakpoint location has already | |
| 1541 // been compiled. We can resolve the breakpoint now. | |
| 1542 DeoptimizeWorld(); | |
| 1543 intptr_t breakpoint_pos = | |
| 1544 ResolveBreakpointPos(func, range_start, range_end); | |
| 1545 if (breakpoint_pos >= 0) { | |
| 1546 SourceBreakpoint* bpt = GetResolvedBreakpoint(script, breakpoint_pos); | |
| 1547 if (bpt != NULL) { | |
| 1548 // A source breakpoint for this location already exists. | |
| 1549 return bpt; | |
| 1550 } | |
| 1551 bpt = new SourceBreakpoint(nextId(), script, range_start, range_end); | |
| 1552 bpt->SetResolved(func, breakpoint_pos); | |
| 1553 RegisterSourceBreakpoint(bpt); | |
| 1554 // There may be more than one function object for a given function | |
| 1555 // in source code. There may be implicit closure functions, and | |
| 1556 // there may be copies of mixin functions. Collect all functions whose | |
| 1557 // source code range matches exactly the best fit function we | |
| 1558 // found. | |
| 1559 GrowableObjectArray& functions = | |
| 1560 GrowableObjectArray::Handle(GrowableObjectArray::New()); | |
| 1561 FindAllFunctions(script, | |
| 1562 func.token_pos(), | |
| 1563 func.end_token_pos(), | |
| 1564 &functions); | |
| 1565 const intptr_t num_functions = functions.Length(); | |
| 1566 // We must have found at least one function: func. | |
| 1567 ASSERT(num_functions > 0); | |
| 1568 // Create code breakpoints for all compiled functions we found. | |
| 1569 for (intptr_t i = 0; i < num_functions; i++) { | |
| 1570 func ^= functions.At(i); | |
| 1571 if (func.HasCode()) { | |
| 1572 MakeCodeBreakpointsAt(func, bpt); | |
| 1573 } | |
| 1574 } | |
| 1575 bpt->Enable(); | |
|
turnidge
2013/12/19 22:31:59
If we move the call to Enable before we make the c
hausner
2013/12/21 00:08:32
Yes but the call to Enable() has the side effect o
| |
| 1576 SignalBpResolved(bpt); | |
| 1577 return bpt; | |
| 1578 } | |
| 1579 } | |
| 1580 // There is no compiled function at this range. Register an unresolved | |
| 1581 // breakpoint. | |
| 1582 if (FLAG_verbose_debug && !func.IsNull()) { | |
| 1583 intptr_t line_number; | |
| 1584 script.GetTokenLocation(range_start, &line_number, NULL); | |
| 1585 OS::Print("Registering pending breakpoint for " | |
| 1586 "uncompiled function '%s' at line %" Pd "\n", | |
| 1587 func.ToFullyQualifiedCString(), | |
| 1588 line_number); | |
| 1589 } | |
| 1590 SourceBreakpoint* bpt = GetUnresolvedBreakpoint(script, range_start); | |
| 1591 if (bpt == NULL) { | |
| 1592 bpt = new SourceBreakpoint(nextId(), script, range_start, range_end); | |
| 1593 } | |
| 1594 RegisterSourceBreakpoint(bpt); | |
| 1595 bpt->Enable(); | |
| 1596 return bpt; | |
| 1597 } | |
| 1598 | |
| 1599 | |
| 1450 // Synchronize the enabled/disabled state of all code breakpoints | 1600 // Synchronize the enabled/disabled state of all code breakpoints |
| 1451 // associated with the source breakpoint bpt. | 1601 // associated with the source breakpoint bpt. |
| 1452 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { | 1602 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
| 1453 CodeBreakpoint* cbpt = code_breakpoints_; | 1603 CodeBreakpoint* cbpt = code_breakpoints_; |
| 1454 while (cbpt != NULL) { | 1604 while (cbpt != NULL) { |
| 1455 if (bpt == cbpt->src_bpt()) { | 1605 if (bpt == cbpt->src_bpt()) { |
| 1456 if (bpt->IsEnabled()) { | 1606 if (bpt->IsEnabled()) { |
| 1457 cbpt->Enable(); | 1607 cbpt->Enable(); |
| 1458 } else { | 1608 } else { |
| 1459 cbpt->Disable(); | 1609 cbpt->Disable(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1470 const Function& closure_func = | 1620 const Function& closure_func = |
| 1471 Function::Handle(target_function.ImplicitClosureFunction()); | 1621 Function::Handle(target_function.ImplicitClosureFunction()); |
| 1472 InstrumentForStepping(closure_func); | 1622 InstrumentForStepping(closure_func); |
| 1473 } | 1623 } |
| 1474 } | 1624 } |
| 1475 | 1625 |
| 1476 | 1626 |
| 1477 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 1627 SourceBreakpoint* Debugger::SetBreakpointAtEntry( |
| 1478 const Function& target_function) { | 1628 const Function& target_function) { |
| 1479 ASSERT(!target_function.IsNull()); | 1629 ASSERT(!target_function.IsNull()); |
| 1480 return SetBreakpoint(target_function, | 1630 const Script& script = Script::Handle(target_function.script()); |
| 1631 return SetBreakpoint(script, | |
| 1481 target_function.token_pos(), | 1632 target_function.token_pos(), |
| 1482 target_function.end_token_pos()); | 1633 target_function.token_pos() + 1); |
|
turnidge
2013/12/19 22:31:59
If the range end is included in the range, do you
hausner
2013/12/21 00:08:32
obsolete.
| |
| 1483 } | 1634 } |
| 1484 | 1635 |
| 1485 | 1636 |
| 1486 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 1637 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 1487 intptr_t line_number) { | 1638 intptr_t line_number) { |
| 1488 Library& lib = Library::Handle(isolate_); | 1639 Library& lib = Library::Handle(isolate_); |
| 1489 Script& script = Script::Handle(isolate_); | 1640 Script& script = Script::Handle(isolate_); |
| 1490 const GrowableObjectArray& libs = | 1641 const GrowableObjectArray& libs = |
| 1491 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 1642 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 1492 for (intptr_t i = 0; i < libs.Length(); i++) { | 1643 for (intptr_t i = 0; i < libs.Length(); i++) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1512 script_url.ToCString(), line_number); | 1663 script_url.ToCString(), line_number); |
| 1513 } | 1664 } |
| 1514 return NULL; | 1665 return NULL; |
| 1515 } else if (last_token_idx < 0) { | 1666 } else if (last_token_idx < 0) { |
| 1516 // Line does not contain any tokens. first_token_index is the first | 1667 // Line does not contain any tokens. first_token_index is the first |
| 1517 // token after the given line. We check whether that token is | 1668 // token after the given line. We check whether that token is |
| 1518 // part of a function. | 1669 // part of a function. |
| 1519 last_token_idx = first_token_idx; | 1670 last_token_idx = first_token_idx; |
| 1520 } | 1671 } |
| 1521 | 1672 |
| 1522 Function& func = Function::Handle(isolate_); | 1673 SourceBreakpoint* bpt = |
| 1523 while (first_token_idx <= last_token_idx) { | 1674 SetBreakpoint(script, first_token_idx, last_token_idx); |
| 1524 func = lib.LookupFunctionInScript(script, first_token_idx); | 1675 if ((bpt == NULL) && FLAG_verbose_debug) { |
| 1525 if (!func.IsNull()) { | 1676 OS::Print("No executable code at line %" Pd " in '%s'\n", |
| 1526 break; | 1677 line_number, script_url.ToCString()); |
| 1527 } | |
| 1528 first_token_idx++; | |
| 1529 } | 1678 } |
| 1530 if (func.IsNull()) { | 1679 return bpt; |
| 1531 if (FLAG_verbose_debug) { | |
| 1532 OS::Print("No executable code at line %" Pd " in '%s'\n", | |
| 1533 line_number, script_url.ToCString()); | |
| 1534 } | |
| 1535 return NULL; | |
| 1536 } | |
| 1537 if (last_token_idx < 0) { | |
| 1538 // The token at first_token_index is past the requested source line. | |
| 1539 // Set the breakpoint at the closest position after that line. | |
| 1540 last_token_idx = func.end_token_pos(); | |
| 1541 } | |
| 1542 return SetBreakpoint(func, first_token_idx, last_token_idx); | |
| 1543 } | 1680 } |
| 1544 | 1681 |
| 1545 | 1682 |
| 1546 intptr_t Debugger::CacheObject(const Object& obj) { | 1683 intptr_t Debugger::CacheObject(const Object& obj) { |
| 1547 ASSERT(obj_cache_ != NULL); | 1684 ASSERT(obj_cache_ != NULL); |
| 1548 return obj_cache_->AddObject(obj); | 1685 return obj_cache_->AddObject(obj); |
| 1549 } | 1686 } |
| 1550 | 1687 |
| 1551 | 1688 |
| 1552 bool Debugger::IsValidObjectId(intptr_t obj_id) { | 1689 bool Debugger::IsValidObjectId(intptr_t obj_id) { |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1912 // 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 |
| 1913 // debugger wire protocol messages. | 2050 // debugger wire protocol messages. |
| 1914 isolate_id_ = isolate->main_port(); | 2051 isolate_id_ = isolate->main_port(); |
| 1915 initialized_ = true; | 2052 initialized_ = true; |
| 1916 | 2053 |
| 1917 // Signal isolate creation event. | 2054 // Signal isolate creation event. |
| 1918 SignalIsolateEvent(Debugger::kIsolateCreated); | 2055 SignalIsolateEvent(Debugger::kIsolateCreated); |
| 1919 } | 2056 } |
| 1920 | 2057 |
| 1921 | 2058 |
| 1922 static RawFunction* GetOriginalFunction(const Function& func) { | 2059 // Return innermost closure contained in 'function' that entirely contains |
| 1923 if (func.IsClosureFunction()) { | 2060 // the given token range. |
| 1924 // Local functions (closures) in mixin functions do not have | 2061 RawFunction* Debugger::FindInnermostClosure(const Function& function, |
| 1925 // an original function they were cloned from. | 2062 intptr_t range_start, |
| 1926 // Note: this is a problem when a breakpoint is set in a mixed-in | 2063 intptr_t range_end) { |
|
turnidge
2013/12/19 22:31:59
Could this be static?
hausner
2013/12/21 00:08:32
Yes but I wanted to used debugger->isolate_ to spe
| |
| 1927 // closure. The breakpoint is linked to the closure attached to the | 2064 const Class& owner = Class::Handle(isolate_, function.Owner()); |
| 1928 // mixin application class, not the mixin class. When the same | 2065 if (owner.closures() == GrowableObjectArray::null()) { |
| 1929 // closure is compiled for another mixin application class, we | 2066 return Function::null(); |
| 1930 // don't find the breakpoint since we'll be looking in the | |
| 1931 // mixin class. | |
| 1932 return func.raw(); | |
| 1933 } | 2067 } |
| 1934 const Class& origin_class = Class::Handle(func.origin()); | 2068 // Note that we need to check that the closure is in the same |
| 1935 if (origin_class.is_patch()) { | 2069 // script as the outer function. We could have closures originating |
| 1936 // Patched functions from patch classes are removed from the | 2070 // in mixin classes whose source code is contained in a differenct |
|
turnidge
2013/12/19 22:31:59
typo "differenct"
hausner
2013/12/21 00:08:32
Done.
| |
| 1937 // function array of the patch class, so we will not find an | 2071 // script. |
| 1938 // original function object. | 2072 const Script& outer_origin = Script::Handle(isolate_, function.script()); |
| 1939 return func.raw(); | 2073 const GrowableObjectArray& closures = |
| 1940 } | 2074 GrowableObjectArray::Handle(isolate_, owner.closures()); |
| 1941 const Array& functions = Array::Handle(origin_class.functions()); | 2075 const intptr_t num_closures = closures.Length(); |
| 1942 Object& orig_func = Object::Handle(); | 2076 Function& closure = Function::Handle(isolate_); |
| 1943 for (intptr_t i = 0; i < functions.Length(); i++) { | 2077 Function& best_fit = Function::Handle(isolate_); |
| 1944 orig_func = functions.At(i); | 2078 for (intptr_t i = 0; i < num_closures; i++) { |
| 1945 // Function names are symbols, so we can compare the raw pointers. | 2079 closure ^= closures.At(i); |
| 1946 if (func.name() == Function::Cast(orig_func).name()) { | 2080 if ((function.token_pos() < closure.token_pos()) && |
| 1947 return Function::Cast(orig_func).raw(); | 2081 (closure.end_token_pos() < function.end_token_pos()) && |
| 2082 (closure.token_pos() <= range_start) && | |
| 2083 (range_end <= closure.end_token_pos()) && | |
| 2084 (closure.script() == outer_origin.raw())) { | |
| 2085 SelectBestFit(&best_fit, &closure); | |
| 1948 } | 2086 } |
| 1949 } | 2087 } |
| 1950 // Uncommon case: not a mixin function. | 2088 return best_fit.raw(); |
| 1951 ASSERT(!Class::Handle(func.Owner()).IsMixinApplication()); | |
| 1952 return func.raw(); | |
| 1953 } | 2089 } |
| 1954 | 2090 |
| 1955 | 2091 |
| 1956 void Debugger::NotifyCompilation(const Function& func) { | 2092 void Debugger::NotifyCompilation(const Function& func) { |
| 1957 if (src_breakpoints_ == NULL) { | 2093 if (src_breakpoints_ == NULL) { |
| 1958 // Return with minimal overhead if there are no breakpoints. | 2094 // Return with minimal overhead if there are no breakpoints. |
| 1959 return; | 2095 return; |
| 1960 } | 2096 } |
| 1961 Function& lookup_function = Function::Handle(func.raw()); | 2097 // Iterate over all source breakpoints to check whether breakpoints |
| 1962 if (func.IsImplicitClosureFunction()) { | 2098 // need to be set in the newly compiled function. |
| 1963 // If the newly compiled function is a an implicit closure (a closure that | 2099 Script& script = Script::Handle(isolate_); |
| 1964 // was formed by assigning a static or instance method to a function | 2100 for (SourceBreakpoint* bpt = src_breakpoints_; |
| 1965 // object), we need to use the closure's parent function to see whether | 2101 bpt != NULL; |
| 1966 // there are any breakpoints. The parent function is the actual method on | 2102 bpt = bpt->next()) { |
| 1967 // which the user sets breakpoints. | 2103 script = bpt->script(); |
| 1968 lookup_function = func.parent_function(); | 2104 if (RangeOverlaps(func, script, bpt->range_start_, bpt->range_end_)) { |
| 1969 ASSERT(!lookup_function.IsNull()); | 2105 Function& inner_function = Function::Handle(isolate_); |
|
turnidge
2013/12/19 22:31:59
Since the function name doesn't say "containing th
hausner
2013/12/21 00:08:32
obsolete
| |
| 1970 } | 2106 inner_function = |
| 1971 if (lookup_function.Owner() != lookup_function.origin()) { | 2107 FindInnermostClosure(func, bpt->range_start_, bpt->range_end_); |
| 1972 // This is a cloned function from a mixin class. If a breakpoint | 2108 if (!inner_function.IsNull()) { |
| 1973 // was set in this function, it is registered using the function | 2109 // The local function of a function we just compiled cannot |
| 1974 // of the origin class. | 2110 // be compiled already. |
| 1975 lookup_function = GetOriginalFunction(lookup_function); | 2111 ASSERT(!inner_function.HasCode()); |
| 1976 } | |
| 1977 SourceBreakpoint* bpt = src_breakpoints_; | |
| 1978 while (bpt != NULL) { | |
| 1979 if (lookup_function.raw() == bpt->function()) { | |
| 1980 // Check if the breakpoint is inside a closure or local function | |
| 1981 // within the newly compiled function. Note that we must look | |
| 1982 // in the owner class of the function that just got compiled | |
| 1983 // (i.e. func), not the owner class of the function we use to | |
| 1984 // record the breakpoint (lookup_function). | |
| 1985 Class& owner = Class::Handle(func.Owner()); | |
| 1986 Function& closure = | |
| 1987 Function::Handle(owner.LookupClosureFunction(bpt->token_pos())); | |
| 1988 if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) { | |
| 1989 if (FLAG_verbose_debug) { | 2112 if (FLAG_verbose_debug) { |
| 1990 OS::Print("Resetting pending breakpoint to function %s\n", | 2113 OS::Print("Pending BP remains unresolved in inner function '%s'\n", |
| 1991 closure.ToFullyQualifiedCString()); | 2114 inner_function.ToFullyQualifiedCString()); |
| 1992 } | 2115 } |
| 1993 bpt->set_function(closure); | 2116 continue; |
| 1994 } else { | 2117 } |
| 2118 | |
| 2119 // TODO(hausner): What should we do here? Can we deoptimize the function? | |
| 2120 ASSERT(!func.HasOptimizedCode()); | |
| 2121 | |
| 2122 // There is no local function within func that contains the | |
| 2123 // breakpoint token range. Resolve the breakpoint if necessary | |
| 2124 // and set the code breakpoints. | |
| 2125 if (!bpt->IsResolved()) { | |
| 2126 // Resolve source breakpoint in the newly compiled function. | |
| 2127 intptr_t bp_pos = | |
| 2128 ResolveBreakpointPos(func, bpt->range_start_, bpt->range_end_); | |
| 2129 if (bp_pos < 0) { | |
| 2130 if (FLAG_verbose_debug) { | |
| 2131 OS::Print("Failed resolving breakpoint for function '%s'\n", | |
| 2132 String::Handle(func.name()).ToCString()); | |
| 2133 } | |
| 2134 continue; | |
| 2135 } | |
| 2136 bpt->SetResolved(func, bp_pos); | |
| 1995 if (FLAG_verbose_debug) { | 2137 if (FLAG_verbose_debug) { |
| 1996 OS::Print("Enable pending breakpoint for function '%s'\n", | 2138 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " |
| 1997 String::Handle(lookup_function.name()).ToCString()); | 2139 "function '%s' (requested range %" Pd "-%" Pd ")\n", |
| 2140 bpt->id(), | |
| 2141 bpt->token_pos(), | |
| 2142 bpt->LineNumber(), | |
| 2143 func.ToFullyQualifiedCString(), | |
| 2144 bpt->range_start_, bpt->range_end_); | |
| 1998 } | 2145 } |
| 1999 const Script& script= Script::Handle(func.script()); | |
| 2000 intptr_t first_pos, last_pos; | |
| 2001 script.TokenRangeAtLine(bpt->LineNumber(), &first_pos, &last_pos); | |
| 2002 intptr_t bp_pos = | |
| 2003 ResolveBreakpointPos(func, bpt->token_pos(), last_pos); | |
| 2004 bpt->set_token_pos(bp_pos); | |
| 2005 MakeCodeBreakpointsAt(func, bp_pos, bpt); | |
| 2006 SignalBpResolved(bpt); | 2146 SignalBpResolved(bpt); |
| 2007 } | 2147 } |
| 2008 bpt->Enable(); // Enables the code breakpoint as well. | 2148 ASSERT(bpt->IsResolved()); |
| 2149 if (FLAG_verbose_debug) { | |
| 2150 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", | |
| 2151 bpt->id(), | |
| 2152 bpt->LineNumber(), | |
| 2153 func.IsClosureFunction() ? "closure" : "function", | |
| 2154 String::Handle(func.name()).ToCString()); | |
| 2155 } | |
| 2156 MakeCodeBreakpointsAt(func, bpt); | |
|
turnidge
2013/12/19 22:31:59
In SetBreakpoint, you call SignalBpResolved *after
hausner
2013/12/21 00:08:32
I don't think it matters. The isolate is not pause
| |
| 2009 } | 2157 } |
| 2010 bpt = bpt->next(); | |
| 2011 } | 2158 } |
| 2012 } | 2159 } |
| 2013 | 2160 |
| 2014 | 2161 |
| 2015 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 2162 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
| 2016 CodeBreakpoint* bpt = code_breakpoints_; | 2163 CodeBreakpoint* bpt = code_breakpoints_; |
| 2017 while (bpt != NULL) { | 2164 while (bpt != NULL) { |
| 2018 if (bpt->pc() == breakpoint_address) { | 2165 if (bpt->pc() == breakpoint_address) { |
| 2019 return bpt; | 2166 return bpt; |
| 2020 } | 2167 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2094 temp_bpt->Disable(); | 2241 temp_bpt->Disable(); |
| 2095 delete temp_bpt; | 2242 delete temp_bpt; |
| 2096 } else { | 2243 } else { |
| 2097 prev_bpt = curr_bpt; | 2244 prev_bpt = curr_bpt; |
| 2098 curr_bpt = curr_bpt->next(); | 2245 curr_bpt = curr_bpt->next(); |
| 2099 } | 2246 } |
| 2100 } | 2247 } |
| 2101 } | 2248 } |
| 2102 | 2249 |
| 2103 | 2250 |
| 2104 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func, | 2251 SourceBreakpoint* Debugger::GetUnresolvedBreakpoint(const Script& script, |
| 2105 intptr_t token_pos) { | 2252 intptr_t range_start) { |
| 2106 SourceBreakpoint* bpt = src_breakpoints_; | 2253 SourceBreakpoint* bpt = src_breakpoints_; |
| 2107 while (bpt != NULL) { | 2254 while (bpt != NULL) { |
| 2108 if ((bpt->function() == func.raw()) && | 2255 if ((bpt->script_ == script.raw()) && (bpt->range_start_ == range_start)) { |
|
turnidge
2013/12/19 22:31:59
SetResolved does not clear the range_start_, does
hausner
2013/12/21 00:08:32
obsolete
| |
| 2109 (bpt->token_pos() == token_pos)) { | |
| 2110 return bpt; | 2256 return bpt; |
| 2111 } | 2257 } |
| 2112 bpt = bpt->next(); | 2258 bpt = bpt->next(); |
| 2113 } | 2259 } |
| 2114 return NULL; | 2260 return NULL; |
| 2115 } | 2261 } |
| 2116 | 2262 |
| 2117 | 2263 |
| 2264 SourceBreakpoint* Debugger::GetResolvedBreakpoint(const Script& script, | |
| 2265 intptr_t token_pos) { | |
| 2266 SourceBreakpoint* bpt = src_breakpoints_; | |
| 2267 while (bpt != NULL) { | |
| 2268 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { | |
| 2269 return bpt; | |
| 2270 } | |
| 2271 bpt = bpt->next(); | |
| 2272 } | |
| 2273 return NULL; | |
| 2274 } | |
| 2275 | |
| 2276 | |
| 2118 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { | 2277 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { |
| 2119 SourceBreakpoint* bpt = src_breakpoints_; | 2278 SourceBreakpoint* bpt = src_breakpoints_; |
| 2120 while (bpt != NULL) { | 2279 while (bpt != NULL) { |
| 2121 if (bpt->id() == id) { | 2280 if (bpt->id() == id) { |
| 2122 return bpt; | 2281 return bpt; |
| 2123 } | 2282 } |
| 2124 bpt = bpt->next(); | 2283 bpt = bpt->next(); |
| 2125 } | 2284 } |
| 2126 return NULL; | 2285 return NULL; |
| 2127 } | 2286 } |
| 2128 | 2287 |
| 2129 | 2288 |
| 2130 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { | 2289 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { |
| 2131 ASSERT(bpt->next() == NULL); | 2290 ASSERT(bpt->next() == NULL); |
| 2132 bpt->set_next(src_breakpoints_); | 2291 bpt->set_next(src_breakpoints_); |
| 2133 src_breakpoints_ = bpt; | 2292 src_breakpoints_ = bpt; |
| 2134 } | 2293 } |
| 2135 | 2294 |
| 2136 | 2295 |
| 2137 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2296 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 2138 ASSERT(bpt->next() == NULL); | 2297 ASSERT(bpt->next() == NULL); |
| 2139 bpt->set_next(code_breakpoints_); | 2298 bpt->set_next(code_breakpoints_); |
| 2140 code_breakpoints_ = bpt; | 2299 code_breakpoints_ = bpt; |
| 2141 } | 2300 } |
| 2142 | 2301 |
| 2143 } // namespace dart | 2302 } // namespace dart |
| OLD | NEW |