From 6fb2a4a2d48576cb8a2b470a937a7c505419de32 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 5 Oct 2025 05:20:48 +0300 Subject: [PATCH 01/59] Move SymbolTable out of binary writer --- include/wabt/ir.h | 181 +++++++++++++++++++++++++++++++ src/binary-writer.cc | 246 ------------------------------------------- src/ir.cc | 139 ++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 246 deletions(-) diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 5fa4439a0c..3100cacde7 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -1211,6 +1211,187 @@ struct Custom { Location loc; }; +class Symbol: public SymbolCommon { + public: + struct Function { + static const SymbolType type = SymbolType::Function; + Index index; + }; + struct Data { + static const SymbolType type = SymbolType::Data; + Index index; + Offset offset; + Address size; + }; + struct Global { + static const SymbolType type = SymbolType::Global; + Index index; + }; + struct Section { + static const SymbolType type = SymbolType::Section; + Index section; + }; + struct Tag { + static const SymbolType type = SymbolType::Tag; + Index index; + }; + struct Table { + static const SymbolType type = SymbolType::Table; + Index index; + }; + + private: + SymbolType type_; + union { + Function function_; + Data data_; + Global global_; + Section section_; + Tag tag_; + Table table_; + }; + + public: + Symbol(const std::string& name, uint32_t flags, const Function& f) + : type_(Function::type), SymbolCommon{flags, name}, function_(f) {} + Symbol(const std::string& name, uint32_t flags, const Data& d) + : type_(Data::type), SymbolCommon{flags, name}, data_(d) {} + Symbol(const std::string& name, uint32_t flags, const Global& g) + : type_(Global::type), SymbolCommon{flags, name}, global_(g) {} + Symbol(const std::string& name, uint32_t flags, const Section& s) + : type_(Section::type), SymbolCommon{flags, name}, section_(s) {} + Symbol(const std::string& name, uint32_t flags, const Tag& e) + : type_(Tag::type), SymbolCommon{flags, name}, tag_(e) {} + Symbol(const std::string& name, uint32_t flags, const Table& t) + : type_(Table::type), SymbolCommon{flags, name}, table_(t) {} + + template + auto visit(F f) { + switch (type()) { + case Function::type: + return f(AsFunction()); + case Data::type: + return f(AsData()); + case Global::type: + return f(AsGlobal()); + case Section::type: + return f(AsSection()); + case Tag::type: + return f(AsTag()); + case Table::type: + return f(AsTable()); + } + } + + SymbolType type() const { return type_; } + + bool IsFunction() const { return type() == Function::type; } + bool IsData() const { return type() == Data::type; } + bool IsGlobal() const { return type() == Global::type; } + bool IsSection() const { return type() == Section::type; } + bool IsTag() const { return type() == Tag::type; } + bool IsTable() const { return type() == Table::type; } + + const Function& AsFunction() const { + assert(IsFunction()); + return function_; + } + const Data& AsData() const { + assert(IsData()); + return data_; + } + const Global& AsGlobal() const { + assert(IsGlobal()); + return global_; + } + const Section& AsSection() const { + assert(IsSection()); + return section_; + } + const Tag& AsTag() const { + assert(IsTag()); + return tag_; + } + const Table& AsTable() const { + assert(IsTable()); + return table_; + } +}; + +class SymbolTable { + std::vector symbols_; + + // Maps from wasm entities to symbol entry indices + std::vector functions_; + std::vector tables_; + std::vector globals_; + std::vector tags_; + std::vector datas_; + + std::set seen_names_; + + Result EnsureUnique(const std::string_view& name) { + if (seen_names_.count(name)) { + fprintf(stderr, + "error: duplicate symbol when writing relocatable " + "binary: %s\n", + &name[0]); + return Result::Error; + } + seen_names_.insert(name); + return Result::Ok; + }; + + template + std::vector& GetTable() = delete; + + template + auto GetTable() const + -> const decltype(std::declval().GetTable())& { + return const_cast(this)->GetTable(); + } + + template + Result AddSymbol(std::string_view name, bool imported, bool exported, + T&& sym); + + public: + SymbolTable() {} + + Result Populate(const Module* module); + + Result AddSymbol(Symbol sym); + + std::vector& symbols() { return symbols_; } + const std::vector& symbols() const { return symbols_; } + + template + Index SymbolIndex(Index index) const { + // For well-formed modules, an index into (e.g.) functions_ will always be + // within bounds; the out-of-bounds case here is just to allow --relocatable + // to write known-invalid modules. + return index < GetTable().size() ? GetTable()[index] : kInvalidIndex; + } + + Index FunctionSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index TableSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index GlobalSymbolIndex(Index index) const { + return SymbolIndex(index); + } +}; +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); + struct Module { Index GetFuncTypeIndex(const Var&) const; Index GetFuncTypeIndex(const FuncDeclaration&) const; diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 600154b941..c11ed5ae9e 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -117,252 +117,6 @@ struct RelocSection { std::vector relocations; }; -class Symbol { - public: - struct Function { - static const SymbolType type = SymbolType::Function; - Index index; - }; - struct Data { - static const SymbolType type = SymbolType::Data; - Index index; - Offset offset; - Address size; - }; - struct Global { - static const SymbolType type = SymbolType::Global; - Index index; - }; - struct Section { - static const SymbolType type = SymbolType::Section; - Index section; - }; - struct Tag { - static const SymbolType type = SymbolType::Tag; - Index index; - }; - struct Table { - static const SymbolType type = SymbolType::Table; - Index index; - }; - - private: - SymbolType type_; - std::string_view name_; - uint8_t flags_; - union { - Function function_; - Data data_; - Global global_; - Section section_; - Tag tag_; - Table table_; - }; - - public: - Symbol(const std::string_view& name, uint8_t flags, const Function& f) - : type_(Function::type), name_(name), flags_(flags), function_(f) {} - Symbol(const std::string_view& name, uint8_t flags, const Data& d) - : type_(Data::type), name_(name), flags_(flags), data_(d) {} - Symbol(const std::string_view& name, uint8_t flags, const Global& g) - : type_(Global::type), name_(name), flags_(flags), global_(g) {} - Symbol(const std::string_view& name, uint8_t flags, const Section& s) - : type_(Section::type), name_(name), flags_(flags), section_(s) {} - Symbol(const std::string_view& name, uint8_t flags, const Tag& e) - : type_(Tag::type), name_(name), flags_(flags), tag_(e) {} - Symbol(const std::string_view& name, uint8_t flags, const Table& t) - : type_(Table::type), name_(name), flags_(flags), table_(t) {} - - SymbolType type() const { return type_; } - const std::string_view& name() const { return name_; } - uint8_t flags() const { return flags_; } - - SymbolVisibility visibility() const { - return static_cast(flags() & WABT_SYMBOL_MASK_VISIBILITY); - } - SymbolBinding binding() const { - return static_cast(flags() & WABT_SYMBOL_MASK_BINDING); - } - bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; } - bool defined() const { return !undefined(); } - bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; } - bool explicit_name() const { - return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; - } - bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } - - bool IsFunction() const { return type() == Function::type; } - bool IsData() const { return type() == Data::type; } - bool IsGlobal() const { return type() == Global::type; } - bool IsSection() const { return type() == Section::type; } - bool IsTag() const { return type() == Tag::type; } - bool IsTable() const { return type() == Table::type; } - - const Function& AsFunction() const { - assert(IsFunction()); - return function_; - } - const Data& AsData() const { - assert(IsData()); - return data_; - } - const Global& AsGlobal() const { - assert(IsGlobal()); - return global_; - } - const Section& AsSection() const { - assert(IsSection()); - return section_; - } - const Tag& AsTag() const { - assert(IsTag()); - return tag_; - } - const Table& AsTable() const { - assert(IsTable()); - return table_; - } -}; - -class SymbolTable { - WABT_DISALLOW_COPY_AND_ASSIGN(SymbolTable); - - std::vector symbols_; - - std::vector functions_; - std::vector tables_; - std::vector globals_; - - std::set seen_names_; - - Result EnsureUnique(const std::string_view& name) { - if (seen_names_.count(name)) { - fprintf(stderr, - "error: duplicate symbol when writing relocatable " - "binary: %s\n", - &name[0]); - return Result::Error; - } - seen_names_.insert(name); - return Result::Ok; - }; - - template - Result AddSymbol(std::vector* map, - std::string_view name, - bool imported, - bool exported, - T&& sym) { - uint8_t flags = 0; - if (imported) { - flags |= WABT_SYMBOL_FLAG_UNDEFINED; - // Wabt currently has no way for a user to explicitly specify the name of - // an import, so never set the EXPLICIT_NAME flag, and ignore any display - // name fabricated by wabt. - name = std::string_view(); - } else { - if (name.empty()) { - // Definitions without a name are local. - flags |= uint8_t(SymbolBinding::Local); - flags |= uint8_t(SymbolVisibility::Hidden); - } else { - // Otherwise, strip the dollar off the name; a definition $foo is - // available for linking as "foo". - assert(name[0] == '$'); - name.remove_prefix(1); - } - - if (exported) { - CHECK_RESULT(EnsureUnique(name)); - flags |= uint8_t(SymbolVisibility::Hidden); - flags |= WABT_SYMBOL_FLAG_NO_STRIP; - } - } - if (exported) { - flags |= WABT_SYMBOL_FLAG_EXPORTED; - } - - map->push_back(symbols_.size()); - symbols_.emplace_back(name, flags, sym); - return Result::Ok; - }; - - Index SymbolIndex(const std::vector& table, Index index) const { - // For well-formed modules, an index into (e.g.) functions_ will always be - // within bounds; the out-of-bounds case here is just to allow --relocatable - // to write known-invalid modules. - return index < table.size() ? table[index] : kInvalidIndex; - } - - public: - SymbolTable() {} - - Result Populate(const Module* module) { - std::set exported_funcs; - std::set exported_globals; - std::set exported_tags; - std::set exported_tables; - - for (const Export* export_ : module->exports) { - switch (export_->kind) { - case ExternalKind::Func: - exported_funcs.insert(module->GetFuncIndex(export_->var)); - break; - case ExternalKind::Table: - exported_tables.insert(module->GetTableIndex(export_->var)); - break; - case ExternalKind::Memory: - break; - case ExternalKind::Global: - exported_globals.insert(module->GetGlobalIndex(export_->var)); - break; - case ExternalKind::Tag: - exported_tags.insert(module->GetTagIndex(export_->var)); - break; - } - } - - // We currently only create symbol table entries for function, table, and - // global symbols. - for (size_t i = 0; i < module->funcs.size(); ++i) { - const Func* func = module->funcs[i]; - bool imported = i < module->num_func_imports; - bool exported = exported_funcs.count(i); - CHECK_RESULT(AddSymbol(&functions_, func->name, imported, exported, - Symbol::Function{Index(i)})); - } - - for (size_t i = 0; i < module->tables.size(); ++i) { - const Table* table = module->tables[i]; - bool imported = i < module->num_table_imports; - bool exported = exported_tables.count(i); - CHECK_RESULT(AddSymbol(&tables_, table->name, imported, exported, - Symbol::Table{Index(i)})); - } - - for (size_t i = 0; i < module->globals.size(); ++i) { - const Global* global = module->globals[i]; - bool imported = i < module->num_global_imports; - bool exported = exported_globals.count(i); - CHECK_RESULT(AddSymbol(&globals_, global->name, imported, exported, - Symbol::Global{Index(i)})); - } - - return Result::Ok; - } - - const std::vector& symbols() const { return symbols_; } - Index FunctionSymbolIndex(Index index) const { - return SymbolIndex(functions_, index); - } - Index TableSymbolIndex(Index index) const { - return SymbolIndex(tables_, index); - } - Index GlobalSymbolIndex(Index index) const { - return SymbolIndex(globals_, index); - } -}; - struct CodeMetadata { Offset offset; std::vector data; diff --git a/src/ir.cc b/src/ir.cc index 47b5cb3187..570e4ba064 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -110,6 +110,145 @@ bool FuncSignature::operator==(const FuncSignature& rhs) const { return param_types == rhs.param_types && result_types == rhs.result_types; } +template <> +std::vector& SymbolTable::GetTable() { + return functions_; +} +template <> +std::vector& SymbolTable::GetTable() { + return tables_; +} +template <> +std::vector& SymbolTable::GetTable() { + return globals_; +} +template <> +std::vector& SymbolTable::GetTable() { + return tags_; +} +template +Result SymbolTable::AddSymbol(std::string_view name, + bool imported, + bool exported, + T&& sym) { + uint8_t flags = 0; + if (imported) { + flags |= WABT_SYMBOL_FLAG_UNDEFINED; + // Wabt currently has no way for a user to explicitly specify the name of + // an import, so never set the EXPLICIT_NAME flag, and ignore any display + // name fabricated by wabt. + name = std::string_view(); + } else { + if (name.empty()) { + // Definitions without a name are local. + flags |= uint8_t(SymbolBinding::Local); + flags |= uint8_t(SymbolVisibility::Hidden); + } else { + // Otherwise, strip the dollar off the name; a definition $foo is + // available for linking as "foo". + assert(name[0] == '$'); + name.remove_prefix(1); + } + + if (exported) { + CHECK_RESULT(EnsureUnique(name)); + flags |= uint8_t(SymbolVisibility::Hidden); + flags |= WABT_SYMBOL_FLAG_NO_STRIP; + } + } + if (exported) { + flags |= WABT_SYMBOL_FLAG_EXPORTED; + } + + AddSymbol(Symbol{std::string(name), flags, sym}); + return Result::Ok; +} + +void EnlargeFor(std::vector& v, Index i) { + if (size(v) <= i) + v.resize(i + 1, kInvalidIndex); +} + +Result SymbolTable::AddSymbol(Symbol sym) { + sym.visit([this](auto type) { + using T = decltype(type); + if constexpr (!std::is_same_v && + !std::is_same_v) { + EnlargeFor(GetTable(), type.index); + assert(GetTable()[type.index] == kInvalidIndex); + GetTable()[type.index] = symbols_.size(); + } + }); + symbols_.push_back(sym); + return Result::Ok; +} +Result SymbolTable::Populate(const Module* module) { + std::set exported_funcs; + std::set exported_globals; + std::set exported_tags; + std::set exported_tables; + std::set exported_datas; + + for (const Export* export_ : module->exports) { + switch (export_->kind) { + case ExternalKind::Func: + exported_funcs.insert(module->GetFuncIndex(export_->var)); + break; + case ExternalKind::Table: + exported_tables.insert(module->GetTableIndex(export_->var)); + break; + case ExternalKind::Memory: + break; + case ExternalKind::Global: + exported_globals.insert(module->GetGlobalIndex(export_->var)); + break; + case ExternalKind::Tag: + exported_tags.insert(module->GetTagIndex(export_->var)); + break; + } + } + + for (size_t i = 0; i < module->funcs.size(); ++i) { + const Func* func = module->funcs[i]; + bool imported = i < module->num_func_imports; + bool exported = exported_funcs.count(i); + CHECK_RESULT( + AddSymbol(func->name, imported, exported, Symbol::Function{Index(i)})); + } + + for (size_t i = 0; i < module->tables.size(); ++i) { + const Table* table = module->tables[i]; + bool imported = i < module->num_table_imports; + bool exported = exported_tables.count(i); + CHECK_RESULT( + AddSymbol(table->name, imported, exported, Symbol::Table{Index(i)})); + } + + for (size_t i = 0; i < module->globals.size(); ++i) { + const Global* global = module->globals[i]; + bool imported = i < module->num_global_imports; + bool exported = exported_globals.count(i); + CHECK_RESULT( + AddSymbol(global->name, imported, exported, Symbol::Global{Index(i)})); + } + for (size_t i = 0; i < module->tags.size(); ++i) { + const Tag* tag = module->tags[i]; + bool imported = i < module->num_tag_imports; + bool exported = exported_tags.count(i); + CHECK_RESULT( + AddSymbol(tag->name, imported, exported, Symbol::Tag{Index(i)})); + } + for (size_t i = 0; i < module->data_symbols.size(); ++i) { + const DataSym* data = &module->data_symbols[i]; + bool imported = i < module->num_data_imports; + bool exported = data->exported(); + CHECK_RESULT( + AddSymbol(data->name, imported, exported, Symbol::Tag{Index(i)})); + } + + return Result::Ok; +} + const Export* Module::GetExport(std::string_view name) const { Index index = export_bindings.FindIndex(name); if (index >= exports.size()) { From 30e3733475ed2eefed5255ae7a1bf0ec929b2a37 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 5 Oct 2025 05:22:50 +0300 Subject: [PATCH 02/59] Add representation for relocations in instructions --- include/wabt/common.h | 153 ++++++++++++++++++++++++++++++++++++++++++ include/wabt/ir.h | 104 +++++++++++++++++++++++++--- src/ir.cc | 12 ++++ 3 files changed, 259 insertions(+), 10 deletions(-) diff --git a/include/wabt/common.h b/include/wabt/common.h index e1411b4870..943280cff7 100644 --- a/include/wabt/common.h +++ b/include/wabt/common.h @@ -297,9 +297,162 @@ enum class RelocType { First = FuncIndexLEB, Last = FuncIndexI32, + None = -1, // Used internally as a sentinel value }; + +enum class RelocDataType { + I32, I64, + LEB, LEB64, + SLEB, SLEB64, +}; + +constexpr size_t kRelocDataTypeSize[] { + 4, 8, + 5, 10, + 5, 10 +}; + +constexpr RelocDataType kRelocDataType[] { + RelocDataType::LEB, // FuncIndexLEB = 0 + RelocDataType::SLEB, // TableIndexSLEB = 1 + RelocDataType::I32, // TableIndexI32 = 2 + RelocDataType::LEB, // MemoryAddressLEB = 3 + RelocDataType::SLEB, // MemoryAddressSLEB = 4 + RelocDataType::I32, // MemoryAddressI32 = 5 + RelocDataType::LEB, // TypeIndexLEB = 6 + RelocDataType::LEB, // GlobalIndexLEB = 7 + RelocDataType::I32, // FunctionOffsetI32 = 8 + RelocDataType::I32, // SectionOffsetI32 = 9 + RelocDataType::LEB, // TagIndexLEB = 10 + RelocDataType::SLEB, // MemoryAddressRelSLEB = 11 + RelocDataType::SLEB, // TableIndexRelSLEB = 12 + RelocDataType::I32, // GlobalIndexI32 = 13 + RelocDataType::LEB64, // MemoryAddressLEB64 = 14 + RelocDataType::SLEB64, // MemoryAddressSLEB64 = 15 + RelocDataType::I64, // MemoryAddressI64 = 16 + RelocDataType::SLEB64, // MemoryAddressRelSLEB64 = 17 + RelocDataType::SLEB64, // TableIndexSLEB64 = 18 + RelocDataType::I64, // TableIndexI64 = 19 + RelocDataType::LEB, // TableNumberLEB = 20 + RelocDataType::SLEB, // MemoryAddressTLSSLEB = 21 + RelocDataType::I64, // FunctionOffsetI64 = 22 + RelocDataType::I32, // MemoryAddressLocRelI32 = 23 + RelocDataType::SLEB64, // TableIndexRelSLEB64 = 24 + RelocDataType::SLEB64, // MemoryAddressTLSSLEB64 = 25 + RelocDataType::I32, // FuncIndexI32 = 26 +}; + +enum class RelocKind { + Function, + FunctionTbl, + Data, + Global, + Table, + Tag, + Type, + Section, + Text, +}; + +constexpr RelocKind kRelocSymbolType[] { + RelocKind::Function, // FuncIndexLEB = 0 + RelocKind::FunctionTbl, // TableIndexSLEB = 1 + RelocKind::FunctionTbl, // TableIndexI32 = 2 + RelocKind::Data, // MemoryAddressLEB = 3 + RelocKind::Data, // MemoryAddressSLEB = 4 + RelocKind::Data, // MemoryAddressI32 = 5 + RelocKind::Type, // TypeIndexLEB = 6 + RelocKind::Global, // GlobalIndexLEB = 7 + RelocKind::Text, // FunctionOffsetI32 = 8 + RelocKind::Section, // SectionOffsetI32 = 9 + RelocKind::Tag, // TagIndexLEB = 10 + RelocKind::Data, // MemoryAddressRelSLEB = 11 + RelocKind::Table, // TableIndexRelSLEB = 12 + RelocKind::Global, // GlobalIndexI32 = 13 + RelocKind::Data, // MemoryAddressLEB64 = 14 + RelocKind::Data, // MemoryAddressSLEB64 = 15 + RelocKind::Data, // MemoryAddressI64 = 16 + RelocKind::Data, // MemoryAddressRelSLEB64 = 17 + RelocKind::FunctionTbl, // TableIndexSLEB64 = 18 + RelocKind::FunctionTbl, // TableIndexI64 = 19 + RelocKind::Table, // TableNumberLEB = 20 + RelocKind::Data, // MemoryAddressTLSSLEB = 21 + RelocKind::Text, // FunctionOffsetI64 = 22 + RelocKind::Data, // MemoryAddressLocRelI32 = 23 + RelocKind::FunctionTbl, // TableIndexRelSLEB64 = 24 + RelocKind::Data, // MemoryAddressTLSSLEB64 = 25 + RelocKind::Function, // FuncIndexI32 = 26 +}; + +enum class RelocModifiers { + None = 0, + TLS = 1, + PIC = 2, +}; + +inline RelocModifiers operator|(RelocModifiers a, RelocModifiers b) { + using U = std::underlying_type_t; + return RelocModifiers(U(a) | U(b)); +} + +inline RelocModifiers operator&(RelocModifiers a, RelocModifiers b) { + using U = std::underlying_type_t; + return RelocModifiers(U(a) & U(b)); +} + +inline RelocModifiers operator~(RelocModifiers a) { + using U = std::underlying_type_t; + return RelocModifiers(~U(a)); +} + +constexpr RelocModifiers kRelocModifiers[] { + RelocModifiers::None, // FuncIndexLEB = 0 + RelocModifiers::None, // TableIndexSLEB = 1 + RelocModifiers::None, // TableIndexI32 = 2 + RelocModifiers::None, // MemoryAddressLEB = 3 + RelocModifiers::None, // MemoryAddressSLEB = 4 + RelocModifiers::None, // MemoryAddressI32 = 5 + RelocModifiers::None, // TypeIndexLEB = 6 + RelocModifiers::None, // GlobalIndexLEB = 7 + RelocModifiers::None, // FunctionOffsetI32 = 8 + RelocModifiers::None, // SectionOffsetI32 = 9 + RelocModifiers::None, // TagIndexLEB = 10 + RelocModifiers::PIC, // MemoryAddressRelSLEB = 11 + RelocModifiers::PIC, // TableIndexRelSLEB = 12 + RelocModifiers::None, // GlobalIndexI32 = 13 + RelocModifiers::None, // MemoryAddressLEB64 = 14 + RelocModifiers::None, // MemoryAddressSLEB64 = 15 + RelocModifiers::None, // MemoryAddressI64 = 16 + RelocModifiers::PIC, // MemoryAddressRelSLEB64 = 17 + RelocModifiers::None, // TableIndexSLEB64 = 18 + RelocModifiers::None, // TableIndexI64 = 19 + RelocModifiers::None, // TableNumberLEB = 20 + RelocModifiers::TLS, // MemoryAddressTLSSLEB = 21 + RelocModifiers::None, // FunctionOffsetI64 = 22 + RelocModifiers::PIC, // MemoryAddressLocRelI32 = 23 + RelocModifiers::PIC, // TableIndexRelSLEB64 = 24 + RelocModifiers::TLS, // MemoryAddressTLSSLEB64 = 25 + RelocModifiers::None, // FuncIndexI32 = 26 +}; + + constexpr int kRelocTypeCount = WABT_ENUM_COUNT(RelocType); +constexpr RelocType RecognizeReloc(RelocKind kind, + RelocDataType type, + RelocModifiers mod) { + for (int i = 0; i < kRelocTypeCount; ++i) { + if (kind != kRelocSymbolType[i]) + continue; + if (type != kRelocDataType[i]) + continue; + if (mod != kRelocModifiers[i]) + continue; + return RelocType(i); + } + return RelocType::None; +} + struct Reloc { Reloc(RelocType, size_t offset, Index index, int32_t addend = 0); diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 3100cacde7..ccaaf7c02a 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -21,11 +21,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "wabt/binding-hash.h" #include "wabt/common.h" @@ -203,6 +205,76 @@ struct Const { }; using ConstVector = std::vector; +struct IrReloc { + IrReloc(): type(RelocType::None) {} + IrReloc(RelocType type, Var symbol, int32_t addend = 0) + : type(type), symbol(symbol), addend(addend) { + static constexpr RelocType addend_allowed[] = { + RelocType::MemoryAddressI32, RelocType::MemoryAddressI64, + RelocType::MemoryAddressLEB, RelocType::MemoryAddressLEB64, + RelocType::MemoryAddressSLEB, RelocType::MemoryAddressSLEB64, + RelocType::MemoryAddressTLSSLEB, RelocType::MemoryAddressTLSSLEB64, + RelocType::MemoryAddressRelSLEB, RelocType::MemoryAddressRelSLEB64, + RelocType::MemoryAddressLocRelI32, RelocType::SectionOffsetI32, + RelocType::FunctionOffsetI32, RelocType::FunctionOffsetI64, + }; + if (addend) { + for (auto allowed_type: addend_allowed) + if (allowed_type == this->type) + return; + assert(!"Forbidden addend for relocation type"); + } + } + RelocType type; + Var symbol; + int32_t addend; +}; + +class SymbolCommon { + std::string name_; + uint32_t flags_; +public: + SymbolCommon(uint32_t flags = 0, std::string name = "") + : name_(name), flags_(flags) {} + const std::string& name() const { return name_; } + uint32_t flags() const { return flags_; } + + SymbolVisibility visibility() const { + return static_cast(flags() & WABT_SYMBOL_MASK_VISIBILITY); + } + SymbolBinding binding() const { + return static_cast(flags() & WABT_SYMBOL_MASK_BINDING); + } + bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; } + bool defined() const { return !undefined(); } + bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; } + bool explicit_name() const { + return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } + bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } +}; + +struct DataSym: SymbolCommon { + static DataSym MakeForSearch(Index segment, Index idx) { + return {{0}, "", segment, idx, 0}; + } + bool imported() const { + return segment == kInvalidIndex; + } + std::string name; + Index segment; + Address offset; + Address size; + bool operator<(const DataSym& other) const { + if (imported() && other.imported()) + return offset < other.offset; + if (!imported() && !other.imported()) + return std::tuple(segment, offset) < + std::tuple(other.segment, other.offset); + return !imported() < !other.imported(); + }; +}; + enum class ExpectationType { Values, Either, @@ -789,6 +861,7 @@ class ConstExpr : public ExprMixin { : ExprMixin(loc), const_(c) {} Const const_; + IrReloc reloc; }; // TODO(binji): Rename this, it is used for more than loads/stores now. @@ -808,6 +881,7 @@ class LoadStoreExpr : public MemoryExpr { Opcode opcode; Address align; Address offset; + IrReloc reloc; }; using LoadExpr = LoadStoreExpr; @@ -832,7 +906,7 @@ class AtomicFenceExpr : public ExprMixin { uint32_t consistency_model; }; -struct Tag { +struct Tag: SymbolCommon { explicit Tag(std::string_view name) : name(name) {} std::string name; @@ -900,7 +974,7 @@ inline bool operator!=(const LocalTypes::const_iterator& lhs, return !operator==(lhs, rhs); } -struct Func { +struct Func: SymbolCommon { explicit Func(std::string_view name) : name(name) {} Type GetParamType(Index index) const { return decl.GetParamType(index); } @@ -928,9 +1002,12 @@ struct Func { struct { bool tailcall = false; } features_used; + + // For relocatable binaries, if a function is an init function, its priority + std::optional priority = {}; }; -struct Global { +struct Global: SymbolCommon { explicit Global(std::string_view name) : name(name) {} std::string name; @@ -939,7 +1016,7 @@ struct Global { ExprList init_expr; }; -struct Table { +struct Table: SymbolCommon { explicit Table(std::string_view name) : name(name), elem_type(Type::FuncRef) {} @@ -979,6 +1056,8 @@ struct DataSegment { Var memory_var; ExprList offset; std::vector data; + std::vector> relocs; + std::pair symbol_range = {}; }; class Import { @@ -1253,17 +1332,17 @@ class Symbol: public SymbolCommon { public: Symbol(const std::string& name, uint32_t flags, const Function& f) - : type_(Function::type), SymbolCommon{flags, name}, function_(f) {} + : SymbolCommon{flags, name}, type_(Function::type), function_(f) {} Symbol(const std::string& name, uint32_t flags, const Data& d) - : type_(Data::type), SymbolCommon{flags, name}, data_(d) {} + : SymbolCommon{flags, name}, type_(Data::type), data_(d) {} Symbol(const std::string& name, uint32_t flags, const Global& g) - : type_(Global::type), SymbolCommon{flags, name}, global_(g) {} + : SymbolCommon{flags, name}, type_(Global::type), global_(g) {} Symbol(const std::string& name, uint32_t flags, const Section& s) - : type_(Section::type), SymbolCommon{flags, name}, section_(s) {} + : SymbolCommon{flags, name}, type_(Section::type), section_(s) {} Symbol(const std::string& name, uint32_t flags, const Tag& e) - : type_(Tag::type), SymbolCommon{flags, name}, tag_(e) {} + : SymbolCommon{flags, name}, type_(Tag::type), tag_(e) {} Symbol(const std::string& name, uint32_t flags, const Table& t) - : type_(Table::type), SymbolCommon{flags, name}, table_(t) {} + : SymbolCommon{flags, name}, type_(Table::type), table_(t) {} template auto visit(F f) { @@ -1419,6 +1498,8 @@ struct Module { const ElemSegment* GetElemSegment(const Var&) const; ElemSegment* GetElemSegment(const Var&); Index GetElemSegmentIndex(const Var&) const; + DataSym* GetDataSym(const Var&); + Index GetDataSymIndex(const Var&) const; bool IsImport(ExternalKind kind, const Var&) const; bool IsImport(const Export& export_) const { @@ -1449,6 +1530,7 @@ struct Module { Index num_table_imports = 0; Index num_memory_imports = 0; Index num_global_imports = 0; + Index num_data_imports = 0; // Cached for convenience; the pointers are shared with values that are // stored in either ModuleField or Import. @@ -1464,6 +1546,7 @@ struct Module { std::vector data_segments; std::vector starts; std::vector customs; + std::vector data_symbols; BindingHash tag_bindings; BindingHash func_bindings; @@ -1474,6 +1557,7 @@ struct Module { BindingHash memory_bindings; BindingHash data_segment_bindings; BindingHash elem_segment_bindings; + BindingHash data_symbol_bindings; // For a subset of features, the BinaryReaderIR tracks whether they are // actually used by the module. wasm2c (CWriter) uses this information to diff --git a/src/ir.cc b/src/ir.cc index 570e4ba064..b501dbfbb8 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -289,6 +289,10 @@ Index Module::GetElemSegmentIndex(const Var& var) const { return elem_segment_bindings.FindIndex(var); } +Index Module::GetDataSymIndex(const Var& var) const { + return data_symbol_bindings.FindIndex(var); +} + bool Module::IsImport(ExternalKind kind, const Var& var) const { switch (kind) { case ExternalKind::Func: @@ -451,6 +455,14 @@ ElemSegment* Module::GetElemSegment(const Var& var) { return elem_segments[index]; } +DataSym* Module::GetDataSym(const Var& var) { + Index index = data_symbol_bindings.FindIndex(var); + if (index >= elem_segments.size()) { + return nullptr; + } + return &data_symbols[index]; +} + const FuncType* Module::GetFuncType(const Var& var) const { return const_cast(this)->GetFuncType(var); } From 4aaed1ee3386fc3755c3e2611fee613d28684787 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 9 Oct 2025 01:48:51 +0300 Subject: [PATCH 03/59] Add support for relocations in the binary reader --- include/wabt/common.h | 7 ++ src/binary-reader-ir.cc | 251 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) diff --git a/include/wabt/common.h b/include/wabt/common.h index 943280cff7..692c622bd6 100644 --- a/include/wabt/common.h +++ b/include/wabt/common.h @@ -186,6 +186,13 @@ void Destruct(T& placement) { placement.~T(); } +template +struct Overload: Fs... { + using Fs::operator()...; +}; +template +Overload(Fs...)->Overload; + enum class LabelType { Func, InitExpr, diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 11e88da549..fd5ac5b4b2 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -361,7 +361,25 @@ class BinaryReaderIR : public BinaryReaderNop { std::string_view name, Index table_index) override; + /* Relocation handling */ + Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) override; + Result BeginCodeSection(Offset size) override; + Result BeginDataSection(Offset size) override; + Result BeginGenericCustomSection(Offset size) override; + Result BeginElemSection(Offset size) override; + Result OnRelocCount(Index count, Index section_index) override; + Result EndRelocSection() override; + Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) override; + Result OnInitFunction(uint32_t priority, Index sym) override; + Result EndModule() override; + private: + void MakeQueue(); Location GetLocation() const; void PrintError(const char* format, ...); Result PushLabel(LabelType label_type, @@ -398,6 +416,35 @@ class BinaryReaderIR : public BinaryReaderNop { CodeMetadataExprQueue code_metadata_queue_; std::string_view current_metadata_name_; + + // Queue instructions to patch + struct RelocQueue { + RelocQueue(Offset start) + : start(start), incoming_relocs(), entries(), data_segment_starts() {} + + template + using Entries = std::tuple...>; + + template + decltype(auto) get() { + return std::get>(entries); + } + template + void traverse(F f) { + std::apply([&f](auto&&... vs) { (f(vs), ...); }, entries); + } + + Offset start; + std::vector incoming_relocs; + Entries entries; + std::map data_segment_starts; + }; + std::unordered_map reloc_queues; + decltype(reloc_queues)::iterator active_reloc_section = {}; + SymbolTable table; + std::multiset data_symbols; + + Index active_section = kInvalidIndex; }; BinaryReaderIR::BinaryReaderIR(Module* out_module, @@ -467,6 +514,13 @@ Result BinaryReaderIR::TopLabelExpr(LabelNode** label, Expr** expr) { } Result BinaryReaderIR::AppendExpr(std::unique_ptr expr) { + RelocQueue& queue = active_reloc_section->second; + queue.traverse([&](auto&& map) { + using Value = std::remove_reference_t; + if (auto* ce = dynamic_cast(expr.get())) { + map.insert({state->offset - queue.start, ce}); + } + }); expr->loc = GetLocation(); LabelNode* label; CHECK_RESULT(TopLabel(&label)); @@ -1480,6 +1534,8 @@ Result BinaryReaderIR::OnDataSegmentData(Index index, Address size) { assert(index == module_->data_segments.size() - 1); DataSegment* segment = module_->data_segments[index]; + active_reloc_section->second.data_segment_starts.emplace(state->offset - size, + segment); segment->data.resize(size); if (size > 0) { memcpy(segment->data.data(), data, size); @@ -1750,6 +1806,19 @@ Result BinaryReaderIR::OnDataSymbol(Index index, Index segment, uint32_t offset, uint32_t size) { + bool undef = flags & WABT_SYMBOL_FLAG_UNDEFINED; + if (undef) + ++module_->num_data_imports; + std::string name2{name}; + SymbolCommon common = {flags, name2}; + DataSym sym = + undef ? DataSym{common, MakeDollarName(name), kInvalidIndex, + module_->num_data_imports, 0} + : DataSym{common, MakeDollarName(name), segment, offset, size}; + data_symbols.emplace(sym); + assert(index == table.symbols().size()); + table.AddSymbol( + {name2, flags, Symbol::Data{sym.segment, sym.offset, sym.size}}); if (name.empty()) { return Result::Ok; } @@ -1778,6 +1847,10 @@ Result BinaryReaderIR::OnFunctionSymbol(Index index, uint32_t flags, std::string_view name, Index func_index) { + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Function{func_index}}; + table.AddSymbol(sym); + static_cast(*module_->funcs[func_index]) = sym; if (name.empty()) { return Result::Ok; } @@ -1801,12 +1874,18 @@ Result BinaryReaderIR::OnGlobalSymbol(Index index, uint32_t flags, std::string_view name, Index global_index) { + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Global{global_index}}; + table.AddSymbol(sym); + static_cast(*module_->globals[global_index]) = sym; return SetGlobalName(global_index, name); } Result BinaryReaderIR::OnSectionSymbol(Index index, uint32_t flags, Index section_index) { + assert(index == table.symbols().size()); + table.AddSymbol({"", flags, Symbol::Section{section_index}}); return Result::Ok; } @@ -1814,6 +1893,10 @@ Result BinaryReaderIR::OnTagSymbol(Index index, uint32_t flags, std::string_view name, Index tag_index) { + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Tag{tag_index}}; + table.AddSymbol(sym); + static_cast(*module_->tags[tag_index]) = sym; if (name.empty()) { return Result::Ok; } @@ -1833,9 +1916,69 @@ Result BinaryReaderIR::OnTableSymbol(Index index, uint32_t flags, std::string_view name, Index table_index) { + assert(index == table.symbols().size()); + Symbol sym = {std::string(name), flags, Symbol::Table{table_index}}; + table.AddSymbol(sym); + static_cast(*module_->tables[table_index]) = sym; return SetTableName(table_index, name); } +Result BinaryReaderIR::OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) { + active_reloc_section->second.incoming_relocs.emplace_back(type, offset, index, + addend); + return Result::Ok; +} +void BinaryReaderIR::MakeQueue() { + assert(active_section != kInvalidIndex); + active_reloc_section = + reloc_queues.insert({active_section, RelocQueue{state->offset}}).first; +} + +Result BinaryReaderIR::BeginCodeSection(Offset size) { + MakeQueue(); + return Result::Ok; +} + +Result BinaryReaderIR::BeginDataSection(Offset size) { + MakeQueue(); + return Result::Ok; +} + +Result BinaryReaderIR::BeginGenericCustomSection(Offset size) { + return Result::Ok; +} + +Result BinaryReaderIR::BeginElemSection(Offset size) { + MakeQueue(); + return Result::Ok; +} + +Result BinaryReaderIR::OnRelocCount(Index count, Index section_index) { + active_reloc_section = reloc_queues.find(section_index); + assert(active_reloc_section != end(reloc_queues)); + return Result::Ok; +} + +Result BinaryReaderIR::EndRelocSection() { + active_reloc_section = {}; + return Result::Ok; +} + +Result BinaryReaderIR::BeginSection(Index section_index, + BinarySection section_type, + Offset size) { + active_section = section_index; + return Result::Ok; +} + +Result BinaryReaderIR::OnInitFunction(uint32_t prio, Index sym) { + module_->funcs[table.symbols()[sym].AsFunction().index]->priority = prio; + return Result::Ok; +} + Result BinaryReaderIR::OnGenericCustomSection(std::string_view name, const void* data, Offset size) { @@ -1848,6 +1991,114 @@ Result BinaryReaderIR::OnGenericCustomSection(std::string_view name, return Result::Ok; } +Result BinaryReaderIR::EndModule() { + size_t i = 0; + Index range_start = 0, data_segment = -1; + for (auto& datasym : data_symbols) { + if (datasym.segment != data_segment) { + if (data_segment != kInvalidIndex) { + module_->data_segments[data_segment]->symbol_range = {range_start, i}; + } + range_start = i; + data_segment = datasym.segment; + } + module_->data_symbols.push_back(datasym); + if (!datasym.name.empty()) { + module_->data_symbols[i].name = datasym.name; + module_->data_symbol_bindings.emplace(datasym.name, i); + } + ++i; + } + if (data_segment != kInvalidIndex) { + module_->data_segments[data_segment]->symbol_range = {range_start, i}; + } + + auto lookup_reloc = [this](Reloc r) { + auto maybe_name = [](auto& table, Index idx) { + auto sym = Overload{ + [](auto* x) { return x; }, + [](auto& x) { return &x; }, + }(table[idx]); + return sym->name.empty() ? Var{idx, {}} : Var{sym->name, {}}; + }; + + auto& sym = table.symbols()[r.index]; + switch (sym.type()) { + case SymbolType::Data: { + auto& data = sym.AsData(); + auto&& syms = module_->data_symbols; + auto res = + std::lower_bound(syms.begin(), syms.end(), + DataSym::MakeForSearch(data.index, data.offset)); + Index sym = res - syms.begin(); + return maybe_name(module_->data_symbols, sym); + } + // Sure would've been nice to have a feature that would allow one to write + // a piece of code and stamp it out multiple times, but with different + // types and stuff. Better yet, maybe use that to yield different data for + // different types. And call that feature templates, that'd be a great + // name for it! + case SymbolType::Section: { + auto idx = sym.AsSection().section; + return maybe_name(module_->customs, idx); + } + case SymbolType::Function: { + auto idx = sym.AsFunction().index; + return maybe_name(module_->funcs, idx); + } + case SymbolType::Global: { + auto idx = sym.AsGlobal().index; + return maybe_name(module_->globals, idx); + } + case SymbolType::Table: { + auto idx = sym.AsTable().index; + return maybe_name(module_->tables, idx); + } + case SymbolType::Tag: { + auto idx = sym.AsTag().index; + return maybe_name(module_->tags, idx); + } + default: + WABT_UNREACHABLE; + } + }; + + for (auto& [index, queue] : reloc_queues) { + bool applied_relocation = false; + for (auto reloc : queue.incoming_relocs) { + auto reloc_size = + kRelocDataTypeSize[int(kRelocDataType[int(reloc.type)])]; + // We pray that the relocation is always the last operand, and that the + // operand is an overlong leb already + auto reloc_addr = reloc.offset + reloc_size; + queue.traverse([&](auto& insns) { + auto insn = insns.find(reloc_addr); + if (insn != end(insns)) { + insn->second->reloc = {reloc.type, lookup_reloc(reloc), reloc.addend}; + assert(insn->second->reloc.type != RelocType::None); + applied_relocation = true; + } + }); + if (applied_relocation) + continue; + auto it = queue.data_segment_starts.lower_bound(reloc.offset); + if (it != end(queue.data_segment_starts)) { + auto end = it->first + it->second->data.size(); + auto abs_offset = reloc.offset + queue.start; + if (end >= abs_offset + reloc_size) { + it->second->relocs.push_back( + {abs_offset - it->first, + {reloc.type, lookup_reloc(reloc), reloc.addend}}); + applied_relocation = true; + } + } + assert(applied_relocation && "Unable to apply relocation"); + } + } + + return Result::Ok; +} + } // end anonymous namespace Result ReadBinaryIr(const char* filename, From 3c9615d1c60351283afd7c4c3e9a68d25ee15806 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 9 Oct 2025 01:54:29 +0300 Subject: [PATCH 04/59] Add support for relocations in the text writer --- src/wat-writer.cc | 161 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 4 deletions(-) diff --git a/src/wat-writer.cc b/src/wat-writer.cc index f19e3c3c86..0a7bf1d050 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -136,7 +137,7 @@ class WatWriter : ModuleContext { const Block& block, const char* text); void WriteEndBlock(); - void WriteConst(const Const& const_); + void WriteConst(const ConstExpr& const_); void WriteExpr(const Expr* expr); template void WriteLoadStoreExpr(const Expr* expr); @@ -149,6 +150,9 @@ class WatWriter : ModuleContext { const T& types, const std::vector& index_to_name, Index binding_index_offset = 0); + void WriteRelocAttrs(const SymbolCommon& sym); + void WriteReloc(const IrReloc& reloc, bool require_type = false); + void WriteDataImports(); void WriteBeginFunc(const Func& func); void WriteFunc(const Func& func); void WriteBeginGlobal(const Global& global); @@ -469,17 +473,20 @@ void WatWriter::WriteEndBlock() { WritePutsNewline(Opcode::End_Opcode.GetName()); } -void WatWriter::WriteConst(const Const& const_) { +void WatWriter::WriteConst(const ConstExpr& expr) { + const Const& const_ = expr.const_; switch (const_.type()) { case Type::I32: WritePutsSpace(Opcode::I32Const_Opcode.GetName()); Writef("%d", static_cast(const_.u32())); + WriteReloc(expr.reloc); WriteNewline(NO_FORCE_NEWLINE); break; case Type::I64: WritePutsSpace(Opcode::I64Const_Opcode.GetName()); Writef("%" PRId64, static_cast(const_.u64())); + WriteReloc(expr.reloc); WriteNewline(NO_FORCE_NEWLINE); break; @@ -539,6 +546,7 @@ void WatWriter::WriteMemoryLoadStoreExpr(const Expr* expr) { if (typed_expr->offset) { Writef("offset=%" PRIaddress, typed_expr->offset); } + WriteReloc(typed_expr->reloc); if (!typed_expr->opcode.IsNaturallyAligned(typed_expr->align)) { Writef("align=%" PRIaddress, typed_expr->align); } @@ -705,7 +713,7 @@ Result WatWriter::ExprVisitorDelegate::OnCompareExpr(CompareExpr* expr) { } Result WatWriter::ExprVisitorDelegate::OnConstExpr(ConstExpr* expr) { - writer_->WriteConst(expr->const_); + writer_->WriteConst(*expr); return Result::Ok; } @@ -1435,9 +1443,111 @@ void WatWriter::WriteTypeBindings(const char* prefix, } } +void WatWriter::WriteRelocAttrs(const SymbolCommon& sym) { + if (sym.binding() == SymbolBinding::Weak) + WritePutsSpace("weak"); + if (sym.binding() == SymbolBinding::Local) + WritePutsSpace("static"); + else { + if (sym.visibility() == SymbolVisibility::Hidden) + WritePutsSpace("hidden"); + } + if (sym.no_strip()) + WritePutsSpace("retain"); + if (sym.exported()) + WritePutsSpace("exported"); + if (!sym.name().empty()) { + WritePuts("name=", NextChar::None); + WriteQuotedString(sym.name(), NextChar::Space); + } +} + +void WatWriter::WriteReloc(const IrReloc& reloc, bool require_type) { + if (reloc.type == RelocType::None) + return; + WriteOpenSpace("@reloc"); + switch (kRelocSymbolType[int(reloc.type)]) { + case RelocKind::Function: + WritePutsSpace("func"); + break; + case RelocKind::Data: + WritePutsSpace("data"); + break; + case RelocKind::Global: + WritePutsSpace("global"); + break; + case RelocKind::FunctionTbl: + WritePutsSpace("functable"); + break; + case RelocKind::Table: + WritePutsSpace("table"); + break; + case RelocKind::Tag: + WritePutsSpace("tag"); + break; + case RelocKind::Type: + WritePutsSpace("type"); + break; + case RelocKind::Text: + WritePutsSpace("text"); + break; + case RelocKind::Section: + WritePutsSpace("section"); + break; + default: + WABT_UNREACHABLE; + } + + if (bool(kRelocModifiers[int(reloc.type)] & RelocModifiers::TLS)) + WritePutsSpace("tls"); + if (bool(kRelocModifiers[int(reloc.type)] & RelocModifiers::PIC)) + WritePutsSpace("pic"); + + if (require_type) + switch (kRelocDataType[int(reloc.type)]) { + case RelocDataType::I32: + WritePutsSpace("i32"); + break; + case RelocDataType::I64: + WritePutsSpace("i64"); + break; + case RelocDataType::LEB: + WritePutsSpace("leb"); + break; + case RelocDataType::SLEB: + WritePutsSpace("sleb"); + break; + case RelocDataType::LEB64: + WritePutsSpace("leb64"); + break; + case RelocDataType::SLEB64: + WritePutsSpace("sleb64"); + break; + } + WriteVar(reloc.symbol, NextChar::None); + if (reloc.addend) + Writef("+%u", reloc.addend); + WriteCloseSpace(); +} +void WatWriter::WriteDataImports() { + for (Index i = 0; i != module.num_data_imports; ++i) { + const DataSym& sym = module.data_symbols[i]; + WriteOpenSpace("@reloc.import.data"); + if (!sym.name.empty()) + WriteName(sym.name, NextChar::Space); + WriteRelocAttrs(sym); + WriteCloseNewline(); + } +} + void WatWriter::WriteBeginFunc(const Func& func) { WriteOpenSpace("func"); WriteNameOrIndex(func.name, func_index_, NextChar::Space); + WriteOpenSpace("@sym"); + WriteRelocAttrs(func); + if (func.priority.has_value()) + Writef("init=%u", *func.priority); + WriteCloseSpace(); WriteInlineExports(ExternalKind::Func, func_index_); WriteInlineImport(ExternalKind::Func, func_index_); if (func.decl.has_func_type) { @@ -1491,6 +1601,9 @@ void WatWriter::WriteFunc(const Func& func) { void WatWriter::WriteBeginGlobal(const Global& global) { WriteOpenSpace("global"); WriteNameOrIndex(global.name, global_index_, NextChar::Space); + WriteOpenSpace("@sym"); + WriteRelocAttrs(global); + WriteCloseSpace(); WriteInlineExports(ExternalKind::Global, global_index_); WriteInlineImport(ExternalKind::Global, global_index_); if (global.mutable_) { @@ -1512,6 +1625,9 @@ void WatWriter::WriteGlobal(const Global& global) { void WatWriter::WriteTag(const Tag& tag) { WriteOpenSpace("tag"); WriteNameOrIndex(tag.name, tag_index_, NextChar::Space); + WriteOpenSpace("@sym"); + WriteRelocAttrs(tag); + WriteCloseSpace(); WriteInlineExports(ExternalKind::Tag, tag_index_); WriteInlineImport(ExternalKind::Tag, tag_index_); if (tag.decl.has_func_type) { @@ -1540,6 +1656,9 @@ void WatWriter::WriteLimits(const Limits& limits) { void WatWriter::WriteTable(const Table& table) { WriteOpenSpace("table"); WriteNameOrIndex(table.name, table_index_, NextChar::Space); + WriteOpenSpace("@sym"); + WriteRelocAttrs(table); + WriteCloseSpace(); WriteInlineExports(ExternalKind::Table, table_index_); WriteInlineImport(ExternalKind::Table, table_index_); WriteLimits(table.elem_limits); @@ -1622,7 +1741,40 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { } WriteInitExpr(segment.offset); } - WriteQuotedData(segment.data.data(), segment.data.size()); + Offset offset = 0, next_sym = 0, next_reloc = 0; + constexpr auto end_offset = std::numeric_limits::max(); + Index curr_sym = segment.symbol_range.first; + auto curr_reloc = begin(segment.relocs); + for (;;) { + next_reloc = curr_reloc != end(segment.relocs) + ? curr_reloc->first + + kRelocDataTypeSize[int( + kRelocDataType[int(curr_reloc->second.type)])] + : end_offset; + next_sym = curr_sym != segment.symbol_range.second + ? module.data_symbols[curr_sym].offset + : end_offset; + if (offset == next_reloc) { + WriteReloc(curr_reloc->second, true); + ++curr_reloc; + continue; + } + if (offset == next_sym) { + WriteOpenSpace("@sym"); + WriteName(module.data_symbols[curr_sym].name, NextChar::Space); + WriteRelocAttrs(module.data_symbols[curr_sym]); + WriteCloseSpace(); + ++curr_sym; + continue; + } + if (offset == segment.data.size()) + // if we have no relocs/syms left, and there's also no data, leave + break; + Offset write_to = + std::min(segment.data.size(), std::min(next_reloc, next_sym)); + WriteQuotedData(segment.data.data() + offset, write_to - offset); + offset = write_to; + } WriteCloseNewline(); data_segment_index_++; } @@ -1745,6 +1897,7 @@ Result WatWriter::WriteModule() { } else { WriteName(module.name, NextChar::Newline); } + WriteDataImports(); for (const ModuleField& field : module.fields) { switch (field.type()) { case ModuleFieldType::Func: From 6d48401090da75881c9a1f902caa802a29673c12 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 9 Oct 2025 02:38:20 +0300 Subject: [PATCH 05/59] Add a check for token contents in ParseCodeMetadataAnnotation --- src/wast-parser.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index b452697bfa..1f52317012 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -2169,8 +2169,12 @@ Result WastParser::ParseInstr(ExprList* exprs) { Result WastParser::ParseCodeMetadataAnnotation(ExprList* exprs) { WABT_TRACE(ParseCodeMetadataAnnotation); Token tk = Consume(); + constexpr std::string_view pfx = "metadata.code."; std::string_view name = tk.text(); - name.remove_prefix(sizeof("metadata.code.") - 1); + assert(name.substr(0, size(pfx)) != pfx && + "ParseCodeMetadataAnnotation should only be called with appropriate " + "annotation"); + name.remove_prefix(size(pfx)); std::string data_text; CHECK_RESULT(ParseQuotedText(&data_text, false)); std::vector data(data_text.begin(), data_text.end()); From aa75317b8006fc6f265e9617e1e149bb33d1b57d Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 9 Oct 2025 08:36:29 +0300 Subject: [PATCH 06/59] Small adjustments to reloc printing --- src/wat-writer.cc | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 0a7bf1d050..f9a8ce5027 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -1455,7 +1455,7 @@ void WatWriter::WriteRelocAttrs(const SymbolCommon& sym) { if (sym.no_strip()) WritePutsSpace("retain"); if (sym.exported()) - WritePutsSpace("exported"); + WritePutsSpace("export"); if (!sym.name().empty()) { WritePuts("name=", NextChar::None); WriteQuotedString(sym.name(), NextChar::Space); @@ -1466,6 +1466,27 @@ void WatWriter::WriteReloc(const IrReloc& reloc, bool require_type) { if (reloc.type == RelocType::None) return; WriteOpenSpace("@reloc"); + if (require_type) + switch (kRelocDataType[int(reloc.type)]) { + case RelocDataType::I32: + WritePutsSpace("i32"); + break; + case RelocDataType::I64: + WritePutsSpace("i64"); + break; + case RelocDataType::LEB: + WritePutsSpace("leb"); + break; + case RelocDataType::SLEB: + WritePutsSpace("sleb"); + break; + case RelocDataType::LEB64: + WritePutsSpace("leb64"); + break; + case RelocDataType::SLEB64: + WritePutsSpace("sleb64"); + break; + } switch (kRelocSymbolType[int(reloc.type)]) { case RelocKind::Function: WritePutsSpace("func"); @@ -1503,27 +1524,6 @@ void WatWriter::WriteReloc(const IrReloc& reloc, bool require_type) { if (bool(kRelocModifiers[int(reloc.type)] & RelocModifiers::PIC)) WritePutsSpace("pic"); - if (require_type) - switch (kRelocDataType[int(reloc.type)]) { - case RelocDataType::I32: - WritePutsSpace("i32"); - break; - case RelocDataType::I64: - WritePutsSpace("i64"); - break; - case RelocDataType::LEB: - WritePutsSpace("leb"); - break; - case RelocDataType::SLEB: - WritePutsSpace("sleb"); - break; - case RelocDataType::LEB64: - WritePutsSpace("leb64"); - break; - case RelocDataType::SLEB64: - WritePutsSpace("sleb64"); - break; - } WriteVar(reloc.symbol, NextChar::None); if (reloc.addend) Writef("+%u", reloc.addend); @@ -1532,7 +1532,7 @@ void WatWriter::WriteReloc(const IrReloc& reloc, bool require_type) { void WatWriter::WriteDataImports() { for (Index i = 0; i != module.num_data_imports; ++i) { const DataSym& sym = module.data_symbols[i]; - WriteOpenSpace("@reloc.import.data"); + WriteOpenSpace("@sym.import.data"); if (!sym.name.empty()) WriteName(sym.name, NextChar::Space); WriteRelocAttrs(sym); From f15f4ce421b661407c7daf09c2b12481e503075f Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 9 Oct 2025 08:37:10 +0300 Subject: [PATCH 07/59] Make fields of SymbolCommon public --- include/wabt/ir.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wabt/ir.h b/include/wabt/ir.h index ccaaf7c02a..0c897e8490 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -231,9 +231,9 @@ struct IrReloc { }; class SymbolCommon { +public: std::string name_; uint32_t flags_; -public: SymbolCommon(uint32_t flags = 0, std::string name = "") : name_(name), flags_(flags) {} const std::string& name() const { return name_; } From 0475fb1d0229302298d58094415c6b2b9c3d4ee2 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 9 Oct 2025 08:39:37 +0300 Subject: [PATCH 08/59] Add support for relocations in wast-parser --- include/wabt/wast-parser.h | 19 ++ src/wast-parser.cc | 395 ++++++++++++++++++++++++++++++++++++- 2 files changed, 406 insertions(+), 8 deletions(-) diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 7a60af23b5..78743f354d 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -64,6 +64,11 @@ class WastParser { Var var; }; + struct DatasymAux { + Var name; + Address size; + }; + typedef std::vector ReferenceVars; struct ResolveTypes { @@ -196,7 +201,13 @@ class WastParser { Result ParseCustomSectionAnnotation(Module*); bool PeekIsCustom(); + bool PeekIsDataImport(); + Result ParseSymAfterPar(SymbolCommon*, + bool in_import, + DatasymAux* dat_sym = 0); + Result ParseSymOpt(SymbolCommon *, bool in_import, DatasymAux *dat_sym = 0); + Result ParseDataImport(Module* module); Result ParseExportDesc(Export*); Result ParseInlineExports(ModuleFieldList*, ExternalKind); Result ParseInlineImport(Import*); @@ -216,6 +227,14 @@ class WastParser { Result ParseInstrList(ExprList*); Result ParseTerminatingInstrList(ExprList*); Result ParseInstr(ExprList*); + Result ParseRejectReloc(); + Result ParseUnwindReloc(int curr_indent); + Result ParseRelocAfterType(IrReloc*, RelocDataType type); + Result ParseRelocModifiers(RelocModifiers*); + Result ParseRelocKind(RelocKind*); + Result ParseRelocDataType(RelocDataType*); + Result ParseReloc(IrReloc*); + Result ParseReloc(IrReloc*, RelocDataType type); Result ParseCodeMetadataAnnotation(ExprList*); Result ParsePlainInstr(std::unique_ptr*); Result ParseF32(Const*, ConstType type); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 1f52317012..e389fa9067 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -587,7 +587,8 @@ TokenType WastParser::Peek(size_t n) { } if ((options_->features.code_metadata_enabled() && cur.text().find("metadata.code.") == 0) || - cur.text() == "custom") { + cur.text() == "custom" || cur.text() == "reloc" || + cur.text() == "sym.import.data" || cur.text() == "sym") { tokens_.push_back(cur); continue; } @@ -1297,6 +1298,149 @@ bool WastParser::PeekIsCustom() { return options_->features.annotations_enabled() && IsLparAnn(PeekPair()) && tokens_.front().text() == "custom"; } +bool WastParser::PeekIsDataImport() { + // If IsLparAnn succeeds, tokens_.front() must have text, as it is an LparAnn + // token. + return options_->features.annotations_enabled() && IsLparAnn(PeekPair()) && + tokens_.front().text() == "sym.import.data"; +} + +Result WastParser::ParseSymAfterPar(SymbolCommon* sym, + bool in_import, + DatasymAux* data) { + const auto seen = [x = false, this](const char* property) mutable { + if (!x) { + x = true; + return Result::Ok; + } + Error(GetLocation(), "Symbol's %s already seen", property); + return Result::Error; + }; + if (data) { + ParseVarOpt(&data->name, data->name); + } + + auto seen_name = seen; + auto seen_size = seen; + auto seen_visibility = seen; + auto seen_binding = seen; + auto seen_export = seen; + auto seen_retain = seen; + + for (;;) { + Token tok = GetToken(); + TokenType tt = tok.token_type(); + if (tt == TokenType::Rpar) { + Consume(); + return Result::Ok; + } + if (tt == TokenType::Reserved && tok.text() == "static") { + CHECK_RESULT(seen_binding("binding")); + if (in_import) { + Error(GetLocation(), "static symbol cannot be an import"); + return Result::Error; + } + Consume(); + sym->flags_ |= uint32_t(SymbolBinding::Local); + continue; + } + if (tt == TokenType::Reserved && tok.text() == "weak") { + CHECK_RESULT(seen_binding("binding")); + Consume(); + sym->flags_ |= uint32_t(SymbolBinding::Weak); + continue; + } + if (tt == TokenType::Reserved && tok.text() == "retain") { + CHECK_RESULT(seen_retain("retain")); + Consume(); + sym->flags_ |= WABT_SYMBOL_FLAG_NO_STRIP; + continue; + } + constexpr std::string_view name_pfx = "name="; + if (tt == TokenType::Reserved && + tok.text().substr(0, size(name_pfx)) == name_pfx) { + CHECK_RESULT(seen_name("name")); + Consume(); + RemoveEscapes(tok.text().substr(size(name_pfx)), + std::back_inserter(sym->name_)); + continue; + } + constexpr std::string_view size_pfx = "size="; + if (tt == TokenType::Reserved && + tok.text().substr(0, size(size_pfx)) == size_pfx) { + CHECK_RESULT(seen_size("size")); + if (!data) { + Error(GetLocation(), "Can only specify size on data symbols"); + return Result::Error; + } + Consume(); + CHECK_RESULT(ParseUint64(tok.text().substr(size(size_pfx)), &data->size)); + continue; + } + if (tt == TokenType::Reserved && tok.text() == "hidden") { + CHECK_RESULT(seen_visibility("visibility")); + Consume(); + sym->flags_ |= uint32_t(SymbolVisibility::Hidden); + continue; + } + if (tt == TokenType::Export) { + CHECK_RESULT(seen_export("export")); + if (!data) { + Error(GetLocation(), "Can only export data via attribute"); + return Result::Error; + } + Consume(); + sym->flags_ |= WABT_SYMBOL_FLAG_EXPORTED; + continue; + } + Error(GetLocation(), "Expected symbol attribute or ')'"); + ParseUnwindReloc(1); + return Result::Error; + } +} + +Result WastParser::ParseSymOpt(SymbolCommon* sym, + bool in_import, + DatasymAux* dat_sym) { + sym->flags_ |= in_import ? WABT_SYMBOL_FLAG_UNDEFINED : 0; + if (!IsLparAnn(PeekPair())) + return Result::Ok; + Token tok = GetToken(); + if (tok.text() != "sym") + return Result::Ok; + Consume(); + return ParseSymAfterPar(sym, in_import, dat_sym); +} + +Result WastParser::ParseDataImport(Module* module) { + DataSym sym; + DatasymAux aux; + sym.flags_ |= WABT_SYMBOL_FLAG_UNDEFINED; + if (!IsLparAnn(PeekPair())) + return Result::Ok; + Token tok = GetToken(); + if (tok.text() != "sym.import.data") + return Result::Ok; + Consume(); + CHECK_RESULT(ParseSymAfterPar(&sym, true, &aux)); + + if (!module->data_symbols.empty()) { + if (module->data_symbols.back().segment != kInvalidIndex) { + Error(GetLocation(), "data imports must occur before definitions"); + return Result::Error; + } + } + ++module->num_data_imports; + sym.segment = kInvalidIndex; + sym.offset = module->num_data_imports; + if (aux.name.is_name()) { + module->data_symbol_bindings.insert( + {aux.name.name(), {aux.name.loc, module->num_data_imports}}); + sym.name = aux.name.name(); + } + module->data_symbols.push_back(sym); + return Result::Ok; +} Result WastParser::ResolveRefTypes(const Module& module, TypeVector* types, @@ -1358,11 +1502,15 @@ Result WastParser::ParseModuleFieldList(Module* module) { resolve_types_.clear(); resolve_funcs_.clear(); - while (IsModuleField(PeekPair()) || PeekIsCustom()) { + while (IsModuleField(PeekPair()) || PeekIsCustom() || PeekIsDataImport()) { if (PeekIsCustom()) { CHECK_RESULT(ParseCustomSectionAnnotation(module)); continue; } + if (PeekIsDataImport()) { + CHECK_RESULT(ParseDataImport(module)); + continue; + } if (Failed(ParseModuleField(module))) { CHECK_RESULT(Synchronize(IsModuleField)); } @@ -1433,7 +1581,51 @@ Result WastParser::ParseDataModuleField(Module* module) { field->data_segment.kind = SegmentKind::Passive; } - ParseTextListOpt(&field->data_segment.data); + field->data_segment.symbol_range.first = module->data_symbols.size(); + + for (;;) { + Token tok = GetToken(); + if (tok.token_type() == TokenType::Rpar) + break; + if (tok.token_type() == TokenType::LparAnn) { + size_t offset = field->data_segment.data.size(); + if (tok.text() == "reloc") { + IrReloc r; + ParseReloc(&r); + size_t reloc_size = + kRelocDataTypeSize[int(kRelocDataType[int(r.type)])]; + field->data_segment.relocs.push_back({offset - reloc_size, r}); + continue; + } + if (tok.text() == "sym") { + DataSym sym; + Index sym_idx = module->data_symbols.size(); + DatasymAux aux = {Var{sym_idx, GetLocation()}, 0}; + ParseSymOpt(&sym, false, &aux); + sym.segment = module->data_segments.size(); + sym.offset = offset; + sym.size = aux.size; + if (aux.name.is_name()) { + module->data_symbol_bindings.insert( + {aux.name.name(), {aux.name.loc, sym_idx}}); + sym.name = aux.name.name(); + } + module->data_symbols.push_back(sym); + continue; + } + } + if (PeekMatch(TokenType::Text)) { + RemoveEscapes(Consume().text(), + std::back_inserter(field->data_segment.data)); + continue; + } + ErrorExpected({"relocation", "symbol definition", "a quoted string"}, + "\"foo\""); + return Result::Error; + } + + field->data_segment.symbol_range.second = module->data_symbols.size(); + EXPECT(Rpar); module->AppendField(std::move(field)); return Result::Ok; @@ -1572,6 +1764,7 @@ Result WastParser::ParseFuncModuleField(Module* module) { CheckImportOrdering(module); auto import = std::make_unique(name); Func& func = import->func; + CHECK_RESULT(ParseSymOpt(&func, true)); CHECK_RESULT(ParseInlineImport(import.get())); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); @@ -1583,6 +1776,7 @@ Result WastParser::ParseFuncModuleField(Module* module) { auto field = std::make_unique(loc, name); Func& func = field->func; func.loc = GetLocation(); + CHECK_RESULT(ParseSymOpt(&func, false)); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); @@ -1743,6 +1937,7 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->func, true)); CHECK_RESULT(ParseTypeUseOpt(&import->func.decl)); CHECK_RESULT( ParseFuncSignature(&import->func.decl.sig, &import->func.bindings)); @@ -1756,6 +1951,7 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->table, true)); CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); CHECK_RESULT(ParseLimits(&import->table.elem_limits)); CHECK_RESULT(ParseRefType(&import->table.elem_type)); @@ -1781,6 +1977,7 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->global, true)); CHECK_RESULT(ParseGlobalType(&import->global)); EXPECT(Rpar); field = std::make_unique(std::move(import), loc); @@ -1791,6 +1988,7 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->tag, true)); CHECK_RESULT(ParseTypeUseOpt(&import->tag.decl)); CHECK_RESULT(ParseUnboundFuncSignature(&import->tag.decl.sig)); EXPECT(Rpar); @@ -1905,6 +2103,7 @@ Result WastParser::ParseTableModuleField(Module* module) { if (PeekMatchLpar(TokenType::Import)) { CheckImportOrdering(module); auto import = std::make_unique(name); + CHECK_RESULT(ParseSymOpt(&import->table, true)); CHECK_RESULT(ParseInlineImport(import.get())); CHECK_RESULT(ParseLimitsIndex(&import->table.elem_limits)); CHECK_RESULT(ParseLimits(&import->table.elem_limits)); @@ -1915,6 +2114,7 @@ Result WastParser::ParseTableModuleField(Module* module) { } else { auto field = std::make_unique(loc, name); auto& table = field->table; + CHECK_RESULT(ParseSymOpt(&table, false)); CHECK_RESULT(ParseLimitsIndex(&table.elem_limits)); if (PeekMatch(TokenType::ValueType)) { Type elem_type; @@ -2124,9 +2324,17 @@ Result WastParser::ParseInstrList(ExprList* exprs) { CHECK_RESULT(Synchronize(IsInstr)); } } else if (IsLparAnn(pair)) { - if (Succeeded(ParseCodeMetadataAnnotation(&new_exprs))) { - exprs->splice(exprs->end(), new_exprs); + Token tk = GetToken(); + constexpr std::string_view pfx = "metadata.code."; + std::string_view name = tk.text(); + if (name.substr(0, size(pfx)) == pfx) { + if (Succeeded(ParseCodeMetadataAnnotation(&new_exprs))) { + exprs->splice(exprs->end(), new_exprs); + } else { + CHECK_RESULT(Synchronize(IsLparAnn)); + } } else { + ErrorExpected({"an annotation", "an instruction"}); CHECK_RESULT(Synchronize(IsLparAnn)); } } else { @@ -2166,6 +2374,160 @@ Result WastParser::ParseInstr(ExprList* exprs) { } } +Result WastParser::ParseRejectReloc() { + Token tok = GetToken(); + if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { + Error(GetLocation(), "Operand is not relocatable"); + Consume(); + return ParseUnwindReloc(1); + } + return Result::Ok; +} +Result WastParser::ParseUnwindReloc(int curr_indent) { + while (curr_indent) { + if (PeekMatch(TokenType::Lpar) || PeekMatch(TokenType::LparAnn)) + ++curr_indent; + if (PeekMatch(TokenType::Rpar)) + --curr_indent; + Consume(); + } + return Result::Ok; +} +Result WastParser::ParseRelocAfterType(IrReloc* reloc, RelocDataType type) { + RelocKind kind; + CHECK_RESULT(ParseRelocKind(&kind)); + RelocModifiers mod; + CHECK_RESULT(ParseRelocModifiers(&mod)); + RelocType reloc_type = RecognizeReloc(kind, type, mod); + if (reloc_type == RelocType::None) { + Error(GetLocation(), "Invalid relocation"); + return ParseUnwindReloc(1); + } + Var target; + ParseVar(&target); + *reloc = {reloc_type, target}; + CHECK_RESULT(Expect(TokenType::Rpar)); + return Result::Ok; +} +Result WastParser::ParseRelocModifiers(RelocModifiers* mod) { + *mod = RelocModifiers::None; + Token tok = GetToken(); + if (tok.token_type() == TokenType::Reserved) { + if (tok.text() == "tls") + *mod = RelocModifiers::TLS; + else if (tok.text() == "pic") + *mod = RelocModifiers::PIC; + } + if (*mod != RelocModifiers::None) + Consume(); + return Result::Ok; +} + +Result WastParser::ParseRelocKind(RelocKind* kind) { + bool did_reloc = false; + Token tok = GetToken(); + TokenType tt = tok.token_type(); + if (tt == TokenType::Global) { + *kind = RelocKind::Global; + did_reloc = true; + } + if (tt == TokenType::Function) { + *kind = RelocKind::Function; + did_reloc = true; + } + if (tt == TokenType::Table) { + *kind = RelocKind::Table; + did_reloc = true; + } + if (tt == TokenType::Tag) { + *kind = RelocKind::Tag; + did_reloc = true; + } + if (tt == TokenType::Data) { + *kind = RelocKind::Data; + did_reloc = true; + } + if (tt == TokenType::Type) { + *kind = RelocKind::Type; + did_reloc = true; + } + if (tt == TokenType::Reserved) { + if (tok.text() == "text") { + *kind = RelocKind::Text; + did_reloc = true; + } + if (tok.text() == "functable") { + *kind = RelocKind::FunctionTbl; + did_reloc = true; + } + if (tok.text() == "custom") { + *kind = RelocKind::Section; + did_reloc = true; + } + } + if (did_reloc) { + Consume(); + return Result::Ok; + } else + return Result::Error; +} +Result WastParser::ParseRelocDataType(RelocDataType* type) { + bool did_reloc = false; + Token tok = GetToken(); + TokenType tt = tok.token_type(); + if (tt == TokenType::ValueType) { + if (tok.type() == Type::I32) { + *type = RelocDataType::I32; + did_reloc = true; + } + if (tok.type() == Type::I64) { + *type = RelocDataType::I64; + did_reloc = true; + } + } + if (tt == TokenType::Reserved) { + if (tok.text() == "leb") { + *type = RelocDataType::LEB; + did_reloc = true; + } + if (tok.text() == "sleb") { + *type = RelocDataType::SLEB; + did_reloc = true; + } + if (tok.text() == "leb64") { + *type = RelocDataType::LEB64; + did_reloc = true; + } + if (tok.text() == "sleb64") { + *type = RelocDataType::SLEB64; + did_reloc = true; + } + } + if (did_reloc) { + Consume(); + return Result::Ok; + } else + return Result::Error; +} +Result WastParser::ParseReloc(IrReloc* reloc) { + Token tok = GetToken(); + if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { + Consume(); + RelocDataType t; + CHECK_RESULT(ParseRelocDataType(&t)); + return ParseRelocAfterType(reloc, t); + } + return Result::Ok; +} +Result WastParser::ParseReloc(IrReloc* reloc, RelocDataType type) { + Token tok = GetToken(); + if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { + Consume(); + return ParseRelocAfterType(reloc, type); + } + return Result::Ok; +} + Result WastParser::ParseCodeMetadataAnnotation(ExprList* exprs) { WABT_TRACE(ParseCodeMetadataAnnotation); Token tk = Consume(); @@ -2224,14 +2586,24 @@ template Result WastParser::ParseLoadStoreInstr(Location loc, Token token, std::unique_ptr* out_expr) { + constexpr bool relocatable = + std::is_same_v || std::is_same_v; Opcode opcode = token.opcode(); Var memidx; Address offset; Address align; + IrReloc reloc; CHECK_RESULT(ParseMemidx(loc, &memidx)); ParseOffsetOpt(&offset); + if constexpr (relocatable) { + CHECK_RESULT(ParseReloc(&reloc, RelocDataType::LEB)); + } ParseAlignOpt(&align); - out_expr->reset(new T(opcode, memidx, align, offset, loc)); + T* expr = new T(opcode, memidx, align, offset, loc); + if constexpr (relocatable) { + expr->reloc = reloc; + } + out_expr->reset(expr); return Result::Ok; } @@ -2451,7 +2823,14 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { case TokenType::Const: { Const const_; CHECK_RESULT(ParseConst(&const_, ConstType::Normal)); - out_expr->reset(new ConstExpr(const_, loc)); + auto expr = new ConstExpr(const_, loc); + out_expr->reset(expr); + if (const_.type() == Type::I64) + CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::I64)); + else if (const_.type() == Type::I32) + CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::I32)); + else + CHECK_RESULT(ParseRejectReloc()); break; } @@ -3817,7 +4196,7 @@ Result WastParser::ParseScriptModule( auto tsm = std::make_unique(); tsm->module.name = name; tsm->module.loc = loc; - if (IsModuleField(PeekPair()) || PeekIsCustom()) { + if (IsModuleField(PeekPair()) || PeekIsCustom() || PeekIsDataImport()) { CHECK_RESULT(ParseModuleFieldList(&tsm->module)); } else if (!PeekMatch(TokenType::Rpar)) { ConsumeIfLpar(); From f1b58e9080ca9570ee9c9d06aad67df9f8907a79 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 10:39:57 +0300 Subject: [PATCH 09/59] Add size output for data symbols --- src/wat-writer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wat-writer.cc b/src/wat-writer.cc index f9a8ce5027..315856ef47 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -1762,6 +1762,7 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { if (offset == next_sym) { WriteOpenSpace("@sym"); WriteName(module.data_symbols[curr_sym].name, NextChar::Space); + Writef("size=%" PRIaddress, module.data_symbols[curr_sym].size); WriteRelocAttrs(module.data_symbols[curr_sym]); WriteCloseSpace(); ++curr_sym; From f3c53e933426a6cdfa787742c39c5ac0f8d17351 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 10:43:26 +0300 Subject: [PATCH 10/59] Remove 'export' in symbols as it doesn't make sense for data symbols --- src/wast-parser.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index e389fa9067..bcb419bf3f 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1324,7 +1324,6 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, auto seen_size = seen; auto seen_visibility = seen; auto seen_binding = seen; - auto seen_export = seen; auto seen_retain = seen; for (;;) { @@ -1383,16 +1382,6 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, sym->flags_ |= uint32_t(SymbolVisibility::Hidden); continue; } - if (tt == TokenType::Export) { - CHECK_RESULT(seen_export("export")); - if (!data) { - Error(GetLocation(), "Can only export data via attribute"); - return Result::Error; - } - Consume(); - sym->flags_ |= WABT_SYMBOL_FLAG_EXPORTED; - continue; - } Error(GetLocation(), "Expected symbol attribute or ')'"); ParseUnwindReloc(1); return Result::Error; From 88015ed5d6321ca467c228c8753947747c0db836 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 21:23:54 +0300 Subject: [PATCH 11/59] Clean up the implementation for symbol parser --- include/wabt/wast-parser.h | 12 +++ src/wast-parser.cc | 152 +++++++++++++++++++++---------------- 2 files changed, 99 insertions(+), 65 deletions(-) diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 78743f354d..354b1b72ca 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -88,6 +88,9 @@ class WastParser { ReferenceVars vars; }; + static std::optional TryTrimPfx(std::string_view string, + std::string_view prefix); + void ErrorUnlessOpcodeEnabled(const Token&); // Print an error message listing the expected tokens, as well as an example @@ -137,6 +140,15 @@ class WastParser { // token is equal to the parameter. If so, then the token is consumed. bool MatchLpar(TokenType); + // Returns true if the next token's type is equal to the parameter, and if + // token's text matches parameter. If so, then the token is consumed. + bool MatchText(TokenType, std::string_view); + + // Returns true if the next token's type is equal to the parameter, and if + // token's text starts with parameter. If so, then the token is consumed and + // the rest of token's text is returned. + std::optional MatchTextPrefix(TokenType, std::string_view); + // Like Match(), but prints an error message if the token doesn't match, and // returns Result::Error. Result Expect(TokenType); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index bcb419bf3f..87d56a4890 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -658,6 +658,26 @@ bool WastParser::MatchLpar(TokenType type) { return false; } +bool WastParser::MatchText(TokenType type, std::string_view text) { + auto tok = GetToken(); + if (tok.token_type() == type && tok.text() == text) { + Consume(); + return true; + } + return false; +} +std::optional WastParser::MatchTextPrefix( + TokenType type, + std::string_view prefix) { + auto tok = GetToken(); + if (tok.token_type() == type) + if (auto rest = TryTrimPfx(tok.text(), prefix)) { + Consume(); + return rest; + } + return std::nullopt; +} + Result WastParser::Expect(TokenType type) { if (!Match(type)) { Token token = Consume(); @@ -694,6 +714,14 @@ Result WastParser::Synchronize(SynchronizeFunc func) { return Result::Error; } +std::optional WastParser::TryTrimPfx( + std::string_view string, + std::string_view prefix) { + if (string.substr(0, prefix.size()) == prefix) + return string.substr(prefix.size()); + return std::nullopt; +} + void WastParser::ErrorUnlessOpcodeEnabled(const Token& token) { Opcode opcode = token.opcode(); if (!opcode.IsEnabled(options_->features)) { @@ -1308,83 +1336,77 @@ bool WastParser::PeekIsDataImport() { Result WastParser::ParseSymAfterPar(SymbolCommon* sym, bool in_import, DatasymAux* data) { - const auto seen = [x = false, this](const char* property) mutable { - if (!x) { - x = true; - return Result::Ok; + using OnceProperty = std::pair>; + Location last_tok_loc; + + OnceProperty visibility{"visibility", {}}; + OnceProperty binding{"linkage", {}}; + OnceProperty retain{"retain", {}}; + OnceProperty name{"name", {}}; + OnceProperty size{"size", {}}; + + auto check_once = [this, &last_tok_loc](OnceProperty& var) { + if (!var.second) + var.second = last_tok_loc; + else { + Error(last_tok_loc, "Symbol's " PRIstringview " already specified", + WABT_PRINTF_STRING_VIEW_ARG(var.first)); + Error(*var.second, "See previous definition"); } - Error(GetLocation(), "Symbol's %s already seen", property); - return Result::Error; }; + auto check_seen = [this, &last_tok_loc](OnceProperty& var) { + if (!var.second) + Error(last_tok_loc, "Must specify " PRIstringview " for this symbol", + WABT_PRINTF_STRING_VIEW_ARG(var.first)); + }; + auto check_unseen = [this, &last_tok_loc](OnceProperty& var) { + if (var.second) + Error(*var.second, "Cannot specify " PRIstringview " for this symbol", + WABT_PRINTF_STRING_VIEW_ARG(var.first)); + }; + + auto validate = [&] { + if (in_import && (sym->flags_ & uint32_t(SymbolBinding::Local))) { + Error(*visibility.second, "static symbol cannot be an import"); + } + if (data) { + if (!in_import) + check_seen(size); + check_seen(name); + } else { + check_unseen(size); + } + }; + if (data) { ParseVarOpt(&data->name, data->name); } - - auto seen_name = seen; - auto seen_size = seen; - auto seen_visibility = seen; - auto seen_binding = seen; - auto seen_retain = seen; - for (;;) { - Token tok = GetToken(); - TokenType tt = tok.token_type(); - if (tt == TokenType::Rpar) { - Consume(); + last_tok_loc = GetLocation(); + if (Match(TokenType::Rpar)) { + validate(); return Result::Ok; - } - if (tt == TokenType::Reserved && tok.text() == "static") { - CHECK_RESULT(seen_binding("binding")); - if (in_import) { - Error(GetLocation(), "static symbol cannot be an import"); - return Result::Error; - } - Consume(); + } else if (MatchText(TokenType::Reserved, "static")) { + check_once(binding); sym->flags_ |= uint32_t(SymbolBinding::Local); - continue; - } - if (tt == TokenType::Reserved && tok.text() == "weak") { - CHECK_RESULT(seen_binding("binding")); - Consume(); + } else if (MatchText(TokenType::Reserved, "weak")) { + check_once(binding); sym->flags_ |= uint32_t(SymbolBinding::Weak); - continue; - } - if (tt == TokenType::Reserved && tok.text() == "retain") { - CHECK_RESULT(seen_retain("retain")); - Consume(); + } else if (MatchText(TokenType::Reserved, "retain")) { + check_once(retain); sym->flags_ |= WABT_SYMBOL_FLAG_NO_STRIP; - continue; - } - constexpr std::string_view name_pfx = "name="; - if (tt == TokenType::Reserved && - tok.text().substr(0, size(name_pfx)) == name_pfx) { - CHECK_RESULT(seen_name("name")); - Consume(); - RemoveEscapes(tok.text().substr(size(name_pfx)), - std::back_inserter(sym->name_)); - continue; - } - constexpr std::string_view size_pfx = "size="; - if (tt == TokenType::Reserved && - tok.text().substr(0, size(size_pfx)) == size_pfx) { - CHECK_RESULT(seen_size("size")); - if (!data) { - Error(GetLocation(), "Can only specify size on data symbols"); - return Result::Error; - } - Consume(); - CHECK_RESULT(ParseUint64(tok.text().substr(size(size_pfx)), &data->size)); - continue; - } - if (tt == TokenType::Reserved && tok.text() == "hidden") { - CHECK_RESULT(seen_visibility("visibility")); - Consume(); + } else if (auto sym_name = MatchTextPrefix(TokenType::Reserved, "name=")) { + check_once(name); + RemoveEscapes(*sym_name, std::back_inserter(sym->name_)); + } else if (auto sym_size = MatchTextPrefix(TokenType::Reserved, "size=")) { + check_once(size); + CHECK_RESULT(ParseUint64(*sym_size, &data->size)); + } else if (MatchText(TokenType::Reserved, "hidden")) { + check_once(visibility); sym->flags_ |= uint32_t(SymbolVisibility::Hidden); - continue; + } else { + ErrorExpected({"symbol attribute", "')'"}); } - Error(GetLocation(), "Expected symbol attribute or ')'"); - ParseUnwindReloc(1); - return Result::Error; } } From 391e05666481cf5e27c7ca5ec35f77b113d27fbb Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 21:24:50 +0300 Subject: [PATCH 12/59] Fix binding generation with invalid indices --- src/wast-parser.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 87d56a4890..b8dbb5515d 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1444,9 +1444,10 @@ Result WastParser::ParseDataImport(Module* module) { ++module->num_data_imports; sym.segment = kInvalidIndex; sym.offset = module->num_data_imports; + Index sym_idx = module->data_symbols.size(); if (aux.name.is_name()) { module->data_symbol_bindings.insert( - {aux.name.name(), {aux.name.loc, module->num_data_imports}}); + {aux.name.name(), {aux.name.loc, sym_idx}}); sym.name = aux.name.name(); } module->data_symbols.push_back(sym); From ff37487dd49977ef42f2254827c59b2ed6353492 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 21:25:39 +0300 Subject: [PATCH 13/59] Add export symbol flags --- src/wast-parser.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index b8dbb5515d..7035664b95 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1543,6 +1543,31 @@ Result WastParser::ParseModuleFieldList(Module* module) { CHECK_RESULT(result); CHECK_RESULT(ResolveFuncTypes(module, errors_)); CHECK_RESULT(ResolveNamesModule(module, errors_)); + for (auto exp : module->exports) { + auto patch = [&](auto& fields, const BindingHash& bindings) { + Index i = bindings.FindIndex(exp->name); + if (i == kInvalidIndex) + return; + fields[i]->flags_ |= WABT_SYMBOL_FLAG_EXPORTED; + }; + switch (exp->kind) { + case ExternalKind::Func: + patch(module->funcs, module->func_bindings); + break; + case ExternalKind::Table: + patch(module->tables, module->table_bindings); + break; + case ExternalKind::Global: + patch(module->globals, module->global_bindings); + break; + case ExternalKind::Tag: + patch(module->tags, module->tag_bindings); + break; + case ExternalKind::Memory: + // Memories are not relocatable + break; + } + } return Result::Ok; } From 5e31c0d87f2bc07993f2c02542c3a6c9338bfa6e Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 21:26:08 +0300 Subject: [PATCH 14/59] Add name resolution for relocations --- src/resolve-names.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/resolve-names.cc b/src/resolve-names.cc index 67fc44e923..38c16aef65 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -81,6 +81,7 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnRethrowExpr(RethrowExpr*) override; Result OnSimdLoadLaneExpr(SimdLoadLaneExpr*) override; Result OnSimdStoreLaneExpr(SimdStoreLaneExpr*) override; + Result OnConstExpr(ConstExpr*) override; private: void PrintError(const Location* loc, const char* fmt, ...); @@ -100,7 +101,9 @@ class NameResolver : public ExprVisitor::DelegateNop { void ResolveTagVar(Var* var); void ResolveDataSegmentVar(Var* var); void ResolveElemSegmentVar(Var* var); + void ResolveDataVar(Var* var); void ResolveLocalVar(Var* var); + void ResolveReloc(IrReloc* reloc); void ResolveBlockDeclarationVar(BlockDeclaration* decl); void VisitFunc(Func* func); void VisitExport(Export* export_); @@ -219,6 +222,9 @@ void NameResolver::ResolveDataSegmentVar(Var* var) { void NameResolver::ResolveElemSegmentVar(Var* var) { ResolveVar(¤t_module_->elem_segment_bindings, var, "elem segment"); } +void NameResolver::ResolveDataVar(Var* var) { + ResolveVar(¤t_module_->data_symbol_bindings, var, "data symbol"); +} void NameResolver::ResolveLocalVar(Var* var) { if (var->is_name()) { @@ -236,6 +242,35 @@ void NameResolver::ResolveLocalVar(Var* var) { var->set_index(index); } } +void NameResolver::ResolveReloc(IrReloc* reloc) { + if (reloc->type == RelocType::None) + return; + switch (kRelocSymbolType[int(reloc->type)]) { + case RelocKind::Text: + case RelocKind::Function: + case RelocKind::FunctionTbl: + ResolveFuncVar(&reloc->symbol); + break; + case RelocKind::Data: + ResolveDataVar(&reloc->symbol); + break; + case RelocKind::Type: + ResolveFuncTypeVar(&reloc->symbol); + break; + case RelocKind::Table: + ResolveTableVar(&reloc->symbol); + break; + case RelocKind::Global: + ResolveGlobalVar(&reloc->symbol); + break; + case RelocKind::Tag: + ResolveTagVar(&reloc->symbol); + break; + case RelocKind::Section: + // Do nothing for now + break; + } +} void NameResolver::ResolveBlockDeclarationVar(BlockDeclaration* decl) { if (decl->has_func_type) { @@ -331,6 +366,7 @@ Result NameResolver::EndIfExpr(IfExpr* expr) { Result NameResolver::OnLoadExpr(LoadExpr* expr) { ResolveMemoryVar(&expr->memidx); + ResolveReloc(&expr->reloc); return Result::Ok; } @@ -430,6 +466,7 @@ Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) { Result NameResolver::OnStoreExpr(StoreExpr* expr) { ResolveMemoryVar(&expr->memidx); + ResolveReloc(&expr->reloc); return Result::Ok; } @@ -500,6 +537,10 @@ Result NameResolver::OnSimdStoreLaneExpr(SimdStoreLaneExpr* expr) { ResolveMemoryVar(&expr->memidx); return Result::Ok; } +Result NameResolver::OnConstExpr(ConstExpr* expr) { + ResolveReloc(&expr->reloc); + return Result::Ok; +} void NameResolver::VisitFunc(Func* func) { current_func_ = func; From 4bcc9590f5964004f3e86f4e67573b060366ac9d Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Fri, 10 Oct 2025 21:36:46 +0300 Subject: [PATCH 15/59] Add name resolution for relocations in data segments --- src/resolve-names.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/resolve-names.cc b/src/resolve-names.cc index 38c16aef65..5ac824b4ce 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -607,6 +607,8 @@ void NameResolver::VisitElemSegment(ElemSegment* segment) { void NameResolver::VisitDataSegment(DataSegment* segment) { ResolveMemoryVar(&segment->memory_var); visitor_.VisitExprList(segment->offset); + for (auto& [offset, reloc] : segment->relocs) + ResolveReloc(&reloc); } Result NameResolver::VisitModule(Module* module) { From 40046a0fab6b99d6c9029d9c580dfee6269a91c4 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:56:23 +0300 Subject: [PATCH 16/59] Fix parser setting invalid flags and types --- src/wast-parser.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 7035664b95..7fc23b7832 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1398,6 +1398,7 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, } else if (auto sym_name = MatchTextPrefix(TokenType::Reserved, "name=")) { check_once(name); RemoveEscapes(*sym_name, std::back_inserter(sym->name_)); + sym->flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; } else if (auto sym_size = MatchTextPrefix(TokenType::Reserved, "size=")) { check_once(size); CHECK_RESULT(ParseUint64(*sym_size, &data->size)); @@ -2863,9 +2864,9 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { auto expr = new ConstExpr(const_, loc); out_expr->reset(expr); if (const_.type() == Type::I64) - CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::I64)); + CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::SLEB64)); else if (const_.type() == Type::I32) - CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::I32)); + CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::SLEB)); else CHECK_RESULT(ParseRejectReloc()); break; From beb3e961c175c2ac2150b8c06f9175a5778d82f8 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:56:45 +0300 Subject: [PATCH 17/59] Add fixed 64 bit leb writers --- include/wabt/leb128.h | 2 ++ src/leb128.cc | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/wabt/leb128.h b/include/wabt/leb128.h index e7290475b3..72571cf5c1 100644 --- a/include/wabt/leb128.h +++ b/include/wabt/leb128.h @@ -34,6 +34,8 @@ void WriteU64Leb128(Stream* stream, uint64_t value, const char* desc); void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc); void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc); void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc); +void WriteFixedS64Leb128(Stream* stream, uint64_t value, const char* desc); +void WriteFixedU64Leb128(Stream* stream, uint64_t value, const char* desc); Offset WriteU32Leb128At(Stream* stream, Offset offset, diff --git a/src/leb128.cc b/src/leb128.cc index 6c5a650fa9..ed2f2a26aa 100644 --- a/src/leb128.cc +++ b/src/leb128.cc @@ -141,6 +141,22 @@ void WriteU64Leb128(Stream* stream, uint64_t value, const char* desc) { stream->WriteData(data, length, desc); } +void WriteFixedU64Leb128(Stream* stream, uint64_t value, const char* desc) { + uint8_t data[MAX_U64_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(length == MAX_U64_LEB128_BYTES); + stream->WriteData(data, length, desc); +} +void WriteFixedS64Leb128(Stream* stream, int64_t value, const char* desc) { + uint8_t data[MAX_U64_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(length == MAX_U64_LEB128_BYTES); + stream->WriteData(data, length, desc); +} +void WriteFixedS64Leb128(Stream* stream, uint64_t value, const char* desc) { + WriteS64Leb128(stream, Bitcast(value), desc); +} + void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc) { WriteS64Leb128(stream, Bitcast(value), desc); } From 44d0f98856b53195fc983d2006706ca08d2fe3c0 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:58:58 +0300 Subject: [PATCH 18/59] Adjust symbol table implementation to account for the fact that symbol info is now stored in IR --- include/wabt/ir.h | 12 +++-- src/ir.cc | 113 ++++++++-------------------------------------- 2 files changed, 26 insertions(+), 99 deletions(-) diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 0c897e8490..e4680474bd 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -1430,10 +1430,6 @@ class SymbolTable { return const_cast(this)->GetTable(); } - template - Result AddSymbol(std::string_view name, bool imported, bool exported, - T&& sym); - public: SymbolTable() {} @@ -1461,6 +1457,12 @@ class SymbolTable { Index GlobalSymbolIndex(Index index) const { return SymbolIndex(index); } + Index TagSymbolIndex(Index index) const { + return SymbolIndex(index); + } + Index DataSymbolIndex(Index index) const { + return SymbolIndex(index); + } }; template<> std::vector& SymbolTable::GetTable(); @@ -1470,6 +1472,8 @@ template<> std::vector& SymbolTable::GetTable(); template<> std::vector& SymbolTable::GetTable(); +template<> +std::vector& SymbolTable::GetTable(); struct Module { Index GetFuncTypeIndex(const Var&) const; diff --git a/src/ir.cc b/src/ir.cc index b501dbfbb8..b7d6bb0405 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -126,42 +126,9 @@ template <> std::vector& SymbolTable::GetTable() { return tags_; } -template -Result SymbolTable::AddSymbol(std::string_view name, - bool imported, - bool exported, - T&& sym) { - uint8_t flags = 0; - if (imported) { - flags |= WABT_SYMBOL_FLAG_UNDEFINED; - // Wabt currently has no way for a user to explicitly specify the name of - // an import, so never set the EXPLICIT_NAME flag, and ignore any display - // name fabricated by wabt. - name = std::string_view(); - } else { - if (name.empty()) { - // Definitions without a name are local. - flags |= uint8_t(SymbolBinding::Local); - flags |= uint8_t(SymbolVisibility::Hidden); - } else { - // Otherwise, strip the dollar off the name; a definition $foo is - // available for linking as "foo". - assert(name[0] == '$'); - name.remove_prefix(1); - } - - if (exported) { - CHECK_RESULT(EnsureUnique(name)); - flags |= uint8_t(SymbolVisibility::Hidden); - flags |= WABT_SYMBOL_FLAG_NO_STRIP; - } - } - if (exported) { - flags |= WABT_SYMBOL_FLAG_EXPORTED; - } - - AddSymbol(Symbol{std::string(name), flags, sym}); - return Result::Ok; +template <> +std::vector& SymbolTable::GetTable() { + return datas_; } void EnlargeFor(std::vector& v, Index i) { @@ -183,67 +150,23 @@ Result SymbolTable::AddSymbol(Symbol sym) { return Result::Ok; } Result SymbolTable::Populate(const Module* module) { - std::set exported_funcs; - std::set exported_globals; - std::set exported_tags; - std::set exported_tables; - std::set exported_datas; - - for (const Export* export_ : module->exports) { - switch (export_->kind) { - case ExternalKind::Func: - exported_funcs.insert(module->GetFuncIndex(export_->var)); - break; - case ExternalKind::Table: - exported_tables.insert(module->GetTableIndex(export_->var)); - break; - case ExternalKind::Memory: - break; - case ExternalKind::Global: - exported_globals.insert(module->GetGlobalIndex(export_->var)); - break; - case ExternalKind::Tag: - exported_tags.insert(module->GetTagIndex(export_->var)); - break; + auto add = [&](auto& table, auto make_sym) { + for (size_t i = 0; i < table.size(); ++i) { + auto sym = table[i]; + CHECK_RESULT(AddSymbol({sym->name_, sym->flags_, make_sym(i, sym)})); } - } - - for (size_t i = 0; i < module->funcs.size(); ++i) { - const Func* func = module->funcs[i]; - bool imported = i < module->num_func_imports; - bool exported = exported_funcs.count(i); - CHECK_RESULT( - AddSymbol(func->name, imported, exported, Symbol::Function{Index(i)})); - } - - for (size_t i = 0; i < module->tables.size(); ++i) { - const Table* table = module->tables[i]; - bool imported = i < module->num_table_imports; - bool exported = exported_tables.count(i); - CHECK_RESULT( - AddSymbol(table->name, imported, exported, Symbol::Table{Index(i)})); - } - - for (size_t i = 0; i < module->globals.size(); ++i) { - const Global* global = module->globals[i]; - bool imported = i < module->num_global_imports; - bool exported = exported_globals.count(i); - CHECK_RESULT( - AddSymbol(global->name, imported, exported, Symbol::Global{Index(i)})); - } - for (size_t i = 0; i < module->tags.size(); ++i) { - const Tag* tag = module->tags[i]; - bool imported = i < module->num_tag_imports; - bool exported = exported_tags.count(i); - CHECK_RESULT( - AddSymbol(tag->name, imported, exported, Symbol::Tag{Index(i)})); - } + return Result::Ok; + }; + add(module->funcs, [](Index i, auto&) { return Symbol::Function{i}; }); + add(module->tables, [](Index i, auto&) { return Symbol::Table{i}; }); + add(module->globals, [](Index i, auto&) { return Symbol::Global{i}; }); + add(module->tags, [](Index i, auto&) { return Symbol::Tag{i}; }); for (size_t i = 0; i < module->data_symbols.size(); ++i) { - const DataSym* data = &module->data_symbols[i]; - bool imported = i < module->num_data_imports; - bool exported = data->exported(); - CHECK_RESULT( - AddSymbol(data->name, imported, exported, Symbol::Tag{Index(i)})); + auto& sym = module->data_symbols[i]; + CHECK_RESULT(AddSymbol({sym.name_, sym.flags_, + Symbol::Data{sym.segment, sym.offset, sym.size}})); + EnlargeFor(datas_, i); + datas_[i] = symbols().size() - 1; } return Result::Ok; From 4aea26c68f075c8bab9706c8ca90fe8f27e8ad76 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 01:02:23 +0300 Subject: [PATCH 19/59] Adjust binary writer to output more relocations --- src/binary-writer.cc | 81 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/src/binary-writer.cc b/src/binary-writer.cc index c11ed5ae9e..9451587176 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -161,6 +161,8 @@ class BinaryWriter { Index GetLocalIndex(const Func* func, const Var& var); Index GetSymbolIndex(RelocType reloc_type, Index index); void AddReloc(RelocType reloc_type, Index index); + void AddRelocAt(IrReloc, Offset); + void AddReloc(IrReloc); void WriteBlockDecl(const BlockDeclaration& decl); void WriteU32Leb128WithReloc(Index index, const char* desc, @@ -355,14 +357,20 @@ Index BinaryWriter::GetTagVarDepth(const Var* var) { } Index BinaryWriter::GetSymbolIndex(RelocType reloc_type, Index index) { - switch (reloc_type) { - case RelocType::FuncIndexLEB: + switch (kRelocSymbolType[int(reloc_type)]) { + case RelocKind::FunctionTbl: + case RelocKind::Function: + case RelocKind::Text: return symtab_.FunctionSymbolIndex(index); - case RelocType::TableNumberLEB: + case RelocKind::Table: return symtab_.TableSymbolIndex(index); - case RelocType::GlobalIndexLEB: + case RelocKind::Global: return symtab_.GlobalSymbolIndex(index); - case RelocType::TypeIndexLEB: + case RelocKind::Data: + return symtab_.DataSymbolIndex(index); + case RelocKind::Tag: + return symtab_.TagSymbolIndex(index); + case RelocKind::Type: // Type indexes don't create entries in the symbol table; instead their // index is used directly. return index; @@ -373,7 +381,7 @@ Index BinaryWriter::GetSymbolIndex(RelocType reloc_type, Index index) { } } -void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { +void BinaryWriter::AddRelocAt(IrReloc r, Offset offset) { // Add a new reloc section if needed if (!current_reloc_section_ || current_reloc_section_->section_index != section_count_) { @@ -383,16 +391,25 @@ void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { } // Add a new relocation to the curent reloc section - size_t offset = stream_->offset() - last_section_payload_offset_; - Index symbol_index = GetSymbolIndex(reloc_type, index); + Index symbol_index = GetSymbolIndex(r.type, r.symbol.index()); if (symbol_index == kInvalidIndex) { // The file is invalid, for example a reference to function 42 where only 10 // functions are defined. The user must have already passed --no-check, so // no extra warning here is needed. return; } - current_reloc_section_->relocations.emplace_back(reloc_type, offset, - symbol_index); + current_reloc_section_->relocations.emplace_back(r.type, offset, symbol_index, + r.addend); +} + +void BinaryWriter::AddReloc(IrReloc r) { + // Add a new relocation to the curent reloc section + size_t offset = stream_->offset() - last_section_payload_offset_; + return AddRelocAt(r, offset); +} + +void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { + return AddReloc({reloc_type, Var{index, {}}}); } void BinaryWriter::WriteU32Leb128WithReloc(Index index, @@ -455,7 +472,24 @@ void BinaryWriter::WriteLoadStoreExpr(const Func* func, } else { stream_->WriteU8(log2_u32(align), "alignment"); } - WriteU64Leb128(stream_, typed_expr->offset, desc); + if constexpr (std::is_same_v || std::is_same_v) { + if (options_.relocatable && typed_expr->reloc.type != RelocType::None) { + AddReloc(typed_expr->reloc); + switch (kRelocDataType[int(typed_expr->reloc.type)]) { + case RelocDataType::LEB64: + WriteFixedU64Leb128(stream_, typed_expr->offset, desc); + break; + case RelocDataType::LEB: + WriteFixedU32Leb128(stream_, typed_expr->offset, desc); + break; + default: + WABT_UNREACHABLE; + } + } else + WriteU64Leb128(stream_, typed_expr->offset, desc); + } else { + WriteU64Leb128(stream_, typed_expr->offset, desc); + } } template @@ -568,16 +602,31 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteOpcode(stream_, cast(expr)->opcode); break; case ExprType::Const: { - const Const& const_ = cast(expr)->const_; + const ConstExpr* const_expr = cast(expr); + const Const& const_ = const_expr->const_; switch (const_.type()) { case Type::I32: { WriteOpcode(stream_, Opcode::I32Const); - WriteS32Leb128(stream_, const_.u32(), "i32 literal"); + if (options_.relocatable && + const_expr->reloc.type != RelocType::None) { + assert(kRelocDataType[int(const_expr->reloc.type)] == + RelocDataType::SLEB); + AddReloc(const_expr->reloc); + WriteFixedS32Leb128(stream_, const_.u32(), "i32 literal"); + } else + WriteS32Leb128(stream_, const_.u32(), "i32 literal"); break; } case Type::I64: WriteOpcode(stream_, Opcode::I64Const); - WriteS64Leb128(stream_, const_.u64(), "i64 literal"); + if (options_.relocatable && + const_expr->reloc.type != RelocType::None) { + assert(kRelocDataType[int(const_expr->reloc.type)] == + RelocDataType::SLEB64); + AddReloc(const_expr->reloc); + WriteFixedS64Leb128(stream_, const_.u64(), "i64 literal"); + } else + WriteS64Leb128(stream_, const_.u64(), "i64 literal"); break; case Type::F32: WriteOpcode(stream_, Opcode::F32Const); @@ -1461,7 +1510,11 @@ Result BinaryWriter::WriteModule() { } WriteU32Leb128(stream_, segment->data.size(), "data segment size"); WriteHeader("data segment data", i); + size_t start_offset = stream_->offset() - last_section_payload_offset_; stream_->WriteData(segment->data, "data segment data"); + for (auto& [offset, reloc] : segment->relocs) { + AddRelocAt(reloc, offset + start_offset); + } } EndSection(); } From 8588622dd0b9587587132a9db6c6026fc2d5f370 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 22:38:58 +0300 Subject: [PATCH 20/59] Prevent writing symbol metadata when no attributes need to be specified --- include/wabt/ir.h | 4 ++++ src/wat-writer.cc | 43 ++++++++++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/include/wabt/ir.h b/include/wabt/ir.h index e4680474bd..527535de37 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -252,6 +252,10 @@ class SymbolCommon { return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; } bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } + bool non_default(bool imported) const { + uint32_t flags = flags_ & ~WABT_SYMBOL_FLAG_EXPORTED; + return flags != (imported ? WABT_SYMBOL_FLAG_UNDEFINED : 0); + } }; struct DataSym: SymbolCommon { diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 315856ef47..307ddc8ae7 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -1541,13 +1541,17 @@ void WatWriter::WriteDataImports() { } void WatWriter::WriteBeginFunc(const Func& func) { + bool import = module.IsImport(ExternalKind::Func, Var(func_index_, {})); WriteOpenSpace("func"); WriteNameOrIndex(func.name, func_index_, NextChar::Space); - WriteOpenSpace("@sym"); - WriteRelocAttrs(func); - if (func.priority.has_value()) - Writef("init=%u", *func.priority); - WriteCloseSpace(); + + if (func.non_default(import) && !func.priority) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(func); + if (func.priority.has_value()) + Writef("init=%u", *func.priority); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Func, func_index_); WriteInlineImport(ExternalKind::Func, func_index_); if (func.decl.has_func_type) { @@ -1556,7 +1560,7 @@ void WatWriter::WriteBeginFunc(const Func& func) { WriteCloseSpace(); } - if (module.IsImport(ExternalKind::Func, Var(func_index_, Location()))) { + if (import) { // Imported functions can be written a few ways: // // 1. (import "module" "field" (func (type 0))) @@ -1599,11 +1603,14 @@ void WatWriter::WriteFunc(const Func& func) { } void WatWriter::WriteBeginGlobal(const Global& global) { + bool import = module.IsImport(ExternalKind::Global, Var(func_index_, {})); WriteOpenSpace("global"); WriteNameOrIndex(global.name, global_index_, NextChar::Space); - WriteOpenSpace("@sym"); - WriteRelocAttrs(global); - WriteCloseSpace(); + if (global.non_default(import)) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(global); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Global, global_index_); WriteInlineImport(ExternalKind::Global, global_index_); if (global.mutable_) { @@ -1623,11 +1630,14 @@ void WatWriter::WriteGlobal(const Global& global) { } void WatWriter::WriteTag(const Tag& tag) { + bool import = module.IsImport(ExternalKind::Tag, Var(func_index_, {})); WriteOpenSpace("tag"); WriteNameOrIndex(tag.name, tag_index_, NextChar::Space); - WriteOpenSpace("@sym"); - WriteRelocAttrs(tag); - WriteCloseSpace(); + if (tag.non_default(import)) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(tag); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Tag, tag_index_); WriteInlineImport(ExternalKind::Tag, tag_index_); if (tag.decl.has_func_type) { @@ -1654,11 +1664,14 @@ void WatWriter::WriteLimits(const Limits& limits) { } void WatWriter::WriteTable(const Table& table) { + bool import = module.IsImport(ExternalKind::Table, Var(func_index_, {})); WriteOpenSpace("table"); WriteNameOrIndex(table.name, table_index_, NextChar::Space); - WriteOpenSpace("@sym"); - WriteRelocAttrs(table); - WriteCloseSpace(); + if (table.non_default(import)) { + WriteOpenSpace("@sym"); + WriteRelocAttrs(table); + WriteCloseSpace(); + } WriteInlineExports(ExternalKind::Table, table_index_); WriteInlineImport(ExternalKind::Table, table_index_); WriteLimits(table.elem_limits); From 667ff47f45b140d2486e283b18d83527449b0882 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:46:48 +0300 Subject: [PATCH 21/59] Add handling for invalid symbol definitions and relocations --- src/binary-reader-ir.cc | 49 +++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index fd5ac5b4b2..2599533b5e 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -1850,15 +1850,15 @@ Result BinaryReaderIR::OnFunctionSymbol(Index index, assert(index == table.symbols().size()); Symbol sym = {std::string(name), flags, Symbol::Function{func_index}}; table.AddSymbol(sym); - static_cast(*module_->funcs[func_index]) = sym; - if (name.empty()) { - return Result::Ok; - } if (func_index >= module_->funcs.size()) { PrintError("invalid function index: %" PRIindex, func_index); return Result::Error; } Func* func = module_->funcs[func_index]; + static_cast(*func) = sym; + if (name.empty()) { + return Result::Ok; + } if (!func->name.empty()) { // The name section has already named this function. return Result::Ok; @@ -1877,7 +1877,12 @@ Result BinaryReaderIR::OnGlobalSymbol(Index index, assert(index == table.symbols().size()); Symbol sym = {std::string(name), flags, Symbol::Global{global_index}}; table.AddSymbol(sym); - static_cast(*module_->globals[global_index]) = sym; + if (index >= module_->globals.size()) { + PrintError("invalid global index: %" PRIindex, index); + return Result::Error; + } + Global* glob = module_->globals[index]; + static_cast(*glob) = sym; return SetGlobalName(global_index, name); } @@ -1896,15 +1901,15 @@ Result BinaryReaderIR::OnTagSymbol(Index index, assert(index == table.symbols().size()); Symbol sym = {std::string(name), flags, Symbol::Tag{tag_index}}; table.AddSymbol(sym); - static_cast(*module_->tags[tag_index]) = sym; - if (name.empty()) { - return Result::Ok; - } if (tag_index >= module_->tags.size()) { PrintError("invalid tag index: %" PRIindex, tag_index); return Result::Error; } Tag* tag = module_->tags[tag_index]; + static_cast(*tag) = sym; + if (name.empty()) { + return Result::Ok; + } std::string dollar_name = GetUniqueName(&module_->tag_bindings, MakeDollarName(name)); tag->name = dollar_name; @@ -1919,7 +1924,12 @@ Result BinaryReaderIR::OnTableSymbol(Index index, assert(index == table.symbols().size()); Symbol sym = {std::string(name), flags, Symbol::Table{table_index}}; table.AddSymbol(sym); - static_cast(*module_->tables[table_index]) = sym; + if (index >= module_->tables.size()) { + PrintError("invalid table index: %" PRIindex, index); + return Result::Error; + } + Table* table = module_->tables[index]; + static_cast(*table) = sym; return SetTableName(table_index, name); } @@ -1995,6 +2005,9 @@ Result BinaryReaderIR::EndModule() { size_t i = 0; Index range_start = 0, data_segment = -1; for (auto& datasym : data_symbols) { + if (datasym.segment >= module_->data_segments.size()) + // all further symbols are invalid + break; if (datasym.segment != data_segment) { if (data_segment != kInvalidIndex) { module_->data_segments[data_segment]->symbol_range = {range_start, i}; @@ -2015,6 +2028,8 @@ Result BinaryReaderIR::EndModule() { auto lookup_reloc = [this](Reloc r) { auto maybe_name = [](auto& table, Index idx) { + if (idx >= table.size()) + return Var{kInvalidIndex, {}}; auto sym = Overload{ [](auto* x) { return x; }, [](auto& x) { return &x; }, @@ -2022,6 +2037,9 @@ Result BinaryReaderIR::EndModule() { return sym->name.empty() ? Var{idx, {}} : Var{sym->name, {}}; }; + if (r.index >= size(table.symbols())) + return Var{kInvalidIndex, {}}; + auto& sym = table.symbols()[r.index]; switch (sym.type()) { case SymbolType::Data: { @@ -2064,8 +2082,12 @@ Result BinaryReaderIR::EndModule() { }; for (auto& [index, queue] : reloc_queues) { - bool applied_relocation = false; for (auto reloc : queue.incoming_relocs) { + bool applied_relocation = false; + Var sym_id = lookup_reloc(reloc); + if (sym_id.is_index() && sym_id.index() == kInvalidIndex) + // this reloc points to an invalid symbol and is therefore unapplicable + continue; auto reloc_size = kRelocDataTypeSize[int(kRelocDataType[int(reloc.type)])]; // We pray that the relocation is always the last operand, and that the @@ -2074,7 +2096,7 @@ Result BinaryReaderIR::EndModule() { queue.traverse([&](auto& insns) { auto insn = insns.find(reloc_addr); if (insn != end(insns)) { - insn->second->reloc = {reloc.type, lookup_reloc(reloc), reloc.addend}; + insn->second->reloc = {reloc.type, sym_id, reloc.addend}; assert(insn->second->reloc.type != RelocType::None); applied_relocation = true; } @@ -2087,8 +2109,7 @@ Result BinaryReaderIR::EndModule() { auto abs_offset = reloc.offset + queue.start; if (end >= abs_offset + reloc_size) { it->second->relocs.push_back( - {abs_offset - it->first, - {reloc.type, lookup_reloc(reloc), reloc.addend}}); + {abs_offset - it->first, {reloc.type, sym_id, reloc.addend}}); applied_relocation = true; } } From c09b03a4aeb777813072bab7c614d1285b3ead30 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sat, 11 Oct 2025 23:48:15 +0300 Subject: [PATCH 22/59] Handle expressions appearing outside relocatable sections --- src/binary-reader-ir.cc | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 2599533b5e..7c2aa7228d 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -379,7 +379,6 @@ class BinaryReaderIR : public BinaryReaderNop { Result EndModule() override; private: - void MakeQueue(); Location GetLocation() const; void PrintError(const char* format, ...); Result PushLabel(LabelType label_type, @@ -440,11 +439,13 @@ class BinaryReaderIR : public BinaryReaderNop { std::map data_segment_starts; }; std::unordered_map reloc_queues; - decltype(reloc_queues)::iterator active_reloc_section = {}; + decltype(reloc_queues)::iterator active_reloc_section = end(reloc_queues); SymbolTable table; std::multiset data_symbols; Index active_section = kInvalidIndex; + void MakeQueue(); + RelocQueue* GetQueue(); }; BinaryReaderIR::BinaryReaderIR(Module* out_module, @@ -514,13 +515,13 @@ Result BinaryReaderIR::TopLabelExpr(LabelNode** label, Expr** expr) { } Result BinaryReaderIR::AppendExpr(std::unique_ptr expr) { - RelocQueue& queue = active_reloc_section->second; - queue.traverse([&](auto&& map) { - using Value = std::remove_reference_t; - if (auto* ce = dynamic_cast(expr.get())) { - map.insert({state->offset - queue.start, ce}); - } - }); + if (RelocQueue* queue = GetQueue()) + queue->traverse([&](auto&& map) { + using Value = std::remove_reference_t; + if (auto* ce = dynamic_cast(expr.get())) { + map.insert({state->offset - queue->start, ce}); + } + }); expr->loc = GetLocation(); LabelNode* label; CHECK_RESULT(TopLabel(&label)); @@ -1534,8 +1535,7 @@ Result BinaryReaderIR::OnDataSegmentData(Index index, Address size) { assert(index == module_->data_segments.size() - 1); DataSegment* segment = module_->data_segments[index]; - active_reloc_section->second.data_segment_starts.emplace(state->offset - size, - segment); + GetQueue()->data_segment_starts.emplace(state->offset - size, segment); segment->data.resize(size); if (size > 0) { memcpy(segment->data.data(), data, size); @@ -1937,8 +1937,7 @@ Result BinaryReaderIR::OnReloc(RelocType type, Offset offset, Index index, uint32_t addend) { - active_reloc_section->second.incoming_relocs.emplace_back(type, offset, index, - addend); + GetQueue()->incoming_relocs.emplace_back(type, offset, index, addend); return Result::Ok; } void BinaryReaderIR::MakeQueue() { @@ -1946,6 +1945,11 @@ void BinaryReaderIR::MakeQueue() { active_reloc_section = reloc_queues.insert({active_section, RelocQueue{state->offset}}).first; } +BinaryReaderIR::RelocQueue* BinaryReaderIR::GetQueue() { + if (active_reloc_section != end(reloc_queues)) + return &active_reloc_section->second; + return nullptr; +} Result BinaryReaderIR::BeginCodeSection(Offset size) { MakeQueue(); @@ -1968,12 +1972,12 @@ Result BinaryReaderIR::BeginElemSection(Offset size) { Result BinaryReaderIR::OnRelocCount(Index count, Index section_index) { active_reloc_section = reloc_queues.find(section_index); - assert(active_reloc_section != end(reloc_queues)); + assert(GetQueue()); return Result::Ok; } Result BinaryReaderIR::EndRelocSection() { - active_reloc_section = {}; + active_reloc_section = end(reloc_queues); return Result::Ok; } From 0f3b61eb1f85328f3b1ca5a1852e3b48221f53dd Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 00:22:22 +0300 Subject: [PATCH 23/59] Revert to older error message to pass more tests --- src/wast-parser.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 7fc23b7832..6f101da0b2 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1657,8 +1657,7 @@ Result WastParser::ParseDataModuleField(Module* module) { std::back_inserter(field->data_segment.data)); continue; } - ErrorExpected({"relocation", "symbol definition", "a quoted string"}, - "\"foo\""); + Expect(TokenType::Rpar); return Result::Error; } From 8b1afe0bea306ba5ff7c3d5aa7cbe41995c4f01a Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 00:22:47 +0300 Subject: [PATCH 24/59] Fix inverted assetion condition --- src/wast-parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 6f101da0b2..429db84979 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -2570,7 +2570,7 @@ Result WastParser::ParseCodeMetadataAnnotation(ExprList* exprs) { Token tk = Consume(); constexpr std::string_view pfx = "metadata.code."; std::string_view name = tk.text(); - assert(name.substr(0, size(pfx)) != pfx && + assert(name.substr(0, size(pfx)) == pfx && "ParseCodeMetadataAnnotation should only be called with appropriate " "annotation"); name.remove_prefix(size(pfx)); From 2f9a0d65d73c7048635db696f368d114f1540608 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 02:07:32 +0300 Subject: [PATCH 25/59] Always print at least an empty string in data segments --- src/wat-writer.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 307ddc8ae7..c229b410ad 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -1758,6 +1758,7 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { constexpr auto end_offset = std::numeric_limits::max(); Index curr_sym = segment.symbol_range.first; auto curr_reloc = begin(segment.relocs); + bool written_some_data = false; for (;;) { next_reloc = curr_reloc != end(segment.relocs) ? curr_reloc->first + @@ -1781,13 +1782,14 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { ++curr_sym; continue; } - if (offset == segment.data.size()) + if (offset == segment.data.size() && written_some_data) // if we have no relocs/syms left, and there's also no data, leave break; Offset write_to = std::min(segment.data.size(), std::min(next_reloc, next_sym)); WriteQuotedData(segment.data.data() + offset, write_to - offset); offset = write_to; + written_some_data = true; } WriteCloseNewline(); data_segment_index_++; From 52f74d3e19272912f774223d6ae26f1bf06818ef Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 02:10:24 +0300 Subject: [PATCH 26/59] Add validation for invalid init functions --- src/binary-reader-ir.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 7c2aa7228d..b390394638 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -1989,7 +1989,16 @@ Result BinaryReaderIR::BeginSection(Index section_index, } Result BinaryReaderIR::OnInitFunction(uint32_t prio, Index sym) { - module_->funcs[table.symbols()[sym].AsFunction().index]->priority = prio; + if (sym >= table.symbols().size()) { + return Result::Ok; + // PrintError("invalid init function priority symbol index: %" PRIindex, + // sym); return Result::Error; + } + Index func = table.symbols()[sym].AsFunction().index; + if (func >= module_->funcs.size()) + // We already emitted an error for the invalid symbol + return Result::Ok; + module_->funcs[func]->priority = prio; return Result::Ok; } From 219584cd38180459bb3e1fb14047752e77a6377a Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 02:11:09 +0300 Subject: [PATCH 27/59] Fix global symbol handler using an inappropriate index --- src/binary-reader-ir.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index b390394638..e88485d108 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -1877,11 +1877,11 @@ Result BinaryReaderIR::OnGlobalSymbol(Index index, assert(index == table.symbols().size()); Symbol sym = {std::string(name), flags, Symbol::Global{global_index}}; table.AddSymbol(sym); - if (index >= module_->globals.size()) { - PrintError("invalid global index: %" PRIindex, index); + if (global_index >= module_->globals.size()) { + PrintError("invalid global index: %" PRIindex, global_index); return Result::Error; } - Global* glob = module_->globals[index]; + Global* glob = module_->globals[global_index]; static_cast(*glob) = sym; return SetGlobalName(global_index, name); } From a699ca75f1693e15857e6a97b343cd8cff15ae8e Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 03:47:29 +0300 Subject: [PATCH 28/59] Fix exports not being looked up correctly --- src/wast-parser.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 429db84979..5bece0be46 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1546,8 +1546,8 @@ Result WastParser::ParseModuleFieldList(Module* module) { CHECK_RESULT(ResolveNamesModule(module, errors_)); for (auto exp : module->exports) { auto patch = [&](auto& fields, const BindingHash& bindings) { - Index i = bindings.FindIndex(exp->name); - if (i == kInvalidIndex) + Index i = bindings.FindIndex(exp->var); + if (i >= fields.size()) return; fields[i]->flags_ |= WABT_SYMBOL_FLAG_EXPORTED; }; From eb99d50b11ff7c08f9547101feb2511d4ffb75d0 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 04:00:52 +0300 Subject: [PATCH 29/59] Imply no_strip when exporting --- src/wast-parser.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 5bece0be46..60a8783c7a 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1549,7 +1549,8 @@ Result WastParser::ParseModuleFieldList(Module* module) { Index i = bindings.FindIndex(exp->var); if (i >= fields.size()) return; - fields[i]->flags_ |= WABT_SYMBOL_FLAG_EXPORTED; + fields[i]->flags_ |= + WABT_SYMBOL_FLAG_EXPORTED | WABT_SYMBOL_FLAG_NO_STRIP; }; switch (exp->kind) { case ExternalKind::Func: From 3cbbf345f4cf26c117e0264dd16644626818b864 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 05:27:20 +0300 Subject: [PATCH 30/59] Set WASM_EXPLICIT_NAME when exporting [old behavior compat] --- src/wast-parser.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 60a8783c7a..3d157e563c 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1549,8 +1549,12 @@ Result WastParser::ParseModuleFieldList(Module* module) { Index i = bindings.FindIndex(exp->var); if (i >= fields.size()) return; - fields[i]->flags_ |= - WABT_SYMBOL_FLAG_EXPORTED | WABT_SYMBOL_FLAG_NO_STRIP; + SymbolCommon& sym = *fields[i]; + sym.flags_ |= WABT_SYMBOL_FLAG_EXPORTED | WABT_SYMBOL_FLAG_NO_STRIP; + if (sym.name_.empty() && sym.defined()) { + sym.name_ = exp->name; + sym.flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } }; switch (exp->kind) { case ExternalKind::Func: From 4c25f78b234e67788780ca7889f335a11694c20e Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 05:30:59 +0300 Subject: [PATCH 31/59] Set WASM_EXPLICIT_NAME from variable name [old behavior compat] --- src/wast-parser.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 3d157e563c..baa4e83d54 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1768,6 +1768,8 @@ Result WastParser::ParseTagModuleField(Module* module) { module->AppendField(std::move(field)); } else { auto field = std::make_unique(loc, name); + if (!name.empty() && !field->tag.explicit_name()) + field->tag.name_ = name.substr(1); CHECK_RESULT(ParseTypeUseOpt(&field->tag.decl)); CHECK_RESULT(ParseUnboundFuncSignature(&field->tag.decl.sig)); module->AppendField(std::move(field)); @@ -1819,6 +1821,8 @@ Result WastParser::ParseFuncModuleField(Module* module) { Func& func = field->func; func.loc = GetLocation(); CHECK_RESULT(ParseSymOpt(&func, false)); + if (!name.empty() && !func.explicit_name()) + func.name_ = name.substr(1); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); @@ -1948,6 +1952,8 @@ Result WastParser::ParseGlobalModuleField(Module* module) { module->AppendField(std::move(field)); } else { auto field = std::make_unique(loc, name); + if (!name.empty() && !field->global.explicit_name()) + field->global.name_ = name.substr(1); CHECK_RESULT(ParseGlobalType(&field->global)); CHECK_RESULT(ParseTerminatingInstrList(&field->global.init_expr)); module->AppendField(std::move(field)); @@ -2157,6 +2163,8 @@ Result WastParser::ParseTableModuleField(Module* module) { auto field = std::make_unique(loc, name); auto& table = field->table; CHECK_RESULT(ParseSymOpt(&table, false)); + if (!name.empty() && !table.explicit_name()) + table.name_ = name.substr(1); CHECK_RESULT(ParseLimitsIndex(&table.elem_limits)); if (PeekMatch(TokenType::ValueType)) { Type elem_type; From 6fb2d4571a05473acacee6a1cdb2aa9acdad76d2 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 05:31:23 +0300 Subject: [PATCH 32/59] Set WASM_EXPLICIT_NAME from import name [old behavior compat] --- src/wast-parser.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index baa4e83d54..7a91741b1c 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1977,6 +1977,11 @@ Result WastParser::ParseImportModuleField(Module* module) { CHECK_RESULT(ParseQuotedText(&field_name)); EXPECT(Lpar); + auto inject_name = [&](SymbolCommon& sym) { + if (!sym.explicit_name()) + sym.name_ = field_name; + }; + std::unique_ptr field; std::string name; @@ -1991,6 +1996,7 @@ Result WastParser::ParseImportModuleField(Module* module) { ParseFuncSignature(&import->func.decl.sig, &import->func.bindings)); CHECK_RESULT(ErrorIfLpar({"param", "result"})); EXPECT(Rpar); + inject_name(import->func); field = std::make_unique(std::move(import), loc); break; } @@ -2004,6 +2010,7 @@ Result WastParser::ParseImportModuleField(Module* module) { CHECK_RESULT(ParseLimits(&import->table.elem_limits)); CHECK_RESULT(ParseRefType(&import->table.elem_type)); EXPECT(Rpar); + inject_name(import->table); field = std::make_unique(std::move(import), loc); break; } @@ -2028,6 +2035,7 @@ Result WastParser::ParseImportModuleField(Module* module) { CHECK_RESULT(ParseSymOpt(&import->global, true)); CHECK_RESULT(ParseGlobalType(&import->global)); EXPECT(Rpar); + inject_name(import->global); field = std::make_unique(std::move(import), loc); break; } @@ -2040,6 +2048,7 @@ Result WastParser::ParseImportModuleField(Module* module) { CHECK_RESULT(ParseTypeUseOpt(&import->tag.decl)); CHECK_RESULT(ParseUnboundFuncSignature(&import->tag.decl.sig)); EXPECT(Rpar); + inject_name(import->tag); field = std::make_unique(std::move(import), loc); break; } From 9f89fd56d8596072c4f0a1c3e88cf1776a096861 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 06:53:24 +0300 Subject: [PATCH 33/59] Add symbol annotation handling where I forgot them --- src/wast-parser.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 7a91741b1c..a6333c9487 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1768,8 +1768,10 @@ Result WastParser::ParseTagModuleField(Module* module) { module->AppendField(std::move(field)); } else { auto field = std::make_unique(loc, name); - if (!name.empty() && !field->tag.explicit_name()) - field->tag.name_ = name.substr(1); + Tag& tag = field->tag; + CHECK_RESULT(ParseSymOpt(&tag, false)); + if (!name.empty() && !tag.explicit_name()) + tag.name_ = name.substr(1); CHECK_RESULT(ParseTypeUseOpt(&field->tag.decl)); CHECK_RESULT(ParseUnboundFuncSignature(&field->tag.decl.sig)); module->AppendField(std::move(field)); @@ -1952,8 +1954,10 @@ Result WastParser::ParseGlobalModuleField(Module* module) { module->AppendField(std::move(field)); } else { auto field = std::make_unique(loc, name); - if (!name.empty() && !field->global.explicit_name()) - field->global.name_ = name.substr(1); + Global& global = field->global; + CHECK_RESULT(ParseSymOpt(&global, false)); + if (!name.empty() && !global.explicit_name()) + global.name_ = name.substr(1); CHECK_RESULT(ParseGlobalType(&field->global)); CHECK_RESULT(ParseTerminatingInstrList(&field->global.init_expr)); module->AppendField(std::move(field)); From a69c8a52b54afbda2b00510ed250deb6b2e3dbb1 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 06:57:12 +0300 Subject: [PATCH 34/59] Force symbols without a name to be local --- include/wabt/ir.h | 7 +++++-- src/wast-parser.cc | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 527535de37..66d89cabd1 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -253,8 +253,11 @@ class SymbolCommon { } bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } bool non_default(bool imported) const { - uint32_t flags = flags_ & ~WABT_SYMBOL_FLAG_EXPORTED; - return flags != (imported ? WABT_SYMBOL_FLAG_UNDEFINED : 0); + uint32_t flags = + flags_ & ~WABT_SYMBOL_FLAG_EXPORTED & ~WABT_SYMBOL_FLAG_UNDEFINED; + if (!undefined() && !exported() && name().empty()) + flags &= ~WABT_SYMBOL_MASK_BINDING & ~WABT_SYMBOL_MASK_VISIBILITY; + return flags != 0; } }; diff --git a/src/wast-parser.cc b/src/wast-parser.cc index a6333c9487..2628204c4e 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1574,6 +1574,21 @@ Result WastParser::ParseModuleFieldList(Module* module) { break; } } + auto validize_flags = [](SymbolCommon* sym) { + if (!sym->undefined() && !sym->exported() && sym->name().empty()) { + sym->flags_ |= uint32_t(SymbolVisibility::Hidden); + sym->flags_ &= ~WABT_SYMBOL_MASK_BINDING; + sym->flags_ |= uint32_t(SymbolBinding::Local); + } + }; + for (auto sym : module->funcs) + validize_flags(sym); + for (auto sym : module->globals) + validize_flags(sym); + for (auto sym : module->tables) + validize_flags(sym); + for (auto sym : module->tags) + validize_flags(sym); return Result::Ok; } From 61b4ad9985ccf42fd361a4543b61a355566bbe2a Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 07:03:37 +0300 Subject: [PATCH 35/59] Edit tests to reflect the fact that visibility is specified via an annotation --- test/dump/relocations-all-features.txt | 2 +- test/dump/relocations-block-types.txt | 2 +- test/dump/relocations-section-target.txt | 2 +- test/dump/relocations.txt | 2 +- test/dump/symbol-tables-all-features.txt | 2 +- test/dump/symbol-tables.txt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/dump/relocations-all-features.txt b/test/dump/relocations-all-features.txt index 0b22b64184..b6d6dc48fd 100644 --- a/test/dump/relocations-all-features.txt +++ b/test/dump/relocations-all-features.txt @@ -59,7 +59,7 @@ Custom: - symbol table [count=5] - 0: F <__extern.foo> func=0 [ undefined binding=global vis=default ] - 1: F <__extern.bar> func=1 [ undefined binding=global vis=default ] - - 2: F func=2 [ exported no_strip binding=global vis=hidden ] + - 2: F func=2 [ exported no_strip binding=global vis=default ] - 3: T <> table=0 [ binding=local vis=hidden ] - 4: G global=0 [ binding=global vis=default ] Custom: diff --git a/test/dump/relocations-block-types.txt b/test/dump/relocations-block-types.txt index 5192b77488..9089b5b462 100644 --- a/test/dump/relocations-block-types.txt +++ b/test/dump/relocations-block-types.txt @@ -30,7 +30,7 @@ Code[1]: Custom: - name: "linking" - symbol table [count=1] - - 0: F func=0 [ exported no_strip binding=global vis=hidden ] + - 0: F func=0 [ exported no_strip binding=global vis=default ] Custom: - name: "reloc.Code" - relocations for section: 3 (Code) [1] diff --git a/test/dump/relocations-section-target.txt b/test/dump/relocations-section-target.txt index 112b655315..075bb9d235 100644 --- a/test/dump/relocations-section-target.txt +++ b/test/dump/relocations-section-target.txt @@ -27,7 +27,7 @@ Custom: - name: "linking" - symbol table [count=2] - 0: F func=0 [ undefined binding=global vis=default ] - - 1: F func=1 [ exported no_strip binding=global vis=hidden ] + - 1: F func=1 [ exported no_strip binding=global vis=default ] Custom: - name: "reloc.Code" - relocations for section: 4 (Code) [1] diff --git a/test/dump/relocations.txt b/test/dump/relocations.txt index 9114e3562f..ead46a0a43 100644 --- a/test/dump/relocations.txt +++ b/test/dump/relocations.txt @@ -59,7 +59,7 @@ Custom: - symbol table [count=5] - 0: F <__extern.foo> func=0 [ undefined binding=global vis=default ] - 1: F <__extern.bar> func=1 [ undefined binding=global vis=default ] - - 2: F func=2 [ exported no_strip binding=global vis=hidden ] + - 2: F func=2 [ exported no_strip binding=global vis=default ] - 3: T <> table=0 [ binding=local vis=hidden ] - 4: G global=0 [ binding=global vis=default ] Custom: diff --git a/test/dump/symbol-tables-all-features.txt b/test/dump/symbol-tables-all-features.txt index 5aaa07bfeb..a87c8cdda5 100644 --- a/test/dump/symbol-tables-all-features.txt +++ b/test/dump/symbol-tables-all-features.txt @@ -39,7 +39,7 @@ Custom: - name: "linking" - symbol table [count=5] - 0: F func=0 [ undefined binding=global vis=default ] - - 1: F func=1 [ exported no_strip binding=global vis=hidden ] + - 1: F func=1 [ exported no_strip binding=global vis=default ] - 2: F <> func=2 [ binding=local vis=hidden ] - 3: F func=3 [ binding=global vis=default ] - 4: T table=0 [ binding=global vis=default ] diff --git a/test/dump/symbol-tables.txt b/test/dump/symbol-tables.txt index 04a2085d97..8f716bafa0 100644 --- a/test/dump/symbol-tables.txt +++ b/test/dump/symbol-tables.txt @@ -41,7 +41,7 @@ Custom: - name: "linking" - symbol table [count=6] - 0: F func=0 [ undefined binding=global vis=default ] - - 1: F func=1 [ exported no_strip binding=global vis=hidden ] + - 1: F func=1 [ exported no_strip binding=global vis=default ] - 2: F <> func=2 [ binding=local vis=hidden ] - 3: F func=3 [ binding=global vis=default ] - 4: T table=0 [ undefined binding=global vis=default ] From ffc7772a2693ec10b84944ec82686ae823cafcbf Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 07:07:42 +0300 Subject: [PATCH 36/59] Ignore other symbols pointing to the same entity for the purposes of lookup --- src/ir.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ir.cc b/src/ir.cc index b7d6bb0405..301678696c 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -142,8 +142,10 @@ Result SymbolTable::AddSymbol(Symbol sym) { if constexpr (!std::is_same_v && !std::is_same_v) { EnlargeFor(GetTable(), type.index); - assert(GetTable()[type.index] == kInvalidIndex); - GetTable()[type.index] = symbols_.size(); + // This is lossy since multiple symbols are genuinely possible, but apart + // from data symbols their semantics is not very clear + if (GetTable()[type.index] == kInvalidIndex) + GetTable()[type.index] = symbols_.size(); } }); symbols_.push_back(sym); From 52341976bdcf8287e45f934fc172474eeed107b7 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 07:14:26 +0300 Subject: [PATCH 37/59] Fix wrong index in OnTableSymbol --- src/binary-reader-ir.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index e88485d108..e072d2d0dd 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -1924,11 +1924,11 @@ Result BinaryReaderIR::OnTableSymbol(Index index, assert(index == table.symbols().size()); Symbol sym = {std::string(name), flags, Symbol::Table{table_index}}; table.AddSymbol(sym); - if (index >= module_->tables.size()) { - PrintError("invalid table index: %" PRIindex, index); + if (table_index >= module_->tables.size()) { + PrintError("invalid table index: %" PRIindex, table_index); return Result::Error; } - Table* table = module_->tables[index]; + Table* table = module_->tables[table_index]; static_cast(*table) = sym; return SetTableName(table_index, name); } From 118f86618d8aa74a5dc7facfacd1a6c0bc2311cd Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 12 Oct 2025 08:34:21 +0300 Subject: [PATCH 38/59] Add an option to emit relocation annotations --- include/wabt/wat-writer.h | 1 + src/tools/wasm2wat.cc | 4 ++++ src/wat-writer.cc | 14 +++++++------- test/help/wasm2wat.txt | 1 + 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/wabt/wat-writer.h b/include/wabt/wat-writer.h index 0f19ba2465..c10337adb0 100644 --- a/include/wabt/wat-writer.h +++ b/include/wabt/wat-writer.h @@ -32,6 +32,7 @@ struct WriteWatOptions { bool fold_exprs = false; // Write folded expressions. bool inline_export = false; bool inline_import = false; + bool relocatable = false; }; Result WriteWat(Stream*, const Module*, const WriteWatOptions&); diff --git a/src/tools/wasm2wat.cc b/src/tools/wasm2wat.cc index 25e1c743c6..015865fff5 100644 --- a/src/tools/wasm2wat.cc +++ b/src/tools/wasm2wat.cc @@ -46,6 +46,7 @@ static bool s_read_debug_names = true; static bool s_fail_on_custom_section_error = true; static std::unique_ptr s_log_stream; static bool s_validate = true; +static bool s_relocatable = false; static const char s_description[] = R"( Read a file in the WebAssembly binary format, and convert it to @@ -96,6 +97,8 @@ static void ParseOptions(int argc, char** argv) { s_infile = argument; ConvertBackslashToSlash(&s_infile); }); + parser.AddOption('r', "relocatable", "Generate relocation annotations", + []() { s_relocatable = true; }); parser.Parse(argc, argv); } @@ -138,6 +141,7 @@ int ProgramMain(int argc, char** argv) { wat_options.fold_exprs = s_fold_exprs; wat_options.inline_import = s_inline_import; wat_options.inline_export = s_inline_export; + wat_options.relocatable = s_relocatable; FileStream stream(!s_outfile.empty() ? FileStream(s_outfile) : FileStream(stdout)); result = WriteWat(&stream, &module, wat_options); diff --git a/src/wat-writer.cc b/src/wat-writer.cc index c229b410ad..ceaab64c61 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -1463,7 +1463,7 @@ void WatWriter::WriteRelocAttrs(const SymbolCommon& sym) { } void WatWriter::WriteReloc(const IrReloc& reloc, bool require_type) { - if (reloc.type == RelocType::None) + if (reloc.type == RelocType::None || !options_.relocatable) return; WriteOpenSpace("@reloc"); if (require_type) @@ -1545,7 +1545,7 @@ void WatWriter::WriteBeginFunc(const Func& func) { WriteOpenSpace("func"); WriteNameOrIndex(func.name, func_index_, NextChar::Space); - if (func.non_default(import) && !func.priority) { + if ((func.non_default(import) || func.priority) && options_.relocatable) { WriteOpenSpace("@sym"); WriteRelocAttrs(func); if (func.priority.has_value()) @@ -1606,7 +1606,7 @@ void WatWriter::WriteBeginGlobal(const Global& global) { bool import = module.IsImport(ExternalKind::Global, Var(func_index_, {})); WriteOpenSpace("global"); WriteNameOrIndex(global.name, global_index_, NextChar::Space); - if (global.non_default(import)) { + if (global.non_default(import) && options_.relocatable) { WriteOpenSpace("@sym"); WriteRelocAttrs(global); WriteCloseSpace(); @@ -1633,7 +1633,7 @@ void WatWriter::WriteTag(const Tag& tag) { bool import = module.IsImport(ExternalKind::Tag, Var(func_index_, {})); WriteOpenSpace("tag"); WriteNameOrIndex(tag.name, tag_index_, NextChar::Space); - if (tag.non_default(import)) { + if (tag.non_default(import) && options_.relocatable) { WriteOpenSpace("@sym"); WriteRelocAttrs(tag); WriteCloseSpace(); @@ -1667,7 +1667,7 @@ void WatWriter::WriteTable(const Table& table) { bool import = module.IsImport(ExternalKind::Table, Var(func_index_, {})); WriteOpenSpace("table"); WriteNameOrIndex(table.name, table_index_, NextChar::Space); - if (table.non_default(import)) { + if (table.non_default(import) && options_.relocatable) { WriteOpenSpace("@sym"); WriteRelocAttrs(table); WriteCloseSpace(); @@ -1760,12 +1760,12 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { auto curr_reloc = begin(segment.relocs); bool written_some_data = false; for (;;) { - next_reloc = curr_reloc != end(segment.relocs) + next_reloc = curr_reloc != end(segment.relocs) && options_.relocatable ? curr_reloc->first + kRelocDataTypeSize[int( kRelocDataType[int(curr_reloc->second.type)])] : end_offset; - next_sym = curr_sym != segment.symbol_range.second + next_sym = curr_sym != segment.symbol_range.second && options_.relocatable ? module.data_symbols[curr_sym].offset : end_offset; if (offset == next_reloc) { diff --git a/test/help/wasm2wat.txt b/test/help/wasm2wat.txt index f2b2f5c88f..93fa020485 100644 --- a/test/help/wasm2wat.txt +++ b/test/help/wasm2wat.txt @@ -45,4 +45,5 @@ options: --ignore-custom-section-errors Ignore errors in custom sections --generate-names Give auto-generated names to non-named functions, types, etc. --no-check Don't check for invalid modules + -r, --relocatable Generate relocation annotations ;;; STDOUT ;;) From c1abb262e3300e310943edc29aa4632139b67c27 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Mon, 13 Oct 2025 23:43:20 +0300 Subject: [PATCH 39/59] Fix warning --- src/wast-parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 2628204c4e..5e49fb2753 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1359,7 +1359,7 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, Error(last_tok_loc, "Must specify " PRIstringview " for this symbol", WABT_PRINTF_STRING_VIEW_ARG(var.first)); }; - auto check_unseen = [this, &last_tok_loc](OnceProperty& var) { + auto check_unseen = [this](OnceProperty& var) { if (var.second) Error(*var.second, "Cannot specify " PRIstringview " for this symbol", WABT_PRINTF_STRING_VIEW_ARG(var.first)); From 96a44d6d0405b14a80a8e1f206702f63da782576 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Tue, 14 Oct 2025 00:11:27 +0300 Subject: [PATCH 40/59] Fix narrowing conversion error on 32-bit machines --- src/binary-reader-ir.cc | 3 ++- src/ir.cc | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index e072d2d0dd..41e33be786 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -1818,7 +1818,8 @@ Result BinaryReaderIR::OnDataSymbol(Index index, data_symbols.emplace(sym); assert(index == table.symbols().size()); table.AddSymbol( - {name2, flags, Symbol::Data{sym.segment, sym.offset, sym.size}}); + {name2, flags, + Symbol::Data{sym.segment, static_cast(sym.offset), sym.size}}); if (name.empty()) { return Result::Ok; } diff --git a/src/ir.cc b/src/ir.cc index 301678696c..2d47934a0d 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -165,8 +165,10 @@ Result SymbolTable::Populate(const Module* module) { add(module->tags, [](Index i, auto&) { return Symbol::Tag{i}; }); for (size_t i = 0; i < module->data_symbols.size(); ++i) { auto& sym = module->data_symbols[i]; - CHECK_RESULT(AddSymbol({sym.name_, sym.flags_, - Symbol::Data{sym.segment, sym.offset, sym.size}})); + CHECK_RESULT( + AddSymbol({sym.name_, sym.flags_, + Symbol::Data{sym.segment, static_cast(sym.offset), + sym.size}})); EnlargeFor(datas_, i); datas_[i] = symbols().size() - 1; } From 62fd9aa423074501bf9a54540cf105f382a5d4c5 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Tue, 14 Oct 2025 03:02:58 +0300 Subject: [PATCH 41/59] Error instead of failing assert in OnRelocCount --- src/binary-reader-ir.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 41e33be786..94d88f438b 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -1973,7 +1973,19 @@ Result BinaryReaderIR::BeginElemSection(Offset size) { Result BinaryReaderIR::OnRelocCount(Index count, Index section_index) { active_reloc_section = reloc_queues.find(section_index); - assert(GetQueue()); + if (!GetQueue()) { + if (active_section < section_index) { + PrintError( + "Relocation section [%d] does not follow its target section [%d]", + active_section, section_index); + } else { + PrintError( + "The target section for the relocation section [%d] does not have a " + "valid index [%d]", + active_section, section_index); + } + return Result::Error; + } return Result::Ok; } From c01759f4f29f8685476276857263cd2883220cc4 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Tue, 14 Oct 2025 04:18:51 +0300 Subject: [PATCH 42/59] Work around msvc SKILL ISSUE, take 1 --- src/ir.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ir.cc b/src/ir.cc index 2d47934a0d..2880f611ae 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -138,14 +138,13 @@ void EnlargeFor(std::vector& v, Index i) { Result SymbolTable::AddSymbol(Symbol sym) { sym.visit([this](auto type) { - using T = decltype(type); - if constexpr (!std::is_same_v && - !std::is_same_v) { - EnlargeFor(GetTable(), type.index); + if constexpr (!std::is_same_v && + !std::is_same_v) { + EnlargeFor(GetTable(), type.index); // This is lossy since multiple symbols are genuinely possible, but apart // from data symbols their semantics is not very clear - if (GetTable()[type.index] == kInvalidIndex) - GetTable()[type.index] = symbols_.size(); + if (GetTable()[type.index] == kInvalidIndex) + GetTable()[type.index] = symbols_.size(); } }); symbols_.push_back(sym); From ddf521de11a39e95640d3b15dd0b3390ac5ee5e0 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Tue, 14 Oct 2025 04:27:42 +0300 Subject: [PATCH 43/59] Work around msvc SKILL ISSUE, take 2 --- src/ir.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ir.cc b/src/ir.cc index 2880f611ae..053237ccc7 100644 --- a/src/ir.cc +++ b/src/ir.cc @@ -140,11 +140,12 @@ Result SymbolTable::AddSymbol(Symbol sym) { sym.visit([this](auto type) { if constexpr (!std::is_same_v && !std::is_same_v) { - EnlargeFor(GetTable(), type.index); + auto& table = this->GetTable(); + EnlargeFor(table, type.index); // This is lossy since multiple symbols are genuinely possible, but apart // from data symbols their semantics is not very clear - if (GetTable()[type.index] == kInvalidIndex) - GetTable()[type.index] = symbols_.size(); + if (table[type.index] == kInvalidIndex) + table[type.index] = symbols_.size(); } }); symbols_.push_back(sym); From 87259c4d40d868b9878fb6bbb3d4e82adcfca843 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Tue, 14 Oct 2025 05:06:52 +0300 Subject: [PATCH 44/59] Exit early on invalid symtab --- src/binary-reader.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/binary-reader.cc b/src/binary-reader.cc index cbdd3384f8..434e15bf9e 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -2341,6 +2341,9 @@ Result BinaryReader::ReadLinkingSection(Offset section_size) { CALLBACK(OnSectionSymbol, i, flags, index); break; } + default: + PrintError("Unknown symbol type: %d", static_cast(sym_type)); + return Result::Error; } } break; From 5f7f384e9ef59059a1767b79a33918eb1e559552 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 19 Oct 2025 03:18:46 +0300 Subject: [PATCH 45/59] Fix invalid treatment of data imports --- src/binary-reader-ir.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 94d88f438b..2fb3120ca5 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -2031,7 +2031,7 @@ Result BinaryReaderIR::EndModule() { size_t i = 0; Index range_start = 0, data_segment = -1; for (auto& datasym : data_symbols) { - if (datasym.segment >= module_->data_segments.size()) + if (datasym.segment >= module_->data_segments.size() && datasym.segment != kInvalidIndex) // all further symbols are invalid break; if (datasym.segment != data_segment) { From 8c1da43f864e1ec26d4c2706916dffbb4a0718b8 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 19 Oct 2025 03:21:43 +0300 Subject: [PATCH 46/59] Assume all leb relocs of primary shapes are valid in the code section --- src/binary-reader-ir.cc | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index 2fb3120ca5..b305e235c0 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -418,8 +418,14 @@ class BinaryReaderIR : public BinaryReaderNop { // Queue instructions to patch struct RelocQueue { - RelocQueue(Offset start) - : start(start), incoming_relocs(), entries(), data_segment_starts() {} + enum Type { + CODE, + DATA, + CUSTOM, + }; + + RelocQueue(Offset start, Type type) + : start(start), type(type), incoming_relocs(), entries(), data_segment_starts() {} template using Entries = std::tuple...>; @@ -434,6 +440,7 @@ class BinaryReaderIR : public BinaryReaderNop { } Offset start; + Type type; std::vector incoming_relocs; Entries entries; std::map data_segment_starts; @@ -444,7 +451,7 @@ class BinaryReaderIR : public BinaryReaderNop { std::multiset data_symbols; Index active_section = kInvalidIndex; - void MakeQueue(); + void MakeQueue(RelocQueue::Type); RelocQueue* GetQueue(); }; @@ -1941,10 +1948,10 @@ Result BinaryReaderIR::OnReloc(RelocType type, GetQueue()->incoming_relocs.emplace_back(type, offset, index, addend); return Result::Ok; } -void BinaryReaderIR::MakeQueue() { +void BinaryReaderIR::MakeQueue(RelocQueue::Type t) { assert(active_section != kInvalidIndex); active_reloc_section = - reloc_queues.insert({active_section, RelocQueue{state->offset}}).first; + reloc_queues.insert({active_section, RelocQueue{state->offset, t}}).first; } BinaryReaderIR::RelocQueue* BinaryReaderIR::GetQueue() { if (active_reloc_section != end(reloc_queues)) @@ -1953,21 +1960,21 @@ BinaryReaderIR::RelocQueue* BinaryReaderIR::GetQueue() { } Result BinaryReaderIR::BeginCodeSection(Offset size) { - MakeQueue(); + MakeQueue(RelocQueue::CODE); return Result::Ok; } Result BinaryReaderIR::BeginDataSection(Offset size) { - MakeQueue(); + MakeQueue(RelocQueue::DATA); return Result::Ok; } Result BinaryReaderIR::BeginGenericCustomSection(Offset size) { + MakeQueue(RelocQueue::CUSTOM); return Result::Ok; } Result BinaryReaderIR::BeginElemSection(Offset size) { - MakeQueue(); return Result::Ok; } @@ -2119,6 +2126,19 @@ Result BinaryReaderIR::EndModule() { // We pray that the relocation is always the last operand, and that the // operand is an overlong leb already auto reloc_addr = reloc.offset + reloc_size; + if (queue.type == RelocQueue::CODE && kRelocDataType[int(reloc.type)] == RelocDataType::LEB) { + switch (kRelocSymbolType[int(reloc.type)]) { + case RelocKind::Global: + case RelocKind::Type: + case RelocKind::Table: + case RelocKind::Function: + // Assume all relocations of primary shape are valid, we have no way + // to check + continue; + default: + break; + } + } queue.traverse([&](auto& insns) { auto insn = insns.find(reloc_addr); if (insn != end(insns)) { From b61fa7a63385aaac6bc4926bf737f25188c15ff8 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 19 Oct 2025 04:11:21 +0300 Subject: [PATCH 47/59] Skip raw output of linking and reloc sections when outputting relocations --- src/wat-writer.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wat-writer.cc b/src/wat-writer.cc index ceaab64c61..dab08cd6dd 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -1953,6 +1953,10 @@ Result WatWriter::WriteModule() { } if (options_.features.annotations_enabled()) { for (const Custom& custom : module.customs) { + if (custom.name == "linking") + continue; + if (std::string_view{custom.name}.substr(0, 6) == "reloc." && options_.relocatable) + continue; WriteCustom(custom); } } From b72e498472d0a49f2316b4b30e3cefd056fc9357 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 23 Oct 2025 06:13:25 +0300 Subject: [PATCH 48/59] Add an operator bool so that conversion to bool is no longer counterintuitive --- include/wabt/result.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/wabt/result.h b/include/wabt/result.h index a40faab78b..a425fd15f7 100644 --- a/include/wabt/result.h +++ b/include/wabt/result.h @@ -28,6 +28,7 @@ struct Result { Result() : Result(Ok) {} Result(Enum e) : enum_(e) {} operator Enum() const { return enum_; } + operator bool() const { return enum_ == Ok; } Result& operator|=(Result rhs); private: From 03634d233e871051d490d48073fe97a42bf88bd9 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Thu, 23 Oct 2025 06:14:09 +0300 Subject: [PATCH 49/59] Edit symbol parsers to reflect the new syntax --- include/wabt/common.h | 2 + include/wabt/wast-parser.h | 23 +++-- src/wast-parser.cc | 180 +++++++++++++++++++++++++++---------- 3 files changed, 151 insertions(+), 54 deletions(-) diff --git a/include/wabt/common.h b/include/wabt/common.h index 692c622bd6..5e5fb55fad 100644 --- a/include/wabt/common.h +++ b/include/wabt/common.h @@ -308,6 +308,7 @@ enum class RelocType { }; enum class RelocDataType { + None, I32, I64, LEB, LEB64, SLEB, SLEB64, @@ -350,6 +351,7 @@ constexpr RelocDataType kRelocDataType[] { }; enum class RelocKind { + None, Function, FunctionTbl, Data, diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 354b1b72ca..7d225cda09 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "wabt/error.h" #include "wabt/feature.h" @@ -68,6 +69,10 @@ class WastParser { Var name; Address size; }; + struct FuncsymAux { + std::optional priority; + }; + using SymAux = std::variant; typedef std::vector ReferenceVars; @@ -217,8 +222,8 @@ class WastParser { Result ParseSymAfterPar(SymbolCommon*, bool in_import, - DatasymAux* dat_sym = 0); - Result ParseSymOpt(SymbolCommon *, bool in_import, DatasymAux *dat_sym = 0); + SymAux dat_sym = {}); + Result ParseSymOpt(SymbolCommon *, bool in_import, SymAux dat_sym = {}); Result ParseDataImport(Module* module); Result ParseExportDesc(Export*); Result ParseInlineExports(ModuleFieldList*, ExternalKind); @@ -241,12 +246,20 @@ class WastParser { Result ParseInstr(ExprList*); Result ParseRejectReloc(); Result ParseUnwindReloc(int curr_indent); - Result ParseRelocAfterType(IrReloc*, RelocDataType type); + Result ParseRelocAddend( + uint32_t* addend, + Var* name = nullptr); Result ParseRelocModifiers(RelocModifiers*); Result ParseRelocKind(RelocKind*); Result ParseRelocDataType(RelocDataType*); - Result ParseReloc(IrReloc*); - Result ParseReloc(IrReloc*, RelocDataType type); + Result ParseReloc(bool opt, + IrReloc*, + RelocDataType = RelocDataType::None, + RelocKind = RelocKind::None, + Var* = nullptr, + bool data_default = false, + bool kind_default = false, + bool name_default = false); Result ParseCodeMetadataAnnotation(ExprList*); Result ParsePlainInstr(std::unique_ptr*); Result ParseF32(Const*, ConstType type); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 5e49fb2753..ba509739a3 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1335,7 +1335,7 @@ bool WastParser::PeekIsDataImport() { Result WastParser::ParseSymAfterPar(SymbolCommon* sym, bool in_import, - DatasymAux* data) { + SymAux aux) { using OnceProperty = std::pair>; Location last_tok_loc; @@ -1344,6 +1344,7 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, OnceProperty retain{"retain", {}}; OnceProperty name{"name", {}}; OnceProperty size{"size", {}}; + OnceProperty priority{"priority", {}}; auto check_once = [this, &last_tok_loc](OnceProperty& var) { if (!var.second) @@ -1369,24 +1370,51 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, if (in_import && (sym->flags_ & uint32_t(SymbolBinding::Local))) { Error(*visibility.second, "static symbol cannot be an import"); } - if (data) { + if (std::get_if(&aux)) { if (!in_import) check_seen(size); check_seen(name); } else { check_unseen(size); } + if (!std::get_if(&aux)) + check_unseen(priority); }; - if (data) { - ParseVarOpt(&data->name, data->name); + if (auto *data = std::get_if(&aux)) { + ParseVarOpt(&(*data)->name, (*data)->name); } for (;;) { last_tok_loc = GetLocation(); if (Match(TokenType::Rpar)) { validate(); return Result::Ok; - } else if (MatchText(TokenType::Reserved, "static")) { + } else if (Match(TokenType::Lpar)) { + last_tok_loc = GetLocation(); + if (MatchText(TokenType::Reserved, "name")) { + check_once(name); + if (!ParseQuotedText(&sym->name_)) + goto fail; + sym->flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } else if (MatchText(TokenType::Reserved, "size")) { + check_once(size); + Address res; + if (!ParseNat(&res, true)) + goto fail; + if (auto *data = std::get_if(&aux)) + (*data)->size = res; + } else if (MatchText(TokenType::Reserved, "init_prio")) { + check_once(priority); + Address res; + if (!ParseNat(&res, true)) + goto fail; + if (auto *data = std::get_if(&aux)) + (*data)->priority = res; + } + fail: + if (!Expect(TokenType::Rpar)) + ParseUnwindReloc(1); + } else if (Match(TokenType::Local)) { check_once(binding); sym->flags_ |= uint32_t(SymbolBinding::Local); } else if (MatchText(TokenType::Reserved, "weak")) { @@ -1395,13 +1423,6 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, } else if (MatchText(TokenType::Reserved, "retain")) { check_once(retain); sym->flags_ |= WABT_SYMBOL_FLAG_NO_STRIP; - } else if (auto sym_name = MatchTextPrefix(TokenType::Reserved, "name=")) { - check_once(name); - RemoveEscapes(*sym_name, std::back_inserter(sym->name_)); - sym->flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; - } else if (auto sym_size = MatchTextPrefix(TokenType::Reserved, "size=")) { - check_once(size); - CHECK_RESULT(ParseUint64(*sym_size, &data->size)); } else if (MatchText(TokenType::Reserved, "hidden")) { check_once(visibility); sym->flags_ |= uint32_t(SymbolVisibility::Hidden); @@ -1413,7 +1434,7 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, Result WastParser::ParseSymOpt(SymbolCommon* sym, bool in_import, - DatasymAux* dat_sym) { + SymAux dat_sym) { sym->flags_ |= in_import ? WABT_SYMBOL_FLAG_UNDEFINED : 0; if (!IsLparAnn(PeekPair())) return Result::Ok; @@ -1649,7 +1670,7 @@ Result WastParser::ParseDataModuleField(Module* module) { size_t offset = field->data_segment.data.size(); if (tok.text() == "reloc") { IrReloc r; - ParseReloc(&r); + ParseReloc(true, &r); size_t reloc_size = kRelocDataTypeSize[int(kRelocDataType[int(r.type)])]; field->data_segment.relocs.push_back({offset - reloc_size, r}); @@ -1825,7 +1846,9 @@ Result WastParser::ParseFuncModuleField(Module* module) { CheckImportOrdering(module); auto import = std::make_unique(name); Func& func = import->func; - CHECK_RESULT(ParseSymOpt(&func, true)); + FuncsymAux aux; + CHECK_RESULT(ParseSymOpt(&func, true, &aux)); + func.priority = aux.priority; CHECK_RESULT(ParseInlineImport(import.get())); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings)); @@ -1837,7 +1860,9 @@ Result WastParser::ParseFuncModuleField(Module* module) { auto field = std::make_unique(loc, name); Func& func = field->func; func.loc = GetLocation(); - CHECK_RESULT(ParseSymOpt(&func, false)); + FuncsymAux aux; + CHECK_RESULT(ParseSymOpt(&func, false, &aux)); + func.priority = aux.priority; if (!name.empty() && !func.explicit_name()) func.name_ = name.substr(1); CHECK_RESULT(ParseTypeUseOpt(&func.decl)); @@ -2009,7 +2034,9 @@ Result WastParser::ParseImportModuleField(Module* module) { Consume(); ParseBindVarOpt(&name); auto import = std::make_unique(name); - CHECK_RESULT(ParseSymOpt(&import->func, true)); + FuncsymAux aux; + CHECK_RESULT(ParseSymOpt(&import->func, true, &aux)); + import->func.priority = aux.priority; CHECK_RESULT(ParseTypeUseOpt(&import->func.decl)); CHECK_RESULT( ParseFuncSignature(&import->func.decl.sig, &import->func.bindings)); @@ -2471,22 +2498,33 @@ Result WastParser::ParseUnwindReloc(int curr_indent) { } return Result::Ok; } -Result WastParser::ParseRelocAfterType(IrReloc* reloc, RelocDataType type) { - RelocKind kind; - CHECK_RESULT(ParseRelocKind(&kind)); - RelocModifiers mod; - CHECK_RESULT(ParseRelocModifiers(&mod)); - RelocType reloc_type = RecognizeReloc(kind, type, mod); - if (reloc_type == RelocType::None) { - Error(GetLocation(), "Invalid relocation"); - return ParseUnwindReloc(1); + +Result WastParser::ParseRelocAddend(uint32_t* addend, + Var* name) { + if (PeekMatch(TokenType::Rpar)) { + if (addend) + *addend = 0; + return Result::Ok; + } + if (!addend) + return Result::Error; + Token curr = GetToken(); + if (name && Match(TokenType::Var)) { + *name = Var{curr.text(), curr.loc}; + return Result::Ok; } - Var target; - ParseVar(&target); - *reloc = {reloc_type, target}; - CHECK_RESULT(Expect(TokenType::Rpar)); + if (!Expect(TokenType::Int)) { + return Result::Error; + } + auto sv = curr.literal().text; + if (!ParseInt32(sv, addend, ParseIntType::SignedAndUnsigned)) + ErrorExpected({"integer with sign"}, "+123"); + if (sv.find_first_of("+-") != 0) + return ErrorExpected({"integer with sign"}, + ("+" + std::string(sv)).c_str()); return Result::Ok; } + Result WastParser::ParseRelocModifiers(RelocModifiers* mod) { *mod = RelocModifiers::None; Token tok = GetToken(); @@ -2587,22 +2625,66 @@ Result WastParser::ParseRelocDataType(RelocDataType* type) { } else return Result::Error; } -Result WastParser::ParseReloc(IrReloc* reloc) { - Token tok = GetToken(); - if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { - Consume(); - RelocDataType t; - CHECK_RESULT(ParseRelocDataType(&t)); - return ParseRelocAfterType(reloc, t); - } - return Result::Ok; -} -Result WastParser::ParseReloc(IrReloc* reloc, RelocDataType type) { + +Result WastParser::ParseReloc(bool opt, + IrReloc* reloc, + RelocDataType data, + RelocKind kind, + Var* name, + bool data_default, + bool kind_default, + bool name_default) { Token tok = GetToken(); + Result res = Result::Ok; + RelocModifiers mod = RelocModifiers::None; + Var sym_name; + Var addend_name; + uint32_t addend_num; + if (tok.token_type() == TokenType::LparAnn && tok.text() == "reloc") { Consume(); - return ParseRelocAfterType(reloc, type); + if (data == RelocDataType::None) + res |= ParseRelocDataType(&data); + else if (data_default) + ParseRelocDataType(&data); + + if (kind == RelocKind::None) + res |= ParseRelocKind(&kind); + else if (kind_default) + ParseRelocKind(&kind); + + ParseRelocModifiers(&mod); + + if (!name) + res |= ParseVar(&sym_name); + else if (name_default) + ParseVar(&sym_name); + else + sym_name = *name; + + bool text_addend_allowed = + kind == RelocKind::Text || kind == RelocKind::Section; + bool addend_allowed = kind == RelocKind::Data || text_addend_allowed; + ParseRelocAddend(addend_allowed ? &addend_num : nullptr, + text_addend_allowed ? &addend_name : nullptr); + if (!Expect(TokenType::Rpar)) { + res = Result::Error; + ParseUnwindReloc(1); + } + } else if (!name || kind == RelocKind::None || data == RelocDataType::None) { + if (opt) + return Result::Ok; + return ErrorExpected({"relocation annotation"}, "(@reloc $foo)"); } + + RelocType reloc_type = RecognizeReloc(kind, data, mod); + if (reloc_type == RelocType::None) + res = Result::Error; + CHECK_RESULT(res); + + reloc->type = reloc_type; + reloc->addend = addend_num; + return Result::Ok; } @@ -2673,14 +2755,14 @@ Result WastParser::ParseLoadStoreInstr(Location loc, IrReloc reloc; CHECK_RESULT(ParseMemidx(loc, &memidx)); ParseOffsetOpt(&offset); - if constexpr (relocatable) { - CHECK_RESULT(ParseReloc(&reloc, RelocDataType::LEB)); - } + if constexpr (relocatable) + CHECK_RESULT(ParseReloc(true, &reloc, RelocDataType::LEB, RelocKind::Data, + nullptr, false, true)); ParseAlignOpt(&align); T* expr = new T(opcode, memidx, align, offset, loc); - if constexpr (relocatable) { + if constexpr (relocatable) expr->reloc = reloc; - } + out_expr->reset(expr); return Result::Ok; } @@ -2904,9 +2986,9 @@ Result WastParser::ParsePlainInstr(std::unique_ptr* out_expr) { auto expr = new ConstExpr(const_, loc); out_expr->reset(expr); if (const_.type() == Type::I64) - CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::SLEB64)); + CHECK_RESULT(ParseReloc(true, &expr->reloc, RelocDataType::SLEB64)); else if (const_.type() == Type::I32) - CHECK_RESULT(ParseReloc(&expr->reloc, RelocDataType::SLEB)); + CHECK_RESULT(ParseReloc(true, &expr->reloc, RelocDataType::SLEB)); else CHECK_RESULT(ParseRejectReloc()); break; From 509ee7bfe6e866e2717d44c1997b568521555dc1 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 23 Nov 2025 15:01:12 +0200 Subject: [PATCH 50/59] Fix addend output --- src/binary-writer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 9451587176..7e5076e9b2 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -1044,7 +1044,7 @@ void BinaryWriter::WriteRelocSection(const RelocSection* reloc_section) { case RelocType::SectionOffsetI32: case RelocType::MemoryAddressTLSSLEB: case RelocType::MemoryAddressTLSSLEB64: - WriteU32Leb128(stream_, reloc.addend, "reloc addend"); + WriteS32Leb128(stream_, reloc.addend, "reloc addend"); break; case RelocType::FuncIndexLEB: case RelocType::FuncIndexI32: From 901adb84eae927a2a0ae7db3c218d80e41b74c14 Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 23 Nov 2025 15:01:29 +0200 Subject: [PATCH 51/59] Write init section --- src/binary-writer.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 7e5076e9b2..4cbaaab8a5 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -1072,6 +1072,7 @@ void BinaryWriter::WriteLinkingSection() { BeginCustomSection(WABT_BINARY_SECTION_LINKING); WriteU32Leb128(stream_, 2, "metadata version"); const std::vector& symbols = symtab_.symbols(); + int has_init = 0; if (symbols.size()) { stream_->WriteU8Enum(LinkingEntryType::SymbolTable, "symbol table"); BeginSubsection("symbol table"); @@ -1086,6 +1087,9 @@ void BinaryWriter::WriteLinkingSection() { if (sym.defined() || sym.explicit_name()) { WriteStr(stream_, sym.name(), "function name", PrintChars::Yes); } + if (module_->funcs[sym.AsFunction().index]->priority) { + ++has_init; + } break; case SymbolType::Data: WriteStr(stream_, sym.name(), "data name", PrintChars::Yes); @@ -1119,6 +1123,24 @@ void BinaryWriter::WriteLinkingSection() { } } EndSubsection(); + + if (has_init) { + stream_->WriteU8Enum(LinkingEntryType::InitFunctions, "initializsers"); + BeginSubsection("initializsers"); + WriteU32Leb128(stream_, has_init, "initializser count"); + int i = 0; + for (const Symbol& sym : symbols) { + if (sym.IsFunction()) { + auto &prio = module_->funcs[sym.AsFunction().index]->priority; + if (prio) { + WriteU32Leb128(stream_, *prio, "priority"); + WriteU32Leb128(stream_, i, "func id"); + } + } + ++i; + } + EndSubsection(); + } } EndSection(); } From a67b573e007f0148027a8afbce36145ea77e04fb Mon Sep 17 00:00:00 2001 From: feedable <141534996+feedab1e@users.noreply.github.com> Date: Sun, 23 Nov 2025 15:02:44 +0200 Subject: [PATCH 52/59] Actually write relocations in wasm2wat --- src/wat-writer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wat-writer.cc b/src/wat-writer.cc index dab08cd6dd..424d5e3463 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -523,6 +523,7 @@ void WatWriter::WriteConst(const ConstExpr& expr) { assert(0); break; } + WriteReloc(expr.reloc, false); } template From a756968f821ba64b9fe628420f61fafebd386a35 Mon Sep 17 00:00:00 2001 From: feedable Date: Sat, 10 Jan 2026 15:27:44 +0200 Subject: [PATCH 53/59] Fix reloc datatype size enum --- include/wabt/common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/wabt/common.h b/include/wabt/common.h index 5e5fb55fad..7d2b8472bf 100644 --- a/include/wabt/common.h +++ b/include/wabt/common.h @@ -315,6 +315,7 @@ enum class RelocDataType { }; constexpr size_t kRelocDataTypeSize[] { + 0, 4, 8, 5, 10, 5, 10 From cfbfdff4d5120418900cf229466263549e4e4a7f Mon Sep 17 00:00:00 2001 From: feedable Date: Sat, 10 Jan 2026 15:28:53 +0200 Subject: [PATCH 54/59] Avoid UB in ParseDataImport --- src/wast-parser.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index ba509739a3..2a2a6090a9 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1446,9 +1446,9 @@ Result WastParser::ParseSymOpt(SymbolCommon* sym, } Result WastParser::ParseDataImport(Module* module) { - DataSym sym; + DataSym sym{}; DatasymAux aux; - sym.flags_ |= WABT_SYMBOL_FLAG_UNDEFINED; + sym.flags_ = WABT_SYMBOL_FLAG_UNDEFINED; if (!IsLparAnn(PeekPair())) return Result::Ok; Token tok = GetToken(); From cd9d67ab341a099f301ca568c07d3e74ad994cd4 Mon Sep 17 00:00:00 2001 From: feedable Date: Sat, 10 Jan 2026 15:29:13 +0200 Subject: [PATCH 55/59] Avoid UB in ParseSymAfterPar validation --- src/wast-parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 2a2a6090a9..2b8bd8c43d 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1368,7 +1368,7 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, auto validate = [&] { if (in_import && (sym->flags_ & uint32_t(SymbolBinding::Local))) { - Error(*visibility.second, "static symbol cannot be an import"); + Error(*binding.second, "static symbol cannot be an import"); } if (std::get_if(&aux)) { if (!in_import) From 1d777c54784fe8e45b007b9019c487952b225ba1 Mon Sep 17 00:00:00 2001 From: feedable Date: Sat, 10 Jan 2026 15:29:41 +0200 Subject: [PATCH 56/59] Initialize DataSym in ParseDataModuleField --- src/wast-parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 2b8bd8c43d..d1b46ead8e 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1677,7 +1677,7 @@ Result WastParser::ParseDataModuleField(Module* module) { continue; } if (tok.text() == "sym") { - DataSym sym; + DataSym sym{}; Index sym_idx = module->data_symbols.size(); DatasymAux aux = {Var{sym_idx, GetLocation()}, 0}; ParseSymOpt(&sym, false, &aux); From c84cd03e3e2780153506f432405526968048f095 Mon Sep 17 00:00:00 2001 From: feedable Date: Sat, 10 Jan 2026 15:30:36 +0200 Subject: [PATCH 57/59] Actually set rerloc destination --- src/wast-parser.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wast-parser.cc b/src/wast-parser.cc index d1b46ead8e..3701fd8dc7 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -2684,6 +2684,7 @@ Result WastParser::ParseReloc(bool opt, reloc->type = reloc_type; reloc->addend = addend_num; + reloc->symbol = sym_name; return Result::Ok; } From 63785fa6f9a213e6c7cd12117c17908df676a447 Mon Sep 17 00:00:00 2001 From: feedable Date: Tue, 24 Feb 2026 19:45:09 +0200 Subject: [PATCH 58/59] Add data segment metadata --- include/wabt/ir.h | 9 + include/wabt/token.def | 11 +- include/wabt/wast-parser.h | 6 +- src/binary-writer.cc | 11 + src/lexer-keywords.txt | 9 + src/prebuilt/lexer-keywords.cc | 2728 +++++++++++++++++--------------- src/wast-parser.cc | 140 +- 7 files changed, 1549 insertions(+), 1365 deletions(-) diff --git a/include/wabt/ir.h b/include/wabt/ir.h index 66d89cabd1..01da26107c 100644 --- a/include/wabt/ir.h +++ b/include/wabt/ir.h @@ -1065,6 +1065,15 @@ struct DataSegment { std::vector data; std::vector> relocs; std::pair symbol_range = {}; + struct SymInfo { + std::string name = ""; + Offset align = 0; + enum Flags: uint32_t { + WASM_SEGMENT_FLAG_STRINGS = 1, + WASM_SEGMENT_FLAG_TLS = 2, + WASM_SEG_FLAG_RETAIN = 4, + } flags = {}; + } sym; }; class Import { diff --git a/include/wabt/token.def b/include/wabt/token.def index f2f05aec34..39fb663eb7 100644 --- a/include/wabt/token.def +++ b/include/wabt/token.def @@ -21,6 +21,7 @@ /* Tokens with no additional data (i.e. bare). */ WABT_TOKEN(Invalid, "Invalid") WABT_TOKEN(After, "after") +WABT_TOKEN(Align, "align") WABT_TOKEN(Array, "array") WABT_TOKEN(AssertException, "assert_exception") WABT_TOKEN(AssertExhaustion, "assert_exhaustion") @@ -45,7 +46,9 @@ WABT_TOKEN(Field, "field") WABT_TOKEN(Function, "function") WABT_TOKEN(Get, "get") WABT_TOKEN(Global, "global") +WABT_TOKEN(Hidden, "hidden") WABT_TOKEN(Import, "import") +WABT_TOKEN(InitPrio, "init_prio") WABT_TOKEN(Invoke, "invoke") WABT_TOKEN(Input, "input") WABT_TOKEN(Local, "local") @@ -53,6 +56,7 @@ WABT_TOKEN(Lpar, "(") WABT_TOKEN(Memory, "memory") WABT_TOKEN(Module, "module") WABT_TOKEN(Mut, "mut") +WABT_TOKEN(Name, "name") WABT_TOKEN(NanArithmetic, "nan:arithmetic") WABT_TOKEN(NanCanonical, "nan:canonical") WABT_TOKEN(Offset, "offset") @@ -62,13 +66,17 @@ WABT_TOKEN(Param, "param") WABT_TOKEN(Ref, "ref") WABT_TOKEN(Quote, "quote") WABT_TOKEN(Register, "register") +WABT_TOKEN(Retain, "retain") WABT_TOKEN(Result, "result") WABT_TOKEN(Rpar, ")") WABT_TOKEN(Shared, "shared") +WABT_TOKEN(Size, "size") WABT_TOKEN(Start, "start") +WABT_TOKEN(Strings, "strings") WABT_TOKEN(Struct, "struct") WABT_TOKEN(Table, "table") WABT_TOKEN(Then, "then") +WABT_TOKEN(TLS, "tls") WABT_TOKEN(Type, "type") WABT_TOKEN(I8X16, "i8x16") WABT_TOKEN(I16X8, "i16x8") @@ -76,8 +84,9 @@ WABT_TOKEN(I32X4, "i32x4") WABT_TOKEN(I64X2, "i64x2") WABT_TOKEN(F32X4, "f32x4") WABT_TOKEN(F64X2, "f64x2") +WABT_TOKEN(Weak, "weak") WABT_TOKEN_FIRST(Bare, Invalid) -WABT_TOKEN_LAST(Bare, F64X2) +WABT_TOKEN_LAST(Bare, Weak) /* Tokens with Literal data. */ WABT_TOKEN(Float, "FLOAT") diff --git a/include/wabt/wast-parser.h b/include/wabt/wast-parser.h index 7d225cda09..5b6479b42b 100644 --- a/include/wabt/wast-parser.h +++ b/include/wabt/wast-parser.h @@ -220,9 +220,9 @@ class WastParser { bool PeekIsCustom(); bool PeekIsDataImport(); - Result ParseSymAfterPar(SymbolCommon*, - bool in_import, - SymAux dat_sym = {}); + std::optional ParseSymAttrString(TokenType tag); + std::optional ParseSymAttrNumber(TokenType tag); + Result ParseSymSegment(DataSegment::SymInfo*); Result ParseSymOpt(SymbolCommon *, bool in_import, SymAux dat_sym = {}); Result ParseDataImport(Module* module); Result ParseExportDesc(Export*); diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 4cbaaab8a5..09c9aa7ad6 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -1073,6 +1073,17 @@ void BinaryWriter::WriteLinkingSection() { WriteU32Leb128(stream_, 2, "metadata version"); const std::vector& symbols = symtab_.symbols(); int has_init = 0; + + stream_->WriteU8Enum(LinkingEntryType::SegmentInfo, "segments table"); + BeginSubsection("segment table"); + WriteU32Leb128(stream_, module_->data_segments.size(), "segment count"); + for (auto &&seg : module_->data_segments) { + WriteStr(stream_, seg->sym.name, "segment name"); + WriteU32Leb128(stream_, seg->sym.align, "segment align"); + WriteU32Leb128(stream_, seg->sym.flags, "segment flags"); + } + EndSubsection(); + if (symbols.size()) { stream_->WriteU8Enum(LinkingEntryType::SymbolTable, "symbol table"); BeginSubsection("symbol table"); diff --git a/src/lexer-keywords.txt b/src/lexer-keywords.txt index 5923c7109c..d571d80bd3 100644 --- a/src/lexer-keywords.txt +++ b/src/lexer-keywords.txt @@ -19,6 +19,7 @@ struct TokenInfo { %% array, Type::Array, TokenType::Array after, TokenType::After +align, TokenType::Align assert_exception, TokenType::AssertException assert_exhaustion, TokenType::AssertExhaustion assert_invalid, TokenType::AssertInvalid @@ -190,6 +191,7 @@ get, TokenType::Get global.get, TokenType::GlobalGet, Opcode::GlobalGet global.set, TokenType::GlobalSet, Opcode::GlobalSet global, TokenType::Global +hidden, TokenType::Hidden i16x8.abs, TokenType::Unary, Opcode::I16X8Abs i16x8.add_sat_s, TokenType::Binary, Opcode::I16X8AddSatS i16x8.add_sat_u, TokenType::Binary, Opcode::I16X8AddSatU @@ -534,6 +536,7 @@ i8x16.sub, TokenType::Binary, Opcode::I8X16Sub i8x16, TokenType::I8X16 if, TokenType::If, Opcode::If import, TokenType::Import +init_prio, TokenType::InitPrio input, TokenType::Input invoke, TokenType::Invoke item, TokenType::Item @@ -555,6 +558,7 @@ module, TokenType::Module mut, TokenType::Mut nan:arithmetic, TokenType::NanArithmetic nan:canonical, TokenType::NanCanonical +name, TokenType::Name nop, TokenType::Nop, Opcode::Nop offset, TokenType::Offset output, TokenType::Output @@ -568,13 +572,16 @@ ref.is_null, TokenType::RefIsNull, Opcode::RefIsNull ref.null, TokenType::RefNull, Opcode::RefNull register, TokenType::Register result, TokenType::Result +retain, TokenType::Retain rethrow, TokenType::Rethrow, Opcode::Rethrow return_call_indirect, TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect return_call, TokenType::ReturnCall, Opcode::ReturnCall return, TokenType::Return, Opcode::Return select, TokenType::Select, Opcode::Select shared, TokenType::Shared +size, TokenType::Size start, TokenType::Start +strings, TokenType::Strings struct, Type::Struct, TokenType::Struct table.copy, TokenType::TableCopy, Opcode::TableCopy table.fill, TokenType::TableFill, Opcode::TableFill @@ -587,10 +594,12 @@ table, TokenType::Table then, TokenType::Then throw, TokenType::Throw, Opcode::Throw throw_ref, TokenType::ThrowRef, Opcode::ThrowRef +tls, TokenType::TLS try, TokenType::Try, Opcode::Try try_table, TokenType::TryTable, Opcode::TryTable type, TokenType::Type unreachable, TokenType::Unreachable, Opcode::Unreachable +weak, TokenType::Weak v128.andnot, TokenType::Binary, Opcode::V128Andnot v128.and, TokenType::Binary, Opcode::V128And v128.bitselect, TokenType::Ternary, Opcode::V128BitSelect diff --git a/src/prebuilt/lexer-keywords.cc b/src/prebuilt/lexer-keywords.cc index 89f14dbaca..0b18c5025c 100644 --- a/src/prebuilt/lexer-keywords.cc +++ b/src/prebuilt/lexer-keywords.cc @@ -1,4 +1,4 @@ -/* C++ code produced by gperf version 3.1 */ +/* C++ code produced by gperf version 3.3 */ /* Command-line: gperf -m 50 -L C++ -N InWordSet -E -t -c --output-file=src/prebuilt/lexer-keywords.cc src/lexer-keywords.txt */ /* Computed positions: -k'1,3,5-8,10,12,15,17-19,23,27,$' */ @@ -48,7 +48,7 @@ struct TokenInfo { Opcode opcode; }; }; -/* maximum key range = 2193, duplicates = 0 */ +/* maximum key range = 2332, duplicates = 0 */ class Perfect_Hash { @@ -63,32 +63,32 @@ Perfect_Hash::hash (const char *str, size_t len) { static unsigned short asso_values[] = { - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 13, 2230, 2230, 426, - 351, 14, 17, 13, 176, 531, 32, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 183, 13, 16, 811, 21, - 68, 16, 326, 13, 347, 223, 20, 13, 15, 140, - 80, 54, 559, 611, 14, 15, 24, 13, 556, 521, - 125, 416, 213, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, 2230, - 2230, 2230, 2230, 2230, 2230, 2230, 2230 + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2, 2341, 2341, 448, + 310, 2, 31, 1, 331, 255, 90, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 225, 1, 3, 723, 30, + 73, 1, 385, 6, 449, 332, 2, 1, 14, 136, + 65, 101, 439, 655, 8, 3, 3, 1, 482, 664, + 143, 231, 119, 3, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, 2341, + 2341, 2341, 2341, 2341, 2341, 2341, 2341 }; unsigned int hval = len; @@ -96,54 +96,119 @@ Perfect_Hash::hash (const char *str, size_t len) { default: hval += asso_values[static_cast(str[26])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 26: case 25: case 24: case 23: hval += asso_values[static_cast(str[22])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 22: case 21: case 20: case 19: hval += asso_values[static_cast(str[18])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 18: hval += asso_values[static_cast(str[17])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 17: hval += asso_values[static_cast(str[16])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 16: case 15: hval += asso_values[static_cast(str[14])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 14: case 13: case 12: hval += asso_values[static_cast(str[11])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 11: case 10: hval += asso_values[static_cast(str[9])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 9: case 8: hval += asso_values[static_cast(str[7])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 7: hval += asso_values[static_cast(str[6])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 6: hval += asso_values[static_cast(str[5])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 5: hval += asso_values[static_cast(str[4])]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 4: case 3: hval += asso_values[static_cast(str[2]+1)]; +#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9))) + [[fallthrough]]; +#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10) + __attribute__ ((__fallthrough__)); +#endif /*FALLTHROUGH*/ case 2: case 1: @@ -158,1499 +223,1581 @@ Perfect_Hash::InWordSet (const char *str, size_t len) { enum { - TOTAL_KEYWORDS = 601, + TOTAL_KEYWORDS = 610, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 35, - MIN_HASH_VALUE = 37, - MAX_HASH_VALUE = 2229 + MIN_HASH_VALUE = 9, + MAX_HASH_VALUE = 2340 }; +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif static struct TokenInfo wordlist[] = { {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 35 "src/lexer-keywords.txt" - {"br", TokenType::Br, Opcode::Br}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 152 "src/lexer-keywords.txt" - {"f64", Type::F64}, - {""}, {""}, -#line 45 "src/lexer-keywords.txt" +#line 46 "src/lexer-keywords.txt" {"data", TokenType::Data}, - {""}, {""}, {""}, -#line 464 "src/lexer-keywords.txt" - {"i64", Type::I64}, +#line 597 "src/lexer-keywords.txt" + {"tls", TokenType::TLS}, +#line 582 "src/lexer-keywords.txt" + {"size", TokenType::Size}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 122 "src/lexer-keywords.txt" - {"f32x4", TokenType::F32X4}, - {""}, {""}, {""}, {""}, -#line 586 "src/lexer-keywords.txt" - {"table", TokenType::Table}, -#line 48 "src/lexer-keywords.txt" - {"do", TokenType::Do}, -#line 364 "src/lexer-keywords.txt" - {"i32x4", TokenType::I32X4}, - {""}, {""}, {""}, -#line 135 "src/lexer-keywords.txt" +#line 136 "src/lexer-keywords.txt" {"f64.ge", TokenType::Compare, Opcode::F64Ge}, -#line 74 "src/lexer-keywords.txt" +#line 75 "src/lexer-keywords.txt" {"f32.ge", TokenType::Compare, Opcode::F32Ge}, + {""}, {""}, #line 137 "src/lexer-keywords.txt" - {"f64.le", TokenType::Compare, Opcode::F64Le}, -#line 76 "src/lexer-keywords.txt" - {"f32.le", TokenType::Compare, Opcode::F32Le}, - {""}, {""}, {""}, {""}, {""}, -#line 30 "src/lexer-keywords.txt" - {"before", TokenType::Before}, - {""}, {""}, {""}, {""}, {""}, -#line 187 "src/lexer-keywords.txt" - {"func", Type::FuncRef, TokenType::Func}, -#line 136 "src/lexer-keywords.txt" {"f64.gt", TokenType::Compare, Opcode::F64Gt}, -#line 75 "src/lexer-keywords.txt" +#line 76 "src/lexer-keywords.txt" {"f32.gt", TokenType::Compare, Opcode::F32Gt}, -#line 139 "src/lexer-keywords.txt" + {""}, {""}, +#line 138 "src/lexer-keywords.txt" + {"f64.le", TokenType::Compare, Opcode::F64Le}, +#line 77 "src/lexer-keywords.txt" + {"f32.le", TokenType::Compare, Opcode::F32Le}, + {""}, +#line 574 "src/lexer-keywords.txt" + {"result", TokenType::Result}, +#line 140 "src/lexer-keywords.txt" {"f64.lt", TokenType::Compare, Opcode::F64Lt}, -#line 78 "src/lexer-keywords.txt" +#line 79 "src/lexer-keywords.txt" {"f32.lt", TokenType::Compare, Opcode::F32Lt}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 43 "src/lexer-keywords.txt" - {"code", TokenType::Code}, - {""}, {""}, {""}, -#line 570 "src/lexer-keywords.txt" - {"result", TokenType::Result}, + {""}, {""}, +#line 466 "src/lexer-keywords.txt" + {"i64", Type::I64}, +#line 593 "src/lexer-keywords.txt" + {"table", TokenType::Table}, {""}, -#line 100 "src/lexer-keywords.txt" - {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge}, +#line 36 "src/lexer-keywords.txt" + {"br", TokenType::Br, Opcode::Br}, +#line 153 "src/lexer-keywords.txt" + {"f64", Type::F64}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 585 "src/lexer-keywords.txt" + {"struct", Type::Struct, TokenType::Struct}, {""}, -#line 102 "src/lexer-keywords.txt" - {"f32x4.le", TokenType::Compare, Opcode::F32X4Le}, +#line 591 "src/lexer-keywords.txt" + {"table.set", TokenType::TableSet, Opcode::TableSet}, {""}, -#line 578 "src/lexer-keywords.txt" - {"struct", Type::Struct, TokenType::Struct}, - {""}, {""}, {""}, {""}, {""}, -#line 555 "src/lexer-keywords.txt" - {"mut", TokenType::Mut}, -#line 441 "src/lexer-keywords.txt" - {"i64.or", TokenType::Binary, Opcode::I64Or}, -#line 298 "src/lexer-keywords.txt" - {"i32.or", TokenType::Binary, Opcode::I32Or}, - {""}, {""}, -#line 581 "src/lexer-keywords.txt" +#line 31 "src/lexer-keywords.txt" + {"before", TokenType::Before}, +#line 588 "src/lexer-keywords.txt" {"table.get", TokenType::TableGet, Opcode::TableGet}, -#line 101 "src/lexer-keywords.txt" - {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt}, -#line 584 "src/lexer-keywords.txt" - {"table.set", TokenType::TableSet, Opcode::TableSet}, -#line 103 "src/lexer-keywords.txt" - {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt}, -#line 330 "src/lexer-keywords.txt" + {""}, {""}, +#line 332 "src/lexer-keywords.txt" {"i32x4.ge_u", TokenType::Compare, Opcode::I32X4GeU}, - {""}, +#line 101 "src/lexer-keywords.txt" + {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge}, #line 334 "src/lexer-keywords.txt" - {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU}, + {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU}, {""}, -#line 329 "src/lexer-keywords.txt" +#line 331 "src/lexer-keywords.txt" {"i32x4.ge_s", TokenType::Compare, Opcode::I32X4GeS}, -#line 93 "src/lexer-keywords.txt" - {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil}, +#line 102 "src/lexer-keywords.txt" + {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt}, #line 333 "src/lexer-keywords.txt" - {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS}, - {""}, -#line 332 "src/lexer-keywords.txt" - {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU}, + {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS}, {""}, -#line 342 "src/lexer-keywords.txt" +#line 336 "src/lexer-keywords.txt" + {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU}, +#line 103 "src/lexer-keywords.txt" + {"f32x4.le", TokenType::Compare, Opcode::F32X4Le}, +#line 344 "src/lexer-keywords.txt" {"i32x4.lt_u", TokenType::Compare, Opcode::I32X4LtU}, {""}, -#line 331 "src/lexer-keywords.txt" - {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS}, - {""}, -#line 341 "src/lexer-keywords.txt" +#line 335 "src/lexer-keywords.txt" + {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS}, +#line 104 "src/lexer-keywords.txt" + {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt}, +#line 343 "src/lexer-keywords.txt" {"i32x4.lt_s", TokenType::Compare, Opcode::I32X4LtS}, -#line 145 "src/lexer-keywords.txt" +#line 366 "src/lexer-keywords.txt" + {"i32x4", TokenType::I32X4}, +#line 558 "src/lexer-keywords.txt" + {"mut", TokenType::Mut}, + {""}, {""}, +#line 123 "src/lexer-keywords.txt" + {"f32x4", TokenType::F32X4}, +#line 442 "src/lexer-keywords.txt" + {"i64.ne", TokenType::Compare, Opcode::I64Ne}, +#line 299 "src/lexer-keywords.txt" + {"i32.ne", TokenType::Compare, Opcode::I32Ne}, + {""}, +#line 44 "src/lexer-keywords.txt" + {"code", TokenType::Code}, +#line 146 "src/lexer-keywords.txt" {"f64.ne", TokenType::Compare, Opcode::F64Ne}, -#line 84 "src/lexer-keywords.txt" +#line 85 "src/lexer-keywords.txt" {"f32.ne", TokenType::Compare, Opcode::F32Ne}, - {""}, {""}, {""}, -#line 554 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, +#line 557 "src/lexer-keywords.txt" {"module", TokenType::Module}, {""}, -#line 440 "src/lexer-keywords.txt" - {"i64.ne", TokenType::Compare, Opcode::I64Ne}, -#line 297 "src/lexer-keywords.txt" - {"i32.ne", TokenType::Compare, Opcode::I32Ne}, -#line 46 "src/lexer-keywords.txt" - {"declare", TokenType::Declare}, +#line 584 "src/lexer-keywords.txt" + {"strings", TokenType::Strings}, {""}, -#line 144 "src/lexer-keywords.txt" +#line 145 "src/lexer-keywords.txt" {"f64.neg", TokenType::Unary, Opcode::F64Neg}, -#line 83 "src/lexer-keywords.txt" +#line 84 "src/lexer-keywords.txt" {"f32.neg", TokenType::Unary, Opcode::F32Neg}, +#line 47 "src/lexer-keywords.txt" + {"declare", TokenType::Declare}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 144 "src/lexer-keywords.txt" + {"f64.nearest", TokenType::Unary, Opcode::F64Nearest}, +#line 83 "src/lexer-keywords.txt" + {"f32.nearest", TokenType::Unary, Opcode::F32Nearest}, {""}, -#line 149 "src/lexer-keywords.txt" - {"f64.store", TokenType::Store, Opcode::F64Store}, -#line 87 "src/lexer-keywords.txt" - {"f32.store", TokenType::Store, Opcode::F32Store}, - {""}, -#line 447 "src/lexer-keywords.txt" - {"i64.rotr", TokenType::Binary, Opcode::I64Rotr}, -#line 304 "src/lexer-keywords.txt" - {"i32.rotr", TokenType::Binary, Opcode::I32Rotr}, -#line 446 "src/lexer-keywords.txt" - {"i64.rotl", TokenType::Binary, Opcode::I64Rotl}, -#line 303 "src/lexer-keywords.txt" - {"i32.rotl", TokenType::Binary, Opcode::I32Rotl}, -#line 454 "src/lexer-keywords.txt" - {"i64.store", TokenType::Store, Opcode::I64Store}, -#line 310 "src/lexer-keywords.txt" - {"i32.store", TokenType::Store, Opcode::I32Store}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 568 "src/lexer-keywords.txt" - {"ref.null", TokenType::RefNull, Opcode::RefNull}, -#line 108 "src/lexer-keywords.txt" - {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg}, +#line 49 "src/lexer-keywords.txt" + {"do", TokenType::Do}, + {""}, {""}, {""}, {""}, {""}, +#line 94 "src/lexer-keywords.txt" + {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil}, {""}, -#line 109 "src/lexer-keywords.txt" +#line 352 "src/lexer-keywords.txt" + {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne}, + {""}, {""}, {""}, +#line 110 "src/lexer-keywords.txt" {"f32x4.ne", TokenType::Compare, Opcode::F32X4Ne}, - {""}, {""}, {""}, {""}, -#line 349 "src/lexer-keywords.txt" - {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg}, {""}, -#line 350 "src/lexer-keywords.txt" - {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne}, - {""}, {""}, -#line 151 "src/lexer-keywords.txt" +#line 351 "src/lexer-keywords.txt" + {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg}, + {""}, {""}, {""}, +#line 109 "src/lexer-keywords.txt" + {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg}, +#line 152 "src/lexer-keywords.txt" {"f64.trunc", TokenType::Unary, Opcode::F64Trunc}, -#line 89 "src/lexer-keywords.txt" +#line 90 "src/lexer-keywords.txt" {"f32.trunc", TokenType::Unary, Opcode::F32Trunc}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 572 "src/lexer-keywords.txt" + {"ref.null", TokenType::RefNull, Opcode::RefNull}, +#line 443 "src/lexer-keywords.txt" + {"i64.or", TokenType::Binary, Opcode::I64Or}, +#line 300 "src/lexer-keywords.txt" + {"i32.or", TokenType::Binary, Opcode::I32Or}, +#line 456 "src/lexer-keywords.txt" + {"i64.store", TokenType::Store, Opcode::I64Store}, +#line 312 "src/lexer-keywords.txt" + {"i32.store", TokenType::Store, Opcode::I32Store}, + {""}, {""}, +#line 150 "src/lexer-keywords.txt" + {"f64.store", TokenType::Store, Opcode::F64Store}, +#line 88 "src/lexer-keywords.txt" + {"f32.store", TokenType::Store, Opcode::F32Store}, +#line 108 "src/lexer-keywords.txt" + {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest}, {""}, {""}, {""}, {""}, -#line 143 "src/lexer-keywords.txt" - {"f64.nearest", TokenType::Unary, Opcode::F64Nearest}, -#line 82 "src/lexer-keywords.txt" - {"f32.nearest", TokenType::Unary, Opcode::F32Nearest}, - {""}, {""}, {""}, -#line 120 "src/lexer-keywords.txt" - {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc}, -#line 574 "src/lexer-keywords.txt" +#line 449 "src/lexer-keywords.txt" + {"i64.rotr", TokenType::Binary, Opcode::I64Rotr}, +#line 306 "src/lexer-keywords.txt" + {"i32.rotr", TokenType::Binary, Opcode::I32Rotr}, +#line 188 "src/lexer-keywords.txt" + {"func", Type::FuncRef, TokenType::Func}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 579 "src/lexer-keywords.txt" {"return", TokenType::Return, Opcode::Return}, + {""}, {""}, +#line 448 "src/lexer-keywords.txt" + {"i64.rotl", TokenType::Binary, Opcode::I64Rotl}, +#line 305 "src/lexer-keywords.txt" + {"i32.rotl", TokenType::Binary, Opcode::I32Rotl}, {""}, {""}, {""}, {""}, {""}, -#line 453 "src/lexer-keywords.txt" - {"i64.store8", TokenType::Store, Opcode::I64Store8}, -#line 309 "src/lexer-keywords.txt" - {"i32.store8", TokenType::Store, Opcode::I32Store8}, -#line 142 "src/lexer-keywords.txt" - {"f64.mul", TokenType::Binary, Opcode::F64Mul}, -#line 81 "src/lexer-keywords.txt" - {"f32.mul", TokenType::Binary, Opcode::F32Mul}, -#line 92 "src/lexer-keywords.txt" - {"f32x4.add", TokenType::Binary, Opcode::F32X4Add}, -#line 107 "src/lexer-keywords.txt" - {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest}, +#line 121 "src/lexer-keywords.txt" + {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc}, +#line 48 "src/lexer-keywords.txt" + {"delegate", TokenType::Delegate}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, +#line 561 "src/lexer-keywords.txt" + {"name", TokenType::Name}, {""}, {""}, {""}, -#line 439 "src/lexer-keywords.txt" +#line 441 "src/lexer-keywords.txt" {"i64.mul", TokenType::Binary, Opcode::I64Mul}, -#line 296 "src/lexer-keywords.txt" +#line 298 "src/lexer-keywords.txt" {"i32.mul", TokenType::Binary, Opcode::I32Mul}, -#line 323 "src/lexer-keywords.txt" + {""}, {""}, +#line 143 "src/lexer-keywords.txt" + {"f64.mul", TokenType::Binary, Opcode::F64Mul}, +#line 82 "src/lexer-keywords.txt" + {"f32.mul", TokenType::Binary, Opcode::F32Mul}, +#line 580 "src/lexer-keywords.txt" + {"select", TokenType::Select, Opcode::Select}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 354 "src/lexer-keywords.txt" + {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane}, +#line 353 "src/lexer-keywords.txt" + {"i32x4.relaxed_laneselect", TokenType::Ternary, Opcode::I32X4RelaxedLaneSelect}, + {""}, {""}, +#line 117 "src/lexer-keywords.txt" + {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane}, + {""}, +#line 325 "src/lexer-keywords.txt" {"i32x4.add", TokenType::Binary, Opcode::I32X4Add}, {""}, -#line 38 "src/lexer-keywords.txt" - {"call", TokenType::Call, Opcode::Call}, +#line 350 "src/lexer-keywords.txt" + {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul}, {""}, -#line 126 "src/lexer-keywords.txt" - {"f64.const", TokenType::Const, Opcode::F64Const}, -#line 64 "src/lexer-keywords.txt" - {"f32.const", TokenType::Const, Opcode::F32Const}, - {""}, {""}, {""}, -#line 106 "src/lexer-keywords.txt" - {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul}, +#line 93 "src/lexer-keywords.txt" + {"f32x4.add", TokenType::Binary, Opcode::F32X4Add}, {""}, -#line 413 "src/lexer-keywords.txt" +#line 107 "src/lexer-keywords.txt" + {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 415 "src/lexer-keywords.txt" {"i64.const", TokenType::Const, Opcode::I64Const}, -#line 275 "src/lexer-keywords.txt" +#line 277 "src/lexer-keywords.txt" {"i32.const", TokenType::Const, Opcode::I32Const}, + {""}, {""}, +#line 127 "src/lexer-keywords.txt" + {"f64.const", TokenType::Const, Opcode::F64Const}, +#line 65 "src/lexer-keywords.txt" + {"f32.const", TokenType::Const, Opcode::F32Const}, + {""}, {""}, {""}, {""}, +#line 377 "src/lexer-keywords.txt" + {"i64.and", TokenType::Binary, Opcode::I64And}, +#line 248 "src/lexer-keywords.txt" + {"i32.and", TokenType::Binary, Opcode::I32And}, {""}, -#line 575 "src/lexer-keywords.txt" - {"select", TokenType::Select, Opcode::Select}, +#line 39 "src/lexer-keywords.txt" + {"call", TokenType::Call, Opcode::Call}, + {""}, {""}, {""}, {""}, +#line 376 "src/lexer-keywords.txt" + {"i64.add", TokenType::Binary, Opcode::I64Add}, +#line 247 "src/lexer-keywords.txt" + {"i32.add", TokenType::Binary, Opcode::I32Add}, + {""}, {""}, +#line 125 "src/lexer-keywords.txt" + {"f64.add", TokenType::Binary, Opcode::F64Add}, +#line 63 "src/lexer-keywords.txt" + {"f32.add", TokenType::Binary, Opcode::F32Add}, {""}, -#line 348 "src/lexer-keywords.txt" - {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul}, +#line 545 "src/lexer-keywords.txt" + {"local.tee", TokenType::LocalTee, Opcode::LocalTee}, {""}, -#line 543 "src/lexer-keywords.txt" +#line 544 "src/lexer-keywords.txt" + {"local.set", TokenType::LocalSet, Opcode::LocalSet}, +#line 546 "src/lexer-keywords.txt" {"local", TokenType::Local}, - {""}, {""}, {""}, -#line 496 "src/lexer-keywords.txt" - {"i64.xor", TokenType::Binary, Opcode::I64Xor}, -#line 373 "src/lexer-keywords.txt" - {"i32.xor", TokenType::Binary, Opcode::I32Xor}, -#line 47 "src/lexer-keywords.txt" - {"delegate", TokenType::Delegate}, - {""}, {""}, {""}, -#line 124 "src/lexer-keywords.txt" - {"f64.add", TokenType::Binary, Opcode::F64Add}, -#line 62 "src/lexer-keywords.txt" - {"f32.add", TokenType::Binary, Opcode::F32Add}, -#line 138 "src/lexer-keywords.txt" - {"f64.load", TokenType::Load, Opcode::F64Load}, -#line 77 "src/lexer-keywords.txt" - {"f32.load", TokenType::Load, Opcode::F32Load}, - {""}, {""}, {""}, -#line 374 "src/lexer-keywords.txt" - {"i64.add", TokenType::Binary, Opcode::I64Add}, -#line 245 "src/lexer-keywords.txt" - {"i32.add", TokenType::Binary, Opcode::I32Add}, -#line 436 "src/lexer-keywords.txt" - {"i64.load", TokenType::Load, Opcode::I64Load}, -#line 293 "src/lexer-keywords.txt" - {"i32.load", TokenType::Load, Opcode::I32Load}, - {""}, {""}, {""}, {""}, -#line 116 "src/lexer-keywords.txt" - {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane}, - {""}, {""}, {""}, -#line 375 "src/lexer-keywords.txt" - {"i64.and", TokenType::Binary, Opcode::I64And}, -#line 246 "src/lexer-keywords.txt" - {"i32.and", TokenType::Binary, Opcode::I32And}, {""}, -#line 352 "src/lexer-keywords.txt" - {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane}, - {""}, {""}, {""}, -#line 425 "src/lexer-keywords.txt" +#line 543 "src/lexer-keywords.txt" + {"local.get", TokenType::LocalGet, Opcode::LocalGet}, +#line 427 "src/lexer-keywords.txt" {"i64.ge_u", TokenType::Compare, Opcode::I64GeU}, -#line 284 "src/lexer-keywords.txt" +#line 286 "src/lexer-keywords.txt" {"i32.ge_u", TokenType::Compare, Opcode::I32GeU}, #line 429 "src/lexer-keywords.txt" - {"i64.le_u", TokenType::Compare, Opcode::I64LeU}, + {"i64.gt_u", TokenType::Compare, Opcode::I64GtU}, #line 288 "src/lexer-keywords.txt" - {"i32.le_u", TokenType::Compare, Opcode::I32LeU}, -#line 424 "src/lexer-keywords.txt" + {"i32.gt_u", TokenType::Compare, Opcode::I32GtU}, +#line 426 "src/lexer-keywords.txt" {"i64.ge_s", TokenType::Compare, Opcode::I64GeS}, -#line 283 "src/lexer-keywords.txt" +#line 285 "src/lexer-keywords.txt" {"i32.ge_s", TokenType::Compare, Opcode::I32GeS}, #line 428 "src/lexer-keywords.txt" - {"i64.le_s", TokenType::Compare, Opcode::I64LeS}, + {"i64.gt_s", TokenType::Compare, Opcode::I64GtS}, #line 287 "src/lexer-keywords.txt" - {"i32.le_s", TokenType::Compare, Opcode::I32LeS}, -#line 427 "src/lexer-keywords.txt" - {"i64.gt_u", TokenType::Compare, Opcode::I64GtU}, -#line 286 "src/lexer-keywords.txt" - {"i32.gt_u", TokenType::Compare, Opcode::I32GtU}, -#line 438 "src/lexer-keywords.txt" + {"i32.gt_s", TokenType::Compare, Opcode::I32GtS}, +#line 431 "src/lexer-keywords.txt" + {"i64.le_u", TokenType::Compare, Opcode::I64LeU}, +#line 290 "src/lexer-keywords.txt" + {"i32.le_u", TokenType::Compare, Opcode::I32LeU}, +#line 440 "src/lexer-keywords.txt" {"i64.lt_u", TokenType::Compare, Opcode::I64LtU}, -#line 295 "src/lexer-keywords.txt" +#line 297 "src/lexer-keywords.txt" {"i32.lt_u", TokenType::Compare, Opcode::I32LtU}, -#line 426 "src/lexer-keywords.txt" - {"i64.gt_s", TokenType::Compare, Opcode::I64GtS}, -#line 285 "src/lexer-keywords.txt" - {"i32.gt_s", TokenType::Compare, Opcode::I32GtS}, -#line 437 "src/lexer-keywords.txt" +#line 430 "src/lexer-keywords.txt" + {"i64.le_s", TokenType::Compare, Opcode::I64LeS}, +#line 289 "src/lexer-keywords.txt" + {"i32.le_s", TokenType::Compare, Opcode::I32LeS}, +#line 439 "src/lexer-keywords.txt" {"i64.lt_s", TokenType::Compare, Opcode::I64LtS}, -#line 294 "src/lexer-keywords.txt" +#line 296 "src/lexer-keywords.txt" {"i32.lt_s", TokenType::Compare, Opcode::I32LtS}, - {""}, {""}, {""}, -#line 540 "src/lexer-keywords.txt" - {"local.get", TokenType::LocalGet, Opcode::LocalGet}, - {""}, -#line 541 "src/lexer-keywords.txt" - {"local.set", TokenType::LocalSet, Opcode::LocalSet}, -#line 542 "src/lexer-keywords.txt" - {"local.tee", TokenType::LocalTee, Opcode::LocalTee}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 498 "src/lexer-keywords.txt" + {"i64.xor", TokenType::Binary, Opcode::I64Xor}, +#line 375 "src/lexer-keywords.txt" + {"i32.xor", TokenType::Binary, Opcode::I32Xor}, + {""}, {""}, {""}, +#line 438 "src/lexer-keywords.txt" + {"i64.load", TokenType::Load, Opcode::I64Load}, +#line 295 "src/lexer-keywords.txt" + {"i32.load", TokenType::Load, Opcode::I32Load}, + {""}, {""}, +#line 139 "src/lexer-keywords.txt" + {"f64.load", TokenType::Load, Opcode::F64Load}, +#line 78 "src/lexer-keywords.txt" + {"f32.load", TokenType::Load, Opcode::F32Load}, +#line 416 "src/lexer-keywords.txt" + {"i64.ctz", TokenType::Unary, Opcode::I64Ctz}, +#line 278 "src/lexer-keywords.txt" + {"i32.ctz", TokenType::Unary, Opcode::I32Ctz}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 351 "src/lexer-keywords.txt" - {"i32x4.relaxed_laneselect", TokenType::Ternary, Opcode::I32X4RelaxedLaneSelect}, -#line 324 "src/lexer-keywords.txt" +#line 414 "src/lexer-keywords.txt" + {"i64.clz", TokenType::Unary, Opcode::I64Clz}, +#line 276 "src/lexer-keywords.txt" + {"i32.clz", TokenType::Unary, Opcode::I32Clz}, + {""}, {""}, {""}, +#line 569 "src/lexer-keywords.txt" + {"ref.extern", TokenType::RefExtern}, + {""}, {""}, {""}, {""}, +#line 326 "src/lexer-keywords.txt" {"i32x4.all_true", TokenType::Unary, Opcode::I32X4AllTrue}, {""}, -#line 125 "src/lexer-keywords.txt" - {"f64.ceil", TokenType::Unary, Opcode::F64Ceil}, -#line 63 "src/lexer-keywords.txt" - {"f32.ceil", TokenType::Unary, Opcode::F32Ceil}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 585 "src/lexer-keywords.txt" - {"table.size", TokenType::TableSize, Opcode::TableSize}, - {""}, {""}, {""}, -#line 104 "src/lexer-keywords.txt" - {"f32x4.max", TokenType::Binary, Opcode::F32X4Max}, -#line 535 "src/lexer-keywords.txt" - {"if", TokenType::If, Opcode::If}, -#line 411 "src/lexer-keywords.txt" +#line 413 "src/lexer-keywords.txt" {"i64.atomic.store", TokenType::AtomicStore, Opcode::I64AtomicStore}, -#line 273 "src/lexer-keywords.txt" +#line 275 "src/lexer-keywords.txt" {"i32.atomic.store", TokenType::AtomicStore, Opcode::I32AtomicStore}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 563 "src/lexer-keywords.txt" - {"ref", TokenType::Ref}, {""}, {""}, -#line 404 "src/lexer-keywords.txt" - {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr}, -#line 267 "src/lexer-keywords.txt" - {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr}, - {""}, {""}, {""}, {""}, {""}, -#line 573 "src/lexer-keywords.txt" - {"return_call", TokenType::ReturnCall, Opcode::ReturnCall}, - {""}, {""}, -#line 53 "src/lexer-keywords.txt" - {"else", TokenType::Else, Opcode::Else}, - {""}, {""}, {""}, {""}, {""}, -#line 55 "src/lexer-keywords.txt" - {"tag", TokenType::Tag}, - {""}, -#line 98 "src/lexer-keywords.txt" - {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane}, -#line 565 "src/lexer-keywords.txt" - {"ref.extern", TokenType::RefExtern}, -#line 338 "src/lexer-keywords.txt" +#line 455 "src/lexer-keywords.txt" + {"i64.store8", TokenType::Store, Opcode::I64Store8}, +#line 311 "src/lexer-keywords.txt" + {"i32.store8", TokenType::Store, Opcode::I32Store8}, + {""}, {""}, {""}, {""}, +#line 340 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f64x2_u_zero", TokenType::Unary, Opcode::I32X4RelaxedTruncF64X2UZero}, -#line 90 "src/lexer-keywords.txt" - {"f32", Type::F32}, -#line 337 "src/lexer-keywords.txt" +#line 393 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU}, +#line 339 "src/lexer-keywords.txt" {"i32x4.relaxed_trunc_f64x2_s_zero", TokenType::Unary, Opcode::I32X4RelaxedTruncF64X2SZero}, - {""}, {""}, -#line 328 "src/lexer-keywords.txt" - {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane}, - {""}, -#line 189 "src/lexer-keywords.txt" - {"get", TokenType::Get}, -#line 320 "src/lexer-keywords.txt" +#line 322 "src/lexer-keywords.txt" {"i32", Type::I32}, -#line 50 "src/lexer-keywords.txt" - {"either", TokenType::Either}, - {""}, {""}, -#line 391 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU}, -#line 435 "src/lexer-keywords.txt" - {"i64.load8_u", TokenType::Load, Opcode::I64Load8U}, -#line 292 "src/lexer-keywords.txt" - {"i32.load8_u", TokenType::Load, Opcode::I32Load8U}, -#line 434 "src/lexer-keywords.txt" - {"i64.load8_s", TokenType::Load, Opcode::I64Load8S}, -#line 291 "src/lexer-keywords.txt" - {"i32.load8_s", TokenType::Load, Opcode::I32Load8S}, +#line 330 "src/lexer-keywords.txt" + {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane}, +#line 406 "src/lexer-keywords.txt" + {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr}, +#line 269 "src/lexer-keywords.txt" + {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr}, +#line 91 "src/lexer-keywords.txt" + {"f32", Type::F32}, +#line 99 "src/lexer-keywords.txt" + {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane}, {""}, -#line 410 "src/lexer-keywords.txt" - {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8}, -#line 272 "src/lexer-keywords.txt" - {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8}, -#line 431 "src/lexer-keywords.txt" - {"i64.load16_u", TokenType::Load, Opcode::I64Load16U}, -#line 290 "src/lexer-keywords.txt" - {"i32.load16_u", TokenType::Load, Opcode::I32Load16U}, -#line 457 "src/lexer-keywords.txt" +#line 459 "src/lexer-keywords.txt" {"i64.trunc_f32_u", TokenType::Convert, Opcode::I64TruncF32U}, -#line 313 "src/lexer-keywords.txt" +#line 315 "src/lexer-keywords.txt" {"i32.trunc_f32_u", TokenType::Convert, Opcode::I32TruncF32U}, -#line 430 "src/lexer-keywords.txt" - {"i64.load16_s", TokenType::Load, Opcode::I64Load16S}, -#line 289 "src/lexer-keywords.txt" - {"i32.load16_s", TokenType::Load, Opcode::I32Load16S}, -#line 456 "src/lexer-keywords.txt" + {""}, {""}, +#line 458 "src/lexer-keywords.txt" {"i64.trunc_f32_s", TokenType::Convert, Opcode::I64TruncF32S}, -#line 312 "src/lexer-keywords.txt" +#line 314 "src/lexer-keywords.txt" {"i32.trunc_f32_s", TokenType::Convert, Opcode::I32TruncF32S}, -#line 445 "src/lexer-keywords.txt" + {""}, {""}, +#line 105 "src/lexer-keywords.txt" + {"f32x4.max", TokenType::Binary, Opcode::F32X4Max}, + {""}, {""}, +#line 161 "src/lexer-keywords.txt" + {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge}, + {""}, +#line 115 "src/lexer-keywords.txt" + {"f32x4.relaxed_min", TokenType::Binary, Opcode::F32X4RelaxedMin}, +#line 477 "src/lexer-keywords.txt" + {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS}, +#line 162 "src/lexer-keywords.txt" + {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt}, +#line 475 "src/lexer-keywords.txt" + {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS}, + {""}, {""}, +#line 163 "src/lexer-keywords.txt" + {"f64x2.le", TokenType::Compare, Opcode::F64X2Le}, + {""}, {""}, +#line 476 "src/lexer-keywords.txt" + {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS}, +#line 164 "src/lexer-keywords.txt" + {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt}, +#line 474 "src/lexer-keywords.txt" + {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS}, + {""}, {""}, {""}, {""}, {""}, +#line 598 "src/lexer-keywords.txt" + {"try", TokenType::Try, Opcode::Try}, + {""}, {""}, {""}, {""}, {""}, +#line 116 "src/lexer-keywords.txt" + {"f32x4.relaxed_nmadd", TokenType::Ternary, Opcode::F32X4RelaxedNmadd}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 207 "src/lexer-keywords.txt" + {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU}, + {""}, +#line 209 "src/lexer-keywords.txt" + {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU}, +#line 578 "src/lexer-keywords.txt" + {"return_call", TokenType::ReturnCall, Opcode::ReturnCall}, +#line 206 "src/lexer-keywords.txt" + {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS}, + {""}, +#line 208 "src/lexer-keywords.txt" + {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS}, + {""}, +#line 211 "src/lexer-keywords.txt" + {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU}, + {""}, +#line 215 "src/lexer-keywords.txt" + {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU}, +#line 390 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU}, +#line 210 "src/lexer-keywords.txt" + {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS}, +#line 592 "src/lexer-keywords.txt" + {"table.size", TokenType::TableSize, Opcode::TableSize}, +#line 214 "src/lexer-keywords.txt" + {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS}, +#line 447 "src/lexer-keywords.txt" {"i64.rem_u", TokenType::Binary, Opcode::I64RemU}, -#line 302 "src/lexer-keywords.txt" +#line 304 "src/lexer-keywords.txt" {"i32.rem_u", TokenType::Binary, Opcode::I32RemU}, -#line 444 "src/lexer-keywords.txt" +#line 446 "src/lexer-keywords.txt" {"i64.rem_s", TokenType::Binary, Opcode::I64RemS}, -#line 301 "src/lexer-keywords.txt" +#line 303 "src/lexer-keywords.txt" {"i32.rem_s", TokenType::Binary, Opcode::I32RemS}, - {""}, +#line 389 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU}, +#line 156 "src/lexer-keywords.txt" + {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil}, +#line 537 "src/lexer-keywords.txt" + {"if", TokenType::If, Opcode::If}, +#line 473 "src/lexer-keywords.txt" + {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne}, + {""}, {""}, #line 54 "src/lexer-keywords.txt" - {"end", TokenType::End, Opcode::End}, + {"else", TokenType::Else, Opcode::Else}, +#line 170 "src/lexer-keywords.txt" + {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne}, {""}, -#line 407 "src/lexer-keywords.txt" - {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor}, -#line 270 "src/lexer-keywords.txt" - {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 587 "src/lexer-keywords.txt" - {"then", TokenType::Then}, -#line 583 "src/lexer-keywords.txt" - {"table.init", TokenType::TableInit, Opcode::TableInit}, +#line 479 "src/lexer-keywords.txt" + {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg}, +#line 567 "src/lexer-keywords.txt" + {"ref", TokenType::Ref}, {""}, {""}, -#line 344 "src/lexer-keywords.txt" +#line 169 "src/lexer-keywords.txt" + {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg}, + {""}, {""}, {""}, {""}, {""}, +#line 126 "src/lexer-keywords.txt" + {"f64.ceil", TokenType::Unary, Opcode::F64Ceil}, +#line 64 "src/lexer-keywords.txt" + {"f32.ceil", TokenType::Unary, Opcode::F32Ceil}, + {""}, +#line 51 "src/lexer-keywords.txt" + {"either", TokenType::Either}, + {""}, {""}, +#line 168 "src/lexer-keywords.txt" + {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest}, +#line 346 "src/lexer-keywords.txt" {"i32x4.max_u", TokenType::Binary, Opcode::I32X4MaxU}, {""}, -#line 343 "src/lexer-keywords.txt" +#line 345 "src/lexer-keywords.txt" {"i32x4.max_s", TokenType::Binary, Opcode::I32X4MaxS}, - {""}, -#line 390 "src/lexer-keywords.txt" + {""}, {""}, {""}, +#line 392 "src/lexer-keywords.txt" {"i64.atomic.rmw32.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU}, -#line 448 "src/lexer-keywords.txt" - {"i64.shl", TokenType::Binary, Opcode::I64Shl}, -#line 305 "src/lexer-keywords.txt" - {"i32.shl", TokenType::Binary, Opcode::I32Shl}, - {""}, {""}, -#line 114 "src/lexer-keywords.txt" - {"f32x4.relaxed_min", TokenType::Binary, Opcode::F32X4RelaxedMin}, {""}, -#line 115 "src/lexer-keywords.txt" - {"f32x4.relaxed_nmadd", TokenType::Ternary, Opcode::F32X4RelaxedNmadd}, -#line 140 "src/lexer-keywords.txt" - {"f64.max", TokenType::Binary, Opcode::F64Max}, -#line 79 "src/lexer-keywords.txt" - {"f32.max", TokenType::Binary, Opcode::F32Max}, - {""}, {""}, -#line 160 "src/lexer-keywords.txt" - {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge}, +#line 409 "src/lexer-keywords.txt" + {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor}, +#line 272 "src/lexer-keywords.txt" + {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor}, {""}, -#line 162 "src/lexer-keywords.txt" - {"f64x2.le", TokenType::Compare, Opcode::F64X2Le}, +#line 225 "src/lexer-keywords.txt" + {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne}, {""}, {""}, -#line 387 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU}, +#line 113 "src/lexer-keywords.txt" + {"f32x4.relaxed_madd", TokenType::Ternary, Opcode::F32X4RelaxedMadd}, + {""}, {""}, +#line 223 "src/lexer-keywords.txt" + {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg}, +#line 437 "src/lexer-keywords.txt" + {"i64.load8_u", TokenType::Load, Opcode::I64Load8U}, +#line 294 "src/lexer-keywords.txt" + {"i32.load8_u", TokenType::Load, Opcode::I32Load8U}, +#line 436 "src/lexer-keywords.txt" + {"i64.load8_s", TokenType::Load, Opcode::I64Load8S}, +#line 293 "src/lexer-keywords.txt" + {"i32.load8_s", TokenType::Load, Opcode::I32Load8S}, {""}, -#line 353 "src/lexer-keywords.txt" - {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl}, +#line 181 "src/lexer-keywords.txt" + {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc}, {""}, {""}, -#line 569 "src/lexer-keywords.txt" - {"register", TokenType::Register}, -#line 379 "src/lexer-keywords.txt" +#line 141 "src/lexer-keywords.txt" + {"f64.max", TokenType::Binary, Opcode::F64Max}, +#line 80 "src/lexer-keywords.txt" + {"f32.max", TokenType::Binary, Opcode::F32Max}, +#line 454 "src/lexer-keywords.txt" + {"i64.store32", TokenType::Store, Opcode::I64Store32}, +#line 242 "src/lexer-keywords.txt" + {"i16x8", TokenType::I16X8}, + {""}, {""}, {""}, {""}, +#line 590 "src/lexer-keywords.txt" + {"table.init", TokenType::TableInit, Opcode::TableInit}, + {""}, {""}, {""}, +#line 381 "src/lexer-keywords.txt" {"i64.atomic.load", TokenType::AtomicLoad, Opcode::I64AtomicLoad}, -#line 249 "src/lexer-keywords.txt" +#line 251 "src/lexer-keywords.txt" {"i32.atomic.load", TokenType::AtomicLoad, Opcode::I32AtomicLoad}, - {""}, {""}, {""}, -#line 161 "src/lexer-keywords.txt" - {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt}, -#line 388 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU}, -#line 163 "src/lexer-keywords.txt" - {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt}, - {""}, -#line 58 "src/lexer-keywords.txt" - {"exn", Type::ExnRef, TokenType::Exn}, - {""}, {""}, -#line 475 "src/lexer-keywords.txt" - {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS}, -#line 155 "src/lexer-keywords.txt" - {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil}, -#line 474 "src/lexer-keywords.txt" - {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS}, - {""}, {""}, {""}, {""}, {""}, -#line 473 "src/lexer-keywords.txt" - {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS}, +#line 564 "src/lexer-keywords.txt" + {"output", TokenType::Output}, +#line 568 "src/lexer-keywords.txt" + {"quote", TokenType::Quote}, +#line 594 "src/lexer-keywords.txt" + {"then", TokenType::Then}, +#line 190 "src/lexer-keywords.txt" + {"get", TokenType::Get}, {""}, -#line 472 "src/lexer-keywords.txt" - {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS}, -#line 99 "src/lexer-keywords.txt" - {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor}, +#line 563 "src/lexer-keywords.txt" + {"offset", TokenType::Offset}, +#line 56 "src/lexer-keywords.txt" + {"tag", TokenType::Tag}, {""}, {""}, -#line 185 "src/lexer-keywords.txt" - {"field", TokenType::Field}, -#line 112 "src/lexer-keywords.txt" - {"f32x4.relaxed_madd", TokenType::Ternary, Opcode::F32X4RelaxedMadd}, - {""}, {""}, {""}, {""}, {""}, -#line 419 "src/lexer-keywords.txt" - {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S}, -#line 281 "src/lexer-keywords.txt" - {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S}, - {""}, -#line 539 "src/lexer-keywords.txt" - {"item", TokenType::Item}, +#line 55 "src/lexer-keywords.txt" + {"end", TokenType::End, Opcode::End}, {""}, {""}, -#line 421 "src/lexer-keywords.txt" +#line 423 "src/lexer-keywords.txt" {"i64.extend8_s", TokenType::Unary, Opcode::I64Extend8S}, -#line 282 "src/lexer-keywords.txt" +#line 284 "src/lexer-keywords.txt" {"i32.extend8_s", TokenType::Unary, Opcode::I32Extend8S}, - {""}, {""}, -#line 566 "src/lexer-keywords.txt" - {"ref.func", TokenType::RefFunc, Opcode::RefFunc}, -#line 134 "src/lexer-keywords.txt" - {"f64.floor", TokenType::Unary, Opcode::F64Floor}, -#line 73 "src/lexer-keywords.txt" - {"f32.floor", TokenType::Unary, Opcode::F32Floor}, - {""}, {""}, -#line 412 "src/lexer-keywords.txt" - {"i64.clz", TokenType::Unary, Opcode::I64Clz}, -#line 274 "src/lexer-keywords.txt" - {"i32.clz", TokenType::Unary, Opcode::I32Clz}, - {""}, {""}, {""}, {""}, -#line 168 "src/lexer-keywords.txt" - {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg}, -#line 105 "src/lexer-keywords.txt" - {"f32x4.min", TokenType::Binary, Opcode::F32X4Min}, -#line 169 "src/lexer-keywords.txt" - {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne}, -#line 414 "src/lexer-keywords.txt" - {"i64.ctz", TokenType::Unary, Opcode::I64Ctz}, -#line 276 "src/lexer-keywords.txt" - {"i32.ctz", TokenType::Unary, Opcode::I32Ctz}, - {""}, {""}, -#line 477 "src/lexer-keywords.txt" - {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg}, -#line 452 "src/lexer-keywords.txt" - {"i64.store32", TokenType::Store, Opcode::I64Store32}, +#line 487 "src/lexer-keywords.txt" + {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane}, +#line 486 "src/lexer-keywords.txt" + {"i64x2.relaxed_laneselect", TokenType::Ternary, Opcode::I64X2RelaxedLaneSelect}, + {""}, +#line 194 "src/lexer-keywords.txt" + {"hidden", TokenType::Hidden}, +#line 177 "src/lexer-keywords.txt" + {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane}, +#line 575 "src/lexer-keywords.txt" + {"retain", TokenType::Retain}, +#line 467 "src/lexer-keywords.txt" + {"i64x2.add", TokenType::Binary, Opcode::I64X2Add}, + {""}, #line 471 "src/lexer-keywords.txt" - {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne}, + {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul}, +#line 33 "src/lexer-keywords.txt" + {"block", TokenType::Block, Opcode::Block}, +#line 155 "src/lexer-keywords.txt" + {"f64x2.add", TokenType::Binary, Opcode::F64X2Add}, {""}, -#line 56 "src/lexer-keywords.txt" - {"extern", Type::ExternRef, TokenType::Extern}, +#line 167 "src/lexer-keywords.txt" + {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul}, + {""}, {""}, {""}, +#line 573 "src/lexer-keywords.txt" + {"register", TokenType::Register}, +#line 412 "src/lexer-keywords.txt" + {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8}, +#line 274 "src/lexer-keywords.txt" + {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8}, #line 394 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU}, -#line 257 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU}, - {""}, {""}, -#line 392 "src/lexer-keywords.txt" {"i64.atomic.rmw32.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU}, {""}, -#line 113 "src/lexer-keywords.txt" +#line 338 "src/lexer-keywords.txt" + {"i32x4.relaxed_trunc_f32x4_u", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4U}, + {""}, +#line 450 "src/lexer-keywords.txt" + {"i64.shl", TokenType::Binary, Opcode::I64Shl}, +#line 307 "src/lexer-keywords.txt" + {"i32.shl", TokenType::Binary, Opcode::I32Shl}, +#line 337 "src/lexer-keywords.txt" + {"i32x4.relaxed_trunc_f32x4_s", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4S}, +#line 114 "src/lexer-keywords.txt" {"f32x4.relaxed_max", TokenType::Binary, Opcode::F32X4RelaxedMax}, - {""}, {""}, {""}, {""}, {""}, -#line 395 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU}, -#line 258 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU}, {""}, {""}, -#line 188 "src/lexer-keywords.txt" - {"function", TokenType::Function}, -#line 401 "src/lexer-keywords.txt" - {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd}, -#line 264 "src/lexer-keywords.txt" - {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd}, - {""}, -#line 180 "src/lexer-keywords.txt" - {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc}, +#line 358 "src/lexer-keywords.txt" + {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat}, + {""}, {""}, {""}, +#line 118 "src/lexer-keywords.txt" + {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat}, +#line 228 "src/lexer-keywords.txt" + {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane}, +#line 226 "src/lexer-keywords.txt" + {"i16x8.relaxed_laneselect", TokenType::Ternary, Opcode::I16X8RelaxedLaneSelect}, {""}, {""}, -#line 393 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU}, +#line 555 "src/lexer-keywords.txt" + {"memory.size", TokenType::MemorySize, Opcode::MemorySize}, + {""}, +#line 198 "src/lexer-keywords.txt" + {"i16x8.add", TokenType::Binary, Opcode::I16X8Add}, + {""}, +#line 220 "src/lexer-keywords.txt" + {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul}, {""}, {""}, -#line 557 "src/lexer-keywords.txt" - {"nan:canonical", TokenType::NanCanonical}, +#line 355 "src/lexer-keywords.txt" + {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl}, {""}, {""}, -#line 402 "src/lexer-keywords.txt" +#line 404 "src/lexer-keywords.txt" {"i64.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd}, -#line 265 "src/lexer-keywords.txt" +#line 267 "src/lexer-keywords.txt" {"i32.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd}, -#line 154 "src/lexer-keywords.txt" - {"f64x2.add", TokenType::Binary, Opcode::F64X2Add}, -#line 167 "src/lexer-keywords.txt" - {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest}, - {""}, {""}, {""}, -#line 141 "src/lexer-keywords.txt" - {"f64.min", TokenType::Binary, Opcode::F64Min}, -#line 80 "src/lexer-keywords.txt" - {"f32.min", TokenType::Binary, Opcode::F32Min}, -#line 465 "src/lexer-keywords.txt" - {"i64x2.add", TokenType::Binary, Opcode::I64X2Add}, - {""}, {""}, -#line 400 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU}, -#line 263 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU}, - {""}, -#line 459 "src/lexer-keywords.txt" - {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U}, -#line 315 "src/lexer-keywords.txt" - {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U}, {""}, -#line 166 "src/lexer-keywords.txt" - {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul}, -#line 458 "src/lexer-keywords.txt" - {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S}, -#line 314 "src/lexer-keywords.txt" - {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S}, -#line 567 "src/lexer-keywords.txt" - {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull}, -#line 605 "src/lexer-keywords.txt" - {"v128", Type::V128}, - {""}, {""}, -#line 469 "src/lexer-keywords.txt" - {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul}, -#line 433 "src/lexer-keywords.txt" +#line 435 "src/lexer-keywords.txt" {"i64.load32_u", TokenType::Load, Opcode::I64Load32U}, {""}, {""}, {""}, -#line 432 "src/lexer-keywords.txt" +#line 434 "src/lexer-keywords.txt" {"i64.load32_s", TokenType::Load, Opcode::I64Load32S}, - {""}, {""}, {""}, {""}, -#line 556 "src/lexer-keywords.txt" - {"nan:arithmetic", TokenType::NanArithmetic}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 538 "src/lexer-keywords.txt" - {"invoke", TokenType::Invoke}, - {""}, {""}, {""}, {""}, {""}, -#line 378 "src/lexer-keywords.txt" - {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U}, -#line 248 "src/lexer-keywords.txt" - {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U}, +#line 403 "src/lexer-keywords.txt" + {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd}, +#line 266 "src/lexer-keywords.txt" + {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd}, + {""}, {""}, +#line 542 "src/lexer-keywords.txt" + {"item", TokenType::Item}, +#line 570 "src/lexer-keywords.txt" + {"ref.func", TokenType::RefFunc, Opcode::RefFunc}, {""}, -#line 176 "src/lexer-keywords.txt" - {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane}, +#line 57 "src/lexer-keywords.txt" + {"extern", Type::ExternRef, TokenType::Extern}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 485 "src/lexer-keywords.txt" - {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane}, - {""}, -#line 564 "src/lexer-keywords.txt" - {"quote", TokenType::Quote}, -#line 32 "src/lexer-keywords.txt" - {"block", TokenType::Block, Opcode::Block}, - {""}, {""}, -#line 450 "src/lexer-keywords.txt" - {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU}, -#line 307 "src/lexer-keywords.txt" - {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU}, -#line 449 "src/lexer-keywords.txt" - {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS}, -#line 306 "src/lexer-keywords.txt" - {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS}, #line 397 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU}, + {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU}, #line 260 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU}, -#line 240 "src/lexer-keywords.txt" - {"i16x8", TokenType::I16X8}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 355 "src/lexer-keywords.txt" - {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU}, -#line 346 "src/lexer-keywords.txt" - {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU}, -#line 354 "src/lexer-keywords.txt" - {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS}, -#line 345 "src/lexer-keywords.txt" - {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS}, -#line 600 "src/lexer-keywords.txt" - {"v128.or", TokenType::Binary, Opcode::V128Or}, + {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU}, +#line 433 "src/lexer-keywords.txt" + {"i64.load16_u", TokenType::Load, Opcode::I64Load16U}, +#line 292 "src/lexer-keywords.txt" + {"i32.load16_u", TokenType::Load, Opcode::I32Load16U}, {""}, -#line 560 "src/lexer-keywords.txt" - {"output", TokenType::Output}, +#line 186 "src/lexer-keywords.txt" + {"field", TokenType::Field}, +#line 432 "src/lexer-keywords.txt" + {"i64.load16_s", TokenType::Load, Opcode::I64Load16S}, +#line 291 "src/lexer-keywords.txt" + {"i32.load16_s", TokenType::Load, Opcode::I32Load16S}, +#line 396 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU}, +#line 259 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU}, + {""}, {""}, {""}, {""}, +#line 422 "src/lexer-keywords.txt" + {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S}, {""}, {""}, -#line 559 "src/lexer-keywords.txt" - {"offset", TokenType::Offset}, - {""}, -#line 592 "src/lexer-keywords.txt" - {"type", TokenType::Type}, -#line 590 "src/lexer-keywords.txt" - {"try", TokenType::Try, Opcode::Try}, +#line 59 "src/lexer-keywords.txt" + {"exn", Type::ExnRef, TokenType::Exn}, +#line 395 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU}, + {""}, {""}, {""}, {""}, +#line 100 "src/lexer-keywords.txt" + {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, +#line 421 "src/lexer-keywords.txt" + {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S}, +#line 283 "src/lexer-keywords.txt" + {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 580 "src/lexer-keywords.txt" - {"table.fill", TokenType::TableFill, Opcode::TableFill}, - {""}, -#line 484 "src/lexer-keywords.txt" - {"i64x2.relaxed_laneselect", TokenType::Ternary, Opcode::I64X2RelaxedLaneSelect}, -#line 478 "src/lexer-keywords.txt" +#line 480 "src/lexer-keywords.txt" {"i64x2.all_true", TokenType::Unary, Opcode::I64X2AllTrue}, - {""}, {""}, {""}, {""}, {""}, -#line 205 "src/lexer-keywords.txt" - {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU}, -#line 420 "src/lexer-keywords.txt" - {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S}, -#line 209 "src/lexer-keywords.txt" - {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU}, - {""}, -#line 204 "src/lexer-keywords.txt" - {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS}, -#line 40 "src/lexer-keywords.txt" - {"catch_all", TokenType::CatchAll, Opcode::CatchAll}, -#line 208 "src/lexer-keywords.txt" - {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS}, -#line 336 "src/lexer-keywords.txt" - {"i32x4.relaxed_trunc_f32x4_u", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4U}, -#line 207 "src/lexer-keywords.txt" - {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU}, - {""}, -#line 213 "src/lexer-keywords.txt" - {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU}, -#line 335 "src/lexer-keywords.txt" - {"i32x4.relaxed_trunc_f32x4_s", TokenType::Unary, Opcode::I32X4RelaxedTruncF32X4S}, -#line 206 "src/lexer-keywords.txt" - {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS}, - {""}, -#line 212 "src/lexer-keywords.txt" - {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS}, - {""}, {""}, -#line 70 "src/lexer-keywords.txt" - {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64}, - {""}, -#line 164 "src/lexer-keywords.txt" - {"f64x2.max", TokenType::Binary, Opcode::F64X2Max}, - {""}, -#line 117 "src/lexer-keywords.txt" - {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat}, -#line 604 "src/lexer-keywords.txt" - {"v128.store", TokenType::Store, Opcode::V128Store}, -#line 537 "src/lexer-keywords.txt" - {"input", TokenType::Input}, {""}, {""}, -#line 572 "src/lexer-keywords.txt" - {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect}, +#line 106 "src/lexer-keywords.txt" + {"f32x4.min", TokenType::Binary, Opcode::F32X4Min}, {""}, -#line 356 "src/lexer-keywords.txt" - {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat}, -#line 508 "src/lexer-keywords.txt" +#line 510 "src/lexer-keywords.txt" {"i8x16.ge_u", TokenType::Compare, Opcode::I8X16GeU}, -#line 33 "src/lexer-keywords.txt" - {"br_if", TokenType::BrIf, Opcode::BrIf}, + {""}, #line 512 "src/lexer-keywords.txt" - {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU}, + {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU}, {""}, -#line 507 "src/lexer-keywords.txt" +#line 509 "src/lexer-keywords.txt" {"i8x16.ge_s", TokenType::Compare, Opcode::I8X16GeS}, {""}, #line 511 "src/lexer-keywords.txt" - {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS}, + {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS}, {""}, -#line 510 "src/lexer-keywords.txt" - {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU}, -#line 536 "src/lexer-keywords.txt" - {"import", TokenType::Import}, #line 514 "src/lexer-keywords.txt" - {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU}, - {""}, -#line 509 "src/lexer-keywords.txt" - {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS}, + {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU}, {""}, +#line 516 "src/lexer-keywords.txt" + {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU}, +#line 468 "src/lexer-keywords.txt" + {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane}, #line 513 "src/lexer-keywords.txt" + {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS}, +#line 234 "src/lexer-keywords.txt" + {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU}, +#line 515 "src/lexer-keywords.txt" {"i8x16.lt_s", TokenType::Compare, Opcode::I8X16LtS}, - {""}, {""}, {""}, {""}, {""}, -#line 598 "src/lexer-keywords.txt" - {"v128.load", TokenType::Load, Opcode::V128Load}, -#line 158 "src/lexer-keywords.txt" +#line 159 "src/lexer-keywords.txt" {"f64x2.extract_lane", TokenType::SimdLaneOp, Opcode::F64X2ExtractLane}, - {""}, {""}, -#line 221 "src/lexer-keywords.txt" - {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg}, - {""}, -#line 223 "src/lexer-keywords.txt" - {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne}, -#line 423 "src/lexer-keywords.txt" - {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U}, -#line 466 "src/lexer-keywords.txt" - {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane}, -#line 422 "src/lexer-keywords.txt" - {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S}, - {""}, {""}, -#line 148 "src/lexer-keywords.txt" - {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt}, -#line 86 "src/lexer-keywords.txt" - {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt}, -#line 211 "src/lexer-keywords.txt" - {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U}, {""}, -#line 210 "src/lexer-keywords.txt" - {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S}, -#line 611 "src/lexer-keywords.txt" - {"v128.load8_lane", TokenType::SimdLoadLane, Opcode::V128Load8Lane}, -#line 406 "src/lexer-keywords.txt" - {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg}, -#line 269 "src/lexer-keywords.txt" - {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg}, +#line 233 "src/lexer-keywords.txt" + {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS}, {""}, {""}, {""}, -#line 184 "src/lexer-keywords.txt" - {"f64x2", TokenType::F64X2}, - {""}, {""}, -#line 610 "src/lexer-keywords.txt" - {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat}, +#line 556 "src/lexer-keywords.txt" + {"memory", TokenType::Memory}, +#line 32 "src/lexer-keywords.txt" + {"binary", TokenType::Bin}, +#line 380 "src/lexer-keywords.txt" + {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U}, +#line 250 "src/lexer-keywords.txt" + {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U}, +#line 165 "src/lexer-keywords.txt" + {"f64x2.max", TokenType::Binary, Opcode::F64X2Max}, {""}, -#line 599 "src/lexer-keywords.txt" - {"v128.not", TokenType::Unary, Opcode::V128Not}, -#line 618 "src/lexer-keywords.txt" - {"v128.store64_lane", TokenType::SimdStoreLane, Opcode::V128Store64Lane}, -#line 495 "src/lexer-keywords.txt" - {"i64x2", TokenType::I64X2}, -#line 118 "src/lexer-keywords.txt" - {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt}, +#line 142 "src/lexer-keywords.txt" + {"f64.min", TokenType::Binary, Opcode::F64Min}, +#line 81 "src/lexer-keywords.txt" + {"f32.min", TokenType::Binary, Opcode::F32Min}, +#line 199 "src/lexer-keywords.txt" + {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue}, +#line 175 "src/lexer-keywords.txt" + {"f64x2.relaxed_min", TokenType::Binary, Opcode::F64X2RelaxedMin}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 135 "src/lexer-keywords.txt" + {"f64.floor", TokenType::Unary, Opcode::F64Floor}, +#line 74 "src/lexer-keywords.txt" + {"f32.floor", TokenType::Unary, Opcode::F32Floor}, {""}, -#line 521 "src/lexer-keywords.txt" - {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg}, +#line 497 "src/lexer-keywords.txt" + {"i64x2", TokenType::I64X2}, + {""}, {""}, {""}, +#line 185 "src/lexer-keywords.txt" + {"f64x2", TokenType::F64X2}, {""}, -#line 523 "src/lexer-keywords.txt" - {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne}, -#line 44 "src/lexer-keywords.txt" +#line 45 "src/lexer-keywords.txt" {"data.drop", TokenType::DataDrop, Opcode::DataDrop}, + {""}, {""}, +#line 586 "src/lexer-keywords.txt" + {"table.copy", TokenType::TableCopy, Opcode::TableCopy}, +#line 176 "src/lexer-keywords.txt" + {"f64x2.relaxed_nmadd", TokenType::Ternary, Opcode::F64X2RelaxedNmadd}, + {""}, {""}, +#line 525 "src/lexer-keywords.txt" + {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne}, + {""}, {""}, {""}, {""}, {""}, +#line 523 "src/lexer-keywords.txt" + {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg}, +#line 402 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU}, +#line 265 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU}, + {""}, {""}, {""}, +#line 461 "src/lexer-keywords.txt" + {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U}, +#line 317 "src/lexer-keywords.txt" + {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U}, + {""}, {""}, +#line 460 "src/lexer-keywords.txt" + {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S}, +#line 316 "src/lexer-keywords.txt" + {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S}, + {""}, {""}, +#line 600 "src/lexer-keywords.txt" + {"type", TokenType::Type}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 451 "src/lexer-keywords.txt" - {"i64.store16", TokenType::Store, Opcode::I64Store16}, -#line 308 "src/lexer-keywords.txt" - {"i32.store16", TokenType::Store, Opcode::I32Store16}, +#line 540 "src/lexer-keywords.txt" + {"input", TokenType::Input}, {""}, -#line 186 "src/lexer-keywords.txt" - {"funcref", Type::FuncRef}, +#line 197 "src/lexer-keywords.txt" + {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU}, + {""}, {""}, +#line 571 "src/lexer-keywords.txt" + {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull}, #line 196 "src/lexer-keywords.txt" - {"i16x8.add", TokenType::Binary, Opcode::I16X8Add}, - {""}, {""}, {""}, -#line 597 "src/lexer-keywords.txt" - {"v128.const", TokenType::Const, Opcode::V128Const}, + {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS}, +#line 541 "src/lexer-keywords.txt" + {"invoke", TokenType::Invoke}, {""}, -#line 606 "src/lexer-keywords.txt" - {"v128.xor", TokenType::Binary, Opcode::V128Xor}, +#line 538 "src/lexer-keywords.txt" + {"import", TokenType::Import}, + {""}, {""}, {""}, +#line 189 "src/lexer-keywords.txt" + {"function", TokenType::Function}, {""}, {""}, {""}, {""}, {""}, -#line 174 "src/lexer-keywords.txt" - {"f64x2.relaxed_min", TokenType::Binary, Opcode::F64X2RelaxedMin}, - {""}, -#line 175 "src/lexer-keywords.txt" - {"f64x2.relaxed_nmadd", TokenType::Ternary, Opcode::F64X2RelaxedNmadd}, - {""}, -#line 218 "src/lexer-keywords.txt" - {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul}, - {""}, -#line 376 "src/lexer-keywords.txt" - {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U}, -#line 247 "src/lexer-keywords.txt" - {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U}, +#line 149 "src/lexer-keywords.txt" + {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt}, +#line 87 "src/lexer-keywords.txt" + {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 452 "src/lexer-keywords.txt" + {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU}, +#line 309 "src/lexer-keywords.txt" + {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU}, +#line 451 "src/lexer-keywords.txt" + {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS}, +#line 308 "src/lexer-keywords.txt" + {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS}, {""}, {""}, {""}, -#line 39 "src/lexer-keywords.txt" - {"catch", TokenType::Catch, Opcode::Catch}, - {""}, {""}, -#line 486 "src/lexer-keywords.txt" - {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl}, +#line 173 "src/lexer-keywords.txt" + {"f64x2.relaxed_madd", TokenType::Ternary, Opcode::F64X2RelaxedMadd}, +#line 577 "src/lexer-keywords.txt" + {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 119 "src/lexer-keywords.txt" + {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt}, {""}, {""}, -#line 500 "src/lexer-keywords.txt" +#line 528 "src/lexer-keywords.txt" + {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane}, +#line 527 "src/lexer-keywords.txt" + {"i8x16.relaxed_laneselect", TokenType::Ternary, Opcode::I8X16RelaxedLaneSelect}, + {""}, {""}, {""}, {""}, +#line 502 "src/lexer-keywords.txt" {"i8x16.add", TokenType::Binary, Opcode::I8X16Add}, - {""}, -#line 595 "src/lexer-keywords.txt" - {"v128.and", TokenType::Binary, Opcode::V128And}, +#line 217 "src/lexer-keywords.txt" + {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU}, +#line 357 "src/lexer-keywords.txt" + {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU}, +#line 216 "src/lexer-keywords.txt" + {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS}, +#line 356 "src/lexer-keywords.txt" + {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS}, +#line 399 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU}, +#line 262 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU}, +#line 559 "src/lexer-keywords.txt" + {"nan:arithmetic", TokenType::NanArithmetic}, + {""}, {""}, {""}, {""}, {""}, +#line 583 "src/lexer-keywords.txt" + {"start", TokenType::Start}, {""}, {""}, {""}, {""}, -#line 534 "src/lexer-keywords.txt" - {"i8x16", TokenType::I8X16}, - {""}, {""}, -#line 52 "src/lexer-keywords.txt" - {"elem", TokenType::Elem}, +#line 348 "src/lexer-keywords.txt" + {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU}, {""}, -#line 57 "src/lexer-keywords.txt" - {"externref", Type::ExternRef}, - {""}, {""}, -#line 594 "src/lexer-keywords.txt" - {"v128.andnot", TokenType::Binary, Opcode::V128Andnot}, +#line 347 "src/lexer-keywords.txt" + {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS}, +#line 21 "src/lexer-keywords.txt" + {"after", TokenType::After}, +#line 124 "src/lexer-keywords.txt" + {"f64.abs", TokenType::Unary, Opcode::F64Abs}, +#line 62 "src/lexer-keywords.txt" + {"f32.abs", TokenType::Unary, Opcode::F32Abs}, {""}, {""}, -#line 384 "src/lexer-keywords.txt" +#line 71 "src/lexer-keywords.txt" + {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64}, + {""}, {""}, {""}, {""}, {""}, +#line 112 "src/lexer-keywords.txt" + {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin}, + {""}, {""}, {""}, +#line 614 "src/lexer-keywords.txt" + {"v128", Type::V128}, +#line 386 "src/lexer-keywords.txt" {"i64.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU}, -#line 254 "src/lexer-keywords.txt" +#line 256 "src/lexer-keywords.txt" {"i32.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU}, - {""}, -#line 226 "src/lexer-keywords.txt" - {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane}, - {""}, {""}, -#line 159 "src/lexer-keywords.txt" - {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor}, - {""}, {""}, -#line 468 "src/lexer-keywords.txt" - {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U}, -#line 172 "src/lexer-keywords.txt" - {"f64x2.relaxed_madd", TokenType::Ternary, Opcode::F64X2RelaxedMadd}, - {""}, {""}, -#line 467 "src/lexer-keywords.txt" - {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 560 "src/lexer-keywords.txt" + {"nan:canonical", TokenType::NanCanonical}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 36 "src/lexer-keywords.txt" - {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect}, +#line 174 "src/lexer-keywords.txt" + {"f64x2.relaxed_max", TokenType::Binary, Opcode::F64X2RelaxedMax}, {""}, -#line 526 "src/lexer-keywords.txt" - {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane}, +#line 359 "src/lexer-keywords.txt" + {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub}, +#line 491 "src/lexer-keywords.txt" + {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat}, +#line 324 "src/lexer-keywords.txt" + {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs}, + {""}, +#line 120 "src/lexer-keywords.txt" + {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub}, +#line 178 "src/lexer-keywords.txt" + {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat}, +#line 92 "src/lexer-keywords.txt" + {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs}, + {""}, +#line 35 "src/lexer-keywords.txt" + {"br_table", TokenType::BrTable, Opcode::BrTable}, {""}, {""}, {""}, {""}, {""}, -#line 165 "src/lexer-keywords.txt" - {"f64x2.min", TokenType::Binary, Opcode::F64X2Min}, -#line 383 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU}, -#line 253 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 224 "src/lexer-keywords.txt" - {"i16x8.relaxed_laneselect", TokenType::Ternary, Opcode::I16X8RelaxedLaneSelect}, -#line 197 "src/lexer-keywords.txt" - {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue}, +#line 613 "src/lexer-keywords.txt" + {"v128.store", TokenType::Store, Opcode::V128Store}, +#line 41 "src/lexer-keywords.txt" + {"catch_all", TokenType::CatchAll, Opcode::CatchAll}, +#line 587 "src/lexer-keywords.txt" + {"table.fill", TokenType::TableFill, Opcode::TableFill}, +#line 488 "src/lexer-keywords.txt" + {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl}, + {""}, +#line 609 "src/lexer-keywords.txt" + {"v128.or", TokenType::Binary, Opcode::V128Or}, {""}, {""}, -#line 21 "src/lexer-keywords.txt" - {"after", TokenType::After}, #line 552 "src/lexer-keywords.txt" - {"memory.size", TokenType::MemorySize, Opcode::MemorySize}, -#line 173 "src/lexer-keywords.txt" - {"f64x2.relaxed_max", TokenType::Binary, Opcode::F64X2RelaxedMax}, -#line 380 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU}, -#line 250 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU}, -#line 399 "src/lexer-keywords.txt" - {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU}, -#line 262 "src/lexer-keywords.txt" - {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU}, -#line 232 "src/lexer-keywords.txt" - {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU}, - {""}, {""}, {""}, -#line 231 "src/lexer-keywords.txt" - {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS}, - {""}, {""}, {""}, -#line 381 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU}, -#line 251 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU}, -#line 347 "src/lexer-keywords.txt" - {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S}, + {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill}, +#line 408 "src/lexer-keywords.txt" + {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg}, +#line 271 "src/lexer-keywords.txt" + {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg}, +#line 425 "src/lexer-keywords.txt" + {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U}, {""}, -#line 389 "src/lexer-keywords.txt" - {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU}, +#line 424 "src/lexer-keywords.txt" + {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S}, {""}, {""}, {""}, {""}, {""}, -#line 525 "src/lexer-keywords.txt" - {"i8x16.relaxed_laneselect", TokenType::Ternary, Opcode::I8X16RelaxedLaneSelect}, -#line 501 "src/lexer-keywords.txt" - {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue}, - {""}, {""}, {""}, {""}, -#line 577 "src/lexer-keywords.txt" - {"start", TokenType::Start}, - {""}, -#line 123 "src/lexer-keywords.txt" - {"f64.abs", TokenType::Unary, Opcode::F64Abs}, -#line 61 "src/lexer-keywords.txt" - {"f32.abs", TokenType::Unary, Opcode::F32Abs}, +#line 34 "src/lexer-keywords.txt" + {"br_if", TokenType::BrIf, Opcode::BrIf}, {""}, -#line 532 "src/lexer-keywords.txt" +#line 232 "src/lexer-keywords.txt" + {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 534 "src/lexer-keywords.txt" {"i8x16.sub_sat_u", TokenType::Binary, Opcode::I8X16SubSatU}, {""}, {""}, {""}, -#line 531 "src/lexer-keywords.txt" +#line 533 "src/lexer-keywords.txt" {"i8x16.sub_sat_s", TokenType::Binary, Opcode::I8X16SubSatS}, -#line 616 "src/lexer-keywords.txt" - {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 119 "src/lexer-keywords.txt" - {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub}, + {""}, {""}, {""}, {""}, +#line 229 "src/lexer-keywords.txt" + {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl}, +#line 383 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU}, +#line 253 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU}, {""}, {""}, -#line 91 "src/lexer-keywords.txt" - {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs}, +#line 627 "src/lexer-keywords.txt" + {"v128.store64_lane", TokenType::SimdStoreLane, Opcode::V128Store64Lane}, {""}, -#line 608 "src/lexer-keywords.txt" - {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat}, -#line 562 "src/lexer-keywords.txt" - {"param", TokenType::Param}, -#line 357 "src/lexer-keywords.txt" - {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub}, -#line 96 "src/lexer-keywords.txt" - {"f32x4.div", TokenType::Binary, Opcode::F32X4Div}, -#line 602 "src/lexer-keywords.txt" - {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero}, -#line 322 "src/lexer-keywords.txt" - {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs}, -#line 34 "src/lexer-keywords.txt" - {"br_table", TokenType::BrTable, Opcode::BrTable}, - {""}, {""}, {""}, -#line 195 "src/lexer-keywords.txt" - {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU}, - {""}, {""}, {""}, -#line 194 "src/lexer-keywords.txt" - {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS}, +#line 503 "src/lexer-keywords.txt" + {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue}, {""}, -#line 111 "src/lexer-keywords.txt" - {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin}, -#line 31 "src/lexer-keywords.txt" - {"binary", TokenType::Bin}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 463 "src/lexer-keywords.txt" - {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U}, -#line 319 "src/lexer-keywords.txt" - {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U}, +#line 382 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU}, +#line 252 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU}, + {""}, {""}, {""}, +#line 160 "src/lexer-keywords.txt" + {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 608 "src/lexer-keywords.txt" + {"v128.not", TokenType::Unary, Opcode::V128Not}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 200 "src/lexer-keywords.txt" + {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU}, +#line 205 "src/lexer-keywords.txt" + {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU}, + {""}, +#line 204 "src/lexer-keywords.txt" + {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS}, +#line 22 "src/lexer-keywords.txt" + {"align", TokenType::Align}, +#line 166 "src/lexer-keywords.txt" + {"f64x2.min", TokenType::Binary, Opcode::F64X2Min}, +#line 58 "src/lexer-keywords.txt" + {"externref", Type::ExternRef}, + {""}, {""}, #line 385 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU}, + {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU}, #line 255 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU}, -#line 462 "src/lexer-keywords.txt" - {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S}, -#line 318 "src/lexer-keywords.txt" - {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S}, + {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU}, + {""}, +#line 607 "src/lexer-keywords.txt" + {"v128.load", TokenType::Load, Opcode::V128Load}, {""}, {""}, -#line 613 "src/lexer-keywords.txt" - {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 499 "src/lexer-keywords.txt" - {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU}, -#line 377 "src/lexer-keywords.txt" - {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U}, +#line 602 "src/lexer-keywords.txt" + {"weak", TokenType::Weak}, {""}, -#line 615 "src/lexer-keywords.txt" - {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane}, -#line 498 "src/lexer-keywords.txt" +#line 599 "src/lexer-keywords.txt" + {"try_table", TokenType::TryTable, Opcode::TryTable}, + {""}, {""}, {""}, {""}, {""}, +#line 581 "src/lexer-keywords.txt" + {"shared", TokenType::Shared}, +#line 606 "src/lexer-keywords.txt" + {"v128.const", TokenType::Const, Opcode::V128Const}, + {""}, {""}, +#line 50 "src/lexer-keywords.txt" + {"drop", TokenType::Drop, Opcode::Drop}, + {""}, {""}, {""}, +#line 501 "src/lexer-keywords.txt" + {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU}, + {""}, {""}, +#line 604 "src/lexer-keywords.txt" + {"v128.and", TokenType::Binary, Opcode::V128And}, +#line 500 "src/lexer-keywords.txt" {"i8x16.add_sat_s", TokenType::Binary, Opcode::I8X16AddSatS}, {""}, -#line 386 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU}, -#line 256 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU}, +#line 187 "src/lexer-keywords.txt" + {"funcref", Type::FuncRef}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 536 "src/lexer-keywords.txt" + {"i8x16", TokenType::I8X16}, +#line 619 "src/lexer-keywords.txt" + {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat}, + {""}, {""}, +#line 420 "src/lexer-keywords.txt" + {"i64.eqz", TokenType::Convert, Opcode::I64Eqz}, +#line 282 "src/lexer-keywords.txt" + {"i32.eqz", TokenType::Convert, Opcode::I32Eqz}, {""}, -#line 192 "src/lexer-keywords.txt" - {"global", TokenType::Global}, -#line 215 "src/lexer-keywords.txt" - {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU}, +#line 620 "src/lexer-keywords.txt" + {"v128.load8_lane", TokenType::SimdLoadLane, Opcode::V128Load8Lane}, +#line 453 "src/lexer-keywords.txt" + {"i64.store16", TokenType::Store, Opcode::I64Store16}, +#line 310 "src/lexer-keywords.txt" + {"i32.store16", TokenType::Store, Opcode::I32Store16}, +#line 53 "src/lexer-keywords.txt" + {"elem", TokenType::Elem}, {""}, -#line 214 "src/lexer-keywords.txt" - {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS}, +#line 111 "src/lexer-keywords.txt" + {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 379 "src/lexer-keywords.txt" + {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U}, {""}, {""}, {""}, {""}, -#line 488 "src/lexer-keywords.txt" - {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU}, +#line 603 "src/lexer-keywords.txt" + {"v128.andnot", TokenType::Binary, Opcode::V128Andnot}, +#line 193 "src/lexer-keywords.txt" + {"global", TokenType::Global}, +#line 192 "src/lexer-keywords.txt" + {"global.set", TokenType::GlobalSet, Opcode::GlobalSet}, +#line 411 "src/lexer-keywords.txt" + {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32}, {""}, -#line 487 "src/lexer-keywords.txt" - {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS}, +#line 191 "src/lexer-keywords.txt" + {"global.get", TokenType::GlobalGet, Opcode::GlobalGet}, +#line 391 "src/lexer-keywords.txt" + {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU}, {""}, -#line 549 "src/lexer-keywords.txt" - {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill}, - {""}, {""}, {""}, {""}, -#line 326 "src/lexer-keywords.txt" - {"i32x4.relaxed_dot_i8x16_i7x16_add_s", TokenType::Ternary, Opcode::I32X4DotI8X16I7X16AddS}, -#line 41 "src/lexer-keywords.txt" - {"catch_ref", TokenType::CatchRef}, - {""}, {""}, {""}, -#line 579 "src/lexer-keywords.txt" - {"table.copy", TokenType::TableCopy, Opcode::TableCopy}, +#line 387 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU}, +#line 257 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU}, {""}, -#line 227 "src/lexer-keywords.txt" - {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl}, - {""}, {""}, {""}, {""}, {""}, -#line 516 "src/lexer-keywords.txt" +#line 566 "src/lexer-keywords.txt" + {"param", TokenType::Param}, +#line 615 "src/lexer-keywords.txt" + {"v128.xor", TokenType::Binary, Opcode::V128Xor}, +#line 97 "src/lexer-keywords.txt" + {"f32x4.div", TokenType::Binary, Opcode::F32X4Div}, + {""}, {""}, +#line 378 "src/lexer-keywords.txt" + {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U}, +#line 249 "src/lexer-keywords.txt" + {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U}, +#line 518 "src/lexer-keywords.txt" {"i8x16.max_u", TokenType::Binary, Opcode::I8X16MaxU}, {""}, -#line 515 "src/lexer-keywords.txt" +#line 517 "src/lexer-keywords.txt" {"i8x16.max_s", TokenType::Binary, Opcode::I8X16MaxS}, - {""}, {""}, -#line 576 "src/lexer-keywords.txt" - {"shared", TokenType::Shared}, -#line 130 "src/lexer-keywords.txt" + {""}, {""}, {""}, +#line 470 "src/lexer-keywords.txt" + {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U}, + {""}, {""}, {""}, +#line 469 "src/lexer-keywords.txt" + {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S}, + {""}, {""}, {""}, {""}, {""}, +#line 37 "src/lexer-keywords.txt" + {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 131 "src/lexer-keywords.txt" {"f64.convert_i64_u", TokenType::Convert, Opcode::F64ConvertI64U}, -#line 68 "src/lexer-keywords.txt" +#line 69 "src/lexer-keywords.txt" {"f32.convert_i64_u", TokenType::Convert, Opcode::F32ConvertI64U}, - {""}, {""}, -#line 129 "src/lexer-keywords.txt" +#line 465 "src/lexer-keywords.txt" + {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U}, +#line 321 "src/lexer-keywords.txt" + {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U}, +#line 130 "src/lexer-keywords.txt" {"f64.convert_i64_s", TokenType::Convert, Opcode::F64ConvertI64S}, -#line 67 "src/lexer-keywords.txt" +#line 68 "src/lexer-keywords.txt" {"f32.convert_i64_s", TokenType::Convert, Opcode::F32ConvertI64S}, - {""}, {""}, {""}, {""}, {""}, -#line 60 "src/lexer-keywords.txt" - {"export", TokenType::Export}, - {""}, {""}, {""}, {""}, {""}, -#line 527 "src/lexer-keywords.txt" - {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl}, -#line 553 "src/lexer-keywords.txt" - {"memory", TokenType::Memory}, -#line 593 "src/lexer-keywords.txt" - {"unreachable", TokenType::Unreachable, Opcode::Unreachable}, +#line 464 "src/lexer-keywords.txt" + {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S}, +#line 320 "src/lexer-keywords.txt" + {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S}, {""}, -#line 177 "src/lexer-keywords.txt" - {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat}, -#line 110 "src/lexer-keywords.txt" - {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax}, -#line 372 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero}, +#line 40 "src/lexer-keywords.txt" + {"catch", TokenType::Catch, Opcode::Catch}, + {""}, {""}, {""}, +#line 213 "src/lexer-keywords.txt" + {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U}, {""}, -#line 371 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero}, +#line 212 "src/lexer-keywords.txt" + {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S}, {""}, -#line 190 "src/lexer-keywords.txt" - {"global.get", TokenType::GlobalGet, Opcode::GlobalGet}, -#line 489 "src/lexer-keywords.txt" - {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat}, -#line 191 "src/lexer-keywords.txt" - {"global.set", TokenType::GlobalSet, Opcode::GlobalSet}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 409 "src/lexer-keywords.txt" - {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32}, - {""}, {""}, -#line 59 "src/lexer-keywords.txt" - {"exnref", Type::ExnRef}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 609 "src/lexer-keywords.txt" - {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat}, -#line 617 "src/lexer-keywords.txt" - {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane}, -#line 178 "src/lexer-keywords.txt" +#line 610 "src/lexer-keywords.txt" + {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 179 "src/lexer-keywords.txt" {"f64x2.sqrt", TokenType::Unary, Opcode::F64X2Sqrt}, -#line 588 "src/lexer-keywords.txt" - {"throw", TokenType::Throw, Opcode::Throw}, -#line 603 "src/lexer-keywords.txt" - {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero}, - {""}, {""}, {""}, {""}, -#line 37 "src/lexer-keywords.txt" - {"call_ref", TokenType::CallRef, Opcode::CallRef}, - {""}, {""}, -#line 551 "src/lexer-keywords.txt" - {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit}, -#line 416 "src/lexer-keywords.txt" - {"i64.div_u", TokenType::Binary, Opcode::I64DivU}, -#line 278 "src/lexer-keywords.txt" - {"i32.div_u", TokenType::Binary, Opcode::I32DivU}, -#line 415 "src/lexer-keywords.txt" - {"i64.div_s", TokenType::Binary, Opcode::I64DivS}, -#line 277 "src/lexer-keywords.txt" - {"i32.div_s", TokenType::Binary, Opcode::I32DivS}, - {""}, {""}, {""}, {""}, -#line 418 "src/lexer-keywords.txt" - {"i64.eqz", TokenType::Convert, Opcode::I64Eqz}, -#line 280 "src/lexer-keywords.txt" - {"i32.eqz", TokenType::Convert, Opcode::I32Eqz}, {""}, {""}, -#line 589 "src/lexer-keywords.txt" - {"throw_ref", TokenType::ThrowRef, Opcode::ThrowRef}, - {""}, -#line 203 "src/lexer-keywords.txt" - {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU}, +#line 601 "src/lexer-keywords.txt" + {"unreachable", TokenType::Unreachable, Opcode::Unreachable}, +#line 349 "src/lexer-keywords.txt" + {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S}, + {""}, {""}, {""}, +#line 388 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU}, +#line 258 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU}, {""}, -#line 202 "src/lexer-keywords.txt" - {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS}, - {""}, {""}, -#line 614 "src/lexer-keywords.txt" - {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane}, -#line 396 "src/lexer-keywords.txt" +#line 490 "src/lexer-keywords.txt" + {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU}, + {""}, +#line 489 "src/lexer-keywords.txt" + {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS}, + {""}, {""}, {""}, {""}, +#line 398 "src/lexer-keywords.txt" {"i64.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU}, -#line 259 "src/lexer-keywords.txt" +#line 261 "src/lexer-keywords.txt" {"i32.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 408 "src/lexer-keywords.txt" - {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16}, -#line 271 "src/lexer-keywords.txt" - {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16}, + {""}, {""}, {""}, {""}, {""}, +#line 547 "src/lexer-keywords.txt" + {"loop", TokenType::Loop, Opcode::Loop}, +#line 401 "src/lexer-keywords.txt" + {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU}, +#line 264 "src/lexer-keywords.txt" + {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU}, + {""}, {""}, {""}, {""}, +#line 532 "src/lexer-keywords.txt" + {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat}, {""}, {""}, -#line 591 "src/lexer-keywords.txt" - {"try_table", TokenType::TryTable, Opcode::TryTable}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 601 "src/lexer-keywords.txt" - {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue}, - {""}, -#line 506 "src/lexer-keywords.txt" - {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU}, -#line 366 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U}, -#line 505 "src/lexer-keywords.txt" - {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS}, +#line 444 "src/lexer-keywords.txt" + {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt}, +#line 301 "src/lexer-keywords.txt" + {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt}, {""}, {""}, -#line 365 "src/lexer-keywords.txt" - {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S}, - {""}, {""}, {""}, {""}, -#line 49 "src/lexer-keywords.txt" - {"drop", TokenType::Drop, Opcode::Drop}, +#line 405 "src/lexer-keywords.txt" + {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg}, +#line 268 "src/lexer-keywords.txt" + {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg}, +#line 172 "src/lexer-keywords.txt" + {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin}, {""}, {""}, {""}, -#line 582 "src/lexer-keywords.txt" - {"table.grow", TokenType::TableGrow, Opcode::TableGrow}, - {""}, {""}, -#line 571 "src/lexer-keywords.txt" - {"rethrow", TokenType::Rethrow, Opcode::Rethrow}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 229 "src/lexer-keywords.txt" +#line 231 "src/lexer-keywords.txt" {"i16x8.shr_u", TokenType::Binary, Opcode::I16X8ShrU}, -#line 217 "src/lexer-keywords.txt" - {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU}, -#line 228 "src/lexer-keywords.txt" + {""}, +#line 230 "src/lexer-keywords.txt" {"i16x8.shr_s", TokenType::Binary, Opcode::I16X8ShrS}, -#line 216 "src/lexer-keywords.txt" +#line 529 "src/lexer-keywords.txt" + {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 554 "src/lexer-keywords.txt" + {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit}, +#line 617 "src/lexer-keywords.txt" + {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat}, +#line 492 "src/lexer-keywords.txt" + {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub}, + {""}, +#line 478 "src/lexer-keywords.txt" + {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs}, +#line 219 "src/lexer-keywords.txt" + {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU}, +#line 180 "src/lexer-keywords.txt" + {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub}, +#line 218 "src/lexer-keywords.txt" {"i16x8.min_s", TokenType::Binary, Opcode::I16X8MinS}, - {""}, {""}, {""}, {""}, {""}, -#line 403 "src/lexer-keywords.txt" - {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg}, -#line 266 "src/lexer-keywords.txt" - {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg}, +#line 154 "src/lexer-keywords.txt" + {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs}, {""}, -#line 121 "src/lexer-keywords.txt" - {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero}, +#line 27 "src/lexer-keywords.txt" + {"assert_return", TokenType::AssertReturn}, +#line 61 "src/lexer-keywords.txt" + {"export", TokenType::Export}, {""}, {""}, -#line 42 "src/lexer-keywords.txt" - {"catch_all_ref", TokenType::CatchAllRef}, +#line 368 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U}, + {""}, {""}, {""}, +#line 367 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S}, + {""}, {""}, {""}, {""}, {""}, +#line 504 "src/lexer-keywords.txt" + {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU}, +#line 508 "src/lexer-keywords.txt" + {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU}, + {""}, +#line 507 "src/lexer-keywords.txt" + {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS}, + {""}, {""}, {""}, {""}, {""}, +#line 551 "src/lexer-keywords.txt" + {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy}, +#line 624 "src/lexer-keywords.txt" + {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane}, + {""}, +#line 235 "src/lexer-keywords.txt" + {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub}, + {""}, +#line 195 "src/lexer-keywords.txt" + {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 622 "src/lexer-keywords.txt" + {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, -#line 529 "src/lexer-keywords.txt" - {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU}, -#line 518 "src/lexer-keywords.txt" - {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU}, -#line 528 "src/lexer-keywords.txt" - {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS}, -#line 517 "src/lexer-keywords.txt" - {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS}, {""}, {""}, {""}, -#line 26 "src/lexer-keywords.txt" - {"assert_return", TokenType::AssertReturn}, -#line 550 "src/lexer-keywords.txt" - {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow}, +#line 626 "src/lexer-keywords.txt" + {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 539 "src/lexer-keywords.txt" + {"init_prio", TokenType::InitPrio}, {""}, {""}, {""}, {""}, -#line 398 "src/lexer-keywords.txt" +#line 400 "src/lexer-keywords.txt" {"i64.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU}, -#line 261 "src/lexer-keywords.txt" +#line 263 "src/lexer-keywords.txt" {"i32.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU}, +#line 418 "src/lexer-keywords.txt" + {"i64.div_u", TokenType::Binary, Opcode::I64DivU}, +#line 280 "src/lexer-keywords.txt" + {"i32.div_u", TokenType::Binary, Opcode::I32DivU}, +#line 417 "src/lexer-keywords.txt" + {"i64.div_s", TokenType::Binary, Opcode::I64DivS}, +#line 279 "src/lexer-keywords.txt" + {"i32.div_s", TokenType::Binary, Opcode::I32DivS}, +#line 625 "src/lexer-keywords.txt" + {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 611 "src/lexer-keywords.txt" + {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 198 "src/lexer-keywords.txt" - {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU}, -#line 230 "src/lexer-keywords.txt" - {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat}, {""}, {""}, {""}, -#line 340 "src/lexer-keywords.txt" - {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U}, +#line 42 "src/lexer-keywords.txt" + {"catch_ref", TokenType::CatchRef}, {""}, -#line 558 "src/lexer-keywords.txt" - {"nop", TokenType::Nop, Opcode::Nop}, +#line 553 "src/lexer-keywords.txt" + {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow}, +#line 524 "src/lexer-keywords.txt" + {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 339 "src/lexer-keywords.txt" - {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 179 "src/lexer-keywords.txt" - {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub}, +#line 526 "src/lexer-keywords.txt" + {"i8x16.relaxed_swizzle", TokenType::Binary, Opcode::I8X16RelaxedSwizzle}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 227 "src/lexer-keywords.txt" + {"i16x8.relaxed_q15mulr_s", TokenType::Binary, Opcode::I16X8RelaxedQ15mulrS}, + {""}, {""}, {""}, {""}, {""}, +#line 171 "src/lexer-keywords.txt" + {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax}, {""}, {""}, -#line 153 "src/lexer-keywords.txt" - {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs}, - {""}, {""}, {""}, -#line 490 "src/lexer-keywords.txt" - {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub}, -#line 156 "src/lexer-keywords.txt" - {"f64x2.div", TokenType::Binary, Opcode::F64X2Div}, +#line 20 "src/lexer-keywords.txt" + {"array", Type::Array, TokenType::Array}, {""}, -#line 476 "src/lexer-keywords.txt" - {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs}, -#line 502 "src/lexer-keywords.txt" - {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU}, -#line 530 "src/lexer-keywords.txt" - {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 171 "src/lexer-keywords.txt" - {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin}, +#line 328 "src/lexer-keywords.txt" + {"i32x4.relaxed_dot_i8x16_i7x16_add_s", TokenType::Ternary, Opcode::I32X4DotI8X16I7X16AddS}, {""}, {""}, -#line 544 "src/lexer-keywords.txt" - {"loop", TokenType::Loop, Opcode::Loop}, +#line 562 "src/lexer-keywords.txt" + {"nop", TokenType::Nop, Opcode::Nop}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 157 "src/lexer-keywords.txt" + {"f64x2.div", TokenType::Binary, Opcode::F64X2Div}, {""}, {""}, {""}, {""}, {""}, -#line 461 "src/lexer-keywords.txt" +#line 38 "src/lexer-keywords.txt" + {"call_ref", TokenType::CallRef, Opcode::CallRef}, + {""}, {""}, {""}, {""}, +#line 374 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero}, + {""}, +#line 373 "src/lexer-keywords.txt" + {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 327 "src/lexer-keywords.txt" + {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask}, + {""}, +#line 129 "src/lexer-keywords.txt" + {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U}, +#line 67 "src/lexer-keywords.txt" + {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U}, +#line 463 "src/lexer-keywords.txt" {"i64.trunc_sat_f32_u", TokenType::Convert, Opcode::I64TruncSatF32U}, -#line 317 "src/lexer-keywords.txt" +#line 319 "src/lexer-keywords.txt" {"i32.trunc_sat_f32_u", TokenType::Convert, Opcode::I32TruncSatF32U}, -#line 133 "src/lexer-keywords.txt" - {"f64.eq", TokenType::Compare, Opcode::F64Eq}, -#line 72 "src/lexer-keywords.txt" - {"f32.eq", TokenType::Compare, Opcode::F32Eq}, -#line 460 "src/lexer-keywords.txt" +#line 128 "src/lexer-keywords.txt" + {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S}, +#line 66 "src/lexer-keywords.txt" + {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S}, +#line 462 "src/lexer-keywords.txt" {"i64.trunc_sat_f32_s", TokenType::Convert, Opcode::I64TruncSatF32S}, -#line 316 "src/lexer-keywords.txt" +#line 318 "src/lexer-keywords.txt" {"i32.trunc_sat_f32_s", TokenType::Convert, Opcode::I32TruncSatF32S}, +#line 531 "src/lexer-keywords.txt" + {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU}, + {""}, +#line 530 "src/lexer-keywords.txt" + {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS}, + {""}, {""}, {""}, {""}, {""}, +#line 60 "src/lexer-keywords.txt" + {"exnref", Type::ExnRef}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 520 "src/lexer-keywords.txt" + {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU}, + {""}, +#line 519 "src/lexer-keywords.txt" + {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 132 "src/lexer-keywords.txt" + {"f64.copysign", TokenType::Binary, Opcode::F64Copysign}, +#line 70 "src/lexer-keywords.txt" + {"f32.copysign", TokenType::Binary, Opcode::F32Copysign}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 417 "src/lexer-keywords.txt" +#line 596 "src/lexer-keywords.txt" + {"throw_ref", TokenType::ThrowRef, Opcode::ThrowRef}, + {""}, {""}, {""}, {""}, {""}, +#line 535 "src/lexer-keywords.txt" + {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub}, +#line 26 "src/lexer-keywords.txt" + {"assert_malformed", TokenType::AssertMalformed}, +#line 499 "src/lexer-keywords.txt" + {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 419 "src/lexer-keywords.txt" {"i64.eq", TokenType::Compare, Opcode::I64Eq}, -#line 279 "src/lexer-keywords.txt" +#line 281 "src/lexer-keywords.txt" {"i32.eq", TokenType::Compare, Opcode::I32Eq}, -#line 325 "src/lexer-keywords.txt" - {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask}, - {""}, {""}, {""}, {""}, -#line 442 "src/lexer-keywords.txt" - {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt}, -#line 299 "src/lexer-keywords.txt" - {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt}, {""}, {""}, -#line 382 "src/lexer-keywords.txt" - {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU}, -#line 252 "src/lexer-keywords.txt" - {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU}, +#line 134 "src/lexer-keywords.txt" + {"f64.eq", TokenType::Compare, Opcode::F64Eq}, +#line 73 "src/lexer-keywords.txt" + {"f32.eq", TokenType::Compare, Opcode::F32Eq}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, -#line 97 "src/lexer-keywords.txt" + {""}, {""}, +#line 595 "src/lexer-keywords.txt" + {"throw", TokenType::Throw, Opcode::Throw}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 329 "src/lexer-keywords.txt" + {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq}, + {""}, {""}, {""}, +#line 98 "src/lexer-keywords.txt" {"f32x4.eq", TokenType::Compare, Opcode::F32X4Eq}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 327 "src/lexer-keywords.txt" - {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq}, +#line 384 "src/lexer-keywords.txt" + {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU}, +#line 254 "src/lexer-keywords.txt" + {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU}, + {""}, +#line 618 "src/lexer-keywords.txt" + {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat}, +#line 629 "src/lexer-keywords.txt" + {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle}, + {""}, {""}, +#line 133 "src/lexer-keywords.txt" + {"f64.div", TokenType::Binary, Opcode::F64Div}, +#line 72 "src/lexer-keywords.txt" + {"f32.div", TokenType::Binary, Opcode::F32Div}, + {""}, +#line 589 "src/lexer-keywords.txt" + {"table.grow", TokenType::TableGrow, Opcode::TableGrow}, + {""}, {""}, +#line 43 "src/lexer-keywords.txt" + {"catch_all_ref", TokenType::CatchAllRef}, + {""}, {""}, {""}, {""}, +#line 342 "src/lexer-keywords.txt" + {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U}, + {""}, {""}, {""}, +#line 341 "src/lexer-keywords.txt" + {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S}, + {""}, {""}, {""}, +#line 52 "src/lexer-keywords.txt" + {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 410 "src/lexer-keywords.txt" + {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16}, +#line 273 "src/lexer-keywords.txt" + {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16}, + {""}, +#line 28 "src/lexer-keywords.txt" + {"assert_trap", TokenType::AssertTrap}, {""}, {""}, {""}, {""}, {""}, -#line 482 "src/lexer-keywords.txt" +#line 623 "src/lexer-keywords.txt" + {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 628 "src/lexer-keywords.txt" + {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, +#line 484 "src/lexer-keywords.txt" {"i64x2.extend_low_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendLowI32X4U}, {""}, -#line 480 "src/lexer-keywords.txt" +#line 482 "src/lexer-keywords.txt" {"i64x2.extend_low_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendLowI32X4S}, -#line 522 "src/lexer-keywords.txt" - {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt}, {""}, {""}, -#line 607 "src/lexer-keywords.txt" +#line 576 "src/lexer-keywords.txt" + {"rethrow", TokenType::Rethrow, Opcode::Rethrow}, + {""}, {""}, +#line 122 "src/lexer-keywords.txt" + {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 457 "src/lexer-keywords.txt" + {"i64.sub", TokenType::Binary, Opcode::I64Sub}, +#line 313 "src/lexer-keywords.txt" + {"i32.sub", TokenType::Binary, Opcode::I32Sub}, + {""}, {""}, +#line 151 "src/lexer-keywords.txt" + {"f64.sub", TokenType::Binary, Opcode::F64Sub}, +#line 89 "src/lexer-keywords.txt" + {"f32.sub", TokenType::Binary, Opcode::F32Sub}, + {""}, +#line 612 "src/lexer-keywords.txt" + {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 616 "src/lexer-keywords.txt" {"v128.load16_splat", TokenType::Load, Opcode::V128Load16Splat}, + {""}, {""}, {""}, +#line 96 "src/lexer-keywords.txt" + {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U}, + {""}, +#line 95 "src/lexer-keywords.txt" + {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S}, +#line 202 "src/lexer-keywords.txt" + {"i16x8.relaxed_dot_i8x16_i7x16_s", TokenType::Binary, Opcode::I16X8DotI8X16I7X16S}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 222 "src/lexer-keywords.txt" + {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U}, + {""}, +#line 221 "src/lexer-keywords.txt" + {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S}, {""}, {""}, {""}, {""}, {""}, -#line 128 "src/lexer-keywords.txt" - {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U}, -#line 66 "src/lexer-keywords.txt" - {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U}, - {""}, {""}, -#line 127 "src/lexer-keywords.txt" - {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S}, -#line 65 "src/lexer-keywords.txt" - {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S}, +#line 495 "src/lexer-keywords.txt" + {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U}, {""}, -#line 368 "src/lexer-keywords.txt" - {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U}, +#line 493 "src/lexer-keywords.txt" + {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S}, {""}, -#line 367 "src/lexer-keywords.txt" - {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S}, +#line 481 "src/lexer-keywords.txt" + {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask}, +#line 323 "src/lexer-keywords.txt" + {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 170 "src/lexer-keywords.txt" - {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax}, - {""}, {""}, {""}, {""}, -#line 612 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 621 "src/lexer-keywords.txt" {"v128.load16_lane", TokenType::SimdLoadLane, Opcode::V128Load16Lane}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 147 "src/lexer-keywords.txt" + {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32}, {""}, {""}, -#line 619 "src/lexer-keywords.txt" - {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle}, - {""}, {""}, -#line 359 "src/lexer-keywords.txt" - {"i32x4.extadd_pairwise_i16x8_u", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U}, +#line 201 "src/lexer-keywords.txt" + {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 246 "src/lexer-keywords.txt" + {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U}, {""}, -#line 358 "src/lexer-keywords.txt" - {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S}, - {""}, {""}, -#line 25 "src/lexer-keywords.txt" - {"assert_malformed", TokenType::AssertMalformed}, - {""}, {""}, {""}, -#line 51 "src/lexer-keywords.txt" - {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop}, +#line 245 "src/lexer-keywords.txt" + {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S}, +#line 565 "src/lexer-keywords.txt" + {"pagesize", TokenType::PageSize}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 493 "src/lexer-keywords.txt" - {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U}, -#line 524 "src/lexer-keywords.txt" - {"i8x16.relaxed_swizzle", TokenType::Binary, Opcode::I8X16RelaxedSwizzle}, -#line 491 "src/lexer-keywords.txt" - {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S}, - {""}, {""}, {""}, {""}, {""}, -#line 370 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, +#line 148 "src/lexer-keywords.txt" + {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 372 "src/lexer-keywords.txt" {"i32x4.extend_low_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendLowI16X8U}, {""}, -#line 369 "src/lexer-keywords.txt" +#line 371 "src/lexer-keywords.txt" {"i32x4.extend_low_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendLowI16X8S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 363 "src/lexer-keywords.txt" - {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U}, - {""}, -#line 361 "src/lexer-keywords.txt" - {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S}, - {""}, -#line 147 "src/lexer-keywords.txt" - {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64}, - {""}, {""}, -#line 321 "src/lexer-keywords.txt" - {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64}, - {""}, {""}, {""}, {""}, -#line 620 "src/lexer-keywords.txt" - {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle}, +#line 23 "src/lexer-keywords.txt" + {"assert_exception", TokenType::AssertException}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 132 "src/lexer-keywords.txt" - {"f64.div", TokenType::Binary, Opcode::F64Div}, -#line 71 "src/lexer-keywords.txt" - {"f32.div", TokenType::Binary, Opcode::F32Div}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 233 "src/lexer-keywords.txt" - {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub}, - {""}, {""}, -#line 193 "src/lexer-keywords.txt" - {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs}, {""}, -#line 561 "src/lexer-keywords.txt" - {"pagesize", TokenType::PageSize}, +#line 472 "src/lexer-keywords.txt" + {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq}, + {""}, {""}, {""}, +#line 158 "src/lexer-keywords.txt" + {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq}, {""}, {""}, -#line 95 "src/lexer-keywords.txt" - {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U}, +#line 240 "src/lexer-keywords.txt" + {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U}, {""}, -#line 94 "src/lexer-keywords.txt" - {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S}, +#line 238 "src/lexer-keywords.txt" + {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S}, + {""}, {""}, {""}, {""}, {""}, +#line 445 "src/lexer-keywords.txt" + {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 362 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 203 "src/lexer-keywords.txt" + {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 364 "src/lexer-keywords.txt" {"i32x4.extmul_low_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8U}, {""}, -#line 360 "src/lexer-keywords.txt" +#line 362 "src/lexer-keywords.txt" {"i32x4.extmul_low_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8S}, - {""}, {""}, -#line 131 "src/lexer-keywords.txt" - {"f64.copysign", TokenType::Binary, Opcode::F64Copysign}, -#line 69 "src/lexer-keywords.txt" - {"f32.copysign", TokenType::Binary, Opcode::F32Copysign}, -#line 533 "src/lexer-keywords.txt" - {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub}, - {""}, {""}, -#line 497 "src/lexer-keywords.txt" - {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 225 "src/lexer-keywords.txt" - {"i16x8.relaxed_q15mulr_s", TokenType::Binary, Opcode::I16X8RelaxedQ15mulrS}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, +#line 370 "src/lexer-keywords.txt" + {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U}, + {""}, +#line 369 "src/lexer-keywords.txt" + {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S}, + {""}, {""}, {""}, {""}, +#line 361 "src/lexer-keywords.txt" + {"i32x4.extadd_pairwise_i16x8_u", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U}, + {""}, +#line 360 "src/lexer-keywords.txt" + {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 605 "src/lexer-keywords.txt" + {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect}, {""}, {""}, {""}, {""}, {""}, -#line 200 "src/lexer-keywords.txt" - {"i16x8.relaxed_dot_i8x16_i7x16_s", TokenType::Binary, Opcode::I16X8DotI8X16I7X16S}, +#line 407 "src/lexer-keywords.txt" + {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub}, +#line 270 "src/lexer-keywords.txt" + {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 443 "src/lexer-keywords.txt" - {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 244 "src/lexer-keywords.txt" - {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U}, - {""}, -#line 243 "src/lexer-keywords.txt" - {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 505 "src/lexer-keywords.txt" + {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 29 "src/lexer-keywords.txt" + {"assert_unlinkable", TokenType::AssertUnlinkable}, +#line 365 "src/lexer-keywords.txt" + {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U}, + {""}, +#line 363 "src/lexer-keywords.txt" + {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 86 "src/lexer-keywords.txt" + {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 220 "src/lexer-keywords.txt" - {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U}, - {""}, -#line 219 "src/lexer-keywords.txt" - {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S}, - {""}, {""}, -#line 238 "src/lexer-keywords.txt" - {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U}, - {""}, -#line 236 "src/lexer-keywords.txt" - {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S}, {""}, {""}, {""}, #line 548 "src/lexer-keywords.txt" - {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy}, - {""}, -#line 479 "src/lexer-keywords.txt" - {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask}, + {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, +#line 224 "src/lexer-keywords.txt" + {"i16x8.q15mulr_sat_s", TokenType::Binary, Opcode::I16X8Q15mulrSatS}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 25 "src/lexer-keywords.txt" + {"assert_invalid", TokenType::AssertInvalid}, + {""}, +#line 302 "src/lexer-keywords.txt" + {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32}, {""}, {""}, {""}, {""}, {""}, -#line 157 "src/lexer-keywords.txt" - {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq}, +#line 506 "src/lexer-keywords.txt" + {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 470 "src/lexer-keywords.txt" - {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq}, +#line 24 "src/lexer-keywords.txt" + {"assert_exhaustion", TokenType::AssertExhaustion}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 483 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 485 "src/lexer-keywords.txt" {"i64x2.extend_high_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendHighI32X4U}, {""}, -#line 481 "src/lexer-keywords.txt" +#line 483 "src/lexer-keywords.txt" {"i64x2.extend_high_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendHighI32X4S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 20 "src/lexer-keywords.txt" - {"array", Type::Array, TokenType::Array}, - {""}, {""}, -#line 27 "src/lexer-keywords.txt" - {"assert_trap", TokenType::AssertTrap}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 596 "src/lexer-keywords.txt" - {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 150 "src/lexer-keywords.txt" - {"f64.sub", TokenType::Binary, Opcode::F64Sub}, -#line 88 "src/lexer-keywords.txt" - {"f32.sub", TokenType::Binary, Opcode::F32Sub}, - {""}, {""}, {""}, {""}, {""}, -#line 455 "src/lexer-keywords.txt" - {"i64.sub", TokenType::Binary, Opcode::I64Sub}, -#line 311 "src/lexer-keywords.txt" - {"i32.sub", TokenType::Binary, Opcode::I32Sub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 146 "src/lexer-keywords.txt" - {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 494 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, +#line 30 "src/lexer-keywords.txt" + {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, +#line 496 "src/lexer-keywords.txt" {"i64x2.extmul_high_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4U}, {""}, -#line 492 "src/lexer-keywords.txt" +#line 494 "src/lexer-keywords.txt" {"i64x2.extmul_high_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, @@ -1660,124 +1807,69 @@ Perfect_Hash::InWordSet (const char *str, size_t len) {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 22 "src/lexer-keywords.txt" - {"assert_exception", TokenType::AssertException}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 199 "src/lexer-keywords.txt" - {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, -#line 23 "src/lexer-keywords.txt" - {"assert_exhaustion", TokenType::AssertExhaustion}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 503 "src/lexer-keywords.txt" - {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask}, - {""}, -#line 201 "src/lexer-keywords.txt" - {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 504 "src/lexer-keywords.txt" - {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 547 "src/lexer-keywords.txt" - {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64}, +#line 549 "src/lexer-keywords.txt" + {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, -#line 85 "src/lexer-keywords.txt" - {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, -#line 24 "src/lexer-keywords.txt" - {"assert_invalid", TokenType::AssertInvalid}, + {""}, {""}, {""}, {""}, +#line 550 "src/lexer-keywords.txt" + {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 405 "src/lexer-keywords.txt" - {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub}, -#line 268 "src/lexer-keywords.txt" - {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, -#line 545 "src/lexer-keywords.txt" - {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 183 "src/lexer-keywords.txt" + {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U}, +#line 522 "src/lexer-keywords.txt" + {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U}, +#line 182 "src/lexer-keywords.txt" + {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S}, +#line 521 "src/lexer-keywords.txt" + {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 242 "src/lexer-keywords.txt" + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 244 "src/lexer-keywords.txt" {"i16x8.extend_high_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendHighI8X16U}, {""}, -#line 241 "src/lexer-keywords.txt" +#line 243 "src/lexer-keywords.txt" {"i16x8.extend_high_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendHighI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 28 "src/lexer-keywords.txt" - {"assert_unlinkable", TokenType::AssertUnlinkable}, - {""}, {""}, -#line 300 "src/lexer-keywords.txt" - {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32}, {""}, {""}, {""}, {""}, -#line 182 "src/lexer-keywords.txt" - {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U}, - {""}, -#line 181 "src/lexer-keywords.txt" - {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S}, - {""}, -#line 235 "src/lexer-keywords.txt" +#line 237 "src/lexer-keywords.txt" {"i16x8.extadd_pairwise_i8x16_u", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16U}, {""}, -#line 234 "src/lexer-keywords.txt" +#line 236 "src/lexer-keywords.txt" {"i16x8.extadd_pairwise_i8x16_s", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, -#line 546 "src/lexer-keywords.txt" - {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32}, - {""}, {""}, {""}, {""}, {""}, -#line 520 "src/lexer-keywords.txt" - {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U}, - {""}, -#line 519 "src/lexer-keywords.txt" - {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S}, - {""}, -#line 222 "src/lexer-keywords.txt" - {"i16x8.q15mulr_sat_s", TokenType::Binary, Opcode::I16X8Q15mulrSatS}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 29 "src/lexer-keywords.txt" - {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence}, - {""}, {""}, {""}, {""}, -#line 239 "src/lexer-keywords.txt" - {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U}, - {""}, -#line 237 "src/lexer-keywords.txt" - {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, +#line 184 "src/lexer-keywords.txt" + {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 183 "src/lexer-keywords.txt" - {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4} + {""}, {""}, {""}, {""}, {""}, +#line 241 "src/lexer-keywords.txt" + {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U}, + {""}, +#line 239 "src/lexer-keywords.txt" + {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S} }; +#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3) +#pragma GCC diagnostic pop +#endif if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { @@ -1791,5 +1883,5 @@ Perfect_Hash::InWordSet (const char *str, size_t len) return &wordlist[key]; } } - return 0; + return static_cast (0); } diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 3701fd8dc7..ef157b0289 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1333,7 +1333,37 @@ bool WastParser::PeekIsDataImport() { tokens_.front().text() == "sym.import.data"; } -Result WastParser::ParseSymAfterPar(SymbolCommon* sym, +std::optional WastParser::ParseSymAttrString(TokenType tag) { + if (!MatchLpar(tag)) + return {}; + std::optional ret(std::in_place); + if (ParseQuotedText(&*ret)) { + if (Failed(Expect(TokenType::Rpar))) + ParseUnwindReloc(1); + return ret; + } + ErrorExpected({"A quoted string"}, "\"foo\""); + ParseUnwindReloc(1); + ret.reset(); + return ret; +} + +std::optional WastParser::ParseSymAttrNumber(TokenType tag) { + if (!MatchLpar(tag)) + return {}; + std::optional ret(std::in_place); + if (ParseNat(&*ret, true)) { + if (Failed(Expect(TokenType::Rpar))) + ParseUnwindReloc(1); + return ret; + } + ErrorExpected({"A number"}, "32"); + ParseUnwindReloc(1); + ret.reset(); + return ret; +} + +Result WastParser::ParseSymOpt(SymbolCommon* sym, bool in_import, SymAux aux) { using OnceProperty = std::pair>; @@ -1381,6 +1411,15 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, check_unseen(priority); }; + sym->flags_ |= in_import ? WABT_SYMBOL_FLAG_UNDEFINED : 0; + if (!IsLparAnn(PeekPair())) + return Result::Ok; + Token tok = GetToken(); + bool is_data = std::get_if(&aux); + if (tok.text() != (is_data && in_import ? "sym.import.data" : "sym")) + return Result::Ok; + Consume(); + if (auto *data = std::get_if(&aux)) { ParseVarOpt(&(*data)->name, (*data)->name); } @@ -1389,73 +1428,86 @@ Result WastParser::ParseSymAfterPar(SymbolCommon* sym, if (Match(TokenType::Rpar)) { validate(); return Result::Ok; - } else if (Match(TokenType::Lpar)) { - last_tok_loc = GetLocation(); - if (MatchText(TokenType::Reserved, "name")) { - check_once(name); - if (!ParseQuotedText(&sym->name_)) - goto fail; - sym->flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; - } else if (MatchText(TokenType::Reserved, "size")) { - check_once(size); - Address res; - if (!ParseNat(&res, true)) - goto fail; - if (auto *data = std::get_if(&aux)) - (*data)->size = res; - } else if (MatchText(TokenType::Reserved, "init_prio")) { - check_once(priority); - Address res; - if (!ParseNat(&res, true)) - goto fail; - if (auto *data = std::get_if(&aux)) - (*data)->priority = res; - } - fail: - if (!Expect(TokenType::Rpar)) - ParseUnwindReloc(1); + } + if (auto sym_name = ParseSymAttrString(TokenType::Name)) { + check_once(name); + sym->name_ = *sym_name; + sym->flags_ |= WABT_SYMBOL_FLAG_EXPLICIT_NAME; + } else if (auto sym_size = ParseSymAttrNumber(TokenType::Size)) { + check_once(size); + if (auto *data = std::get_if(&aux)) + (*data)->size = *sym_size; + } else if (auto sym_prio = ParseSymAttrNumber(TokenType::InitPrio)) { + check_once(priority); + if (auto *data = std::get_if(&aux)) + (*data)->priority = *sym_prio; } else if (Match(TokenType::Local)) { check_once(binding); sym->flags_ |= uint32_t(SymbolBinding::Local); - } else if (MatchText(TokenType::Reserved, "weak")) { + } else if (Match(TokenType::Weak)) { check_once(binding); sym->flags_ |= uint32_t(SymbolBinding::Weak); - } else if (MatchText(TokenType::Reserved, "retain")) { + } else if (Match(TokenType::Retain)) { check_once(retain); sym->flags_ |= WABT_SYMBOL_FLAG_NO_STRIP; - } else if (MatchText(TokenType::Reserved, "hidden")) { + } else if (Match(TokenType::Hidden)) { check_once(visibility); sym->flags_ |= uint32_t(SymbolVisibility::Hidden); } else { - ErrorExpected({"symbol attribute", "')'"}); + bool do_unwind = PeekMatch(TokenType::Lpar); + ErrorExpected({"symbol attribute", "')'"}, "(name \"foo\")"); + if (do_unwind) + ParseUnwindReloc(1); } } } - -Result WastParser::ParseSymOpt(SymbolCommon* sym, - bool in_import, - SymAux dat_sym) { - sym->flags_ |= in_import ? WABT_SYMBOL_FLAG_UNDEFINED : 0; +Result WastParser::ParseSymSegment(DataSegment::SymInfo* info) { if (!IsLparAnn(PeekPair())) return Result::Ok; Token tok = GetToken(); if (tok.text() != "sym") return Result::Ok; Consume(); - return ParseSymAfterPar(sym, in_import, dat_sym); + Location last_tok_loc = GetLocation(); + for (;;) { + last_tok_loc = GetLocation(); + using Flags = DataSegment::SymInfo::Flags; + + if (Match(TokenType::Rpar)) break; + if (auto name = ParseSymAttrString(TokenType::Name)) + info->name = *std::move(name); + else if (auto align = ParseSymAttrNumber(TokenType::Align)) { + for (int i = 0;; ++i) { + uint64_t num = 1 << i; + if (num < *align) + continue; + if (num == *align) + info->align = i; + else + Error(last_tok_loc, "Alignment is not a power of 2"); + break; + } + } + else if (Match(TokenType::Retain)) + info->flags = Flags(info->flags | Flags::WASM_SEG_FLAG_RETAIN); + else if (Match(TokenType::TLS)) + info->flags = Flags(info->flags | Flags::WASM_SEGMENT_FLAG_TLS); + else if (Match(TokenType::Strings)) + info->flags = Flags(info->flags | Flags::WASM_SEGMENT_FLAG_STRINGS); + else { + ErrorExpected({"segment attribute"}, "(name \"foo\")"); + ParseUnwindReloc(1); + return Result::Error; + } + } + return Result::Ok; } Result WastParser::ParseDataImport(Module* module) { DataSym sym{}; DatasymAux aux; sym.flags_ = WABT_SYMBOL_FLAG_UNDEFINED; - if (!IsLparAnn(PeekPair())) - return Result::Ok; - Token tok = GetToken(); - if (tok.text() != "sym.import.data") - return Result::Ok; - Consume(); - CHECK_RESULT(ParseSymAfterPar(&sym, true, &aux)); + CHECK_RESULT(ParseSymOpt(&sym, true, &aux)); if (!module->data_symbols.empty()) { if (module->data_symbols.back().segment != kInvalidIndex) { @@ -1643,6 +1695,8 @@ Result WastParser::ParseDataModuleField(Module* module) { ParseBindVarOpt(&name); auto field = std::make_unique(loc, name); + ParseSymSegment(&field->data_segment.sym); + if (PeekMatchLpar(TokenType::Memory)) { EXPECT(Lpar); EXPECT(Memory); From 651c9ffbce3d0525d2d1324fab79160e5fcf8173 Mon Sep 17 00:00:00 2001 From: feedable Date: Thu, 7 May 2026 19:02:44 +0300 Subject: [PATCH 59/59] Fix build --- include/wabt/result.h | 1 - src/wast-parser.cc | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/wabt/result.h b/include/wabt/result.h index a425fd15f7..a40faab78b 100644 --- a/include/wabt/result.h +++ b/include/wabt/result.h @@ -28,7 +28,6 @@ struct Result { Result() : Result(Ok) {} Result(Enum e) : enum_(e) {} operator Enum() const { return enum_; } - operator bool() const { return enum_ == Ok; } Result& operator|=(Result rhs); private: diff --git a/src/wast-parser.cc b/src/wast-parser.cc index ef157b0289..578f04c80a 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1337,7 +1337,7 @@ std::optional WastParser::ParseSymAttrString(TokenType tag) { if (!MatchLpar(tag)) return {}; std::optional ret(std::in_place); - if (ParseQuotedText(&*ret)) { + if (Succeeded(ParseQuotedText(&*ret))) { if (Failed(Expect(TokenType::Rpar))) ParseUnwindReloc(1); return ret; @@ -1352,7 +1352,7 @@ std::optional WastParser::ParseSymAttrNumber(TokenType tag) { if (!MatchLpar(tag)) return {}; std::optional ret(std::in_place); - if (ParseNat(&*ret, true)) { + if (Succeeded(ParseNat(&*ret, true))) { if (Failed(Expect(TokenType::Rpar))) ParseUnwindReloc(1); return ret; @@ -2567,11 +2567,11 @@ Result WastParser::ParseRelocAddend(uint32_t* addend, *name = Var{curr.text(), curr.loc}; return Result::Ok; } - if (!Expect(TokenType::Int)) { + if (Failed(Expect(TokenType::Int))) { return Result::Error; } auto sv = curr.literal().text; - if (!ParseInt32(sv, addend, ParseIntType::SignedAndUnsigned)) + if (Failed(ParseInt32(sv, addend, ParseIntType::SignedAndUnsigned))) ErrorExpected({"integer with sign"}, "+123"); if (sv.find_first_of("+-") != 0) return ErrorExpected({"integer with sign"}, @@ -2721,7 +2721,7 @@ Result WastParser::ParseReloc(bool opt, bool addend_allowed = kind == RelocKind::Data || text_addend_allowed; ParseRelocAddend(addend_allowed ? &addend_num : nullptr, text_addend_allowed ? &addend_name : nullptr); - if (!Expect(TokenType::Rpar)) { + if (Failed(Expect(TokenType::Rpar))) { res = Result::Error; ParseUnwindReloc(1); }