| 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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 private: | 58 private: |
| 59 GrowableObjectArray* objs_; | 59 GrowableObjectArray* objs_; |
| 60 | 60 |
| 61 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); | 61 DISALLOW_COPY_AND_ASSIGN(RemoteObjectCache); |
| 62 }; | 62 }; |
| 63 | 63 |
| 64 | 64 |
| 65 // Create an unresolved breakpoint in given token range and script. | 65 // Create an unresolved breakpoint in given token range and script. |
| 66 BreakpointLocation::BreakpointLocation(const Script& script, | 66 BreakpointLocation::BreakpointLocation(const Script& script, |
| 67 intptr_t token_pos, | 67 intptr_t token_pos, |
| 68 intptr_t end_token_pos) | 68 intptr_t end_token_pos, |
| 69 intptr_t requested_line_number, |
| 70 intptr_t requested_column_number) |
| 69 : script_(script.raw()), | 71 : script_(script.raw()), |
| 70 url_(script.url()), | 72 url_(script.url()), |
| 71 token_pos_(token_pos), | 73 token_pos_(token_pos), |
| 72 end_token_pos_(end_token_pos), | 74 end_token_pos_(end_token_pos), |
| 73 is_resolved_(false), | 75 is_resolved_(false), |
| 74 next_(NULL), | 76 next_(NULL), |
| 75 conditions_(NULL), | 77 conditions_(NULL), |
| 78 requested_line_number_(requested_line_number), |
| 79 requested_column_number_(requested_column_number), |
| 76 function_(Function::null()), | 80 function_(Function::null()), |
| 77 line_number_(-1) { | 81 line_number_(-1), |
| 82 column_number_(-1) { |
| 78 ASSERT(!script.IsNull()); | 83 ASSERT(!script.IsNull()); |
| 79 ASSERT(token_pos_ >= 0); | 84 ASSERT(token_pos_ >= 0); |
| 80 } | 85 } |
| 81 | 86 |
| 82 // Create a latent breakpoint at given url and line number. | 87 // Create a latent breakpoint at given url and line number. |
| 83 BreakpointLocation::BreakpointLocation(const String& url, | 88 BreakpointLocation::BreakpointLocation(const String& url, |
| 84 intptr_t line_number) | 89 intptr_t requested_line_number, |
| 90 intptr_t requested_column_number) |
| 85 : script_(Script::null()), | 91 : script_(Script::null()), |
| 86 url_(url.raw()), | 92 url_(url.raw()), |
| 87 token_pos_(-1), | 93 token_pos_(-1), |
| 88 end_token_pos_(-1), | 94 end_token_pos_(-1), |
| 89 is_resolved_(false), | 95 is_resolved_(false), |
| 90 next_(NULL), | 96 next_(NULL), |
| 91 conditions_(NULL), | 97 conditions_(NULL), |
| 98 requested_line_number_(requested_line_number), |
| 99 requested_column_number_(requested_column_number), |
| 92 function_(Function::null()), | 100 function_(Function::null()), |
| 93 line_number_(line_number) { | 101 line_number_(-1), |
| 94 ASSERT(line_number_ >= 0); | 102 column_number_(-1) { |
| 103 ASSERT(requested_line_number_ >= 0); |
| 95 } | 104 } |
| 96 | 105 |
| 97 | 106 |
| 98 BreakpointLocation::~BreakpointLocation() { | 107 BreakpointLocation::~BreakpointLocation() { |
| 99 Breakpoint* bpt = breakpoints(); | 108 Breakpoint* bpt = breakpoints(); |
| 100 while (bpt != NULL) { | 109 while (bpt != NULL) { |
| 101 Breakpoint* temp = bpt; | 110 Breakpoint* temp = bpt; |
| 102 bpt = bpt->next(); | 111 bpt = bpt->next(); |
| 103 delete temp; | 112 delete temp; |
| 104 } | 113 } |
| 105 } | 114 } |
| 106 | 115 |
| 107 | 116 |
| 108 bool BreakpointLocation::AnyEnabled() const { | 117 bool BreakpointLocation::AnyEnabled() const { |
| 109 return breakpoints() != NULL; | 118 return breakpoints() != NULL; |
| 110 } | 119 } |
| 111 | 120 |
| 112 | 121 |
| 113 void BreakpointLocation::SetResolved(const Function& func, intptr_t token_pos) { | 122 void BreakpointLocation::SetResolved(const Function& func, intptr_t token_pos) { |
| 114 ASSERT(!IsLatent()); | 123 ASSERT(!IsLatent()); |
| 115 ASSERT(func.script() == script_); | 124 ASSERT(func.script() == script_); |
| 116 ASSERT((func.token_pos() <= token_pos) && | 125 ASSERT((func.token_pos() <= token_pos) && |
| 117 (token_pos <= func.end_token_pos())); | 126 (token_pos <= func.end_token_pos())); |
| 118 ASSERT(func.is_debuggable()); | 127 ASSERT(func.is_debuggable()); |
| 119 function_ = func.raw(); | 128 function_ = func.raw(); |
| 120 token_pos_ = token_pos; | 129 token_pos_ = token_pos; |
| 121 end_token_pos_ = token_pos; | 130 end_token_pos_ = token_pos; |
| 122 line_number_ = -1; // Recalculate lazily. | |
| 123 is_resolved_ = true; | 131 is_resolved_ = true; |
| 124 } | 132 } |
| 125 | 133 |
| 126 | 134 |
| 127 // TODO(hausner): Get rid of library parameter. A source breakpoint location | 135 // TODO(hausner): Get rid of library parameter. A source breakpoint location |
| 128 // does not imply a library, since the same source code can be included | 136 // does not imply a library, since the same source code can be included |
| 129 // in more than one library, e.g. the text location of mixin functions. | 137 // in more than one library, e.g. the text location of mixin functions. |
| 130 void BreakpointLocation::GetCodeLocation(Library* lib, | 138 void BreakpointLocation::GetCodeLocation(Library* lib, |
| 131 Script* script, | 139 Script* script, |
| 132 intptr_t* pos) { | 140 intptr_t* pos) const { |
| 133 if (IsLatent()) { | 141 if (IsLatent()) { |
| 134 *lib = Library::null(); | 142 *lib = Library::null(); |
| 135 *script = Script::null(); | 143 *script = Script::null(); |
| 136 *pos = -1; | 144 *pos = -1; |
| 137 } else { | 145 } else { |
| 138 *script = this->script(); | 146 *script = this->script(); |
| 139 *pos = token_pos_; | 147 *pos = token_pos_; |
| 140 if (IsResolved()) { | 148 if (IsResolved()) { |
| 141 const Function& func = Function::Handle(function_); | 149 const Function& func = Function::Handle(function_); |
| 142 ASSERT(!func.IsNull()); | 150 ASSERT(!func.IsNull()); |
| 143 const Class& cls = Class::Handle(func.origin()); | 151 const Class& cls = Class::Handle(func.origin()); |
| 144 *lib = cls.library(); | 152 *lib = cls.library(); |
| 145 } else { | 153 } else { |
| 146 *lib = Library::null(); | 154 *lib = Library::null(); |
| 147 } | 155 } |
| 148 } | 156 } |
| 149 } | 157 } |
| 150 | 158 |
| 151 | 159 |
| 152 intptr_t BreakpointLocation::LineNumber() { | 160 intptr_t BreakpointLocation::LineNumber() { |
| 153 // Latent breakpoints must have a requested line number >= 0. | 161 ASSERT(IsResolved()); |
| 154 ASSERT(!IsLatent() || line_number_ >= 0); | |
| 155 // Compute line number lazily since it causes scanning of the script. | 162 // Compute line number lazily since it causes scanning of the script. |
| 156 if (line_number_ < 0) { | 163 if (line_number_ < 0) { |
| 157 const Script& script = Script::Handle(this->script()); | 164 const Script& script = Script::Handle(this->script()); |
| 158 script.GetTokenLocation(token_pos_, &line_number_, NULL); | 165 script.GetTokenLocation(token_pos_, &line_number_, NULL); |
| 159 } | 166 } |
| 160 return line_number_; | 167 return line_number_; |
| 161 } | 168 } |
| 162 | 169 |
| 163 | 170 |
| 171 intptr_t BreakpointLocation::ColumnNumber() { |
| 172 ASSERT(IsResolved()); |
| 173 // Compute column number lazily since it causes scanning of the script. |
| 174 if (column_number_ < 0) { |
| 175 const Script& script = Script::Handle(this->script()); |
| 176 script.GetTokenLocation(token_pos_, &line_number_, &column_number_); |
| 177 } |
| 178 return column_number_; |
| 179 } |
| 180 |
| 181 |
| 164 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { | 182 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { |
| 165 ASSERT(bpt_location_->IsLatent()); // Only reason to move. | 183 ASSERT(bpt_location_->IsLatent()); // Only reason to move. |
| 166 bpt_location_ = new_bpt_location; | 184 bpt_location_ = new_bpt_location; |
| 167 } | 185 } |
| 168 | 186 |
| 169 | 187 |
| 170 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 188 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 171 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); | 189 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); |
| 172 } | 190 } |
| 173 | 191 |
| 174 | 192 |
| 175 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 193 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 176 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); | 194 visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_)); |
| 177 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); | 195 visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_)); |
| 178 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); | 196 visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_)); |
| 179 | 197 |
| 180 Breakpoint* bpt = conditions_; | 198 Breakpoint* bpt = conditions_; |
| 181 while (bpt != NULL) { | 199 while (bpt != NULL) { |
| 182 bpt -> VisitObjectPointers(visitor); | 200 bpt -> VisitObjectPointers(visitor); |
| 183 bpt = bpt->next(); | 201 bpt = bpt->next(); |
| 184 } | 202 } |
| 185 } | 203 } |
| 186 | 204 |
| 187 | 205 |
| 188 void Breakpoint::PrintJSON(JSONStream* stream) { | 206 void Breakpoint::PrintJSON(JSONStream* stream) { |
| 189 Isolate* isolate = Isolate::Current(); | |
| 190 | |
| 191 JSONObject jsobj(stream); | 207 JSONObject jsobj(stream); |
| 192 jsobj.AddProperty("type", "Breakpoint"); | 208 jsobj.AddProperty("type", "Breakpoint"); |
| 193 | 209 |
| 194 jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); | 210 jsobj.AddFixedServiceId("breakpoints/%" Pd "", id()); |
| 195 jsobj.AddProperty("breakpointNumber", id()); | 211 jsobj.AddProperty("breakpointNumber", id()); |
| 196 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); | 212 jsobj.AddProperty("resolved", bpt_location_->IsResolved()); |
| 197 | 213 if (bpt_location_->IsResolved()) { |
| 198 Library& library = Library::Handle(isolate); | 214 jsobj.AddLocation(bpt_location_); |
| 199 Script& script = Script::Handle(isolate); | 215 } else { |
| 200 intptr_t token_pos; | 216 jsobj.AddUnresolvedLocation(bpt_location_); |
| 201 bpt_location_->GetCodeLocation(&library, &script, &token_pos); | 217 } |
| 202 jsobj.AddLocation(script, token_pos); | |
| 203 } | 218 } |
| 204 | 219 |
| 205 | 220 |
| 206 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 221 void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 207 visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); | 222 visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_)); |
| 208 } | 223 } |
| 209 | 224 |
| 210 | 225 |
| 211 ActivationFrame::ActivationFrame( | 226 ActivationFrame::ActivationFrame( |
| 212 uword pc, | 227 uword pc, |
| (...skipping 1382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 intptr_t last_pos = pos; | 1610 intptr_t last_pos = pos; |
| 1596 while ((iter.CurrentTokenKind() != Token::kNEWLINE) && | 1611 while ((iter.CurrentTokenKind() != Token::kNEWLINE) && |
| 1597 (iter.CurrentTokenKind() != Token::kEOS)) { | 1612 (iter.CurrentTokenKind() != Token::kEOS)) { |
| 1598 last_pos = iter.CurrentPosition(); | 1613 last_pos = iter.CurrentPosition(); |
| 1599 iter.Advance(); | 1614 iter.Advance(); |
| 1600 } | 1615 } |
| 1601 return last_pos; | 1616 return last_pos; |
| 1602 } | 1617 } |
| 1603 | 1618 |
| 1604 | 1619 |
| 1605 // Given a function and a token range, return the best fit | 1620 // Returns the best fit token position for a breakpoint. |
| 1606 // token position to set a breakpoint. The best fit is the safe point | 1621 // |
| 1607 // in the line closest to the beginning of the token range, and within | 1622 // Takes a range of tokens [requested_token_pos, last_token_pos] and |
| 1608 // that line, the safe point with the lowest compiled code address. | 1623 // an optional column (requested_column). The range of tokens usually |
| 1624 // represents one line of the program text, but can represent a larger |
| 1625 // range on recursive calls. |
| 1626 // |
| 1627 // The best fit is found in two passes. |
| 1628 // |
| 1629 // The first pass finds a candidate token which: |
| 1630 // |
| 1631 // - is a safepoint, |
| 1632 // - has the lowest column number compatible with the requested column |
| 1633 // if a column has been specified, |
| 1634 // and: |
| 1635 // - has the lowest token position number which satisfies the above. |
| 1636 // |
| 1637 // When we consider a column number, we look for the closed token |
| 1638 // which intersects the desired column. For example: |
| 1639 // |
| 1640 // 1 2 3 |
| 1641 // 12345678901234567890 0 |
| 1642 // |
| 1643 // var x = function(function(y)); |
| 1644 // ^ |
| 1645 // |
| 1646 // If we request a breakpoint at column 14, the lowest column number |
| 1647 // compatible with that would for column 11 (beginning of the |
| 1648 // 'function' token) in the example above. |
| 1649 // |
| 1650 // Once this candidate token from the first pass is found, we then |
| 1651 // have a second pass which considers only those tokens on the same |
| 1652 // line as the candidate token. |
| 1653 // |
| 1654 // The second pass finds a best fit token which: |
| 1655 // |
| 1656 // - is a safepoint, |
| 1657 // - has the same column number as the candidate token (perhaps |
| 1658 // more than one token has the same column number), |
| 1659 // and: |
| 1660 // - has the lowest code address in the generated code. |
| 1661 // |
| 1662 // We prefer the lowest compiled code address, because this tends to |
| 1663 // select the first subexpression on a line. For example in a line |
| 1664 // with nested function calls f(g(x)), the call to g() will have a |
| 1665 // lower compiled code address than the call to f(). |
| 1666 // |
| 1667 // If no best fit token can be found, the search is expanded, |
| 1668 // searching through the rest of the current function by calling this |
| 1669 // function recursively. |
| 1670 // |
| 1671 // TODO(turnidge): Given that we usually call this function with a |
| 1672 // token range restricted to a single line, this could be a one-pass |
| 1673 // algorithm, which would be simpler. I believe that it only needs |
| 1674 // two passes to support the recursive try-the-whole-function case. |
| 1675 // Rewrite this later, once there are more tests in place. |
| 1609 intptr_t Debugger::ResolveBreakpointPos(const Function& func, | 1676 intptr_t Debugger::ResolveBreakpointPos(const Function& func, |
| 1610 intptr_t requested_token_pos, | 1677 intptr_t requested_token_pos, |
| 1611 intptr_t last_token_pos) { | 1678 intptr_t last_token_pos, |
| 1679 intptr_t requested_column) { |
| 1612 ASSERT(func.HasCode()); | 1680 ASSERT(func.HasCode()); |
| 1613 ASSERT(!func.HasOptimizedCode()); | 1681 ASSERT(!func.HasOptimizedCode()); |
| 1614 | 1682 |
| 1615 if (requested_token_pos < func.token_pos()) { | 1683 if (requested_token_pos < func.token_pos()) { |
| 1616 requested_token_pos = func.token_pos(); | 1684 requested_token_pos = func.token_pos(); |
| 1617 } | 1685 } |
| 1618 if (last_token_pos > func.end_token_pos()) { | 1686 if (last_token_pos > func.end_token_pos()) { |
| 1619 last_token_pos = func.end_token_pos(); | 1687 last_token_pos = func.end_token_pos(); |
| 1620 } | 1688 } |
| 1621 | 1689 |
| 1690 Script& script = Script::Handle(func.script()); |
| 1622 Code& code = Code::Handle(func.unoptimized_code()); | 1691 Code& code = Code::Handle(func.unoptimized_code()); |
| 1623 ASSERT(!code.IsNull()); | 1692 ASSERT(!code.IsNull()); |
| 1624 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1693 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 1625 | 1694 |
| 1626 // First pass: find the safe point which is closest to the beginning | 1695 // First pass: find the safe point which is closest to the beginning |
| 1627 // of the given token range. | 1696 // of the given token range. |
| 1628 intptr_t best_fit_pos = INT_MAX; | 1697 intptr_t best_fit_pos = INT_MAX; |
| 1698 intptr_t best_column = INT_MAX; |
| 1629 PcDescriptors::Iterator iter(desc, kSafepointKind); | 1699 PcDescriptors::Iterator iter(desc, kSafepointKind); |
| 1630 while (iter.MoveNext()) { | 1700 while (iter.MoveNext()) { |
| 1631 const intptr_t desc_token_pos = iter.TokenPos(); | 1701 const intptr_t pos = iter.TokenPos(); |
| 1632 if ((desc_token_pos != Scanner::kNoSourcePos) && | 1702 if ((pos == Scanner::kNoSourcePos) || |
| 1633 (desc_token_pos < best_fit_pos) && | 1703 (pos < requested_token_pos) || |
| 1634 (desc_token_pos >= requested_token_pos) && | 1704 (pos > last_token_pos)) { |
| 1635 (desc_token_pos <= last_token_pos)) { | 1705 // Token is not in the target range. |
| 1636 best_fit_pos = desc_token_pos; | 1706 continue; |
| 1707 } |
| 1708 |
| 1709 intptr_t token_start_column = -1; |
| 1710 if (requested_column >= 0) { |
| 1711 intptr_t ignored = -1; |
| 1712 intptr_t token_len = -1; |
| 1713 // TODO(turnidge): GetTokenLocation is a very expensive |
| 1714 // operation, and this code will blow up when we are setting |
| 1715 // column breakpoints on, for example, a large, single-line |
| 1716 // program. Consider rewriting this code so that it only scans |
| 1717 // the program code once and caches the token positions and |
| 1718 // lengths. |
| 1719 script.GetTokenLocation(pos, &ignored, &token_start_column, &token_len); |
| 1720 intptr_t token_end_column = token_start_column + token_len - 1; |
| 1721 if ((token_end_column < requested_column) || |
| 1722 (token_start_column > best_column)) { |
| 1723 // Prefer the token with the lowest column number compatible |
| 1724 // with the requested column. |
| 1725 continue; |
| 1726 } |
| 1727 } |
| 1728 |
| 1729 // Prefer the lowest (first) token pos. |
| 1730 if (pos < best_fit_pos) { |
| 1731 best_fit_pos = pos; |
| 1732 best_column = token_start_column; |
| 1637 } | 1733 } |
| 1638 } | 1734 } |
| 1639 // Second pass (if we found a safe point in the first pass): | 1735 |
| 1640 // For all token positions on the same line, select the one | 1736 // Second pass (if we found a safe point in the first pass). Find |
| 1641 // with the lowest compiled code address. E.g., in a line with | 1737 // the token on the line which is at the best fit column (if column |
| 1642 // the nested function calls f(g(x)), the call g() will have a lower | 1738 // was specified) and has the lowest code address. |
| 1643 // compiled code address but is not the lowest token position in the | |
| 1644 // line. | |
| 1645 if (best_fit_pos != INT_MAX) { | 1739 if (best_fit_pos != INT_MAX) { |
| 1646 const Script& script = Script::Handle(func.script()); | 1740 const Script& script = Script::Handle(func.script()); |
| 1647 const TokenStream& tokens = TokenStream::Handle(script.tokens()); | 1741 const TokenStream& tokens = TokenStream::Handle(script.tokens()); |
| 1648 const intptr_t begin_pos = best_fit_pos; | 1742 const intptr_t begin_pos = best_fit_pos; |
| 1649 const intptr_t end_of_line_pos = LastTokenOnLine(tokens, begin_pos); | 1743 const intptr_t end_of_line_pos = LastTokenOnLine(tokens, begin_pos); |
| 1650 uword lowest_pc_offset = kUwordMax; | 1744 uword lowest_pc_offset = kUwordMax; |
| 1651 PcDescriptors::Iterator iter(desc, kSafepointKind); | 1745 PcDescriptors::Iterator iter(desc, kSafepointKind); |
| 1652 while (iter.MoveNext()) { | 1746 while (iter.MoveNext()) { |
| 1653 const intptr_t pos = iter.TokenPos(); | 1747 const intptr_t pos = iter.TokenPos(); |
| 1654 if ((pos != Scanner::kNoSourcePos) && | 1748 if ((pos == Scanner::kNoSourcePos) || |
| 1655 (begin_pos <= pos) && (pos <= end_of_line_pos) && | 1749 (pos < begin_pos) || |
| 1656 (iter.PcOffset() < lowest_pc_offset)) { | 1750 (pos > end_of_line_pos)) { |
| 1751 // Token is not on same line as best fit. |
| 1752 continue; |
| 1753 } |
| 1754 |
| 1755 if (requested_column >= 0) { |
| 1756 intptr_t ignored = -1; |
| 1757 intptr_t token_start_column = -1; |
| 1758 // We look for other tokens at the best column in case there |
| 1759 // is more than one token at the same column offset. |
| 1760 script.GetTokenLocation(pos, &ignored, &token_start_column); |
| 1761 if (token_start_column != best_column) { |
| 1762 continue; |
| 1763 } |
| 1764 } |
| 1765 |
| 1766 // Prefer the lowest pc offset. |
| 1767 if (iter.PcOffset() < lowest_pc_offset) { |
| 1657 lowest_pc_offset = iter.PcOffset(); | 1768 lowest_pc_offset = iter.PcOffset(); |
| 1658 best_fit_pos = pos; | 1769 best_fit_pos = pos; |
| 1659 } | 1770 } |
| 1660 } | 1771 } |
| 1661 return best_fit_pos; | 1772 return best_fit_pos; |
| 1662 } | 1773 } |
| 1663 | 1774 |
| 1664 // We didn't find a safe point in the given token range. Try and find | 1775 // We didn't find a safe point in the given token range. Try and |
| 1665 // a safe point in the remaining source code of the function. | 1776 // find a safe point in the remaining source code of the function. |
| 1777 // Since we have moved to the next line of the function, we no |
| 1778 // longer are requesting a specific column number. |
| 1666 if (last_token_pos < func.end_token_pos()) { | 1779 if (last_token_pos < func.end_token_pos()) { |
| 1667 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos()); | 1780 return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(), |
| 1781 -1 /* no column */); |
| 1668 } | 1782 } |
| 1669 return -1; | 1783 return -1; |
| 1670 } | 1784 } |
| 1671 | 1785 |
| 1672 | 1786 |
| 1673 void Debugger::MakeCodeBreakpointAt(const Function& func, | 1787 void Debugger::MakeCodeBreakpointAt(const Function& func, |
| 1674 BreakpointLocation* loc) { | 1788 BreakpointLocation* loc) { |
| 1675 ASSERT(loc->token_pos_ != Scanner::kNoSourcePos); | 1789 ASSERT(loc->token_pos_ != Scanner::kNoSourcePos); |
| 1676 ASSERT((loc != NULL) && loc->IsResolved()); | 1790 ASSERT((loc != NULL) && loc->IsResolved()); |
| 1677 ASSERT(!func.HasOptimizedCode()); | 1791 ASSERT(!func.HasOptimizedCode()); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1850 } | 1964 } |
| 1851 } | 1965 } |
| 1852 } | 1966 } |
| 1853 } | 1967 } |
| 1854 return best_fit.raw(); | 1968 return best_fit.raw(); |
| 1855 } | 1969 } |
| 1856 | 1970 |
| 1857 | 1971 |
| 1858 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, | 1972 BreakpointLocation* Debugger::SetBreakpoint(const Script& script, |
| 1859 intptr_t token_pos, | 1973 intptr_t token_pos, |
| 1860 intptr_t last_token_pos) { | 1974 intptr_t last_token_pos, |
| 1975 intptr_t requested_line, |
| 1976 intptr_t requested_column) { |
| 1861 Function& func = Function::Handle(isolate_); | 1977 Function& func = Function::Handle(isolate_); |
| 1862 func = FindBestFit(script, token_pos); | 1978 func = FindBestFit(script, token_pos); |
| 1863 if (func.IsNull()) { | 1979 if (func.IsNull()) { |
| 1864 return NULL; | 1980 return NULL; |
| 1865 } | 1981 } |
| 1866 // There may be more than one function object for a given function | 1982 // There may be more than one function object for a given function |
| 1867 // in source code. There may be implicit closure functions, and | 1983 // in source code. There may be implicit closure functions, and |
| 1868 // there may be copies of mixin functions. Collect all compiled | 1984 // there may be copies of mixin functions. Collect all compiled |
| 1869 // functions whose source code range matches exactly the best fit | 1985 // functions whose source code range matches exactly the best fit |
| 1870 // function we found. | 1986 // function we found. |
| 1871 GrowableObjectArray& functions = | 1987 GrowableObjectArray& functions = |
| 1872 GrowableObjectArray::Handle(GrowableObjectArray::New()); | 1988 GrowableObjectArray::Handle(GrowableObjectArray::New()); |
| 1873 FindCompiledFunctions(script, | 1989 FindCompiledFunctions(script, |
| 1874 func.token_pos(), | 1990 func.token_pos(), |
| 1875 func.end_token_pos(), | 1991 func.end_token_pos(), |
| 1876 &functions); | 1992 &functions); |
| 1877 | 1993 |
| 1878 if (functions.Length() > 0) { | 1994 if (functions.Length() > 0) { |
| 1879 // One or more function object containing this breakpoint location | 1995 // One or more function object containing this breakpoint location |
| 1880 // have already been compiled. We can resolve the breakpoint now. | 1996 // have already been compiled. We can resolve the breakpoint now. |
| 1881 DeoptimizeWorld(); | 1997 DeoptimizeWorld(); |
| 1882 func ^= functions.At(0); | 1998 func ^= functions.At(0); |
| 1883 intptr_t breakpoint_pos = | 1999 intptr_t breakpoint_pos = |
| 1884 ResolveBreakpointPos(func, token_pos, last_token_pos); | 2000 ResolveBreakpointPos(func, token_pos, last_token_pos, requested_column); |
| 1885 if (breakpoint_pos >= 0) { | 2001 if (breakpoint_pos >= 0) { |
| 1886 BreakpointLocation* bpt = GetBreakpointLocation(script, breakpoint_pos); | 2002 BreakpointLocation* bpt = |
| 2003 GetBreakpointLocation(script, breakpoint_pos, requested_column); |
| 1887 if (bpt != NULL) { | 2004 if (bpt != NULL) { |
| 1888 // A source breakpoint for this location already exists. | 2005 // A source breakpoint for this location already exists. |
| 1889 return bpt; | 2006 return bpt; |
| 1890 } | 2007 } |
| 1891 bpt = new BreakpointLocation(script, token_pos, last_token_pos); | 2008 bpt = new BreakpointLocation(script, token_pos, last_token_pos, |
| 2009 requested_line, requested_column); |
| 1892 bpt->SetResolved(func, breakpoint_pos); | 2010 bpt->SetResolved(func, breakpoint_pos); |
| 1893 RegisterBreakpointLocation(bpt); | 2011 RegisterBreakpointLocation(bpt); |
| 1894 | 2012 |
| 1895 // Create code breakpoints for all compiled functions we found. | 2013 // Create code breakpoints for all compiled functions we found. |
| 1896 const intptr_t num_functions = functions.Length(); | 2014 const intptr_t num_functions = functions.Length(); |
| 1897 for (intptr_t i = 0; i < num_functions; i++) { | 2015 for (intptr_t i = 0; i < num_functions; i++) { |
| 1898 func ^= functions.At(i); | 2016 func ^= functions.At(i); |
| 1899 ASSERT(func.HasCode()); | 2017 ASSERT(func.HasCode()); |
| 1900 MakeCodeBreakpointAt(func, bpt); | 2018 MakeCodeBreakpointAt(func, bpt); |
| 1901 } | 2019 } |
| 1902 if (FLAG_verbose_debug) { | 2020 if (FLAG_verbose_debug) { |
| 1903 intptr_t line_number; | 2021 intptr_t line_number; |
| 1904 script.GetTokenLocation(breakpoint_pos, &line_number, NULL); | 2022 intptr_t column_number; |
| 2023 script.GetTokenLocation(breakpoint_pos, &line_number, &column_number); |
| 1905 OS::Print("Resolved BP for " | 2024 OS::Print("Resolved BP for " |
| 1906 "function '%s' at line %" Pd "\n", | 2025 "function '%s' at line %" Pd " col %" Pd "\n", |
| 1907 func.ToFullyQualifiedCString(), | 2026 func.ToFullyQualifiedCString(), |
| 1908 line_number); | 2027 line_number, column_number); |
| 1909 } | 2028 } |
| 1910 return bpt; | 2029 return bpt; |
| 1911 } | 2030 } |
| 1912 } | 2031 } |
| 1913 // There is no compiled function at this token position. | 2032 // There is no compiled function at this token position. |
| 1914 // Register an unresolved breakpoint. | 2033 // Register an unresolved breakpoint. |
| 1915 if (FLAG_verbose_debug && !func.IsNull()) { | 2034 if (FLAG_verbose_debug && !func.IsNull()) { |
| 1916 intptr_t line_number; | 2035 intptr_t line_number; |
| 1917 script.GetTokenLocation(token_pos, &line_number, NULL); | 2036 intptr_t column_number; |
| 2037 script.GetTokenLocation(token_pos, &line_number, &column_number); |
| 1918 OS::Print("Registering pending breakpoint for " | 2038 OS::Print("Registering pending breakpoint for " |
| 1919 "uncompiled function '%s' at line %" Pd "\n", | 2039 "uncompiled function '%s' at line %" Pd " col %" Pd "\n", |
| 1920 func.ToFullyQualifiedCString(), | 2040 func.ToFullyQualifiedCString(), |
| 1921 line_number); | 2041 line_number, column_number); |
| 1922 } | 2042 } |
| 1923 BreakpointLocation* bpt = GetBreakpointLocation(script, token_pos); | 2043 BreakpointLocation* bpt = |
| 2044 GetBreakpointLocation(script, token_pos, requested_column); |
| 1924 if (bpt == NULL) { | 2045 if (bpt == NULL) { |
| 1925 bpt = new BreakpointLocation(script, token_pos, last_token_pos); | 2046 bpt = new BreakpointLocation(script, token_pos, last_token_pos, |
| 2047 requested_line, requested_column); |
| 1926 RegisterBreakpointLocation(bpt); | 2048 RegisterBreakpointLocation(bpt); |
| 1927 } | 2049 } |
| 1928 return bpt; | 2050 return bpt; |
| 1929 } | 2051 } |
| 1930 | 2052 |
| 1931 | 2053 |
| 1932 // Synchronize the enabled/disabled state of all code breakpoints | 2054 // Synchronize the enabled/disabled state of all code breakpoints |
| 1933 // associated with the breakpoint location loc. | 2055 // associated with the breakpoint location loc. |
| 1934 void Debugger::SyncBreakpointLocation(BreakpointLocation* loc) { | 2056 void Debugger::SyncBreakpointLocation(BreakpointLocation* loc) { |
| 1935 bool any_enabled = loc->AnyEnabled(); | 2057 bool any_enabled = loc->AnyEnabled(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1962 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, | 2084 Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function, |
| 1963 bool single_shot) { | 2085 bool single_shot) { |
| 1964 ASSERT(!target_function.IsNull()); | 2086 ASSERT(!target_function.IsNull()); |
| 1965 if (!target_function.is_debuggable()) { | 2087 if (!target_function.is_debuggable()) { |
| 1966 return NULL; | 2088 return NULL; |
| 1967 } | 2089 } |
| 1968 const Script& script = Script::Handle(target_function.script()); | 2090 const Script& script = Script::Handle(target_function.script()); |
| 1969 BreakpointLocation* bpt_location = | 2091 BreakpointLocation* bpt_location = |
| 1970 SetBreakpoint(script, | 2092 SetBreakpoint(script, |
| 1971 target_function.token_pos(), | 2093 target_function.token_pos(), |
| 1972 target_function.end_token_pos()); | 2094 target_function.end_token_pos(), |
| 2095 -1, -1 /* no requested line/col */); |
| 1973 if (single_shot) { | 2096 if (single_shot) { |
| 1974 return bpt_location->AddSingleShot(this); | 2097 return bpt_location->AddSingleShot(this); |
| 1975 } else { | 2098 } else { |
| 1976 return bpt_location->AddRepeated(this); | 2099 return bpt_location->AddRepeated(this); |
| 1977 } | 2100 } |
| 1978 } | 2101 } |
| 1979 | 2102 |
| 1980 | 2103 |
| 1981 Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) { | 2104 Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) { |
| 1982 if (!closure.IsClosure()) { | 2105 if (!closure.IsClosure()) { |
| 1983 return NULL; | 2106 return NULL; |
| 1984 } | 2107 } |
| 1985 const Function& func = Function::Handle(Closure::function(closure)); | 2108 const Function& func = Function::Handle(Closure::function(closure)); |
| 1986 const Script& script = Script::Handle(func.script()); | 2109 const Script& script = Script::Handle(func.script()); |
| 1987 BreakpointLocation* bpt_location = SetBreakpoint(script, | 2110 BreakpointLocation* bpt_location = SetBreakpoint(script, |
| 1988 func.token_pos(), | 2111 func.token_pos(), |
| 1989 func.end_token_pos()); | 2112 func.end_token_pos(), |
| 2113 -1, -1 /* no line/col */); |
| 1990 return bpt_location->AddPerClosure(this, closure); | 2114 return bpt_location->AddPerClosure(this, closure); |
| 1991 } | 2115 } |
| 1992 | 2116 |
| 1993 | 2117 |
| 1994 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) { | 2118 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) { |
| 1995 if (!closure.IsClosure()) { | 2119 if (!closure.IsClosure()) { |
| 1996 return NULL; | 2120 return NULL; |
| 1997 } | 2121 } |
| 1998 | 2122 |
| 1999 BreakpointLocation* loc = breakpoint_locations_; | 2123 BreakpointLocation* loc = breakpoint_locations_; |
| 2000 while (loc != NULL) { | 2124 while (loc != NULL) { |
| 2001 Breakpoint* bpt = loc->breakpoints(); | 2125 Breakpoint* bpt = loc->breakpoints(); |
| 2002 while (bpt != NULL) { | 2126 while (bpt != NULL) { |
| 2003 if (bpt->IsPerClosure()) { | 2127 if (bpt->IsPerClosure()) { |
| 2004 if (closure.raw() == bpt->closure()) { | 2128 if (closure.raw() == bpt->closure()) { |
| 2005 return bpt; | 2129 return bpt; |
| 2006 } | 2130 } |
| 2007 } | 2131 } |
| 2008 bpt = bpt->next(); | 2132 bpt = bpt->next(); |
| 2009 } | 2133 } |
| 2010 loc = loc->next(); | 2134 loc = loc->next(); |
| 2011 } | 2135 } |
| 2012 | 2136 |
| 2013 return NULL; | 2137 return NULL; |
| 2014 } | 2138 } |
| 2015 | 2139 |
| 2016 | 2140 |
| 2017 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 2141 Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 2018 intptr_t line_number) { | 2142 intptr_t line_number) { |
| 2019 BreakpointLocation* loc = BreakpointLocationAtLine(script_url, line_number); | 2143 BreakpointLocation* loc = |
| 2144 BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */); |
| 2020 if (loc != NULL) { | 2145 if (loc != NULL) { |
| 2021 return loc->AddRepeated(this); | 2146 return loc->AddRepeated(this); |
| 2022 } | 2147 } |
| 2148 return NULL; |
| 2149 } |
| 2150 |
| 2151 |
| 2152 Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url, |
| 2153 intptr_t line_number, |
| 2154 intptr_t column_number) { |
| 2155 BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url, |
| 2156 line_number, |
| 2157 column_number); |
| 2158 if (loc != NULL) { |
| 2159 return loc->AddRepeated(this); |
| 2160 } |
| 2023 return NULL; | 2161 return NULL; |
| 2024 } | 2162 } |
| 2025 | 2163 |
| 2026 | 2164 |
| 2027 BreakpointLocation* Debugger::BreakpointLocationAtLine(const String& script_url, | 2165 BreakpointLocation* Debugger::BreakpointLocationAtLineCol( |
| 2028 intptr_t line_number) { | 2166 const String& script_url, |
| 2167 intptr_t line_number, |
| 2168 intptr_t column_number) { |
| 2029 Library& lib = Library::Handle(isolate_); | 2169 Library& lib = Library::Handle(isolate_); |
| 2030 Script& script = Script::Handle(isolate_); | 2170 Script& script = Script::Handle(isolate_); |
| 2031 const GrowableObjectArray& libs = | 2171 const GrowableObjectArray& libs = |
| 2032 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 2172 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 2033 const GrowableObjectArray& scripts = | 2173 const GrowableObjectArray& scripts = |
| 2034 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); | 2174 GrowableObjectArray::Handle(isolate_, GrowableObjectArray::New()); |
| 2035 for (intptr_t i = 0; i < libs.Length(); i++) { | 2175 for (intptr_t i = 0; i < libs.Length(); i++) { |
| 2036 lib ^= libs.At(i); | 2176 lib ^= libs.At(i); |
| 2037 script = lib.LookupScript(script_url); | 2177 script = lib.LookupScript(script_url); |
| 2038 if (!script.IsNull()) { | 2178 if (!script.IsNull()) { |
| 2039 scripts.Add(script); | 2179 scripts.Add(script); |
| 2040 } | 2180 } |
| 2041 } | 2181 } |
| 2042 if (scripts.Length() == 0) { | 2182 if (scripts.Length() == 0) { |
| 2043 // No script found with given url. Create a latent breakpoint which | 2183 // No script found with given url. Create a latent breakpoint which |
| 2044 // will be set if the url is loaded later. | 2184 // will be set if the url is loaded later. |
| 2045 BreakpointLocation* latent_bpt = GetLatentBreakpoint(script_url, | 2185 BreakpointLocation* latent_bpt = GetLatentBreakpoint(script_url, |
| 2046 line_number); | 2186 line_number, |
| 2187 column_number); |
| 2047 if (FLAG_verbose_debug) { | 2188 if (FLAG_verbose_debug) { |
| 2048 OS::Print("Set latent breakpoint in url '%s' at line %" Pd "\n", | 2189 OS::Print("Set latent breakpoint in url '%s' at " |
| 2190 "line %" Pd " col %" Pd "\n", |
| 2049 script_url.ToCString(), | 2191 script_url.ToCString(), |
| 2050 line_number); | 2192 line_number, column_number); |
| 2051 } | 2193 } |
| 2052 return latent_bpt; | 2194 return latent_bpt; |
| 2053 } | 2195 } |
| 2054 if (scripts.Length() > 1) { | 2196 if (scripts.Length() > 1) { |
| 2055 if (FLAG_verbose_debug) { | 2197 if (FLAG_verbose_debug) { |
| 2056 OS::Print("Multiple scripts match url '%s'\n", script_url.ToCString()); | 2198 OS::Print("Multiple scripts match url '%s'\n", script_url.ToCString()); |
| 2057 } | 2199 } |
| 2058 return NULL; | 2200 return NULL; |
| 2059 } | 2201 } |
| 2060 script ^= scripts.At(0); | 2202 script ^= scripts.At(0); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2072 if (FLAG_verbose_debug) { | 2214 if (FLAG_verbose_debug) { |
| 2073 OS::Print("No executable code at line %" Pd " in '%s'\n", | 2215 OS::Print("No executable code at line %" Pd " in '%s'\n", |
| 2074 line_number, script_url.ToCString()); | 2216 line_number, script_url.ToCString()); |
| 2075 } | 2217 } |
| 2076 return NULL; | 2218 return NULL; |
| 2077 } | 2219 } |
| 2078 | 2220 |
| 2079 BreakpointLocation* bpt = NULL; | 2221 BreakpointLocation* bpt = NULL; |
| 2080 ASSERT(first_token_idx <= last_token_idx); | 2222 ASSERT(first_token_idx <= last_token_idx); |
| 2081 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) { | 2223 while ((bpt == NULL) && (first_token_idx <= last_token_idx)) { |
| 2082 bpt = SetBreakpoint(script, first_token_idx, last_token_idx); | 2224 bpt = SetBreakpoint(script, first_token_idx, last_token_idx, |
| 2225 line_number, column_number); |
| 2083 first_token_idx++; | 2226 first_token_idx++; |
| 2084 } | 2227 } |
| 2085 if ((bpt == NULL) && FLAG_verbose_debug) { | 2228 if ((bpt == NULL) && FLAG_verbose_debug) { |
| 2086 OS::Print("No executable code at line %" Pd " in '%s'\n", | 2229 OS::Print("No executable code at line %" Pd " in '%s'\n", |
| 2087 line_number, script_url.ToCString()); | 2230 line_number, script_url.ToCString()); |
| 2088 } | 2231 } |
| 2089 return bpt; | 2232 return bpt; |
| 2090 } | 2233 } |
| 2091 | 2234 |
| 2092 | 2235 |
| (...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2673 // TODO(hausner): What should we do if function is optimized? | 2816 // TODO(hausner): What should we do if function is optimized? |
| 2674 // Can we deoptimize the function? | 2817 // Can we deoptimize the function? |
| 2675 ASSERT(!func.HasOptimizedCode()); | 2818 ASSERT(!func.HasOptimizedCode()); |
| 2676 | 2819 |
| 2677 // There is no local function within func that contains the | 2820 // There is no local function within func that contains the |
| 2678 // breakpoint token position. Resolve the breakpoint if necessary | 2821 // breakpoint token position. Resolve the breakpoint if necessary |
| 2679 // and set the code breakpoints. | 2822 // and set the code breakpoints. |
| 2680 if (!loc->IsResolved()) { | 2823 if (!loc->IsResolved()) { |
| 2681 // Resolve source breakpoint in the newly compiled function. | 2824 // Resolve source breakpoint in the newly compiled function. |
| 2682 intptr_t bp_pos = | 2825 intptr_t bp_pos = |
| 2683 ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos()); | 2826 ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos(), |
| 2827 loc->requested_column_number()); |
| 2684 if (bp_pos < 0) { | 2828 if (bp_pos < 0) { |
| 2685 if (FLAG_verbose_debug) { | 2829 if (FLAG_verbose_debug) { |
| 2686 OS::Print("Failed resolving breakpoint for function '%s'\n", | 2830 OS::Print("Failed resolving breakpoint for function '%s'\n", |
| 2687 String::Handle(func.name()).ToCString()); | 2831 String::Handle(func.name()).ToCString()); |
| 2688 } | 2832 } |
| 2689 continue; | 2833 continue; |
| 2690 } | 2834 } |
| 2691 intptr_t requested_pos = loc->token_pos(); | 2835 intptr_t requested_pos = loc->token_pos(); |
| 2692 intptr_t requested_end_pos = loc->end_token_pos(); | 2836 intptr_t requested_end_pos = loc->end_token_pos(); |
| 2693 loc->SetResolved(func, bp_pos); | 2837 loc->SetResolved(func, bp_pos); |
| 2694 Breakpoint* bpt = loc->breakpoints(); | 2838 Breakpoint* bpt = loc->breakpoints(); |
| 2695 while (bpt != NULL) { | 2839 while (bpt != NULL) { |
| 2696 if (FLAG_verbose_debug) { | 2840 if (FLAG_verbose_debug) { |
| 2697 OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", " | 2841 OS::Print("Resolved BP %" Pd " to pos %" Pd ", " |
| 2698 "function '%s' (requested range %" Pd "-%" Pd ")\n", | 2842 "line %" Pd " col %" Pd ", " |
| 2843 "function '%s' (requested range %" Pd "-%" Pd ", " |
| 2844 "requested col %" Pd ")\n", |
| 2699 bpt->id(), | 2845 bpt->id(), |
| 2700 loc->token_pos(), | 2846 loc->token_pos(), |
| 2701 loc->LineNumber(), | 2847 loc->LineNumber(), |
| 2848 loc->ColumnNumber(), |
| 2702 func.ToFullyQualifiedCString(), | 2849 func.ToFullyQualifiedCString(), |
| 2703 requested_pos, | 2850 requested_pos, |
| 2704 requested_end_pos); | 2851 requested_end_pos, |
| 2852 loc->requested_column_number()); |
| 2705 } | 2853 } |
| 2706 SignalBpResolved(bpt); | 2854 SignalBpResolved(bpt); |
| 2707 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); | 2855 SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt); |
| 2708 bpt = bpt->next(); | 2856 bpt = bpt->next(); |
| 2709 } | 2857 } |
| 2710 } | 2858 } |
| 2711 ASSERT(loc->IsResolved()); | 2859 ASSERT(loc->IsResolved()); |
| 2712 if (FLAG_verbose_debug) { | 2860 if (FLAG_verbose_debug) { |
| 2713 Breakpoint* bpt = loc->breakpoints(); | 2861 Breakpoint* bpt = loc->breakpoints(); |
| 2714 while (bpt != NULL) { | 2862 while (bpt != NULL) { |
| 2715 OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n", | 2863 OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd "" |
| 2864 " for %s '%s'\n", |
| 2716 bpt->id(), | 2865 bpt->id(), |
| 2717 loc->LineNumber(), | 2866 loc->LineNumber(), |
| 2867 loc->ColumnNumber(), |
| 2718 func.IsClosureFunction() ? "closure" : "function", | 2868 func.IsClosureFunction() ? "closure" : "function", |
| 2719 String::Handle(func.name()).ToCString()); | 2869 String::Handle(func.name()).ToCString()); |
| 2720 bpt = bpt->next(); | 2870 bpt = bpt->next(); |
| 2721 } | 2871 } |
| 2722 } | 2872 } |
| 2723 MakeCodeBreakpointAt(func, loc); | 2873 MakeCodeBreakpointAt(func, loc); |
| 2724 } | 2874 } |
| 2725 } | 2875 } |
| 2726 } | 2876 } |
| 2727 | 2877 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2750 found_match = true; | 2900 found_match = true; |
| 2751 BreakpointLocation* matched_loc = loc; | 2901 BreakpointLocation* matched_loc = loc; |
| 2752 loc = loc->next(); | 2902 loc = loc->next(); |
| 2753 if (prev_loc == NULL) { | 2903 if (prev_loc == NULL) { |
| 2754 latent_locations_ = loc; | 2904 latent_locations_ = loc; |
| 2755 } else { | 2905 } else { |
| 2756 prev_loc->set_next(loc); | 2906 prev_loc->set_next(loc); |
| 2757 } | 2907 } |
| 2758 // Now find the token range at the requested line and make a | 2908 // Now find the token range at the requested line and make a |
| 2759 // new unresolved source breakpoint. | 2909 // new unresolved source breakpoint. |
| 2760 intptr_t line_number = matched_loc->LineNumber(); | 2910 intptr_t line_number = matched_loc->requested_line_number(); |
| 2911 intptr_t column_number = matched_loc->requested_column_number(); |
| 2761 ASSERT(line_number >= 0); | 2912 ASSERT(line_number >= 0); |
| 2762 intptr_t first_token_pos, last_token_pos; | 2913 intptr_t first_token_pos, last_token_pos; |
| 2763 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); | 2914 script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos); |
| 2764 if ((first_token_pos < 0) || | 2915 if ((first_token_pos < 0) || |
| 2765 (last_token_pos < 0)) { | 2916 (last_token_pos < 0)) { |
| 2766 // Script does not contain the given line number or there are no | 2917 // Script does not contain the given line number or there are no |
| 2767 // tokens on the line. Drop the breakpoint silently. | 2918 // tokens on the line. Drop the breakpoint silently. |
| 2768 Breakpoint* bpt = matched_loc->breakpoints(); | 2919 Breakpoint* bpt = matched_loc->breakpoints(); |
| 2769 while (bpt != NULL) { | 2920 while (bpt != NULL) { |
| 2770 if (FLAG_verbose_debug) { | 2921 if (FLAG_verbose_debug) { |
| 2771 OS::Print("No code found at line %" Pd ": " | 2922 OS::Print("No code found at line %" Pd ": " |
| 2772 "dropping latent breakpoint %" Pd " in '%s'\n", | 2923 "dropping latent breakpoint %" Pd " in '%s'\n", |
| 2773 line_number, | 2924 line_number, |
| 2774 bpt->id(), | 2925 bpt->id(), |
| 2775 url.ToCString()); | 2926 url.ToCString()); |
| 2776 } | 2927 } |
| 2777 Breakpoint* prev = bpt; | 2928 Breakpoint* prev = bpt; |
| 2778 bpt = bpt->next(); | 2929 bpt = bpt->next(); |
| 2779 delete prev; | 2930 delete prev; |
| 2780 } | 2931 } |
| 2781 delete matched_loc; | 2932 delete matched_loc; |
| 2782 } else { | 2933 } else { |
| 2783 // We don't expect to already have a breakpoint for this location. | 2934 // We don't expect to already have a breakpoint for this location. |
| 2784 // If there is one, assert in debug build but silently drop | 2935 // If there is one, assert in debug build but silently drop |
| 2785 // the latent breakpoint in release build. | 2936 // the latent breakpoint in release build. |
| 2786 BreakpointLocation* existing_loc = | 2937 BreakpointLocation* existing_loc = |
| 2787 GetBreakpointLocation(script, first_token_pos); | 2938 GetBreakpointLocation(script, first_token_pos, column_number); |
| 2788 ASSERT(existing_loc == NULL); | 2939 ASSERT(existing_loc == NULL); |
| 2789 if (existing_loc == NULL) { | 2940 if (existing_loc == NULL) { |
| 2790 // Create and register a new source breakpoint for the | 2941 // Create and register a new source breakpoint for the |
| 2791 // latent breakpoint. | 2942 // latent breakpoint. |
| 2792 BreakpointLocation* unresolved_loc = | 2943 BreakpointLocation* unresolved_loc = |
| 2793 new BreakpointLocation(script, | 2944 new BreakpointLocation(script, |
| 2794 first_token_pos, | 2945 first_token_pos, last_token_pos, |
| 2795 last_token_pos); | 2946 line_number, column_number); |
| 2796 RegisterBreakpointLocation(unresolved_loc); | 2947 RegisterBreakpointLocation(unresolved_loc); |
| 2797 | 2948 |
| 2798 // Move breakpoints over. | 2949 // Move breakpoints over. |
| 2799 Breakpoint* bpt = matched_loc->breakpoints(); | 2950 Breakpoint* bpt = matched_loc->breakpoints(); |
| 2800 unresolved_loc->set_breakpoints(bpt); | 2951 unresolved_loc->set_breakpoints(bpt); |
| 2801 matched_loc->set_breakpoints(NULL); | 2952 matched_loc->set_breakpoints(NULL); |
| 2802 while (bpt != NULL) { | 2953 while (bpt != NULL) { |
| 2803 bpt->set_bpt_location(unresolved_loc); | 2954 bpt->set_bpt_location(unresolved_loc); |
| 2804 if (FLAG_verbose_debug) { | 2955 if (FLAG_verbose_debug) { |
| 2805 OS::Print("Converted latent breakpoint " | 2956 OS::Print("Converted latent breakpoint " |
| 2806 "%" Pd " in '%s' at line %" Pd "\n", | 2957 "%" Pd " in '%s' at line %" Pd " col %" Pd "\n", |
| 2807 bpt->id(), | 2958 bpt->id(), |
| 2808 url.ToCString(), | 2959 url.ToCString(), |
| 2809 line_number); | 2960 line_number, column_number); |
| 2810 } | 2961 } |
| 2811 bpt = bpt->next(); | 2962 bpt = bpt->next(); |
| 2812 } | 2963 } |
| 2813 SyncBreakpointLocation(unresolved_loc); | 2964 SyncBreakpointLocation(unresolved_loc); |
| 2814 } | 2965 } |
| 2815 delete matched_loc; | 2966 delete matched_loc; |
| 2816 // Break out of the iteration over loaded libraries. If the | 2967 // Break out of the iteration over loaded libraries. If the |
| 2817 // same url has been loaded into more than one library, we | 2968 // same url has been loaded into more than one library, we |
| 2818 // only set a breakpoint in the first one. | 2969 // only set a breakpoint in the first one. |
| 2819 // TODO(hausner): There is one possible pitfall here. | 2970 // TODO(hausner): There is one possible pitfall here. |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2963 delete temp_bpt; | 3114 delete temp_bpt; |
| 2964 } else { | 3115 } else { |
| 2965 prev_bpt = curr_bpt; | 3116 prev_bpt = curr_bpt; |
| 2966 curr_bpt = curr_bpt->next(); | 3117 curr_bpt = curr_bpt->next(); |
| 2967 } | 3118 } |
| 2968 } | 3119 } |
| 2969 } | 3120 } |
| 2970 | 3121 |
| 2971 | 3122 |
| 2972 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, | 3123 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, |
| 2973 intptr_t token_pos) { | 3124 intptr_t token_pos, |
| 3125 intptr_t requested_column) { |
| 2974 BreakpointLocation* bpt = breakpoint_locations_; | 3126 BreakpointLocation* bpt = breakpoint_locations_; |
| 2975 while (bpt != NULL) { | 3127 while (bpt != NULL) { |
| 2976 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) { | 3128 if ((bpt->script_ == script.raw()) && |
| 3129 (bpt->token_pos_ == token_pos) && |
| 3130 (bpt->requested_column_number_ == requested_column)) { |
| 2977 return bpt; | 3131 return bpt; |
| 2978 } | 3132 } |
| 2979 bpt = bpt->next(); | 3133 bpt = bpt->next(); |
| 2980 } | 3134 } |
| 2981 return NULL; | 3135 return NULL; |
| 2982 } | 3136 } |
| 2983 | 3137 |
| 2984 | 3138 |
| 2985 Breakpoint* Debugger::GetBreakpointById(intptr_t id) { | 3139 Breakpoint* Debugger::GetBreakpointById(intptr_t id) { |
| 2986 BreakpointLocation* loc = breakpoint_locations_; | 3140 BreakpointLocation* loc = breakpoint_locations_; |
| 2987 while (loc != NULL) { | 3141 while (loc != NULL) { |
| 2988 Breakpoint* bpt = loc->breakpoints(); | 3142 Breakpoint* bpt = loc->breakpoints(); |
| 2989 while (bpt != NULL) { | 3143 while (bpt != NULL) { |
| 2990 if (bpt->id() == id) { | 3144 if (bpt->id() == id) { |
| 2991 return bpt; | 3145 return bpt; |
| 2992 } | 3146 } |
| 2993 bpt = bpt->next(); | 3147 bpt = bpt->next(); |
| 2994 } | 3148 } |
| 2995 loc = loc->next(); | 3149 loc = loc->next(); |
| 2996 } | 3150 } |
| 2997 return NULL; | 3151 return NULL; |
| 2998 } | 3152 } |
| 2999 | 3153 |
| 3000 | 3154 |
| 3001 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, | 3155 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, |
| 3002 intptr_t line) { | 3156 intptr_t line, |
| 3157 intptr_t column) { |
| 3003 BreakpointLocation* bpt = latent_locations_; | 3158 BreakpointLocation* bpt = latent_locations_; |
| 3004 String& bpt_url = String::Handle(isolate_); | 3159 String& bpt_url = String::Handle(isolate_); |
| 3005 while (bpt != NULL) { | 3160 while (bpt != NULL) { |
| 3006 bpt_url = bpt->url(); | 3161 bpt_url = bpt->url(); |
| 3007 if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) { | 3162 if (bpt_url.Equals(url) && |
| 3163 (bpt->requested_line_number() == line) && |
| 3164 (bpt->requested_column_number() == column)) { |
| 3008 return bpt; | 3165 return bpt; |
| 3009 } | 3166 } |
| 3010 bpt = bpt->next(); | 3167 bpt = bpt->next(); |
| 3011 } | 3168 } |
| 3012 // No breakpint for this url and line requested. Allocate new one. | 3169 // No breakpoint for this location requested. Allocate new one. |
| 3013 bpt = new BreakpointLocation(url, line); | 3170 bpt = new BreakpointLocation(url, line, column); |
| 3014 bpt->set_next(latent_locations_); | 3171 bpt->set_next(latent_locations_); |
| 3015 latent_locations_ = bpt; | 3172 latent_locations_ = bpt; |
| 3016 return bpt; | 3173 return bpt; |
| 3017 } | 3174 } |
| 3018 | 3175 |
| 3019 | 3176 |
| 3020 void Debugger::RegisterBreakpointLocation(BreakpointLocation* bpt) { | 3177 void Debugger::RegisterBreakpointLocation(BreakpointLocation* bpt) { |
| 3021 ASSERT(bpt->next() == NULL); | 3178 ASSERT(bpt->next() == NULL); |
| 3022 bpt->set_next(breakpoint_locations_); | 3179 bpt->set_next(breakpoint_locations_); |
| 3023 breakpoint_locations_ = bpt; | 3180 breakpoint_locations_ = bpt; |
| 3024 } | 3181 } |
| 3025 | 3182 |
| 3026 | 3183 |
| 3027 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3184 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 3028 ASSERT(bpt->next() == NULL); | 3185 ASSERT(bpt->next() == NULL); |
| 3029 bpt->set_next(code_breakpoints_); | 3186 bpt->set_next(code_breakpoints_); |
| 3030 code_breakpoints_ = bpt; | 3187 code_breakpoints_ = bpt; |
| 3031 } | 3188 } |
| 3032 | 3189 |
| 3033 } // namespace dart | 3190 } // namespace dart |
| OLD | NEW |