From 4aea7b7db95915699805aac328cd9691d6aa1938 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 16 Jan 2026 15:32:22 -0800 Subject: [PATCH 1/2] Add initial support for compact import section. NFC See https://github.com/WebAssembly/compact-import-section For this initial commit I've just added a single simple test in form of test/binary/compact-imports.txt. Once we update the `testsuite` repo we can pull in the official tests. --- README.md | 2 + include/wabt/feature.def | 1 + src/binary-reader.cc | 201 ++++++++++++++++++------- src/binary-writer.cc | 94 ++++++++---- src/tools/wasm2c.cc | 12 +- src/wabt.post.js | 1 + test/binary/compact-imports.txt | 54 +++++++ test/dump/compact-imports.txt | 117 ++++++++++++++ test/dump/memory64.txt | 8 +- test/dump/relocations-all-features.txt | 60 ++++---- test/dump/symbol-tables.txt | 44 +++--- test/help/spectest-interp.txt | 1 + test/help/wasm-interp.txt | 1 + test/help/wasm-stats.txt | 1 + test/help/wasm-validate.txt | 1 + test/help/wasm2wat.txt | 1 + test/help/wast2json.txt | 1 + test/help/wat-desugar.txt | 1 + test/help/wat2wasm.txt | 1 + 19 files changed, 459 insertions(+), 143 deletions(-) create mode 100644 test/binary/compact-imports.txt create mode 100644 test/dump/compact-imports.txt diff --git a/README.md b/README.md index b59b1c98ac..ad57d06448 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ Wabt has been compiled to JavaScript via emscripten. Some of the functionality i | [extended-const][] | `--enable-extended-const` | | ✓ | ✓ | ✓ | ✓ | ✓ | | [relaxed-simd][] | `--enable-relaxed-simd` | | ✓ | ✓ | ✓ | ✓ | | | [custom-page-sizes][] | `--enable-custom-page-sizes`| | ✓ | ✓ | ✓ | ✓ | ✓ | +| [compact-imports][] | `--enable-compact-imports` | | ✓ | | ✓ | | | | [function-references][] | `--enable-function-references` | | ✓ | ✓ | ✓ | ✓ | | [exception handling]: https://github.com/WebAssembly/exception-handling @@ -82,6 +83,7 @@ Wabt has been compiled to JavaScript via emscripten. Some of the functionality i [relaxed-simd]: https://github.com/WebAssembly/relaxed-simd [custom-page-sizes]: https://github.com/WebAssembly/custom-page-sizes [function-references]: https://github.com/WebAssembly/function-references +[compact-imports]: https://github.com/WebAssembly/compact-import-section ## Cloning diff --git a/include/wabt/feature.def b/include/wabt/feature.def index ac96377b43..f81bf852c0 100644 --- a/include/wabt/feature.def +++ b/include/wabt/feature.def @@ -41,3 +41,4 @@ WABT_FEATURE(multi_memory, "multi-memory", false, "Multi-mem WABT_FEATURE(extended_const, "extended-const", false, "Extended constant expressions") WABT_FEATURE(relaxed_simd, "relaxed-simd", false, "Relaxed SIMD") WABT_FEATURE(custom_page_sizes, "custom-page-sizes", false, "Custom page sizes") +WABT_FEATURE(compact_imports, "compact-imports", false, "Compact import section") diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 53cd267a28..e80acf68e1 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -70,6 +70,33 @@ namespace wabt { namespace { +struct ExternalType { + // Union into which we read extern type details. + ExternalType() : memType{} {} + ~ExternalType() {} + union { + // Global + struct { + Type type; + bool mutable_; + } globalType; + // Function/Tag + struct { + Index sig_index; + } funcType; + // Memory + struct { + Limits page_limits; + uint32_t page_size; + } memType; + // Table + struct { + Limits elem_limits; + Type elem_type; + } tableType; + }; +}; + class BinaryReader { public: struct ReadModuleOptions { @@ -177,6 +204,12 @@ class BinaryReader { [[nodiscard]] Result ReadCustomSection(Index section_index, Offset section_size); [[nodiscard]] Result ReadTypeSection(Offset section_size); + [[nodiscard]] Result ReadImportDetails(ExternalKind kind, ExternalType* out); + [[nodiscard]] Result ReportImport(Index i, + std::string_view module_name, + std::string_view field_name, + ExternalKind kind, + ExternalType& type); [[nodiscard]] Result ReadImportSection(Offset section_size); [[nodiscard]] Result ReadFunctionSection(Offset section_size); [[nodiscard]] Result ReadTableSection(Offset section_size); @@ -2687,72 +2720,132 @@ Result BinaryReader::ReadTypeSection(Offset section_size) { return Result::Ok; } +Result BinaryReader::ReadImportDetails(ExternalKind kind, ExternalType* out) { + switch (kind) { + case ExternalKind::Func: { + CHECK_RESULT( + ReadIndex(&out->funcType.sig_index, "import signature index")); + break; + } + + case ExternalKind::Table: { + CHECK_RESULT(ReadRefType(&out->tableType.elem_type, "table elem type")); + CHECK_RESULT(ReadTable(&out->tableType.elem_limits)); + break; + } + + case ExternalKind::Memory: { + CHECK_RESULT( + ReadMemory(&out->memType.page_limits, &out->memType.page_size)); + break; + } + + case ExternalKind::Global: { + CHECK_RESULT( + ReadGlobalHeader(&out->globalType.type, &out->globalType.mutable_)); + break; + } + + case ExternalKind::Tag: { + ERROR_UNLESS(options_.features.exceptions_enabled(), + "invalid import tag kind: exceptions not allowed"); + CHECK_RESULT(ReadTagType(&out->funcType.sig_index)); + break; + } + } + return Result::Ok; +} + +Result BinaryReader::ReportImport(Index i, + std::string_view module_name, + std::string_view field_name, + ExternalKind kind, + ExternalType& t) { + CALLBACK(OnImport, i, kind, module_name, field_name); + switch (kind) { + case ExternalKind::Func: { + CALLBACK(OnImportFunc, i, module_name, field_name, num_func_imports_, + t.funcType.sig_index); + num_func_imports_++; + break; + } + + case ExternalKind::Table: { + CALLBACK(OnImportTable, i, module_name, field_name, num_table_imports_, + t.tableType.elem_type, &t.tableType.elem_limits); + num_table_imports_++; + break; + } + + case ExternalKind::Memory: { + CALLBACK(OnImportMemory, i, module_name, field_name, num_memory_imports_, + &t.memType.page_limits, t.memType.page_size); + num_memory_imports_++; + break; + } + + case ExternalKind::Global: { + CALLBACK(OnImportGlobal, i, module_name, field_name, num_global_imports_, + t.globalType.type, t.globalType.mutable_); + num_global_imports_++; + break; + } + + case ExternalKind::Tag: { + CALLBACK(OnImportTag, i, module_name, field_name, num_tag_imports_, + t.funcType.sig_index); + num_tag_imports_++; + break; + } + } + + return Result::Ok; +} + Result BinaryReader::ReadImportSection(Offset section_size) { CALLBACK(BeginImportSection, section_size); Index num_imports; CHECK_RESULT(ReadCount(&num_imports, "import count")); CALLBACK(OnImportCount, num_imports); - for (Index i = 0; i < num_imports; ++i) { + Index i = 0; + while (i < num_imports) { std::string_view module_name; CHECK_RESULT(ReadStr(&module_name, "import module name")); std::string_view field_name; CHECK_RESULT(ReadStr(&field_name, "import field name")); - ExternalKind kind; - CHECK_RESULT(ReadExternalKind(&kind, "import kind", "import")); - CALLBACK(OnImport, i, kind, module_name, field_name); - - switch (kind) { - case ExternalKind::Func: { - Index sig_index; - CHECK_RESULT(ReadIndex(&sig_index, "import signature index")); - CALLBACK(OnImportFunc, i, module_name, field_name, num_func_imports_, - sig_index); - num_func_imports_++; - break; - } - - case ExternalKind::Table: { - Type elem_type; - Limits elem_limits; - CHECK_RESULT(ReadRefType(&elem_type, "table elem type")); - CHECK_RESULT(ReadTable(&elem_limits)); - CALLBACK(OnImportTable, i, module_name, field_name, num_table_imports_, - elem_type, &elem_limits); - num_table_imports_++; - break; - } - - case ExternalKind::Memory: { - Limits page_limits; - uint32_t page_size; - CHECK_RESULT(ReadMemory(&page_limits, &page_size)); - CALLBACK(OnImportMemory, i, module_name, field_name, - num_memory_imports_, &page_limits, page_size); - num_memory_imports_++; - break; - } - - case ExternalKind::Global: { - Type type; - bool mutable_; - CHECK_RESULT(ReadGlobalHeader(&type, &mutable_)); - CALLBACK(OnImportGlobal, i, module_name, field_name, - num_global_imports_, type, mutable_); - num_global_imports_++; - break; - } + uint8_t kind_u8; + CHECK_RESULT(ReadU8(&kind_u8, "import kind")); - case ExternalKind::Tag: { - ERROR_UNLESS(options_.features.exceptions_enabled(), - "invalid import tag kind: exceptions not allowed"); - Index sig_index; - CHECK_RESULT(ReadTagType(&sig_index)); - CALLBACK(OnImportTag, i, module_name, field_name, num_tag_imports_, - sig_index); - num_tag_imports_++; - break; + ExternalKind kind; + if (field_name == "" && (kind_u8 == 0x7F || kind_u8 == 0x7E)) { + ERROR_UNLESS(options_.features.compact_imports_enabled(), + "module uses compact imports, but feature not enabled"); + if (kind_u8 == 0x7E) { + // Read the import kind once and re-used for each of num_compact_imports + CHECK_RESULT(ReadExternalKind(&kind, "compact import kind", "import")); + } + Index num_compact_imports; + CHECK_RESULT(ReadCount(&num_compact_imports, "compact import count")); + for (Index j = 0; j < num_compact_imports; ++j) { + CHECK_RESULT(ReadStr(&field_name, "compact import field name")); + if (kind_u8 != 0x7E) { + CHECK_RESULT( + ReadExternalKind(&kind, "compact import kind", "import")); + } + ExternalType type; + CHECK_RESULT(ReadImportDetails(kind, &type)); + CHECK_RESULT(ReportImport(i++, module_name, field_name, kind, type)); } + } else { + // Normal non-compact import + ExternalType type; + // kind_u8 was not one of the special values above so rewind one + // byte so we can read it with ReadExternalKind + state_.offset--; + CHECK_RESULT(ReadExternalKind(&kind, "import kind", "import")); + CHECK_RESULT(ReadImportDetails(kind, &type)); + CHECK_RESULT(ReportImport(i++, module_name, field_name, kind, type)); } } diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 52671de617..609bcaddf3 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -435,6 +435,7 @@ class BinaryWriter { void WriteTagType(const Tag* tag); void WriteRelocSection(const RelocSection* reloc_section); void WriteLinkingSection(); + void WriteImport(const Import* import); template void WriteNames(const std::vector& elems, NameSectionSubsection type); void WriteCodeMetadataSections(); @@ -1401,6 +1402,33 @@ void BinaryWriter::WriteNames(const std::vector& elems, EndSubsection(); } +void BinaryWriter::WriteImport(const Import* import) { + switch (import->kind()) { + case ExternalKind::Func: + WriteU32Leb128( + stream_, + module_->GetFuncTypeIndex(cast(import)->func.decl), + "import signature index"); + break; + + case ExternalKind::Table: + WriteTable(&cast(import)->table); + break; + + case ExternalKind::Memory: + WriteMemory(&cast(import)->memory); + break; + + case ExternalKind::Global: + WriteGlobalHeader(&cast(import)->global); + break; + + case ExternalKind::Tag: + WriteTagType(&cast(import)->tag); + break; + } +} + Result BinaryWriter::WriteModule() { stream_->WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC"); stream_->WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION"); @@ -1466,37 +1494,49 @@ Result BinaryWriter::WriteModule() { BeginKnownSection(BinarySection::Import); WriteU32Leb128(stream_, module_->imports.size(), "num imports"); - for (size_t i = 0; i < module_->imports.size(); ++i) { + size_t i = 0; + while (i < module_->imports.size()) { const Import* import = module_->imports[i]; WriteHeader("import header", i); WriteStr(stream_, import->module_name, "import module name", PrintChars::Yes); - WriteStr(stream_, import->field_name, "import field name", - PrintChars::Yes); - stream_->WriteU8Enum(import->kind(), "import kind"); - switch (import->kind()) { - case ExternalKind::Func: - WriteU32Leb128( - stream_, - module_->GetFuncTypeIndex(cast(import)->func.decl), - "import signature index"); - break; - - case ExternalKind::Table: - WriteTable(&cast(import)->table); - break; - - case ExternalKind::Memory: - WriteMemory(&cast(import)->memory); - break; - - case ExternalKind::Global: - WriteGlobalHeader(&cast(import)->global); - break; - - case ExternalKind::Tag: - WriteTagType(&cast(import)->tag); - break; + bool compact = false; + if (options_.features.compact_imports_enabled()) { + // Write compact imports when they are available. + // Currentsly we donly support grouping by module name (0x7F mode) + // and not the module name + kind grouping (0x7E mode). + size_t group_size = 1; + for (size_t j = i + 1; j < module_->imports.size(); ++j) { + if (import->module_name == module_->imports[j]->module_name) { + group_size++; + } else { + break; + } + } + // Use compact imports iff we have a continuous sequence of more than + // one import with the same module name. + if (group_size > 1) { + compact = true; + WriteStr(stream_, "", "empty field name", PrintChars::Yes); + stream_->WriteU8(0x7F, "compact import marker"); + WriteU32Leb128(stream_, group_size, "import group size"); + while (group_size--) { + WriteHeader("compact import header", i); + const Import* import = module_->imports[i]; + WriteStr(stream_, import->field_name, "import field name", + PrintChars::Yes); + stream_->WriteU8Enum(import->kind(), "import kind"); + WriteImport(import); + i++; + } + } + } + if (!compact) { + WriteStr(stream_, import->field_name, "import field name", + PrintChars::Yes); + stream_->WriteU8Enum(import->kind(), "import kind"); + WriteImport(import); + i++; } } EndSection(); diff --git a/src/tools/wasm2c.cc b/src/tools/wasm2c.cc index df0d7be74b..fae89a5327 100644 --- a/src/tools/wasm2c.cc +++ b/src/tools/wasm2c.cc @@ -58,12 +58,12 @@ static const char s_description[] = )"; static const std::string supported_features[] = { - "multi-memory", "multi-value", - "sign-extension", "saturating-float-to-int", - "exceptions", "memory64", - "extended-const", "simd", - "threads", "tail-call", - "custom-page-sizes"}; + "multi-memory", "multi-value", + "sign-extension", "saturating-float-to-int", + "exceptions", "memory64", + "extended-const", "simd", + "threads", "tail-call", + "custom-page-sizes", "compact-imports"}; static bool IsFeatureSupported(const std::string& feature) { return std::find(std::begin(supported_features), std::end(supported_features), diff --git a/src/wabt.post.js b/src/wabt.post.js index db324687ce..dc2fca323b 100644 --- a/src/wabt.post.js +++ b/src/wabt.post.js @@ -37,6 +37,7 @@ const FEATURES = Object.freeze({ 'multi_memory': false, 'extended_const': false, 'relaxed_simd': false, + 'compact_imports': false, }); /// If value is not undefined, return it. Otherwise return default_. diff --git a/test/binary/compact-imports.txt b/test/binary/compact-imports.txt new file mode 100644 index 0000000000..ae1400e6a1 --- /dev/null +++ b/test/binary/compact-imports.txt @@ -0,0 +1,54 @@ +;;; TOOL: run-gen-wasm +;;; ARGS: -v +;;; ARGS1: --enable-compact-import +;;; ARGS2: --enable-compact-import +magic +version +section(TYPE) { count[1] function params[0] results[1] i32 } +section(IMPORT) { + count[6] + str("mod") str("func") func_kind type[0] + str("mod") str("") compact[0x7F] + count[3] + str("func2") func_kind type[0] + str("func3") func_kind type[0] + str("func4") func_kind type[0] + str("mod") str("") compact[0x7E] + func_kind + count[2] + str("func5") type[0] + str("func6") type[0] +} +(;; STDERR ;;; +BeginModule(version: 1) + BeginTypeSection(5) + OnTypeCount(1) + OnFuncType(index: 0, params: [], results: [i32]) + EndTypeSection + BeginImportSection(65) + OnImportCount(6) + OnImport(index: 0, kind: func, module: "mod", field: "func") + OnImportFunc(import_index: 0, func_index: 0, sig_index: 0) + OnImport(index: 1, kind: func, module: "mod", field: "func2") + OnImportFunc(import_index: 1, func_index: 1, sig_index: 0) + OnImport(index: 2, kind: func, module: "mod", field: "func3") + OnImportFunc(import_index: 2, func_index: 2, sig_index: 0) + OnImport(index: 3, kind: func, module: "mod", field: "func4") + OnImportFunc(import_index: 3, func_index: 3, sig_index: 0) + OnImport(index: 4, kind: func, module: "mod", field: "func5") + OnImportFunc(import_index: 4, func_index: 4, sig_index: 0) + OnImport(index: 5, kind: func, module: "mod", field: "func6") + OnImportFunc(import_index: 5, func_index: 5, sig_index: 0) + EndImportSection +EndModule +;;; STDERR ;;) +(;; STDOUT ;;; +(module + (type (;0;) (func (result i32))) + (import "mod" "func" (func (;0;) (type 0))) + (import "mod" "func2" (func (;1;) (type 0))) + (import "mod" "func3" (func (;2;) (type 0))) + (import "mod" "func4" (func (;3;) (type 0))) + (import "mod" "func5" (func (;4;) (type 0))) + (import "mod" "func6" (func (;5;) (type 0)))) +;;; STDOUT ;;) diff --git a/test/dump/compact-imports.txt b/test/dump/compact-imports.txt new file mode 100644 index 0000000000..babda98c83 --- /dev/null +++ b/test/dump/compact-imports.txt @@ -0,0 +1,117 @@ +;;; TOOL: run-objdump +;;; ARGS0: -v --enable-compact-imports +;;; ARGS1: -x +(module + (import "mod1" "test" (func (param i32 i64 f32 f64))) + (import "mod1" "test2" (func (param i32) (result i32))) + (import "mod2" "testmem" (memory 0)) + (import "mod2" "testtable" (table 0 funcref)) + (import "mod1" "testtag" (tag (param i32))) + (import "mod1" "func" (func (param i32 i64 f32 f64))) +) +(;; STDERR ;;; +0000000: 0061 736d ; WASM_BINARY_MAGIC +0000004: 0100 0000 ; WASM_BINARY_VERSION +; section "Type" (1) +0000008: 01 ; section code +0000009: 00 ; section size (guess) +000000a: 03 ; num types +; func type 0 +000000b: 60 ; func +000000c: 04 ; num params +000000d: 7f ; i32 +000000e: 7e ; i64 +000000f: 7d ; f32 +0000010: 7c ; f64 +0000011: 00 ; num results +; func type 1 +0000012: 60 ; func +0000013: 01 ; num params +0000014: 7f ; i32 +0000015: 01 ; num results +0000016: 7f ; i32 +; func type 2 +0000017: 60 ; func +0000018: 01 ; num params +0000019: 7f ; i32 +000001a: 00 ; num results +0000009: 11 ; FIXUP section size +; section "Import" (2) +000001b: 02 ; section code +000001c: 00 ; section size (guess) +000001d: 06 ; num imports +; import header 0 +000001e: 04 ; string length +000001f: 6d6f 6431 mod1 ; import module name +0000023: 00 ; string length +0000024: 7f ; compact import marker +0000025: 02 ; import group size +; compact import header 0 +0000026: 04 ; string length +0000027: 7465 7374 test ; import field name +000002b: 00 ; import kind +000002c: 00 ; import signature index +; compact import header 1 +000002d: 05 ; string length +000002e: 7465 7374 32 test2 ; import field name +0000033: 00 ; import kind +0000034: 01 ; import signature index +; import header 2 +0000035: 04 ; string length +0000036: 6d6f 6432 mod2 ; import module name +000003a: 00 ; string length +000003b: 7f ; compact import marker +000003c: 02 ; import group size +; compact import header 2 +000003d: 07 ; string length +000003e: 7465 7374 6d65 6d testmem ; import field name +0000045: 02 ; import kind +0000046: 00 ; limits: flags +0000047: 00 ; limits: initial +; compact import header 3 +0000048: 09 ; string length +0000049: 7465 7374 7461 626c 65 testtable ; import field name +0000052: 01 ; import kind +0000053: 70 ; funcref +0000054: 00 ; limits: flags +0000055: 00 ; limits: initial +; import header 4 +0000056: 04 ; string length +0000057: 6d6f 6431 mod1 ; import module name +000005b: 00 ; string length +000005c: 7f ; compact import marker +000005d: 02 ; import group size +; compact import header 4 +000005e: 07 ; string length +000005f: 7465 7374 7461 67 testtag ; import field name +0000066: 04 ; import kind +0000067: 00 ; tag attribute +0000068: 02 ; tag signature index +; compact import header 5 +0000069: 04 ; string length +000006a: 6675 6e63 func ; import field name +000006e: 00 ; import kind +000006f: 00 ; import signature index +000001c: 53 ; FIXUP section size +;;; STDERR ;;) +(;; STDOUT ;;; + +compact-imports.wasm: file format wasm 0x1 + +Section Details: + +Type[3]: + - type[0] (i32, i64, f32, f64) -> nil + - type[1] (i32) -> i32 + - type[2] (i32) -> nil +Import[6]: + - func[0] sig=0 <- mod1.test + - func[1] sig=1 <- mod1.test2 + - memory[0] pages: initial=0 <- mod2.testmem + - table[0] type=funcref initial=0 <- mod2.testtable + - tag[0] sig=2 <- mod1.testtag + - func[2] sig=0 <- mod1.func + +Code Disassembly: + +;;; STDOUT ;;) diff --git a/test/dump/memory64.txt b/test/dump/memory64.txt index 6ad7f1fda8..09de4e0406 100644 --- a/test/dump/memory64.txt +++ b/test/dump/memory64.txt @@ -15,10 +15,10 @@ memory64.wasm: file format wasm 0x1 Sections: - Import start=0x0000000a end=0x00000027 (size=0x0000001d) count: 2 - Table start=0x00000029 end=0x0000002d (size=0x00000004) count: 1 - Memory start=0x0000002f end=0x00000032 (size=0x00000003) count: 1 - Data start=0x00000034 end=0x0000003b (size=0x00000007) count: 1 + Import start=0x0000000a end=0x00000026 (size=0x0000001c) count: 2 + Table start=0x00000028 end=0x0000002c (size=0x00000004) count: 1 + Memory start=0x0000002e end=0x00000031 (size=0x00000003) count: 1 + Data start=0x00000033 end=0x0000003a (size=0x00000007) count: 1 Section Details: diff --git a/test/dump/relocations-all-features.txt b/test/dump/relocations-all-features.txt index 8575f6140c..97ac6b20f7 100644 --- a/test/dump/relocations-all-features.txt +++ b/test/dump/relocations-all-features.txt @@ -22,16 +22,16 @@ relocations-all-features.wasm: file format wasm 0x1 Sections: Type start=0x0000000a end=0x0000001a (size=0x00000010) count: 3 - Import start=0x0000001c end=0x0000003b (size=0x0000001f) count: 2 - Function start=0x0000003d end=0x0000003f (size=0x00000002) count: 1 - Table start=0x00000041 end=0x00000046 (size=0x00000005) count: 1 - Global start=0x00000048 end=0x0000004e (size=0x00000006) count: 1 - Export start=0x00000050 end=0x00000055 (size=0x00000005) count: 1 - Elem start=0x00000057 end=0x00000064 (size=0x0000000d) count: 1 - Code start=0x00000066 end=0x0000008c (size=0x00000026) count: 1 - Custom start=0x0000008e end=0x000000af (size=0x00000021) "linking" - Custom start=0x000000b1 end=0x000000c1 (size=0x00000010) "reloc.Elem" - Custom start=0x000000c3 end=0x000000df (size=0x0000001c) "reloc.Code" + Import start=0x0000001c end=0x00000035 (size=0x00000019) count: 2 + Function start=0x00000037 end=0x00000039 (size=0x00000002) count: 1 + Table start=0x0000003b end=0x00000040 (size=0x00000005) count: 1 + Global start=0x00000042 end=0x00000048 (size=0x00000006) count: 1 + Export start=0x0000004a end=0x0000004f (size=0x00000005) count: 1 + Elem start=0x00000051 end=0x0000005e (size=0x0000000d) count: 1 + Code start=0x00000060 end=0x00000086 (size=0x00000026) count: 1 + Custom start=0x00000088 end=0x000000a9 (size=0x00000021) "linking" + Custom start=0x000000ab end=0x000000bb (size=0x00000010) "reloc.Elem" + Custom start=0x000000bd end=0x000000d9 (size=0x0000001c) "reloc.Code" Section Details: @@ -66,30 +66,30 @@ Custom: Custom: - name: "reloc.Elem" - relocations for section: 6 (Elem) [1] - - R_WASM_FUNCTION_INDEX_LEB offset=0x000007(file=0x00005e) symbol=1 <__extern.bar> + - R_WASM_FUNCTION_INDEX_LEB offset=0x000007(file=0x000058) symbol=1 <__extern.bar> Custom: - name: "reloc.Code" - relocations for section: 7 (Code) [5] - - R_WASM_GLOBAL_INDEX_LEB offset=0x000004(file=0x00006a) symbol=4 - - R_WASM_FUNCTION_INDEX_LEB offset=0x00000a(file=0x000070) symbol=2 - - R_WASM_FUNCTION_INDEX_LEB offset=0x000010(file=0x000076) symbol=0 <__extern.foo> - - R_WASM_TYPE_INDEX_LEB offset=0x00001b(file=0x000081) type=2 - - R_WASM_TABLE_NUMBER_LEB offset=0x000020(file=0x000086) symbol=3 <> + - R_WASM_GLOBAL_INDEX_LEB offset=0x000004(file=0x000064) symbol=4 + - R_WASM_FUNCTION_INDEX_LEB offset=0x00000a(file=0x00006a) symbol=2 + - R_WASM_FUNCTION_INDEX_LEB offset=0x000010(file=0x000070) symbol=0 <__extern.foo> + - R_WASM_TYPE_INDEX_LEB offset=0x00001b(file=0x00007b) type=2 + - R_WASM_TABLE_NUMBER_LEB offset=0x000020(file=0x000080) symbol=3 <> Code Disassembly: -000068 func[2] : - 000069: 23 80 80 80 80 00 | global.get 0 - 00006a: R_WASM_GLOBAL_INDEX_LEB 4 - 00006f: 10 82 80 80 80 00 | call 2 - 000070: R_WASM_FUNCTION_INDEX_LEB 2 - 000075: 10 80 80 80 80 00 | call 0 <__extern.foo> - 000076: R_WASM_FUNCTION_INDEX_LEB 0 <__extern.foo> - 00007b: 41 d2 09 | i32.const 1234 - 00007e: 41 00 | i32.const 0 - 000080: 11 82 80 80 80 00 80 80 80 | call_indirect 0 (type 2) - 000089: 80 00 | - 000081: R_WASM_TYPE_INDEX_LEB 2 - 00008b: 0b | end - 000086: R_WASM_TABLE_NUMBER_LEB 3 <> +000062 func[2] : + 000063: 23 80 80 80 80 00 | global.get 0 + 000064: R_WASM_GLOBAL_INDEX_LEB 4 + 000069: 10 82 80 80 80 00 | call 2 + 00006a: R_WASM_FUNCTION_INDEX_LEB 2 + 00006f: 10 80 80 80 80 00 | call 0 <__extern.foo> + 000070: R_WASM_FUNCTION_INDEX_LEB 0 <__extern.foo> + 000075: 41 d2 09 | i32.const 1234 + 000078: 41 00 | i32.const 0 + 00007a: 11 82 80 80 80 00 80 80 80 | call_indirect 0 (type 2) + 000083: 80 00 | + 00007b: R_WASM_TYPE_INDEX_LEB 2 + 000085: 0b | end + 000080: R_WASM_TABLE_NUMBER_LEB 3 <> ;;; STDOUT ;;) diff --git a/test/dump/symbol-tables.txt b/test/dump/symbol-tables.txt index 04a2085d97..8dc405faef 100644 --- a/test/dump/symbol-tables.txt +++ b/test/dump/symbol-tables.txt @@ -49,29 +49,29 @@ Custom: Custom: - name: "reloc.Code" - relocations for section: 5 (Code) [5] - - R_WASM_FUNCTION_INDEX_LEB offset=0x000004(file=0x000042) symbol=0 - - R_WASM_FUNCTION_INDEX_LEB offset=0x00000d(file=0x00004b) symbol=0 - - R_WASM_TYPE_INDEX_LEB offset=0x000018(file=0x000056) type=0 - - R_WASM_TABLE_NUMBER_LEB offset=0x00001d(file=0x00005b) symbol=4 - - R_WASM_FUNCTION_INDEX_LEB offset=0x000023(file=0x000061) symbol=0 + - R_WASM_FUNCTION_INDEX_LEB offset=0x000004(file=0x000041) symbol=0 + - R_WASM_FUNCTION_INDEX_LEB offset=0x00000d(file=0x00004a) symbol=0 + - R_WASM_TYPE_INDEX_LEB offset=0x000018(file=0x000055) type=0 + - R_WASM_TABLE_NUMBER_LEB offset=0x00001d(file=0x00005a) symbol=4 + - R_WASM_FUNCTION_INDEX_LEB offset=0x000023(file=0x000060) symbol=0 Code Disassembly: -000040 func[1] : - 000041: 10 80 80 80 80 00 | call 0 - 000042: R_WASM_FUNCTION_INDEX_LEB 0 - 000047: 0b | end -000049 func[2]: - 00004a: 10 80 80 80 80 00 | call 0 - 00004b: R_WASM_FUNCTION_INDEX_LEB 0 - 000050: 0b | end -000052 func[3] : - 000053: 41 00 | i32.const 0 - 000055: 11 80 80 80 80 00 80 80 80 | call_indirect 0 (type 0) - 00005e: 80 00 | - 000056: R_WASM_TYPE_INDEX_LEB 0 - 000060: 10 80 80 80 80 00 | call 0 - 00005b: R_WASM_TABLE_NUMBER_LEB 4 - 000066: 0b | end - 000061: R_WASM_FUNCTION_INDEX_LEB 0 +00003f func[1] : + 000040: 10 80 80 80 80 00 | call 0 + 000041: R_WASM_FUNCTION_INDEX_LEB 0 + 000046: 0b | end +000048 func[2]: + 000049: 10 80 80 80 80 00 | call 0 + 00004a: R_WASM_FUNCTION_INDEX_LEB 0 + 00004f: 0b | end +000051 func[3] : + 000052: 41 00 | i32.const 0 + 000054: 11 80 80 80 80 00 80 80 80 | call_indirect 0 (type 0) + 00005d: 80 00 | + 000055: R_WASM_TYPE_INDEX_LEB 0 + 00005f: 10 80 80 80 80 00 | call 0 + 00005a: R_WASM_TABLE_NUMBER_LEB 4 + 000065: 0b | end + 000060: R_WASM_FUNCTION_INDEX_LEB 0 ;;; STDOUT ;;) diff --git a/test/help/spectest-interp.txt b/test/help/spectest-interp.txt index 3fc0e6d7c5..2e96e24b73 100644 --- a/test/help/spectest-interp.txt +++ b/test/help/spectest-interp.txt @@ -32,6 +32,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features -V, --value-stack-size=SIZE Size in elements of the value stack -C, --call-stack-size=SIZE Size in elements of the call stack diff --git a/test/help/wasm-interp.txt b/test/help/wasm-interp.txt index 800532e660..47b5618a53 100644 --- a/test/help/wasm-interp.txt +++ b/test/help/wasm-interp.txt @@ -46,6 +46,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features -V, --value-stack-size=SIZE Size in elements of the value stack -C, --call-stack-size=SIZE Size in elements of the call stack diff --git a/test/help/wasm-stats.txt b/test/help/wasm-stats.txt index 5e83b1e32f..c31fef7496 100644 --- a/test/help/wasm-stats.txt +++ b/test/help/wasm-stats.txt @@ -32,6 +32,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features -o, --output=FILENAME Output file for the stats, by default use stdout -c, --cutoff=N Cutoff for reporting counts less than N diff --git a/test/help/wasm-validate.txt b/test/help/wasm-validate.txt index 1b4b424b39..bf86370dc3 100644 --- a/test/help/wasm-validate.txt +++ b/test/help/wasm-validate.txt @@ -32,6 +32,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features --no-debug-names Ignore debug names in the binary file --ignore-custom-section-errors Ignore errors in custom sections diff --git a/test/help/wasm2wat.txt b/test/help/wasm2wat.txt index f2b2f5c88f..e37d25b2da 100644 --- a/test/help/wasm2wat.txt +++ b/test/help/wasm2wat.txt @@ -38,6 +38,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features --inline-exports Write all exports inline --inline-imports Write all imports inline diff --git a/test/help/wast2json.txt b/test/help/wast2json.txt index 1dbb9c54d6..9fe7c1b73e 100644 --- a/test/help/wast2json.txt +++ b/test/help/wast2json.txt @@ -35,6 +35,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features -o, --output=FILE output JSON file -r, --relocatable Create a relocatable wasm binary (suitable for linking with e.g. lld) diff --git a/test/help/wat-desugar.txt b/test/help/wat-desugar.txt index 2560ed7585..d08c84f041 100644 --- a/test/help/wat-desugar.txt +++ b/test/help/wat-desugar.txt @@ -42,6 +42,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features --generate-names Give auto-generated names to non-named functions, types, etc. ;;; STDOUT ;;) diff --git a/test/help/wat2wasm.txt b/test/help/wat2wasm.txt index 19b3d5d15e..b94d920832 100644 --- a/test/help/wat2wasm.txt +++ b/test/help/wat2wasm.txt @@ -42,6 +42,7 @@ options: --enable-extended-const Enable Extended constant expressions --enable-relaxed-simd Enable Relaxed SIMD --enable-custom-page-sizes Enable Custom page sizes + --enable-compact-imports Enable Compact import section --enable-all Enable all features -o, --output=FILE Output wasm binary file. Use "-" to write to stdout. -r, --relocatable Create a relocatable wasm binary (suitable for linking with e.g. lld) From c99744e57fd60b3f17637e6364b74dd58d76886e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 21 Jan 2026 11:03:19 -0800 Subject: [PATCH 2/2] feedback --- src/binary-reader.cc | 132 ++++++++++++++----------------------------- src/binary-writer.cc | 13 ++--- 2 files changed, 47 insertions(+), 98 deletions(-) diff --git a/src/binary-reader.cc b/src/binary-reader.cc index e80acf68e1..379c6f2c0f 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -70,33 +70,6 @@ namespace wabt { namespace { -struct ExternalType { - // Union into which we read extern type details. - ExternalType() : memType{} {} - ~ExternalType() {} - union { - // Global - struct { - Type type; - bool mutable_; - } globalType; - // Function/Tag - struct { - Index sig_index; - } funcType; - // Memory - struct { - Limits page_limits; - uint32_t page_size; - } memType; - // Table - struct { - Limits elem_limits; - Type elem_type; - } tableType; - }; -}; - class BinaryReader { public: struct ReadModuleOptions { @@ -204,12 +177,10 @@ class BinaryReader { [[nodiscard]] Result ReadCustomSection(Index section_index, Offset section_size); [[nodiscard]] Result ReadTypeSection(Offset section_size); - [[nodiscard]] Result ReadImportDetails(ExternalKind kind, ExternalType* out); - [[nodiscard]] Result ReportImport(Index i, - std::string_view module_name, - std::string_view field_name, - ExternalKind kind, - ExternalType& type); + [[nodiscard]] Result ReadImport(Index i, + std::string_view module_name, + std::string_view field_name, + ExternalKind kind); [[nodiscard]] Result ReadImportSection(Offset section_size); [[nodiscard]] Result ReadFunctionSection(Offset section_size); [[nodiscard]] Result ReadTableSection(Offset section_size); @@ -2720,80 +2691,59 @@ Result BinaryReader::ReadTypeSection(Offset section_size) { return Result::Ok; } -Result BinaryReader::ReadImportDetails(ExternalKind kind, ExternalType* out) { - switch (kind) { - case ExternalKind::Func: { - CHECK_RESULT( - ReadIndex(&out->funcType.sig_index, "import signature index")); - break; - } - - case ExternalKind::Table: { - CHECK_RESULT(ReadRefType(&out->tableType.elem_type, "table elem type")); - CHECK_RESULT(ReadTable(&out->tableType.elem_limits)); - break; - } - - case ExternalKind::Memory: { - CHECK_RESULT( - ReadMemory(&out->memType.page_limits, &out->memType.page_size)); - break; - } - - case ExternalKind::Global: { - CHECK_RESULT( - ReadGlobalHeader(&out->globalType.type, &out->globalType.mutable_)); - break; - } - - case ExternalKind::Tag: { - ERROR_UNLESS(options_.features.exceptions_enabled(), - "invalid import tag kind: exceptions not allowed"); - CHECK_RESULT(ReadTagType(&out->funcType.sig_index)); - break; - } - } - return Result::Ok; -} - -Result BinaryReader::ReportImport(Index i, - std::string_view module_name, - std::string_view field_name, - ExternalKind kind, - ExternalType& t) { +Result BinaryReader::ReadImport(Index i, + std::string_view module_name, + std::string_view field_name, + ExternalKind kind) { CALLBACK(OnImport, i, kind, module_name, field_name); switch (kind) { case ExternalKind::Func: { + Index sig_index; + CHECK_RESULT(ReadIndex(&sig_index, "import signature index")); CALLBACK(OnImportFunc, i, module_name, field_name, num_func_imports_, - t.funcType.sig_index); + sig_index); num_func_imports_++; break; } case ExternalKind::Table: { + Limits elem_limits; + Type elem_type; + CHECK_RESULT(ReadRefType(&elem_type, "table elem type")); + CHECK_RESULT(ReadTable(&elem_limits)); CALLBACK(OnImportTable, i, module_name, field_name, num_table_imports_, - t.tableType.elem_type, &t.tableType.elem_limits); + elem_type, &elem_limits); num_table_imports_++; break; } case ExternalKind::Memory: { + Limits page_limits; + uint32_t page_size; + CHECK_RESULT(ReadMemory(&page_limits, &page_size)); CALLBACK(OnImportMemory, i, module_name, field_name, num_memory_imports_, - &t.memType.page_limits, t.memType.page_size); + &page_limits, page_size); num_memory_imports_++; break; } case ExternalKind::Global: { + Type type; + bool mutable_; + CHECK_RESULT(ReadGlobalHeader(&type, &mutable_)); CALLBACK(OnImportGlobal, i, module_name, field_name, num_global_imports_, - t.globalType.type, t.globalType.mutable_); + type, mutable_); num_global_imports_++; break; } case ExternalKind::Tag: { + Index sig_index; + ERROR_UNLESS(options_.features.exceptions_enabled(), + "invalid import tag kind: exceptions not allowed"); + CHECK_RESULT(ReadTagType(&sig_index)); CALLBACK(OnImportTag, i, module_name, field_name, num_tag_imports_, - t.funcType.sig_index); + sig_index); num_tag_imports_++; break; } @@ -2821,31 +2771,31 @@ Result BinaryReader::ReadImportSection(Offset section_size) { if (field_name == "" && (kind_u8 == 0x7F || kind_u8 == 0x7E)) { ERROR_UNLESS(options_.features.compact_imports_enabled(), "module uses compact imports, but feature not enabled"); + Index num_compact_imports; if (kind_u8 == 0x7E) { // Read the import kind once and re-used for each of num_compact_imports CHECK_RESULT(ReadExternalKind(&kind, "compact import kind", "import")); - } - Index num_compact_imports; - CHECK_RESULT(ReadCount(&num_compact_imports, "compact import count")); - for (Index j = 0; j < num_compact_imports; ++j) { - CHECK_RESULT(ReadStr(&field_name, "compact import field name")); - if (kind_u8 != 0x7E) { + CHECK_RESULT(ReadCount(&num_compact_imports, "compact import count")); + for (Index j = 0; j < num_compact_imports; ++j) { + CHECK_RESULT(ReadStr(&field_name, "compact import field name")); + CHECK_RESULT(ReadImport(i++, module_name, field_name, kind)); + } + } else { + CHECK_RESULT(ReadCount(&num_compact_imports, "compact import count")); + for (Index j = 0; j < num_compact_imports; ++j) { + CHECK_RESULT(ReadStr(&field_name, "compact import field name")); CHECK_RESULT( ReadExternalKind(&kind, "compact import kind", "import")); + CHECK_RESULT(ReadImport(i++, module_name, field_name, kind)); } - ExternalType type; - CHECK_RESULT(ReadImportDetails(kind, &type)); - CHECK_RESULT(ReportImport(i++, module_name, field_name, kind, type)); } } else { // Normal non-compact import - ExternalType type; // kind_u8 was not one of the special values above so rewind one // byte so we can read it with ReadExternalKind state_.offset--; CHECK_RESULT(ReadExternalKind(&kind, "import kind", "import")); - CHECK_RESULT(ReadImportDetails(kind, &type)); - CHECK_RESULT(ReportImport(i++, module_name, field_name, kind, type)); + CHECK_RESULT(ReadImport(i++, module_name, field_name, kind)); } } diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 609bcaddf3..7336129aa9 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -1503,15 +1503,14 @@ Result BinaryWriter::WriteModule() { bool compact = false; if (options_.features.compact_imports_enabled()) { // Write compact imports when they are available. - // Currentsly we donly support grouping by module name (0x7F mode) + // Currently we only support grouping by module name (0x7F mode) // and not the module name + kind grouping (0x7E mode). size_t group_size = 1; - for (size_t j = i + 1; j < module_->imports.size(); ++j) { - if (import->module_name == module_->imports[j]->module_name) { - group_size++; - } else { - break; - } + size_t j = i + 1; + while (j < module_->imports.size() && + import->module_name == module_->imports[j]->module_name) { + group_size++; + j++; } // Use compact imports iff we have a continuous sequence of more than // one import with the same module name.