Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/wasm2c/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 63 kB image not shown  

Quelle  binary-reader-ir.cc   Sprache: C

 
/*
 * 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,
                        uint32_t page_size) 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,
                  uint32_t page_size) 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 destmemidx, Index srcmemidx) 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 BeginElemExpr(Index elem_index, Index expr_index) override;
  Result EndElemExpr(Index elem_index, Index expr_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 OnGenericCustomSection(std::string_view name,
                                const void* data,
                                Offset size) 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; });
  module_->features_used.exceptions |=
      std::any_of(func_type->sig.param_types.begin(),
                  func_type->sig.param_types.end(),
                  [](auto x) { return x == Type::ExnRef; }) ||
      std::any_of(func_type->sig.result_types.begin(),
                  func_type->sig.result_types.end(),
                  [](auto x) { return x == Type::ExnRef; });

  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);
    module_->features_used.exceptions |= (fields[i].type == Type::ExnRef);
  }
  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);
  module_->features_used.exceptions |= (type_mut.type == Type::ExnRef);
  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,
                                      uint32_t page_size) {
  auto import = std::make_unique<MemoryImport>();
  import->module_name = module_name;
  import->field_name = field_name;
  import->memory.page_limits = *page_limits;
  import->memory.page_size = page_size;
  if (import->memory.page_limits.is_shared) {
    module_->features_used.threads = true;
  }
  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);
  module_->features_used.exceptions |= (type == Type::ExnRef);
  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_->features_used.exceptions |= (elem_type == Type::ExnRef);
  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,
                                uint32_t page_size) {
  auto field = std::make_unique<MemoryModuleField>(GetLocation());
  Memory& memory = field->memory;
  memory.page_limits = *page_limits;
  memory.page_size = page_size;
  if (memory.page_limits.is_shared) {
    module_->features_used.threads = true;
  }
  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);
  module_->features_used.exceptions |= (type == Type::ExnRef);
  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);
  module_->features_used.exceptions |= (type == Type::ExnRef);
  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);
  module_->features_used.threads |= (opcode.GetPrefix() == 0xfe);
  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()), 1ull << 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()), 1ull << 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()), 1ull << 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()), 1ull << 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()), 1ull << 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()), 1ull << 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) {
  if (current_func_) {
    // syntactically, a return_call expr can occur in an init expression
    // (outside a function)
    current_func_->features_used.tailcall = true;
  }
  return AppendExpr(
      std::make_unique<ReturnCallExpr>(Var(func_index, GetLocation())));
}

Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index,
                                                Index table_index) {
  if (current_func_) {
    // syntactically, a return_call_indirect expr can occur in an init
    // expression (outside a function)
    current_func_->features_used.tailcall = true;
  }
  auto expr = std::make_unique<ReturnCallIndirectExpr>();
  SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation()));
  expr->table = Var(table_index, GetLocation());
  FuncType* type = module_->GetFuncType(Var(sig_index, GetLocation()));
  if (type) {
    type->features_used.tailcall = true;
  }
  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()), 1ull << 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 destmemidx, Index srcmemidx) {
  return AppendExpr(std::make_unique<MemoryCopyExpr>(
      Var(destmemidx, GetLocation()), Var(srcmemidx, 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) {
  module_->used_func_refs.insert(func_index);
  return AppendExpr(
      std::make_unique<RefFuncExpr>(Var(func_index, GetLocation())));
}

Result BinaryReaderIR::OnRefNullExpr(Type type) {
  module_->features_used.exceptions |= (type == Type::ExnRef);
  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()), 1ull << alignment_log2, offset));
}

Result BinaryReaderIR::OnThrowExpr(Index tag_index) {
  module_->features_used.exceptions = true;
  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()), 1ull << 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()), 1ull << 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()), 1ull << 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()), 1ull << 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::BeginElemExpr(Index elem_index, Index expr_index) {
  assert(elem_index == module_->elem_segments.size() - 1);
  ElemSegment* segment = module_->elem_segments[elem_index];
  assert(expr_index == segment->elem_exprs.size());
  segment->elem_exprs.emplace_back();
  return BeginInitExpr(&segment->elem_exprs.back());
}

Result BinaryReaderIR::EndElemExpr(Index elem_index, Index expr_index) {
  return EndInitExpr();
}

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:
    case NameSectionSubsection::Field:
      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);
}

Result BinaryReaderIR::OnGenericCustomSection(std::string_view name,
                                              const void* data,
                                              Offset size) {
  Custom custom = Custom(GetLocation(), name);
  custom.data.resize(size);
  if (size > 0) {
    memcpy(custom.data.data(), data, size);
  }
  module_->customs.push_back(std::move(custom));
  return Result::Ok;
}

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

Messung V0.5
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.59 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.