Chromium Code Reviews| Index: runtime/vm/debugger.cc |
| =================================================================== |
| --- runtime/vm/debugger.cc (revision 8858) |
| +++ runtime/vm/debugger.cc (working copy) |
| @@ -106,13 +106,19 @@ |
| } |
| -ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp) |
| +ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp, |
| + const Context& ctx) |
| : pc_(pc), fp_(fp), sp_(sp), |
| + ctx_(Context::ZoneHandle(ctx.raw())), |
| function_(Function::ZoneHandle()), |
| token_index_(-1), |
| + pc_desc_index_(-1), |
| line_number_(-1), |
| + context_level_(-1), |
| + vars_initialized_(false), |
| var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| - desc_indices_(8) { |
| + desc_indices_(8), |
|
regis
2012/06/19 18:14:41
We usually avoid setting an initial size.
hausner
2012/06/19 18:49:41
It avoids reallocating a couple of times in the ve
|
| + pc_desc_(PcDescriptors::ZoneHandle()) { |
| } |
| @@ -167,16 +173,26 @@ |
| } |
| -intptr_t ActivationFrame::TokenIndex() { |
| - if (token_index_ < 0) { |
| +void ActivationFrame::GetPcDescriptors() { |
| + if (pc_desc_.IsNull()) { |
| const Function& func = DartFunction(); |
| ASSERT(!func.HasOptimizedCode()); |
| 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++) { |
| - if (desc.PC(i) == pc_) { |
| - token_index_ = desc.TokenIndex(i); |
| + pc_desc_ = code.pc_descriptors(); |
| + ASSERT(!pc_desc_.IsNull()); |
| + } |
| +} |
| + |
| + |
| +// Compute token_index_ and pc_desc_index_. |
| +intptr_t ActivationFrame::TokenIndex() { |
| + if (token_index_ < 0) { |
| + GetPcDescriptors(); |
| + for (int i = 0; i < pc_desc_.Length(); i++) { |
| + if (pc_desc_.PC(i) == pc_) { |
| + pc_desc_index_ = i; |
| + token_index_ = pc_desc_.TokenIndex(i); |
| break; |
| } |
| } |
| @@ -186,6 +202,15 @@ |
| } |
| +intptr_t ActivationFrame::PcDescIndex() { |
| + if (pc_desc_index_ < 0) { |
| + TokenIndex(); |
| + ASSERT(pc_desc_index_ >= 0); |
| + } |
| + return pc_desc_index_; |
| +} |
| + |
| + |
| intptr_t ActivationFrame::LineNumber() { |
| // Compute line number lazily since it causes scanning of the script. |
| if (line_number_ < 0) { |
| @@ -197,58 +222,133 @@ |
| } |
| -void ActivationFrame::GetDescIndices() { |
| - if (var_descriptors_.IsNull()) { |
| - ASSERT(!DartFunction().HasOptimizedCode()); |
| - const Code& code = Code::Handle(DartFunction().unoptimized_code()); |
| - var_descriptors_ = code.var_descriptors(); |
| - // TODO(Hausner): Consider replacing this GrowableArray. |
| - GrowableArray<String*> var_names(8); |
| +void ActivationFrame::GetVarDescriptors() { |
| + if (!var_descriptors_.IsNull()) { |
| + return; |
| + } |
| + ASSERT(!DartFunction().HasOptimizedCode()); |
| + const Code& code = Code::Handle(DartFunction().unoptimized_code()); |
| + var_descriptors_ = code.var_descriptors(); |
| + ASSERT(!var_descriptors_.IsNull()); |
| +} |
| + |
| + |
| +// Calculate the context level at the current token index of the frame. |
| +intptr_t ActivationFrame::ContextLevel() { |
| + if (context_level_ < 0) { |
| + context_level_ = 0; |
| + intptr_t pc_desc_idx = PcDescIndex(); |
| + ASSERT(!pc_desc_.IsNull()); |
| + if (pc_desc_.DescriptorKind(pc_desc_idx) == PcDescriptors::kReturn) { |
| + // Special case: the context chain has already been deallocated. |
| + // The context level is 0. |
| + return context_level_; |
| + } |
| + intptr_t innermost_begin_pos = 0; |
| intptr_t activation_token_pos = TokenIndex(); |
| + GetVarDescriptors(); |
| intptr_t var_desc_len = var_descriptors_.Length(); |
| for (int cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { |
| - ASSERT(var_names.length() == desc_indices_.length()); |
| - intptr_t scope_id, begin_pos, end_pos; |
| - var_descriptors_.GetScopeInfo(cur_idx, &scope_id, &begin_pos, &end_pos); |
| - if ((begin_pos <= activation_token_pos) && |
| - (activation_token_pos <= end_pos)) { |
| - // The current variable is textually in scope. Now check whether |
| - // there is another local variable with the same name that shadows |
| - // or is shadowed by this variable. |
| - 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++) { |
| - if (var_name.Equals(*var_names[i])) { |
| - // Found two local variables with the same name. Now determine |
| - // which one is shadowed. |
| - name_match_found = true; |
| - intptr_t i_begin_pos, ignore; |
| - var_descriptors_.GetScopeInfo( |
| - desc_indices_[i], &ignore, &i_begin_pos, &ignore); |
| - if (i_begin_pos < begin_pos) { |
| - // The variable we found earlier is in an outer scope |
| - // and is shadowed by the current variable. Replace the |
| - // descriptor index of the previously found variable |
| - // with the descriptor index of the current variable. |
| - desc_indices_[i] = cur_idx; |
| - } else { |
| - // The variable we found earlier is in an inner scope |
| - // and shadows the current variable. Skip the current |
| - // variable. (Nothing to do.) |
| - } |
| - break; // Stop looking for name matches. |
| + RawLocalVarDescriptors::VarInfo var_info; |
| + var_descriptors_.GetInfo(cur_idx, &var_info); |
| + if ((var_info.kind == RawLocalVarDescriptors::kContextLevel) && |
| + (var_info.begin_pos <= activation_token_pos) && |
| + (activation_token_pos < var_info.end_pos)) { |
| + // This var_descriptors_ entry is a context scope which is in scope |
| + // of the current token position. Now check whether it is shadowing |
| + // the previous context scope. |
| + if (innermost_begin_pos < var_info.begin_pos) { |
| + innermost_begin_pos = var_info.begin_pos; |
| + context_level_ = var_info.index; |
| + } |
| + } |
| + } |
| + ASSERT(context_level_ >= 0); |
| + } |
| + return context_level_; |
| +} |
| + |
| + |
| +RawContext* ActivationFrame::CallerContext() { |
| + GetVarDescriptors(); |
| + intptr_t var_desc_len = var_descriptors_.Length(); |
| + for (int i = 0; i < var_desc_len; i++) { |
| + RawLocalVarDescriptors::VarInfo var_info; |
| + var_descriptors_.GetInfo(i, &var_info); |
| + if (var_info.kind == RawLocalVarDescriptors::kContextChain) { |
| + return reinterpret_cast<RawContext*>(GetLocalVarValue(var_info.index)); |
| + } |
| + } |
| + // Caller uses same context chain. |
| + return ctx_.raw(); |
| +} |
| + |
| + |
| +void ActivationFrame::GetDescIndices() { |
| + if (vars_initialized_) { |
| + return; |
| + } |
| + GetVarDescriptors(); |
| + // TODO(hausner): Consider replacing this GrowableArray. |
| + GrowableArray<String*> var_names(8); |
|
regis
2012/06/19 18:14:41
I think we usually avoid setting an initial size (
hausner
2012/06/19 18:49:41
Same comment as above.
|
| + intptr_t activation_token_pos = TokenIndex(); |
| + intptr_t var_desc_len = var_descriptors_.Length(); |
| + for (int 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); |
| + if ((var_info.kind != RawLocalVarDescriptors::kStackVar) && |
| + (var_info.kind != RawLocalVarDescriptors::kContextVar)) { |
| + continue; |
| + } |
| + if ((var_info.begin_pos <= activation_token_pos) && |
| + (activation_token_pos <= var_info.end_pos)) { |
| + if ((var_info.kind == RawLocalVarDescriptors::kContextVar) && |
| + (ContextLevel() < var_info.scope_id)) { |
| + // The variable is textually in scope but the context level |
| + // at the activation frame's PC is lower than the context |
| + // level of the variable. The context containing the variable |
| + // has already been removed from the chain. This can happen when we |
| + // break at a return statement, since the contexts get discarded |
| + // before the debugger gets called. |
| + continue; |
| + } |
| + // The current variable is textually in scope. Now check whether |
| + // there is another local variable with the same name that shadows |
| + // or is shadowed by this variable. |
| + 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++) { |
| + if (var_name.Equals(*var_names[i])) { |
| + // Found two local variables with the same name. Now determine |
| + // which one is shadowed. |
| + name_match_found = true; |
| + RawLocalVarDescriptors::VarInfo i_var_info; |
| + var_descriptors_.GetInfo(desc_indices_[i], &i_var_info); |
| + if (i_var_info.begin_pos < var_info.begin_pos) { |
| + // The variable we found earlier is in an outer scope |
| + // and is shadowed by the current variable. Replace the |
| + // descriptor index of the previously found variable |
| + // with the descriptor index of the current variable. |
| + desc_indices_[i] = cur_idx; |
| + } else { |
| + // The variable we found earlier is in an inner scope |
| + // and shadows the current variable. Skip the current |
| + // variable. (Nothing to do.) |
| } |
| + break; // Stop looking for name matches. |
| } |
| - if (!name_match_found) { |
| - // No duplicate name found. Add the current descriptor index to the |
| - // list of visible variables. |
| - desc_indices_.Add(cur_idx); |
| - var_names.Add(&var_name); |
| - } |
| } |
| + if (!name_match_found) { |
| + // No duplicate name found. Add the current descriptor index to the |
| + // list of visible variables. |
| + desc_indices_.Add(cur_idx); |
| + var_names.Add(&var_name); |
| + } |
| } |
| } |
| + vars_initialized_ = true; |
| } |
| @@ -265,13 +365,41 @@ |
| Instance* value) { |
| GetDescIndices(); |
| ASSERT(i < desc_indices_.length()); |
| + intptr_t desc_index = desc_indices_[i]; |
| ASSERT(name != NULL); |
| - intptr_t desc_index = desc_indices_[i]; |
| *name ^= var_descriptors_.GetName(desc_index); |
| - intptr_t scope_id; |
| - var_descriptors_.GetScopeInfo(desc_index, &scope_id, token_pos, end_pos); |
| + RawLocalVarDescriptors::VarInfo var_info; |
| + var_descriptors_.GetInfo(desc_index, &var_info); |
| + ASSERT(token_pos != NULL); |
| + *token_pos = var_info.begin_pos; |
| + ASSERT(end_pos != NULL); |
| + *end_pos = var_info.end_pos; |
| ASSERT(value != NULL); |
| - *value = GetLocalVarValue(var_descriptors_.GetSlotIndex(desc_index)); |
| + if (var_info.kind == RawLocalVarDescriptors::kStackVar) { |
| + *value = GetLocalVarValue(var_info.index); |
| + } else { |
| + ASSERT(var_info.kind == RawLocalVarDescriptors::kContextVar); |
| + ASSERT(!ctx_.IsNull()); |
| + // The context level at the PC/token index of this activation frame. |
| + intptr_t frame_ctx_level = ContextLevel(); |
| + // The context level of the variable. |
| + intptr_t var_ctx_level = var_info.scope_id; |
| + intptr_t level_diff = frame_ctx_level - var_ctx_level; |
| + intptr_t ctx_slot = var_info.index; |
| + if (level_diff == 0) { |
| + *value = ctx_.At(ctx_slot); |
| + } else { |
| + ASSERT(level_diff > 0); |
| + Context& ctx = Context::Handle(ctx_.raw()); |
| + while (level_diff > 0) { |
| + ASSERT(!ctx.IsNull()); |
| + level_diff--; |
| + ctx = ctx.parent(); |
| + } |
| + ASSERT(!ctx.IsNull()); |
| + *value = ctx.At(ctx_slot); |
| + } |
| + } |
| } |
| @@ -282,9 +410,9 @@ |
| Instance& value = Instance::Handle(); |
| const Array& list = Array::Handle(Array::New(2 * num_variables)); |
| for (int i = 0; i < num_variables; i++) { |
| - var_name = var_descriptors_.GetName(i); |
| + intptr_t ignore; |
| + VariableAt(i, &var_name, &ignore, &ignore, &value); |
| list.SetAt(2 * i, var_name); |
| - value = GetLocalVarValue(var_descriptors_.GetSlotIndex(i)); |
| list.SetAt((2 * i) + 1, value); |
| } |
| return list.raw(); |
| @@ -609,13 +737,15 @@ |
| DebuggerStackTrace* Debugger::CollectStackTrace() { |
| DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| + Context& ctx = Context::Handle(Isolate::Current()->top_context()); |
| DartFrameIterator iterator; |
| StackFrame* frame = iterator.NextFrame(); |
| while (frame != NULL) { |
| ASSERT(frame->IsValid()); |
| ASSERT(frame->IsDartFrame()); |
| ActivationFrame* activation = |
| - new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); |
| + new ActivationFrame(frame->pc(), frame->fp(), frame->sp(), ctx); |
| + ctx = activation->CallerContext(); |
| stack_trace->AddActivation(activation); |
| frame = iterator.NextFrame(); |
| } |