[vm,dyn_modules] Fix Scope check in ActivationFrame::ContextLevel.

The end PC offset for the scope is inclusive, not exclusive.

Also rename PrintDescriptorsError -> PrintContextLevelError and
print the Bytecode local variable information since that is what
is searched for the context level for interpreted frames.

TEST=pkg/vm_service/test/step_through_closure
     pkg/vm_service/test/step_through_function_expression

Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try,vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-mac-debug-arm64-try
Change-Id: Ib53d0a7cff81de16c957b73ce9ec7dcb0e4aaa34
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449740
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Tess Strickland
2025-09-16 05:52:51 -07:00
committed by Commit Queue
parent 20428509df
commit e01fad78df
5 changed files with 106 additions and 81 deletions
@@ -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();
+19 -10
View File
@@ -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);
}
+1 -1
View File
@@ -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();
+80
View File
@@ -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 {
+2
View File
@@ -7610,6 +7610,8 @@ class Bytecode : public Object {
untag()->set_var_descriptors<std::memory_order_release>(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)