| Index: runtime/vm/debugger.cc
|
| ===================================================================
|
| --- runtime/vm/debugger.cc (revision 4881)
|
| +++ runtime/vm/debugger.cc (working copy)
|
| @@ -25,57 +25,65 @@
|
| static const bool verbose = false;
|
|
|
|
|
| -Breakpoint::Breakpoint(const Function& func, intptr_t pc_desc_index)
|
| +SourceBreakpoint::SourceBreakpoint(const Function& func, intptr_t token_index)
|
| : function_(func.raw()),
|
| - pc_desc_index_(pc_desc_index),
|
| - pc_(0),
|
| + token_index_(token_index),
|
| line_number_(-1),
|
| - is_temporary_(false),
|
| - is_patched_(false),
|
| + is_enabled_(false),
|
| next_(NULL) {
|
| - ASSERT(!func.HasOptimizedCode());
|
| - Code& code = Code::Handle(func.unoptimized_code());
|
| - ASSERT(!code.IsNull()); // Function must be compiled.
|
| - PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
|
| - ASSERT(pc_desc_index < desc.Length());
|
| - this->token_index_ = desc.TokenIndex(pc_desc_index);
|
| - ASSERT(this->token_index_ > 0);
|
| - this->pc_ = desc.PC(pc_desc_index);
|
| - ASSERT(this->pc_ != 0);
|
| - this->breakpoint_kind_ = desc.DescriptorKind(pc_desc_index);
|
| + ASSERT(!func.IsNull());
|
| + ASSERT((func.token_index() <= token_index_) &&
|
| + (token_index_ < func.end_token_index()));
|
| }
|
|
|
|
|
| -RawScript* Breakpoint::SourceCode() {
|
| - const Function& func = Function::Handle(this->function_);
|
| +void SourceBreakpoint::Enable() {
|
| + is_enabled_ = true;
|
| + Isolate::Current()->debugger()->SyncBreakpoint(this);
|
| +}
|
| +
|
| +
|
| +void SourceBreakpoint::Disable() {
|
| + is_enabled_ = false;
|
| + Isolate::Current()->debugger()->SyncBreakpoint(this);
|
| +}
|
| +
|
| +
|
| +RawScript* SourceBreakpoint::SourceCode() {
|
| + const Function& func = Function::Handle(function_);
|
| const Class& cls = Class::Handle(func.owner());
|
| return cls.script();
|
| }
|
|
|
|
|
| -RawString* Breakpoint::SourceUrl() {
|
| - const Script& script = Script::Handle(this->SourceCode());
|
| +RawString* SourceBreakpoint::SourceUrl() {
|
| + const Script& script = Script::Handle(SourceCode());
|
| return script.url();
|
| }
|
|
|
|
|
| -intptr_t Breakpoint::LineNumber() {
|
| +intptr_t SourceBreakpoint::LineNumber() {
|
| // Compute line number lazily since it causes scanning of the script.
|
| - if (this->line_number_ < 0) {
|
| - const Script& script = Script::Handle(this->SourceCode());
|
| + if (line_number_ < 0) {
|
| + const Script& script = Script::Handle(SourceCode());
|
| intptr_t ignore_column;
|
| - script.GetTokenLocation(this->token_index_,
|
| - &this->line_number_, &ignore_column);
|
| + script.GetTokenLocation(token_index_, &line_number_, &ignore_column);
|
| }
|
| - return this->line_number_;
|
| + return line_number_;
|
| }
|
|
|
|
|
| -void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
| +void SourceBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
| visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
|
| }
|
|
|
|
|
| +
|
| +void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
| + visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
|
| +}
|
| +
|
| +
|
| ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp)
|
| : pc_(pc), fp_(fp), sp_(sp),
|
| function_(Function::ZoneHandle()),
|
| @@ -281,12 +289,63 @@
|
|
|
|
|
| void StackTrace::AddActivation(ActivationFrame* frame) {
|
| - this->trace_.Add(frame);
|
| + trace_.Add(frame);
|
| }
|
|
|
|
|
| -void Breakpoint::PatchCode() {
|
| - ASSERT(!is_patched_);
|
| +CodeBreakpoint::CodeBreakpoint(const Function& func, intptr_t pc_desc_index)
|
| + : function_(func.raw()),
|
| + pc_desc_index_(pc_desc_index),
|
| + pc_(0),
|
| + line_number_(-1),
|
| + is_enabled_(false),
|
| + src_bpt_(NULL),
|
| + next_(NULL) {
|
| + ASSERT(!func.HasOptimizedCode());
|
| + Code& code = Code::Handle(func.unoptimized_code());
|
| + ASSERT(!code.IsNull()); // Function must be compiled.
|
| + PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
|
| + ASSERT(pc_desc_index < desc.Length());
|
| + token_index_ = desc.TokenIndex(pc_desc_index);
|
| + ASSERT(token_index_ > 0);
|
| + pc_ = desc.PC(pc_desc_index);
|
| + ASSERT(pc_ != 0);
|
| + breakpoint_kind_ = desc.DescriptorKind(pc_desc_index);
|
| +}
|
| +
|
| +
|
| +CodeBreakpoint::~CodeBreakpoint() {
|
| + // Make sure we don't leave patched code behind.
|
| + ASSERT(!IsEnabled());
|
| +}
|
| +
|
| +
|
| +RawScript* CodeBreakpoint::SourceCode() {
|
| + const Function& func = Function::Handle(function_);
|
| + const Class& cls = Class::Handle(func.owner());
|
| + return cls.script();
|
| +}
|
| +
|
| +
|
| +RawString* CodeBreakpoint::SourceUrl() {
|
| + const Script& script = Script::Handle(SourceCode());
|
| + return script.url();
|
| +}
|
| +
|
| +
|
| +intptr_t CodeBreakpoint::LineNumber() {
|
| + // Compute line number lazily since it causes scanning of the script.
|
| + if (line_number_ < 0) {
|
| + const Script& script = Script::Handle(SourceCode());
|
| + intptr_t ignore_column;
|
| + script.GetTokenLocation(token_index_, &line_number_, &ignore_column);
|
| + }
|
| + return line_number_;
|
| +}
|
| +
|
| +
|
| +void CodeBreakpoint::PatchCode() {
|
| + ASSERT(!is_enabled_);
|
| switch (breakpoint_kind_) {
|
| case PcDescriptors::kIcCall: {
|
| int num_args, num_named_args;
|
| @@ -310,12 +369,12 @@
|
| default:
|
| UNREACHABLE();
|
| }
|
| - is_patched_ = true;
|
| + is_enabled_ = true;
|
| }
|
|
|
|
|
| -void Breakpoint::RestoreCode() {
|
| - ASSERT(is_patched_);
|
| +void CodeBreakpoint::RestoreCode() {
|
| + ASSERT(is_enabled_);
|
| switch (breakpoint_kind_) {
|
| case PcDescriptors::kIcCall:
|
| CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_);
|
| @@ -329,22 +388,23 @@
|
| default:
|
| UNREACHABLE();
|
| }
|
| - is_patched_ = false;
|
| + is_enabled_ = false;
|
| }
|
|
|
| -void Breakpoint::SetActive(bool value) {
|
| - if (value && !is_patched_) {
|
| +
|
| +void CodeBreakpoint::Enable() {
|
| + if (!is_enabled_) {
|
| PatchCode();
|
| - return;
|
| }
|
| - if (!value && is_patched_) {
|
| - RestoreCode();
|
| - }
|
| + ASSERT(is_enabled_);
|
| }
|
|
|
|
|
| -bool Breakpoint::IsActive() {
|
| - return is_patched_;
|
| +void CodeBreakpoint::Disable() {
|
| + if (is_enabled_) {
|
| + RestoreCode();
|
| + }
|
| + ASSERT(!is_enabled_);
|
| }
|
|
|
|
|
| @@ -352,23 +412,30 @@
|
| : isolate_(NULL),
|
| initialized_(false),
|
| bp_handler_(NULL),
|
| - breakpoints_(NULL),
|
| + src_breakpoints_(NULL),
|
| + code_breakpoints_(NULL),
|
| resume_action_(kContinue) {
|
| }
|
|
|
|
|
| Debugger::~Debugger() {
|
| - ASSERT(breakpoints_ == NULL);
|
| + ASSERT(src_breakpoints_ == NULL);
|
| + ASSERT(code_breakpoints_ == NULL);
|
| }
|
|
|
|
|
| void Debugger::Shutdown() {
|
| - while (breakpoints_ != NULL) {
|
| - Breakpoint* bpt = breakpoints_;
|
| - breakpoints_ = breakpoints_->next();
|
| - UnsetBreakpoint(bpt);
|
| + while (src_breakpoints_ != NULL) {
|
| + SourceBreakpoint* bpt = src_breakpoints_;
|
| + src_breakpoints_ = src_breakpoints_->next();
|
| delete bpt;
|
| }
|
| + while (code_breakpoints_ != NULL) {
|
| + CodeBreakpoint* bpt = code_breakpoints_;
|
| + code_breakpoints_ = code_breakpoints_->next();
|
| + bpt->Disable();
|
| + delete bpt;
|
| + }
|
| }
|
|
|
|
|
| @@ -378,7 +445,7 @@
|
| // This is probably not conservative enough (we could set the first
|
| // breakpoint after optimized code has already been produced).
|
| // Long-term, we need to be able to de-optimize code.
|
| - return breakpoints_ != NULL;
|
| + return (src_breakpoints_ != NULL) || (code_breakpoints_ != NULL);
|
| }
|
|
|
|
|
| @@ -430,7 +497,7 @@
|
| ASSERT(!code.IsNull());
|
| PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
|
| for (int i = 0; i < desc.Length(); i++) {
|
| - Breakpoint* bpt = GetBreakpoint(desc.PC(i));
|
| + CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
|
| if (bpt != NULL) {
|
| // There is already a breakpoint for this address. Leave it alone.
|
| continue;
|
| @@ -439,57 +506,50 @@
|
| if ((kind == PcDescriptors::kIcCall) ||
|
| (kind == PcDescriptors::kFuncCall) ||
|
| (kind == PcDescriptors::kReturn)) {
|
| - bpt = new Breakpoint(target_function, i);
|
| - bpt->set_temporary(true);
|
| - bpt->PatchCode();
|
| - RegisterBreakpoint(bpt);
|
| + bpt = new CodeBreakpoint(target_function, i);
|
| + RegisterCodeBreakpoint(bpt);
|
| + bpt->Enable();
|
| }
|
| }
|
| }
|
|
|
|
|
| -// TODO(hausner): Distinguish between newly created breakpoints and
|
| -// returning a breakpoint that already exists?
|
| -Breakpoint* Debugger::SetBreakpoint(const Function& target_function,
|
| - intptr_t token_index,
|
| - Error* error) {
|
| - if ((token_index < target_function.token_index()) ||
|
| - (target_function.end_token_index() <= token_index)) {
|
| - // The given token position is not within the target function.
|
| - return NULL;
|
| - }
|
| - if (!target_function.HasCode()) {
|
| - *error = Compiler::CompileFunction(target_function);
|
| - if (!error->IsNull()) {
|
| - return NULL;
|
| - }
|
| - }
|
| - ASSERT(!target_function.HasOptimizedCode());
|
| - Code& code = Code::Handle(target_function.unoptimized_code());
|
| +CodeBreakpoint* Debugger::MakeCodeBreakpoint(SourceBreakpoint* src_bpt) {
|
| + Function& func = Function::Handle(src_bpt->function());
|
| + ASSERT(func.HasCode());
|
| + ASSERT(!func.HasOptimizedCode());
|
| + Code& code = Code::Handle(func.unoptimized_code());
|
| ASSERT(!code.IsNull());
|
| PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
|
| + intptr_t requested_token_index = src_bpt->token_index();
|
| for (int i = 0; i < desc.Length(); i++) {
|
| - if (desc.TokenIndex(i) < token_index) {
|
| + if (desc.TokenIndex(i) < requested_token_index) {
|
| continue;
|
| }
|
| - Breakpoint* bpt = GetBreakpoint(desc.PC(i));
|
| + CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
|
| + // We should only ever have one code breakpoint at the same address.
|
| + // If we find an existing breakpoint, it must be an internal one which
|
| + // is used for stepping.
|
| if (bpt != NULL) {
|
| - // Found existing breakpoint.
|
| + ASSERT(bpt->src_bpt() == NULL);
|
| + bpt->set_src_bpt(src_bpt);
|
| return bpt;
|
| }
|
| +
|
| PcDescriptors::Kind kind = desc.DescriptorKind(i);
|
| if ((kind == PcDescriptors::kIcCall) ||
|
| (kind == PcDescriptors::kFuncCall) ||
|
| (kind == PcDescriptors::kReturn)) {
|
| - bpt = new Breakpoint(target_function, i);
|
| - bpt->PatchCode();
|
| - RegisterBreakpoint(bpt);
|
| + bpt = new CodeBreakpoint(func, i);
|
| + bpt->set_src_bpt(src_bpt);
|
| if (verbose) {
|
| - OS::Print("Setting breakpoint at '%s' line %d (PC %p)\n",
|
| + OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n",
|
| + String::Handle(func.name()).ToCString(),
|
| String::Handle(bpt->SourceUrl()).ToCString(),
|
| bpt->LineNumber(),
|
| bpt->pc());
|
| }
|
| + RegisterCodeBreakpoint(bpt);
|
| return bpt;
|
| }
|
| }
|
| @@ -497,21 +557,67 @@
|
| }
|
|
|
|
|
| -void Debugger::UnsetBreakpoint(Breakpoint* bpt) {
|
| - bpt->SetActive(false);
|
| +SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function,
|
| + intptr_t token_index) {
|
| + if ((token_index < target_function.token_index()) ||
|
| + (target_function.end_token_index() <= token_index)) {
|
| + // The given token position is not within the target function.
|
| + return NULL;
|
| + }
|
| + SourceBreakpoint* bpt = GetSourceBreakpoint(target_function, token_index);
|
| + if (bpt != NULL) {
|
| + // A breakpoint for this location already exists, return it.
|
| + return bpt;
|
| + }
|
| + bpt = new SourceBreakpoint(target_function, token_index);
|
| + RegisterSourceBreakpoint(bpt);
|
| + if (verbose && !target_function.HasCode()) {
|
| + OS::Print("Registering breakpoint for uncompiled function '%s'"
|
| + " (%s:%d)\n",
|
| + String::Handle(target_function.name()).ToCString(),
|
| + String::Handle(bpt->SourceUrl()).ToCString(),
|
| + bpt->LineNumber());
|
| + }
|
| +
|
| + if (target_function.HasCode()) {
|
| + CodeBreakpoint* cbpt = MakeCodeBreakpoint(bpt);
|
| + if (cbpt == NULL) {
|
| + if (verbose) {
|
| + OS::Print("Failed to set breakpoint at '%s' line %d\n",
|
| + String::Handle(bpt->SourceUrl()).ToCString(),
|
| + bpt->LineNumber());
|
| + }
|
| + }
|
| + }
|
| + bpt->Enable();
|
| + return bpt;
|
| }
|
|
|
|
|
| -Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function,
|
| - Error* error) {
|
| +void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) {
|
| + CodeBreakpoint* cbpt = code_breakpoints_;
|
| + while (cbpt != NULL) {
|
| + if (bpt == cbpt->src_bpt()) {
|
| + if (bpt->IsEnabled()) {
|
| + cbpt->Enable();
|
| + } else {
|
| + cbpt->Disable();
|
| + }
|
| + }
|
| + cbpt = cbpt->next();
|
| + }
|
| +}
|
| +
|
| +
|
| +SourceBreakpoint* Debugger::SetBreakpointAtEntry(
|
| + const Function& target_function) {
|
| ASSERT(!target_function.IsNull());
|
| - return SetBreakpoint(target_function, target_function.token_index(), error);
|
| + return SetBreakpoint(target_function, target_function.token_index());
|
| }
|
|
|
|
|
| -Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
|
| - intptr_t line_number,
|
| - Error* error) {
|
| +SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
|
| + intptr_t line_number) {
|
| Library& lib = Library::Handle();
|
| Script& script = Script::Handle();
|
| lib = isolate_->object_store()->registered_libraries();
|
| @@ -523,19 +629,31 @@
|
| lib = lib.next_registered();
|
| }
|
| if (script.IsNull()) {
|
| + if (verbose) {
|
| + OS::Print("Failed to find script with url '%s'\n",
|
| + script_url.ToCString());
|
| + }
|
| return NULL;
|
| }
|
| intptr_t token_index_at_line = script.TokenIndexAtLine(line_number);
|
| if (token_index_at_line < 0) {
|
| // Script does not contain the given line number.
|
| + if (verbose) {
|
| + OS::Print("Script '%s' does not contain line number %d\n",
|
| + script_url.ToCString(), line_number);
|
| + }
|
| return NULL;
|
| }
|
| const Function& func =
|
| Function::Handle(lib.LookupFunctionInScript(script, token_index_at_line));
|
| if (func.IsNull()) {
|
| + if (verbose) {
|
| + OS::Print("No executable code at line %d in '%s'\n",
|
| + line_number, script_url.ToCString());
|
| + }
|
| return NULL;
|
| }
|
| - return SetBreakpoint(func, token_index_at_line, error);
|
| + return SetBreakpoint(func, token_index_at_line);
|
| }
|
|
|
|
|
| @@ -641,15 +759,20 @@
|
|
|
| void Debugger::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
| ASSERT(visitor != NULL);
|
| - Breakpoint* bpt = this->breakpoints_;
|
| + SourceBreakpoint* bpt = src_breakpoints_;
|
| while (bpt != NULL) {
|
| bpt->VisitObjectPointers(visitor);
|
| bpt = bpt->next();
|
| }
|
| + CodeBreakpoint* cbpt = code_breakpoints_;
|
| + while (cbpt != NULL) {
|
| + cbpt->VisitObjectPointers(visitor);
|
| + cbpt = cbpt->next();
|
| + }
|
| }
|
|
|
|
|
| -static void DefaultBreakpointHandler(Breakpoint* bpt, StackTrace* stack) {
|
| +static void DefaultBreakpointHandler(SourceBreakpoint* bpt, StackTrace* stack) {
|
| String& var_name = String::Handle();
|
| Instance& value = Instance::Handle();
|
| for (intptr_t i = 0; i < stack->Length(); i++) {
|
| @@ -680,11 +803,11 @@
|
| DartFrameIterator iterator;
|
| DartFrame* frame = iterator.NextFrame();
|
| ASSERT(frame != NULL);
|
| - Breakpoint* bpt = GetBreakpoint(frame->pc());
|
| + CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc());
|
| ASSERT(bpt != NULL);
|
| if (verbose) {
|
| OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n",
|
| - bpt->is_temporary() ? "hit temp" : "hit user",
|
| + bpt->IsInternal() ? "hit internal" : "hit user",
|
| bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?",
|
| bpt ? bpt->LineNumber() : 0,
|
| frame->pc());
|
| @@ -701,11 +824,12 @@
|
|
|
| resume_action_ = kContinue;
|
| if (bp_handler_ != NULL) {
|
| - (*bp_handler_)(bpt, stack_trace);
|
| + SourceBreakpoint* src_bpt = bpt->src_bpt();
|
| + (*bp_handler_)(src_bpt, stack_trace);
|
| }
|
|
|
| if (resume_action_ == kContinue) {
|
| - RemoveTemporaryBreakpoints();
|
| + RemoveInternalBreakpoints();
|
| } else if (resume_action_ == kStepOver) {
|
| Function& func = Function::Handle(bpt->function());
|
| if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) {
|
| @@ -713,12 +837,12 @@
|
| if (stack_trace->Length() > 1) {
|
| ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
|
| func = caller->DartFunction().raw();
|
| - RemoveTemporaryBreakpoints();
|
| + RemoveInternalBreakpoints();
|
| }
|
| }
|
| InstrumentForStepping(func);
|
| } else if (resume_action_ == kStepInto) {
|
| - RemoveTemporaryBreakpoints();
|
| + RemoveInternalBreakpoints();
|
| if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) {
|
| int num_args, num_named_args;
|
| uword target;
|
| @@ -748,8 +872,8 @@
|
| }
|
| } else {
|
| ASSERT(resume_action_ == kStepOut);
|
| - // Set temporary breakpoints in the caller.
|
| - RemoveTemporaryBreakpoints();
|
| + // Set stepping breakpoints in the caller.
|
| + RemoveInternalBreakpoints();
|
| if (stack_trace->Length() > 1) {
|
| ActivationFrame* caller = stack_trace->ActivationFrameAt(1);
|
| InstrumentForStepping(caller->DartFunction());
|
| @@ -768,9 +892,26 @@
|
| }
|
|
|
|
|
| -Breakpoint* Debugger::GetBreakpoint(uword breakpoint_address) {
|
| - Breakpoint* bpt = this->breakpoints_;
|
| +// TODO(hausner): handle closure functions.
|
| +void Debugger::NotifyCompilation(const Function& func) {
|
| + SourceBreakpoint* bpt = src_breakpoints_;
|
| while (bpt != NULL) {
|
| + if (func.raw() == bpt->function()) {
|
| + if (verbose) {
|
| + OS::Print("Enable latent breakpoint for function '%s'\n",
|
| + String::Handle(func.name()).ToCString());
|
| + }
|
| + CodeBreakpoint* cbpt = MakeCodeBreakpoint(bpt);
|
| + bpt->Enable();
|
| + }
|
| + bpt = bpt->next();
|
| + }
|
| +}
|
| +
|
| +
|
| +CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) {
|
| + CodeBreakpoint* bpt = code_breakpoints_;
|
| + while (bpt != NULL) {
|
| if (bpt->pc() == breakpoint_address) {
|
| return bpt;
|
| }
|
| @@ -780,18 +921,21 @@
|
| }
|
|
|
|
|
| -void Debugger::RemoveBreakpoint(Breakpoint* bpt) {
|
| - ASSERT(breakpoints_ != NULL);
|
| - Breakpoint* prev_bpt = NULL;
|
| - Breakpoint* curr_bpt = breakpoints_;
|
| +// Remove and delete the source breakpoint bpt and its associated
|
| +// code breakpoints.
|
| +void Debugger::RemoveBreakpoint(SourceBreakpoint* bpt) {
|
| + ASSERT(src_breakpoints_ != NULL);
|
| + SourceBreakpoint* prev_bpt = NULL;
|
| + SourceBreakpoint* curr_bpt = src_breakpoints_;
|
| while (curr_bpt != NULL) {
|
| if (bpt == curr_bpt) {
|
| if (prev_bpt == NULL) {
|
| - breakpoints_ = breakpoints_->next();
|
| + src_breakpoints_ = src_breakpoints_->next();
|
| } else {
|
| prev_bpt->set_next(curr_bpt->next());
|
| }
|
| - UnsetBreakpoint(bpt);
|
| + // Remove the code breakpoints associated with the source breakpoint.
|
| + RemoveCodeBreakpoints(bpt);
|
| delete bpt;
|
| return;
|
| }
|
| @@ -802,19 +946,21 @@
|
| }
|
|
|
|
|
| -void Debugger::RemoveTemporaryBreakpoints() {
|
| - Breakpoint* prev_bpt = NULL;
|
| - Breakpoint* curr_bpt = breakpoints_;
|
| +// Remove and delete the code breakpoints that are associated with given
|
| +// source breakpoint bpt. If bpt is null, remove the internal breakpoints.
|
| +void Debugger::RemoveCodeBreakpoints(SourceBreakpoint* src_bpt) {
|
| + CodeBreakpoint* prev_bpt = NULL;
|
| + CodeBreakpoint* curr_bpt = code_breakpoints_;
|
| while (curr_bpt != NULL) {
|
| - if (curr_bpt->is_temporary()) {
|
| + if (curr_bpt->src_bpt() == src_bpt) {
|
| if (prev_bpt == NULL) {
|
| - breakpoints_ = breakpoints_->next();
|
| + code_breakpoints_ = code_breakpoints_->next();
|
| } else {
|
| prev_bpt->set_next(curr_bpt->next());
|
| }
|
| - Breakpoint* temp_bpt = curr_bpt;
|
| + CodeBreakpoint* temp_bpt = curr_bpt;
|
| curr_bpt = curr_bpt->next();
|
| - UnsetBreakpoint(temp_bpt);
|
| + temp_bpt->Disable();
|
| delete temp_bpt;
|
| } else {
|
| prev_bpt = curr_bpt;
|
| @@ -824,9 +970,16 @@
|
| }
|
|
|
|
|
| -Breakpoint* Debugger::GetBreakpointByFunction(const Function& func,
|
| - intptr_t token_index) {
|
| - Breakpoint* bpt = this->breakpoints_;
|
| +// Remove and delete all breakpoints that are not associated with a
|
| +// user-defined source breakpoint.
|
| +void Debugger::RemoveInternalBreakpoints() {
|
| + RemoveCodeBreakpoints(NULL);
|
| +}
|
| +
|
| +
|
| +SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func,
|
| + intptr_t token_index) {
|
| + SourceBreakpoint* bpt = src_breakpoints_;
|
| while (bpt != NULL) {
|
| if ((bpt->function() == func.raw()) &&
|
| (bpt->token_index() == token_index)) {
|
| @@ -838,11 +991,17 @@
|
| }
|
|
|
|
|
| -void Debugger::RegisterBreakpoint(Breakpoint* bpt) {
|
| +void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) {
|
| ASSERT(bpt->next() == NULL);
|
| - bpt->set_next(this->breakpoints_);
|
| - this->breakpoints_ = bpt;
|
| + bpt->set_next(src_breakpoints_);
|
| + src_breakpoints_ = bpt;
|
| }
|
|
|
|
|
| +void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
|
| + ASSERT(bpt->next() == NULL);
|
| + bpt->set_next(code_breakpoints_);
|
| + code_breakpoints_ = bpt;
|
| +}
|
| +
|
| } // namespace dart
|
|
|