[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:
Clemens Backes 2019-11-25 16:58:21 +01:00 committed by Commit Bot
parent 5d29947d06
commit 4105cce511
2 changed files with 144 additions and 8 deletions

View File

@ -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_;

View File

@ -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>);