[wasm] Add a debug side table for Liftoff
This adds the data structure and a builder for it, without ever using it yet. Users and tests will be added in a follow-up CL. R=mstarzinger@chromium.org Bug: v8:10019 Change-Id: I5c332c8b3a499d3844113fbd4108a9138eef01f1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1932365 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#65165}
This commit is contained in:
parent
5d29947d06
commit
4105cce511
@ -22,6 +22,7 @@
|
||||
#include "src/wasm/function-compiler.h"
|
||||
#include "src/wasm/memory-tracing.h"
|
||||
#include "src/wasm/object-access.h"
|
||||
#include "src/wasm/wasm-debug.h"
|
||||
#include "src/wasm/wasm-engine.h"
|
||||
#include "src/wasm/wasm-linkage.h"
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
@ -151,6 +152,52 @@ constexpr Condition GetCompareCondition(WasmOpcode opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a {DebugSideTable}.
|
||||
class DebugSideTableBuilder {
|
||||
public:
|
||||
class EntryBuilder {
|
||||
public:
|
||||
explicit EntryBuilder(int pc_offset, int stack_height)
|
||||
: pc_offset_(pc_offset), stack_height_(stack_height) {}
|
||||
|
||||
void SetConstant(int index, int32_t i32_const) {
|
||||
// Add constants in order.
|
||||
DCHECK(constants_.empty() || constants_.back().index < index);
|
||||
constants_.push_back({index, i32_const});
|
||||
}
|
||||
|
||||
DebugSideTable::Entry ToTableEntry() const {
|
||||
DCHECK_LE(0, stack_height_);
|
||||
return DebugSideTable::Entry{pc_offset_, stack_height_, constants_};
|
||||
}
|
||||
|
||||
int pc_offset() const { return pc_offset_; }
|
||||
|
||||
private:
|
||||
const int pc_offset_;
|
||||
const int stack_height_;
|
||||
std::vector<DebugSideTable::Entry::Constant> constants_;
|
||||
};
|
||||
|
||||
// Adds a new entry, and returns a reference for modifying that entry. The
|
||||
// reference can only be used until the next call to {NewEntry}.
|
||||
EntryBuilder& NewEntry(int pc_offset, int stack_height) {
|
||||
DCHECK(entries_.empty() || entries_.back().pc_offset() < pc_offset);
|
||||
entries_.emplace_back(pc_offset, stack_height);
|
||||
return entries_.back();
|
||||
}
|
||||
|
||||
DebugSideTable GenerateDebugSideTable() {
|
||||
std::vector<DebugSideTable::Entry> table_entries;
|
||||
table_entries.reserve(entries_.size());
|
||||
for (auto& entry : entries_) table_entries.push_back(entry.ToTableEntry());
|
||||
return DebugSideTable{std::move(table_entries)};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<EntryBuilder> entries_;
|
||||
};
|
||||
|
||||
class LiftoffCompiler {
|
||||
public:
|
||||
// TODO(clemensb): Make this a template parameter.
|
||||
@ -485,6 +532,7 @@ class LiftoffCompiler {
|
||||
source_position_table_builder_.AddPosition(
|
||||
__ pc_offset(), SourcePosition(ool->position), false);
|
||||
__ CallRuntimeStub(ool->stub);
|
||||
RegisterDebugSideTableEntry();
|
||||
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
|
||||
DCHECK_EQ(ool->continuation.get()->is_bound(), is_stack_check);
|
||||
if (!ool->regs_to_save.is_empty()) __ PopRegisters(ool->regs_to_save);
|
||||
@ -1808,6 +1856,7 @@ class LiftoffCompiler {
|
||||
if (input.gp() != param_reg) __ Move(param_reg, input.gp(), kWasmI32);
|
||||
|
||||
__ CallRuntimeStub(WasmCode::kWasmMemoryGrow);
|
||||
RegisterDebugSideTableEntry();
|
||||
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
|
||||
|
||||
if (kReturnRegister0 != result.gp()) {
|
||||
@ -1817,6 +1866,18 @@ class LiftoffCompiler {
|
||||
__ PushRegister(kWasmI32, result);
|
||||
}
|
||||
|
||||
void RegisterDebugSideTableEntry() {
|
||||
if (V8_LIKELY(!debug_sidetable_builder_)) return;
|
||||
int stack_height = static_cast<int>(__ cache_state()->stack_height());
|
||||
auto entry =
|
||||
debug_sidetable_builder_->NewEntry(__ pc_offset(), stack_height);
|
||||
// Record all constants on the stack.
|
||||
for (int idx = 0; idx < stack_height; ++idx) {
|
||||
auto& slot = __ cache_state()->stack_state[idx];
|
||||
if (slot.is_const()) entry.SetConstant(idx, slot.i32_const());
|
||||
}
|
||||
}
|
||||
|
||||
void CallDirect(FullDecoder* decoder,
|
||||
const CallFunctionImmediate<validate>& imm,
|
||||
const Value args[], Value returns[]) {
|
||||
@ -1860,10 +1921,6 @@ class LiftoffCompiler {
|
||||
__ pc_offset(), SourcePosition(decoder->position()), false);
|
||||
|
||||
__ CallIndirect(imm.sig, call_descriptor, target);
|
||||
|
||||
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
|
||||
|
||||
__ FinishCall(imm.sig, call_descriptor);
|
||||
} else {
|
||||
// A direct call within this module just gets the current instance.
|
||||
__ PrepareCall(imm.sig, call_descriptor);
|
||||
@ -1874,11 +1931,12 @@ class LiftoffCompiler {
|
||||
// Just encode the function index. This will be patched at instantiation.
|
||||
Address addr = static_cast<Address>(imm.index);
|
||||
__ CallNativeWasmCode(addr);
|
||||
|
||||
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
|
||||
|
||||
__ FinishCall(imm.sig, call_descriptor);
|
||||
}
|
||||
|
||||
RegisterDebugSideTableEntry();
|
||||
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
|
||||
|
||||
__ FinishCall(imm.sig, call_descriptor);
|
||||
}
|
||||
|
||||
void CallIndirect(FullDecoder* decoder, const Value& index_val,
|
||||
@ -2008,6 +2066,7 @@ class LiftoffCompiler {
|
||||
__ PrepareCall(imm.sig, call_descriptor, &target, explicit_instance);
|
||||
__ CallIndirect(imm.sig, call_descriptor, target);
|
||||
|
||||
RegisterDebugSideTableEntry();
|
||||
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
|
||||
|
||||
__ FinishCall(imm.sig, call_descriptor);
|
||||
@ -2110,6 +2169,8 @@ class LiftoffCompiler {
|
||||
|
||||
compiler::CallDescriptor* const descriptor_;
|
||||
CompilationEnv* const env_;
|
||||
// TODO(clemensb): Provide a DebugSideTableBuilder here.
|
||||
DebugSideTableBuilder* const debug_sidetable_builder_ = nullptr;
|
||||
LiftoffBailoutReason bailout_reason_ = kSuccess;
|
||||
std::vector<OutOfLineCode> out_of_line_code_;
|
||||
SourcePositionTableBuilder source_position_table_builder_;
|
||||
|
@ -5,6 +5,11 @@
|
||||
#ifndef V8_WASM_WASM_DEBUG_H_
|
||||
#define V8_WASM_WASM_DEBUG_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "src/base/logging.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
@ -15,6 +20,76 @@ class WasmInstanceObject;
|
||||
|
||||
namespace wasm {
|
||||
|
||||
// Side table storing information used to inspect Liftoff frames at runtime.
|
||||
// This table is only created on demand for debugging, so it is not optimized
|
||||
// for memory size.
|
||||
class DebugSideTable {
|
||||
public:
|
||||
class Entry {
|
||||
public:
|
||||
struct Constant {
|
||||
int index;
|
||||
int32_t i32_const;
|
||||
};
|
||||
|
||||
Entry(int pc_offset, int stack_height, std::vector<Constant> constants)
|
||||
: pc_offset_(pc_offset),
|
||||
stack_height_(stack_height),
|
||||
constants_(std::move(constants)) {
|
||||
DCHECK(std::is_sorted(constants_.begin(), constants_.end(),
|
||||
ConstantIndexLess{}));
|
||||
}
|
||||
|
||||
int pc_offset() const { return pc_offset_; }
|
||||
int stack_height() const { return stack_height_; }
|
||||
bool IsConstant(int index) const {
|
||||
return std::binary_search(constants_.begin(), constants_.end(),
|
||||
Constant{index, 0}, ConstantIndexLess{});
|
||||
}
|
||||
int32_t GetConstant(int index) const {
|
||||
DCHECK(IsConstant(index));
|
||||
auto it = std::lower_bound(constants_.begin(), constants_.end(),
|
||||
Constant{index, 0}, ConstantIndexLess{});
|
||||
DCHECK_NE(it, constants_.end());
|
||||
DCHECK_EQ(it->index, index);
|
||||
return it->i32_const;
|
||||
}
|
||||
|
||||
private:
|
||||
struct ConstantIndexLess {
|
||||
bool operator()(const Constant& a, const Constant& b) const {
|
||||
return a.index < b.index;
|
||||
}
|
||||
};
|
||||
|
||||
int pc_offset_;
|
||||
int stack_height_;
|
||||
std::vector<Constant> constants_;
|
||||
};
|
||||
|
||||
explicit DebugSideTable(std::vector<Entry> entries)
|
||||
: 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, 0, {}}, EntryPositionLess{});
|
||||
if (it == entries_.end() || it->pc_offset() != pc_offset) return nullptr;
|
||||
return &*it;
|
||||
}
|
||||
|
||||
private:
|
||||
struct EntryPositionLess {
|
||||
bool operator()(const Entry& a, const Entry& b) const {
|
||||
return a.pc_offset() < b.pc_offset();
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Entry> entries_;
|
||||
};
|
||||
|
||||
// Get the global scope for a given instance. This will contain the wasm memory
|
||||
// (if the instance has a memory) and the values of all globals.
|
||||
Handle<JSObject> GetGlobalScopeObject(Handle<WasmInstanceObject>);
|
||||
|
Loading…
Reference in New Issue
Block a user