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

Unified Diff: runtime/vm/debugger.cc

Issue 26255004: Allow the debugger to inspect local variables from optimized and (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 2 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
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/debugger_api_impl_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/debugger.cc
===================================================================
--- runtime/vm/debugger.cc (revision 28466)
+++ runtime/vm/debugger.cc (working copy)
@@ -10,6 +10,7 @@
#include "vm/code_patcher.h"
#include "vm/compiler.h"
#include "vm/dart_entry.h"
+#include "vm/deopt_instructions.h"
#include "vm/flags.h"
#include "vm/globals.h"
#include "vm/longjump.h"
@@ -26,6 +27,8 @@
namespace dart {
DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages");
+DEFINE_FLAG(bool, use_new_stacktrace, true,
+ "Use new stacktrace creation");
Debugger::EventHandler* Debugger::event_handler_ = NULL;
@@ -133,6 +136,8 @@
pc_desc_index_(-1),
line_number_(-1),
context_level_(-1),
+ deopt_frame_(Array::ZoneHandle()),
+ deopt_frame_offset_(0),
vars_initialized_(false),
var_descriptors_(LocalVarDescriptors::ZoneHandle()),
desc_indices_(8),
@@ -245,7 +250,7 @@
intptr_t ActivationFrame::TokenPos() {
if (token_pos_ < 0) {
GetPcDescriptors();
- for (int i = 0; i < pc_desc_.Length(); i++) {
+ for (intptr_t i = 0; i < pc_desc_.Length(); i++) {
if (pc_desc_.PC(i) == pc_) {
pc_desc_index_ = i;
token_pos_ = pc_desc_.TokenPos(i);
@@ -321,7 +326,7 @@
ASSERT(activation_token_pos >= 0);
GetVarDescriptors();
intptr_t var_desc_len = var_descriptors_.Length();
- for (int cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
+ for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
RawLocalVarDescriptors::VarInfo var_info;
var_descriptors_.GetInfo(cur_idx, &var_info);
if ((var_info.kind == RawLocalVarDescriptors::kContextLevel) &&
@@ -347,27 +352,50 @@
RawContext* ActivationFrame::GetSavedEntryContext(const Context& ctx) {
GetVarDescriptors();
intptr_t var_desc_len = var_descriptors_.Length();
- for (int i = 0; i < var_desc_len; i++) {
+ for (intptr_t i = 0; i < var_desc_len; i++) {
RawLocalVarDescriptors::VarInfo var_info;
var_descriptors_.GetInfo(i, &var_info);
if (var_info.kind == RawLocalVarDescriptors::kSavedEntryContext) {
- return reinterpret_cast<RawContext*>(GetLocalVarValue(var_info.index));
+ return GetLocalContextVar(var_info.index);
}
}
return ctx.raw();
}
+RawContext* ActivationFrame::GetSavedEntryContextNew() {
+ if (ctx_.IsNull()) {
+ // We have bailed on providing a context for this frame. Bail for
+ // the caller as well.
+ return Context::null();
+ }
+
+ // Attempt to find a saved context.
+ GetVarDescriptors();
+ intptr_t var_desc_len = var_descriptors_.Length();
+ for (intptr_t i = 0; i < var_desc_len; i++) {
+ RawLocalVarDescriptors::VarInfo var_info;
+ var_descriptors_.GetInfo(i, &var_info);
+ if (var_info.kind == RawLocalVarDescriptors::kSavedEntryContext) {
+ return GetLocalContextVar(var_info.index);
+ }
+ }
+
+ // No saved context. Return the current context.
+ return ctx_.raw();
+}
+
+
// Get the saved context if the callee of this activation frame is a
// closure function.
RawContext* ActivationFrame::GetSavedCurrentContext() {
GetVarDescriptors();
intptr_t var_desc_len = var_descriptors_.Length();
- for (int i = 0; i < var_desc_len; i++) {
+ for (intptr_t i = 0; i < var_desc_len; i++) {
RawLocalVarDescriptors::VarInfo var_info;
var_descriptors_.GetInfo(i, &var_info);
if (var_info.kind == RawLocalVarDescriptors::kSavedCurrentContext) {
- return reinterpret_cast<RawContext*>(GetLocalVarValue(var_info.index));
+ return GetLocalContextVar(var_info.index);
}
}
return Context::null();
@@ -380,7 +408,9 @@
Array& handled_types = Array::Handle();
AbstractType& type = Type::Handle();
const TypeArguments& no_instantiator = TypeArguments::Handle();
- for (int frame_index = 0; frame_index < UnfilteredLength(); frame_index++) {
+ for (intptr_t frame_index = 0;
+ frame_index < UnfilteredLength();
+ frame_index++) {
ActivationFrame* frame = UnfilteredFrameAt(frame_index);
intptr_t try_index = frame->TryIndex();
if (try_index < 0) continue;
@@ -393,7 +423,7 @@
ASSERT(num_handlers_checked <= handlers.Length());
handled_types = handlers.GetHandledTypes(try_index);
const intptr_t num_types = handled_types.Length();
- for (int k = 0; k < num_types; k++) {
+ for (intptr_t k = 0; k < num_types; k++) {
type ^= handled_types.At(k);
ASSERT(!type.IsNull());
// Uninstantiated types are not added to ExceptionHandlers data.
@@ -421,7 +451,7 @@
// Rather than potentially displaying incorrect values, we
// pretend that there are no variables in the frame.
// We should be more clever about this in the future.
- if (code().is_optimized()) {
+ if (!FLAG_use_new_stacktrace && code().is_optimized()) {
vars_initialized_ = true;
return;
}
@@ -436,7 +466,7 @@
GrowableArray<String*> var_names(8);
intptr_t var_desc_len = var_descriptors_.Length();
- for (int cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
+ for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
ASSERT(var_names.length() == desc_indices_.length());
RawLocalVarDescriptors::VarInfo var_info;
var_descriptors_.GetInfo(cur_idx, &var_info);
@@ -462,7 +492,7 @@
String& var_name = String::Handle(var_descriptors_.GetName(cur_idx));
intptr_t indices_len = desc_indices_.length();
bool name_match_found = false;
- for (int i = 0; i < indices_len; i++) {
+ for (intptr_t i = 0; i < indices_len; i++) {
if (var_name.Equals(*var_names[i])) {
// Found two local variables with the same name. Now determine
// which one is shadowed.
@@ -500,7 +530,32 @@
return desc_indices_.length();
}
+// TODO(hausner): Handle captured variables.
+RawObject* ActivationFrame::GetLocalVar(intptr_t slot_index) {
+ if (deopt_frame_.IsNull()) {
+ uword var_address = fp() + slot_index * kWordSize;
+ return reinterpret_cast<RawObject*>(
+ *reinterpret_cast<uword*>(var_address));
+ } else {
+ return deopt_frame_.At(deopt_frame_offset_ + slot_index);
+ }
+}
+
+RawInstance* ActivationFrame::GetLocalInstanceVar(intptr_t slot_index) {
+ Instance& instance = Instance::Handle();
+ instance ^= GetLocalVar(slot_index);
+ return instance.raw();
+}
+
+
+RawContext* ActivationFrame::GetLocalContextVar(intptr_t slot_index) {
+ Context& context = Context::Handle();
+ context ^= GetLocalVar(slot_index);
+ return context.raw();
+}
+
+
void ActivationFrame::VariableAt(intptr_t i,
String* name,
intptr_t* token_pos,
@@ -519,7 +574,7 @@
*end_pos = var_info.end_pos;
ASSERT(value != NULL);
if (var_info.kind == RawLocalVarDescriptors::kStackVar) {
- *value = GetLocalVarValue(var_info.index);
+ *value = GetLocalInstanceVar(var_info.index);
} else {
ASSERT(var_info.kind == RawLocalVarDescriptors::kContextVar);
// The context level at the PC/token index of this activation frame.
@@ -566,7 +621,7 @@
String& var_name = String::Handle();
Instance& value = Instance::Handle();
const Array& list = Array::Handle(Array::New(2 * num_variables));
- for (int i = 0; i < num_variables; i++) {
+ for (intptr_t i = 0; i < num_variables; i++) {
intptr_t ignore;
VariableAt(i, &var_name, &ignore, &ignore, &value);
list.SetAt(2 * i, var_name);
@@ -762,7 +817,7 @@
intptr_t RemoteObjectCache::AddObject(const Object& obj) {
intptr_t len = objs_->Length();
- for (int i = 0; i < len; i++) {
+ for (intptr_t i = 0; i < len; i++) {
if (objs_->At(i) == obj.raw()) {
return i;
}
@@ -918,7 +973,7 @@
Code& code = Code::Handle(target_function.unoptimized_code());
ASSERT(!code.IsNull());
PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
- for (int i = 0; i < desc.Length(); i++) {
+ for (intptr_t i = 0; i < desc.Length(); i++) {
CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
if (bpt != NULL) {
// There is already a breakpoint for this address. Make sure
@@ -945,7 +1000,159 @@
}
+static void PrintStackTraceError(const char* message,
+ ActivationFrame* current_activation,
+ ActivationFrame* callee_activation) {
+ const Function& current = current_activation->function();
+ const Function& callee = callee_activation->function();
+ const Script& script =
+ Script::Handle(Class::Handle(current.Owner()).script());
+ intptr_t line, col;
+ script.GetTokenLocation(current_activation->TokenPos(), &line, &col);
+ OS::PrintErr("Error building stack trace: %s:"
+ "current function '%s' callee_function '%s' "
+ " line %" Pd " column %" Pd "\n",
+ message,
+ current.ToFullyQualifiedCString(),
+ callee.ToFullyQualifiedCString(),
+ line, col);
+}
+
+
+ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate,
+ uword pc,
+ StackFrame* frame,
+ const Code& code,
+ bool optimized,
+ ActivationFrame* callee_activation,
+ const Context& entry_ctx) {
+ // We never provide both a callee activation and an entry context.
+ ASSERT((callee_activation == NULL) || entry_ctx.IsNull());
+ ActivationFrame* activation =
+ new ActivationFrame(pc, frame->fp(), frame->sp(), code);
+
+ // Recover the context for this frame.
+ if (optimized) {
+ // Bail out for optimized frames for now.
+ activation->SetContext(Context::Handle(isolate));
+
+ } else if (callee_activation == NULL) {
+ // No callee. Use incoming entry context. Could be from
+ // isolate's top context or from an entry frame.
+ activation->SetContext(entry_ctx);
+
+ } else if (callee_activation->function().IsClosureFunction()) {
+ // If the callee is a closure, we should have stored the context
+ // in the current frame before making the call.
+ const Context& closure_call_ctx =
+ Context::Handle(isolate, activation->GetSavedCurrentContext());
+ activation->SetContext(closure_call_ctx);
+
+ // Sometimes there is no saved context. This is a bug.
+ // https://code.google.com/p/dart/issues/detail?id=12767
+ if (FLAG_verbose_debug && closure_call_ctx.IsNull()) {
+ PrintStackTraceError(
+ "Expected to find saved context for call to closure function",
+ activation, callee_activation);
+ }
+
+ } else {
+ // Use the context provided by our callee. This is either the
+ // callee's context or a context that was saved in the callee's
+ // frame.
+ const Context& callee_ctx =
+ Context::Handle(isolate, callee_activation->GetSavedEntryContextNew());
+ activation->SetContext(callee_ctx);
+ }
+ return activation;
+}
+
+
+RawArray* Debugger::DeoptimizeToArray(Isolate* isolate,
+ StackFrame* frame,
+ const Code& code) {
+ ASSERT(code.is_optimized());
+
+ // Create the DeoptContext for this deoptimization.
+ DeoptContext* deopt_context =
+ new DeoptContext(frame, code,
+ DeoptContext::kDestIsAllocated,
+ NULL, NULL);
+ isolate->set_deopt_context(deopt_context);
+
+ deopt_context->FillDestFrame();
+ deopt_context->MaterializeDeferredObjects();
+ const Array& dest_frame = Array::Handle(deopt_context->DestFrameAsArray());
+
+ isolate->set_deopt_context(NULL);
+ delete deopt_context;
+
+ return dest_frame.raw();
+}
+
+
+DebuggerStackTrace* Debugger::CollectStackTraceNew() {
+ Isolate* isolate = Isolate::Current();
+ DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
+ StackFrameIterator iterator(false);
+ ActivationFrame* current_activation = NULL;
+ Context& entry_ctx = Context::Handle(isolate->top_context());
+ Code& code = Code::Handle(isolate);
+ Code& inlined_code = Code::Handle(isolate);
+ Array& deopt_frame = Array::Handle(isolate);
+
+ for (StackFrame* frame = iterator.NextFrame();
+ frame != NULL;
+ frame = iterator.NextFrame()) {
+ ASSERT(frame->IsValid());
+ if (frame->IsEntryFrame()) {
+ current_activation = NULL;
+ entry_ctx = reinterpret_cast<EntryFrame*>(frame)->SavedContext();
+
+ } else if (frame->IsDartFrame()) {
+ code = frame->LookupDartCode();
+ if (code.is_optimized()) {
+ deopt_frame = DeoptimizeToArray(isolate, frame, code);
+ for (InlinedFunctionsIterator it(code, frame->pc());
+ !it.Done();
+ it.Advance()) {
+ inlined_code = it.code();
+ intptr_t deopt_frame_offset = it.GetDeoptFpOffset();
+ current_activation = CollectDartFrame(isolate,
+ it.pc(),
+ frame,
+ inlined_code,
+ true,
+ current_activation,
+ entry_ctx);
+ current_activation->SetDeoptFrame(deopt_frame, deopt_frame_offset);
+ stack_trace->AddActivation(current_activation);
+ entry_ctx = Context::null(); // Only use entry context once.
+ }
+ } else {
+ current_activation = CollectDartFrame(isolate,
+ frame->pc(),
+ frame,
+ code,
+ false,
+ current_activation,
+ entry_ctx);
+ stack_trace->AddActivation(current_activation);
+ entry_ctx = Context::null(); // Only use entry context once.
+ }
+ }
+ }
+ return stack_trace;
+}
+
+
+
DebuggerStackTrace* Debugger::CollectStackTrace() {
+ if (FLAG_use_new_stacktrace) {
+ // Guard new stack trace generation under a flag in case there are
+ // problems rolling it out.
+ return CollectStackTraceNew();
+ }
Isolate* isolate = Isolate::Current();
DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
Context& ctx = Context::Handle(isolate->top_context());
@@ -1103,7 +1310,7 @@
intptr_t best_fit = INT_MAX;
uword lowest_pc = kUwordMax;
intptr_t lowest_pc_index = -1;
- for (int i = 0; i < desc.Length(); i++) {
+ for (intptr_t i = 0; i < desc.Length(); i++) {
intptr_t desc_token_pos = desc.TokenPos(i);
ASSERT(desc_token_pos >= 0);
if (desc_token_pos < first_token_pos) {
@@ -1149,7 +1356,7 @@
Code& code = Code::Handle(func.unoptimized_code());
ASSERT(!code.IsNull());
PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
- for (int i = 0; i < desc.Length(); i++) {
+ for (intptr_t i = 0; i < desc.Length(); i++) {
intptr_t desc_token_pos = desc.TokenPos(i);
if ((desc_token_pos == token_pos) && IsSafePoint(desc.DescriptorKind(i))) {
CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i));
@@ -1276,7 +1483,7 @@
Script& script = Script::Handle(isolate_);
const GrowableObjectArray& libs =
GrowableObjectArray::Handle(isolate_->object_store()->libraries());
- for (int i = 0; i < libs.Length(); i++) {
+ for (intptr_t i = 0; i < libs.Length(); i++) {
lib ^= libs.At(i);
script = lib.LookupScript(script_url);
if (!script.IsNull()) {
@@ -1423,7 +1630,7 @@
// Iterate over fields in class hierarchy to count all instance fields.
while (!cls.IsNull()) {
fields = cls.fields();
- for (int i = 0; i < fields.Length(); i++) {
+ for (intptr_t i = 0; i < fields.Length(); i++) {
field ^= fields.At(i);
if (!field.is_static()) {
field_name = field.name();
@@ -1445,7 +1652,7 @@
Field& field = Field::Handle();
String& field_name = String::Handle();
Object& field_value = Object::Handle();
- for (int i = 0; i < fields.Length(); i++) {
+ for (intptr_t i = 0; i < fields.Length(); i++) {
field ^= fields.At(i);
if (field.is_static()) {
field_name = field.name();
@@ -1505,7 +1712,7 @@
CollectLibraryFields(field_list, lib, prefix_name, true);
Library& imported = Library::Handle(isolate_);
intptr_t num_imports = lib.num_imports();
- for (int i = 0; i < num_imports; i++) {
+ for (intptr_t i = 0; i < num_imports; i++) {
imported = lib.ImportLibraryAt(i);
ASSERT(!imported.IsNull());
CollectLibraryFields(field_list, imported, prefix_name, false);
@@ -1517,7 +1724,7 @@
prefix_name = prefix.name();
ASSERT(!prefix_name.IsNull());
prefix_name = String::Concat(prefix_name, Symbols::Dot());
- for (int i = 0; i < prefix.num_imports(); i++) {
+ for (intptr_t i = 0; i < prefix.num_imports(); i++) {
imported = prefix.GetLibrary(i);
CollectLibraryFields(field_list, imported, prefix_name, false);
}
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/debugger_api_impl_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698