diff --git a/runtime/vm/compiler/assembler/disassembler_kbc.cc b/runtime/vm/compiler/assembler/disassembler_kbc.cc index 1807619e526..84c945e7db0 100644 --- a/runtime/vm/compiler/assembler/disassembler_kbc.cc +++ b/runtime/vm/compiler/assembler/disassembler_kbc.cc @@ -10,6 +10,7 @@ #include "platform/assert.h" #include "vm/bytecode_reader.h" #include "vm/constants_kbc.h" +#include "vm/zone_text_buffer.h" namespace dart { @@ -354,23 +355,6 @@ void KernelBytecodeDisassembler::Disassemble(uword start, #endif } -#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) -static const int kLocalVariableKindMaxWidth = strlen( - bytecode::BytecodeLocalVariablesIterator::kKindNames - [bytecode::BytecodeLocalVariablesIterator::kVariableDeclaration]); - -static const int kLocalVariableColumnWidths[] = { - kLocalVariableKindMaxWidth, // kind - 14, // start pc - 14, // end pc - 7, // context level - 7, // index - 7, // start token pos - 7, // end token pos - 7, // decl token pos -}; -#endif - void KernelBytecodeDisassembler::Disassemble(const Function& function) { #if !defined(PRODUCT) ASSERT(function.HasBytecode()); @@ -416,61 +400,11 @@ void KernelBytecodeDisassembler::Disassemble(const Function& function) { if (bytecode.HasLocalVariablesInfo()) { #if !defined(DART_PRECOMPILED_RUNTIME) - auto& name = String::Handle(zone); - auto& type = AbstractType::Handle(zone); THR_Print("Local variable information for function '%s' {\n", function_fullname); - // "*" in a printf format specifier tells it to read the field width from - // the printf argument list. - THR_Print( - " %*s %*s %*s %*s %*s %*s %*s %*s name\n", - kLocalVariableColumnWidths[0], "kind", kLocalVariableColumnWidths[1], - "start pc", kLocalVariableColumnWidths[2], "end pc", - kLocalVariableColumnWidths[3], "ctx", kLocalVariableColumnWidths[4], - "index", kLocalVariableColumnWidths[5], "start", - kLocalVariableColumnWidths[6], "end", kLocalVariableColumnWidths[7], - "decl"); - bytecode::BytecodeLocalVariablesIterator iter(zone, bytecode); - while (iter.MoveNext()) { - THR_Print(" %*s %-#*" Px "", kLocalVariableColumnWidths[0], - iter.KindName(), kLocalVariableColumnWidths[1], - base + iter.StartPC()); - if (iter.IsVariableDeclaration() || iter.IsScope()) { - THR_Print(" %-#*" Px "", kLocalVariableColumnWidths[2], - base + iter.EndPC()); - } else { - THR_Print(" %*s", kLocalVariableColumnWidths[2], ""); - } - if (iter.IsScope()) { - THR_Print(" %*" Pd "", kLocalVariableColumnWidths[3], - iter.ContextLevel()); - } else { - THR_Print(" %*s", kLocalVariableColumnWidths[3], ""); - } - if (iter.IsContextVariable() || iter.IsVariableDeclaration()) { - THR_Print(" %*" Pd "", kLocalVariableColumnWidths[4], iter.Index()); - } else { - THR_Print(" %*s", kLocalVariableColumnWidths[4], ""); - } - if (iter.IsVariableDeclaration() || iter.IsScope()) { - THR_Print(" %*s %*s", kLocalVariableColumnWidths[5], - iter.StartTokenPos().ToCString(), - kLocalVariableColumnWidths[6], - iter.EndTokenPos().ToCString()); - - } else { - THR_Print(" %*s %*s", kLocalVariableColumnWidths[5], "", - kLocalVariableColumnWidths[6], ""); - } - if (iter.IsVariableDeclaration()) { - name = iter.Name(); - type = iter.Type(); - THR_Print(" %*s %s: %s%s", kLocalVariableColumnWidths[7], - iter.DeclarationTokenPos().ToCString(), name.ToCString(), - type.ToCString(), iter.IsCaptured() ? " (captured)" : ""); - } - THR_Print("\n"); - } + ZoneTextBuffer buffer(zone); + bytecode.WriteLocalVariablesInfo(zone, &buffer); + THR_Print("%s", buffer.buffer()); THR_Print("}\n"); #else UNREACHABLE(); diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index 689595df3a7..310f91a2fbe 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -40,6 +40,7 @@ #include "vm/timeline.h" #include "vm/token_position.h" #include "vm/visitor.h" +#include "vm/zone_text_buffer.h" #if !defined(DART_PRECOMPILED_RUNTIME) #include "vm/deopt_instructions.h" @@ -629,8 +630,8 @@ bool ActivationFrame::IsDebuggable() const { return Debugger::IsDebuggable(function()); } -void ActivationFrame::PrintDescriptorsError(const char* message) { - OS::PrintErr("Bad descriptors: %s\n", message); +void ActivationFrame::PrintContextLevelError(const char* message) { + OS::PrintErr("Cannot locate context level: %s\n", message); OS::PrintErr("function %s\n", function().ToQualifiedCString()); OS::PrintErr("pc_ %" Px "\n", pc_); OS::PrintErr("deopt_id_ %" Px "\n", deopt_id_); @@ -638,9 +639,12 @@ void ActivationFrame::PrintDescriptorsError(const char* message) { OS::PrintErr("token_pos_ %s\n", token_pos_.ToCString()); if (IsInterpreted()) { #if defined(DART_DYNAMIC_MODULES) - DisassembleToStdout formatter; - bytecode().Disassemble(&formatter); - OS::PrintErr("%s\n", var_descriptors_.ToCString()); +#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) + Zone* const zone = Thread::Current()->zone(); + ZoneTextBuffer buffer(zone); + bytecode().WriteLocalVariablesInfo(zone, &buffer); + OS::PrintErr("%s\n", buffer.buffer()); +#endif #else UNREACHABLE(); #endif @@ -677,7 +681,7 @@ intptr_t ActivationFrame::ContextLevel() { while (local_vars.MoveNext()) { if (local_vars.IsScope()) { if (local_vars.StartPC() <= pc_offset && - pc_offset < local_vars.EndPC()) { + pc_offset <= local_vars.EndPC()) { DEBUG_ASSERT(!found || local_vars.StartPC() > closest_start); found = true; context_level_ = local_vars.ContextLevel(); @@ -689,6 +693,10 @@ intptr_t ActivationFrame::ContextLevel() { } } } + if (!found) { + PrintContextLevelError( + "No Scope local variable info for the current PC"); + } #else UNREACHABLE(); #endif @@ -698,7 +706,7 @@ intptr_t ActivationFrame::ContextLevel() { // We store the deopt ids as real token positions. intptr_t deopt_id = DeoptId(); if (deopt_id == DeoptId::kNone) { - PrintDescriptorsError("Missing deopt id"); + PrintContextLevelError("Missing deopt id"); } const TokenPosition to_compare = TokenPosition::Deserialize(deopt_id); for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { @@ -712,9 +720,10 @@ intptr_t ActivationFrame::ContextLevel() { break; } } - } - if (!found) { - PrintDescriptorsError("Missing context level in var descriptors"); + if (!found) { + PrintContextLevelError( + "No ContextLevel var descriptor that contains the deopt id"); + } } ASSERT(context_level_ >= 0); } diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h index 309d12027e8..e78cd24e9c6 100644 --- a/runtime/vm/debugger.h +++ b/runtime/vm/debugger.h @@ -423,7 +423,7 @@ class ActivationFrame : public ZoneAllocated { void PrintContextMismatchError(intptr_t ctx_slot, intptr_t frame_ctx_level, intptr_t var_ctx_level); - void PrintDescriptorsError(const char* message); + void PrintContextLevelError(const char* message); intptr_t TryIndex(); intptr_t DeoptId(); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 85403725c00..9be731849b8 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -19389,6 +19389,86 @@ LocalVarDescriptorsPtr Bytecode::GetLocalVarDescriptors() const { UNREACHABLE(); #endif } + +#if defined(DART_DYNAMIC_MODULES) +static const int kLocalVariableKindMaxWidth = strlen( + bytecode::BytecodeLocalVariablesIterator::kKindNames + [bytecode::BytecodeLocalVariablesIterator::kVariableDeclaration]); + +static const int kLocalVariableColumnWidths[] = { + kLocalVariableKindMaxWidth, // kind + 14, // start pc + 14, // end pc + 7, // context level + 7, // index + 7, // start token pos + 7, // end token pos + 7, // decl token pos +}; +#endif + +void Bytecode::WriteLocalVariablesInfo(Zone* zone, + BaseTextBuffer* buffer) const { +#if defined(DART_DYNAMIC_MODULES) + if (!HasLocalVariablesInfo()) return; + + // "*" in a printf format specifier tells it to read the field width from + // the printf argument list. + buffer->Printf( + " %*s %*s %*s %*s %*s %*s %*s %*s name\n", kLocalVariableColumnWidths[0], + "kind", kLocalVariableColumnWidths[1], "start pc", + kLocalVariableColumnWidths[2], "end pc", kLocalVariableColumnWidths[3], + "ctx", kLocalVariableColumnWidths[4], "index", + kLocalVariableColumnWidths[5], "start", kLocalVariableColumnWidths[6], + "end", kLocalVariableColumnWidths[7], "decl"); + auto& name = String::Handle(zone); + auto& type = AbstractType::Handle(zone); + const uword base = PayloadStart(); + bytecode::BytecodeLocalVariablesIterator iter(zone, *this); + while (iter.MoveNext()) { + buffer->Printf(" %*s %-#*" Px "", kLocalVariableColumnWidths[0], + iter.KindName(), kLocalVariableColumnWidths[1], + base + iter.StartPC()); + if (iter.IsVariableDeclaration() || iter.IsScope()) { + buffer->Printf(" %-#*" Px "", kLocalVariableColumnWidths[2], + base + iter.EndPC()); + } else { + buffer->Printf(" %*s", kLocalVariableColumnWidths[2], ""); + } + if (iter.IsScope()) { + buffer->Printf(" %*" Pd "", kLocalVariableColumnWidths[3], + iter.ContextLevel()); + } else { + buffer->Printf(" %*s", kLocalVariableColumnWidths[3], ""); + } + if (iter.IsContextVariable() || iter.IsVariableDeclaration()) { + buffer->Printf(" %*" Pd "", kLocalVariableColumnWidths[4], iter.Index()); + } else { + buffer->Printf(" %*s", kLocalVariableColumnWidths[4], ""); + } + if (iter.IsVariableDeclaration() || iter.IsScope()) { + buffer->Printf(" %*s %*s", kLocalVariableColumnWidths[5], + iter.StartTokenPos().ToCString(), + kLocalVariableColumnWidths[6], + iter.EndTokenPos().ToCString()); + + } else { + buffer->Printf(" %*s %*s", kLocalVariableColumnWidths[5], "", + kLocalVariableColumnWidths[6], ""); + } + if (iter.IsVariableDeclaration()) { + name = iter.Name(); + type = iter.Type(); + buffer->Printf(" %*s %s: %s%s", kLocalVariableColumnWidths[7], + iter.DeclarationTokenPos().ToCString(), name.ToCString(), + type.ToCString(), iter.IsCaptured() ? " (captured)" : ""); + } + buffer->AddString("\n"); + } +#else + UNREACHABLE(); +#endif +} #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) const char* Bytecode::ToCString() const { diff --git a/runtime/vm/object.h b/runtime/vm/object.h index eeebf08dc65..35a80a101bc 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -7610,6 +7610,8 @@ class Bytecode : public Object { untag()->set_var_descriptors(value.ptr()); } + void WriteLocalVariablesInfo(Zone* zone, BaseTextBuffer* buffer) const; + // Will compute local var descriptors if necessary. LocalVarDescriptorsPtr GetLocalVarDescriptors() const; #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)