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

Unified Diff: runtime/vm/debugger.cc

Issue 9581013: Splitting debugger breakpoints into two parts (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 10 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
===================================================================
--- 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

Powered by Google App Engine
This is Rietveld 408576698