| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 SourceBreakpoint::SourceBreakpoint(intptr_t id, | 57 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
| 58 const Script& script, | 58 const Script& script, |
| 59 intptr_t token_pos, | 59 intptr_t token_pos, |
| 60 intptr_t end_token_pos) | 60 intptr_t end_token_pos) |
| 61 : id_(id), | 61 : id_(id), |
| 62 script_(script.raw()), | 62 script_(script.raw()), |
| 63 token_pos_(token_pos), | 63 token_pos_(token_pos), |
| 64 end_token_pos_(end_token_pos), | 64 end_token_pos_(end_token_pos), |
| 65 is_resolved_(false), | 65 is_resolved_(false), |
| 66 is_enabled_(false), | 66 is_enabled_(false), |
| 67 is_one_shot_(false), |
| 67 next_(NULL), | 68 next_(NULL), |
| 68 function_(Function::null()), | 69 function_(Function::null()), |
| 69 line_number_(-1) { | 70 line_number_(-1) { |
| 70 ASSERT(id_ > 0); | 71 ASSERT(id_ > 0); |
| 71 ASSERT(!script.IsNull()); | 72 ASSERT(!script.IsNull()); |
| 72 ASSERT(token_pos_ >= 0); | 73 ASSERT(token_pos_ >= 0); |
| 73 } | 74 } |
| 74 | 75 |
| 75 | 76 |
| 76 void SourceBreakpoint::Enable() { | 77 void SourceBreakpoint::Enable() { |
| (...skipping 1054 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 if (function.HasOptimizedCode()) { | 1132 if (function.HasOptimizedCode()) { |
| 1132 function.SwitchToUnoptimizedCode(); | 1133 function.SwitchToUnoptimizedCode(); |
| 1133 } | 1134 } |
| 1134 } | 1135 } |
| 1135 } | 1136 } |
| 1136 } | 1137 } |
| 1137 } | 1138 } |
| 1138 } | 1139 } |
| 1139 | 1140 |
| 1140 | 1141 |
| 1141 RawError* Debugger::SetInternalBreakpoints(const Function& target_function) { | |
| 1142 if (target_function.is_native()) { | |
| 1143 // Can't instrument native functions. Fail silently. | |
| 1144 return Error::null(); | |
| 1145 } | |
| 1146 Isolate* isolate = Isolate::Current(); | |
| 1147 if (!target_function.HasCode()) { | |
| 1148 const Error& error = Error::Handle( | |
| 1149 Compiler::CompileFunction(isolate, target_function)); | |
| 1150 if (!error.IsNull()) { | |
| 1151 return error.raw(); | |
| 1152 } | |
| 1153 } | |
| 1154 // Hang on to the code object before deoptimizing, in case deoptimization | |
| 1155 // might cause the GC to run. | |
| 1156 Code& code = Code::Handle(isolate, target_function.unoptimized_code()); | |
| 1157 ASSERT(!code.IsNull()); | |
| 1158 DeoptimizeWorld(); | |
| 1159 ASSERT(!target_function.HasOptimizedCode()); | |
| 1160 PcDescriptors& desc = PcDescriptors::Handle(isolate, code.pc_descriptors()); | |
| 1161 PcDescriptors::Iterator iter(desc, kSafepointKind); | |
| 1162 while (iter.MoveNext()) { | |
| 1163 if (iter.TokenPos() != Scanner::kNoSourcePos) { | |
| 1164 CodeBreakpoint* bpt = GetCodeBreakpoint(iter.Pc()); | |
| 1165 if (bpt != NULL) { | |
| 1166 // There is already a breakpoint for this address. Make sure | |
| 1167 // it is enabled. | |
| 1168 bpt->Enable(); | |
| 1169 continue; | |
| 1170 } | |
| 1171 bpt = new CodeBreakpoint(code, iter.TokenPos(), | |
| 1172 iter.Pc(), iter.Kind()); | |
| 1173 RegisterCodeBreakpoint(bpt); | |
| 1174 bpt->Enable(); | |
| 1175 } | |
| 1176 } | |
| 1177 return Error::null(); | |
| 1178 } | |
| 1179 | |
| 1180 | |
| 1181 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { | 1142 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { |
| 1182 if (HasEventHandler()) { | 1143 if (HasEventHandler() && !bpt->IsOneShot()) { |
| 1183 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); | 1144 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved); |
| 1184 event.set_breakpoint(bpt); | 1145 event.set_breakpoint(bpt); |
| 1185 InvokeEventHandler(&event); | 1146 InvokeEventHandler(&event); |
| 1186 } | 1147 } |
| 1187 } | 1148 } |
| 1188 | 1149 |
| 1189 | 1150 |
| 1190 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, | 1151 ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate, |
| 1191 uword pc, | 1152 uword pc, |
| 1192 StackFrame* frame, | 1153 StackFrame* frame, |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1411 } | 1372 } |
| 1412 DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown); | 1373 DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown); |
| 1413 event.set_exception(&exc); | 1374 event.set_exception(&exc); |
| 1414 ASSERT(stack_trace_ == NULL); | 1375 ASSERT(stack_trace_ == NULL); |
| 1415 stack_trace_ = stack_trace; | 1376 stack_trace_ = stack_trace; |
| 1416 Pause(&event); | 1377 Pause(&event); |
| 1417 stack_trace_ = NULL; | 1378 stack_trace_ = NULL; |
| 1418 } | 1379 } |
| 1419 | 1380 |
| 1420 | 1381 |
| 1382 static intptr_t LastTokenOnLine(const TokenStream& tokens, intptr_t pos) { |
| 1383 TokenStream::Iterator iter(tokens, pos, TokenStream::Iterator::kAllTokens); |
| 1384 ASSERT(iter.IsValid()); |
| 1385 intptr_t last_pos = pos; |
| 1386 while ((iter.CurrentTokenKind() != Token::kNEWLINE) && |
| 1387 (iter.CurrentTokenKind() != Token::kEOS)) { |
| 1388 last_pos = iter.CurrentPosition(); |
| 1389 iter.Advance(); |
| 1390 } |
| 1391 return last_pos; |
| 1392 } |
| 1393 |
| 1394 |
| 1421 // Given a function and a token range, return the best fit | 1395 // Given a function and a token range, return the best fit |
| 1422 // token position to set a breakpoint. The best fit is the safe point | 1396 // token position to set a breakpoint. The best fit is the safe point |
| 1423 // with the lowest compiled code address within the token range. | 1397 // in the line closest to the beginning of the token range, and within |
| 1398 // that line, the safe point with the lowest compiled code address. |
| 1424 intptr_t Debugger::ResolveBreakpointPos(const Function& func, | 1399 intptr_t Debugger::ResolveBreakpointPos(const Function& func, |
| 1425 intptr_t requested_token_pos, | 1400 intptr_t requested_token_pos, |
| 1426 intptr_t last_token_pos) { | 1401 intptr_t last_token_pos) { |
| 1427 ASSERT(func.HasCode()); | 1402 ASSERT(func.HasCode()); |
| 1428 ASSERT(!func.HasOptimizedCode()); | 1403 ASSERT(!func.HasOptimizedCode()); |
| 1429 | 1404 |
| 1430 if (requested_token_pos < func.token_pos()) { | 1405 if (requested_token_pos < func.token_pos()) { |
| 1431 requested_token_pos = func.token_pos(); | 1406 requested_token_pos = func.token_pos(); |
| 1432 } | 1407 } |
| 1433 if (last_token_pos > func.end_token_pos()) { | 1408 if (last_token_pos > func.end_token_pos()) { |
| 1434 last_token_pos = func.end_token_pos(); | 1409 last_token_pos = func.end_token_pos(); |
| 1435 } | 1410 } |
| 1436 | 1411 |
| 1437 Code& code = Code::Handle(func.unoptimized_code()); | 1412 Code& code = Code::Handle(func.unoptimized_code()); |
| 1438 ASSERT(!code.IsNull()); | 1413 ASSERT(!code.IsNull()); |
| 1439 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1414 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 1415 |
| 1416 // First pass: find the safe point which is closest to the beginning |
| 1417 // of the given token range. |
| 1440 intptr_t best_fit_pos = INT_MAX; | 1418 intptr_t best_fit_pos = INT_MAX; |
| 1441 uword lowest_pc = kUwordMax; | |
| 1442 intptr_t lowest_pc_token_pos = INT_MAX; | |
| 1443 PcDescriptors::Iterator iter(desc, kSafepointKind); | 1419 PcDescriptors::Iterator iter(desc, kSafepointKind); |
| 1444 while (iter.MoveNext()) { | 1420 while (iter.MoveNext()) { |
| 1445 const intptr_t desc_token_pos = iter.TokenPos(); | 1421 const intptr_t desc_token_pos = iter.TokenPos(); |
| 1446 ASSERT(desc_token_pos >= 0); | 1422 if ((desc_token_pos != Scanner::kNoSourcePos) && |
| 1447 if (desc_token_pos != Scanner::kNoSourcePos) { | 1423 (desc_token_pos < best_fit_pos) && |
| 1448 if ((desc_token_pos < requested_token_pos) || | 1424 (desc_token_pos >= requested_token_pos) && |
| 1449 (desc_token_pos > last_token_pos)) { | 1425 (desc_token_pos <= last_token_pos)) { |
| 1450 // This descriptor is outside the desired token range. | 1426 best_fit_pos = desc_token_pos; |
| 1451 continue; | 1427 } |
| 1452 } | 1428 } |
| 1453 if (desc_token_pos < best_fit_pos) { | 1429 // Second pass (if we found a safe point in the first pass): |
| 1454 // So far, this descriptor has the lowest token position after | 1430 // For all token positions on the same line, select the one |
| 1455 // the first acceptable token position. | 1431 // with the lowest compiled code address. E.g., in a line with |
| 1456 best_fit_pos = desc_token_pos; | 1432 // the nested function calls f(g(x)), the call g() will have a lower |
| 1457 } | 1433 // compiled code address but is not the lowest token position in the |
| 1458 if (iter.Pc() < lowest_pc) { | 1434 // line. |
| 1459 // This descriptor so far has the lowest code address. | 1435 if (best_fit_pos != INT_MAX) { |
| 1436 const Script& script = Script::Handle(func.script()); |
| 1437 const TokenStream& tokens = TokenStream::Handle(script.tokens()); |
| 1438 const intptr_t begin_pos = best_fit_pos; |
| 1439 const intptr_t end_of_line_pos = LastTokenOnLine(tokens, begin_pos); |
| 1440 uword lowest_pc = kUwordMax; |
| 1441 PcDescriptors::Iterator iter(desc, kSafepointKind); |
| 1442 while (iter.MoveNext()) { |
| 1443 const intptr_t pos = iter.TokenPos(); |
| 1444 if ((pos != Scanner::kNoSourcePos) && |
| 1445 (begin_pos <= pos) && (pos <= end_of_line_pos) && |
| 1446 (iter.Pc() < lowest_pc)) { |
| 1460 lowest_pc = iter.Pc(); | 1447 lowest_pc = iter.Pc(); |
| 1461 lowest_pc_token_pos = desc_token_pos; | 1448 best_fit_pos = pos; |
| 1462 } | 1449 } |
| 1463 } | 1450 } |
| 1464 } | |
| 1465 if (lowest_pc_token_pos != INT_MAX) { | |
| 1466 // We found the pc descriptor that has the lowest execution address. | |
| 1467 // This is the first possible breakpoint after the requested token | |
| 1468 // position. We use this instead of the nearest PC descriptor | |
| 1469 // measured in token index distance. | |
| 1470 return lowest_pc_token_pos; | |
| 1471 } | |
| 1472 if (best_fit_pos != INT_MAX) { | |
| 1473 return best_fit_pos; | 1451 return best_fit_pos; |
| 1474 } | 1452 } |
| 1453 |
| 1475 // We didn't find a safe point in the given token range. Try and find | 1454 // We didn't find a safe point in the given token range. Try and find |
| 1476 // a safe point in the remaining source code of the function. | 1455 // a safe point in the remaining source code of the function. |
| 1477 if (last_token_pos < func.end_token_pos()) { | 1456 if (last_token_pos < func.end_token_pos()) { |
| 1478 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos()); | 1457 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos()); |
| 1479 } | 1458 } |
| 1480 return -1; | 1459 return -1; |
| 1481 } | 1460 } |
| 1482 | 1461 |
| 1483 | 1462 |
| 1484 void Debugger::MakeCodeBreakpointAt(const Function& func, | 1463 void Debugger::MakeCodeBreakpointAt(const Function& func, |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1547 if (!functions.IsNull()) { | 1526 if (!functions.IsNull()) { |
| 1548 const intptr_t num_functions = functions.Length(); | 1527 const intptr_t num_functions = functions.Length(); |
| 1549 for (intptr_t pos = 0; pos < num_functions; pos++) { | 1528 for (intptr_t pos = 0; pos < num_functions; pos++) { |
| 1550 function ^= functions.At(pos); | 1529 function ^= functions.At(pos); |
| 1551 ASSERT(!function.IsNull()); | 1530 ASSERT(!function.IsNull()); |
| 1552 // Check token position first to avoid unnecessary calls | 1531 // Check token position first to avoid unnecessary calls |
| 1553 // to script() which allocates handles. | 1532 // to script() which allocates handles. |
| 1554 if ((function.token_pos() == start_pos) | 1533 if ((function.token_pos() == start_pos) |
| 1555 && (function.end_token_pos() == end_pos) | 1534 && (function.end_token_pos() == end_pos) |
| 1556 && (function.script() == script.raw())) { | 1535 && (function.script() == script.raw())) { |
| 1557 if (function.HasCode()) { | 1536 if (function.HasCode() && !function.IsAsyncFunction()) { |
| 1558 function_list->Add(function); | 1537 function_list->Add(function); |
| 1559 } | 1538 } |
| 1560 if (function.HasImplicitClosureFunction()) { | 1539 if (function.HasImplicitClosureFunction()) { |
| 1561 function = function.ImplicitClosureFunction(); | 1540 function = function.ImplicitClosureFunction(); |
| 1562 if (function.HasCode()) { | 1541 if (function.HasCode() && !function.IsAsyncFunction()) { |
| 1563 function_list->Add(function); | 1542 function_list->Add(function); |
| 1564 } | 1543 } |
| 1565 } | 1544 } |
| 1566 } | 1545 } |
| 1567 } | 1546 } |
| 1568 } | 1547 } |
| 1569 closures = cls.closures(); | 1548 closures = cls.closures(); |
| 1570 if (!closures.IsNull()) { | 1549 if (!closures.IsNull()) { |
| 1571 const intptr_t num_closures = closures.Length(); | 1550 const intptr_t num_closures = closures.Length(); |
| 1572 for (intptr_t pos = 0; pos < num_closures; pos++) { | 1551 for (intptr_t pos = 0; pos < num_closures; pos++) { |
| 1573 function ^= closures.At(pos); | 1552 function ^= closures.At(pos); |
| 1574 ASSERT(!function.IsNull()); | 1553 ASSERT(!function.IsNull()); |
| 1575 if ((function.token_pos() == start_pos) | 1554 if ((function.token_pos() == start_pos) |
| 1576 && (function.end_token_pos() == end_pos) | 1555 && (function.end_token_pos() == end_pos) |
| 1577 && (function.script() == script.raw())) { | 1556 && (function.script() == script.raw())) { |
| 1578 if (function.HasCode()) { | 1557 if (function.HasCode() && !function.IsAsyncFunction()) { |
| 1579 function_list->Add(function); | 1558 function_list->Add(function); |
| 1580 } | 1559 } |
| 1581 if (function.HasImplicitClosureFunction()) { | 1560 if (function.HasImplicitClosureFunction()) { |
| 1582 function = function.ImplicitClosureFunction(); | 1561 function = function.ImplicitClosureFunction(); |
| 1583 if (function.HasCode()) { | 1562 if (function.HasCode() && !function.IsAsyncFunction()) { |
| 1584 function_list->Add(function); | 1563 function_list->Add(function); |
| 1585 } | 1564 } |
| 1586 } | 1565 } |
| 1587 } | 1566 } |
| 1588 } | 1567 } |
| 1589 } | 1568 } |
| 1590 } | 1569 } |
| 1591 } | 1570 } |
| 1592 } | 1571 } |
| 1593 | 1572 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1716 const intptr_t num_functions = functions.Length(); | 1695 const intptr_t num_functions = functions.Length(); |
| 1717 for (intptr_t i = 0; i < num_functions; i++) { | 1696 for (intptr_t i = 0; i < num_functions; i++) { |
| 1718 func ^= functions.At(i); | 1697 func ^= functions.At(i); |
| 1719 ASSERT(func.HasCode()); | 1698 ASSERT(func.HasCode()); |
| 1720 MakeCodeBreakpointAt(func, bpt); | 1699 MakeCodeBreakpointAt(func, bpt); |
| 1721 } | 1700 } |
| 1722 bpt->Enable(); | 1701 bpt->Enable(); |
| 1723 if (FLAG_verbose_debug) { | 1702 if (FLAG_verbose_debug) { |
| 1724 intptr_t line_number; | 1703 intptr_t line_number; |
| 1725 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); | 1704 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); |
| 1726 OS::Print("Resolved breakpoint for " | 1705 OS::Print("Resolved BP for " |
| 1727 "function '%s' at line %" Pd "\n", | 1706 "function '%s' at line %" Pd "\n", |
| 1728 func.ToFullyQualifiedCString(), | 1707 func.ToFullyQualifiedCString(), |
| 1729 line_number); | 1708 line_number); |
| 1730 } | 1709 } |
| 1731 SignalBpResolved(bpt); | 1710 SignalBpResolved(bpt); |
| 1732 return bpt; | 1711 return bpt; |
| 1733 } | 1712 } |
| 1734 } | 1713 } |
| 1735 // There is no compiled function at this token position. | 1714 // There is no compiled function at this token position. |
| 1736 // Register an unresolved breakpoint. | 1715 // Register an unresolved breakpoint. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1763 } else { | 1742 } else { |
| 1764 cbpt->Disable(); | 1743 cbpt->Disable(); |
| 1765 } | 1744 } |
| 1766 } | 1745 } |
| 1767 cbpt = cbpt->next(); | 1746 cbpt = cbpt->next(); |
| 1768 } | 1747 } |
| 1769 } | 1748 } |
| 1770 | 1749 |
| 1771 | 1750 |
| 1772 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { | 1751 RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) { |
| 1773 Error& err = Error::Handle(); | 1752 SourceBreakpoint* bpt = SetBreakpointAtEntry(target_function); |
| 1774 err = SetInternalBreakpoints(target_function); | 1753 if (bpt != NULL) { |
| 1775 if (err.IsNull() && target_function.HasImplicitClosureFunction()) { | 1754 bpt->SetIsOneShot(); |
| 1776 const Function& closure_func = | |
| 1777 Function::Handle(target_function.ImplicitClosureFunction()); | |
| 1778 err = SetInternalBreakpoints(closure_func); | |
| 1779 } | 1755 } |
| 1780 return err.raw(); | 1756 return Error::null(); |
| 1781 } | 1757 } |
| 1782 | 1758 |
| 1783 | 1759 |
| 1784 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 1760 SourceBreakpoint* Debugger::SetBreakpointAtEntry( |
| 1785 const Function& target_function) { | 1761 const Function& target_function) { |
| 1786 ASSERT(!target_function.IsNull()); | 1762 ASSERT(!target_function.IsNull()); |
| 1787 const Script& script = Script::Handle(target_function.script()); | 1763 const Script& script = Script::Handle(target_function.script()); |
| 1788 return SetBreakpoint(script, | 1764 return SetBreakpoint(script, |
| 1789 target_function.token_pos(), | 1765 target_function.token_pos(), |
| 1790 target_function.end_token_pos()); | 1766 target_function.end_token_pos()); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2129 } | 2105 } |
| 2130 | 2106 |
| 2131 | 2107 |
| 2132 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, | 2108 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, |
| 2133 SourceBreakpoint* bpt) { | 2109 SourceBreakpoint* bpt) { |
| 2134 resume_action_ = kContinue; | 2110 resume_action_ = kContinue; |
| 2135 stepping_fp_ = 0; | 2111 stepping_fp_ = 0; |
| 2136 isolate_->set_single_step(false); | 2112 isolate_->set_single_step(false); |
| 2137 ASSERT(!IsPaused()); | 2113 ASSERT(!IsPaused()); |
| 2138 ASSERT(obj_cache_ == NULL); | 2114 ASSERT(obj_cache_ == NULL); |
| 2115 if ((bpt != NULL) && bpt->IsOneShot()) { |
| 2116 RemoveBreakpoint(bpt->id()); |
| 2117 bpt = NULL; |
| 2118 } |
| 2139 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); | 2119 DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached); |
| 2140 event.set_top_frame(top_frame); | 2120 event.set_top_frame(top_frame); |
| 2141 event.set_breakpoint(bpt); | 2121 event.set_breakpoint(bpt); |
| 2142 Pause(&event); | 2122 Pause(&event); |
| 2143 } | 2123 } |
| 2144 | 2124 |
| 2145 | 2125 |
| 2146 void Debugger::DebuggerStepCallback() { | 2126 void Debugger::DebuggerStepCallback() { |
| 2147 ASSERT(isolate_->single_step()); | 2127 ASSERT(isolate_->single_step()); |
| 2148 // We can't get here unless the debugger event handler enabled | 2128 // We can't get here unless the debugger event handler enabled |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2497 } | 2477 } |
| 2498 | 2478 |
| 2499 | 2479 |
| 2500 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 2480 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 2501 ASSERT(bpt->next() == NULL); | 2481 ASSERT(bpt->next() == NULL); |
| 2502 bpt->set_next(code_breakpoints_); | 2482 bpt->set_next(code_breakpoints_); |
| 2503 code_breakpoints_ = bpt; | 2483 code_breakpoints_ = bpt; |
| 2504 } | 2484 } |
| 2505 | 2485 |
| 2506 } // namespace dart | 2486 } // namespace dart |
| OLD | NEW |