Commit 382237a3 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm] Extend debug side table with type information

Store the types of locals in the {DebugSideTable}, and the type of all
stack values on each entry.
Especially the stack value types would be difficult to reconstruct later
on.

R=jkummerow@chromium.org

Bug: v8:10019
Change-Id: I9b945b4e0a51166460420099908442703d3d486a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1975759
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65670}
parent bc9db9f5
...@@ -157,18 +157,16 @@ class DebugSideTableBuilder { ...@@ -157,18 +157,16 @@ class DebugSideTableBuilder {
public: public:
class EntryBuilder { class EntryBuilder {
public: public:
explicit EntryBuilder(int pc_offset, int stack_height) explicit EntryBuilder(
: pc_offset_(pc_offset), stack_height_(stack_height) {} int pc_offset, std::vector<ValueType> stack_types,
std::vector<DebugSideTable::Entry::Constant> constants)
void SetConstant(int index, int32_t i32_const) { : pc_offset_(pc_offset),
// Add constants in order. stack_types_(std::move(stack_types)),
DCHECK(constants_.empty() || constants_.back().index < index); constants_(std::move(constants)) {}
constants_.push_back({index, i32_const});
}
DebugSideTable::Entry ToTableEntry() const { DebugSideTable::Entry ToTableEntry() const {
DCHECK_LE(0, stack_height_); return DebugSideTable::Entry{pc_offset_, std::move(stack_types_),
return DebugSideTable::Entry{pc_offset_, stack_height_, constants_}; std::move(constants_)};
} }
int pc_offset() const { return pc_offset_; } int pc_offset() const { return pc_offset_; }
...@@ -176,17 +174,34 @@ class DebugSideTableBuilder { ...@@ -176,17 +174,34 @@ class DebugSideTableBuilder {
private: private:
int pc_offset_; int pc_offset_;
const int stack_height_; std::vector<ValueType> stack_types_;
std::vector<DebugSideTable::Entry::Constant> constants_; std::vector<DebugSideTable::Entry::Constant> constants_;
}; };
// Adds a new entry, and returns a pointer to a builder for modifying that // Adds a new entry, and returns a pointer to a builder for modifying that
// entry. // entry ({stack_height} includes {num_locals}).
EntryBuilder* NewEntry(int pc_offset, int stack_height) { EntryBuilder* NewEntry(int pc_offset, int num_locals, int stack_height,
entries_.emplace_back(pc_offset, stack_height); LiftoffAssembler::VarState* stack_state) {
DCHECK_LE(num_locals, stack_height);
// Record stack types.
int stack_height_without_locals = stack_height - num_locals;
std::vector<ValueType> stack_types(stack_height_without_locals);
for (int i = 0; i < stack_height_without_locals; ++i) {
stack_types[i] = stack_state[num_locals + i].type();
}
// Record all constants on the locals and stack.
std::vector<DebugSideTable::Entry::Constant> constants;
for (int idx = 0; idx < stack_height; ++idx) {
auto& slot = stack_state[idx];
if (slot.is_const()) constants.push_back({idx, slot.i32_const()});
}
entries_.emplace_back(pc_offset, std::move(stack_types),
std::move(constants));
return &entries_.back(); return &entries_.back();
} }
void AddLocalType(ValueType type) { local_types_.push_back(type); }
DebugSideTable GenerateDebugSideTable() { DebugSideTable GenerateDebugSideTable() {
std::vector<DebugSideTable::Entry> table_entries; std::vector<DebugSideTable::Entry> table_entries;
table_entries.reserve(entries_.size()); table_entries.reserve(entries_.size());
...@@ -195,10 +210,11 @@ class DebugSideTableBuilder { ...@@ -195,10 +210,11 @@ class DebugSideTableBuilder {
[](DebugSideTable::Entry& a, DebugSideTable::Entry& b) { [](DebugSideTable::Entry& a, DebugSideTable::Entry& b) {
return a.pc_offset() < b.pc_offset(); return a.pc_offset() < b.pc_offset();
}); });
return DebugSideTable{std::move(table_entries)}; return DebugSideTable{std::move(local_types_), std::move(table_entries)};
} }
private: private:
std::vector<ValueType> local_types_;
std::list<EntryBuilder> entries_; std::list<EntryBuilder> entries_;
}; };
...@@ -363,6 +379,11 @@ class LiftoffCompiler { ...@@ -363,6 +379,11 @@ class LiftoffCompiler {
ValueType type = decoder->GetLocalType(i); ValueType type = decoder->GetLocalType(i);
__ set_local_type(i, type); __ 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). // Returns the number of inputs processed (1 or 2).
...@@ -1888,14 +1909,9 @@ class LiftoffCompiler { ...@@ -1888,14 +1909,9 @@ class LiftoffCompiler {
DebugSideTableBuilder::EntryBuilder* RegisterDebugSideTableEntry() { DebugSideTableBuilder::EntryBuilder* RegisterDebugSideTableEntry() {
if (V8_LIKELY(!debug_sidetable_builder_)) return nullptr; if (V8_LIKELY(!debug_sidetable_builder_)) return nullptr;
int stack_height = static_cast<int>(__ cache_state()->stack_height()); int stack_height = static_cast<int>(__ cache_state()->stack_height());
auto* entry_builder = return debug_sidetable_builder_->NewEntry(
debug_sidetable_builder_->NewEntry(__ pc_offset(), stack_height); __ pc_offset(), __ num_locals(), stack_height,
// Record all constants on the stack. __ cache_state()->stack_state.begin());
for (int idx = 0; idx < stack_height; ++idx) {
auto& slot = __ cache_state()->stack_state[idx];
if (slot.is_const()) entry_builder->SetConstant(idx, slot.i32_const());
}
return entry_builder;
} }
void CallDirect(FullDecoder* decoder, void CallDirect(FullDecoder* decoder,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "src/base/iterator.h" #include "src/base/iterator.h"
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/base/macros.h" #include "src/base/macros.h"
#include "src/wasm/value-type.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -39,16 +40,21 @@ class DebugSideTable { ...@@ -39,16 +40,21 @@ class DebugSideTable {
int32_t i32_const; int32_t i32_const;
}; };
Entry(int pc_offset, int stack_height, std::vector<Constant> constants) Entry(int pc_offset, std::vector<ValueType> stack_types,
std::vector<Constant> constants)
: pc_offset_(pc_offset), : pc_offset_(pc_offset),
stack_height_(stack_height), stack_types_(std::move(stack_types)),
constants_(std::move(constants)) { constants_(std::move(constants)) {
DCHECK(std::is_sorted(constants_.begin(), constants_.end(), DCHECK(std::is_sorted(constants_.begin(), constants_.end(),
ConstantIndexLess{})); ConstantIndexLess{}));
} }
int pc_offset() const { return pc_offset_; } int pc_offset() const { return pc_offset_; }
int stack_height() const { return stack_height_; } int stack_height() const { return static_cast<int>(stack_types_.size()); }
ValueType stack_type(int stack_index) const {
return stack_types_[stack_index];
}
// {index} can point to a local or operand stack value.
bool IsConstant(int index) const { bool IsConstant(int index) const {
return std::binary_search(constants_.begin(), constants_.end(), return std::binary_search(constants_.begin(), constants_.end(),
Constant{index, 0}, ConstantIndexLess{}); Constant{index, 0}, ConstantIndexLess{});
...@@ -70,7 +76,7 @@ class DebugSideTable { ...@@ -70,7 +76,7 @@ class DebugSideTable {
}; };
int pc_offset_; int pc_offset_;
int stack_height_; std::vector<ValueType> stack_types_;
std::vector<Constant> constants_; std::vector<Constant> constants_;
}; };
...@@ -78,15 +84,16 @@ class DebugSideTable { ...@@ -78,15 +84,16 @@ class DebugSideTable {
// reason to do so, hence mark it move only. // reason to do so, hence mark it move only.
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(DebugSideTable); MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(DebugSideTable);
explicit DebugSideTable(std::vector<Entry> entries) explicit DebugSideTable(std::vector<ValueType> local_types,
: entries_(std::move(entries)) { std::vector<Entry> entries)
: local_types_(std::move(local_types)), entries_(std::move(entries)) {
DCHECK( DCHECK(
std::is_sorted(entries_.begin(), entries_.end(), EntryPositionLess{})); std::is_sorted(entries_.begin(), entries_.end(), EntryPositionLess{}));
} }
const Entry* GetEntry(int pc_offset) const { const Entry* GetEntry(int pc_offset) const {
auto it = std::lower_bound(entries_.begin(), entries_.end(), auto it = std::lower_bound(entries_.begin(), entries_.end(),
Entry{pc_offset, 0, {}}, EntryPositionLess{}); Entry{pc_offset, {}, {}}, EntryPositionLess{});
if (it == entries_.end() || it->pc_offset() != pc_offset) return nullptr; if (it == entries_.end() || it->pc_offset() != pc_offset) return nullptr;
return &*it; return &*it;
} }
...@@ -96,6 +103,8 @@ class DebugSideTable { ...@@ -96,6 +103,8 @@ class DebugSideTable {
} }
size_t num_entries() const { return entries_.size(); } 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]; }
private: private:
struct EntryPositionLess { struct EntryPositionLess {
...@@ -104,6 +113,7 @@ class DebugSideTable { ...@@ -104,6 +113,7 @@ class DebugSideTable {
} }
}; };
std::vector<ValueType> local_types_;
std::vector<Entry> entries_; std::vector<Entry> entries_;
}; };
......
...@@ -122,24 +122,30 @@ class LiftoffCompileEnvironment { ...@@ -122,24 +122,30 @@ class LiftoffCompileEnvironment {
}; };
struct DebugSideTableEntry { struct DebugSideTableEntry {
int stack_height; std::vector<ValueType> stack_types;
std::vector<std::pair<int, int>> constants; std::vector<std::pair<int, int>> constants;
bool operator==(const DebugSideTableEntry& other) const { bool operator==(const DebugSideTableEntry& other) const {
return stack_height == other.stack_height && constants == other.constants; return stack_types == other.stack_types && constants == other.constants;
} }
}; };
// Debug builds will print the vector of DebugSideTableEntry. // Debug builds will print the vector of DebugSideTableEntry.
#ifdef DEBUG #ifdef DEBUG
std::ostream& operator<<(std::ostream& out, const DebugSideTableEntry& entry) { std::ostream& operator<<(std::ostream& out, const DebugSideTableEntry& entry) {
out << "{stack height " << entry.stack_height << ", constants: {"; out << "{stack types [";
const char* comma = ""; const char* comma = "";
for (ValueType type : entry.stack_types) {
out << comma << ValueTypes::TypeName(type);
comma = ", ";
}
comma = "";
out << "], constants: [";
for (auto& c : entry.constants) { for (auto& c : entry.constants) {
out << comma << "{" << c.first << ", " << c.second << "}"; out << comma << "<" << c.first << ", " << c.second << ">";
comma = ", "; comma = ", ";
} }
return out << "}}"; return out << "]}";
} }
std::ostream& operator<<(std::ostream& out, std::ostream& operator<<(std::ostream& out,
...@@ -148,17 +154,29 @@ std::ostream& operator<<(std::ostream& out, ...@@ -148,17 +154,29 @@ std::ostream& operator<<(std::ostream& out,
} }
#endif // DEBUG #endif // DEBUG
void CheckEntries(std::vector<DebugSideTableEntry> expected, void CheckDebugSideTable(std::vector<ValueType> expected_local_types,
const wasm::DebugSideTable& debug_side_table) { std::vector<DebugSideTableEntry> expected_entries,
const wasm::DebugSideTable& debug_side_table) {
std::vector<ValueType> local_types;
for (int i = 0; i < debug_side_table.num_locals(); ++i) {
local_types.push_back(debug_side_table.local_type(i));
}
std::vector<DebugSideTableEntry> entries; std::vector<DebugSideTableEntry> entries;
for (auto& entry : debug_side_table.entries()) { for (auto& entry : debug_side_table.entries()) {
std::vector<std::pair<int, int>> constants; std::vector<ValueType> stack_types;
for (int i = 0; i < entry.stack_height(); ++i) { for (int i = 0; i < entry.stack_height(); ++i) {
stack_types.push_back(entry.stack_type(i));
}
std::vector<std::pair<int, int>> constants;
int locals_plus_stack =
debug_side_table.num_locals() + entry.stack_height();
for (int i = 0; i < locals_plus_stack; ++i) {
if (entry.IsConstant(i)) constants.emplace_back(i, entry.GetConstant(i)); if (entry.IsConstant(i)) constants.emplace_back(i, entry.GetConstant(i));
} }
entries.push_back({entry.stack_height(), std::move(constants)}); entries.push_back({std::move(stack_types), std::move(constants)});
} }
CHECK_EQ(expected, entries); CHECK_EQ(expected_local_types, local_types);
CHECK_EQ(expected_entries, entries);
} }
} // namespace } // namespace
...@@ -205,11 +223,12 @@ TEST(Liftoff_debug_side_table_simple) { ...@@ -205,11 +223,12 @@ TEST(Liftoff_debug_side_table_simple) {
auto debug_side_table = env.GenerateDebugSideTable( auto debug_side_table = env.GenerateDebugSideTable(
{kWasmI32}, {kWasmI32, kWasmI32}, {kWasmI32}, {kWasmI32, kWasmI32},
{WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))}); {WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))});
CheckEntries( CheckDebugSideTable({kWasmI32, kWasmI32},
{ {
{2, {}} // OOL stack check, stack: {param0, param1} // OOL stack check, stack: {}
}, {{}, {}},
debug_side_table); },
debug_side_table);
} }
TEST(Liftoff_debug_side_table_call) { TEST(Liftoff_debug_side_table_call) {
...@@ -218,12 +237,14 @@ TEST(Liftoff_debug_side_table_call) { ...@@ -218,12 +237,14 @@ TEST(Liftoff_debug_side_table_call) {
{kWasmI32}, {kWasmI32}, {kWasmI32}, {kWasmI32},
{WASM_I32_ADD(WASM_CALL_FUNCTION(0, WASM_GET_LOCAL(0)), {WASM_I32_ADD(WASM_CALL_FUNCTION(0, WASM_GET_LOCAL(0)),
WASM_GET_LOCAL(0))}); WASM_GET_LOCAL(0))});
CheckEntries( CheckDebugSideTable({kWasmI32},
{ {
{1, {}}, // call, stack: {param0} // call, stack: {}
{1, {}} // OOL stack check, stack: {param0} {{}, {}},
}, // OOL stack check, stack: {}
debug_side_table); {{}, {}},
},
debug_side_table);
} }
TEST(Liftoff_debug_side_table_call_const) { TEST(Liftoff_debug_side_table_call_const) {
...@@ -234,28 +255,35 @@ TEST(Liftoff_debug_side_table_call_const) { ...@@ -234,28 +255,35 @@ TEST(Liftoff_debug_side_table_call_const) {
{WASM_SET_LOCAL(0, WASM_I32V_1(kConst)), {WASM_SET_LOCAL(0, WASM_I32V_1(kConst)),
WASM_I32_ADD(WASM_CALL_FUNCTION(0, WASM_GET_LOCAL(0)), WASM_I32_ADD(WASM_CALL_FUNCTION(0, WASM_GET_LOCAL(0)),
WASM_GET_LOCAL(0))}); WASM_GET_LOCAL(0))});
CheckEntries( CheckDebugSideTable({kWasmI32},
{ {
{1, {{0, kConst}}}, // call, stack: {kConst} // call, stack: {}, local0 is kConst
{1, {}} // OOL stack check, stack: {param0} {{}, {{0, kConst}}},
}, // OOL stack check, stack: {}
debug_side_table); {{}, {}},
},
debug_side_table);
} }
TEST(Liftoff_debug_side_table_indirect_call) { TEST(Liftoff_debug_side_table_indirect_call) {
LiftoffCompileEnvironment env; LiftoffCompileEnvironment env;
constexpr int kConst = 47;
auto debug_side_table = env.GenerateDebugSideTable( auto debug_side_table = env.GenerateDebugSideTable(
{kWasmI32}, {kWasmI32}, {kWasmI32}, {kWasmI32},
{WASM_I32_ADD(WASM_CALL_INDIRECT(0, WASM_I32V_1(47), WASM_GET_LOCAL(0)), {WASM_I32_ADD(WASM_CALL_INDIRECT(0, WASM_I32V_1(47), WASM_GET_LOCAL(0)),
WASM_GET_LOCAL(0))}); WASM_GET_LOCAL(0))});
CheckEntries( CheckDebugSideTable({kWasmI32},
{ {
{1, {}}, // indirect call, stack: {param0} // indirect call, stack: {}
{1, {}}, // OOL stack check, stack: {param0} {{}, {}},
{2, {{1, 47}}}, // OOL invalid index, stack: {param0, 47} // OOL stack check, stack: {}
{2, {{1, 47}}}, // OOL sig mismatch, stack: {param0, 47} {{}, {}},
}, // OOL trap (invalid index), stack: {kConst}
debug_side_table); {{kWasmI32}, {{1, kConst}}},
// OOL trap (sig mismatch), stack: {kConst}
{{kWasmI32}, {{1, kConst}}},
},
debug_side_table);
} }
TEST(Liftoff_debug_side_table_loop) { TEST(Liftoff_debug_side_table_loop) {
...@@ -264,12 +292,14 @@ TEST(Liftoff_debug_side_table_loop) { ...@@ -264,12 +292,14 @@ TEST(Liftoff_debug_side_table_loop) {
auto debug_side_table = env.GenerateDebugSideTable( auto debug_side_table = env.GenerateDebugSideTable(
{kWasmI32}, {kWasmI32}, {kWasmI32}, {kWasmI32},
{WASM_I32V_1(kConst), WASM_LOOP(WASM_BR_IF(0, WASM_GET_LOCAL(0)))}); {WASM_I32V_1(kConst), WASM_LOOP(WASM_BR_IF(0, WASM_GET_LOCAL(0)))});
CheckEntries( CheckDebugSideTable({kWasmI32},
{ {
{1, {}}, // OOL stack check, stack: {param0} // OOL stack check, stack: {}
{2, {{1, kConst}}} // OOL loop stack check, stack: {param0, kConst} {{}, {}},
}, // OOL loop stack check, stack: {kConst}
debug_side_table); {{kWasmI32}, {{1, kConst}}},
},
debug_side_table);
} }
TEST(Liftoff_debug_side_table_trap) { TEST(Liftoff_debug_side_table_trap) {
...@@ -277,13 +307,16 @@ TEST(Liftoff_debug_side_table_trap) { ...@@ -277,13 +307,16 @@ TEST(Liftoff_debug_side_table_trap) {
auto debug_side_table = env.GenerateDebugSideTable( auto debug_side_table = env.GenerateDebugSideTable(
{kWasmI32}, {kWasmI32, kWasmI32}, {kWasmI32}, {kWasmI32, kWasmI32},
{WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))}); {WASM_I32_DIVS(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))});
CheckEntries( CheckDebugSideTable({kWasmI32, kWasmI32},
{ {
{2, {}}, // OOL stack check, stack: {param0, param1} // OOL stack check, stack: {}
{2, {}}, // OOL div by zero, stack: {param0, param1} {{}, {}},
{2, {}} // OOL unrepresentable div, stack: {param0, param1} // OOL trap (div by zero), stack: {}
}, {{}, {}},
debug_side_table); // OOL trap (result unrepresentable), stack: {}
{{}, {}},
},
debug_side_table);
} }
} // namespace wasm } // namespace wasm
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment