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

Unified Diff: runtime/vm/debugger.cc

Issue 1312763010: Support column-based breakpoints in the VM and Observatory. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: hausner review Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/debugger_api_impl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/debugger.cc
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 96966d92ae1c690d3c5604c088c7a414dd6ea5cf..6c0a2d069274e26e82b17c12807065496abd41e4 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -65,7 +65,9 @@ class RemoteObjectCache : public ZoneAllocated {
// Create an unresolved breakpoint in given token range and script.
BreakpointLocation::BreakpointLocation(const Script& script,
intptr_t token_pos,
- intptr_t end_token_pos)
+ intptr_t end_token_pos,
+ intptr_t requested_line_number,
+ intptr_t requested_column_number)
: script_(script.raw()),
url_(script.url()),
token_pos_(token_pos),
@@ -73,15 +75,19 @@ BreakpointLocation::BreakpointLocation(const Script& script,
is_resolved_(false),
next_(NULL),
conditions_(NULL),
+ requested_line_number_(requested_line_number),
+ requested_column_number_(requested_column_number),
function_(Function::null()),
- line_number_(-1) {
+ line_number_(-1),
+ column_number_(-1) {
ASSERT(!script.IsNull());
ASSERT(token_pos_ >= 0);
}
// Create a latent breakpoint at given url and line number.
BreakpointLocation::BreakpointLocation(const String& url,
- intptr_t line_number)
+ intptr_t requested_line_number,
+ intptr_t requested_column_number)
: script_(Script::null()),
url_(url.raw()),
token_pos_(-1),
@@ -89,9 +95,12 @@ BreakpointLocation::BreakpointLocation(const String& url,
is_resolved_(false),
next_(NULL),
conditions_(NULL),
+ requested_line_number_(requested_line_number),
+ requested_column_number_(requested_column_number),
function_(Function::null()),
- line_number_(line_number) {
- ASSERT(line_number_ >= 0);
+ line_number_(-1),
+ column_number_(-1) {
+ ASSERT(requested_line_number_ >= 0);
}
@@ -119,7 +128,6 @@ void BreakpointLocation::SetResolved(const Function& func, intptr_t token_pos) {
function_ = func.raw();
token_pos_ = token_pos;
end_token_pos_ = token_pos;
- line_number_ = -1; // Recalculate lazily.
is_resolved_ = true;
}
@@ -129,7 +137,7 @@ void BreakpointLocation::SetResolved(const Function& func, intptr_t token_pos) {
// in more than one library, e.g. the text location of mixin functions.
void BreakpointLocation::GetCodeLocation(Library* lib,
Script* script,
- intptr_t* pos) {
+ intptr_t* pos) const {
if (IsLatent()) {
*lib = Library::null();
*script = Script::null();
@@ -150,8 +158,7 @@ void BreakpointLocation::GetCodeLocation(Library* lib,
intptr_t BreakpointLocation::LineNumber() {
- // Latent breakpoints must have a requested line number >= 0.
- ASSERT(!IsLatent() || line_number_ >= 0);
+ ASSERT(IsResolved());
// Compute line number lazily since it causes scanning of the script.
if (line_number_ < 0) {
const Script& script = Script::Handle(this->script());
@@ -161,6 +168,17 @@ intptr_t BreakpointLocation::LineNumber() {
}
+intptr_t BreakpointLocation::ColumnNumber() {
+ ASSERT(IsResolved());
+ // Compute column number lazily since it causes scanning of the script.
+ if (column_number_ < 0) {
+ const Script& script = Script::Handle(this->script());
+ script.GetTokenLocation(token_pos_, &line_number_, &column_number_);
+ }
+ return column_number_;
+}
+
+
void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) {
ASSERT(bpt_location_->IsLatent()); // Only reason to move.
bpt_location_ = new_bpt_location;
@@ -186,20 +204,17 @@ void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) {
void Breakpoint::PrintJSON(JSONStream* stream) {
- Isolate* isolate = Isolate::Current();
-
JSONObject jsobj(stream);
jsobj.AddProperty("type", "Breakpoint");
jsobj.AddFixedServiceId("breakpoints/%" Pd "", id());
jsobj.AddProperty("breakpointNumber", id());
jsobj.AddProperty("resolved", bpt_location_->IsResolved());
-
- Library& library = Library::Handle(isolate);
- Script& script = Script::Handle(isolate);
- intptr_t token_pos;
- bpt_location_->GetCodeLocation(&library, &script, &token_pos);
- jsobj.AddLocation(script, token_pos);
+ if (bpt_location_->IsResolved()) {
+ jsobj.AddLocation(bpt_location_);
+ } else {
+ jsobj.AddUnresolvedLocation(bpt_location_);
+ }
}
@@ -1602,13 +1617,66 @@ static intptr_t LastTokenOnLine(const TokenStream& tokens, intptr_t pos) {
}
-// Given a function and a token range, return the best fit
-// token position to set a breakpoint. The best fit is the safe point
-// in the line closest to the beginning of the token range, and within
-// that line, the safe point with the lowest compiled code address.
+// Returns the best fit token position for a breakpoint.
+//
+// Takes a range of tokens [requested_token_pos, last_token_pos] and
+// an optional column (requested_column). The range of tokens usually
+// represents one line of the program text, but can represent a larger
+// range on recursive calls.
+//
+// The best fit is found in two passes.
+//
+// The first pass finds a candidate token which:
+//
+// - is a safepoint,
+// - has the lowest column number compatible with the requested column
+// if a column has been specified,
+// and:
+// - has the lowest token position number which satisfies the above.
+//
+// When we consider a column number, we look for the closed token
+// which intersects the desired column. For example:
+//
+// 1 2 3
+// 12345678901234567890 0
+//
+// var x = function(function(y));
+// ^
+//
+// If we request a breakpoint at column 14, the lowest column number
+// compatible with that would for column 11 (beginning of the
+// 'function' token) in the example above.
+//
+// Once this candidate token from the first pass is found, we then
+// have a second pass which considers only those tokens on the same
+// line as the candidate token.
+//
+// The second pass finds a best fit token which:
+//
+// - is a safepoint,
+// - has the same column number as the candidate token (perhaps
+// more than one token has the same column number),
+// and:
+// - has the lowest code address in the generated code.
+//
+// We prefer the lowest compiled code address, because this tends to
+// select the first subexpression on a line. For example in a line
+// with nested function calls f(g(x)), the call to g() will have a
+// lower compiled code address than the call to f().
+//
+// If no best fit token can be found, the search is expanded,
+// searching through the rest of the current function by calling this
+// function recursively.
+//
+// TODO(turnidge): Given that we usually call this function with a
+// token range restricted to a single line, this could be a one-pass
+// algorithm, which would be simpler. I believe that it only needs
+// two passes to support the recursive try-the-whole-function case.
+// Rewrite this later, once there are more tests in place.
intptr_t Debugger::ResolveBreakpointPos(const Function& func,
intptr_t requested_token_pos,
- intptr_t last_token_pos) {
+ intptr_t last_token_pos,
+ intptr_t requested_column) {
ASSERT(func.HasCode());
ASSERT(!func.HasOptimizedCode());
@@ -1619,6 +1687,7 @@ intptr_t Debugger::ResolveBreakpointPos(const Function& func,
last_token_pos = func.end_token_pos();
}
+ Script& script = Script::Handle(func.script());
Code& code = Code::Handle(func.unoptimized_code());
ASSERT(!code.IsNull());
PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
@@ -1626,22 +1695,47 @@ intptr_t Debugger::ResolveBreakpointPos(const Function& func,
// First pass: find the safe point which is closest to the beginning
// of the given token range.
intptr_t best_fit_pos = INT_MAX;
+ intptr_t best_column = INT_MAX;
PcDescriptors::Iterator iter(desc, kSafepointKind);
while (iter.MoveNext()) {
- const intptr_t desc_token_pos = iter.TokenPos();
- if ((desc_token_pos != Scanner::kNoSourcePos) &&
- (desc_token_pos < best_fit_pos) &&
- (desc_token_pos >= requested_token_pos) &&
- (desc_token_pos <= last_token_pos)) {
- best_fit_pos = desc_token_pos;
- }
- }
- // Second pass (if we found a safe point in the first pass):
- // For all token positions on the same line, select the one
- // with the lowest compiled code address. E.g., in a line with
- // the nested function calls f(g(x)), the call g() will have a lower
- // compiled code address but is not the lowest token position in the
- // line.
+ const intptr_t pos = iter.TokenPos();
+ if ((pos == Scanner::kNoSourcePos) ||
+ (pos < requested_token_pos) ||
+ (pos > last_token_pos)) {
+ // Token is not in the target range.
+ continue;
+ }
+
+ intptr_t token_start_column = -1;
+ if (requested_column >= 0) {
+ intptr_t ignored = -1;
+ intptr_t token_len = -1;
+ // TODO(turnidge): GetTokenLocation is a very expensive
+ // operation, and this code will blow up when we are setting
+ // column breakpoints on, for example, a large, single-line
+ // program. Consider rewriting this code so that it only scans
+ // the program code once and caches the token positions and
+ // lengths.
+ script.GetTokenLocation(pos, &ignored, &token_start_column, &token_len);
+ intptr_t token_end_column = token_start_column + token_len - 1;
+ if ((token_end_column < requested_column) ||
+ (token_start_column > best_column)) {
+ // Prefer the token with the lowest column number compatible
+ // with the requested column.
+ continue;
+ }
+ }
+
+ // Prefer the lowest (first) token pos.
+ if (pos < best_fit_pos) {
+ best_fit_pos = pos;
+ best_column = token_start_column;
+ }
+ }
+
+ // Second pass (if we found a safe point in the first pass). Find
+ // the token on the line which is at the best fit column (if column
+ // was specified) and has the lowest code address.
if (best_fit_pos != INT_MAX) {
const Script& script = Script::Handle(func.script());
const TokenStream& tokens = TokenStream::Handle(script.tokens());
@@ -1651,9 +1745,26 @@ intptr_t Debugger::ResolveBreakpointPos(const Function& func,
PcDescriptors::Iterator iter(desc, kSafepointKind);
while (iter.MoveNext()) {
const intptr_t pos = iter.TokenPos();
- if ((pos != Scanner::kNoSourcePos) &&
- (begin_pos <= pos) && (pos <= end_of_line_pos) &&
- (iter.PcOffset() < lowest_pc_offset)) {
+ if ((pos == Scanner::kNoSourcePos) ||
+ (pos < begin_pos) ||
+ (pos > end_of_line_pos)) {
+ // Token is not on same line as best fit.
+ continue;
+ }
+
+ if (requested_column >= 0) {
+ intptr_t ignored = -1;
+ intptr_t token_start_column = -1;
+ // We look for other tokens at the best column in case there
+ // is more than one token at the same column offset.
+ script.GetTokenLocation(pos, &ignored, &token_start_column);
+ if (token_start_column != best_column) {
+ continue;
+ }
+ }
+
+ // Prefer the lowest pc offset.
+ if (iter.PcOffset() < lowest_pc_offset) {
lowest_pc_offset = iter.PcOffset();
best_fit_pos = pos;
}
@@ -1661,10 +1772,13 @@ intptr_t Debugger::ResolveBreakpointPos(const Function& func,
return best_fit_pos;
}
- // We didn't find a safe point in the given token range. Try and find
- // a safe point in the remaining source code of the function.
+ // We didn't find a safe point in the given token range. Try and
+ // find a safe point in the remaining source code of the function.
+ // Since we have moved to the next line of the function, we no
+ // longer are requesting a specific column number.
if (last_token_pos < func.end_token_pos()) {
- return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos());
+ return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(),
+ -1 /* no column */);
}
return -1;
}
@@ -1857,7 +1971,9 @@ RawFunction* Debugger::FindBestFit(const Script& script,
BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
intptr_t token_pos,
- intptr_t last_token_pos) {
+ intptr_t last_token_pos,
+ intptr_t requested_line,
+ intptr_t requested_column) {
Function& func = Function::Handle(isolate_);
func = FindBestFit(script, token_pos);
if (func.IsNull()) {
@@ -1881,14 +1997,16 @@ BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
DeoptimizeWorld();
func ^= functions.At(0);
intptr_t breakpoint_pos =
- ResolveBreakpointPos(func, token_pos, last_token_pos);
+ ResolveBreakpointPos(func, token_pos, last_token_pos, requested_column);
if (breakpoint_pos >= 0) {
- BreakpointLocation* bpt = GetBreakpointLocation(script, breakpoint_pos);
+ BreakpointLocation* bpt =
+ GetBreakpointLocation(script, breakpoint_pos, requested_column);
if (bpt != NULL) {
// A source breakpoint for this location already exists.
return bpt;
}
- bpt = new BreakpointLocation(script, token_pos, last_token_pos);
+ bpt = new BreakpointLocation(script, token_pos, last_token_pos,
+ requested_line, requested_column);
bpt->SetResolved(func, breakpoint_pos);
RegisterBreakpointLocation(bpt);
@@ -1901,11 +2019,12 @@ BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
}
if (FLAG_verbose_debug) {
intptr_t line_number;
- script.GetTokenLocation(breakpoint_pos, &line_number, NULL);
+ intptr_t column_number;
+ script.GetTokenLocation(breakpoint_pos, &line_number, &column_number);
OS::Print("Resolved BP for "
- "function '%s' at line %" Pd "\n",
+ "function '%s' at line %" Pd " col %" Pd "\n",
func.ToFullyQualifiedCString(),
- line_number);
+ line_number, column_number);
}
return bpt;
}
@@ -1914,15 +2033,18 @@ BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
// Register an unresolved breakpoint.
if (FLAG_verbose_debug && !func.IsNull()) {
intptr_t line_number;
- script.GetTokenLocation(token_pos, &line_number, NULL);
+ intptr_t column_number;
+ script.GetTokenLocation(token_pos, &line_number, &column_number);
OS::Print("Registering pending breakpoint for "
- "uncompiled function '%s' at line %" Pd "\n",
+ "uncompiled function '%s' at line %" Pd " col %" Pd "\n",
func.ToFullyQualifiedCString(),
- line_number);
+ line_number, column_number);
}
- BreakpointLocation* bpt = GetBreakpointLocation(script, token_pos);
+ BreakpointLocation* bpt =
+ GetBreakpointLocation(script, token_pos, requested_column);
if (bpt == NULL) {
- bpt = new BreakpointLocation(script, token_pos, last_token_pos);
+ bpt = new BreakpointLocation(script, token_pos, last_token_pos,
+ requested_line, requested_column);
RegisterBreakpointLocation(bpt);
}
return bpt;
@@ -1969,7 +2091,8 @@ Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function,
BreakpointLocation* bpt_location =
SetBreakpoint(script,
target_function.token_pos(),
- target_function.end_token_pos());
+ target_function.end_token_pos(),
+ -1, -1 /* no requested line/col */);
if (single_shot) {
return bpt_location->AddSingleShot(this);
} else {
@@ -1986,7 +2109,8 @@ Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) {
const Script& script = Script::Handle(func.script());
BreakpointLocation* bpt_location = SetBreakpoint(script,
func.token_pos(),
- func.end_token_pos());
+ func.end_token_pos(),
+ -1, -1 /* no line/col */);
return bpt_location->AddPerClosure(this, closure);
}
@@ -2016,7 +2140,21 @@ Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) {
Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
intptr_t line_number) {
- BreakpointLocation* loc = BreakpointLocationAtLine(script_url, line_number);
+ BreakpointLocation* loc =
+ BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */);
+ if (loc != NULL) {
+ return loc->AddRepeated(this);
+ }
+ return NULL;
+}
+
+
+Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url,
+ intptr_t line_number,
+ intptr_t column_number) {
+ BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url,
+ line_number,
+ column_number);
if (loc != NULL) {
return loc->AddRepeated(this);
}
@@ -2024,8 +2162,10 @@ Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
}
-BreakpointLocation* Debugger::BreakpointLocationAtLine(const String& script_url,
- intptr_t line_number) {
+BreakpointLocation* Debugger::BreakpointLocationAtLineCol(
+ const String& script_url,
+ intptr_t line_number,
+ intptr_t column_number) {
Library& lib = Library::Handle(isolate_);
Script& script = Script::Handle(isolate_);
const GrowableObjectArray& libs =
@@ -2043,11 +2183,13 @@ BreakpointLocation* Debugger::BreakpointLocationAtLine(const String& script_url,
// No script found with given url. Create a latent breakpoint which
// will be set if the url is loaded later.
BreakpointLocation* latent_bpt = GetLatentBreakpoint(script_url,
- line_number);
+ line_number,
+ column_number);
if (FLAG_verbose_debug) {
- OS::Print("Set latent breakpoint in url '%s' at line %" Pd "\n",
+ OS::Print("Set latent breakpoint in url '%s' at "
+ "line %" Pd " col %" Pd "\n",
script_url.ToCString(),
- line_number);
+ line_number, column_number);
}
return latent_bpt;
}
@@ -2079,7 +2221,8 @@ BreakpointLocation* Debugger::BreakpointLocationAtLine(const String& script_url,
BreakpointLocation* bpt = NULL;
ASSERT(first_token_idx <= last_token_idx);
while ((bpt == NULL) && (first_token_idx <= last_token_idx)) {
- bpt = SetBreakpoint(script, first_token_idx, last_token_idx);
+ bpt = SetBreakpoint(script, first_token_idx, last_token_idx,
+ line_number, column_number);
first_token_idx++;
}
if ((bpt == NULL) && FLAG_verbose_debug) {
@@ -2680,7 +2823,8 @@ void Debugger::NotifyCompilation(const Function& func) {
if (!loc->IsResolved()) {
// Resolve source breakpoint in the newly compiled function.
intptr_t bp_pos =
- ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos());
+ ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos(),
+ loc->requested_column_number());
if (bp_pos < 0) {
if (FLAG_verbose_debug) {
OS::Print("Failed resolving breakpoint for function '%s'\n",
@@ -2694,14 +2838,18 @@ void Debugger::NotifyCompilation(const Function& func) {
Breakpoint* bpt = loc->breakpoints();
while (bpt != NULL) {
if (FLAG_verbose_debug) {
- OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", "
- "function '%s' (requested range %" Pd "-%" Pd ")\n",
+ OS::Print("Resolved BP %" Pd " to pos %" Pd ", "
+ "line %" Pd " col %" Pd ", "
+ "function '%s' (requested range %" Pd "-%" Pd ", "
+ "requested col %" Pd ")\n",
bpt->id(),
loc->token_pos(),
loc->LineNumber(),
+ loc->ColumnNumber(),
func.ToFullyQualifiedCString(),
requested_pos,
- requested_end_pos);
+ requested_end_pos,
+ loc->requested_column_number());
}
SignalBpResolved(bpt);
SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
@@ -2712,9 +2860,11 @@ void Debugger::NotifyCompilation(const Function& func) {
if (FLAG_verbose_debug) {
Breakpoint* bpt = loc->breakpoints();
while (bpt != NULL) {
- OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n",
+ OS::Print("Setting breakpoint %" Pd " at line %" Pd " col %" Pd ""
+ " for %s '%s'\n",
bpt->id(),
loc->LineNumber(),
+ loc->ColumnNumber(),
func.IsClosureFunction() ? "closure" : "function",
String::Handle(func.name()).ToCString());
bpt = bpt->next();
@@ -2757,7 +2907,8 @@ void Debugger::NotifyDoneLoading() {
}
// Now find the token range at the requested line and make a
// new unresolved source breakpoint.
- intptr_t line_number = matched_loc->LineNumber();
+ intptr_t line_number = matched_loc->requested_line_number();
+ intptr_t column_number = matched_loc->requested_column_number();
ASSERT(line_number >= 0);
intptr_t first_token_pos, last_token_pos;
script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos);
@@ -2784,15 +2935,15 @@ void Debugger::NotifyDoneLoading() {
// If there is one, assert in debug build but silently drop
// the latent breakpoint in release build.
BreakpointLocation* existing_loc =
- GetBreakpointLocation(script, first_token_pos);
+ GetBreakpointLocation(script, first_token_pos, column_number);
ASSERT(existing_loc == NULL);
if (existing_loc == NULL) {
// Create and register a new source breakpoint for the
// latent breakpoint.
BreakpointLocation* unresolved_loc =
new BreakpointLocation(script,
- first_token_pos,
- last_token_pos);
+ first_token_pos, last_token_pos,
+ line_number, column_number);
RegisterBreakpointLocation(unresolved_loc);
// Move breakpoints over.
@@ -2803,10 +2954,10 @@ void Debugger::NotifyDoneLoading() {
bpt->set_bpt_location(unresolved_loc);
if (FLAG_verbose_debug) {
OS::Print("Converted latent breakpoint "
- "%" Pd " in '%s' at line %" Pd "\n",
+ "%" Pd " in '%s' at line %" Pd " col %" Pd "\n",
bpt->id(),
url.ToCString(),
- line_number);
+ line_number, column_number);
}
bpt = bpt->next();
}
@@ -2970,10 +3121,13 @@ void Debugger::RemoveInternalBreakpoints() {
BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script,
- intptr_t token_pos) {
+ intptr_t token_pos,
+ intptr_t requested_column) {
BreakpointLocation* bpt = breakpoint_locations_;
while (bpt != NULL) {
- if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos)) {
+ if ((bpt->script_ == script.raw()) &&
+ (bpt->token_pos_ == token_pos) &&
+ (bpt->requested_column_number_ == requested_column)) {
return bpt;
}
bpt = bpt->next();
@@ -2999,18 +3153,21 @@ Breakpoint* Debugger::GetBreakpointById(intptr_t id) {
BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url,
- intptr_t line) {
+ intptr_t line,
+ intptr_t column) {
BreakpointLocation* bpt = latent_locations_;
String& bpt_url = String::Handle(isolate_);
while (bpt != NULL) {
bpt_url = bpt->url();
- if (bpt_url.Equals(url) && (bpt->LineNumber() == line)) {
+ if (bpt_url.Equals(url) &&
+ (bpt->requested_line_number() == line) &&
+ (bpt->requested_column_number() == column)) {
return bpt;
}
bpt = bpt->next();
}
- // No breakpint for this url and line requested. Allocate new one.
- bpt = new BreakpointLocation(url, line);
+ // No breakpoint for this location requested. Allocate new one.
+ bpt = new BreakpointLocation(url, line, column);
bpt->set_next(latent_locations_);
latent_locations_ = bpt;
return bpt;
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/debugger_api_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698