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

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

Issue 233973003: Improve breakpoint resolution (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 8 months 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') | no next file » | 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 Script& script, 53 const Script& script,
54 intptr_t token_pos) 54 intptr_t token_pos,
55 intptr_t end_token_pos)
55 : id_(id), 56 : id_(id),
56 script_(script.raw()), 57 script_(script.raw()),
57 token_pos_(token_pos), 58 token_pos_(token_pos),
59 end_token_pos_(end_token_pos),
58 is_resolved_(false), 60 is_resolved_(false),
59 is_enabled_(false), 61 is_enabled_(false),
60 next_(NULL), 62 next_(NULL),
61 function_(Function::null()), 63 function_(Function::null()),
62 line_number_(-1) { 64 line_number_(-1) {
63 ASSERT(id_ > 0); 65 ASSERT(id_ > 0);
64 ASSERT(!script.IsNull()); 66 ASSERT(!script.IsNull());
65 ASSERT(token_pos_ >= 0); 67 ASSERT(token_pos_ >= 0);
66 } 68 }
67 69
68 70
69 void SourceBreakpoint::Enable() { 71 void SourceBreakpoint::Enable() {
70 is_enabled_ = true; 72 is_enabled_ = true;
71 Isolate::Current()->debugger()->SyncBreakpoint(this); 73 Isolate::Current()->debugger()->SyncBreakpoint(this);
72 } 74 }
73 75
74 76
75 void SourceBreakpoint::Disable() { 77 void SourceBreakpoint::Disable() {
76 is_enabled_ = false; 78 is_enabled_ = false;
77 Isolate::Current()->debugger()->SyncBreakpoint(this); 79 Isolate::Current()->debugger()->SyncBreakpoint(this);
78 } 80 }
79 81
80 82
81 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) { 83 void SourceBreakpoint::SetResolved(const Function& func, intptr_t token_pos) {
82 ASSERT(func.script() == script_); 84 ASSERT(func.script() == script_);
83 ASSERT((func.token_pos() <= token_pos) && 85 ASSERT((func.token_pos() <= token_pos) &&
84 (token_pos <= func.end_token_pos())); 86 (token_pos <= func.end_token_pos()));
85 function_ = func.raw(); 87 function_ = func.raw();
86 token_pos_ = token_pos; 88 token_pos_ = token_pos;
89 end_token_pos_ = token_pos;
87 line_number_ = -1; // Recalcualte lazily. 90 line_number_ = -1; // Recalcualte lazily.
88 is_resolved_ = true; 91 is_resolved_ = true;
89 } 92 }
90 93
91 94
92 // TODO(hausner): Get rid of library parameter. A source breakpoint location 95 // TODO(hausner): Get rid of library parameter. A source breakpoint location
93 // does not imply a library, since the same source code can be included 96 // does not imply a library, since the same source code can be included
94 // in more than one library, e.g. the text location of mixin functions. 97 // in more than one library, e.g. the text location of mixin functions.
95 void SourceBreakpoint::GetCodeLocation( 98 void SourceBreakpoint::GetCodeLocation(
96 Library* lib, 99 Library* lib,
(...skipping 1198 matching lines...) Expand 10 before | Expand all | Expand 10 after
1295 } 1298 }
1296 DebuggerEvent event(kExceptionThrown); 1299 DebuggerEvent event(kExceptionThrown);
1297 event.exception = &exc; 1300 event.exception = &exc;
1298 ASSERT(stack_trace_ == NULL); 1301 ASSERT(stack_trace_ == NULL);
1299 stack_trace_ = stack_trace; 1302 stack_trace_ = stack_trace;
1300 Pause(&event); 1303 Pause(&event);
1301 stack_trace_ = NULL; 1304 stack_trace_ = NULL;
1302 } 1305 }
1303 1306
1304 1307
1305 // Given a function and a token position, return the best fit 1308 // Given a function and a token range, return the best fit
1306 // token position to set a breakpoint. The best fit is the safe point 1309 // token position to set a breakpoint. The best fit is the safe point
1307 // with the lowest compiled code address that follows the requsted 1310 // with the lowest compiled code address within the token range.
1308 // token position.
1309 intptr_t Debugger::ResolveBreakpointPos(const Function& func, 1311 intptr_t Debugger::ResolveBreakpointPos(const Function& func,
1310 intptr_t requested_token_pos) { 1312 intptr_t requested_token_pos,
1313 intptr_t last_token_pos) {
1311 ASSERT(func.HasCode()); 1314 ASSERT(func.HasCode());
1312 ASSERT(!func.HasOptimizedCode()); 1315 ASSERT(!func.HasOptimizedCode());
1316
1317 if (requested_token_pos < func.token_pos()) {
1318 requested_token_pos = func.token_pos();
1319 }
1320 if (last_token_pos > func.end_token_pos()) {
1321 last_token_pos = func.end_token_pos();
1322 }
srdjan 2014/04/11 17:12:07 ASSERT(requested_token_pos <= last_token_pos);
hausner 2014/04/11 17:49:05 Not necessarily. It might be possible that the req
1323
1313 Code& code = Code::Handle(func.unoptimized_code()); 1324 Code& code = Code::Handle(func.unoptimized_code());
1314 ASSERT(!code.IsNull()); 1325 ASSERT(!code.IsNull());
1315 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); 1326 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
1316 intptr_t best_fit_index = -1; 1327 intptr_t best_fit_index = -1;
1317 intptr_t best_fit_pos = INT_MAX; 1328 intptr_t best_fit_pos = INT_MAX;
1318 uword lowest_pc = kUwordMax; 1329 uword lowest_pc = kUwordMax;
1319 intptr_t lowest_pc_index = -1; 1330 intptr_t lowest_pc_index = -1;
1331
1320 for (intptr_t i = 0; i < desc.Length(); i++) { 1332 for (intptr_t i = 0; i < desc.Length(); i++) {
1321 intptr_t desc_token_pos = desc.TokenPos(i); 1333 intptr_t desc_token_pos = desc.TokenPos(i);
1322 ASSERT(desc_token_pos >= 0); 1334 ASSERT(desc_token_pos >= 0);
1323 if (IsSafePoint(desc, i)) { 1335 if (IsSafePoint(desc, i)) {
1324 if ((desc_token_pos < func.token_pos()) || 1336 if ((desc_token_pos < requested_token_pos) ||
1325 (desc_token_pos > func.end_token_pos())) { 1337 (desc_token_pos > last_token_pos)) {
1326 // The position is outside of the function token range. This can 1338 // This descriptor is outside the desired token range.
1327 // happen in constructors, for initializer expressions that are
1328 // inlined in the field declaration.
1329 ASSERT(func.IsConstructor());
1330 continue;
1331 }
1332 if (desc_token_pos < requested_token_pos) {
1333 // This descriptor is before the first acceptable token position.
1334 continue; 1339 continue;
1335 } 1340 }
1336 if (desc_token_pos < best_fit_pos) { 1341 if (desc_token_pos < best_fit_pos) {
1337 // So far, this descriptor has the lowest token position after 1342 // So far, this descriptor has the lowest token position after
1338 // the first acceptable token position. 1343 // the first acceptable token position.
1339 best_fit_pos = desc_token_pos; 1344 best_fit_pos = desc_token_pos;
1340 best_fit_index = i; 1345 best_fit_index = i;
1341 } 1346 }
1342 if (desc.PC(i) < lowest_pc) { 1347 if (desc.PC(i) < lowest_pc) {
1343 // This descriptor so far has the lowest code address. 1348 // This descriptor so far has the lowest code address.
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
1535 } 1540 }
1536 } 1541 }
1537 } 1542 }
1538 } 1543 }
1539 } 1544 }
1540 return best_fit.raw(); 1545 return best_fit.raw();
1541 } 1546 }
1542 1547
1543 1548
1544 SourceBreakpoint* Debugger::SetBreakpoint(const Script& script, 1549 SourceBreakpoint* Debugger::SetBreakpoint(const Script& script,
1545 intptr_t token_pos) { 1550 intptr_t token_pos,
1551 intptr_t last_token_pos) {
1546 Function& func = Function::Handle(isolate_); 1552 Function& func = Function::Handle(isolate_);
1547 func = FindBestFit(script, token_pos); 1553 func = FindBestFit(script, token_pos);
1548 if (func.IsNull()) { 1554 if (func.IsNull()) {
1549 return NULL; 1555 return NULL;
1550 } 1556 }
1551 // There may be more than one function object for a given function 1557 // There may be more than one function object for a given function
1552 // in source code. There may be implicit closure functions, and 1558 // in source code. There may be implicit closure functions, and
1553 // there may be copies of mixin functions. Collect all compiled 1559 // there may be copies of mixin functions. Collect all compiled
1554 // functions whose source code range matches exactly the best fit 1560 // functions whose source code range matches exactly the best fit
1555 // function we found. 1561 // function we found.
1556 GrowableObjectArray& functions = 1562 GrowableObjectArray& functions =
1557 GrowableObjectArray::Handle(GrowableObjectArray::New()); 1563 GrowableObjectArray::Handle(GrowableObjectArray::New());
1558 FindCompiledFunctions(script, 1564 FindCompiledFunctions(script,
1559 func.token_pos(), 1565 func.token_pos(),
1560 func.end_token_pos(), 1566 func.end_token_pos(),
1561 &functions); 1567 &functions);
1562 1568
1563 if (functions.Length() > 0) { 1569 if (functions.Length() > 0) {
1564 // One or more function object containing this breakpoint location 1570 // One or more function object containing this breakpoint location
1565 // have already been compiled. We can resolve the breakpoint now. 1571 // have already been compiled. We can resolve the breakpoint now.
1566 DeoptimizeWorld(); 1572 DeoptimizeWorld();
1567 func ^= functions.At(0); 1573 func ^= functions.At(0);
1568 intptr_t breakpoint_pos = ResolveBreakpointPos(func, token_pos); 1574 intptr_t breakpoint_pos =
1575 ResolveBreakpointPos(func, token_pos, last_token_pos);
1569 if (breakpoint_pos >= 0) { 1576 if (breakpoint_pos >= 0) {
1570 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos); 1577 SourceBreakpoint* bpt = GetSourceBreakpoint(script, breakpoint_pos);
1571 if (bpt != NULL) { 1578 if (bpt != NULL) {
1572 // A source breakpoint for this location already exists. 1579 // A source breakpoint for this location already exists.
1573 return bpt; 1580 return bpt;
1574 } 1581 }
1575 bpt = new SourceBreakpoint(nextId(), script, token_pos); 1582 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos);
1576 bpt->SetResolved(func, breakpoint_pos); 1583 bpt->SetResolved(func, breakpoint_pos);
1577 RegisterSourceBreakpoint(bpt); 1584 RegisterSourceBreakpoint(bpt);
1578 1585
1579 // Create code breakpoints for all compiled functions we found. 1586 // Create code breakpoints for all compiled functions we found.
1580 const intptr_t num_functions = functions.Length(); 1587 const intptr_t num_functions = functions.Length();
1581 for (intptr_t i = 0; i < num_functions; i++) { 1588 for (intptr_t i = 0; i < num_functions; i++) {
1582 func ^= functions.At(i); 1589 func ^= functions.At(i);
1583 ASSERT(func.HasCode()); 1590 ASSERT(func.HasCode());
1584 MakeCodeBreakpointsAt(func, bpt); 1591 MakeCodeBreakpointsAt(func, bpt);
1585 } 1592 }
1586 bpt->Enable(); 1593 bpt->Enable();
1594 if (FLAG_verbose_debug) {
1595 intptr_t line_number;
1596 script.GetTokenLocation(breakpoint_pos, &line_number, NULL);
1597 OS::Print("Resolved breakpoint for "
1598 "function '%s' at line %" Pd "\n",
1599 func.ToFullyQualifiedCString(),
1600 line_number);
1601 }
1587 SignalBpResolved(bpt); 1602 SignalBpResolved(bpt);
1588 return bpt; 1603 return bpt;
1589 } 1604 }
1590 } 1605 }
1591 // There is no compiled function at this token position. 1606 // There is no compiled function at this token position.
1592 // Register an unresolved breakpoint. 1607 // Register an unresolved breakpoint.
1593 if (FLAG_verbose_debug && !func.IsNull()) { 1608 if (FLAG_verbose_debug && !func.IsNull()) {
1594 intptr_t line_number; 1609 intptr_t line_number;
1595 script.GetTokenLocation(token_pos, &line_number, NULL); 1610 script.GetTokenLocation(token_pos, &line_number, NULL);
1596 OS::Print("Registering pending breakpoint for " 1611 OS::Print("Registering pending breakpoint for "
1597 "uncompiled function '%s' at line %" Pd "\n", 1612 "uncompiled function '%s' at line %" Pd "\n",
1598 func.ToFullyQualifiedCString(), 1613 func.ToFullyQualifiedCString(),
1599 line_number); 1614 line_number);
1600 } 1615 }
1601 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos); 1616 SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos);
1602 if (bpt == NULL) { 1617 if (bpt == NULL) {
1603 bpt = new SourceBreakpoint(nextId(), script, token_pos); 1618 bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos);
1604 } 1619 }
1605 RegisterSourceBreakpoint(bpt); 1620 RegisterSourceBreakpoint(bpt);
1606 bpt->Enable(); 1621 bpt->Enable();
1607 return bpt; 1622 return bpt;
1608 } 1623 }
1609 1624
1610 1625
1611 // Synchronize the enabled/disabled state of all code breakpoints 1626 // Synchronize the enabled/disabled state of all code breakpoints
1612 // associated with the source breakpoint bpt. 1627 // associated with the source breakpoint bpt.
1613 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { 1628 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) {
(...skipping 18 matching lines...) Expand all
1632 Function::Handle(target_function.ImplicitClosureFunction()); 1647 Function::Handle(target_function.ImplicitClosureFunction());
1633 SetInternalBreakpoints(closure_func); 1648 SetInternalBreakpoints(closure_func);
1634 } 1649 }
1635 } 1650 }
1636 1651
1637 1652
1638 SourceBreakpoint* Debugger::SetBreakpointAtEntry( 1653 SourceBreakpoint* Debugger::SetBreakpointAtEntry(
1639 const Function& target_function) { 1654 const Function& target_function) {
1640 ASSERT(!target_function.IsNull()); 1655 ASSERT(!target_function.IsNull());
1641 const Script& script = Script::Handle(target_function.script()); 1656 const Script& script = Script::Handle(target_function.script());
1642 return SetBreakpoint(script, target_function.token_pos()); 1657 return SetBreakpoint(script,
1658 target_function.token_pos(),
1659 target_function.end_token_pos());
1643 } 1660 }
1644 1661
1645 1662
1646 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, 1663 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
1647 intptr_t line_number) { 1664 intptr_t line_number) {
1648 Library& lib = Library::Handle(isolate_); 1665 Library& lib = Library::Handle(isolate_);
1649 Script& script = Script::Handle(isolate_); 1666 Script& script = Script::Handle(isolate_);
1650 const GrowableObjectArray& libs = 1667 const GrowableObjectArray& libs =
1651 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); 1668 GrowableObjectArray::Handle(isolate_->object_store()->libraries());
1652 for (intptr_t i = 0; i < libs.Length(); i++) { 1669 for (intptr_t i = 0; i < libs.Length(); i++) {
(...skipping 24 matching lines...) Expand all
1677 if (FLAG_verbose_debug) { 1694 if (FLAG_verbose_debug) {
1678 OS::Print("No executable code at line %" Pd " in '%s'\n", 1695 OS::Print("No executable code at line %" Pd " in '%s'\n",
1679 line_number, script_url.ToCString()); 1696 line_number, script_url.ToCString());
1680 } 1697 }
1681 return NULL; 1698 return NULL;
1682 } 1699 }
1683 1700
1684 SourceBreakpoint* bpt = NULL; 1701 SourceBreakpoint* bpt = NULL;
1685 ASSERT(first_token_idx <= last_token_idx); 1702 ASSERT(first_token_idx <= last_token_idx);
1686 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) { 1703 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) {
1687 bpt = SetBreakpoint(script, first_token_idx); 1704 bpt = SetBreakpoint(script, first_token_idx, last_token_idx);
1688 first_token_idx++; 1705 first_token_idx++;
1689 } 1706 }
1690 if ((bpt == NULL) && FLAG_verbose_debug) { 1707 if ((bpt == NULL) && FLAG_verbose_debug) {
1691 OS::Print("No executable code at line %" Pd " in '%s'\n", 1708 OS::Print("No executable code at line %" Pd " in '%s'\n",
1692 line_number, script_url.ToCString()); 1709 line_number, script_url.ToCString());
1693 } 1710 }
1694 return bpt; 1711 return bpt;
1695 } 1712 }
1696 1713
1697 1714
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
2143 2160
2144 // TODO(hausner): What should we do if function is optimized? 2161 // TODO(hausner): What should we do if function is optimized?
2145 // Can we deoptimize the function? 2162 // Can we deoptimize the function?
2146 ASSERT(!func.HasOptimizedCode()); 2163 ASSERT(!func.HasOptimizedCode());
2147 2164
2148 // There is no local function within func that contains the 2165 // There is no local function within func that contains the
2149 // breakpoint token position. Resolve the breakpoint if necessary 2166 // breakpoint token position. Resolve the breakpoint if necessary
2150 // and set the code breakpoints. 2167 // and set the code breakpoints.
2151 if (!bpt->IsResolved()) { 2168 if (!bpt->IsResolved()) {
2152 // Resolve source breakpoint in the newly compiled function. 2169 // Resolve source breakpoint in the newly compiled function.
2153 intptr_t bp_pos = ResolveBreakpointPos(func, bpt->token_pos()); 2170 intptr_t bp_pos =
2171 ResolveBreakpointPos(func, bpt->token_pos(), bpt->end_token_pos());
2154 if (bp_pos < 0) { 2172 if (bp_pos < 0) {
2155 if (FLAG_verbose_debug) { 2173 if (FLAG_verbose_debug) {
2156 OS::Print("Failed resolving breakpoint for function '%s'\n", 2174 OS::Print("Failed resolving breakpoint for function '%s'\n",
2157 String::Handle(func.name()).ToCString()); 2175 String::Handle(func.name()).ToCString());
2158 } 2176 }
2159 continue; 2177 continue;
2160 } 2178 }
2161 intptr_t requested_pos = bpt->token_pos(); 2179 intptr_t requested_pos = bpt->token_pos();
2162 bpt->SetResolved(func, bp_pos); 2180 bpt->SetResolved(func, bp_pos);
2163 if (FLAG_verbose_debug) { 2181 if (FLAG_verbose_debug) {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
2314 } 2332 }
2315 2333
2316 2334
2317 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { 2335 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
2318 ASSERT(bpt->next() == NULL); 2336 ASSERT(bpt->next() == NULL);
2319 bpt->set_next(code_breakpoints_); 2337 bpt->set_next(code_breakpoints_);
2320 code_breakpoints_ = bpt; 2338 code_breakpoints_ = bpt;
2321 } 2339 }
2322 2340
2323 } // namespace dart 2341 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/debugger.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698