Chromium Code Reviews| 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; |