[Liftoff] Read stack values when inspecting frames
This extends the debug side table to track stack offsets of locals and operand stack slots, and uses this to read spilled value from the physical stack frame when inspecting Liftoff frames. R=jkummerow@chromium.org Bug: v8:10019 Change-Id: Ida7ab5256fcc1e9d408201f4eafe26919f1432a1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2000739 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#65789}
This commit is contained in:
parent
ea69636247
commit
3a5223ccc3
@ -159,13 +159,16 @@ class DebugSideTableBuilder {
|
||||
public:
|
||||
explicit EntryBuilder(
|
||||
int pc_offset, std::vector<ValueType> stack_types,
|
||||
std::vector<int> stack_offsets,
|
||||
std::vector<DebugSideTable::Entry::Constant> constants)
|
||||
: pc_offset_(pc_offset),
|
||||
stack_types_(std::move(stack_types)),
|
||||
stack_offsets_(std::move(stack_offsets)),
|
||||
constants_(std::move(constants)) {}
|
||||
|
||||
DebugSideTable::Entry ToTableEntry() const {
|
||||
return DebugSideTable::Entry{pc_offset_, std::move(stack_types_),
|
||||
std::move(stack_offsets_),
|
||||
std::move(constants_)};
|
||||
}
|
||||
|
||||
@ -175,6 +178,7 @@ class DebugSideTableBuilder {
|
||||
private:
|
||||
int pc_offset_;
|
||||
std::vector<ValueType> stack_types_;
|
||||
std::vector<int> stack_offsets_;
|
||||
std::vector<DebugSideTable::Entry::Constant> constants_;
|
||||
};
|
||||
|
||||
@ -189,6 +193,11 @@ class DebugSideTableBuilder {
|
||||
for (int i = 0; i < stack_height_without_locals; ++i) {
|
||||
stack_types[i] = stack_state[num_locals + i].type();
|
||||
}
|
||||
// Record stack offsets.
|
||||
std::vector<int> stack_offsets(stack_height_without_locals);
|
||||
for (int i = 0; i < stack_height_without_locals; ++i) {
|
||||
stack_offsets[i] = stack_state[num_locals + i].offset();
|
||||
}
|
||||
// Record all constants on the locals and stack.
|
||||
std::vector<DebugSideTable::Entry::Constant> constants;
|
||||
for (int idx = 0; idx < stack_height; ++idx) {
|
||||
@ -196,11 +205,14 @@ class DebugSideTableBuilder {
|
||||
if (slot.is_const()) constants.push_back({idx, slot.i32_const()});
|
||||
}
|
||||
entries_.emplace_back(pc_offset, std::move(stack_types),
|
||||
std::move(constants));
|
||||
std::move(stack_offsets), std::move(constants));
|
||||
return &entries_.back();
|
||||
}
|
||||
|
||||
void AddLocalType(ValueType type) { local_types_.push_back(type); }
|
||||
void AddLocalType(ValueType type, int stack_offset) {
|
||||
local_types_.push_back(type);
|
||||
local_stack_offsets_.push_back(stack_offset);
|
||||
}
|
||||
|
||||
DebugSideTable GenerateDebugSideTable() {
|
||||
std::vector<DebugSideTable::Entry> table_entries;
|
||||
@ -210,11 +222,14 @@ class DebugSideTableBuilder {
|
||||
[](DebugSideTable::Entry& a, DebugSideTable::Entry& b) {
|
||||
return a.pc_offset() < b.pc_offset();
|
||||
});
|
||||
return DebugSideTable{std::move(local_types_), std::move(table_entries)};
|
||||
return DebugSideTable{std::move(local_types_),
|
||||
std::move(local_stack_offsets_),
|
||||
std::move(table_entries)};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ValueType> local_types_;
|
||||
std::vector<int> local_stack_offsets_;
|
||||
std::list<EntryBuilder> entries_;
|
||||
};
|
||||
|
||||
@ -379,11 +394,6 @@ class LiftoffCompiler {
|
||||
ValueType type = decoder->GetLocalType(i);
|
||||
__ set_local_type(i, type);
|
||||
}
|
||||
if (V8_UNLIKELY(debug_sidetable_builder_)) {
|
||||
for (int i = 0; i < num_locals; ++i) {
|
||||
debug_sidetable_builder_->AddLocalType(__ local_type(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of inputs processed (1 or 2).
|
||||
@ -531,11 +541,18 @@ class LiftoffCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
DCHECK_EQ(__ num_locals(), __ cache_state()->stack_height());
|
||||
|
||||
// Register local types and stack offsets for the debug side table.
|
||||
if (V8_UNLIKELY(debug_sidetable_builder_)) {
|
||||
for (uint32_t i = 0; i < __ num_locals(); ++i) {
|
||||
debug_sidetable_builder_->AddLocalType(
|
||||
__ local_type(i), __ cache_state()->stack_state[i].offset());
|
||||
}
|
||||
}
|
||||
// The function-prologue stack check is associated with position 0, which
|
||||
// is never a position of any instruction in the function.
|
||||
StackCheck(0);
|
||||
|
||||
DCHECK_EQ(__ num_locals(), __ cache_state()->stack_height());
|
||||
}
|
||||
|
||||
void GenerateOutOfLineCode(OutOfLineCode* ool) {
|
||||
|
@ -535,8 +535,9 @@ class DebugInfoImpl {
|
||||
// we name them "args" here.
|
||||
const char* label = i < num_params ? "arg#%d" : "local#%d";
|
||||
Handle<String> name = PrintFToOneByteString<true>(isolate, label, i);
|
||||
WasmValue value = GetValue(debug_side_table_entry,
|
||||
debug_side_table->local_type(i), i, fp);
|
||||
WasmValue value =
|
||||
GetValue(debug_side_table_entry, debug_side_table->local_type(i), i,
|
||||
fp - debug_side_table->local_stack_offset(i));
|
||||
Handle<Object> value_obj = WasmValueToValueObject(isolate, value);
|
||||
JSObject::SetOwnPropertyIgnoreAttributes(locals_obj, name, value_obj,
|
||||
NONE)
|
||||
@ -556,8 +557,8 @@ class DebugInfoImpl {
|
||||
NONE);
|
||||
for (int i = 0; i < stack_count; ++i) {
|
||||
ValueType type = debug_side_table_entry->stack_type(i);
|
||||
WasmValue value =
|
||||
GetValue(debug_side_table_entry, type, num_locals + i, fp);
|
||||
WasmValue value = GetValue(debug_side_table_entry, type, num_locals + i,
|
||||
fp - debug_side_table_entry->stack_offset(i));
|
||||
Handle<Object> value_obj = WasmValueToValueObject(isolate, value);
|
||||
JSObject::AddDataElement(stack_obj, static_cast<uint32_t>(i), value_obj,
|
||||
NONE);
|
||||
@ -596,7 +597,7 @@ class DebugInfoImpl {
|
||||
// Get the value of a local (including parameters) or stack value. Stack
|
||||
// values follow the locals in the same index space.
|
||||
WasmValue GetValue(const DebugSideTable::Entry* debug_side_table_entry,
|
||||
ValueType type, int index, Address fp) {
|
||||
ValueType type, int index, Address stack_address) {
|
||||
if (debug_side_table_entry->IsConstant(index)) {
|
||||
DCHECK(type == kWasmI32 || type == kWasmI64);
|
||||
return type == kWasmI32
|
||||
@ -604,18 +605,17 @@ class DebugInfoImpl {
|
||||
: WasmValue(
|
||||
int64_t{debug_side_table_entry->GetConstant(index)});
|
||||
}
|
||||
|
||||
// Otherwise load the value from the stack.
|
||||
// TODO(clemensb): Implement this.
|
||||
USE(fp);
|
||||
switch (type) {
|
||||
case kWasmI32:
|
||||
return WasmValue(int32_t{0});
|
||||
return WasmValue(ReadUnalignedValue<int32_t>(stack_address));
|
||||
case kWasmI64:
|
||||
return WasmValue(int64_t{0});
|
||||
return WasmValue(ReadUnalignedValue<int64_t>(stack_address));
|
||||
case kWasmF32:
|
||||
return WasmValue(float{0});
|
||||
return WasmValue(ReadUnalignedValue<float>(stack_address));
|
||||
case kWasmF64:
|
||||
return WasmValue(double{0});
|
||||
return WasmValue(ReadUnalignedValue<double>(stack_address));
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
@ -41,19 +41,27 @@ class DebugSideTable {
|
||||
};
|
||||
|
||||
Entry(int pc_offset, std::vector<ValueType> stack_types,
|
||||
std::vector<Constant> constants)
|
||||
std::vector<int> stack_offsets, std::vector<Constant> constants)
|
||||
: pc_offset_(pc_offset),
|
||||
stack_types_(std::move(stack_types)),
|
||||
stack_offsets_(std::move(stack_offsets)),
|
||||
constants_(std::move(constants)) {
|
||||
DCHECK(std::is_sorted(constants_.begin(), constants_.end(),
|
||||
ConstantIndexLess{}));
|
||||
DCHECK_EQ(stack_types_.size(), stack_offsets_.size());
|
||||
}
|
||||
|
||||
// Constructor for map lookups (only initializes the {pc_offset_}).
|
||||
explicit Entry(int pc_offset) : pc_offset_(pc_offset) {}
|
||||
|
||||
int pc_offset() const { return pc_offset_; }
|
||||
int stack_height() const { return static_cast<int>(stack_types_.size()); }
|
||||
ValueType stack_type(int stack_index) const {
|
||||
return stack_types_[stack_index];
|
||||
}
|
||||
int stack_offset(int stack_index) const {
|
||||
return stack_offsets_[stack_index];
|
||||
}
|
||||
// {index} can point to a local or operand stack value.
|
||||
bool IsConstant(int index) const {
|
||||
return std::binary_search(constants_.begin(), constants_.end(),
|
||||
@ -76,7 +84,9 @@ class DebugSideTable {
|
||||
};
|
||||
|
||||
int pc_offset_;
|
||||
// TODO(clemensb): Merge these vectors into one.
|
||||
std::vector<ValueType> stack_types_;
|
||||
std::vector<int> stack_offsets_;
|
||||
std::vector<Constant> constants_;
|
||||
};
|
||||
|
||||
@ -85,15 +95,18 @@ class DebugSideTable {
|
||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(DebugSideTable);
|
||||
|
||||
explicit DebugSideTable(std::vector<ValueType> local_types,
|
||||
std::vector<int> local_stack_offsets,
|
||||
std::vector<Entry> entries)
|
||||
: local_types_(std::move(local_types)), entries_(std::move(entries)) {
|
||||
: local_types_(std::move(local_types)),
|
||||
local_stack_offsets_(std::move(local_stack_offsets)),
|
||||
entries_(std::move(entries)) {
|
||||
DCHECK(
|
||||
std::is_sorted(entries_.begin(), entries_.end(), EntryPositionLess{}));
|
||||
}
|
||||
|
||||
const Entry* GetEntry(int pc_offset) const {
|
||||
auto it = std::lower_bound(entries_.begin(), entries_.end(),
|
||||
Entry{pc_offset, {}, {}}, EntryPositionLess{});
|
||||
Entry{pc_offset}, EntryPositionLess{});
|
||||
if (it == entries_.end() || it->pc_offset() != pc_offset) return nullptr;
|
||||
return &*it;
|
||||
}
|
||||
@ -105,6 +118,9 @@ class DebugSideTable {
|
||||
size_t num_entries() const { return entries_.size(); }
|
||||
int num_locals() const { return static_cast<int>(local_types_.size()); }
|
||||
ValueType local_type(int index) const { return local_types_[index]; }
|
||||
int local_stack_offset(int index) const {
|
||||
return local_stack_offsets_[index];
|
||||
}
|
||||
|
||||
private:
|
||||
struct EntryPositionLess {
|
||||
@ -114,6 +130,7 @@ class DebugSideTable {
|
||||
};
|
||||
|
||||
std::vector<ValueType> local_types_;
|
||||
std::vector<int32_t> local_stack_offsets_;
|
||||
std::vector<Entry> entries_;
|
||||
};
|
||||
|
||||
|
@ -22,13 +22,13 @@ at B (liftoff) (0:76):
|
||||
- scope (global):
|
||||
globals: "global#0": 0 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number), "local#1": 0 (number), "local#2": 0 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 0 (number), "1": 3 (number)
|
||||
locals: "arg#0": 42 (number), "local#1": 0 (number), "local#2": 7.199999809265137 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 42 (number), "1": 3 (number)
|
||||
at A (liftoff) (0:54):
|
||||
- scope (global):
|
||||
globals: "global#0": 0 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number)
|
||||
locals: "arg#0": 42 (number)
|
||||
stack:
|
||||
at (anonymous) (0:17):
|
||||
- scope (global):
|
||||
@ -47,13 +47,13 @@ at B (liftoff) (0:76):
|
||||
- scope (global):
|
||||
globals: "global#0": 0 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number), "local#1": 0 (number), "local#2": 0 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 0 (number), "1": 3 (number)
|
||||
locals: "arg#0": 42 (number), "local#1": 0 (number), "local#2": 7.199999809265137 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 42 (number), "1": 3 (number)
|
||||
at A (liftoff) (0:54):
|
||||
- scope (global):
|
||||
globals: "global#0": 0 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number)
|
||||
locals: "arg#0": 42 (number)
|
||||
stack:
|
||||
at (anonymous) (0:17):
|
||||
- scope (global):
|
||||
@ -72,13 +72,13 @@ at B (liftoff) (0:76):
|
||||
- scope (global):
|
||||
globals: "global#0": 42 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number), "local#1": 0 (number), "local#2": 0 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 0 (number), "1": 3 (number)
|
||||
locals: "arg#0": 42 (number), "local#1": 0 (number), "local#2": 7.199999809265137 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 42 (number), "1": 3 (number)
|
||||
at A (liftoff) (0:54):
|
||||
- scope (global):
|
||||
globals: "global#0": 42 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number)
|
||||
locals: "arg#0": 42 (number)
|
||||
stack:
|
||||
at (anonymous) (0:17):
|
||||
- scope (global):
|
||||
@ -97,13 +97,13 @@ at B (liftoff) (0:76):
|
||||
- scope (global):
|
||||
globals: "global#0": 42 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number), "local#1": 0 (number), "local#2": 0 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 0 (number), "1": 3 (number)
|
||||
locals: "arg#0": 42 (number), "local#1": 0 (number), "local#2": 7.199999809265137 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 42 (number), "1": 3 (number)
|
||||
at A (liftoff) (0:54):
|
||||
- scope (global):
|
||||
globals: "global#0": 42 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number)
|
||||
locals: "arg#0": 42 (number)
|
||||
stack:
|
||||
at (anonymous) (0:17):
|
||||
- scope (global):
|
||||
@ -122,13 +122,13 @@ at B (liftoff) (0:76):
|
||||
- scope (global):
|
||||
globals: "global#0": 42 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number), "local#1": 0 (number), "local#2": 0 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 0 (number), "1": 3 (number)
|
||||
locals: "arg#0": 42 (number), "local#1": 0 (number), "local#2": 7.199999809265137 (number), "local#3": 0 (number), "local#4": 0 (number)
|
||||
stack: "0": 42 (number), "1": 3 (number)
|
||||
at A (liftoff) (0:54):
|
||||
- scope (global):
|
||||
globals: "global#0": 42 (number)
|
||||
- scope (local):
|
||||
locals: "arg#0": 0 (number)
|
||||
locals: "arg#0": 42 (number)
|
||||
stack:
|
||||
at (anonymous) (0:17):
|
||||
- scope (global):
|
||||
|
Loading…
Reference in New Issue
Block a user