WasmDump.cpp (28325B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "wasm/WasmDump.h" 8 9 #include <cinttypes> 10 11 #include "wasm/WasmValidate.h" 12 13 using namespace js; 14 using namespace js::wasm; 15 16 static void DumpTypeDefIndex(const TypeDef* typeDef, GenericPrinter& out, 17 const TypeContext* types) { 18 if (types) { 19 out.printf("%" PRIu32, types->indexOf(*typeDef)); 20 } else { 21 out.printf("? (;0x%" PRIxPTR ";)", (uintptr_t)typeDef); 22 } 23 } 24 25 static void DumpFuncParamsAndResults(const FuncType& funcType, 26 StructuredPrinter& out, 27 const TypeContext* types) { 28 if (funcType.args().length() > 0) { 29 out.brk(" ", "\n"); 30 out.printf("(param"); 31 for (ValType arg : funcType.args()) { 32 out.printf(" "); 33 DumpValType(arg, out, types); 34 } 35 out.printf(")"); 36 } 37 if (funcType.results().length() > 0) { 38 out.brk(" ", "\n"); 39 out.printf("(result"); 40 for (ValType result : funcType.results()) { 41 out.printf(" "); 42 DumpValType(result, out, types); 43 } 44 out.printf(")"); 45 } 46 } 47 48 template <size_t MinInlineCapacity, class AllocPolicy> 49 static void DumpBytesAsString( 50 const mozilla::Vector<uint8_t, MinInlineCapacity, AllocPolicy>& bytes, 51 GenericPrinter& out) { 52 WATStringEscape esc; 53 EscapePrinter o(out, esc); 54 55 out.put("\""); 56 for (uint8_t b : bytes) { 57 o.putChar(b); 58 } 59 out.put("\""); 60 } 61 62 static void DumpName(const CacheableName& name, GenericPrinter& out) { 63 WATStringEscape esc; 64 EscapePrinter o(out, esc); 65 66 out.put("\""); 67 o.put(name.utf8Bytes()); 68 out.put("\""); 69 } 70 71 void wasm::DumpModule(const Module& module) { 72 Fprinter out(stdout); 73 wasm::DumpModule(module, out); 74 out.printf("\n"); 75 } 76 77 void wasm::DumpModule(const Module& module, GenericPrinter& out) { 78 StructuredPrinter o(out); 79 80 o.printf("(module"); 81 { 82 StructuredPrinter::Scope _(o); 83 84 // Type section 85 const TypeContext& types = *module.moduleMeta().codeMeta->types.get(); 86 if (types.length()) { 87 o.printf("\n"); 88 DumpTypeContext(types, o); 89 o.printf("\n"); 90 } 91 92 // Import section 93 size_t numFuncImports = 0; 94 size_t numTableImports = 0; 95 size_t numMemoryImports = 0; 96 size_t numGlobalImports = 0; 97 size_t numTagImports = 0; 98 for (const Import& import : module.moduleMeta().imports) { 99 o.printf("\n"); 100 o.printf("(import "); 101 102 DumpName(import.module, o); 103 o.put(" "); 104 DumpName(import.field, o); 105 o.put(" "); 106 107 switch (import.kind) { 108 case DefinitionKind::Function: { 109 size_t funcIndex = numFuncImports++; 110 const TypeDef& funcTypeDef = 111 module.codeMeta().getFuncTypeDef(funcIndex); 112 o.printf("(func (;%zu;) (type ", funcIndex); 113 DumpTypeDefIndex(&funcTypeDef, o, &types); 114 o.printf("))"); 115 } break; 116 case DefinitionKind::Table: { 117 size_t tableIndex = numTableImports++; 118 const TableDesc& tableDesc = module.codeMeta().tables[tableIndex]; 119 DumpTableDesc(tableDesc, module.codeMeta(), /*includeInitExpr=*/false, 120 o, int32_t(tableIndex)); 121 } break; 122 case DefinitionKind::Memory: { 123 size_t memIndex = numMemoryImports++; 124 const MemoryDesc& memDesc = module.codeMeta().memories[memIndex]; 125 DumpMemoryDesc(memDesc, o, int32_t(memIndex)); 126 } break; 127 case DefinitionKind::Global: { 128 size_t globalIndex = numGlobalImports++; 129 const GlobalDesc& globalDesc = module.codeMeta().globals[globalIndex]; 130 DumpGlobalDesc(globalDesc, module.codeMeta(), false, o, 131 int32_t(globalIndex)); 132 } break; 133 case DefinitionKind::Tag: { 134 size_t tagIndex = numTagImports++; 135 const TagDesc& tagDesc = module.codeMeta().tags[tagIndex]; 136 DumpTagDesc(tagDesc, o, int32_t(tagIndex), &types); 137 } break; 138 default: { 139 o.printf("(; unknown import kind ;)"); 140 } break; 141 } 142 143 o.printf(")"); 144 } 145 if (module.moduleMeta().imports.length() > 0) { 146 o.printf("\n"); 147 } 148 149 // We skip the function section because the function types show up later in 150 // the dump of the code section. 151 152 // Table section 153 for (size_t i = numTableImports; i < module.codeMeta().tables.length(); 154 i++) { 155 const TableDesc& tableDesc = module.codeMeta().tables[i]; 156 o.printf("\n"); 157 DumpTableDesc(tableDesc, module.codeMeta(), /*includeInitExpr=*/true, o, 158 int32_t(i)); 159 } 160 if (module.codeMeta().tables.length() - numTableImports > 0) { 161 o.printf("\n"); 162 } 163 164 // Memory section 165 for (size_t i = numMemoryImports; i < module.codeMeta().memories.length(); 166 i++) { 167 const MemoryDesc& memDesc = module.codeMeta().memories[i]; 168 o.printf("\n"); 169 DumpMemoryDesc(memDesc, o, int32_t(i)); 170 } 171 if (module.codeMeta().memories.length() - numMemoryImports > 0) { 172 o.printf("\n"); 173 } 174 175 // Tag section 176 for (size_t i = numTagImports; i < module.codeMeta().tags.length(); i++) { 177 const TagDesc& tagDesc = module.codeMeta().tags[i]; 178 o.printf("\n"); 179 DumpTagDesc(tagDesc, o, int32_t(i), &types); 180 } 181 if (module.codeMeta().tags.length() - numTagImports > 0) { 182 o.printf("\n"); 183 } 184 185 // Global section 186 for (size_t i = numGlobalImports; i < module.codeMeta().globals.length(); 187 i++) { 188 const GlobalDesc& globalDesc = module.codeMeta().globals[i]; 189 o.printf("\n"); 190 DumpGlobalDesc(globalDesc, module.codeMeta(), /*includeInitExpr=*/true, o, 191 int32_t(i)); 192 } 193 if (module.codeMeta().globals.length() - numGlobalImports > 0) { 194 o.printf("\n"); 195 } 196 197 // Export section 198 for (const Export& exp : module.moduleMeta().exports) { 199 o.printf("\n"); 200 o.printf("(export "); 201 DumpName(exp.fieldName(), o); 202 o.printf(" "); 203 switch (exp.kind()) { 204 case DefinitionKind::Function: { 205 o.printf("(func %" PRIu32 ")", exp.funcIndex()); 206 } break; 207 case DefinitionKind::Table: { 208 o.printf("(table %" PRIu32 ")", exp.tableIndex()); 209 } break; 210 case DefinitionKind::Memory: { 211 o.printf("(memory %" PRIu32 ")", exp.memoryIndex()); 212 } break; 213 case DefinitionKind::Global: { 214 o.printf("(global %" PRIu32 ")", exp.globalIndex()); 215 } break; 216 case DefinitionKind::Tag: { 217 o.printf("(tag %" PRIu32 ")", exp.tagIndex()); 218 } break; 219 default: { 220 o.printf("(; unknown export kind ;)"); 221 } break; 222 } 223 o.printf(")"); 224 } 225 if (module.moduleMeta().exports.length() > 0) { 226 o.printf("\n"); 227 } 228 229 // Start section 230 if (module.codeMeta().startFuncIndex.isSome()) { 231 o.printf("\n"); 232 o.printf("(start %" PRIu32 ")", module.codeMeta().startFuncIndex.value()); 233 o.printf("\n"); 234 } 235 236 // Element section 237 for (size_t i = 0; i < module.moduleMeta().elemSegments.length(); i++) { 238 const ModuleElemSegment& elem = module.moduleMeta().elemSegments[i]; 239 o.printf("\n"); 240 o.printf("(elem (;%zu;)", i); 241 242 bool typeExpanded = false; 243 { 244 StructuredPrinter::Scope _(o); 245 if (elem.active()) { 246 o.brk(" ", "\n"); 247 o.printf("(table %" PRIu32 ")", elem.tableIndex); 248 o.brk(" ", "\n"); 249 o.printf("(offset"); 250 { 251 StructuredPrinter::Scope _(o); 252 DumpInitExpr(elem.offset(), module.codeMeta(), o); 253 o.brk("", "\n"); 254 } 255 o.printf(")"); 256 } else if (elem.kind == ModuleElemSegment::Kind::Declared) { 257 o.brk(" ", "\n"); 258 o.printf("declare"); 259 } 260 if (elem.encoding == ModuleElemSegment::Encoding::Expressions) { 261 o.brk(" ", "\n"); 262 DumpRefType(elem.elemType, o, &types); 263 } 264 o.brk("", "\n"); 265 typeExpanded = o.isExpanded(); 266 } 267 { 268 StructuredPrinter::Scope _(o); 269 if (typeExpanded) { 270 o.expand(); 271 } 272 273 switch (elem.encoding) { 274 case ModuleElemSegment::Encoding::Indices: { 275 o.brk(" ", "\n"); 276 o.printf("func"); 277 for (uint32_t idx : elem.elemIndices) { 278 o.printf(" %" PRIu32, idx); 279 } 280 } break; 281 case ModuleElemSegment::Encoding::Expressions: { 282 UniqueChars error; 283 Decoder d(elem.elemExpressions.exprBytes.begin(), 284 elem.elemExpressions.exprBytes.end(), /* dummy */ 0, 285 &error); 286 ValTypeVector locals; 287 ValidatingOpIter iter(module.codeMeta(), d, locals, 288 ValidatingOpIter::Kind::InitExpr); 289 for (uint32_t i = 0; i < elem.numElements(); i++) { 290 o.brk(" ", "\n"); 291 o.printf("(item"); 292 { 293 StructuredPrinter::Scope _(o); 294 295 OpDumper visitor(o, &types); 296 if (!iter.startInitExpr(elem.elemType)) { 297 out.printf("(; bad expression ;)"); 298 return; 299 } 300 if (!ValidateOps(iter, visitor, module.codeMeta())) { 301 out.printf("(; bad expression: %s ;)", d.error()->get()); 302 return; 303 } 304 if (!iter.endInitExpr()) { 305 out.printf("(; bad expression ;)"); 306 return; 307 } 308 o.brk("", "\n"); 309 } 310 o.printf(")"); 311 } 312 313 if (elem.numElements() > 1) { 314 o.expand(); 315 } 316 } break; 317 default: { 318 out.printf("(; unknown encoding ;)"); 319 } break; 320 } 321 o.brk("", "\n"); 322 } 323 o.printf(")"); 324 } 325 if (module.moduleMeta().elemSegments.length() > 0) { 326 o.printf("\n"); 327 } 328 329 // Code section 330 for (size_t i = numFuncImports; i < module.codeMeta().numFuncs(); i++) { 331 o.printf("\n"); 332 DumpFunction(module.codeMeta(), module.codeTailMeta(), i, o); 333 } 334 if (module.codeMeta().numFuncs() - numFuncImports > 0) { 335 o.printf("\n"); 336 } 337 338 // Data section 339 for (size_t i = 0; i < module.moduleMeta().dataSegments.length(); i++) { 340 RefPtr<const DataSegment> seg = module.moduleMeta().dataSegments[i]; 341 342 o.printf("\n"); 343 o.printf("(data (;%zu;)", i); 344 { 345 StructuredPrinter::Scope _(o); 346 if (seg->active()) { 347 o.brk(" ", "\n"); 348 o.printf("(memory %" PRIu32 ")", seg->memoryIndex); 349 o.brk(" ", "\n"); 350 o.printf("(offset"); 351 { 352 StructuredPrinter::Scope _(o); 353 DumpInitExpr(seg->offset(), module.codeMeta(), o); 354 o.brk("", "\n"); 355 } 356 o.printf(")"); 357 } 358 o.brk(" ", "\n"); 359 DumpBytesAsString(seg->bytes, o); 360 o.brk("", "\n"); 361 } 362 o.printf(")"); 363 } 364 } 365 o.brk("", "\n"); 366 o.printf(")"); 367 } 368 369 void wasm::DumpValType(ValType type, const TypeContext* types) { 370 Fprinter out(stdout); 371 wasm::DumpValType(type, out, types); 372 out.printf("\n"); 373 } 374 375 void wasm::DumpValType(ValType type, GenericPrinter& out, 376 const TypeContext* types) { 377 DumpStorageType(type.storageType(), out, types); 378 } 379 380 void wasm::DumpStorageType(StorageType type, const TypeContext* types) { 381 Fprinter out(stdout); 382 wasm::DumpStorageType(type, out, types); 383 out.printf("\n"); 384 } 385 386 void wasm::DumpStorageType(StorageType type, GenericPrinter& out, 387 const TypeContext* types) { 388 const char* literal = nullptr; 389 switch (type.kind()) { 390 case StorageType::I8: 391 literal = "i8"; 392 break; 393 case StorageType::I16: 394 literal = "i16"; 395 break; 396 case StorageType::I32: 397 literal = "i32"; 398 break; 399 case StorageType::I64: 400 literal = "i64"; 401 break; 402 case StorageType::V128: 403 literal = "v128"; 404 break; 405 case StorageType::F32: 406 literal = "f32"; 407 break; 408 case StorageType::F64: 409 literal = "f64"; 410 break; 411 case StorageType::Ref: 412 return DumpRefType(type.refType(), out, types); 413 default: 414 MOZ_CRASH("unexpected storage type"); 415 } 416 out.put(literal); 417 } 418 419 void wasm::DumpRefType(RefType type, const TypeContext* types) { 420 Fprinter out(stdout); 421 wasm::DumpRefType(type, out, types); 422 out.printf("\n"); 423 } 424 425 void wasm::DumpRefType(RefType type, GenericPrinter& out, 426 const TypeContext* types) { 427 if (type.isNullable() && !type.isTypeRef()) { 428 const char* literal = nullptr; 429 switch (type.kind()) { 430 case RefType::Func: 431 literal = "funcref"; 432 break; 433 case RefType::Extern: 434 literal = "externref"; 435 break; 436 case RefType::Any: 437 literal = "anyref"; 438 break; 439 case RefType::NoFunc: 440 literal = "nullfuncref"; 441 break; 442 case RefType::NoExn: 443 literal = "nullexn"; 444 break; 445 case RefType::NoExtern: 446 literal = "nullexternref"; 447 break; 448 case RefType::None: 449 literal = "nullref"; 450 break; 451 case RefType::Eq: 452 literal = "eqref"; 453 break; 454 case RefType::I31: 455 literal = "i31ref"; 456 break; 457 case RefType::Struct: 458 literal = "structref"; 459 break; 460 case RefType::Array: 461 literal = "arrayref"; 462 break; 463 case RefType::Exn: 464 literal = "exnref"; 465 break; 466 case RefType::TypeRef: { 467 MOZ_CRASH("type ref should not be possible here"); 468 } 469 } 470 out.put(literal); 471 return; 472 } 473 474 // Emit the full reference type with heap type 475 out.printf("(ref %s", type.isNullable() ? "null " : ""); 476 DumpHeapType(type, out, types); 477 out.printf(")"); 478 } 479 480 void wasm::DumpHeapType(RefType type, const TypeContext* types) { 481 Fprinter out(stdout); 482 wasm::DumpHeapType(type, out, types); 483 out.printf("\n"); 484 } 485 486 void wasm::DumpHeapType(RefType type, GenericPrinter& out, 487 const TypeContext* types) { 488 switch (type.kind()) { 489 case RefType::Func: 490 out.put("func"); 491 return; 492 case RefType::Extern: 493 out.put("extern"); 494 return; 495 case RefType::Any: 496 out.put("any"); 497 return; 498 case RefType::NoFunc: 499 out.put("nofunc"); 500 return; 501 case RefType::NoExn: 502 out.put("noexn"); 503 return; 504 case RefType::NoExtern: 505 out.put("noextern"); 506 return; 507 case RefType::None: 508 out.put("none"); 509 return; 510 case RefType::Eq: 511 out.put("eq"); 512 return; 513 case RefType::I31: 514 out.put("i31"); 515 return; 516 case RefType::Struct: 517 out.put("struct"); 518 return; 519 case RefType::Array: 520 out.put("array"); 521 return; 522 case RefType::Exn: 523 out.put("exn"); 524 return; 525 case RefType::TypeRef: { 526 DumpTypeDefIndex(type.typeDef(), out, types); 527 return; 528 } 529 } 530 } 531 532 void wasm::DumpFuncType(const FuncType& funcType, const TypeContext* types) { 533 Fprinter fileOut(stdout); 534 StructuredPrinter out(fileOut); 535 wasm::DumpFuncType(funcType, out, types); 536 out.printf("\n"); 537 } 538 539 void wasm::DumpFuncType(const FuncType& funcType, StructuredPrinter& out, 540 const TypeContext* types) { 541 out.printf("(func"); 542 { 543 StructuredPrinter::Scope _(out); 544 DumpFuncParamsAndResults(funcType, out, types); 545 out.brk("", "\n"); 546 547 if (funcType.args().length() + funcType.results().length() > 10) { 548 out.expand(); 549 } 550 } 551 out.printf(")"); 552 } 553 554 void wasm::DumpStructType(const StructType& structType, 555 const TypeContext* types) { 556 Fprinter fileOut(stdout); 557 StructuredPrinter out(fileOut); 558 wasm::DumpStructType(structType, out, types); 559 out.printf("\n"); 560 } 561 562 void wasm::DumpStructType(const StructType& structType, StructuredPrinter& out, 563 const TypeContext* types) { 564 out.printf("(struct"); 565 { 566 StructuredPrinter::Scope _(out); 567 568 for (const FieldType& field : structType.fields_) { 569 out.brk(" ", "\n"); 570 out.printf("(field "); 571 if (field.isMutable) { 572 out.printf("(mut "); 573 } 574 DumpStorageType(field.type, out, types); 575 if (field.isMutable) { 576 out.printf(")"); 577 } 578 out.printf(")"); 579 } 580 out.brk("", "\n"); 581 582 if (structType.fields_.length() > 1) { 583 out.expand(); 584 } 585 } 586 out.printf(")"); 587 } 588 589 void wasm::DumpArrayType(const ArrayType& arrayType, const TypeContext* types) { 590 Fprinter fileOut(stdout); 591 StructuredPrinter out(fileOut); 592 wasm::DumpArrayType(arrayType, out, types); 593 out.printf("\n"); 594 } 595 596 void wasm::DumpArrayType(const ArrayType& arrayType, StructuredPrinter& out, 597 const TypeContext* types) { 598 out.printf("(array "); 599 if (arrayType.isMutable()) { 600 out.printf("(mut "); 601 } 602 DumpStorageType(arrayType.elementType(), out, types); 603 if (arrayType.isMutable()) { 604 out.printf(")"); 605 } 606 out.printf(")"); 607 } 608 609 void wasm::DumpTypeDef(const TypeDef& typeDef, int32_t index, 610 const TypeContext* types) { 611 Fprinter fileOut(stdout); 612 StructuredPrinter out(fileOut); 613 wasm::DumpTypeDef(typeDef, out, index, types); 614 out.printf("\n"); 615 } 616 617 void wasm::DumpTypeDef(const TypeDef& typeDef, StructuredPrinter& out, 618 int32_t index, const TypeContext* types) { 619 out.printf("(type "); 620 if (index >= 0) { 621 out.printf("(;%" PRIi32 ";) ", index); 622 } 623 if (types && int32_t(types->indexOf(typeDef)) != index) { 624 out.printf("(;canonicalized;) "); 625 } 626 627 // Somewhat counterintuitively, the text format works like so: 628 // 629 // (type (struct)): no parent, final 630 // (type (sub (struct))): no parent, open 631 // (type (sub $parent (struct))): has parent, open 632 // (type (sub $parent final (struct))): has parent, final 633 bool printSub = typeDef.superTypeDef() || !typeDef.isFinal(); 634 635 if (printSub) { 636 out.printf("(sub "); 637 if (typeDef.isFinal()) { 638 out.printf("final "); 639 } 640 if (typeDef.superTypeDef()) { 641 DumpTypeDefIndex(typeDef.superTypeDef(), out, types); 642 out.printf(" "); 643 } 644 } 645 646 switch (typeDef.kind()) { 647 case TypeDefKind::Func: 648 DumpFuncType(typeDef.funcType(), out, types); 649 break; 650 case TypeDefKind::Struct: 651 DumpStructType(typeDef.structType(), out, types); 652 break; 653 case TypeDefKind::Array: 654 DumpArrayType(typeDef.arrayType(), out, types); 655 break; 656 case TypeDefKind::None: 657 out.printf("(; TypeDefKind::None ;)\n"); 658 break; 659 } 660 661 if (printSub) { 662 out.printf(")"); 663 } 664 665 out.printf(")"); 666 } 667 668 void wasm::DumpRecGroup(const RecGroup& recGroup, int32_t startTypeIndex, 669 const TypeContext* types) { 670 Fprinter fileOut(stdout); 671 StructuredPrinter out(fileOut); 672 wasm::DumpRecGroup(recGroup, out, startTypeIndex, types); 673 out.printf("\n"); 674 } 675 676 void wasm::DumpRecGroup(const RecGroup& recGroup, StructuredPrinter& out, 677 int32_t startTypeIndex, const TypeContext* types) { 678 if (recGroup.numTypes() > 1) { 679 out.printf("(rec\n"); 680 { 681 StructuredPrinter::Scope _(out); 682 for (uint32_t i = 0; i < recGroup.numTypes(); i++) { 683 if (i > 0) { 684 out.printf("\n"); 685 } 686 DumpTypeDef(recGroup.type(i), out, 687 startTypeIndex < 0 ? -1 : startTypeIndex + int32_t(i), 688 types); 689 } 690 out.printf("\n"); 691 } 692 out.printf(")"); 693 } else { 694 DumpTypeDef(recGroup.type(0), out, startTypeIndex < 0 ? -1 : startTypeIndex, 695 types); 696 } 697 } 698 699 void wasm::DumpTableDesc(const TableDesc& tableDesc, 700 const CodeMetadata& codeMeta, bool includeInitExpr, 701 int32_t index) { 702 Fprinter fileOut(stdout); 703 StructuredPrinter out(fileOut); 704 wasm::DumpTableDesc(tableDesc, codeMeta, includeInitExpr, out, index); 705 out.printf("\n"); 706 } 707 708 void wasm::DumpTableDesc(const TableDesc& tableDesc, 709 const CodeMetadata& codeMeta, bool includeInitExpr, 710 StructuredPrinter& out, int32_t index) { 711 out.printf("(table "); 712 if (index >= 0) { 713 out.printf("(;%" PRIi32 ";) ", index); 714 } 715 if (tableDesc.addressType() == AddressType::I64) { 716 out.printf("i64 "); 717 } 718 out.printf("%" PRIu64 " ", tableDesc.initialLength()); 719 if (tableDesc.maximumLength().isSome()) { 720 out.printf("%" PRIu64 " ", tableDesc.maximumLength().value()); 721 } 722 DumpRefType(tableDesc.elemType, out, codeMeta.types); 723 if (includeInitExpr && tableDesc.initExpr) { 724 StructuredPrinter::Scope _(out); 725 DumpInitExpr(tableDesc.initExpr.ref(), codeMeta, out); 726 out.brk("", "\n"); 727 } 728 out.printf(")"); 729 } 730 731 void wasm::DumpMemoryDesc(const MemoryDesc& memDesc, int32_t index) { 732 Fprinter fileOut(stdout); 733 StructuredPrinter out(fileOut); 734 wasm::DumpMemoryDesc(memDesc, out, index); 735 out.printf("\n"); 736 } 737 738 void wasm::DumpMemoryDesc(const MemoryDesc& memDesc, StructuredPrinter& out, 739 int32_t index) { 740 out.printf("(memory "); 741 if (index >= 0) { 742 out.printf("(;%" PRIi32 ";) ", index); 743 } 744 if (memDesc.addressType() == AddressType::I64) { 745 out.printf("i64 "); 746 } 747 out.printf("%" PRIu64, memDesc.initialPages().pageCount()); 748 if (memDesc.maximumPages().isSome()) { 749 out.printf(" %" PRIu64, memDesc.maximumPages().value().pageCount()); 750 } 751 if (memDesc.initialPages().pageSize() != PageSize::Standard) { 752 out.printf(" (pagesize %d)", 753 PageSizeInBytes(memDesc.initialPages().pageSize())); 754 } 755 out.printf(")"); 756 } 757 758 void wasm::DumpGlobalDesc(const GlobalDesc& globalDesc, 759 const CodeMetadata& codeMeta, bool includeInitExpr, 760 int32_t index) { 761 Fprinter fileOut(stdout); 762 StructuredPrinter out(fileOut); 763 wasm::DumpGlobalDesc(globalDesc, codeMeta, includeInitExpr, out, index); 764 out.printf("\n"); 765 } 766 767 void wasm::DumpGlobalDesc(const GlobalDesc& globalDesc, 768 const CodeMetadata& codeMeta, bool includeInitExpr, 769 StructuredPrinter& out, int32_t index) { 770 out.printf("(global "); 771 if (index >= 0) { 772 out.printf("(;%" PRIi32 ";) ", index); 773 } 774 if (globalDesc.isMutable()) { 775 out.printf("(mut "); 776 } 777 DumpValType(globalDesc.type(), out, codeMeta.types); 778 if (globalDesc.isMutable()) { 779 out.printf(")"); 780 } 781 if (includeInitExpr) { 782 StructuredPrinter::Scope _(out); 783 DumpInitExpr(globalDesc.initExpr(), codeMeta, out); 784 out.brk("", "\n"); 785 } 786 out.printf(")"); 787 } 788 789 void wasm::DumpTagDesc(const TagDesc& tagDesc, int32_t index, 790 const TypeContext* types) { 791 Fprinter fileOut(stdout); 792 StructuredPrinter out(fileOut); 793 wasm::DumpTagDesc(tagDesc, out, index, types); 794 out.printf("\n"); 795 } 796 797 void wasm::DumpTagDesc(const TagDesc& tagDesc, StructuredPrinter& out, 798 int32_t index, const TypeContext* types) { 799 out.printf("(tag "); 800 if (index >= 0) { 801 out.printf("(;%" PRIi32 ";) ", index); 802 } 803 out.printf("(type "); 804 DumpTypeDefIndex(&tagDesc.type->type(), out, types); 805 out.printf("))"); 806 } 807 808 void wasm::DumpInitExpr(const InitExpr& initExpr, 809 const CodeMetadata& codeMeta) { 810 Fprinter fileOut(stdout); 811 StructuredPrinter out(fileOut); 812 wasm::DumpInitExpr(initExpr, codeMeta, out); 813 out.printf("\n"); 814 } 815 816 void wasm::DumpInitExpr(const InitExpr& initExpr, const CodeMetadata& codeMeta, 817 StructuredPrinter& out) { 818 UniqueChars error; 819 Decoder d(initExpr.bytecode().begin(), initExpr.bytecode().end(), 820 /* dummy */ 0, &error); 821 ValTypeVector locals; 822 ValidatingOpIter iter(codeMeta, d, locals, ValidatingOpIter::Kind::InitExpr); 823 OpDumper visitor(out, codeMeta.types); 824 825 if (!iter.startInitExpr(initExpr.type())) { 826 out.brk(" ", "\n"); 827 out.printf("(; bad expression ;)"); 828 return; 829 } 830 if (!ValidateOps(iter, visitor, codeMeta)) { 831 out.brk(" ", "\n"); 832 out.printf("(; bad expression: %s ;)", d.error()->get()); 833 return; 834 } 835 if (!iter.endInitExpr()) { 836 out.brk(" ", "\n"); 837 out.printf("(; bad expression ;)"); 838 return; 839 } 840 } 841 842 void wasm::DumpTypeContext(const TypeContext& typeContext) { 843 Fprinter fileOut(stdout); 844 StructuredPrinter out(fileOut); 845 wasm::DumpTypeContext(typeContext, out); 846 out.printf("\n"); 847 } 848 849 void wasm::DumpTypeContext(const TypeContext& typeContext, 850 StructuredPrinter& out) { 851 uint32_t numTypesSoFar = 0; 852 for (size_t i = 0; i < typeContext.groups().length(); i++) { 853 if (i > 0) { 854 out.printf("\n"); 855 } 856 const RecGroup& group = *typeContext.groups()[i]; 857 DumpRecGroup(group, out, int32_t(numTypesSoFar), &typeContext); 858 numTypesSoFar += group.numTypes(); 859 } 860 } 861 862 void wasm::DumpFunction(const CodeMetadata& codeMeta, 863 const CodeTailMetadata& codeTailMeta, 864 uint32_t funcIndex) { 865 Fprinter fileOut(stdout); 866 StructuredPrinter out(fileOut); 867 wasm::DumpFunction(codeMeta, codeTailMeta, funcIndex, out); 868 out.printf("\n"); 869 } 870 871 void wasm::DumpFunction(const CodeMetadata& codeMeta, 872 const CodeTailMetadata& codeTailMeta, 873 uint32_t funcIndex, StructuredPrinter& out) { 874 const FuncDesc& f = codeMeta.funcs[funcIndex]; 875 const TypeDef& typeDef = codeMeta.getFuncTypeDef(funcIndex); 876 const FuncType& funcType = typeDef.funcType(); 877 878 out.printf("(func (;%" PRIu32 ";) (type %" PRIu32 ")", funcIndex, 879 f.typeIndex); 880 881 bool typeExpanded = false; 882 { 883 StructuredPrinter::Scope _(out); 884 885 DumpFuncParamsAndResults(funcType, out, codeMeta.types); 886 out.brk("", "\n"); 887 if (funcType.args().length() + funcType.results().length() > 8) { 888 out.expand(); 889 } 890 891 typeExpanded = out.isExpanded(); 892 } 893 { 894 StructuredPrinter::Scope _(out); 895 if (typeExpanded) { 896 out.expand(); 897 } 898 899 if (codeTailMeta.codeSectionBytecode) { 900 UniqueChars error; 901 BytecodeSpan funcBytecode = codeTailMeta.funcDefBody(funcIndex); 902 DumpFunctionBody(codeMeta, funcIndex, funcBytecode.data(), 903 funcBytecode.size(), out); 904 } else { 905 out.brk(" ", "\n"); 906 out.printf("(; no bytecode available ;)"); 907 } 908 out.brk("", "\n"); 909 } 910 out.printf(")"); 911 } 912 913 void wasm::DumpFunctionBody(const CodeMetadata& codeMeta, uint32_t funcIndex, 914 const uint8_t* bodyStart, uint32_t bodySize) { 915 Fprinter fileOut(stdout); 916 StructuredPrinter out(fileOut); 917 wasm::DumpFunctionBody(codeMeta, funcIndex, bodyStart, bodySize, out); 918 out.printf("\n"); 919 } 920 921 void wasm::DumpFunctionBody(const CodeMetadata& codeMeta, uint32_t funcIndex, 922 const uint8_t* bodyStart, uint32_t bodySize, 923 StructuredPrinter& out) { 924 UniqueChars error; 925 926 const uint8_t* bodyEnd = bodyStart + bodySize; 927 Decoder d(bodyStart, bodyEnd, 0, &error); 928 929 ValTypeVector locals; 930 if (!DecodeLocalEntriesWithParams(d, codeMeta, funcIndex, &locals)) { 931 out.brk(" ", "\n"); 932 out.printf("(; error: %s ;)", error.get()); 933 return; 934 } 935 uint32_t numArgs = codeMeta.getFuncType(funcIndex).args().length(); 936 if (locals.length() - numArgs > 0) { 937 out.printf("\n(local"); 938 for (size_t i = numArgs; i < locals.length(); i++) { 939 ValType local = locals[i]; 940 out.printf(" "); 941 DumpValType(local, out, codeMeta.types); 942 } 943 out.printf(")\n"); 944 } 945 946 ValidatingOpIter iter(codeMeta, d, locals); 947 if (!iter.startFunction(funcIndex)) { 948 out.brk(" ", "\n"); 949 out.printf("(; error: %s ;)", error.get()); 950 return; 951 } 952 953 OpDumper visitor(out, codeMeta.types); 954 if (!ValidateOps(iter, visitor, codeMeta)) { 955 out.brk(" ", "\n"); 956 out.printf("(; error: %s ;)", error.get()); 957 return; 958 } 959 960 if (!iter.endFunction(bodyEnd)) { 961 out.brk(" ", "\n"); 962 out.printf("(; error: %s ;)", error.get()); 963 return; 964 } 965 }