diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/wasm2c/src/binary-reader-ir.cc | 1775 |
1 files changed, 1775 insertions, 0 deletions
diff --git a/third_party/wasm2c/src/binary-reader-ir.cc b/third_party/wasm2c/src/binary-reader-ir.cc new file mode 100644 index 0000000000..5736e3021e --- /dev/null +++ b/third_party/wasm2c/src/binary-reader-ir.cc @@ -0,0 +1,1775 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wabt/binary-reader-ir.h" + +#include <cassert> +#include <cinttypes> +#include <cstdarg> +#include <cstdint> +#include <cstdio> +#include <deque> +#include <vector> + +#include "wabt/binary-reader-nop.h" +#include "wabt/cast.h" +#include "wabt/common.h" +#include "wabt/ir.h" + +namespace wabt { + +namespace { + +struct LabelNode { + LabelNode(LabelType, ExprList* exprs, Expr* context = nullptr); + + LabelType label_type; + ExprList* exprs; + Expr* context; +}; + +LabelNode::LabelNode(LabelType label_type, ExprList* exprs, Expr* context) + : label_type(label_type), exprs(exprs), context(context) {} + +class CodeMetadataExprQueue { + private: + struct Entry { + Func* func; + std::deque<std::unique_ptr<CodeMetadataExpr>> func_queue; + Entry(Func* f) : func(f) {} + }; + std::deque<Entry> entries; + + public: + CodeMetadataExprQueue() {} + void push_func(Func* f) { entries.emplace_back(f); } + void push_metadata(std::unique_ptr<CodeMetadataExpr> meta) { + assert(!entries.empty()); + entries.back().func_queue.push_back(std::move(meta)); + } + + std::unique_ptr<CodeMetadataExpr> pop_match(Func* f, Offset offset) { + std::unique_ptr<CodeMetadataExpr> ret; + if (entries.empty()) { + return ret; + } + + auto& current_entry = entries.front(); + + if (current_entry.func != f) + return ret; + if (current_entry.func_queue.empty()) { + entries.pop_front(); + return ret; + } + + auto& current_metadata = current_entry.func_queue.front(); + if (current_metadata->loc.offset + current_entry.func->loc.offset != + offset) { + return ret; + } + + current_metadata->loc = Location(offset); + ret = std::move(current_metadata); + current_entry.func_queue.pop_front(); + + return ret; + } +}; + +class BinaryReaderIR : public BinaryReaderNop { + static constexpr size_t kMaxNestingDepth = 16384; // max depth of label stack + static constexpr size_t kMaxFunctionLocals = 50000; // matches V8 + static constexpr size_t kMaxFunctionParams = 1000; // matches V8 + static constexpr size_t kMaxFunctionResults = 1000; // matches V8 + + public: + BinaryReaderIR(Module* out_module, const char* filename, Errors* errors); + + bool OnError(const Error&) override; + + Result OnTypeCount(Index count) override; + Result OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) override; + Result OnStructType(Index index, Index field_count, TypeMut* fields) override; + Result OnArrayType(Index index, TypeMut field) override; + + Result OnImportCount(Index count) override; + Result OnImportFunc(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index func_index, + Index sig_index) override; + Result OnImportTable(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override; + Result OnImportMemory(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index memory_index, + const Limits* page_limits) override; + Result OnImportGlobal(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index global_index, + Type type, + bool mutable_) override; + Result OnImportTag(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index tag_index, + Index sig_index) override; + + Result OnFunctionCount(Index count) override; + Result OnFunction(Index index, Index sig_index) override; + + Result OnTableCount(Index count) override; + Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) override; + + Result OnMemoryCount(Index count) override; + Result OnMemory(Index index, const Limits* limits) override; + + Result OnGlobalCount(Index count) override; + Result BeginGlobal(Index index, Type type, bool mutable_) override; + Result BeginGlobalInitExpr(Index index) override; + Result EndGlobalInitExpr(Index index) override; + + Result OnExportCount(Index count) override; + Result OnExport(Index index, + ExternalKind kind, + Index item_index, + std::string_view name) override; + + Result OnStartFunction(Index func_index) override; + + Result OnFunctionBodyCount(Index count) override; + Result BeginFunctionBody(Index index, Offset size) override; + Result OnLocalDecl(Index decl_index, Index count, Type type) override; + + Result OnOpcode(Opcode opcode) override; + Result OnAtomicLoadExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnAtomicStoreExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnAtomicRmwExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnAtomicRmwCmpxchgExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnAtomicWaitExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnAtomicFenceExpr(uint32_t consistency_model) override; + Result OnAtomicNotifyExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnBinaryExpr(Opcode opcode) override; + Result OnBlockExpr(Type sig_type) override; + Result OnBrExpr(Index depth) override; + Result OnBrIfExpr(Index depth) override; + Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override; + Result OnCallExpr(Index func_index) override; + Result OnCatchExpr(Index tag_index) override; + Result OnCatchAllExpr() override; + Result OnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnCallRefExpr() override; + Result OnReturnCallExpr(Index func_index) override; + Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnCompareExpr(Opcode opcode) override; + Result OnConvertExpr(Opcode opcode) override; + Result OnDelegateExpr(Index depth) override; + Result OnDropExpr() override; + Result OnElseExpr() override; + Result OnEndExpr() override; + Result OnF32ConstExpr(uint32_t value_bits) override; + Result OnF64ConstExpr(uint64_t value_bits) override; + Result OnV128ConstExpr(v128 value_bits) override; + Result OnGlobalGetExpr(Index global_index) override; + Result OnGlobalSetExpr(Index global_index) override; + Result OnI32ConstExpr(uint32_t value) override; + Result OnI64ConstExpr(uint64_t value) override; + Result OnIfExpr(Type sig_type) override; + Result OnLoadExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnLocalGetExpr(Index local_index) override; + Result OnLocalSetExpr(Index local_index) override; + Result OnLocalTeeExpr(Index local_index) override; + Result OnLoopExpr(Type sig_type) override; + Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override; + Result OnDataDropExpr(Index segment_index) override; + Result OnMemoryFillExpr(Index memidx) override; + Result OnMemoryGrowExpr(Index memidx) override; + Result OnMemoryInitExpr(Index segment_index, Index memidx) override; + Result OnMemorySizeExpr(Index memidx) override; + Result OnTableCopyExpr(Index dst_index, Index src_index) override; + Result OnElemDropExpr(Index segment_index) override; + Result OnTableInitExpr(Index segment_index, Index table_index) override; + Result OnTableGetExpr(Index table_index) override; + Result OnTableSetExpr(Index table_index) override; + Result OnTableGrowExpr(Index table_index) override; + Result OnTableSizeExpr(Index table_index) override; + Result OnTableFillExpr(Index table_index) override; + Result OnRefFuncExpr(Index func_index) override; + Result OnRefNullExpr(Type type) override; + Result OnRefIsNullExpr() override; + Result OnNopExpr() override; + Result OnRethrowExpr(Index depth) override; + Result OnReturnExpr() override; + Result OnSelectExpr(Index result_count, Type* result_types) override; + Result OnStoreExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnThrowExpr(Index tag_index) override; + Result OnTryExpr(Type sig_type) override; + Result OnUnaryExpr(Opcode opcode) override; + Result OnTernaryExpr(Opcode opcode) override; + Result OnUnreachableExpr() override; + Result EndFunctionBody(Index index) override; + Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override; + Result OnSimdLoadLaneExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset, + uint64_t value) override; + Result OnSimdStoreLaneExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset, + uint64_t value) override; + Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override; + Result OnLoadSplatExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + Result OnLoadZeroExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) override; + + Result OnElemSegmentCount(Index count) override; + Result BeginElemSegment(Index index, + Index table_index, + uint8_t flags) override; + Result BeginElemSegmentInitExpr(Index index) override; + Result EndElemSegmentInitExpr(Index index) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; + Result OnElemSegmentElemExprCount(Index index, Index count) override; + Result OnElemSegmentElemExpr_RefNull(Index segment_index, Type type) override; + Result OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) override; + + Result OnDataSegmentCount(Index count) override; + Result BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) override; + Result BeginDataSegmentInitExpr(Index index) override; + Result EndDataSegmentInitExpr(Index index) override; + Result OnDataSegmentData(Index index, + const void* data, + Address size) override; + + Result OnModuleName(std::string_view module_name) override; + Result OnFunctionNamesCount(Index num_functions) override; + Result OnFunctionName(Index function_index, + std::string_view function_name) override; + Result OnLocalNameLocalCount(Index function_index, Index num_locals) override; + Result OnLocalName(Index function_index, + Index local_index, + std::string_view local_name) override; + Result OnNameEntry(NameSectionSubsection type, + Index index, + std::string_view name) override; + + Result BeginTagSection(Offset size) override { return Result::Ok; } + Result OnTagCount(Index count) override { return Result::Ok; } + Result OnTagType(Index index, Index sig_index) override; + Result EndTagSection() override { return Result::Ok; } + + Result OnDataSymbol(Index index, + uint32_t flags, + std::string_view name, + Index segment, + uint32_t offset, + uint32_t size) override; + Result OnFunctionSymbol(Index index, + uint32_t flags, + std::string_view name, + Index func_index) override; + Result OnGlobalSymbol(Index index, + uint32_t flags, + std::string_view name, + Index global_index) override; + Result OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) override; + /* Code Metadata sections */ + Result BeginCodeMetadataSection(std::string_view name, Offset size) override; + Result OnCodeMetadataFuncCount(Index count) override; + Result OnCodeMetadataCount(Index function_index, Index count) override; + Result OnCodeMetadata(Offset offset, const void* data, Address size) override; + + Result OnTagSymbol(Index index, + uint32_t flags, + std::string_view name, + Index tag_index) override; + Result OnTableSymbol(Index index, + uint32_t flags, + std::string_view name, + Index table_index) override; + + private: + Location GetLocation() const; + void PrintError(const char* format, ...); + Result PushLabel(LabelType label_type, + ExprList* first, + Expr* context = nullptr); + Result BeginInitExpr(ExprList* init_expr); + Result EndInitExpr(); + Result PopLabel(); + Result GetLabelAt(LabelNode** label, Index depth); + Result TopLabel(LabelNode** label); + Result TopLabelExpr(LabelNode** label, Expr** expr); + Result AppendExpr(std::unique_ptr<Expr> expr); + Result AppendCatch(Catch&& catch_); + void SetFuncDeclaration(FuncDeclaration* decl, Var var); + void SetBlockDeclaration(BlockDeclaration* decl, Type sig_type); + Result SetMemoryName(Index index, std::string_view name); + Result SetTableName(Index index, std::string_view name); + Result SetFunctionName(Index index, std::string_view name); + Result SetTypeName(Index index, std::string_view name); + Result SetGlobalName(Index index, std::string_view name); + Result SetDataSegmentName(Index index, std::string_view name); + Result SetElemSegmentName(Index index, std::string_view name); + Result SetTagName(Index index, std::string_view name); + + std::string GetUniqueName(BindingHash* bindings, + const std::string& original_name); + + Errors* errors_ = nullptr; + Module* module_ = nullptr; + + Func* current_func_ = nullptr; + std::vector<LabelNode> label_stack_; + const char* filename_; + + CodeMetadataExprQueue code_metadata_queue_; + std::string_view current_metadata_name_; +}; + +BinaryReaderIR::BinaryReaderIR(Module* out_module, + const char* filename, + Errors* errors) + : errors_(errors), module_(out_module), filename_(filename) {} + +Location BinaryReaderIR::GetLocation() const { + Location loc; + loc.filename = filename_; + loc.offset = state->offset; + return loc; +} + +void WABT_PRINTF_FORMAT(2, 3) BinaryReaderIR::PrintError(const char* format, + ...) { + WABT_SNPRINTF_ALLOCA(buffer, length, format); + errors_->emplace_back(ErrorLevel::Error, Location(kInvalidOffset), buffer); +} + +Result BinaryReaderIR::PushLabel(LabelType label_type, + ExprList* first, + Expr* context) { + if (label_stack_.size() >= kMaxNestingDepth) { + PrintError("label stack exceeds max nesting depth"); + return Result::Error; + } + label_stack_.emplace_back(label_type, first, context); + return Result::Ok; +} + +Result BinaryReaderIR::PopLabel() { + if (label_stack_.size() == 0) { + PrintError("popping empty label stack"); + return Result::Error; + } + + label_stack_.pop_back(); + return Result::Ok; +} + +Result BinaryReaderIR::GetLabelAt(LabelNode** label, Index depth) { + if (depth >= label_stack_.size()) { + PrintError("accessing stack depth: %" PRIindex " >= max: %" PRIzd, depth, + label_stack_.size()); + return Result::Error; + } + + *label = &label_stack_[label_stack_.size() - depth - 1]; + return Result::Ok; +} + +Result BinaryReaderIR::TopLabel(LabelNode** label) { + return GetLabelAt(label, 0); +} + +Result BinaryReaderIR::TopLabelExpr(LabelNode** label, Expr** expr) { + CHECK_RESULT(TopLabel(label)); + LabelNode* parent_label; + CHECK_RESULT(GetLabelAt(&parent_label, 1)); + if (parent_label->exprs->empty()) { + PrintError("TopLabelExpr: parent label has empty expr list"); + return Result::Error; + } + *expr = &parent_label->exprs->back(); + return Result::Ok; +} + +Result BinaryReaderIR::AppendExpr(std::unique_ptr<Expr> expr) { + expr->loc = GetLocation(); + LabelNode* label; + CHECK_RESULT(TopLabel(&label)); + label->exprs->push_back(std::move(expr)); + return Result::Ok; +} + +void BinaryReaderIR::SetFuncDeclaration(FuncDeclaration* decl, Var var) { + decl->has_func_type = true; + decl->type_var = var; + if (auto* func_type = module_->GetFuncType(var)) { + decl->sig = func_type->sig; + } +} + +void BinaryReaderIR::SetBlockDeclaration(BlockDeclaration* decl, + Type sig_type) { + if (sig_type.IsIndex()) { + Index type_index = sig_type.GetIndex(); + SetFuncDeclaration(decl, Var(type_index, GetLocation())); + } else { + decl->has_func_type = false; + decl->sig.param_types.clear(); + decl->sig.result_types = sig_type.GetInlineVector(); + } +} + +std::string BinaryReaderIR::GetUniqueName(BindingHash* bindings, + const std::string& orig_name) { + int counter = 1; + std::string unique_name = orig_name; + while (bindings->count(unique_name) != 0) { + unique_name = orig_name + "." + std::to_string(counter++); + } + return unique_name; +} + +bool BinaryReaderIR::OnError(const Error& error) { + errors_->push_back(error); + return true; +} + +Result BinaryReaderIR::OnTypeCount(Index count) { + WABT_TRY + module_->types.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) { + if (param_count > kMaxFunctionParams) { + PrintError("FuncType param count exceeds maximum value"); + return Result::Error; + } + + if (result_count > kMaxFunctionResults) { + PrintError("FuncType result count exceeds maximum value"); + return Result::Error; + } + + auto field = std::make_unique<TypeModuleField>(GetLocation()); + auto func_type = std::make_unique<FuncType>(); + func_type->sig.param_types.assign(param_types, param_types + param_count); + func_type->sig.result_types.assign(result_types, result_types + result_count); + + module_->features_used.simd |= + std::any_of(func_type->sig.param_types.begin(), + func_type->sig.param_types.end(), + [](auto x) { return x == Type::V128; }) || + std::any_of(func_type->sig.result_types.begin(), + func_type->sig.result_types.end(), + [](auto x) { return x == Type::V128; }); + + field->type = std::move(func_type); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnStructType(Index index, + Index field_count, + TypeMut* fields) { + auto field = std::make_unique<TypeModuleField>(GetLocation()); + auto struct_type = std::make_unique<StructType>(); + struct_type->fields.resize(field_count); + for (Index i = 0; i < field_count; ++i) { + struct_type->fields[i].type = fields[i].type; + struct_type->fields[i].mutable_ = fields[i].mutable_; + module_->features_used.simd |= (fields[i].type == Type::V128); + } + field->type = std::move(struct_type); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnArrayType(Index index, TypeMut type_mut) { + auto field = std::make_unique<TypeModuleField>(GetLocation()); + auto array_type = std::make_unique<ArrayType>(); + array_type->field.type = type_mut.type; + array_type->field.mutable_ = type_mut.mutable_; + module_->features_used.simd |= (type_mut.type == Type::V128); + field->type = std::move(array_type); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportCount(Index count) { + WABT_TRY + module_->imports.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnImportFunc(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index func_index, + Index sig_index) { + auto import = std::make_unique<FuncImport>(); + import->module_name = module_name; + import->field_name = field_name; + SetFuncDeclaration(&import->func.decl, Var(sig_index, GetLocation())); + module_->AppendField( + std::make_unique<ImportModuleField>(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportTable(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) { + auto import = std::make_unique<TableImport>(); + import->module_name = module_name; + import->field_name = field_name; + import->table.elem_limits = *elem_limits; + import->table.elem_type = elem_type; + module_->AppendField( + std::make_unique<ImportModuleField>(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportMemory(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index memory_index, + const Limits* page_limits) { + auto import = std::make_unique<MemoryImport>(); + import->module_name = module_name; + import->field_name = field_name; + import->memory.page_limits = *page_limits; + module_->AppendField( + std::make_unique<ImportModuleField>(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportGlobal(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index global_index, + Type type, + bool mutable_) { + auto import = std::make_unique<GlobalImport>(); + import->module_name = module_name; + import->field_name = field_name; + import->global.type = type; + import->global.mutable_ = mutable_; + module_->AppendField( + std::make_unique<ImportModuleField>(std::move(import), GetLocation())); + module_->features_used.simd |= (type == Type::V128); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportTag(Index import_index, + std::string_view module_name, + std::string_view field_name, + Index tag_index, + Index sig_index) { + auto import = std::make_unique<TagImport>(); + import->module_name = module_name; + import->field_name = field_name; + SetFuncDeclaration(&import->tag.decl, Var(sig_index, GetLocation())); + module_->AppendField( + std::make_unique<ImportModuleField>(std::move(import), GetLocation())); + module_->features_used.exceptions = true; + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionCount(Index count) { + WABT_TRY + module_->funcs.reserve(module_->num_func_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnFunction(Index index, Index sig_index) { + auto field = std::make_unique<FuncModuleField>(GetLocation()); + Func& func = field->func; + SetFuncDeclaration(&func.decl, Var(sig_index, GetLocation())); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnTableCount(Index count) { + WABT_TRY + module_->tables.reserve(module_->num_table_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnTable(Index index, + Type elem_type, + const Limits* elem_limits) { + auto field = std::make_unique<TableModuleField>(GetLocation()); + Table& table = field->table; + table.elem_limits = *elem_limits; + table.elem_type = elem_type; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnMemoryCount(Index count) { + WABT_TRY + module_->memories.reserve(module_->num_memory_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnMemory(Index index, const Limits* page_limits) { + auto field = std::make_unique<MemoryModuleField>(GetLocation()); + Memory& memory = field->memory; + memory.page_limits = *page_limits; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnGlobalCount(Index count) { + WABT_TRY + module_->globals.reserve(module_->num_global_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::BeginGlobal(Index index, Type type, bool mutable_) { + auto field = std::make_unique<GlobalModuleField>(GetLocation()); + Global& global = field->global; + global.type = type; + global.mutable_ = mutable_; + module_->AppendField(std::move(field)); + module_->features_used.simd |= (type == Type::V128); + return Result::Ok; +} + +Result BinaryReaderIR::BeginGlobalInitExpr(Index index) { + assert(index == module_->globals.size() - 1); + Global* global = module_->globals[index]; + return BeginInitExpr(&global->init_expr); +} + +Result BinaryReaderIR::EndGlobalInitExpr(Index index) { + return EndInitExpr(); +} + +Result BinaryReaderIR::OnExportCount(Index count) { + WABT_TRY + module_->exports.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnExport(Index index, + ExternalKind kind, + Index item_index, + std::string_view name) { + auto field = std::make_unique<ExportModuleField>(GetLocation()); + Export& export_ = field->export_; + export_.name = name; + export_.var = Var(item_index, GetLocation()); + export_.kind = kind; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnStartFunction(Index func_index) { + Var start(func_index, GetLocation()); + module_->AppendField( + std::make_unique<StartModuleField>(start, GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionBodyCount(Index count) { + // Can hit this case on a malformed module if we don't stop on first error. + if (module_->num_func_imports + count != module_->funcs.size()) { + PrintError( + "number of imported func + func count in code section does not match " + "actual number of funcs in module"); + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReaderIR::BeginFunctionBody(Index index, Offset size) { + current_func_ = module_->funcs[index]; + current_func_->loc = GetLocation(); + return PushLabel(LabelType::Func, ¤t_func_->exprs); +} + +Result BinaryReaderIR::OnLocalDecl(Index decl_index, Index count, Type type) { + current_func_->local_types.AppendDecl(type, count); + + if (current_func_->GetNumLocals() > kMaxFunctionLocals) { + PrintError("function local count exceeds maximum value"); + return Result::Error; + } + + module_->features_used.simd |= (type == Type::V128); + return Result::Ok; +} + +Result BinaryReaderIR::OnOpcode(Opcode opcode) { + std::unique_ptr<CodeMetadataExpr> metadata = + code_metadata_queue_.pop_match(current_func_, GetLocation().offset - 1); + if (metadata) { + return AppendExpr(std::move(metadata)); + } + module_->features_used.simd |= (opcode.GetResultType() == Type::V128); + return Result::Ok; +} + +Result BinaryReaderIR::OnAtomicLoadExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<AtomicLoadExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicStoreExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<AtomicStoreExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicRmwExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<AtomicRmwExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicRmwCmpxchgExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<AtomicRmwCmpxchgExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicWaitExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<AtomicWaitExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicFenceExpr(uint32_t consistency_model) { + return AppendExpr(std::make_unique<AtomicFenceExpr>(consistency_model)); +} + +Result BinaryReaderIR::OnAtomicNotifyExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<AtomicNotifyExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnBinaryExpr(Opcode opcode) { + return AppendExpr(std::make_unique<BinaryExpr>(opcode)); +} + +Result BinaryReaderIR::OnBlockExpr(Type sig_type) { + auto expr = std::make_unique<BlockExpr>(); + SetBlockDeclaration(&expr->block.decl, sig_type); + ExprList* expr_list = &expr->block.exprs; + CHECK_RESULT(AppendExpr(std::move(expr))); + return PushLabel(LabelType::Block, expr_list); +} + +Result BinaryReaderIR::OnBrExpr(Index depth) { + return AppendExpr(std::make_unique<BrExpr>(Var(depth, GetLocation()))); +} + +Result BinaryReaderIR::OnBrIfExpr(Index depth) { + return AppendExpr(std::make_unique<BrIfExpr>(Var(depth, GetLocation()))); +} + +Result BinaryReaderIR::OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) { + auto expr = std::make_unique<BrTableExpr>(); + expr->default_target = Var(default_target_depth, GetLocation()); + expr->targets.resize(num_targets); + for (Index i = 0; i < num_targets; ++i) { + expr->targets[i] = Var(target_depths[i], GetLocation()); + } + return AppendExpr(std::move(expr)); +} + +Result BinaryReaderIR::OnCallExpr(Index func_index) { + return AppendExpr(std::make_unique<CallExpr>(Var(func_index, GetLocation()))); +} + +Result BinaryReaderIR::OnCallIndirectExpr(Index sig_index, Index table_index) { + auto expr = std::make_unique<CallIndirectExpr>(); + SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation())); + expr->table = Var(table_index, GetLocation()); + return AppendExpr(std::move(expr)); +} + +Result BinaryReaderIR::OnCallRefExpr() { + return AppendExpr(std::make_unique<CallRefExpr>()); +} + +Result BinaryReaderIR::OnReturnCallExpr(Index func_index) { + return AppendExpr( + std::make_unique<ReturnCallExpr>(Var(func_index, GetLocation()))); +} + +Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index, + Index table_index) { + auto expr = std::make_unique<ReturnCallIndirectExpr>(); + SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation())); + expr->table = Var(table_index, GetLocation()); + return AppendExpr(std::move(expr)); +} + +Result BinaryReaderIR::OnCompareExpr(Opcode opcode) { + return AppendExpr(std::make_unique<CompareExpr>(opcode)); +} + +Result BinaryReaderIR::OnConvertExpr(Opcode opcode) { + return AppendExpr(std::make_unique<ConvertExpr>(opcode)); +} + +Result BinaryReaderIR::OnDropExpr() { + return AppendExpr(std::make_unique<DropExpr>()); +} + +Result BinaryReaderIR::OnElseExpr() { + LabelNode* label; + Expr* expr; + CHECK_RESULT(TopLabelExpr(&label, &expr)); + + if (label->label_type == LabelType::If) { + auto* if_expr = cast<IfExpr>(expr); + if_expr->true_.end_loc = GetLocation(); + label->exprs = &if_expr->false_; + label->label_type = LabelType::Else; + } else { + PrintError("else expression without matching if"); + return Result::Error; + } + + return Result::Ok; +} + +Result BinaryReaderIR::OnEndExpr() { + if (label_stack_.size() > 1) { + LabelNode* label; + Expr* expr; + CHECK_RESULT(TopLabelExpr(&label, &expr)); + switch (label->label_type) { + case LabelType::Block: + cast<BlockExpr>(expr)->block.end_loc = GetLocation(); + break; + case LabelType::Loop: + cast<LoopExpr>(expr)->block.end_loc = GetLocation(); + break; + case LabelType::If: + cast<IfExpr>(expr)->true_.end_loc = GetLocation(); + break; + case LabelType::Else: + cast<IfExpr>(expr)->false_end_loc = GetLocation(); + break; + case LabelType::Try: + cast<TryExpr>(expr)->block.end_loc = GetLocation(); + break; + + case LabelType::InitExpr: + case LabelType::Func: + case LabelType::Catch: + break; + } + } + + return PopLabel(); +} + +Result BinaryReaderIR::OnF32ConstExpr(uint32_t value_bits) { + return AppendExpr( + std::make_unique<ConstExpr>(Const::F32(value_bits, GetLocation()))); +} + +Result BinaryReaderIR::OnF64ConstExpr(uint64_t value_bits) { + return AppendExpr( + std::make_unique<ConstExpr>(Const::F64(value_bits, GetLocation()))); +} + +Result BinaryReaderIR::OnV128ConstExpr(v128 value_bits) { + return AppendExpr( + std::make_unique<ConstExpr>(Const::V128(value_bits, GetLocation()))); +} + +Result BinaryReaderIR::OnGlobalGetExpr(Index global_index) { + return AppendExpr( + std::make_unique<GlobalGetExpr>(Var(global_index, GetLocation()))); +} + +Result BinaryReaderIR::OnLocalGetExpr(Index local_index) { + return AppendExpr( + std::make_unique<LocalGetExpr>(Var(local_index, GetLocation()))); +} + +Result BinaryReaderIR::OnI32ConstExpr(uint32_t value) { + return AppendExpr( + std::make_unique<ConstExpr>(Const::I32(value, GetLocation()))); +} + +Result BinaryReaderIR::OnI64ConstExpr(uint64_t value) { + return AppendExpr( + std::make_unique<ConstExpr>(Const::I64(value, GetLocation()))); +} + +Result BinaryReaderIR::OnIfExpr(Type sig_type) { + auto expr = std::make_unique<IfExpr>(); + SetBlockDeclaration(&expr->true_.decl, sig_type); + ExprList* expr_list = &expr->true_.exprs; + CHECK_RESULT(AppendExpr(std::move(expr))); + return PushLabel(LabelType::If, expr_list); +} + +Result BinaryReaderIR::OnLoadExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<LoadExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnLoopExpr(Type sig_type) { + auto expr = std::make_unique<LoopExpr>(); + SetBlockDeclaration(&expr->block.decl, sig_type); + ExprList* expr_list = &expr->block.exprs; + CHECK_RESULT(AppendExpr(std::move(expr))); + return PushLabel(LabelType::Loop, expr_list); +} + +Result BinaryReaderIR::OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) { + return AppendExpr(std::make_unique<MemoryCopyExpr>( + Var(srcmemidx, GetLocation()), Var(destmemidx, GetLocation()))); +} + +Result BinaryReaderIR::OnDataDropExpr(Index segment) { + return AppendExpr( + std::make_unique<DataDropExpr>(Var(segment, GetLocation()))); +} + +Result BinaryReaderIR::OnMemoryFillExpr(Index memidx) { + return AppendExpr( + std::make_unique<MemoryFillExpr>(Var(memidx, GetLocation()))); +} + +Result BinaryReaderIR::OnMemoryGrowExpr(Index memidx) { + return AppendExpr( + std::make_unique<MemoryGrowExpr>(Var(memidx, GetLocation()))); +} + +Result BinaryReaderIR::OnMemoryInitExpr(Index segment, Index memidx) { + return AppendExpr(std::make_unique<MemoryInitExpr>( + Var(segment, GetLocation()), Var(memidx, GetLocation()))); +} + +Result BinaryReaderIR::OnMemorySizeExpr(Index memidx) { + return AppendExpr( + std::make_unique<MemorySizeExpr>(Var(memidx, GetLocation()))); +} + +Result BinaryReaderIR::OnTableCopyExpr(Index dst_index, Index src_index) { + return AppendExpr(std::make_unique<TableCopyExpr>( + Var(dst_index, GetLocation()), Var(src_index, GetLocation()))); +} + +Result BinaryReaderIR::OnElemDropExpr(Index segment) { + return AppendExpr( + std::make_unique<ElemDropExpr>(Var(segment, GetLocation()))); +} + +Result BinaryReaderIR::OnTableInitExpr(Index segment, Index table_index) { + return AppendExpr(std::make_unique<TableInitExpr>( + Var(segment, GetLocation()), Var(table_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTableGetExpr(Index table_index) { + return AppendExpr( + std::make_unique<TableGetExpr>(Var(table_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTableSetExpr(Index table_index) { + return AppendExpr( + std::make_unique<TableSetExpr>(Var(table_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTableGrowExpr(Index table_index) { + return AppendExpr( + std::make_unique<TableGrowExpr>(Var(table_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTableSizeExpr(Index table_index) { + return AppendExpr( + std::make_unique<TableSizeExpr>(Var(table_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTableFillExpr(Index table_index) { + return AppendExpr( + std::make_unique<TableFillExpr>(Var(table_index, GetLocation()))); +} + +Result BinaryReaderIR::OnRefFuncExpr(Index func_index) { + return AppendExpr( + std::make_unique<RefFuncExpr>(Var(func_index, GetLocation()))); +} + +Result BinaryReaderIR::OnRefNullExpr(Type type) { + return AppendExpr(std::make_unique<RefNullExpr>(type)); +} + +Result BinaryReaderIR::OnRefIsNullExpr() { + return AppendExpr(std::make_unique<RefIsNullExpr>()); +} + +Result BinaryReaderIR::OnNopExpr() { + return AppendExpr(std::make_unique<NopExpr>()); +} + +Result BinaryReaderIR::OnRethrowExpr(Index depth) { + return AppendExpr(std::make_unique<RethrowExpr>(Var(depth, GetLocation()))); +} + +Result BinaryReaderIR::OnReturnExpr() { + return AppendExpr(std::make_unique<ReturnExpr>()); +} + +Result BinaryReaderIR::OnSelectExpr(Index result_count, Type* result_types) { + TypeVector results; + results.assign(result_types, result_types + result_count); + return AppendExpr(std::make_unique<SelectExpr>(results)); +} + +Result BinaryReaderIR::OnGlobalSetExpr(Index global_index) { + return AppendExpr( + std::make_unique<GlobalSetExpr>(Var(global_index, GetLocation()))); +} + +Result BinaryReaderIR::OnLocalSetExpr(Index local_index) { + return AppendExpr( + std::make_unique<LocalSetExpr>(Var(local_index, GetLocation()))); +} + +Result BinaryReaderIR::OnStoreExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<StoreExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnThrowExpr(Index tag_index) { + return AppendExpr(std::make_unique<ThrowExpr>(Var(tag_index, GetLocation()))); +} + +Result BinaryReaderIR::OnLocalTeeExpr(Index local_index) { + return AppendExpr( + std::make_unique<LocalTeeExpr>(Var(local_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTryExpr(Type sig_type) { + auto expr_ptr = std::make_unique<TryExpr>(); + // Save expr so it can be used below, after expr_ptr has been moved. + TryExpr* expr = expr_ptr.get(); + ExprList* expr_list = &expr->block.exprs; + SetBlockDeclaration(&expr->block.decl, sig_type); + CHECK_RESULT(AppendExpr(std::move(expr_ptr))); + module_->features_used.exceptions = true; + return PushLabel(LabelType::Try, expr_list, expr); +} + +Result BinaryReaderIR::AppendCatch(Catch&& catch_) { + LabelNode* label = nullptr; + CHECK_RESULT(TopLabel(&label)); + + if (label->label_type != LabelType::Try) { + PrintError("catch not inside try block"); + return Result::Error; + } + + auto* try_ = cast<TryExpr>(label->context); + + if (catch_.IsCatchAll() && !try_->catches.empty() && + try_->catches.back().IsCatchAll()) { + PrintError("only one catch_all allowed in try block"); + return Result::Error; + } + + if (try_->kind == TryKind::Plain) { + try_->kind = TryKind::Catch; + } else if (try_->kind != TryKind::Catch) { + PrintError("catch not allowed in try-delegate"); + return Result::Error; + } + + try_->catches.push_back(std::move(catch_)); + label->exprs = &try_->catches.back().exprs; + return Result::Ok; +} + +Result BinaryReaderIR::OnCatchExpr(Index except_index) { + return AppendCatch(Catch(Var(except_index, GetLocation()))); +} + +Result BinaryReaderIR::OnCatchAllExpr() { + return AppendCatch(Catch(GetLocation())); +} + +Result BinaryReaderIR::OnDelegateExpr(Index depth) { + LabelNode* label = nullptr; + CHECK_RESULT(TopLabel(&label)); + + if (label->label_type != LabelType::Try) { + PrintError("delegate not inside try block"); + return Result::Error; + } + + auto* try_ = cast<TryExpr>(label->context); + + if (try_->kind == TryKind::Plain) { + try_->kind = TryKind::Delegate; + } else if (try_->kind != TryKind::Delegate) { + PrintError("delegate not allowed in try-catch"); + return Result::Error; + } + + try_->delegate_target = Var(depth, GetLocation()); + + PopLabel(); + return Result::Ok; +} + +Result BinaryReaderIR::OnUnaryExpr(Opcode opcode) { + return AppendExpr(std::make_unique<UnaryExpr>(opcode)); +} + +Result BinaryReaderIR::OnTernaryExpr(Opcode opcode) { + return AppendExpr(std::make_unique<TernaryExpr>(opcode)); +} + +Result BinaryReaderIR::OnUnreachableExpr() { + return AppendExpr(std::make_unique<UnreachableExpr>()); +} + +Result BinaryReaderIR::EndFunctionBody(Index index) { + current_func_ = nullptr; + if (!label_stack_.empty()) { + PrintError("function %" PRIindex " missing end marker", index); + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReaderIR::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) { + return AppendExpr(std::make_unique<SimdLaneOpExpr>(opcode, value)); +} + +Result BinaryReaderIR::OnSimdLoadLaneExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset, + uint64_t value) { + return AppendExpr(std::make_unique<SimdLoadLaneExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset, value)); +} + +Result BinaryReaderIR::OnSimdStoreLaneExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset, + uint64_t value) { + return AppendExpr(std::make_unique<SimdStoreLaneExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset, value)); +} + +Result BinaryReaderIR::OnSimdShuffleOpExpr(Opcode opcode, v128 value) { + return AppendExpr(std::make_unique<SimdShuffleOpExpr>(opcode, value)); +} + +Result BinaryReaderIR::OnLoadSplatExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<LoadSplatExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnLoadZeroExpr(Opcode opcode, + Index memidx, + Address alignment_log2, + Address offset) { + return AppendExpr(std::make_unique<LoadZeroExpr>( + opcode, Var(memidx, GetLocation()), 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnElemSegmentCount(Index count) { + WABT_TRY + module_->elem_segments.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::BeginElemSegment(Index index, + Index table_index, + uint8_t flags) { + auto field = std::make_unique<ElemSegmentModuleField>(GetLocation()); + ElemSegment& elem_segment = field->elem_segment; + elem_segment.table_var = Var(table_index, GetLocation()); + if ((flags & SegDeclared) == SegDeclared) { + elem_segment.kind = SegmentKind::Declared; + } else if ((flags & SegPassive) == SegPassive) { + elem_segment.kind = SegmentKind::Passive; + } else { + elem_segment.kind = SegmentKind::Active; + } + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::BeginInitExpr(ExprList* expr) { + return PushLabel(LabelType::InitExpr, expr); +} + +Result BinaryReaderIR::BeginElemSegmentInitExpr(Index index) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + return BeginInitExpr(&segment->offset); +} + +Result BinaryReaderIR::EndInitExpr() { + if (!label_stack_.empty()) { + PrintError("init expression missing end marker"); + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReaderIR::EndElemSegmentInitExpr(Index index) { + return EndInitExpr(); +} + +Result BinaryReaderIR::OnElemSegmentElemType(Index index, Type elem_type) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + segment->elem_type = elem_type; + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemExprCount(Index index, Index count) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + WABT_TRY + segment->elem_exprs.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemExpr_RefNull(Index segment_index, + Type type) { + assert(segment_index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[segment_index]; + Location loc = GetLocation(); + ExprList init_expr; + init_expr.push_back(std::make_unique<RefNullExpr>(type, loc)); + segment->elem_exprs.push_back(std::move(init_expr)); + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) { + assert(segment_index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[segment_index]; + Location loc = GetLocation(); + ExprList init_expr; + init_expr.push_back(std::make_unique<RefFuncExpr>(Var(func_index, loc), loc)); + segment->elem_exprs.push_back(std::move(init_expr)); + return Result::Ok; +} + +Result BinaryReaderIR::OnDataSegmentCount(Index count) { + WABT_TRY + module_->data_segments.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) { + auto field = std::make_unique<DataSegmentModuleField>(GetLocation()); + DataSegment& data_segment = field->data_segment; + data_segment.memory_var = Var(memory_index, GetLocation()); + if ((flags & SegPassive) == SegPassive) { + data_segment.kind = SegmentKind::Passive; + } else { + data_segment.kind = SegmentKind::Active; + } + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::BeginDataSegmentInitExpr(Index index) { + assert(index == module_->data_segments.size() - 1); + DataSegment* segment = module_->data_segments[index]; + return BeginInitExpr(&segment->offset); +} + +Result BinaryReaderIR::EndDataSegmentInitExpr(Index index) { + return EndInitExpr(); +} + +Result BinaryReaderIR::OnDataSegmentData(Index index, + const void* data, + Address size) { + assert(index == module_->data_segments.size() - 1); + DataSegment* segment = module_->data_segments[index]; + segment->data.resize(size); + if (size > 0) { + memcpy(segment->data.data(), data, size); + } + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionNamesCount(Index count) { + if (count > module_->funcs.size()) { + PrintError("expected function name count (%" PRIindex + ") <= function count (%" PRIzd ")", + count, module_->funcs.size()); + return Result::Error; + } + return Result::Ok; +} + +static std::string MakeDollarName(std::string_view name) { + return std::string("$") + std::string(name); +} + +Result BinaryReaderIR::OnModuleName(std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + + module_->name = MakeDollarName(name); + return Result::Ok; +} + +Result BinaryReaderIR::SetGlobalName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->globals.size()) { + PrintError("invalid global index: %" PRIindex, index); + return Result::Error; + } + Global* glob = module_->globals[index]; + std::string dollar_name = + GetUniqueName(&module_->global_bindings, MakeDollarName(name)); + glob->name = dollar_name; + module_->global_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetFunctionName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->funcs.size()) { + PrintError("invalid function index: %" PRIindex, index); + return Result::Error; + } + Func* func = module_->funcs[index]; + std::string dollar_name = + GetUniqueName(&module_->func_bindings, MakeDollarName(name)); + func->name = dollar_name; + module_->func_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetTypeName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->types.size()) { + PrintError("invalid type index: %" PRIindex, index); + return Result::Error; + } + TypeEntry* type = module_->types[index]; + std::string dollar_name = + GetUniqueName(&module_->type_bindings, MakeDollarName(name)); + type->name = dollar_name; + module_->type_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetTableName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->tables.size()) { + PrintError("invalid table index: %" PRIindex, index); + return Result::Error; + } + Table* table = module_->tables[index]; + std::string dollar_name = + GetUniqueName(&module_->table_bindings, MakeDollarName(name)); + table->name = dollar_name; + module_->table_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetDataSegmentName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->data_segments.size()) { + PrintError("invalid data segment index: %" PRIindex, index); + return Result::Error; + } + DataSegment* segment = module_->data_segments[index]; + std::string dollar_name = + GetUniqueName(&module_->data_segment_bindings, MakeDollarName(name)); + segment->name = dollar_name; + module_->data_segment_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetElemSegmentName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->elem_segments.size()) { + PrintError("invalid elem segment index: %" PRIindex, index); + return Result::Error; + } + ElemSegment* segment = module_->elem_segments[index]; + std::string dollar_name = + GetUniqueName(&module_->elem_segment_bindings, MakeDollarName(name)); + segment->name = dollar_name; + module_->elem_segment_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetMemoryName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->memories.size()) { + PrintError("invalid memory index: %" PRIindex, index); + return Result::Error; + } + Memory* memory = module_->memories[index]; + std::string dollar_name = + GetUniqueName(&module_->memory_bindings, MakeDollarName(name)); + memory->name = dollar_name; + module_->memory_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::SetTagName(Index index, std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + if (index >= module_->tags.size()) { + PrintError("invalid tag index: %" PRIindex, index); + return Result::Error; + } + Tag* tag = module_->tags[index]; + std::string dollar_name = + GetUniqueName(&module_->tag_bindings, MakeDollarName(name)); + tag->name = dollar_name; + module_->tag_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionName(Index index, std::string_view name) { + return SetFunctionName(index, name); +} + +Result BinaryReaderIR::OnNameEntry(NameSectionSubsection type, + Index index, + std::string_view name) { + switch (type) { + // TODO(sbc): remove OnFunctionName in favor of just using + // OnNameEntry so that this works + case NameSectionSubsection::Function: + case NameSectionSubsection::Local: + case NameSectionSubsection::Module: + case NameSectionSubsection::Label: + break; + case NameSectionSubsection::Type: + SetTypeName(index, name); + break; + case NameSectionSubsection::Tag: + SetTagName(index, name); + break; + case NameSectionSubsection::Global: + SetGlobalName(index, name); + break; + case NameSectionSubsection::Table: + SetTableName(index, name); + break; + case NameSectionSubsection::DataSegment: + SetDataSegmentName(index, name); + break; + case NameSectionSubsection::Memory: + SetMemoryName(index, name); + break; + case NameSectionSubsection::ElemSegment: + SetElemSegmentName(index, name); + break; + } + return Result::Ok; +} + +Result BinaryReaderIR::OnLocalNameLocalCount(Index index, Index count) { + assert(index < module_->funcs.size()); + Func* func = module_->funcs[index]; + Index num_params_and_locals = func->GetNumParamsAndLocals(); + if (count > num_params_and_locals) { + PrintError("expected local name count (%" PRIindex + ") <= local count (%" PRIindex ")", + count, num_params_and_locals); + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReaderIR::BeginCodeMetadataSection(std::string_view name, + Offset size) { + current_metadata_name_ = name; + return Result::Ok; +} + +Result BinaryReaderIR::OnCodeMetadataFuncCount(Index count) { + return Result::Ok; +} + +Result BinaryReaderIR::OnCodeMetadataCount(Index function_index, Index count) { + code_metadata_queue_.push_func(module_->funcs[function_index]); + return Result::Ok; +} + +Result BinaryReaderIR::OnCodeMetadata(Offset offset, + const void* data, + Address size) { + std::vector<uint8_t> data_(static_cast<const uint8_t*>(data), + static_cast<const uint8_t*>(data) + size); + auto meta = std::make_unique<CodeMetadataExpr>(current_metadata_name_, + std::move(data_)); + meta->loc.offset = offset; + code_metadata_queue_.push_metadata(std::move(meta)); + return Result::Ok; +} + +Result BinaryReaderIR::OnLocalName(Index func_index, + Index local_index, + std::string_view name) { + if (name.empty()) { + return Result::Ok; + } + + Func* func = module_->funcs[func_index]; + func->bindings.emplace(GetUniqueName(&func->bindings, MakeDollarName(name)), + Binding(local_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnTagType(Index index, Index sig_index) { + auto field = std::make_unique<TagModuleField>(GetLocation()); + Tag& tag = field->tag; + SetFuncDeclaration(&tag.decl, Var(sig_index, GetLocation())); + module_->AppendField(std::move(field)); + module_->features_used.exceptions = true; + return Result::Ok; +} + +Result BinaryReaderIR::OnDataSymbol(Index index, + uint32_t flags, + std::string_view name, + Index segment, + uint32_t offset, + uint32_t size) { + if (name.empty()) { + return Result::Ok; + } + if (flags & WABT_SYMBOL_FLAG_UNDEFINED) { + // Refers to data in another file, `segment` not valid. + return Result::Ok; + } + if (offset) { + // If it is pointing into the data segment, then it's not really naming + // the whole segment. + return Result::Ok; + } + if (segment >= module_->data_segments.size()) { + PrintError("invalid data segment index: %" PRIindex, segment); + return Result::Error; + } + DataSegment* seg = module_->data_segments[segment]; + std::string dollar_name = + GetUniqueName(&module_->data_segment_bindings, MakeDollarName(name)); + seg->name = dollar_name; + module_->data_segment_bindings.emplace(dollar_name, Binding(segment)); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionSymbol(Index index, + uint32_t flags, + std::string_view name, + Index func_index) { + 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]; + if (!func->name.empty()) { + // The name section has already named this function. + return Result::Ok; + } + std::string dollar_name = + GetUniqueName(&module_->func_bindings, MakeDollarName(name)); + func->name = dollar_name; + module_->func_bindings.emplace(dollar_name, Binding(func_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnGlobalSymbol(Index index, + uint32_t flags, + std::string_view name, + Index global_index) { + return SetGlobalName(global_index, name); +} + +Result BinaryReaderIR::OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) { + return Result::Ok; +} + +Result BinaryReaderIR::OnTagSymbol(Index index, + uint32_t flags, + std::string_view name, + Index tag_index) { + 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]; + std::string dollar_name = + GetUniqueName(&module_->tag_bindings, MakeDollarName(name)); + tag->name = dollar_name; + module_->tag_bindings.emplace(dollar_name, Binding(tag_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnTableSymbol(Index index, + uint32_t flags, + std::string_view name, + Index table_index) { + return SetTableName(table_index, name); +} + +} // end anonymous namespace + +Result ReadBinaryIr(const char* filename, + const void* data, + size_t size, + const ReadBinaryOptions& options, + Errors* errors, + Module* out_module) { + BinaryReaderIR reader(out_module, filename, errors); + return ReadBinary(data, size, &reader, options); +} + +} // namespace wabt |