Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: runtime/vm/debugger.cc

Issue 805573003: Fix debugging of async code (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698