v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-disassembler.cc
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
6
7#include <iomanip>
8
15
16namespace v8 {
17namespace internal {
18namespace wasm {
19
21// Public interface.
22
23void Disassemble(const WasmModule* module, ModuleWireBytes wire_bytes,
24 NamesProvider* names,
26 std::vector<int>* function_body_offsets) {
28 AccountingAllocator allocator;
29 ModuleDisassembler md(out, module, names, wire_bytes, &allocator,
30 /* no offsets yet */ {}, function_body_offsets);
31 md.PrintModule({0, 2}, v8_flags.wasm_disassembly_max_mb);
32 out.ToDisassemblyCollector(collector);
33}
34
37 std::vector<int>* function_body_offsets) {
38 std::unique_ptr<OffsetsProvider> offsets = AllocateOffsetsProvider();
40 DecodeWasmModuleForDisassembler(wire_bytes, offsets.get());
42 AccountingAllocator allocator;
43 if (result.failed()) {
44 WasmError error = result.error();
45 out << "Decoding error: " << error.message() << " at offset "
46 << error.offset();
47 out.ToDisassemblyCollector(collector);
48 return;
49 }
50 const WasmModule* module = result.value().get();
51 NamesProvider names(module, wire_bytes);
52 ModuleWireBytes module_bytes(wire_bytes);
53 ModuleDisassembler md(out, module, &names, module_bytes, &allocator,
54 std::move(offsets), function_body_offsets);
55 md.PrintModule({0, 2}, v8_flags.wasm_disassembly_max_mb);
56 out.ToDisassemblyCollector(collector);
57}
58
61 if (length() != 0) NextLine(0); // Finalize last line.
62 collector->ReserveLineCount(lines_.size());
63 for (const Line& l : lines_) {
64 // Don't include trailing '\n'.
65 collector->AddLine(l.data, l.len - 1, l.bytecode_offset);
66 }
67}
68
69void DisassembleFunctionImpl(const WasmModule* module, int func_index,
70 base::Vector<const uint8_t> function_body,
71 ModuleWireBytes module_bytes, NamesProvider* names,
72 std::ostream& os, std::vector<uint32_t>* offsets) {
74 const wasm::WasmFunction& func = module->functions[func_index];
75 AccountingAllocator allocator;
76 Zone zone(&allocator, "Wasm disassembler");
77 bool shared = module->type(func.sig_index).is_shared;
78 WasmDetectedFeatures detected;
79 FunctionBodyDisassembler d(&zone, module, func_index, shared, &detected,
80 func.sig, function_body.begin(),
81 function_body.end(), func.code.offset(),
82 module_bytes, names);
83 d.DecodeAsWat(sb, {0, 2}, FunctionBodyDisassembler::kPrintHeader);
84 const bool print_offsets = false;
85 sb.WriteTo(os, print_offsets, offsets);
86}
87
88void DisassembleFunction(const WasmModule* module, int func_index,
90 NamesProvider* names, std::ostream& os) {
91 DCHECK(func_index < static_cast<int>(module->functions.size()) &&
92 func_index >= static_cast<int>(module->num_imported_functions));
93 ModuleWireBytes module_bytes(wire_bytes);
95 module_bytes.GetFunctionBytes(&module->functions[func_index]);
96 std::vector<uint32_t>* collect_offsets = nullptr;
97 DisassembleFunctionImpl(module, func_index, code, module_bytes, names, os,
98 collect_offsets);
99}
100
101void DisassembleFunction(const WasmModule* module, int func_index,
102 base::Vector<const uint8_t> function_body,
103 base::Vector<const uint8_t> maybe_wire_bytes,
104 uint32_t function_body_offset, std::ostream& os,
105 std::vector<uint32_t>* offsets) {
106 DCHECK(func_index < static_cast<int>(module->functions.size()) &&
107 func_index >= static_cast<int>(module->num_imported_functions));
108 NamesProvider fake_names(module, maybe_wire_bytes);
109 DisassembleFunctionImpl(module, func_index, function_body,
110 ModuleWireBytes{nullptr, 0}, &fake_names, os,
111 offsets);
112}
113
115// Helpers.
116
117static constexpr char kHexChars[] = "0123456789abcdef";
118static constexpr char kUpperHexChars[] = "0123456789ABCDEF";
119
120// Returns the log2 of the alignment, e.g. "4" means 2<<4 == 16 bytes.
121// This is the same format as used in .wasm binary modules.
123 switch (opcode) {
124 case kExprS128LoadMem:
125 case kExprS128StoreMem:
126 return 4;
127 case kExprS128Load8x8S:
128 case kExprS128Load8x8U:
129 case kExprS128Load16x4S:
130 case kExprS128Load16x4U:
131 case kExprS128Load32x2S:
132 case kExprS128Load32x2U:
133 case kExprS128Load64Splat:
134 case kExprS128Load64Zero:
135 case kExprS128Load64Lane:
136 case kExprS128Store64Lane:
137 return 3;
138 case kExprS128Load32Splat:
139 case kExprS128Load32Zero:
140 case kExprS128Load32Lane:
141 case kExprS128Store32Lane:
142 return 2;
143 case kExprS128Load16Splat:
144 case kExprS128Load16Lane:
145 case kExprS128Store16Lane:
146 return 1;
147 case kExprS128Load8Splat:
148 case kExprS128Load8Lane:
149 case kExprS128Store8Lane:
150 return 0;
151
152#define CASE(Opcode, ...) \
153 case kExpr##Opcode: \
154 return GetLoadType(kExpr##Opcode).size_log_2();
156#undef CASE
157#define CASE(Opcode, ...) \
158 case kExpr##Opcode: \
159 return GetStoreType(kExpr##Opcode).size_log_2();
161#undef CASE
162
163#define CASE(Opcode, Type) \
164 case kExpr##Opcode: \
165 return ElementSizeLog2Of(MachineType::Type().representation());
168#undef CASE
169
170 default:
171 UNREACHABLE();
172 }
173}
174
176 uint32_t func_index, NamesProvider* names,
177 bool param_names,
178 IndexAsComment indices_as_comments) {
179 if (param_names) {
180 for (uint32_t i = 0; i < sig->parameter_count(); i++) {
181 out << " (param ";
182 names->PrintLocalName(out, func_index, i, indices_as_comments);
183 out << ' ';
184 names->PrintValueType(out, sig->GetParam(i));
185 out << ")";
186 }
187 } else if (sig->parameter_count() > 0) {
188 out << " (param";
189 for (uint32_t i = 0; i < sig->parameter_count(); i++) {
190 out << " ";
191 names->PrintValueType(out, sig->GetParam(i));
192 }
193 out << ")";
194 }
195 for (size_t i = 0; i < sig->return_count(); i++) {
196 out << " (result ";
197 names->PrintValueType(out, sig->GetReturn(i));
198 out << ")";
199 }
200}
201
202void PrintStringRaw(StringBuilder& out, const uint8_t* start,
203 const uint8_t* end) {
204 for (const uint8_t* ptr = start; ptr < end; ptr++) {
205 uint8_t b = *ptr;
206 if (b < 32 || b >= 127 || b == '"' || b == '\\') {
207 out << '\\' << kHexChars[b >> 4] << kHexChars[b & 0xF];
208 } else {
209 out << static_cast<char>(b);
210 }
211 }
212}
213
215// FunctionBodyDisassembler.
216
218 Indentation indentation,
219 FunctionHeader include_header,
220 uint32_t* first_instruction_offset) {
221 out_ = &out;
222 int base_indentation = indentation.current();
223 // Print header.
224 if (include_header == kPrintHeader) {
225 out << indentation << "(func ";
229 out.NextLine(pc_offset());
230 } else {
231 out.set_current_line_bytecode_offset(pc_offset());
232 }
233 indentation.increase();
234
235 // Decode and print locals.
236 uint32_t locals_length = DecodeLocals(pc_);
237 if (failed()) {
238 // TODO(jkummerow): Improve error handling.
239 out << "Failed to decode locals\n";
240 return;
241 }
242 for (uint32_t i = static_cast<uint32_t>(sig_->parameter_count());
243 i < num_locals_; i++) {
244 out << indentation << "(local ";
246 out << " ";
248 out << ")";
249 out.NextLine(pc_offset());
250 }
251 consume_bytes(locals_length);
252 out.set_current_line_bytecode_offset(pc_offset());
253 if (first_instruction_offset) *first_instruction_offset = pc_offset();
254
255 // Main loop.
256 while (pc_ < end_ && ok()) {
257 WasmOpcode opcode = GetOpcode();
258 current_opcode_ = opcode; // Some immediates need to know this.
259
260 // Deal with indentation.
261 if (opcode == kExprEnd || opcode == kExprElse || opcode == kExprCatch ||
262 opcode == kExprCatchAll || opcode == kExprDelegate) {
263 if (indentation.current() >= base_indentation) {
264 indentation.decrease();
265 }
266 }
267 out << indentation;
268 if (opcode == kExprElse || opcode == kExprCatch ||
269 opcode == kExprCatchAll || opcode == kExprBlock || opcode == kExprIf ||
270 opcode == kExprLoop || opcode == kExprTry || opcode == kExprTryTable) {
271 indentation.increase();
272 }
273
274 // Print the opcode and its immediates.
275 if (opcode == kExprEnd) {
276 if (indentation.current() < base_indentation) {
277 out << ";; Unexpected end byte";
278 } else if (indentation.current() == base_indentation) {
279 out << ")"; // End of the function.
280 } else {
281 out << "end";
282 const LabelInfo& label = label_stack_.back();
283 if (label.start != nullptr) {
284 out << " ";
285 out.write(label.start, label.length);
286 }
287 label_stack_.pop_back();
288 }
289 } else {
290 out << WasmOpcodes::OpcodeName(opcode);
291 }
292 if (opcode == kExprBlock || opcode == kExprIf || opcode == kExprLoop ||
293 opcode == kExprTry || opcode == kExprTryTable) {
294 // Create the LabelInfo now to get the correct offset, but only push it
295 // after printing the immediates because the immediates don't see the new
296 // label yet.
297 LabelInfo label(out.line_number(), out.length(),
300 label_stack_.push_back(label);
301 } else {
303 }
304
305 out.NextLine(pc_offset());
306 }
307
308 if (pc_ != end_) {
309 // TODO(jkummerow): Improve error handling.
310 out << "Beyond end of code";
311 }
312}
313
315 while (pc_ < end_) {
316 WasmOpcode opcode = GetOpcode();
317 current_opcode_ = opcode; // Some immediates need to know this.
318 // Don't print the final "end".
319 if (opcode == kExprEnd && pc_ + 1 == end_) break;
320 uint32_t length;
321 out << " (" << WasmOpcodes::OpcodeName(opcode);
322 length = PrintImmediatesAndGetLength(out);
323 out << ")";
324 pc_ += length;
325 }
326}
327
329 WasmOpcode opcode = static_cast<WasmOpcode>(*pc_);
330 if (!WasmOpcodes::IsPrefixOpcode(opcode)) return opcode;
332}
333
335 uint64_t number) {
336 constexpr size_t kBufferSize = sizeof(number) * 2 + 2; // +2 for "0x".
337 char buffer[kBufferSize];
338 char* end = buffer + kBufferSize;
339 char* ptr = end;
340 do {
341 *(--ptr) = kHexChars[number & 0xF];
342 number >>= 4;
343 } while (number > 0);
344 *(--ptr) = 'x';
345 *(--ptr) = '0';
346 size_t length = static_cast<size_t>(end - ptr);
347 char* output = out.allocate(length);
348 memcpy(output, ptr, length);
349}
350
352// ImmediatesPrinter.
353
354template <typename ValidationTag>
356 public:
359
360 void PrintDepthAsLabel(int imm_depth) {
361 out_ << " ";
362 size_t label_start_position = out_.length();
363 int depth = imm_depth;
364 if (owner_->current_opcode_ == kExprDelegate) depth++;
365 // Be robust: if the module is invalid, print what we got.
366 if (depth < 0 || depth >= static_cast<int>(owner_->label_stack_.size())) {
367 out_ << imm_depth;
368 return;
369 }
370 // If the label's name has already been determined and backpatched, just
371 // copy it here.
372 LabelInfo& label_info = owner_->label_info(depth);
373 if (label_info.start != nullptr) {
374 out_.write(label_info.start, label_info.length);
375 return;
376 }
377 // Determine the label's name and backpatch the line that opened the block.
379 label_info.name_section_index,
381 label_info.length = out_.length() - label_start_position;
382 owner_->out_->PatchLabel(label_info, out_.start() + label_start_position);
383 }
384
386 if (owner_->module_->has_signature(sig_index)) {
387 const FunctionSig* sig = owner_->module_->signature(sig_index);
388 PrintSignatureOneLine(out_, sig, 0 /* ignored */, names(), false);
389 } else {
390 out_ << " (signature: " << sig_index << " INVALID)";
391 }
392 }
393
395 if (imm.sig.all().begin() == nullptr) {
397 } else {
398 PrintSignatureOneLine(out_, &imm.sig, 0 /* ignored */, names(), false);
399 }
400 }
401
403 out_ << " ";
404 names()->PrintHeapType(out_, imm.type);
405 if (imm.type.is_index()) use_type(imm.type.ref_index());
406 }
407
408 void ValueType(ValueType type) {
409 out_ << " ";
410 names()->PrintValueType(out_, type);
411 if (type.has_index()) use_type(type.ref_index());
412 }
413
415 // Ignored here. For printing text format, we do all the work via the
416 // two calls to {ValueType()} that we get for a br_on_cast.
417 }
418
420
422 const uint8_t* pc = imm.table;
423 for (uint32_t i = 0; i <= imm.table_count; i++) {
424 auto [target, length] = owner_->read_u32v<ValidationTag>(pc);
425 PrintDepthAsLabel(target);
426 pc += length;
427 }
428 }
429
431 switch (kind) {
432 case kCatch:
433 return "catch";
434 case kCatchRef:
435 return "catch_ref";
436 case kCatchAll:
437 return "catch_all";
438 case kCatchAllRef:
439 return "catch_all_ref";
440 default:
441 return "<invalid>";
442 }
443 }
444
446 const uint8_t* pc = imm.table;
447 for (uint32_t i = 0; i < imm.table_count; i++) {
448 uint8_t kind = owner_->read_u8<ValidationTag>(pc);
449 pc += 1;
450 out_ << " " << CatchKindToString(static_cast<CatchKind>(kind));
451 if (kind == kCatch || kind == kCatchRef) {
452 auto [tag, length] = owner_->read_u32v<ValidationTag>(pc);
453 out_ << " ";
454 names()->PrintTagName(out_, tag);
455 pc += length;
456 }
457 auto [target, length] = owner_->read_u32v<ValidationTag>(pc);
458 PrintDepthAsLabel(target);
459 pc += length;
460 }
461 }
462
464 const uint8_t* pc = imm.table;
465 for (uint32_t i = 0; i < imm.table_count; i++) {
466 uint8_t kind = owner_->read_u8<ValidationTag>(pc);
467 pc += 1;
468 auto [tag, length] = owner_->read_u32v<ValidationTag>(pc);
469 out_ << "(on ";
470 names()->PrintTagName(out_, tag);
471 out_ << " ";
472 pc += length;
473 if (kind == kOnSuspend) {
474 auto [target, tlen] = owner_->read_u32v<ValidationTag>(pc);
475 PrintDepthAsLabel(target);
476 pc += tlen;
477 out_ << ")";
478 } else {
479 out_ << " switch)";
480 }
481 }
482 }
483
488
490 out_ << " ";
491 names()->PrintValueType(out_, imm.type);
492 }
493
495 if (imm.offset != 0) out_ << " offset=" << imm.offset;
497 out_ << " align=" << (1u << imm.alignment);
498 }
499 }
500
501 void SimdLane(SimdLaneImmediate& imm) { out_ << " " << uint32_t{imm.lane}; }
502
505 out_ << " ";
507 imm.field_imm.index);
508 }
509
511 out_ << " " << imm.index; // --
512 }
513
515 out_ << " ";
516 names()->PrintTagName(out_, imm.index);
517 }
518
523
525 out_ << " ";
526 names()->PrintTypeName(out_, imm.index);
527 use_type(imm.index);
528 }
529
531 out_ << " ";
533 }
534
536 out_ << " ";
538 }
539
541 out_ << " ";
543 }
544
546 if (imm.index == 0) return;
547 out_ << " " << imm.index;
548 }
549
552 out_ << " " << imm.index;
553 } else {
554 out_ << " ";
556 }
557 }
558
560 out_ << " ";
562 }
563
565 out_ << " " << imm.value; // --
566 }
567
569 if (imm.value >= 0) {
570 out_ << " " << static_cast<uint64_t>(imm.value);
571 } else {
572 out_ << " -" << ((~static_cast<uint64_t>(imm.value)) + 1);
573 }
574 }
575
577 float f = imm.value;
578 if (f == 0) {
579 out_ << (1 / f < 0 ? " -0.0" : " 0.0");
580 } else if (std::isinf(f)) {
581 out_ << (f > 0 ? " inf" : " -inf");
582 } else if (std::isnan(f)) {
583 uint32_t bits = base::bit_cast<uint32_t>(f);
584 uint32_t payload = bits & 0x7F'FFFFu;
585 uint32_t signbit = bits >> 31;
586 if (payload == 0x40'0000u) {
587 out_ << (signbit == 1 ? " -nan" : " nan");
588 } else {
589 out_ << (signbit == 1 ? " -nan:" : " +nan:");
590 owner_->PrintHexNumber(out_, payload);
591 }
592 } else {
593 std::ostringstream o;
594 // TODO(dlehmann): Change to `std::format` (C++20) or to `std::to_chars`
595 // (C++17) once available, so that `0.1` isn't printed as `0.100000001`
596 // any more.
597 o << std::setprecision(std::numeric_limits<float>::max_digits10) << f;
598 out_ << " " << o.str();
599 }
600 }
601
603 double d = imm.value;
604 if (d == 0) {
605 out_ << (1 / d < 0 ? " -0.0" : " 0.0");
606 } else if (std::isinf(d)) {
607 out_ << (d > 0 ? " inf" : " -inf");
608 } else if (std::isnan(d)) {
609 uint64_t bits = base::bit_cast<uint64_t>(d);
610 uint64_t payload = bits & 0xF'FFFF'FFFF'FFFFull;
611 uint64_t signbit = bits >> 63;
612 if (payload == 0x8'0000'0000'0000ull) {
613 out_ << (signbit == 1 ? " -nan" : " nan");
614 } else {
615 out_ << (signbit == 1 ? " -nan:" : " +nan:");
616 owner_->PrintHexNumber(out_, payload);
617 }
618 } else {
619 char buffer[100];
620 std::string_view str =
621 DoubleToStringView(d, base::VectorOf(buffer, 100u));
622 out_ << " " << str;
623 }
624 }
625
627 if (owner_->current_opcode_ == kExprI8x16Shuffle) {
628 for (int i = 0; i < 16; i++) {
629 out_ << " " << uint32_t{imm.value[i]};
630 }
631 } else {
632 DCHECK_EQ(owner_->current_opcode_, kExprS128Const);
633 out_ << " i32x4";
634 for (int i = 0; i < 4; i++) {
635 out_ << " 0x";
636 for (int j = 3; j >= 0; j--) { // Little endian.
637 uint8_t b = imm.value[i * 4 + j];
639 out_ << kUpperHexChars[b & 0xF];
640 }
641 }
642 }
643 }
644
646 if (imm.index >= owner_->module_->stringref_literals.size()) {
647 out_ << " " << imm.index << " INVALID";
648 return;
649 }
650 if (owner_->wire_bytes_.start() == nullptr) {
651 out_ << " " << imm.index;
652 return;
653 }
654 out_ << " \"";
655 const WasmStringRefLiteral& lit =
656 owner_->module_->stringref_literals[imm.index];
657 const uint8_t* start = owner_->wire_bytes_.start() + lit.source.offset();
658 static constexpr uint32_t kMaxCharsPrinted = 40;
659 if (lit.source.length() <= kMaxCharsPrinted) {
660 const uint8_t* end =
661 owner_->wire_bytes_.start() + lit.source.end_offset();
663 } else {
664 const uint8_t* end = start + kMaxCharsPrinted - 1;
666 out_ << "…";
667 }
668 out_ << '"';
669 if (kIndicesAsComments) out_ << " (;" << imm.index << ";)";
670 }
671
674 if (imm.memory.index != 0) out_ << " " << uint32_t{imm.memory.index};
675 }
676
678 if (imm.memory_dst.index == 0 && imm.memory_src.index == 0) return;
679 out_ << " " << uint32_t{imm.memory_dst.index};
680 out_ << " " << uint32_t{imm.memory_src.index};
681 }
682
684 if (imm.table.index != 0) TableIndex(imm.table);
686 }
687
689 if (imm.table_dst.index == 0 && imm.table_src.index == 0) return;
690 out_ << " ";
692 out_ << " ";
694 }
695
697 out_ << " ";
698 names()->PrintTypeName(out_, dst.index);
699 out_ << " ";
700 names()->PrintTypeName(out_, src.index);
701 use_type(dst.index);
702 use_type(src.index);
703 }
704
705 private:
706 void use_type(ModuleTypeIndex type_index) {
707 owner_->used_types_.insert(type_index.index);
708 }
709
711
712 uint32_t func_index() { return owner_->func_index_; }
713
716};
717
719 StringBuilder& out) {
720 using Printer = ImmediatesPrinter<ValidationTag>;
721 Printer imm_printer(out, this);
722 return WasmDecoder::OpcodeLength<Printer>(this, this->pc_, imm_printer);
723}
724
726// OffsetsProvider.
727
729 base::Vector<const uint8_t> wire_bytes) {
730 num_imported_tables_ = module->num_imported_tables;
731 num_imported_globals_ = module->num_imported_globals;
732 num_imported_tags_ = module->num_imported_tags;
733 type_offsets_.reserve(module->types.size());
734 import_offsets_.reserve(module->import_table.size());
735 table_offsets_.reserve(module->tables.size() - num_imported_tables_);
736 tag_offsets_.reserve(module->tags.size() - num_imported_tags_);
737 global_offsets_.reserve(module->globals.size() - num_imported_globals_);
738 element_offsets_.reserve(module->elem_segments.size());
739 data_offsets_.reserve(module->data_segments.size());
740 recgroups_.reserve(4); // We can't know, so this is just a guess.
741
742 WasmDetectedFeatures unused_detected_features;
744 &unused_detected_features, this};
745 constexpr bool kNoVerifyFunctions = false;
746 decoder.DecodeModule(kNoVerifyFunctions);
747}
748
750// ModuleDisassembler.
751
753 MultiLineStringBuilder& out, const WasmModule* module, NamesProvider* names,
754 const ModuleWireBytes wire_bytes, AccountingAllocator* allocator,
755 std::unique_ptr<OffsetsProvider> offsets_provider,
756 std::vector<int>* function_body_offsets)
757 : out_(out),
758 module_(module),
759 names_(names),
760 wire_bytes_(wire_bytes),
762 zone_(allocator, "disassembler zone"),
763 offsets_(offsets_provider.release()),
764 function_body_offsets_(function_body_offsets) {
765 if (!offsets_) {
766 offsets_ = std::make_unique<OffsetsProvider>();
767 offsets_->CollectOffsets(module, wire_bytes_.module_bytes());
768 }
769}
770
772
774 Indentation indentation,
775 IndexAsComment index_as_comment) {
776 uint32_t offset = offsets_->type_offset(type_index);
778 out_ << indentation << "(type ";
779 names_->PrintTypeName(out_, type_index, index_as_comment);
780 const TypeDefinition& type = module_->types[type_index];
781 bool has_super = type.supertype != kNoSuperType;
782 if (has_super) {
783 out_ << " (sub ";
784 if (type.is_final) out_ << "final ";
786 HeapType::Index(type.supertype, type.is_shared,
787 static_cast<RefTypeKind>(type.kind)));
788 }
789 if (type.kind == TypeDefinition::kArray) {
790 const ArrayType* atype = type.array_type;
791 out_ << " (array";
792 if (type.is_shared) out_ << " shared";
793 out_ << " (field ";
794 PrintMutableType(atype->mutability(), atype->element_type());
795 out_ << ")"; // Closes "(field ...".
796 } else if (type.kind == TypeDefinition::kStruct) {
797 const StructType* stype = type.struct_type;
798 out_ << " (struct";
799 if (type.is_shared) out_ << " shared";
800 bool break_lines = stype->field_count() > 2;
801 for (uint32_t i = 0; i < stype->field_count(); i++) {
802 LineBreakOrSpace(break_lines, indentation, offset);
803 out_ << "(field ";
804 names_->PrintFieldName(out_, type_index, i);
805 out_ << " ";
806 PrintMutableType(stype->mutability(i), stype->field(i));
807 out_ << ")";
808 }
809 } else if (type.kind == TypeDefinition::kFunction) {
810 const FunctionSig* sig = type.function_sig;
811 out_ << " (func";
812 if (type.is_shared) out_ << " shared";
813 bool break_lines = sig->parameter_count() + sig->return_count() > 2;
814 for (uint32_t i = 0; i < sig->parameter_count(); i++) {
815 LineBreakOrSpace(break_lines, indentation, offset);
816 out_ << "(param ";
817 names_->PrintLocalName(out_, type_index, i);
818 out_ << " ";
819 names_->PrintValueType(out_, sig->GetParam(i));
820 out_ << ")";
821 }
822 for (uint32_t i = 0; i < sig->return_count(); i++) {
823 LineBreakOrSpace(break_lines, indentation, offset);
824 out_ << "(result ";
825 names_->PrintValueType(out_, sig->GetReturn(i));
826 out_ << ")";
827 }
828 }
829 // Closes "(type", "(sub", and "(array" / "(struct" / "(func".
830 out_ << (has_super ? ")))" : "))");
831}
832
833void ModuleDisassembler::PrintModule(Indentation indentation, size_t max_mb) {
834 // 0. General infrastructure.
835 // We don't store import/export information on {WasmTag} currently.
836 size_t num_tags = module_->tags.size();
837 std::vector<bool> exported_tags(num_tags, false);
838 for (const WasmExport& ex : module_->export_table) {
839 if (ex.kind == kExternalTag) exported_tags[ex.index] = true;
840 }
841
842 // I. Module name.
843 out_ << indentation << "(module";
844 if (module_->name.is_set()) {
845 out_ << " $";
846 const uint8_t* name_start = start_ + module_->name.offset();
847 out_.write(name_start, module_->name.length());
848 }
849 indentation.increase();
850
851 // II. Types
852 uint32_t recgroup_index = 0;
853 OffsetsProvider::RecGroup recgroup = offsets_->recgroup(recgroup_index++);
854 bool in_explicit_recgroup = false;
855 for (uint32_t i = 0; i < module_->types.size(); i++) {
856 // No need to check {recgroup.valid()}, as the comparison will simply
857 // never be true otherwise.
858 while (i == recgroup.start_type_index) {
859 out_.NextLine(recgroup.offset);
860 out_ << indentation << "(rec";
861 if V8_UNLIKELY (recgroup.end_type_index == i) {
862 // Empty recgroup.
863 out_ << ")";
864 DCHECK(!in_explicit_recgroup);
865 recgroup = offsets_->recgroup(recgroup_index++);
866 continue;
867 } else {
868 in_explicit_recgroup = true;
869 indentation.increase();
870 break;
871 }
872 }
874 module_->has_signature(ModuleTypeIndex{i}) && !in_explicit_recgroup) {
875 continue;
876 }
878 if (in_explicit_recgroup && i == recgroup.end_type_index - 1) {
879 in_explicit_recgroup = false;
880 indentation.decrease();
881 // The end of a recgroup is implicit in the wire bytes, so repeat the
882 // previous line's offset for it.
885 out_ << indentation << ")";
886 recgroup = offsets_->recgroup(recgroup_index++);
887 }
888 }
889 while (recgroup.valid()) {
890 // There could be empty recgroups at the end of the type section.
891 DCHECK_GE(recgroup.start_type_index, module_->types.size());
892 DCHECK_EQ(recgroup.start_type_index, recgroup.end_type_index);
893 out_.NextLine(recgroup.offset);
894 out_ << indentation << "(rec)";
895 recgroup = offsets_->recgroup(recgroup_index++);
896 }
897
898 // III. Imports
899 for (uint32_t i = 0; i < module_->import_table.size(); i++) {
900 const WasmImport& import = module_->import_table[i];
901 out_.NextLine(offsets_->import_offset(i));
902 out_ << indentation;
903 switch (import.kind) {
904 case kExternalTable: {
905 out_ << "(table ";
907 const WasmTable& table = module_->tables[import.index];
908 if (table.exported) PrintExportName(kExternalTable, import.index);
909 PrintImportName(import);
910 PrintTable(table);
911 break;
912 }
913 case kExternalFunction: {
914 out_ << "(func ";
917 const WasmFunction& func = module_->functions[import.index];
918 if (func.exported) PrintExportName(kExternalFunction, import.index);
919 PrintImportName(import);
920 PrintSignatureOneLine(out_, func.sig, import.index, names_, false);
921 break;
922 }
923 case kExternalGlobal: {
924 out_ << "(global ";
926 const WasmGlobal& global = module_->globals[import.index];
927 if (global.exported) PrintExportName(kExternalGlobal, import.index);
928 PrintImportName(import);
929 PrintGlobal(global);
930 break;
931 }
932 case kExternalMemory:
933 out_ << "(memory ";
935 if (module_->memories[import.index].exported) {
937 }
938 PrintImportName(import);
939 PrintMemory(module_->memories[import.index]);
940 break;
941 case kExternalTag:
942 out_ << "(tag ";
944 PrintImportName(import);
945 if (exported_tags[import.index]) {
946 PrintExportName(kExternalTag, import.index);
947 }
948 PrintTagSignature(module_->tags[import.index].sig);
949 break;
950 }
951 out_ << ")";
952 }
953
954 // IV. Tables
955 for (uint32_t i = module_->num_imported_tables; i < module_->tables.size();
956 i++) {
957 const WasmTable& table = module_->tables[i];
958 DCHECK(!table.imported);
959 out_.NextLine(offsets_->table_offset(i));
960 out_ << indentation << "(table ";
962 if (table.exported) PrintExportName(kExternalTable, i);
963 PrintTable(table);
964 out_ << ")";
965 }
966
967 // V. Memories
968 uint32_t num_memories = static_cast<uint32_t>(module_->memories.size());
969 for (uint32_t memory_index = 0; memory_index < num_memories; ++memory_index) {
970 const WasmMemory& memory = module_->memories[memory_index];
971 if (memory.imported) continue;
972 out_.NextLine(offsets_->memory_offset());
973 out_ << indentation << "(memory ";
975 if (memory.exported) PrintExportName(kExternalMemory, memory_index);
976 PrintMemory(memory);
977 out_ << ")";
978 }
979
980 // VI.Tags
981 for (uint32_t i = module_->num_imported_tags; i < module_->tags.size(); i++) {
982 const WasmTag& tag = module_->tags[i];
983 out_.NextLine(offsets_->tag_offset(i));
984 out_ << indentation << "(tag ";
986 if (exported_tags[i]) PrintExportName(kExternalTag, i);
988 out_ << ")";
989 }
990
991 // VII. String literals
992 size_t num_strings = module_->stringref_literals.size();
993 for (uint32_t i = 0; i < num_strings; i++) {
994 const WasmStringRefLiteral lit = module_->stringref_literals[i];
995 out_.NextLine(offsets_->string_offset(i));
996 out_ << indentation << "(string \"";
997 PrintString(lit.source);
998 out_ << '"';
999 if (kIndicesAsComments) out_ << " (;" << i << ";)";
1000 out_ << ")";
1001 }
1002
1003 // VIII. Globals
1004 for (uint32_t i = module_->num_imported_globals; i < module_->globals.size();
1005 i++) {
1006 const WasmGlobal& global = module_->globals[i];
1007 DCHECK(!global.imported);
1008 out_.NextLine(offsets_->global_offset(i));
1009 out_ << indentation << "(global ";
1012 PrintGlobal(global);
1013 PrintInitExpression(global.init, global.type);
1014 out_ << ")";
1015 }
1016
1017 // IX. Start
1018 if (module_->start_function_index >= 0) {
1019 out_.NextLine(offsets_->start_offset());
1020 out_ << indentation << "(start ";
1021 names_->PrintFunctionName(out_, module_->start_function_index,
1023 out_ << ")";
1024 }
1025
1026 // X. Elements
1027 for (uint32_t i = 0; i < module_->elem_segments.size(); i++) {
1028 const WasmElemSegment& elem = module_->elem_segments[i];
1029 out_.NextLine(offsets_->element_offset(i));
1030 out_ << indentation << "(elem ";
1033 out_ << " declare";
1034 } else if (elem.status == WasmElemSegment::kStatusActive) {
1035 if (elem.table_index != 0) {
1036 out_ << " (table ";
1038 out_ << ")";
1039 }
1041 }
1042 out_ << " ";
1043 if (elem.shared) out_ << "shared ";
1045
1046 WasmDetectedFeatures unused_detected_features;
1047 ModuleDecoderImpl decoder(
1048 WasmEnabledFeatures::All(), wire_bytes_.module_bytes(),
1049 ModuleOrigin::kWasmOrigin, &unused_detected_features);
1051 for (size_t j = 0; j < elem.element_count; j++) {
1053 const_cast<WasmModule*>(module_), elem);
1054 PrintInitExpression(entry, elem.type);
1055 }
1056 out_ << ")";
1057 }
1058
1059 // For the FunctionBodyDisassembler, we flip the convention: {NextLine} is
1060 // now called *after* printing something, instead of before.
1061 if (out_.length() != 0) out_.NextLine(0);
1062
1063 // XI. Code / function bodies.
1064 if (function_body_offsets_ != nullptr) {
1065 size_t num_defined_functions =
1066 module_->functions.size() - module_->num_imported_functions;
1067 function_body_offsets_->reserve(num_defined_functions * 2);
1068 }
1069 for (uint32_t i = module_->num_imported_functions;
1070 i < module_->functions.size(); i++) {
1071 const WasmFunction* func = &module_->functions[i];
1073 out_ << indentation << "(func ";
1078 out_.NextLine(func->code.offset());
1079 bool shared = module_->type(func->sig_index).is_shared;
1080 WasmDetectedFeatures detected;
1081 base::Vector<const uint8_t> code = wire_bytes_.GetFunctionBytes(func);
1082 FunctionBodyDisassembler d(&zone_, module_, i, shared, &detected, func->sig,
1083 code.begin(), code.end(), func->code.offset(),
1085 uint32_t first_instruction_offset;
1086 d.DecodeAsWat(out_, indentation, FunctionBodyDisassembler::kSkipHeader,
1087 &first_instruction_offset);
1088 if (function_body_offsets_ != nullptr) {
1089 function_body_offsets_->push_back(first_instruction_offset);
1090 function_body_offsets_->push_back(d.pc_offset());
1091 }
1092 if (out_.ApproximateSizeMB() > max_mb) {
1093 out_ << "<truncated...>";
1094 return;
1095 }
1096 }
1097
1098 // XII. Data
1099 for (uint32_t i = 0; i < module_->data_segments.size(); i++) {
1100 const WasmDataSegment& data = module_->data_segments[i];
1102 out_ << indentation << "(data";
1103 if (!kSkipDataSegmentNames) {
1104 out_ << " ";
1106 }
1107 if (data.shared) out_ << " shared";
1108 if (data.active) {
1109 ValueType type = module_->memories[data.memory_index].is_memory64()
1110 ? kWasmI64
1111 : kWasmI32;
1112 PrintInitExpression(data.dest_addr, type);
1113 }
1114 out_ << " \"";
1115 PrintString(data.source);
1116 out_ << "\")";
1117 out_.NextLine(0);
1118
1119 if (out_.ApproximateSizeMB() > max_mb) {
1120 out_ << "<truncated...>";
1121 return;
1122 }
1123 }
1124
1125 indentation.decrease();
1127 static_cast<uint32_t>(wire_bytes_.length()));
1128 out_ << indentation << ")"; // End of the module.
1129 out_.NextLine(0);
1130}
1131
1133 out_ << " (import \"";
1134 PrintString(import.module_name);
1135 out_ << "\" \"";
1136 PrintString(import.field_name);
1137 out_ << "\")";
1138}
1139
1141 uint32_t index) {
1142 for (const WasmExport& ex : module_->export_table) {
1143 if (ex.kind != kind || ex.index != index) continue;
1144 out_ << " (export \"";
1146 out_ << "\")";
1147 }
1148}
1149
1151 if (mutability) out_ << "(mut ";
1152 names_->PrintValueType(out_, type);
1153 if (mutability) out_ << ")";
1154}
1155
1157 if (table.shared) out_ << " shared";
1158 out_ << " " << table.initial_size << " ";
1159 if (table.has_maximum_size) out_ << table.maximum_size << " ";
1160 names_->PrintValueType(out_, table.type);
1161}
1162
1164 out_ << " " << memory.initial_pages;
1165 if (memory.has_maximum_pages) out_ << " " << memory.maximum_pages;
1166 if (memory.is_shared) out_ << " shared";
1167}
1168
1170 out_ << " ";
1171 if (global.shared) out_ << "shared ";
1172 PrintMutableType(global.mutability, global.type);
1173}
1174
1176 ValueType expected_type) {
1177 switch (init.kind()) {
1179 break;
1181 out_ << " (i32.const " << init.i32_value() << ")";
1182 break;
1184 out_ << " (ref.null ";
1185 names_->PrintHeapType(out_, init.type());
1186 out_ << ")";
1187 break;
1189 out_ << " (ref.func ";
1191 out_ << ")";
1192 break;
1194 WireBytesRef ref = init.wire_bytes_ref();
1195 const uint8_t* start = start_ + ref.offset();
1196 const uint8_t* end = start_ + ref.end_offset();
1197
1198 auto sig = FixedSizeSignature<ValueType>::Returns(expected_type);
1199 WasmDetectedFeatures detected;
1200 FunctionBodyDisassembler d(&zone_, module_, 0, false, &detected, &sig,
1201 start, end, ref.offset(), wire_bytes_, names_);
1202 d.DecodeGlobalInitializer(out_);
1203 break;
1204 }
1205}
1206
1208 for (uint32_t i = 0; i < sig->parameter_count(); i++) {
1209 out_ << " (param ";
1210 names_->PrintValueType(out_, sig->GetParam(i));
1211 out_ << ")";
1212 }
1213}
1214
1218
1219// This mimics legacy wasmparser behavior. It might be a questionable choice,
1220// but we'll follow suit for now.
1222 i::wasm::PrintStringAsJSON(out_, start_, ref);
1223}
1224
1225void PrintStringAsJSON(StringBuilder& out, const uint8_t* start,
1226 WireBytesRef ref) {
1227 for (const uint8_t* ptr = start + ref.offset();
1228 ptr < start + ref.end_offset(); ptr++) {
1229 uint8_t b = *ptr;
1230 if (b <= 34) {
1231 switch (b) {
1232 // clang-format off
1233 case '\b': out << "\\b"; break;
1234 case '\t': out << "\\t"; break;
1235 case '\n': out << "\\n"; break;
1236 case '\f': out << "\\f"; break;
1237 case '\r': out << "\\r"; break;
1238 case ' ': out << ' '; break;
1239 case '!': out << '!'; break;
1240 case '"': out << "\\\""; break;
1241 // clang-format on
1242 default:
1243 out << "\\u00" << kHexChars[b >> 4] << kHexChars[b & 0xF];
1244 break;
1245 }
1246 } else if (b != 127 && b != '\\') {
1247 out << static_cast<char>(b);
1248 } else if (b == '\\') {
1249 out << "\\\\";
1250 } else {
1251 out << "\\x7F";
1252 }
1253 }
1254}
1255
1257 Indentation indentation,
1258 uint32_t byte_offset) {
1259 if (break_lines) {
1260 out_.NextLine(byte_offset);
1261 out_ << indentation.Extra(2);
1262 } else {
1263 out_ << " ";
1264 }
1265}
1266
1267} // namespace wasm
1268} // namespace internal
1269} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
constexpr T * begin() const
Definition vector.h:96
constexpr T * end() const
Definition vector.h:103
virtual void ReserveLineCount(size_t count)=0
virtual void AddLine(const char *src, size_t length, uint32_t bytecode_offset)=0
auto Returns(ReturnTypes... return_types) const
Definition signature.h:166
base::Vector< const T > all() const
Definition signature.h:117
ValueType element_type() const
V8_EXPORT_PRIVATE WireBytesRef wire_bytes_ref() const
base::EmbeddedVector< char, kMaxErrorMsg > buffer
Definition decoder.h:449
uint8_t read_u8(const uint8_t *pc, Name< ValidationTag > msg="expected 1 byte")
Definition decoder.h:132
std::pair< uint32_t, uint32_t > read_u32v(const uint8_t *pc, Name< ValidationTag > name="LEB32")
Definition decoder.h:161
void consume_bytes(uint32_t size, const char *name="skip")
Definition decoder.h:297
uint32_t pc_offset() const
Definition decoder.h:418
const uint8_t * end() const
Definition decoder.h:426
std::pair< WasmOpcode, uint32_t > read_prefixed_opcode(const uint8_t *pc, Name< ValidationTag > name="prefixed opcode")
Definition decoder.h:202
const uint8_t * pc_
Definition decoder.h:437
const uint8_t * end_
Definition decoder.h:438
void DecodeAsWat(MultiLineStringBuilder &out, Indentation indentation, FunctionHeader include_header=kPrintHeader, uint32_t *first_instruction_offset=nullptr)
uint32_t PrintImmediatesAndGetLength(StringBuilder &out)
void PrintHexNumber(StringBuilder &out, uint64_t number)
static constexpr HeapType Index(ModuleTypeIndex index, bool shared, RefTypeKind kind, Exactness exact=Exactness::kAnySubtype)
Definition value-type.h:716
constexpr bool is_index() const
Definition value-type.h:840
constexpr ModuleTypeIndex ref_index() const
Definition value-type.h:762
void use_type(ModuleTypeIndex type_index)
void TableInit(TableInitImmediate &imm)
ImmediatesPrinter(StringBuilder &out, FunctionBodyDisassembler *owner)
void PrintSignature(ModuleTypeIndex sig_index)
void HeapType(HeapTypeImmediate &imm)
void BlockType(BlockTypeImmediate &imm)
void TagIndex(TagIndexImmediate &imm)
void StringConst(StringConstImmediate &imm)
void SimdLane(SimdLaneImmediate &imm)
void TableCopy(TableCopyImmediate &imm)
void ArrayCopy(TypeIndexImmediate &dst, TypeIndexImmediate &src)
void EffectHandlerTable(EffectHandlerTableImmediate &imm)
void BrOnCastFlags(BrOnCastImmediate &flags)
void CallIndirect(CallIndirectImmediate &imm)
void MemoryIndex(MemoryIndexImmediate &imm)
void TryTable(TryTableImmediate &imm)
void SelectType(SelectTypeImmediate &imm)
void MemoryAccess(MemoryAccessImmediate &imm)
void MemoryInit(MemoryInitImmediate &imm)
void TableIndex(TableIndexImmediate &imm)
const char * CatchKindToString(CatchKind kind)
void MemoryCopy(MemoryCopyImmediate &imm)
void BranchTable(BranchTableImmediate &imm)
void DataSegmentIndex(IndexImmediate &imm)
void ElemSegmentIndex(IndexImmediate &imm)
void BranchDepth(BranchDepthImmediate &imm)
void S128Const(Simd128Immediate &imm)
void TypeIndex(TypeIndexImmediate &imm)
ModuleResult DecodeModule(bool validate_functions)
ConstantExpression consume_element_segment_entry(WasmModule *module, const WasmElemSegment &segment)
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 WriteTo(std::ostream &out, bool print_offsets, std::vector< uint32_t > *collect_offsets=nullptr)
void ToDisassemblyCollector(v8::debug::DisassemblyCollector *collector)
void PatchLabel(LabelInfo &label, const char *label_source)
void PrintLabelName(StringBuilder &out, uint32_t function_index, uint32_t label_index, uint32_t fallback_index)
void PrintGlobalName(StringBuilder &out, uint32_t global_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintTagName(StringBuilder &out, uint32_t tag_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintDataSegmentName(StringBuilder &out, uint32_t data_segment_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintLocalName(StringBuilder &out, uint32_t function_index, uint32_t local_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintValueType(StringBuilder &out, ValueType type)
void PrintTypeName(StringBuilder &out, uint32_t type_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintFunctionName(StringBuilder &out, uint32_t function_index, FunctionNamesBehavior behavior=kWasmInternal, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintHeapType(StringBuilder &out, HeapType type)
void PrintFieldName(StringBuilder &out, uint32_t struct_index, uint32_t field_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintMemoryName(StringBuilder &out, uint32_t memory_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintElementSegmentName(StringBuilder &out, uint32_t element_segment_index, IndexAsComment index_as_comment=kDontPrintIndex)
void PrintTableName(StringBuilder &out, uint32_t table_index, IndexAsComment index_as_comment=kDontPrintIndex)
V8_EXPORT_PRIVATE void CollectOffsets(const WasmModule *module, base::Vector< const uint8_t > wire_bytes)
void write(const uint8_t *data, size_t n)
bool mutability(uint32_t index) const
ValueType field(uint32_t index) const
static uint32_t OpcodeLength(WasmDecoder *decoder, const uint8_t *pc, ImmediateObservers &... ios)
static constexpr WasmEnabledFeatures All()
const std::string & message() const &
Definition wasm-result.h:54
static constexpr const char * OpcodeName(WasmOpcode)
static constexpr bool IsPrefixOpcode(WasmOpcode)
Zone * zone_
uint8_t *const start_
Definition assembler.cc:131
int start
int end
Label label
#define ATOMIC_STORE_OP_LIST(V)
StringsStorage * names_
int32_t offset
TNode< Object > target
ZoneVector< RpoNumber > & result
#define ATOMIC_OP_LIST(type)
const base::Vector< const uint8_t > wire_bytes_
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
void DisassembleFunction(const WasmModule *module, int func_index, base::Vector< const uint8_t > wire_bytes, NamesProvider *names, std::ostream &os)
constexpr bool kSkipFunctionTypesInTypeSection
void PrintStringRaw(StringBuilder &out, const uint8_t *start, const uint8_t *end)
static constexpr char kUpperHexChars[]
constexpr IndexAsComment kIndicesAsComments
static constexpr char kHexChars[]
ModuleResult DecodeWasmModuleForDisassembler(base::Vector< const uint8_t > wire_bytes, ITracer *tracer)
void Disassemble(const WasmModule *module, ModuleWireBytes wire_bytes, NamesProvider *names, v8::debug::DisassemblyCollector *collector, std::vector< int > *function_body_offsets)
constexpr IndependentValueType kWasmI32
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)
constexpr ModuleTypeIndex kNoSuperType
std::unique_ptr< OffsetsProvider > AllocateOffsetsProvider()
void DisassembleFunctionImpl(const WasmModule *module, int func_index, base::Vector< const uint8_t > function_body, ModuleWireBytes module_bytes, NamesProvider *names, std::ostream &os, std::vector< uint32_t > *offsets)
constexpr bool kSkipDataSegmentNames
uint32_t GetDefaultAlignment(WasmOpcode opcode)
V8_EXPORT_PRIVATE void PrintStringAsJSON(StringBuilder &out, const uint8_t *start, WireBytesRef ref)
constexpr IndependentValueType kWasmI64
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset kInstanceObjectOffset kMemoryObjectsOffset kTaggedGlobalsBufferOffset tables
V8_EXPORT_PRIVATE FlagValues v8_flags
std::string_view DoubleToStringView(double v, base::Vector< char > buffer)
Definition c-api.cc:87
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
base::Vector< const uint8_t > GetFunctionBytes(const WasmFunction *function) const
ImportExportKindCode kind
std::vector< TypeDefinition > types
std::vector< WasmElemSegment > elem_segments
std::vector< WasmImport > import_table
std::vector< WasmFunction > functions
std::vector< WasmTag > tags
std::vector< WasmGlobal > globals
std::vector< WasmDataSegment > data_segments
std::vector< WasmTable > tables
const WasmTagSig * sig
char * out_
Definition tostring.cc:212
#define V8_UNLIKELY(condition)
Definition v8config.h:660
const wasm::WasmModule * module_
#define FOREACH_LOAD_MEM_OPCODE(V)
#define FOREACH_STORE_MEM_OPCODE(V)