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 |