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

Unified Diff: runtime/vm/debugger.cc

Issue 1146173003: Per-closure breakpoints; restructure breakpoint implementation to keep a list of conditions. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 7 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
Index: runtime/vm/debugger.cc
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 954aa8215c35cb2a349707a17fba7fa320d113f1..e73ea6cbdddd70252eab19af0bba76dccc7aff11 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -62,42 +62,36 @@ class RemoteObjectCache : public ZoneAllocated {
// Create an unresolved breakpoint in given token range and script.
-SourceBreakpoint::SourceBreakpoint(intptr_t id,
- const Script& script,
+SourceBreakpoint::SourceBreakpoint(const Script& script,
intptr_t token_pos,
intptr_t end_token_pos)
- : id_(id),
- script_(script.raw()),
+ : script_(script.raw()),
url_(script.url()),
token_pos_(token_pos),
end_token_pos_(end_token_pos),
is_resolved_(false),
is_enabled_(false),
- is_one_shot_(false),
next_(NULL),
+ conditions_(NULL),
function_(Function::null()),
line_number_(-1) {
- ASSERT(id_ > 0);
ASSERT(!script.IsNull());
ASSERT(token_pos_ >= 0);
}
// Create a latent breakpoint at given url and line number.
-SourceBreakpoint::SourceBreakpoint(intptr_t id,
- const String& url,
+SourceBreakpoint::SourceBreakpoint(const String& url,
intptr_t line_number)
- : id_(id),
- script_(Script::null()),
+ : script_(Script::null()),
url_(url.raw()),
token_pos_(-1),
end_token_pos_(-1),
is_resolved_(false),
is_enabled_(false),
- is_one_shot_(false),
next_(NULL),
+ conditions_(NULL),
function_(Function::null()),
line_number_(line_number) {
- ASSERT(id >= 0);
ASSERT(line_number_ >= 0);
}
@@ -164,14 +158,31 @@ intptr_t SourceBreakpoint::LineNumber() {
}
+void BreakpointCondition::set_src_bpt(SourceBreakpoint* new_src_bpt) {
+ ASSERT(src_bpt_->IsLatent()); // Only reason to move.
+ src_bpt_ = new_src_bpt;
+}
+
+
+void BreakpointCondition::VisitObjectPointers(ObjectPointerVisitor* visitor) {
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_));
+}
+
+
void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
visitor->VisitPointer(reinterpret_cast<RawObject**>(&script_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&url_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
+
+ BreakpointCondition* cond = conditions_;
+ while (cond != NULL) {
+ cond -> VisitObjectPointers(visitor);
+ cond = cond->next();
+ }
}
-void SourceBreakpoint::PrintJSON(JSONStream* stream) {
+void BreakpointCondition::PrintJSON(JSONStream* stream) {
Isolate* isolate = Isolate::Current();
JSONObject jsobj(stream);
@@ -179,12 +190,12 @@ void SourceBreakpoint::PrintJSON(JSONStream* stream) {
jsobj.AddPropertyF("id", "breakpoints/%" Pd "", id());
jsobj.AddProperty("breakpointNumber", id());
- jsobj.AddProperty("resolved", IsResolved());
+ jsobj.AddProperty("resolved", src_bpt_->IsResolved());
Library& library = Library::Handle(isolate);
Script& script = Script::Handle(isolate);
intptr_t token_pos;
- GetCodeLocation(&library, &script, &token_pos);
+ src_bpt_->GetCodeLocation(&library, &script, &token_pos);
{
JSONObject location(&jsobj, "location");
location.AddProperty("type", "Location");
@@ -293,7 +304,7 @@ void Debugger::SignalIsolateInterrupted() {
// The vm service handles breakpoint notifications in a different way
// than the regular debugger breakpoint notifications.
static void SendServiceBreakpointEvent(ServiceEvent::EventType type,
- SourceBreakpoint* bpt) {
+ BreakpointCondition* bpt) {
if (Service::NeedsEvents()) {
ServiceEvent service_event(Isolate::Current(), type);
service_event.set_breakpoint(bpt);
@@ -302,6 +313,70 @@ static void SendServiceBreakpointEvent(ServiceEvent::EventType type,
}
+BreakpointCondition* SourceBreakpoint::AddRepeated(Debugger* dbg) {
+ BreakpointCondition* cond = conditions();
+ while (cond != NULL) {
+ if (cond->IsRepeated()) break;
+ cond = cond->next();
+ }
+ if (cond == NULL) {
+ cond = new BreakpointCondition(dbg->nextId(), this);
+ cond->SetIsRepeated();
+ cond->set_next(conditions());
+ set_conditions(cond);
+
+ if (IsResolved()) {
+ dbg->SignalBpResolved(cond);
+ }
+ SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond);
+ }
+ return cond;
+}
+
+
+BreakpointCondition* SourceBreakpoint::AddSingleShot(Debugger* dbg) {
+ BreakpointCondition* cond = conditions();
+ while (cond != NULL) {
+ if (cond->IsSingleShot()) break;
+ cond = cond->next();
+ }
+ if (cond == NULL) {
+ cond = new BreakpointCondition(dbg->nextId(), this);
+ cond->SetIsSingleShot();
+ cond->set_next(conditions());
+ set_conditions(cond);
+
+ if (IsResolved()) {
+ dbg->SignalBpResolved(cond);
+ }
+ SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond);
+ }
+ return cond;
+}
+
+
+BreakpointCondition* SourceBreakpoint::AddPerClosure(Debugger* dbg,
+ const Instance& closure) {
+ BreakpointCondition* cond = conditions();
+ while (cond != NULL) {
+ if (cond->IsPerClosure() && cond->closure() == closure.raw()) break;
+ cond = cond->next();
+ }
+ if (cond == NULL) {
+ cond = new BreakpointCondition(dbg->nextId(), this);
+ cond->SetIsPerClosure(closure);
+ cond->set_next(conditions());
+ set_conditions(cond);
+
+ if (IsResolved()) {
+ dbg->SignalBpResolved(cond);
+ }
+ SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, cond);
+ }
+ return cond;
+}
+
+
const char* Debugger::QualifiedFunctionName(const Function& func) {
const String& func_name = String::Handle(func.name());
Class& func_class = Class::Handle(func.Owner());
@@ -378,7 +453,11 @@ bool Debugger::HasBreakpoint(const Code& code) {
void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const {
SourceBreakpoint* sbpt = src_breakpoints_;
while (sbpt != NULL) {
- jsarr->AddValue(sbpt);
+ BreakpointCondition* cond = sbpt->conditions();
+ while (cond != NULL) {
+ jsarr->AddValue(cond);
+ cond = cond->next();
+ }
sbpt = sbpt->next_;
}
}
@@ -675,6 +754,34 @@ intptr_t ActivationFrame::NumLocalVariables() {
}
+RawObject* ActivationFrame::GetParameter(intptr_t index) {
+ intptr_t num_parameters = function().num_fixed_parameters();
+ ASSERT(0 <= index && index < num_parameters);
+ intptr_t reverse_index = num_parameters - index;
+
+ if (function().NumOptionalParameters() > 0) {
+ // If the function has optional parameters, the first positional parameter
+ // can be in a number of places in the caller's frame depending on how many
+ // were actually supplied at the call site, but they are copied to a fixed
+ // place in the callee's frame.
+ uword var_address = fp() + ((kFirstLocalSlotFromFp - index) * kWordSize);
+ return reinterpret_cast<RawObject*>(
+ *reinterpret_cast<uword*>(var_address));
+ } else {
+ uword var_address = fp() + (kParamEndSlotFromFp * kWordSize)
+ + (reverse_index * kWordSize);
+ return reinterpret_cast<RawObject*>(
+ *reinterpret_cast<uword*>(var_address));
+ }
+}
+
+
+RawObject* ActivationFrame::GetClosure() {
+ ASSERT(function().IsClosureFunction());
+ return GetParameter(0);
+}
+
+
RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) {
if (deopt_frame_.IsNull()) {
uword var_address = fp() + slot_index * kWordSize;
@@ -1192,11 +1299,13 @@ void Debugger::DeoptimizeWorld() {
}
-void Debugger::SignalBpResolved(SourceBreakpoint* bpt) {
- if (HasEventHandler() && !bpt->IsOneShot()) {
- DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
- event.set_breakpoint(bpt);
- InvokeEventHandler(&event);
+void Debugger::SignalBpResolved(BreakpointCondition* cond) {
+ if (HasEventHandler()) {
+ if (!cond->IsSingleShot()) {
+ DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
+ event.set_breakpoint(cond);
+ InvokeEventHandler(&event);
+ }
}
}
@@ -1728,7 +1837,7 @@ SourceBreakpoint* Debugger::SetBreakpoint(const Script& script,
// A source breakpoint for this location already exists.
return bpt;
}
- bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos);
+ bpt = new SourceBreakpoint(script, token_pos, last_token_pos);
bpt->SetResolved(func, breakpoint_pos);
RegisterSourceBreakpoint(bpt);
@@ -1748,8 +1857,6 @@ SourceBreakpoint* Debugger::SetBreakpoint(const Script& script,
func.ToFullyQualifiedCString(),
line_number);
}
- SignalBpResolved(bpt);
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
return bpt;
}
}
@@ -1765,9 +1872,8 @@ SourceBreakpoint* Debugger::SetBreakpoint(const Script& script,
}
SourceBreakpoint* bpt = GetSourceBreakpoint(script, token_pos);
if (bpt == NULL) {
- bpt = new SourceBreakpoint(nextId(), script, token_pos, last_token_pos);
+ bpt = new SourceBreakpoint(script, token_pos, last_token_pos);
RegisterSourceBreakpoint(bpt);
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
}
bpt->Enable();
return bpt;
@@ -1794,10 +1900,7 @@ void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) {
RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- SourceBreakpoint* bpt = SetBreakpointAtEntry(target_function);
- if (bpt != NULL) {
- bpt->SetIsOneShot();
- }
+ SetBreakpointAtEntry(target_function, true);
return Error::null();
} else {
return isolate_->object_store()->sticky_error();
@@ -1805,21 +1908,48 @@ RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) {
}
-SourceBreakpoint* Debugger::SetBreakpointAtEntry(
- const Function& target_function) {
+BreakpointCondition* Debugger::SetBreakpointAtEntry(
+ const Function& target_function,
+ bool single_shot) {
ASSERT(!target_function.IsNull());
if (!target_function.is_debuggable()) {
return NULL;
}
const Script& script = Script::Handle(target_function.script());
- return SetBreakpoint(script,
- target_function.token_pos(),
- target_function.end_token_pos());
+ SourceBreakpoint* src_bpt = SetBreakpoint(script,
+ target_function.token_pos(),
+ target_function.end_token_pos());
+ if (single_shot) {
+ return src_bpt->AddSingleShot(this);
+ } else {
+ return src_bpt->AddRepeated(this);
+ }
}
-SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
- intptr_t line_number) {
+BreakpointCondition* Debugger::SetBreakpointAtActivation(
+ const Instance& closure) {
+ if (!closure.IsClosure()) {
+ return NULL;
+ }
+ const Function& func = Function::Handle(Closure::function(closure));
+ const Script& script = Script::Handle(func.script());
+ SourceBreakpoint* bpt = SetBreakpoint(script,
+ func.token_pos(),
+ func.end_token_pos());
+ return bpt->AddPerClosure(this, closure);
+}
+
+
+BreakpointCondition* Debugger::SetBreakpointAtLine(const String& script_url,
+ intptr_t line_number) {
+ SourceBreakpoint* bpt = SourceBreakpointAtLine(script_url, line_number);
+ return bpt->AddRepeated(this);
+}
+
+
+SourceBreakpoint* Debugger::SourceBreakpointAtLine(const String& script_url,
+ intptr_t line_number) {
Library& lib = Library::Handle(isolate_);
Script& script = Script::Handle(isolate_);
const GrowableObjectArray& libs =
@@ -2166,13 +2296,13 @@ bool Debugger::IsDebuggable(const Function& func) {
void Debugger::SignalPausedEvent(ActivationFrame* top_frame,
- SourceBreakpoint* bpt) {
+ BreakpointCondition* bpt) {
resume_action_ = kContinue;
stepping_fp_ = 0;
isolate_->set_single_step(false);
ASSERT(!IsPaused());
ASSERT(obj_cache_ == NULL);
- if ((bpt != NULL) && bpt->IsOneShot()) {
+ if ((bpt != NULL) && bpt->IsSingleShot()) {
RemoveBreakpoint(bpt->id());
bpt = NULL;
}
@@ -2257,6 +2387,31 @@ void Debugger::SignalBpReached() {
CodeBreakpoint* bpt = GetCodeBreakpoint(top_frame->pc());
ASSERT(bpt != NULL);
+ SourceBreakpoint* src_bpt = bpt->src_bpt_;
+ BreakpointCondition* condition_met = NULL;
+ if (src_bpt != NULL) {
+ BreakpointCondition* cond = src_bpt->conditions();
+ while (cond != NULL) {
+ if (cond->IsPerClosure()) {
+ Object& closure = Object::Handle(top_frame->GetClosure());
+ ASSERT(closure.IsInstance());
+ ASSERT(Instance::Cast(closure).IsClosure());
+ if (closure.raw() == cond->closure()) {
+ condition_met = cond;
+ break;
+ }
+ } else {
+ condition_met = cond;
hausner 2015/05/21 18:23:55 This is subtly wrong. If you have a one-shot break
rmacnak 2015/05/21 21:59:35 As discussed, we should not send a series of break
+ break;
+ }
+ cond = cond->next();
+ }
+ }
+ if (condition_met == NULL) {
+ return;
+ }
+
+
if (FLAG_verbose_debug) {
OS::Print(">>> hit %s breakpoint at %s:%" Pd " "
"(token %" Pd ") (address %#" Px ")\n",
@@ -2269,7 +2424,7 @@ void Debugger::SignalBpReached() {
ASSERT(stack_trace_ == NULL);
stack_trace_ = stack_trace;
- SignalPausedEvent(top_frame, bpt->src_bpt_);
+ SignalPausedEvent(top_frame, condition_met);
HandleSteppingRequest(stack_trace_);
stack_trace_ = NULL;
if (bpt->IsInternal()) {
@@ -2410,26 +2565,34 @@ void Debugger::NotifyCompilation(const Function& func) {
intptr_t requested_pos = bpt->token_pos();
intptr_t requested_end_pos = bpt->end_token_pos();
bpt->SetResolved(func, bp_pos);
- if (FLAG_verbose_debug) {
- OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", "
- "function '%s' (requested range %" Pd "-%" Pd ")\n",
- bpt->id(),
- bpt->token_pos(),
- bpt->LineNumber(),
- func.ToFullyQualifiedCString(),
- requested_pos,
- requested_end_pos);
+ BreakpointCondition* cond = bpt->conditions();
+ while (cond != NULL) {
+ if (FLAG_verbose_debug) {
+ OS::Print("Resolved BP %" Pd " to pos %" Pd ", line %" Pd ", "
+ "function '%s' (requested range %" Pd "-%" Pd ")\n",
+ cond->id(),
+ bpt->token_pos(),
+ bpt->LineNumber(),
+ func.ToFullyQualifiedCString(),
+ requested_pos,
+ requested_end_pos);
+ }
+ SignalBpResolved(cond);
+ SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, cond);
+ cond = cond->next();
}
- SignalBpResolved(bpt);
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
}
ASSERT(bpt->IsResolved());
if (FLAG_verbose_debug) {
- OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n",
- bpt->id(),
- bpt->LineNumber(),
- func.IsClosureFunction() ? "closure" : "function",
- String::Handle(func.name()).ToCString());
+ BreakpointCondition* cond = bpt->conditions();
+ while (cond != NULL) {
+ OS::Print("Setting breakpoint %" Pd " at line %" Pd " for %s '%s'\n",
+ cond->id(),
+ bpt->LineNumber(),
+ func.IsClosureFunction() ? "closure" : "function",
+ String::Handle(func.name()).ToCString());
+ cond = cond->next();
+ }
}
MakeCodeBreakpointAt(func, bpt);
}
@@ -2476,12 +2639,18 @@ void Debugger::NotifyDoneLoading() {
(last_token_pos < 0)) {
// Script does not contain the given line number or there are no
// tokens on the line. Drop the breakpoint silently.
- if (FLAG_verbose_debug) {
- OS::Print("No code found at line %" Pd ": "
- "dropping latent breakpoint %" Pd " in '%s'\n",
- line_number,
- matched_bpt->id(),
- url.ToCString());
+ BreakpointCondition* cond = matched_bpt->conditions();
+ while (cond != NULL) {
+ if (FLAG_verbose_debug) {
+ OS::Print("No code found at line %" Pd ": "
+ "dropping latent breakpoint %" Pd " in '%s'\n",
+ line_number,
+ cond->id(),
+ url.ToCString());
+ }
+ BreakpointCondition* prev = cond;
+ cond = cond->next();
+ delete prev;
}
delete matched_bpt;
} else {
@@ -2495,18 +2664,26 @@ void Debugger::NotifyDoneLoading() {
// Create and register a new source breakpoint for the
// latent breakpoint.
SourceBreakpoint* unresolved_bpt =
- new SourceBreakpoint(matched_bpt->id(),
- script,
+ new SourceBreakpoint(script,
first_token_pos,
last_token_pos);
RegisterSourceBreakpoint(unresolved_bpt);
unresolved_bpt->Enable();
- if (FLAG_verbose_debug) {
- OS::Print("Converted latent breakpoint "
- "%" Pd " in '%s' at line %" Pd "\n",
- matched_bpt->id(),
- url.ToCString(),
- line_number);
+
+ // Move conditions over.
+ BreakpointCondition* cond = existing_bpt->conditions();
+ unresolved_bpt->set_conditions(cond);
+ existing_bpt->set_conditions(NULL);
+ while (cond != NULL) {
+ cond->set_src_bpt(unresolved_bpt);
+ if (FLAG_verbose_debug) {
+ OS::Print("Converted latent breakpoint "
+ "%" Pd " in '%s' at line %" Pd "\n",
+ cond->id(),
+ url.ToCString(),
+ line_number);
+ }
+ cond = cond->next();
}
}
delete matched_bpt;
@@ -2526,10 +2703,14 @@ void Debugger::NotifyDoneLoading() {
if (!found_match) {
// No matching url found in any of the libraries.
if (FLAG_verbose_debug) {
- OS::Print("No match found for latent breakpoint id "
- "%" Pd " with url '%s'\n",
- bpt->id(),
- url.ToCString());
+ BreakpointCondition* cond = bpt->conditions();
+ while (cond != NULL) {
+ OS::Print("No match found for latent breakpoint id "
+ "%" Pd " with url '%s'\n",
+ cond->id(),
+ url.ToCString());
+ cond = cond->next();
+ }
}
bpt = bpt->next();
}
@@ -2573,27 +2754,43 @@ void Debugger::RemoveBreakpoint(intptr_t bp_id) {
SourceBreakpoint* prev_bpt = NULL;
SourceBreakpoint* curr_bpt = src_breakpoints_;
while (curr_bpt != NULL) {
- if (curr_bpt->id() == bp_id) {
+ BreakpointCondition* prev_cond = NULL;
+ BreakpointCondition* curr_cond = curr_bpt->conditions();
+ while (curr_cond != NULL) {
+ if (curr_cond->id() == bp_id) {
+ if (prev_cond == NULL) {
+ curr_bpt->set_conditions(curr_cond->next());
+ } else {
+ prev_cond->set_next(curr_cond->next());
+ }
+ SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_cond);
+
+ // Remove references from the current debugger pause event.
+ if (pause_event_ != NULL &&
+ pause_event_->type() == DebuggerEvent::kBreakpointReached &&
+ pause_event_->breakpoint() == curr_cond) {
+ pause_event_->set_breakpoint(NULL);
+ }
+ return;
+ }
+
+ prev_cond = curr_cond;
+ curr_cond = curr_cond->next();
+ }
+
+ if (curr_bpt->conditions() == NULL) {
if (prev_bpt == NULL) {
src_breakpoints_ = src_breakpoints_->next();
} else {
prev_bpt->set_next(curr_bpt->next());
}
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
// Remove references from code breakpoints to this source breakpoint,
// and disable the code breakpoints.
UnlinkCodeBreakpoints(curr_bpt);
delete curr_bpt;
-
- // Remove references from the current debugger pause event.
- if (pause_event_ != NULL &&
- pause_event_->type() == DebuggerEvent::kBreakpointReached &&
- pause_event_->breakpoint() == curr_bpt) {
- pause_event_->set_breakpoint(NULL);
- }
- return;
}
+
prev_bpt = curr_bpt;
curr_bpt = curr_bpt->next();
}
@@ -2656,11 +2853,15 @@ SourceBreakpoint* Debugger::GetSourceBreakpoint(const Script& script,
}
-SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) {
+BreakpointCondition* Debugger::GetBreakpointById(intptr_t id) {
SourceBreakpoint* bpt = src_breakpoints_;
while (bpt != NULL) {
- if (bpt->id() == id) {
- return bpt;
+ BreakpointCondition* cond = bpt->conditions();
+ while (cond != NULL) {
+ if (cond->id() == id) {
+ return cond;
+ }
+ cond = cond->next();
}
bpt = bpt->next();
}
@@ -2680,7 +2881,7 @@ SourceBreakpoint* Debugger::GetLatentBreakpoint(const String& url,
bpt = bpt->next();
}
// No breakpint for this url and line requested. Allocate new one.
- bpt = new SourceBreakpoint(nextId(), url, line);
+ bpt = new SourceBreakpoint(url, line);
bpt->set_next(latent_breakpoints_);
latent_breakpoints_ = bpt;
return bpt;

Powered by Google App Engine
This is Rietveld 408576698