v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-disassembler-impl.h
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of 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_DISASSEMBLER_IMPL_H_
6#define V8_WASM_WASM_DISASSEMBLER_IMPL_H_
7
11#if !V8_ENABLE_WEBASSEMBLY
12#error This header should only be included if WebAssembly is enabled.
13#endif // !V8_ENABLE_WEBASSEMBLY
14
16#include "src/zone/zone.h"
17
18namespace v8 {
19namespace internal {
20namespace wasm {
21
22template <typename ValidationTag>
23class ImmediatesPrinter;
24
26
28// Configuration flags for aspects of behavior where we might want to change
29// our minds. {true} is the legacy DevTools behavior.
30constexpr bool kSkipFunctionTypesInTypeSection = true;
32constexpr bool kSkipDataSegmentNames = true;
33
35// Helpers.
36
38 public:
39 Indentation(int current, int delta) : current_(current), delta_(delta) {
40 DCHECK_GE(current, 0);
41 DCHECK_GE(delta, 0);
42 }
43
44 Indentation Extra(int extra) { return {current_ + extra, delta_}; }
45
46 void increase() { current_ += delta_; }
47 void decrease() {
50 }
51 int current() { return current_; }
52
53 private:
55 int delta_;
56};
57
59 char* ptr = sb.allocate(indentation.current());
60 memset(ptr, ' ', indentation.current());
61 return sb;
62}
63
64inline StringBuilder& operator<<(StringBuilder& sb, uint64_t n) {
65 if (n == 0) {
66 *sb.allocate(1) = '0';
67 return sb;
68 }
69 static constexpr size_t kBufferSize = 20; // Just enough for a uint64.
70 char buffer[kBufferSize];
71 char* end = buffer + kBufferSize;
72 char* out = end;
73 while (n != 0) {
74 *(--out) = '0' + (n % 10);
75 n /= 10;
76 }
77 sb.write(out, static_cast<size_t>(end - out));
78 return sb;
79}
80
82 return sb << index.index;
83}
84
86 StringBuilder& out, const FunctionSig* sig, uint32_t func_index,
87 NamesProvider* names, bool param_names,
89
90V8_EXPORT_PRIVATE void PrintStringAsJSON(StringBuilder& out,
91 const uint8_t* start,
92 WireBytesRef ref);
93
95// OffsetsProvider.
96
97class OffsetsProvider : public ITracer {
98 public:
99 struct RecGroup {
100 uint32_t offset{kInvalid};
102 uint32_t end_type_index{kInvalid}; // Exclusive.
103
104 // For convenience: built-in support for "maybe" values, useful at the
105 // end of iteration.
106 static constexpr uint32_t kInvalid = ~0u;
107 static constexpr RecGroup Invalid() { return {}; }
108 bool valid() { return start_type_index != kInvalid; }
109 };
110
111 OffsetsProvider() = default;
112
113 // All-in-one, expects to be called on a freshly constructed {OffsetsProvider}
114 // when the {WasmModule} already exists.
115 // The alternative is to pass an {OffsetsProvider} as a tracer to the initial
116 // decoding of the wire bytes, letting it record offsets on the fly.
118 base::Vector<const uint8_t> wire_bytes);
119
120 void TypeOffset(uint32_t offset) override { type_offsets_.push_back(offset); }
121
122 void ImportOffset(uint32_t offset) override {
123 import_offsets_.push_back(offset);
124 }
125
126 void TableOffset(uint32_t offset) override {
127 table_offsets_.push_back(offset);
128 }
129
130 void MemoryOffset(uint32_t offset) override { memory_offset_ = offset; }
131
132 void TagOffset(uint32_t offset) override { tag_offsets_.push_back(offset); }
133
134 void GlobalOffset(uint32_t offset) override {
135 global_offsets_.push_back(offset);
136 }
137
138 void StartOffset(uint32_t offset) override { start_offset_ = offset; }
139
140 void ElementOffset(uint32_t offset) override {
141 element_offsets_.push_back(offset);
142 }
143
144 void DataOffset(uint32_t offset) override { data_offsets_.push_back(offset); }
145
146 void StringOffset(uint32_t offset) override {
147 string_offsets_.push_back(offset);
148 }
149
150 void RecGroupOffset(uint32_t offset, uint32_t group_size) override {
151 uint32_t start_index = static_cast<uint32_t>(type_offsets_.size());
152 recgroups_.push_back({offset, start_index, start_index + group_size});
153 }
154
155 void ImportsDone(const WasmModule* module) override {
156 num_imported_tables_ = module->num_imported_tables;
157 num_imported_globals_ = module->num_imported_globals;
158 num_imported_tags_ = module->num_imported_tags;
159 }
160
161 // Unused by this tracer:
162 void Bytes(const uint8_t* start, uint32_t count) override {}
163 void Description(const char* desc) override {}
164 void Description(const char* desc, size_t length) override {}
165 void Description(uint32_t number) override {}
166 void Description(uint64_t number) override {}
167 void Description(ValueType type) override {}
168 void Description(HeapType type) override {}
169 void Description(const FunctionSig* sig) override {}
170 void NextLine() override {}
171 void NextLineIfFull() override {}
172 void NextLineIfNonEmpty() override {}
173 void InitializerExpression(const uint8_t* start, const uint8_t* end,
174 ValueType expected_type) override {}
175 void FunctionBody(const WasmFunction* func, const uint8_t* start) override {}
176 void FunctionName(uint32_t func_index) override {}
177 void NameSection(const uint8_t* start, const uint8_t* end,
178 uint32_t offset) override {}
179
180#define GETTER(name) \
181 uint32_t name##_offset(uint32_t index) { \
182 DCHECK(index < name##_offsets_.size()); \
183 return name##_offsets_[index]; \
184 }
185 GETTER(type)
186 GETTER(import)
187 GETTER(element)
188 GETTER(data)
189 GETTER(string)
190#undef GETTER
191
192#define IMPORT_ADJUSTED_GETTER(name) \
193 uint32_t name##_offset(uint32_t index) { \
194 DCHECK(index >= num_imported_##name##s_ && \
195 index - num_imported_##name##s_ < name##_offsets_.size()); \
196 return name##_offsets_[index - num_imported_##name##s_]; \
197 }
201#undef IMPORT_ADJUSTED_GETTER
202
203 uint32_t memory_offset() { return memory_offset_; }
204
205 uint32_t start_offset() { return start_offset_; }
206
207 RecGroup recgroup(uint32_t index) {
208 if (index >= recgroups_.size()) return RecGroup::Invalid();
209 return recgroups_[index];
210 }
211
212 private:
216 std::vector<uint32_t> type_offsets_;
217 std::vector<uint32_t> import_offsets_;
218 std::vector<uint32_t> table_offsets_;
219 std::vector<uint32_t> tag_offsets_;
220 std::vector<uint32_t> global_offsets_;
221 std::vector<uint32_t> element_offsets_;
222 std::vector<uint32_t> data_offsets_;
223 std::vector<uint32_t> string_offsets_;
224 uint32_t memory_offset_{0};
225 uint32_t start_offset_{0};
226 std::vector<RecGroup> recgroups_;
227};
228
229inline std::unique_ptr<OffsetsProvider> AllocateOffsetsProvider() {
230 return std::make_unique<OffsetsProvider>();
231}
232
234// FunctionBodyDisassembler.
235
237 : public WasmDecoder<Decoder::FullValidationTag> {
238 public:
240 enum FunctionHeader : bool { kSkipHeader = false, kPrintHeader = true };
241
243 uint32_t func_index, bool shared,
244 WasmDetectedFeatures* detected,
245 const FunctionSig* sig, const uint8_t* start,
246 const uint8_t* end, uint32_t offset,
247 const ModuleWireBytes wire_bytes,
248 NamesProvider* names)
249 : WasmDecoder<ValidationTag>(zone, module, WasmEnabledFeatures::All(),
250 detected, sig, shared, start, end, offset),
251 func_index_(func_index),
252 wire_bytes_(wire_bytes),
253 names_(names) {}
254
255 void DecodeAsWat(MultiLineStringBuilder& out, Indentation indentation,
256 FunctionHeader include_header = kPrintHeader,
257 uint32_t* first_instruction_offset = nullptr);
258
259 void DecodeGlobalInitializer(StringBuilder& out);
260
261 std::set<uint32_t>& used_types() { return used_types_; }
262
263 protected:
264 WasmOpcode GetOpcode();
265
266 uint32_t PrintImmediatesAndGetLength(StringBuilder& out);
267
268 void PrintHexNumber(StringBuilder& out, uint64_t number);
269
270 LabelInfo& label_info(int depth) {
271 return label_stack_[label_stack_.size() - 1 - depth];
272 }
273
274 friend class ImmediatesPrinter<ValidationTag>;
275 uint32_t func_index_;
276 WasmOpcode current_opcode_ = kExprUnreachable;
279 std::set<uint32_t> used_types_;
280 std::vector<LabelInfo> label_stack_;
282 // Labels use two different indexing systems: for looking them up in the
283 // name section, they're indexed by order of occurrence; for generating names
284 // like "$label0", the order in which they show up as targets of branch
285 // instructions is used for generating consecutive names.
286 // (This is legacy wasmparser behavior; we could change it.)
287 uint32_t label_occurrence_index_ = 0;
288 uint32_t label_generation_index_ = 0;
289};
290
292// ModuleDisassembler.
293
295 public:
297 MultiLineStringBuilder& out, const WasmModule* module,
298 NamesProvider* names, const ModuleWireBytes wire_bytes,
299 AccountingAllocator* allocator,
300 std::unique_ptr<OffsetsProvider> offsets_provider = {},
301 std::vector<int>* function_body_offsets = nullptr);
303
304 V8_EXPORT_PRIVATE void PrintTypeDefinition(uint32_t type_index,
305 Indentation indendation,
306 IndexAsComment index_as_comment);
307 V8_EXPORT_PRIVATE void PrintModule(Indentation indentation, size_t max_mb);
308
309 private:
310 void PrintImportName(const WasmImport& import);
311 void PrintExportName(ImportExportKindCode kind, uint32_t index);
312 void PrintMutableType(bool mutability, ValueType type);
313 void PrintTable(const WasmTable& table);
314 void PrintMemory(const WasmMemory& memory);
315 void PrintGlobal(const WasmGlobal& global);
317 ValueType expected_type);
318 void PrintTagSignature(const FunctionSig* sig);
319 void PrintString(WireBytesRef ref);
321 void LineBreakOrSpace(bool break_lines, Indentation indentation,
322 uint32_t byte_offset);
323
328 const uint8_t* start_;
330 std::unique_ptr<OffsetsProvider> offsets_;
331 std::vector<int>* function_body_offsets_;
332};
333
334} // namespace wasm
335} // namespace internal
336} // namespace v8
337
338#endif // V8_WASM_WASM_DISASSEMBLER_IMPL_H_
Builtins::Kind kind
Definition builtins.cc:40
FunctionBodyDisassembler(Zone *zone, const WasmModule *module, uint32_t func_index, bool shared, WasmDetectedFeatures *detected, const FunctionSig *sig, const uint8_t *start, const uint8_t *end, uint32_t offset, const ModuleWireBytes wire_bytes, NamesProvider *names)
void LineBreakOrSpace(bool break_lines, Indentation indentation, uint32_t byte_offset)
V8_EXPORT_PRIVATE ModuleDisassembler(MultiLineStringBuilder &out, const WasmModule *module, NamesProvider *names, const ModuleWireBytes wire_bytes, AccountingAllocator *allocator, std::unique_ptr< OffsetsProvider > offsets_provider={}, std::vector< int > *function_body_offsets=nullptr)
void PrintTable(const WasmTable &table)
void PrintTagSignature(const FunctionSig *sig)
void PrintExportName(ImportExportKindCode kind, uint32_t index)
V8_EXPORT_PRIVATE void PrintTypeDefinition(uint32_t type_index, Indentation indendation, IndexAsComment index_as_comment)
void PrintMemory(const WasmMemory &memory)
void PrintInitExpression(const ConstantExpression &init, ValueType expected_type)
V8_EXPORT_PRIVATE void PrintModule(Indentation indentation, size_t max_mb)
std::unique_ptr< OffsetsProvider > offsets_
void PrintMutableType(bool mutability, ValueType type)
void PrintImportName(const WasmImport &import)
void PrintGlobal(const WasmGlobal &global)
void Description(uint32_t number) override
void DataOffset(uint32_t offset) override
void StartOffset(uint32_t offset) override
void Description(uint64_t number) override
V8_EXPORT_PRIVATE void CollectOffsets(const WasmModule *module, base::Vector< const uint8_t > wire_bytes)
void ImportsDone(const WasmModule *module) override
void GlobalOffset(uint32_t offset) override
void Description(const FunctionSig *sig) override
void Description(const char *desc, size_t length) override
void StringOffset(uint32_t offset) override
void ElementOffset(uint32_t offset) override
void TagOffset(uint32_t offset) override
void TableOffset(uint32_t offset) override
void NameSection(const uint8_t *start, const uint8_t *end, uint32_t offset) override
void TypeOffset(uint32_t offset) override
void MemoryOffset(uint32_t offset) override
void Bytes(const uint8_t *start, uint32_t count) override
void InitializerExpression(const uint8_t *start, const uint8_t *end, ValueType expected_type) override
void Description(const char *desc) override
void RecGroupOffset(uint32_t offset, uint32_t group_size) override
void Description(HeapType type) override
void Description(ValueType type) override
void ImportOffset(uint32_t offset) override
void FunctionBody(const WasmFunction *func, const uint8_t *start) override
void FunctionName(uint32_t func_index) override
void write(const uint8_t *data, size_t n)
int start
int end
StringsStorage * names_
int32_t offset
const int func_index_
const base::Vector< const uint8_t > wire_bytes_
constexpr bool kSkipFunctionTypesInTypeSection
constexpr IndexAsComment kIndicesAsComments
V8_EXPORT_PRIVATE void PrintSignatureOneLine(StringBuilder &out, const FunctionSig *sig, uint32_t func_index, NamesProvider *names, bool param_names, IndexAsComment indices_as_comments=NamesProvider::kDontPrintIndex)
std::unique_ptr< OffsetsProvider > AllocateOffsetsProvider()
constexpr bool kSkipDataSegmentNames
std::ostream & operator<<(std::ostream &os, LiftoffVarState slot)
V8_EXPORT_PRIVATE void PrintStringAsJSON(StringBuilder &out, const uint8_t *start, WireBytesRef ref)
Signature< ValueType > FunctionSig
NamesProvider::IndexAsComment IndexAsComment
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
Definition c-api.cc:87
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define IMPORT_ADJUSTED_GETTER(name)
#define GETTER(name)