Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
1 change: 1 addition & 0 deletions include/wabt/feature.def
Original file line number Diff line number Diff line change
Expand Up @@ -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")
151 changes: 97 additions & 54 deletions src/binary-reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ class BinaryReader {
[[nodiscard]] Result ReadCustomSection(Index section_index,
Offset section_size);
[[nodiscard]] Result ReadTypeSection(Offset section_size);
[[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);
Expand Down Expand Up @@ -2687,72 +2691,111 @@ Result BinaryReader::ReadTypeSection(Offset section_size) {
return Result::Ok;
}

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_,
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_,
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;
}

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_,
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;
}
uint8_t kind_u8;
CHECK_RESULT(ReadU8(&kind_u8, "import kind"));

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;
}

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");
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"));
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));
}
}
} else {
// Normal non-compact import
// 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(ReadImport(i++, module_name, field_name, kind));
}
}

Expand Down
93 changes: 66 additions & 27 deletions src/binary-writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T>
void WriteNames(const std::vector<T*>& elems, NameSectionSubsection type);
void WriteCodeMetadataSections();
Expand Down Expand Up @@ -1401,6 +1402,33 @@ void BinaryWriter::WriteNames(const std::vector<T*>& elems,
EndSubsection();
}

void BinaryWriter::WriteImport(const Import* import) {
switch (import->kind()) {
case ExternalKind::Func:
WriteU32Leb128(
stream_,
module_->GetFuncTypeIndex(cast<FuncImport>(import)->func.decl),
"import signature index");
break;

case ExternalKind::Table:
WriteTable(&cast<TableImport>(import)->table);
break;

case ExternalKind::Memory:
WriteMemory(&cast<MemoryImport>(import)->memory);
break;

case ExternalKind::Global:
WriteGlobalHeader(&cast<GlobalImport>(import)->global);
break;

case ExternalKind::Tag:
WriteTagType(&cast<TagImport>(import)->tag);
break;
}
}

Result BinaryWriter::WriteModule() {
stream_->WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC");
stream_->WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION");
Expand Down Expand Up @@ -1466,37 +1494,48 @@ 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<FuncImport>(import)->func.decl),
"import signature index");
break;

case ExternalKind::Table:
WriteTable(&cast<TableImport>(import)->table);
break;

case ExternalKind::Memory:
WriteMemory(&cast<MemoryImport>(import)->memory);
break;

case ExternalKind::Global:
WriteGlobalHeader(&cast<GlobalImport>(import)->global);
break;

case ExternalKind::Tag:
WriteTagType(&cast<TagImport>(import)->tag);
break;
bool compact = false;
if (options_.features.compact_imports_enabled()) {
// Write compact imports when they are available.
// Currently we only support grouping by module name (0x7F mode)
// and not the module name + kind grouping (0x7E mode).
size_t group_size = 1;
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.
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();
Expand Down
12 changes: 6 additions & 6 deletions src/tools/wasm2c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions src/wabt.post.js
Original file line number Diff line number Diff line change
Expand Up @@ -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_.
Expand Down
54 changes: 54 additions & 0 deletions test/binary/compact-imports.txt
Original file line number Diff line number Diff line change
@@ -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 ;;)
Loading
Loading