| Index: runtime/vm/debugger.cc
|
| ===================================================================
|
| --- runtime/vm/debugger.cc (revision 3467)
|
| +++ runtime/vm/debugger.cc (working copy)
|
| @@ -25,6 +25,7 @@
|
| : function_(func.raw()),
|
| pc_desc_index_(pc_desc_index),
|
| pc_(0),
|
| + saved_bytes_(0),
|
| line_number_(-1),
|
| next_(NULL) {
|
| Code& code = Code::Handle(func.code());
|
| @@ -230,6 +231,21 @@
|
| }
|
|
|
|
|
| +Debugger::~Debugger() {
|
| + ASSERT(breakpoints_ == NULL);
|
| +}
|
| +
|
| +
|
| +void Debugger::Shutdown() {
|
| + while (breakpoints_ != NULL) {
|
| + Breakpoint* bpt = breakpoints_;
|
| + breakpoints_ = breakpoints_->next();
|
| + UnsetBreakpoint(bpt);
|
| + delete bpt;
|
| + }
|
| +}
|
| +
|
| +
|
| bool Debugger::IsActive() {
|
| // TODO(hausner): The code generator uses this function to prevent
|
| // generation of optimized code when Dart code is being debugged.
|
| @@ -274,9 +290,8 @@
|
| }
|
|
|
|
|
| -// TODO(hausner): Need to check whether a breakpoint for the
|
| -// location already exists and either return the existing breakpoint
|
| -// or return an error.
|
| +// 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) {
|
| if ((token_index < target_function.token_index()) ||
|
| @@ -297,14 +312,32 @@
|
| PcDescriptors::Kind kind = desc.DescriptorKind(i);
|
| Breakpoint* bpt = NULL;
|
| if (kind == PcDescriptors::kIcCall) {
|
| + bpt = GetBreakpoint(desc.PC(i));
|
| + if (bpt != NULL) {
|
| + // There is an existing breakpoint at this token position.
|
| + break;
|
| + }
|
| + bpt = new Breakpoint(target_function, i);
|
| + String& func_name = String::Handle();
|
| + int num_args, num_named_args;
|
| + CodePatcher::GetInstanceCallAt(desc.PC(i),
|
| + &func_name, &num_args, &num_named_args, &bpt->saved_bytes_);
|
| CodePatcher::PatchInstanceCallAt(
|
| desc.PC(i), StubCode::BreakpointDynamicEntryPoint());
|
| - bpt = new Breakpoint(target_function, i);
|
| + RegisterBreakpoint(bpt);
|
| } else if (kind == PcDescriptors::kOther) {
|
| if ((desc.TokenIndex(i) > 0) && CodePatcher::IsDartCall(desc.PC(i))) {
|
| + bpt = GetBreakpoint(desc.PC(i));
|
| + if (bpt != NULL) {
|
| + // There is an existing breakpoint at this token position.
|
| + break;
|
| + }
|
| + bpt = new Breakpoint(target_function, i);
|
| + Function& func = Function::Handle();
|
| + CodePatcher::GetStaticCallAt(desc.PC(i), &func, &bpt->saved_bytes_);
|
| CodePatcher::PatchStaticCallAt(
|
| desc.PC(i), StubCode::BreakpointStaticEntryPoint());
|
| - bpt = new Breakpoint(target_function, i);
|
| + RegisterBreakpoint(bpt);
|
| }
|
| }
|
| if (bpt != NULL) {
|
| @@ -314,7 +347,6 @@
|
| bpt->LineNumber(),
|
| bpt->pc());
|
| }
|
| - AddBreakpoint(bpt);
|
| return bpt;
|
| }
|
| }
|
| @@ -322,6 +354,22 @@
|
| }
|
|
|
|
|
| +void Debugger::UnsetBreakpoint(Breakpoint* bpt) {
|
| + const Function& func = Function::Handle(bpt->function());
|
| + const Code& code = Code::Handle(func.code());
|
| + PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
|
| + intptr_t desc_index = bpt->pc_desc_index();
|
| + ASSERT(desc_index < desc.Length());
|
| + ASSERT(bpt->pc() == desc.PC(desc_index));
|
| + PcDescriptors::Kind kind = desc.DescriptorKind(desc_index);
|
| + if (kind == PcDescriptors::kIcCall) {
|
| + CodePatcher::PatchInstanceCallAt(desc.PC(desc_index), bpt->saved_bytes_);
|
| + } else {
|
| + CodePatcher::PatchStaticCallAt(desc.PC(desc_index), bpt->saved_bytes_);
|
| + }
|
| +}
|
| +
|
| +
|
| Breakpoint* Debugger::SetBreakpointAtEntry(const Function& target_function) {
|
| ASSERT(!target_function.IsNull());
|
| return SetBreakpoint(target_function, target_function.token_index());
|
| @@ -445,7 +493,43 @@
|
| }
|
|
|
|
|
| -void Debugger::AddBreakpoint(Breakpoint* bpt) {
|
| +void Debugger::RemoveBreakpoint(Breakpoint* bpt) {
|
| + ASSERT(breakpoints_ != NULL);
|
| + Breakpoint* prev_bpt = NULL;
|
| + Breakpoint* curr_bpt = breakpoints_;
|
| + while (curr_bpt != NULL) {
|
| + if (bpt == curr_bpt) {
|
| + if (prev_bpt == NULL) {
|
| + breakpoints_ = breakpoints_->next();
|
| + } else {
|
| + prev_bpt->set_next(curr_bpt->next());
|
| + }
|
| + UnsetBreakpoint(bpt);
|
| + delete bpt;
|
| + return;
|
| + }
|
| + prev_bpt = curr_bpt;
|
| + curr_bpt = curr_bpt->next();
|
| + }
|
| + // bpt is not a registered breakpoint, nothing to do.
|
| +}
|
| +
|
| +
|
| +Breakpoint* Debugger::GetBreakpointByFunction(const Function& func,
|
| + intptr_t token_index) {
|
| + Breakpoint* bpt = this->breakpoints_;
|
| + while (bpt != NULL) {
|
| + if ((bpt->function() == func.raw()) &&
|
| + (bpt->token_index() == token_index)) {
|
| + return bpt;
|
| + }
|
| + bpt = bpt->next();
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void Debugger::RegisterBreakpoint(Breakpoint* bpt) {
|
| ASSERT(bpt->next() == NULL);
|
| bpt->set_next(this->breakpoints_);
|
| this->breakpoints_ = bpt;
|
|
|