v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-debug.h
Go to the documentation of this file.
1// Copyright 2019 the V8 project authors. All rights reserved. Use of
2// this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_WASM_WASM_DEBUG_H_
6#define V8_WASM_WASM_DEBUG_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
12#include <algorithm>
13#include <memory>
14#include <vector>
15
16#include "include/v8-internal.h"
17#include "src/base/iterator.h"
18#include "src/base/logging.h"
19#include "src/base/macros.h"
20#include "src/base/vector.h"
21#include "src/wasm/value-type.h"
23
24namespace v8 {
25namespace internal {
26
27class WasmFrame;
28
29namespace wasm {
30
31class DebugInfoImpl;
32class NativeModule;
33class WasmCode;
34struct WasmFunction;
35struct WasmModule;
36class WasmValue;
37class WireBytesRef;
38
39// Side table storing information used to inspect Liftoff frames at runtime.
40// This table is only created on demand for debugging, so it is not optimized
41// for memory size.
43 public:
44 class Entry {
45 public:
46 enum Storage : int8_t { kConstant, kRegister, kStack };
47 struct Value {
48 int index;
52 union {
53 int32_t i32_const; // if kind == kConstant
54 int reg_code; // if kind == kRegister
55 int stack_offset; // if kind == kStack
56 };
57
58 bool operator==(const Value& other) const {
59 if (index != other.index) return false;
60 if (!EquivalentTypes(type, other.type, module, other.module)) {
61 return false;
62 }
63 if (storage != other.storage) return false;
64 switch (storage) {
65 case kConstant:
66 return i32_const == other.i32_const;
67 case kRegister:
68 return reg_code == other.reg_code;
69 case kStack:
70 return stack_offset == other.stack_offset;
71 }
72 }
73
74 bool is_constant() const { return storage == kConstant; }
75 bool is_register() const { return storage == kRegister; }
76 };
77
82
83 // Constructor for map lookups (only initializes the {pc_offset_}).
84 explicit Entry(int pc_offset) : pc_offset_(pc_offset) {}
85
86 int pc_offset() const { return pc_offset_; }
87
88 // Stack height, including locals.
89 int stack_height() const { return stack_height_; }
90
94
95 const Value* FindChangedValue(int stack_index) const {
96 DCHECK_GT(stack_height_, stack_index);
97 auto it = std::lower_bound(
98 changed_values_.begin(), changed_values_.end(), stack_index,
99 [](const Value& changed_value, int stack_index) {
100 return changed_value.index < stack_index;
101 });
102 return it != changed_values_.end() && it->index == stack_index ? &*it
103 : nullptr;
104 }
105
106 void Print(std::ostream&) const;
107
109
110 private:
113 // Only store differences from the last entry, to keep the table small.
114 std::vector<Value> changed_values_;
115 };
116
117 // Technically it would be fine to copy this class, but there should not be a
118 // reason to do so, hence mark it move only.
120
121 explicit DebugSideTable(int num_locals, std::vector<Entry> entries)
123 DCHECK(
124 std::is_sorted(entries_.begin(), entries_.end(), EntryPositionLess{}));
125 }
126
127 const Entry* GetEntry(int pc_offset) const {
128 auto it = std::lower_bound(entries_.begin(), entries_.end(),
129 Entry{pc_offset}, EntryPositionLess{});
130 if (it == entries_.end() || it->pc_offset() != pc_offset) return nullptr;
131 DCHECK_LE(num_locals_, it->stack_height());
132 return &*it;
133 }
134
135 const Entry::Value* FindValue(const Entry* entry, int stack_index) const {
136 while (true) {
137 if (auto* value = entry->FindChangedValue(stack_index)) {
138 // Check that the table was correctly minimized: If the previous stack
139 // also had an entry for {stack_index}, it must be different.
140 DCHECK(entry == &entries_.front() ||
141 (entry - 1)->stack_height() <= stack_index ||
142 *FindValue(entry - 1, stack_index) != *value);
143 return value;
144 }
145 DCHECK_NE(&entries_.front(), entry);
146 --entry;
147 }
148 }
149
150 auto entries() const {
151 return base::make_iterator_range(entries_.begin(), entries_.end());
152 }
153
154 int num_locals() const { return num_locals_; }
155
156 void Print(std::ostream&) const;
157
159
160 private:
162 bool operator()(const Entry& a, const Entry& b) const {
163 return a.pc_offset() < b.pc_offset();
164 }
165 };
166
168 std::vector<Entry> entries_;
169};
170
171// Debug info per NativeModule, created lazily on demand.
172// Implementation in {wasm-debug.cc} using PIMPL.
174 public:
175 explicit DebugInfo(NativeModule*);
177
178 // For the frame inspection methods below:
179 // {fp} is the frame pointer of the Liftoff frame, {debug_break_fp} that of
180 // the {WasmDebugBreak} frame (if any).
181 int GetNumLocals(Address pc, Isolate* isolate);
182 WasmValue GetLocalValue(int local, Address pc, Address fp,
183 Address debug_break_fp, Isolate* isolate);
184 int GetStackDepth(Address pc, Isolate* isolate);
185
186 const wasm::WasmFunction& GetFunctionAtAddress(Address pc, Isolate* isolate);
187
188 WasmValue GetStackValue(int index, Address pc, Address fp,
189 Address debug_break_fp, Isolate* isolate);
190
191 void SetBreakpoint(int func_index, int offset, Isolate* current_isolate);
192
193 bool IsFrameBlackboxed(WasmFrame* frame);
194 // Returns true if we stay inside the passed frame (or a called frame) after
195 // the step. False if the frame will return after the step.
196 bool PrepareStep(WasmFrame*);
197
198 void PrepareStepOutTo(WasmFrame*);
199
200 void ClearStepping(Isolate*);
201
202 // Remove stepping code from a single frame; this is a performance
203 // optimization only, hitting debug breaks while not stepping and not at a set
204 // breakpoint would be unobservable otherwise.
205 void ClearStepping(WasmFrame*);
206
207 bool IsStepping(WasmFrame*);
208
209 void RemoveBreakpoint(int func_index, int offset, Isolate* current_isolate);
210
211 void RemoveDebugSideTables(base::Vector<WasmCode* const>);
212
213 // Return the debug side table for the given code object, but only if it has
214 // already been created. This will never trigger generation of the table.
215 DebugSideTable* GetDebugSideTableIfExists(const WasmCode*) const;
216
217 void RemoveIsolate(Isolate*);
218
219 size_t EstimateCurrentMemoryConsumption() const;
220
221 private:
222 std::unique_ptr<DebugInfoImpl> impl_;
223};
224
225} // namespace wasm
226} // namespace internal
227} // namespace v8
228
229#endif // V8_WASM_WASM_DEBUG_H_
std::unique_ptr< DebugInfoImpl > impl_
Definition wasm-debug.h:222
base::Vector< const Value > changed_values() const
Definition wasm-debug.h:91
const Value * FindChangedValue(int stack_index) const
Definition wasm-debug.h:95
Entry(int pc_offset, int stack_height, std::vector< Value > changed_values)
Definition wasm-debug.h:78
void Print(std::ostream &) const
Definition wasm-debug.cc:96
const Entry * GetEntry(int pc_offset) const
Definition wasm-debug.h:127
DebugSideTable(int num_locals, std::vector< Entry > entries)
Definition wasm-debug.h:121
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(DebugSideTable)
std::vector< Entry > entries_
Definition wasm-debug.h:168
const Entry::Value * FindValue(const Entry *entry, int stack_index) const
Definition wasm-debug.h:135
size_t EstimateCurrentMemoryConsumption() const
void Print(std::ostream &) const
Definition wasm-debug.cc:89
int32_t offset
int pc_offset
STL namespace.
auto make_iterator_range(ForwardIterator begin, ForwardIterator end)
Definition iterator.h:65
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
wasm::WasmModule WasmModule
return value
Definition map-inl.h:893
wasm::WasmFunction WasmFunction
Definition c-api.cc:87
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
bool operator()(const Entry &a, const Entry &b) const
Definition wasm-debug.h:162
bool operator==(const Value &other) const
Definition wasm-debug.h:58