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 105 kB image not shown  

Quelle  binary-reader.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.h"

#include <cassert>
#include <cinttypes>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>

#include "wabt/config.h"

#include "wabt/binary-reader-logging.h"
#include "wabt/binary.h"
#include "wabt/leb128.h"
#include "wabt/stream.h"
#include "wabt/utf8.h"

#if HAVE_ALLOCA
#include <alloca.h>
#endif

#define ERROR_IF(expr, ...)    \
  do {                         \
    if (expr) {                \
      PrintError(__VA_ARGS__); \
      return Result::Error;    \
    }                          \
  } while (0)

#define ERROR_UNLESS(expr, ...) ERROR_IF(!(expr), __VA_ARGS__)

#define ERROR_UNLESS_OPCODE_ENABLED(opcode)     \
  do {                                          \
    if (!opcode.IsEnabled(options_.features)) { \
      return ReportUnexpectedOpcode(opcode);    \
    }                                           \
  } while (0)

#define CALLBACK0(member) \
  ERROR_UNLESS(Succeeded(delegate_->member()), #member " callback failed")

#define CALLBACK(member, ...)                             \
  ERROR_UNLESS(Succeeded(delegate_->member(__VA_ARGS__)), \
               #member " callback failed")

namespace wabt {

namespace {

class BinaryReader {
 public:
  struct ReadModuleOptions {
    bool stop_on_first_error;
  };

  BinaryReader(const void* data,
               size_t size,
               BinaryReaderDelegate* delegate,
               const ReadBinaryOptions& options);

  Result ReadModule(const ReadModuleOptions& options);

 private:
  template <typename T, T BinaryReader::*member>
  struct ValueRestoreGuard {
    explicit ValueRestoreGuard(BinaryReader* this_)
        : this_(this_), previous_value_(this_->*member) {}
    ~ValueRestoreGuard() { this_->*member = previous_value_; }

    BinaryReader* this_;
    T previous_value_;
  };

  struct ReadSectionsOptions {
    bool stop_on_first_error;
  };

  void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* format, ...);
  [[nodiscard]] Result ReadOpcode(Opcode* out_value, const char* desc);
  template <typename T>
  [[nodiscard]] Result ReadT(T* out_value,
                             const char* type_name,
                             const char* desc);
  [[nodiscard]] Result ReadU8(uint8_t* out_value, const char* desc);
  [[nodiscard]] Result ReadU32(uint32_t* out_value, const char* desc);
  [[nodiscard]] Result ReadF32(uint32_t* out_value, const char* desc);
  [[nodiscard]] Result ReadF64(uint64_t* out_value, const char* desc);
  [[nodiscard]] Result ReadV128(v128* out_value, const char* desc);
  [[nodiscard]] Result ReadU32Leb128(uint32_t* out_value, const char* desc);
  [[nodiscard]] Result ReadU64Leb128(uint64_t* out_value, const char* desc);
  [[nodiscard]] Result ReadS32Leb128(uint32_t* out_value, const char* desc);
  [[nodiscard]] Result ReadS64Leb128(uint64_t* out_value, const char* desc);
  [[nodiscard]] Result ReadType(Type* out_value, const char* desc);
  [[nodiscard]] Result ReadRefType(Type* out_value, const char* desc);
  [[nodiscard]] Result ReadExternalKind(ExternalKind* out_value,
                                        const char* desc);
  [[nodiscard]] Result ReadStr(std::string_view* out_str, const char* desc);
  [[nodiscard]] Result ReadBytes(const void** out_data,
                                 Address* out_data_size,
                                 const char* desc);
  [[nodiscard]] Result ReadBytesWithSize(const void** out_data,
                                         Offset size,
                                         const char* desc);
  [[nodiscard]] Result ReadIndex(Index* index, const char* desc);
  [[nodiscard]] Result ReadOffset(Offset* offset, const char* desc);
  [[nodiscard]] Result ReadAlignment(Address* align_log2, const char* desc);
  [[nodiscard]] Result CheckAlignment(Address* align_log2, const char* desc);
  [[nodiscard]] Result TakeHasMemidx(Address* align_log2, bool* has_memidx);
  [[nodiscard]] Result ReadMemidx(Index* memidx, const char* desc);
  [[nodiscard]] Result ReadMemLocation(Address* alignment_log2,
                                       Index* memidx,
                                       Address* offset,
                                       const char* desc_align,
                                       const char* desc_memidx,
                                       const char* desc_offset,
                                       uint8_t* lane_val = nullptr);
  [[nodiscard]] Result CallbackMemLocation(const Address* alignment_log2,
                                           const Index* memidx,
                                           const Address* offset,
                                           const uint8_t* lane_val = nullptr);
  [[nodiscard]] Result ReadCount(Index* index, const char* desc);
  [[nodiscard]] Result ReadField(TypeMut* out_value);

  bool IsConcreteType(Type);
  bool IsBlockType(Type);

  Index NumTotalFuncs();

  [[nodiscard]] Result ReadInitExpr(Index index);
  [[nodiscard]] Result ReadTable(Type* out_elem_type, Limits* out_elem_limits);
  [[nodiscard]] Result ReadMemory(Limits* out_page_limits,
                                  uint32_t* out_page_size);
  [[nodiscard]] Result ReadGlobalHeader(Type* out_type, bool* out_mutable);
  [[nodiscard]] Result ReadTagType(Index* out_sig_index);
  [[nodiscard]] Result ReadAddress(Address* out_value,
                                   Index memory,
                                   const char* desc);
  [[nodiscard]] Result ReadFunctionBody(Offset end_offset);
  // ReadInstructions reads until end_offset or the nesting depth reaches zero.
  [[nodiscard]] Result ReadInstructions(Offset end_offset, const char* context);
  [[nodiscard]] Result ReadNameSection(Offset section_size);
  [[nodiscard]] Result ReadRelocSection(Offset section_size);
  [[nodiscard]] Result ReadDylinkSection(Offset section_size);
  [[nodiscard]] Result ReadGenericCustomSection(std::string_view name,
                                                Offset section_size);
  [[nodiscard]] Result ReadDylink0Section(Offset section_size);
  [[nodiscard]] Result ReadTargetFeaturesSections(Offset section_size);
  [[nodiscard]] Result ReadLinkingSection(Offset section_size);
  [[nodiscard]] Result ReadCodeMetadataSection(std::string_view name,
                                               Offset section_size);
  [[nodiscard]] Result ReadCustomSection(Index section_index,
                                         Offset section_size);
  [[nodiscard]] Result ReadTypeSection(Offset section_size);
  [[nodiscard]] Result ReadImportSection(Offset section_size);
  [[nodiscard]] Result ReadFunctionSection(Offset section_size);
  [[nodiscard]] Result ReadTableSection(Offset section_size);
  [[nodiscard]] Result ReadMemorySection(Offset section_size);
  [[nodiscard]] Result ReadGlobalSection(Offset section_size);
  [[nodiscard]] Result ReadExportSection(Offset section_size);
  [[nodiscard]] Result ReadStartSection(Offset section_size);
  [[nodiscard]] Result ReadElemSection(Offset section_size);
  [[nodiscard]] Result ReadCodeSection(Offset section_size);
  [[nodiscard]] Result ReadDataSection(Offset section_size);
  [[nodiscard]] Result ReadDataCountSection(Offset section_size);
  [[nodiscard]] Result ReadTagSection(Offset section_size);
  [[nodiscard]] Result ReadSections(const ReadSectionsOptions& options);
  Result ReportUnexpectedOpcode(Opcode opcode, const char* message = nullptr);

  size_t read_end_ = 0;  // Either the section end or data_size.
  BinaryReaderDelegate::State state_;
  BinaryReaderLogging logging_delegate_;
  BinaryReaderDelegate* delegate_ = nullptr;
  TypeVector param_types_;
  TypeVector result_types_;
  TypeMutVector fields_;
  std::vector<Index> target_depths_;
  const ReadBinaryOptions& options_;
  BinarySection last_known_section_ = BinarySection::Invalid;
  bool did_read_names_section_ = false;
  bool reading_custom_section_ = false;
  Index num_func_imports_ = 0;
  Index num_table_imports_ = 0;
  Index num_memory_imports_ = 0;
  Index num_global_imports_ = 0;
  Index num_tag_imports_ = 0;
  Index num_function_signatures_ = 0;
  Index num_function_bodies_ = 0;
  Index num_data_segments_ = 0;
  Index data_count_ = kInvalidIndex;

  using ReadEndRestoreGuard =
      ValueRestoreGuard<size_t, &BinaryReader::read_end_>;
};

BinaryReader::BinaryReader(const void* data,
                           size_t size,
                           BinaryReaderDelegate* delegate,
                           const ReadBinaryOptions& options)
    : read_end_(size),
      state_(static_cast<const uint8_t*>(data), size),
      logging_delegate_(options.log_stream, delegate),
      delegate_(options.log_stream ? &logging_delegate_ : delegate),
      options_(options),
      last_known_section_(BinarySection::Invalid) {
  delegate->OnSetState(&state_);
}

void WABT_PRINTF_FORMAT(2, 3) BinaryReader::PrintError(const char* format,
                                                       ...) {
  ErrorLevel error_level =
      reading_custom_section_ && !options_.fail_on_custom_section_error
          ? ErrorLevel::Warning
          : ErrorLevel::Error;

  WABT_SNPRINTF_ALLOCA(buffer, length, format);
  Error error(error_level, Location(state_.offset), buffer);
  bool handled = delegate_->OnError(error);

  if (!handled) {
    // Not great to just print, but we don't want to eat the error either.
    fprintf(stderr, "%07" PRIzx ": %s: %s\n", state_.offset,
            GetErrorLevelName(error_level), buffer);
  }
}

Result BinaryReader::ReportUnexpectedOpcode(Opcode opcode, const char* where) {
  std::string message = "unexpected opcode";
  if (where) {
    message += ' ';
    message += where;
  }

  message += ":";

  std::vector<uint8_t> bytes = opcode.GetBytes();
  assert(bytes.size() > 0);

  for (uint8_t byte : bytes) {
    message += StringPrintf(" 0x%x", byte);
  }

  PrintError("%s", message.c_str());
  return Result::Error;
}

Result BinaryReader::ReadOpcode(Opcode* out_value, const char* desc) {
  uint8_t value = 0;
  CHECK_RESULT(ReadU8(&value, desc));

  if (Opcode::IsPrefixByte(value)) {
    uint32_t code;
    CHECK_RESULT(ReadU32Leb128(&code, desc));
    *out_value = Opcode::FromCode(value, code);
  } else {
    *out_value = Opcode::FromCode(value);
  }
  return Result::Ok;
}

template <typename T>
Result BinaryReader::ReadT(T* out_value,
                           const char* type_name,
                           const char* desc) {
  if (state_.offset + sizeof(T) > read_end_) {
    PrintError("unable to read %s: %s", type_name, desc);
    return Result::Error;
  }
#if WABT_BIG_ENDIAN
  uint8_t tmp[sizeof(T)];
  memcpy(tmp, state_.data + state_.offset, sizeof(tmp));
  SwapBytesSized(tmp, sizeof(tmp));
  memcpy(out_value, tmp, sizeof(T));
#else
  memcpy(out_value, state_.data + state_.offset, sizeof(T));
#endif
  state_.offset += sizeof(T);
  return Result::Ok;
}

Result BinaryReader::ReadU8(uint8_t* out_value, const char* desc) {
  return ReadT(out_value, "uint8_t", desc);
}

Result BinaryReader::ReadU32(uint32_t* out_value, const char* desc) {
  return ReadT(out_value, "uint32_t", desc);
}

Result BinaryReader::ReadF32(uint32_t* out_value, const char* desc) {
  return ReadT(out_value, "float", desc);
}

Result BinaryReader::ReadF64(uint64_t* out_value, const char* desc) {
  return ReadT(out_value, "double", desc);
}

Result BinaryReader::ReadV128(v128* out_value, const char* desc) {
  return ReadT(out_value, "v128", desc);
}

Result BinaryReader::ReadU32Leb128(uint32_t* out_value, const char* desc) {
  const uint8_t* p = state_.data + state_.offset;
  const uint8_t* end = state_.data + read_end_;
  size_t bytes_read = wabt::ReadU32Leb128(p, end, out_value);
  ERROR_UNLESS(bytes_read > 0, "unable to read u32 leb128: %s", desc);
  state_.offset += bytes_read;
  return Result::Ok;
}

Result BinaryReader::ReadU64Leb128(uint64_t* out_value, const char* desc) {
  const uint8_t* p = state_.data + state_.offset;
  const uint8_t* end = state_.data + read_end_;
  size_t bytes_read = wabt::ReadU64Leb128(p, end, out_value);
  ERROR_UNLESS(bytes_read > 0, "unable to read u64 leb128: %s", desc);
  state_.offset += bytes_read;
  return Result::Ok;
}

Result BinaryReader::ReadS32Leb128(uint32_t* out_value, const char* desc) {
  const uint8_t* p = state_.data + state_.offset;
  const uint8_t* end = state_.data + read_end_;
  size_t bytes_read = wabt::ReadS32Leb128(p, end, out_value);
  ERROR_UNLESS(bytes_read > 0, "unable to read i32 leb128: %s", desc);
  state_.offset += bytes_read;
  return Result::Ok;
}

Result BinaryReader::ReadS64Leb128(uint64_t* out_value, const char* desc) {
  const uint8_t* p = state_.data + state_.offset;
  const uint8_t* end = state_.data + read_end_;
  size_t bytes_read = wabt::ReadS64Leb128(p, end, out_value);
  ERROR_UNLESS(bytes_read > 0, "unable to read i64 leb128: %s", desc);
  state_.offset += bytes_read;
  return Result::Ok;
}

Result BinaryReader::ReadType(Type* out_value, const char* desc) {
  uint32_t type = 0;
  CHECK_RESULT(ReadS32Leb128(&type, desc));
  if (static_cast<Type::Enum>(type) == Type::Reference) {
    uint32_t heap_type = 0;
    CHECK_RESULT(ReadS32Leb128(&heap_type, desc));
    *out_value = Type(Type::Reference, heap_type);
  } else {
    *out_value = static_cast<Type>(type);
  }
  return Result::Ok;
}

Result BinaryReader::ReadRefType(Type* out_value, const char* desc) {
  uint32_t type = 0;
  CHECK_RESULT(ReadS32Leb128(&type, desc));
  *out_value = static_cast<Type>(type);
  ERROR_UNLESS(out_value->IsRef(), "%s must be a reference type", desc);
  return Result::Ok;
}

Result BinaryReader::ReadExternalKind(ExternalKind* out_value,
                                      const char* desc) {
  uint8_t value = 0;
  CHECK_RESULT(ReadU8(&value, desc));
  ERROR_UNLESS(value < kExternalKindCount, "invalid export external kind: %d",
               value);
  *out_value = static_cast<ExternalKind>(value);
  return Result::Ok;
}

Result BinaryReader::ReadStr(std::string_view* out_str, const char* desc) {
  uint32_t str_len = 0;
  CHECK_RESULT(ReadU32Leb128(&str_len, "string length"));

  ERROR_UNLESS(state_.offset + str_len <= read_end_,
               "unable to read string: %s", desc);

  *out_str = std::string_view(
      reinterpret_cast<const char*>(state_.data) + state_.offset, str_len);
  state_.offset += str_len;

  ERROR_UNLESS(IsValidUtf8(out_str->data(), out_str->length()),
               "invalid utf-8 encoding: %s", desc);
  return Result::Ok;
}

Result BinaryReader::ReadBytes(const void** out_data,
                               Address* out_data_size,
                               const char* desc) {
  uint32_t data_size = 0;
  CHECK_RESULT(ReadU32Leb128(&data_size, "data size"));
  CHECK_RESULT(ReadBytesWithSize(out_data, data_size, desc));
  *out_data_size = data_size;
  return Result::Ok;
}

Result BinaryReader::ReadBytesWithSize(const void** out_data,
                                       Offset size,
                                       const char* desc) {
  ERROR_UNLESS(state_.offset + size <= read_end_, "unable to read data: %s",
               desc);

  *out_data = static_cast<const uint8_t*>(state_.data) + state_.offset;
  state_.offset += size;
  return Result::Ok;
}

Result BinaryReader::ReadIndex(Index* index, const char* desc) {
  uint32_t value;
  CHECK_RESULT(ReadU32Leb128(&value, desc));
  *index = value;
  return Result::Ok;
}

Result BinaryReader::ReadOffset(Offset* offset, const char* desc) {
  uint32_t value;
  CHECK_RESULT(ReadU32Leb128(&value, desc));
  *offset = value;
  return Result::Ok;
}

Result BinaryReader::ReadAlignment(Address* alignment_log2, const char* desc) {
  uint32_t value;
  CHECK_RESULT(ReadU32Leb128(&value, desc));
  *alignment_log2 = value;
  return Result::Ok;
}

Result BinaryReader::CheckAlignment(Address* align_log2, const char* desc) {
  uint32_t value = *align_log2;
  if (value >= 32) {
    PrintError("invalid %s: %" PRIu32, desc, value);
    return Result::Error;
  }
  return Result::Ok;
}

Result BinaryReader::TakeHasMemidx(Address* align_log2, bool* has_memidx) {
  // extract the has_memidx flag
  *has_memidx = (*align_log2 >> 6) & 1;
  // then clear it
  *align_log2 &= ~(1 << 6);
  return Result::Ok;
}

Result BinaryReader::ReadMemidx(Index* memidx, const char* desc) {
  CHECK_RESULT(ReadIndex(memidx, desc));
  return Result::Ok;
}

Result BinaryReader::ReadMemLocation(Address* alignment_log2,
                                     Index* memidx,
                                     Address* offset,
                                     const char* desc_align,
                                     const char* desc_memidx,
                                     const char* desc_offset,
                                     uint8_t* lane_val) {
  bool has_memidx = false;
  CHECK_RESULT(ReadAlignment(alignment_log2, desc_align));
  CHECK_RESULT(TakeHasMemidx(alignment_log2, &has_memidx));
  CHECK_RESULT(CheckAlignment(alignment_log2, desc_align));
  *memidx = 0;
  if (has_memidx) {
    ERROR_IF(!options_.features.multi_memory_enabled(),
             "multi_memory not allowed");
    CHECK_RESULT(ReadMemidx(memidx, desc_memidx));
  }
  CHECK_RESULT(ReadAddress(offset, 0, desc_offset));

  if (lane_val) {
    CHECK_RESULT(ReadU8(lane_val, "Lane idx"));
  }

  return Result::Ok;
}

Result BinaryReader::CallbackMemLocation(const Address* alignment_log2,
                                         const Index* memidx,
                                         const Address* offset,
                                         const uint8_t* lane_val) {
  if (lane_val) {
    if (*memidx) {
      CALLBACK(OnOpcodeUint32Uint32Uint32Uint32, *alignment_log2, *memidx,
               *offset, *lane_val);
    } else {
      CALLBACK(OnOpcodeUint32Uint32Uint32, *alignment_log2, *offset, *lane_val);
    }
  } else {
    if (*memidx) {
      CALLBACK(OnOpcodeUint32Uint32Uint32, *alignment_log2, *memidx, *offset);
    } else {
      CALLBACK(OnOpcodeUint32Uint32, *alignment_log2, *offset);
    }
  }

  return Result::Ok;
}

Result BinaryReader::ReadCount(Index* count, const char* desc) {
  CHECK_RESULT(ReadIndex(count, desc));

  // This check assumes that each item follows in this section, and takes at
  // least 1 byte. It's possible that this check passes but reading fails
  // later. It is still useful to check here, though, because it early-outs
  // when an erroneous large count is used, before allocating memory for it.
  size_t section_remaining = read_end_ - state_.offset;
  if (*count > section_remaining) {
    PrintError("invalid %s %" PRIindex ", only %" PRIzd
               " bytes left in section",
               desc, *count, section_remaining);
    return Result::Error;
  }
  return Result::Ok;
}

Result BinaryReader::ReadField(TypeMut* out_value) {
  // TODO: Reuse for global header too?
  Type field_type;
  CHECK_RESULT(ReadType(&field_type, "field type"));
  ERROR_UNLESS(IsConcreteType(field_type),
               "expected valid field type (got " PRItypecode ")",
               WABT_PRINTF_TYPE_CODE(field_type));

  uint8_t mutable_ = 0;
  CHECK_RESULT(ReadU8(&mutable_, "field mutability"));
  ERROR_UNLESS(mutable_ <= 1, "field mutability must be 0 or 1");
  out_value->type = field_type;
  out_value->mutable_ = mutable_;
  return Result::Ok;
}

bool BinaryReader::IsConcreteType(Type type) {
  switch (type) {
    case Type::I32:
    case Type::I64:
    case Type::F32:
    case Type::F64:
      return true;

    case Type::V128:
      return options_.features.simd_enabled();

    case Type::FuncRef:
    case Type::ExternRef:
      return options_.features.reference_types_enabled();

    case Type::ExnRef:
      return options_.features.exceptions_enabled();

    case Type::Reference:
      return options_.features.function_references_enabled();

    default:
      return false;
  }
}

bool BinaryReader::IsBlockType(Type type) {
  if (IsConcreteType(type) || type == Type::Void) {
    return true;
  }

  if (!(options_.features.multi_value_enabled() && type.IsIndex())) {
    return false;
  }

  return true;
}

Index BinaryReader::NumTotalFuncs() {
  return num_func_imports_ + num_function_signatures_;
}

Result BinaryReader::ReadInitExpr(Index index) {
  CHECK_RESULT(ReadInstructions(read_end_, "init expression"));
  assert(state_.offset <= read_end_);
  return Result::Ok;
}

Result BinaryReader::ReadTable(Type* out_elem_type, Limits* out_elem_limits) {
  CHECK_RESULT(ReadRefType(out_elem_type, "table elem type"));

  uint8_t flags;
  uint32_t initial;
  uint32_t max = 0;
  CHECK_RESULT(ReadU8(&flags, "table flags"));
  bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG;
  bool is_shared = flags & WABT_BINARY_LIMITS_IS_SHARED_FLAG;
  bool is_64 = flags & WABT_BINARY_LIMITS_IS_64_FLAG;
  const uint8_t unknown_flags = flags & ~WABT_BINARY_LIMITS_ALL_TABLE_FLAGS;
  ERROR_IF(is_shared, "tables may not be shared");
  ERROR_IF(is_64 && !options_.features.memory64_enabled(),
           "memory64 not allowed");
  ERROR_UNLESS(unknown_flags == 0, "malformed table limits flag: %d", flags);
  CHECK_RESULT(ReadU32Leb128(&initial, "table initial elem count"));
  if (has_max) {
    CHECK_RESULT(ReadU32Leb128(&max, "table max elem count"));
  }

  out_elem_limits->has_max = has_max;
  out_elem_limits->is_64 = is_64;
  out_elem_limits->initial = initial;
  out_elem_limits->max = max;
  return Result::Ok;
}

Result BinaryReader::ReadMemory(Limits* out_page_limits,
                                uint32_t* out_page_size) {
  uint8_t flags;
  uint64_t initial;
  uint64_t max = 0;
  CHECK_RESULT(ReadU8(&flags, "memory flags"));
  bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG;
  bool is_shared = flags & WABT_BINARY_LIMITS_IS_SHARED_FLAG;
  bool is_64 = flags & WABT_BINARY_LIMITS_IS_64_FLAG;
  bool has_custom_page_size =
      flags & WABT_BINARY_LIMITS_HAS_CUSTOM_PAGE_SIZE_FLAG;
  const uint8_t unknown_flags = flags & ~WABT_BINARY_LIMITS_ALL_MEMORY_FLAGS;
  ERROR_UNLESS(unknown_flags == 0, "malformed memory limits flag: %d", flags);
  ERROR_IF(is_shared && !options_.features.threads_enabled(),
           "memory may not be shared: threads not allowed");
  ERROR_IF(is_64 && !options_.features.memory64_enabled(),
           "memory64 not allowed");
  ERROR_IF(
      has_custom_page_size && !options_.features.custom_page_sizes_enabled(),
      "custom page sizes not allowed");
  if (options_.features.memory64_enabled()) {
    CHECK_RESULT(ReadU64Leb128(&initial, "memory initial page count"));
    if (has_max) {
      CHECK_RESULT(ReadU64Leb128(&max, "memory max page count"));
    }
  } else {
    uint32_t initial32;
    CHECK_RESULT(ReadU32Leb128(&initial32, "memory initial page count"));
    initial = initial32;
    if (has_max) {
      uint32_t max32;
      CHECK_RESULT(ReadU32Leb128(&max32, "memory max page count"));
      max = max32;
    }
  }
  if (has_custom_page_size) {
    uint32_t page_size_log2;
    CHECK_RESULT(ReadU32Leb128(&page_size_log2, "memory page size"));
    ERROR_IF(page_size_log2 > 16, "malformed memory page size");
    *out_page_size = 1 << page_size_log2;
  } else {
    *out_page_size = WABT_DEFAULT_PAGE_SIZE;
  }

  out_page_limits->has_max = has_max;
  out_page_limits->is_shared = is_shared;
  out_page_limits->is_64 = is_64;
  out_page_limits->initial = initial;
  out_page_limits->max = max;

  return Result::Ok;
}

Result BinaryReader::ReadGlobalHeader(Type* out_type, bool* out_mutable) {
  Type global_type = Type::Void;
  uint8_t mutable_ = 0;
  CHECK_RESULT(ReadType(&global_type, "global type"));
  ERROR_UNLESS(IsConcreteType(global_type), "invalid global type: %#x",
               static_cast<int>(global_type));

  CHECK_RESULT(ReadU8(&mutable_, "global mutability"));
  ERROR_UNLESS(mutable_ <= 1, "global mutability must be 0 or 1");

  *out_type = global_type;
  *out_mutable = mutable_;
  return Result::Ok;
}

Result BinaryReader::ReadAddress(Address* out_value,
                                 Index memory,
                                 const char* desc) {
  if (options_.features.memory64_enabled()) {
    return ReadU64Leb128(out_value, desc);
  } else {
    uint32_t val;
    Result res = ReadU32Leb128(&val, desc);
    *out_value = val;
    return res;
  }
}

Result BinaryReader::ReadFunctionBody(Offset end_offset) {
  CHECK_RESULT(ReadInstructions(end_offset, "function body"));
  ERROR_UNLESS(state_.offset == end_offset,
               "function body shorter than given size");
  return Result::Ok;
}

Result BinaryReader::ReadInstructions(Offset end_offset, const char* context) {
  std::stack<Opcode> nested_blocks;
  while (state_.offset < end_offset) {
    Opcode opcode;
    CHECK_RESULT(ReadOpcode(&opcode, "opcode"));
    CALLBACK(OnOpcode, opcode);
    ERROR_UNLESS_OPCODE_ENABLED(opcode);

    switch (opcode) {
      case Opcode::Unreachable:
        CALLBACK0(OnUnreachableExpr);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::Block: {
        nested_blocks.push(opcode);
        Type sig_type;
        CHECK_RESULT(ReadType(&sig_type, "block signature type"));
        ERROR_UNLESS(IsBlockType(sig_type),
                     "expected valid block signature type");
        CALLBACK(OnBlockExpr, sig_type);
        CALLBACK(OnOpcodeBlockSig, sig_type);
        break;
      }

      case Opcode::Loop: {
        nested_blocks.push(opcode);
        Type sig_type;
        CHECK_RESULT(ReadType(&sig_type, "loop signature type"));
        ERROR_UNLESS(IsBlockType(sig_type),
                     "expected valid block signature type");
        CALLBACK(OnLoopExpr, sig_type);
        CALLBACK(OnOpcodeBlockSig, sig_type);
        break;
      }

      case Opcode::If: {
        nested_blocks.push(opcode);
        Type sig_type;
        CHECK_RESULT(ReadType(&sig_type, "if signature type"));
        ERROR_UNLESS(IsBlockType(sig_type),
                     "expected valid block signature type");
        CALLBACK(OnIfExpr, sig_type);
        CALLBACK(OnOpcodeBlockSig, sig_type);
        break;
      }

      case Opcode::Else:
        ERROR_IF(nested_blocks.empty() || (nested_blocks.top() != Opcode::If),
                 "else outside if block");
        CALLBACK0(OnElseExpr);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::SelectT: {
        Index num_results;
        CHECK_RESULT(ReadCount(&num_results, "num result types"));

        result_types_.resize(num_results);
        for (Index i = 0; i < num_results; ++i) {
          Type result_type;
          CHECK_RESULT(ReadType(&result_type, "select result type"));
          ERROR_UNLESS(IsConcreteType(result_type),
                       "expected valid select result type (got " PRItypecode
                       ")",
                       WABT_PRINTF_TYPE_CODE(result_type));
          result_types_[i] = result_type;
        }

        if (num_results) {
          CALLBACK(OnSelectExpr, num_results, result_types_.data());
          CALLBACK(OnOpcodeType, result_types_[0]);
        } else {
          CALLBACK(OnSelectExpr, 0, NULL);
          CALLBACK0(OnOpcodeBare);
        }
        break;
      }

      case Opcode::Select:
        CALLBACK(OnSelectExpr, 0, nullptr);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::Br: {
        Index depth;
        CHECK_RESULT(ReadIndex(&depth, "br depth"));
        CALLBACK(OnBrExpr, depth);
        CALLBACK(OnOpcodeIndex, depth);
        break;
      }

      case Opcode::BrIf: {
        Index depth;
        CHECK_RESULT(ReadIndex(&depth, "br_if depth"));
        CALLBACK(OnBrIfExpr, depth);
        CALLBACK(OnOpcodeIndex, depth);
        break;
      }

      case Opcode::BrTable: {
        Index num_targets;
        CHECK_RESULT(ReadCount(&num_targets, "br_table target count"));
        target_depths_.resize(num_targets);

        for (Index i = 0; i < num_targets; ++i) {
          Index target_depth;
          CHECK_RESULT(ReadIndex(&target_depth, "br_table target depth"));
          target_depths_[i] = target_depth;
        }

        Index default_target_depth;
        CHECK_RESULT(
            ReadIndex(&default_target_depth, "br_table default target depth"));

        Index* target_depths = num_targets ? target_depths_.data() : nullptr;

        CALLBACK(OnBrTableExpr, num_targets, target_depths,
                 default_target_depth);
        break;
      }

      case Opcode::Return:
        CALLBACK0(OnReturnExpr);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::Nop:
        CALLBACK0(OnNopExpr);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::Drop:
        CALLBACK0(OnDropExpr);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::End:
        CALLBACK0(OnEndExpr);
        if (nested_blocks.empty()) {
          return Result::Ok;
        }
        nested_blocks.pop();
        break;

      case Opcode::I32Const: {
        uint32_t value;
        CHECK_RESULT(ReadS32Leb128(&value, "i32.const value"));
        CALLBACK(OnI32ConstExpr, value);
        CALLBACK(OnOpcodeUint32, value);
        break;
      }

      case Opcode::I64Const: {
        uint64_t value;
        CHECK_RESULT(ReadS64Leb128(&value, "i64.const value"));
        CALLBACK(OnI64ConstExpr, value);
        CALLBACK(OnOpcodeUint64, value);
        break;
      }

      case Opcode::F32Const: {
        uint32_t value_bits = 0;
        CHECK_RESULT(ReadF32(&value_bits, "f32.const value"));
        CALLBACK(OnF32ConstExpr, value_bits);
        CALLBACK(OnOpcodeF32, value_bits);
        break;
      }

      case Opcode::F64Const: {
        uint64_t value_bits = 0;
        CHECK_RESULT(ReadF64(&value_bits, "f64.const value"));
        CALLBACK(OnF64ConstExpr, value_bits);
        CALLBACK(OnOpcodeF64, value_bits);
        break;
      }

      case Opcode::V128Const: {
        v128 value_bits;
        ZeroMemory(value_bits);
        CHECK_RESULT(ReadV128(&value_bits, "v128.const value"));
        CALLBACK(OnV128ConstExpr, value_bits);
        CALLBACK(OnOpcodeV128, value_bits);
        break;
      }

      case Opcode::GlobalGet: {
        Index global_index;
        CHECK_RESULT(ReadIndex(&global_index, "global.get global index"));
        CALLBACK(OnGlobalGetExpr, global_index);
        CALLBACK(OnOpcodeIndex, global_index);
        break;
      }

      case Opcode::LocalGet: {
        Index local_index;
        CHECK_RESULT(ReadIndex(&local_index, "local.get local index"));
        CALLBACK(OnLocalGetExpr, local_index);
        CALLBACK(OnOpcodeIndex, local_index);
        break;
      }

      case Opcode::GlobalSet: {
        Index global_index;
        CHECK_RESULT(ReadIndex(&global_index, "global.set global index"));
        CALLBACK(OnGlobalSetExpr, global_index);
        CALLBACK(OnOpcodeIndex, global_index);
        break;
      }

      case Opcode::LocalSet: {
        Index local_index;
        CHECK_RESULT(ReadIndex(&local_index, "local.set local index"));
        CALLBACK(OnLocalSetExpr, local_index);
        CALLBACK(OnOpcodeIndex, local_index);
        break;
      }

      case Opcode::Call: {
        Index func_index;
        CHECK_RESULT(ReadIndex(&func_index, "call function index"));
        CALLBACK(OnCallExpr, func_index);
        CALLBACK(OnOpcodeIndex, func_index);
        break;
      }

      case Opcode::CallIndirect: {
        Index sig_index;
        CHECK_RESULT(ReadIndex(&sig_index, "call_indirect signature index"));
        Index table_index = 0;
        if (options_.features.reference_types_enabled()) {
          CHECK_RESULT(ReadIndex(&table_index, "call_indirect table index"));
        } else {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "call_indirect reserved"));
          ERROR_UNLESS(reserved == 0, "call_indirect reserved value must be 0");
        }
        CALLBACK(OnCallIndirectExpr, sig_index, table_index);
        CALLBACK(OnOpcodeUint32Uint32, sig_index, table_index);
        break;
      }

      case Opcode::ReturnCall: {
        Index func_index;
        CHECK_RESULT(ReadIndex(&func_index, "return_call"));
        CALLBACK(OnReturnCallExpr, func_index);
        CALLBACK(OnOpcodeIndex, func_index);
        break;
      }

      case Opcode::ReturnCallIndirect: {
        Index sig_index;
        CHECK_RESULT(ReadIndex(&sig_index, "return_call_indirect"));
        Index table_index = 0;
        if (options_.features.reference_types_enabled()) {
          CHECK_RESULT(
              ReadIndex(&table_index, "return_call_indirect table index"));
        } else {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "return_call_indirect reserved"));
          ERROR_UNLESS(reserved == 0,
                       "return_call_indirect reserved value must be 0");
        }
        CALLBACK(OnReturnCallIndirectExpr, sig_index, table_index);
        CALLBACK(OnOpcodeUint32Uint32, sig_index, table_index);
        break;
      }

      case Opcode::LocalTee: {
        Index local_index;
        CHECK_RESULT(ReadIndex(&local_index, "local.tee local index"));
        CALLBACK(OnLocalTeeExpr, local_index);
        CALLBACK(OnOpcodeIndex, local_index);
        break;
      }

      case Opcode::I32Load8S:
      case Opcode::I32Load8U:
      case Opcode::I32Load16S:
      case Opcode::I32Load16U:
      case Opcode::I64Load8S:
      case Opcode::I64Load8U:
      case Opcode::I64Load16S:
      case Opcode::I64Load16U:
      case Opcode::I64Load32S:
      case Opcode::I64Load32U:
      case Opcode::I32Load:
      case Opcode::I64Load:
      case Opcode::F32Load:
      case Opcode::F64Load:
      case Opcode::V128Load:
      case Opcode::V128Load8X8S:
      case Opcode::V128Load8X8U:
      case Opcode::V128Load16X4S:
      case Opcode::V128Load16X4U:
      case Opcode::V128Load32X2S:
      case Opcode::V128Load32X2U: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "load alignment""load memidx",
                                     "load offset"));
        CALLBACK(OnLoadExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::I32Store8:
      case Opcode::I32Store16:
      case Opcode::I64Store8:
      case Opcode::I64Store16:
      case Opcode::I64Store32:
      case Opcode::I32Store:
      case Opcode::I64Store:
      case Opcode::F32Store:
      case Opcode::F64Store:
      case Opcode::V128Store: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "store alignment""store memidx",
                                     "store offset"));
        CALLBACK(OnStoreExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::MemorySize: {
        Index memidx = 0;
        if (!options_.features.multi_memory_enabled()) {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "memory.size reserved"));
          ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0");
        } else {
          CHECK_RESULT(ReadMemidx(&memidx, "memory.size memidx"));
        }
        CALLBACK(OnMemorySizeExpr, memidx);
        CALLBACK(OnOpcodeUint32, memidx);
        break;
      }

      case Opcode::MemoryGrow: {
        Index memidx = 0;
        if (!options_.features.multi_memory_enabled()) {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved"));
          ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0");
        } else {
          CHECK_RESULT(ReadMemidx(&memidx, "memory.grow memidx"));
        }
        CALLBACK(OnMemoryGrowExpr, memidx);
        CALLBACK(OnOpcodeUint32, memidx);
        break;
      }

      case Opcode::I32Add:
      case Opcode::I32Sub:
      case Opcode::I32Mul:
      case Opcode::I32DivS:
      case Opcode::I32DivU:
      case Opcode::I32RemS:
      case Opcode::I32RemU:
      case Opcode::I32And:
      case Opcode::I32Or:
      case Opcode::I32Xor:
      case Opcode::I32Shl:
      case Opcode::I32ShrU:
      case Opcode::I32ShrS:
      case Opcode::I32Rotr:
      case Opcode::I32Rotl:
      case Opcode::I64Add:
      case Opcode::I64Sub:
      case Opcode::I64Mul:
      case Opcode::I64DivS:
      case Opcode::I64DivU:
      case Opcode::I64RemS:
      case Opcode::I64RemU:
      case Opcode::I64And:
      case Opcode::I64Or:
      case Opcode::I64Xor:
      case Opcode::I64Shl:
      case Opcode::I64ShrU:
      case Opcode::I64ShrS:
      case Opcode::I64Rotr:
      case Opcode::I64Rotl:
      case Opcode::F32Add:
      case Opcode::F32Sub:
      case Opcode::F32Mul:
      case Opcode::F32Div:
      case Opcode::F32Min:
      case Opcode::F32Max:
      case Opcode::F32Copysign:
      case Opcode::F64Add:
      case Opcode::F64Sub:
      case Opcode::F64Mul:
      case Opcode::F64Div:
      case Opcode::F64Min:
      case Opcode::F64Max:
      case Opcode::F64Copysign:
      case Opcode::I8X16Add:
      case Opcode::I16X8Add:
      case Opcode::I32X4Add:
      case Opcode::I64X2Add:
      case Opcode::I8X16Sub:
      case Opcode::I16X8Sub:
      case Opcode::I32X4Sub:
      case Opcode::I64X2Sub:
      case Opcode::I16X8Mul:
      case Opcode::I32X4Mul:
      case Opcode::I64X2Mul:
      case Opcode::I8X16AddSatS:
      case Opcode::I8X16AddSatU:
      case Opcode::I16X8AddSatS:
      case Opcode::I16X8AddSatU:
      case Opcode::I8X16SubSatS:
      case Opcode::I8X16SubSatU:
      case Opcode::I16X8SubSatS:
      case Opcode::I16X8SubSatU:
      case Opcode::I8X16MinS:
      case Opcode::I16X8MinS:
      case Opcode::I32X4MinS:
      case Opcode::I8X16MinU:
      case Opcode::I16X8MinU:
      case Opcode::I32X4MinU:
      case Opcode::I8X16MaxS:
      case Opcode::I16X8MaxS:
      case Opcode::I32X4MaxS:
      case Opcode::I8X16MaxU:
      case Opcode::I16X8MaxU:
      case Opcode::I32X4MaxU:
      case Opcode::I8X16Shl:
      case Opcode::I16X8Shl:
      case Opcode::I32X4Shl:
      case Opcode::I64X2Shl:
      case Opcode::I8X16ShrS:
      case Opcode::I8X16ShrU:
      case Opcode::I16X8ShrS:
      case Opcode::I16X8ShrU:
      case Opcode::I32X4ShrS:
      case Opcode::I32X4ShrU:
      case Opcode::I64X2ShrS:
      case Opcode::I64X2ShrU:
      case Opcode::V128And:
      case Opcode::V128Or:
      case Opcode::V128Xor:
      case Opcode::F32X4Min:
      case Opcode::F32X4PMin:
      case Opcode::F64X2Min:
      case Opcode::F64X2PMin:
      case Opcode::F32X4Max:
      case Opcode::F32X4PMax:
      case Opcode::F64X2Max:
      case Opcode::F64X2PMax:
      case Opcode::F32X4Add:
      case Opcode::F64X2Add:
      case Opcode::F32X4Sub:
      case Opcode::F64X2Sub:
      case Opcode::F32X4Div:
      case Opcode::F64X2Div:
      case Opcode::F32X4Mul:
      case Opcode::F64X2Mul:
      case Opcode::I8X16Swizzle:
      case Opcode::I8X16NarrowI16X8S:
      case Opcode::I8X16NarrowI16X8U:
      case Opcode::I16X8NarrowI32X4S:
      case Opcode::I16X8NarrowI32X4U:
      case Opcode::V128Andnot:
      case Opcode::I8X16AvgrU:
      case Opcode::I16X8AvgrU:
      case Opcode::I16X8ExtmulLowI8X16S:
      case Opcode::I16X8ExtmulHighI8X16S:
      case Opcode::I16X8ExtmulLowI8X16U:
      case Opcode::I16X8ExtmulHighI8X16U:
      case Opcode::I32X4ExtmulLowI16X8S:
      case Opcode::I32X4ExtmulHighI16X8S:
      case Opcode::I32X4ExtmulLowI16X8U:
      case Opcode::I32X4ExtmulHighI16X8U:
      case Opcode::I64X2ExtmulLowI32X4S:
      case Opcode::I64X2ExtmulHighI32X4S:
      case Opcode::I64X2ExtmulLowI32X4U:
      case Opcode::I64X2ExtmulHighI32X4U:
      case Opcode::I16X8Q15mulrSatS:
      case Opcode::I32X4DotI16X8S:
      case Opcode::I8X16RelaxedSwizzle:
      case Opcode::F32X4RelaxedMin:
      case Opcode::F32X4RelaxedMax:
      case Opcode::F64X2RelaxedMin:
      case Opcode::F64X2RelaxedMax:
      case Opcode::I16X8RelaxedQ15mulrS:
      case Opcode::I16X8DotI8X16I7X16S:
        CALLBACK(OnBinaryExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::I32Eq:
      case Opcode::I32Ne:
      case Opcode::I32LtS:
      case Opcode::I32LeS:
      case Opcode::I32LtU:
      case Opcode::I32LeU:
      case Opcode::I32GtS:
      case Opcode::I32GeS:
      case Opcode::I32GtU:
      case Opcode::I32GeU:
      case Opcode::I64Eq:
      case Opcode::I64Ne:
      case Opcode::I64LtS:
      case Opcode::I64LeS:
      case Opcode::I64LtU:
      case Opcode::I64LeU:
      case Opcode::I64GtS:
      case Opcode::I64GeS:
      case Opcode::I64GtU:
      case Opcode::I64GeU:
      case Opcode::F32Eq:
      case Opcode::F32Ne:
      case Opcode::F32Lt:
      case Opcode::F32Le:
      case Opcode::F32Gt:
      case Opcode::F32Ge:
      case Opcode::F64Eq:
      case Opcode::F64Ne:
      case Opcode::F64Lt:
      case Opcode::F64Le:
      case Opcode::F64Gt:
      case Opcode::F64Ge:
      case Opcode::I8X16Eq:
      case Opcode::I16X8Eq:
      case Opcode::I32X4Eq:
      case Opcode::I64X2Eq:
      case Opcode::F32X4Eq:
      case Opcode::F64X2Eq:
      case Opcode::I8X16Ne:
      case Opcode::I16X8Ne:
      case Opcode::I32X4Ne:
      case Opcode::I64X2Ne:
      case Opcode::F32X4Ne:
      case Opcode::F64X2Ne:
      case Opcode::I8X16LtS:
      case Opcode::I8X16LtU:
      case Opcode::I16X8LtS:
      case Opcode::I16X8LtU:
      case Opcode::I32X4LtS:
      case Opcode::I32X4LtU:
      case Opcode::I64X2LtS:
      case Opcode::F32X4Lt:
      case Opcode::F64X2Lt:
      case Opcode::I8X16LeS:
      case Opcode::I8X16LeU:
      case Opcode::I16X8LeS:
      case Opcode::I16X8LeU:
      case Opcode::I32X4LeS:
      case Opcode::I32X4LeU:
      case Opcode::I64X2LeS:
      case Opcode::F32X4Le:
      case Opcode::F64X2Le:
      case Opcode::I8X16GtS:
      case Opcode::I8X16GtU:
      case Opcode::I16X8GtS:
      case Opcode::I16X8GtU:
      case Opcode::I32X4GtS:
      case Opcode::I32X4GtU:
      case Opcode::I64X2GtS:
      case Opcode::F32X4Gt:
      case Opcode::F64X2Gt:
      case Opcode::I8X16GeS:
      case Opcode::I8X16GeU:
      case Opcode::I16X8GeS:
      case Opcode::I16X8GeU:
      case Opcode::I32X4GeS:
      case Opcode::I32X4GeU:
      case Opcode::I64X2GeS:
      case Opcode::F32X4Ge:
      case Opcode::F64X2Ge:
        CALLBACK(OnCompareExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::I32Clz:
      case Opcode::I32Ctz:
      case Opcode::I32Popcnt:
      case Opcode::I64Clz:
      case Opcode::I64Ctz:
      case Opcode::I64Popcnt:
      case Opcode::F32Abs:
      case Opcode::F32Neg:
      case Opcode::F32Ceil:
      case Opcode::F32Floor:
      case Opcode::F32Trunc:
      case Opcode::F32Nearest:
      case Opcode::F32Sqrt:
      case Opcode::F64Abs:
      case Opcode::F64Neg:
      case Opcode::F64Ceil:
      case Opcode::F64Floor:
      case Opcode::F64Trunc:
      case Opcode::F64Nearest:
      case Opcode::F64Sqrt:
      case Opcode::I8X16Splat:
      case Opcode::I16X8Splat:
      case Opcode::I32X4Splat:
      case Opcode::I64X2Splat:
      case Opcode::F32X4Splat:
      case Opcode::F64X2Splat:
      case Opcode::I8X16Neg:
      case Opcode::I16X8Neg:
      case Opcode::I32X4Neg:
      case Opcode::I64X2Neg:
      case Opcode::V128Not:
      case Opcode::V128AnyTrue:
      case Opcode::I8X16Bitmask:
      case Opcode::I16X8Bitmask:
      case Opcode::I32X4Bitmask:
      case Opcode::I64X2Bitmask:
      case Opcode::I8X16AllTrue:
      case Opcode::I16X8AllTrue:
      case Opcode::I32X4AllTrue:
      case Opcode::I64X2AllTrue:
      case Opcode::F32X4Ceil:
      case Opcode::F64X2Ceil:
      case Opcode::F32X4Floor:
      case Opcode::F64X2Floor:
      case Opcode::F32X4Trunc:
      case Opcode::F64X2Trunc:
      case Opcode::F32X4Nearest:
      case Opcode::F64X2Nearest:
      case Opcode::F32X4Neg:
      case Opcode::F64X2Neg:
      case Opcode::F32X4Abs:
      case Opcode::F64X2Abs:
      case Opcode::F32X4Sqrt:
      case Opcode::F64X2Sqrt:
      case Opcode::I16X8ExtendLowI8X16S:
      case Opcode::I16X8ExtendHighI8X16S:
      case Opcode::I16X8ExtendLowI8X16U:
      case Opcode::I16X8ExtendHighI8X16U:
      case Opcode::I32X4ExtendLowI16X8S:
      case Opcode::I32X4ExtendHighI16X8S:
      case Opcode::I32X4ExtendLowI16X8U:
      case Opcode::I32X4ExtendHighI16X8U:
      case Opcode::I64X2ExtendLowI32X4S:
      case Opcode::I64X2ExtendHighI32X4S:
      case Opcode::I64X2ExtendLowI32X4U:
      case Opcode::I64X2ExtendHighI32X4U:
      case Opcode::I8X16Abs:
      case Opcode::I16X8Abs:
      case Opcode::I32X4Abs:
      case Opcode::I64X2Abs:
      case Opcode::I8X16Popcnt:
      case Opcode::I16X8ExtaddPairwiseI8X16S:
      case Opcode::I16X8ExtaddPairwiseI8X16U:
      case Opcode::I32X4ExtaddPairwiseI16X8S:
      case Opcode::I32X4ExtaddPairwiseI16X8U:
      case Opcode::I32X4RelaxedTruncF32X4S:
      case Opcode::I32X4RelaxedTruncF32X4U:
      case Opcode::I32X4RelaxedTruncF64X2SZero:
      case Opcode::I32X4RelaxedTruncF64X2UZero:
        CALLBACK(OnUnaryExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::V128BitSelect:
      case Opcode::F32X4RelaxedMadd:
      case Opcode::F32X4RelaxedNmadd:
      case Opcode::F64X2RelaxedMadd:
      case Opcode::F64X2RelaxedNmadd:
      case Opcode::I8X16RelaxedLaneSelect:
      case Opcode::I16X8RelaxedLaneSelect:
      case Opcode::I32X4RelaxedLaneSelect:
      case Opcode::I64X2RelaxedLaneSelect:
      case Opcode::I32X4DotI8X16I7X16AddS:
        CALLBACK(OnTernaryExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::I8X16ExtractLaneS:
      case Opcode::I8X16ExtractLaneU:
      case Opcode::I16X8ExtractLaneS:
      case Opcode::I16X8ExtractLaneU:
      case Opcode::I32X4ExtractLane:
      case Opcode::I64X2ExtractLane:
      case Opcode::F32X4ExtractLane:
      case Opcode::F64X2ExtractLane:
      case Opcode::I8X16ReplaceLane:
      case Opcode::I16X8ReplaceLane:
      case Opcode::I32X4ReplaceLane:
      case Opcode::I64X2ReplaceLane:
      case Opcode::F32X4ReplaceLane:
      case Opcode::F64X2ReplaceLane: {
        uint8_t lane_val;
        CHECK_RESULT(ReadU8(&lane_val, "Lane idx"));
        CALLBACK(OnSimdLaneOpExpr, opcode, lane_val);
        CALLBACK(OnOpcodeUint64, lane_val);
        break;
      }

      case Opcode::I8X16Shuffle: {
        v128 value;
        CHECK_RESULT(ReadV128(&value, "Lane idx [16]"));
        CALLBACK(OnSimdShuffleOpExpr, opcode, value);
        CALLBACK(OnOpcodeV128, value);
        break;
      }

      case Opcode::V128Load8Splat:
      case Opcode::V128Load16Splat:
      case Opcode::V128Load32Splat:
      case Opcode::V128Load64Splat: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "load alignment""load memidx",
                                     "load offset"));
        CALLBACK(OnLoadSplatExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }
      case Opcode::V128Load8Lane:
      case Opcode::V128Load16Lane:
      case Opcode::V128Load32Lane:
      case Opcode::V128Load64Lane: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        uint8_t lane_val;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "load alignment""load memidx",
                                     "load offset", &lane_val));
        CALLBACK(OnSimdLoadLaneExpr, opcode, memidx, alignment_log2, offset,
                 lane_val);
        CHECK_RESULT(
            CallbackMemLocation(&alignment_log2, &memidx, &offset, &lane_val));
        break;
      }
      case Opcode::V128Store8Lane:
      case Opcode::V128Store16Lane:
      case Opcode::V128Store32Lane:
      case Opcode::V128Store64Lane: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        uint8_t lane_val;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "store alignment""store memidx",
                                     "store offset", &lane_val));
        CALLBACK(OnSimdStoreLaneExpr, opcode, memidx, alignment_log2, offset,
                 lane_val);
        CHECK_RESULT(
            CallbackMemLocation(&alignment_log2, &memidx, &offset, &lane_val));
        break;
      }
      case Opcode::V128Load32Zero:
      case Opcode::V128Load64Zero: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "load alignment""load memidx",
                                     "load offset"));
        CALLBACK(OnLoadZeroExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }
      case Opcode::I32TruncF32S:
      case Opcode::I32TruncF64S:
      case Opcode::I32TruncF32U:
      case Opcode::I32TruncF64U:
      case Opcode::I32WrapI64:
      case Opcode::I64TruncF32S:
      case Opcode::I64TruncF64S:
      case Opcode::I64TruncF32U:
      case Opcode::I64TruncF64U:
      case Opcode::I64ExtendI32S:
      case Opcode::I64ExtendI32U:
      case Opcode::F32ConvertI32S:
      case Opcode::F32ConvertI32U:
      case Opcode::F32ConvertI64S:
      case Opcode::F32ConvertI64U:
      case Opcode::F32DemoteF64:
      case Opcode::F32ReinterpretI32:
      case Opcode::F64ConvertI32S:
      case Opcode::F64ConvertI32U:
      case Opcode::F64ConvertI64S:
      case Opcode::F64ConvertI64U:
      case Opcode::F64PromoteF32:
      case Opcode::F64ReinterpretI64:
      case Opcode::I32ReinterpretF32:
      case Opcode::I64ReinterpretF64:
      case Opcode::I32Eqz:
      case Opcode::I64Eqz:
      case Opcode::F32X4ConvertI32X4S:
      case Opcode::F32X4ConvertI32X4U:
      case Opcode::I32X4TruncSatF32X4S:
      case Opcode::I32X4TruncSatF32X4U:
      case Opcode::F32X4DemoteF64X2Zero:
      case Opcode::F64X2PromoteLowF32X4:
      case Opcode::I32X4TruncSatF64X2SZero:
      case Opcode::I32X4TruncSatF64X2UZero:
      case Opcode::F64X2ConvertLowI32X4S:
      case Opcode::F64X2ConvertLowI32X4U:
        CALLBACK(OnConvertExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::Try: {
        nested_blocks.push(opcode);
        Type sig_type;
        CHECK_RESULT(ReadType(&sig_type, "try signature type"));
        ERROR_UNLESS(IsBlockType(sig_type),
                     "expected valid block signature type");
        CALLBACK(OnTryExpr, sig_type);
        CALLBACK(OnOpcodeBlockSig, sig_type);
        break;
      }

      case Opcode::Catch: {
        Index index;
        CHECK_RESULT(ReadIndex(&index, "tag index"));
        CALLBACK(OnCatchExpr, index);
        CALLBACK(OnOpcodeIndex, index);
        break;
      }

      case Opcode::CatchAll: {
        CALLBACK(OnCatchAllExpr);
        CALLBACK(OnOpcodeBare);
        break;
      }

      case Opcode::Delegate: {
        ERROR_IF(nested_blocks.empty() || (nested_blocks.top() != Opcode::Try),
                 "delegate outside try block");
        nested_blocks.pop();
        Index index;
        CHECK_RESULT(ReadIndex(&index, "depth"));
        CALLBACK(OnDelegateExpr, index);
        CALLBACK(OnOpcodeIndex, index);
        break;
      }

      case Opcode::Rethrow: {
        Index depth;
        CHECK_RESULT(ReadIndex(&depth, "catch depth"));
        CALLBACK(OnRethrowExpr, depth);
        CALLBACK(OnOpcodeIndex, depth);
        break;
      }

      case Opcode::Throw: {
        Index index;
        CHECK_RESULT(ReadIndex(&index, "tag index"));
        CALLBACK(OnThrowExpr, index);
        CALLBACK(OnOpcodeIndex, index);
        break;
      }

      case Opcode::I32Extend8S:
      case Opcode::I32Extend16S:
      case Opcode::I64Extend8S:
      case Opcode::I64Extend16S:
      case Opcode::I64Extend32S:
        CALLBACK(OnUnaryExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::I32TruncSatF32S:
      case Opcode::I32TruncSatF32U:
      case Opcode::I32TruncSatF64S:
      case Opcode::I32TruncSatF64U:
      case Opcode::I64TruncSatF32S:
      case Opcode::I64TruncSatF32U:
      case Opcode::I64TruncSatF64S:
      case Opcode::I64TruncSatF64U:
        CALLBACK(OnConvertExpr, opcode);
        CALLBACK0(OnOpcodeBare);
        break;

      case Opcode::MemoryAtomicNotify: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "notify alignment""notify memidx",
                                     "notify offset"));
        CALLBACK(OnAtomicNotifyExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::MemoryAtomicWait32:
      case Opcode::MemoryAtomicWait64: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "wait alignment""wait memidx",
                                     "wait offset"));
        CALLBACK(OnAtomicWaitExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::AtomicFence: {
        uint8_t consistency_model;
        CHECK_RESULT(ReadU8(&consistency_model, "consistency model"));
        ERROR_UNLESS(consistency_model == 0,
                     "atomic.fence consistency model must be 0");
        CALLBACK(OnAtomicFenceExpr, consistency_model);
        CALLBACK(OnOpcodeUint32, consistency_model);
        break;
      }

      case Opcode::I32AtomicLoad8U:
      case Opcode::I32AtomicLoad16U:
      case Opcode::I64AtomicLoad8U:
      case Opcode::I64AtomicLoad16U:
      case Opcode::I64AtomicLoad32U:
      case Opcode::I32AtomicLoad:
      case Opcode::I64AtomicLoad: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "load alignment""load memidx",
                                     "load offset"));
        CALLBACK(OnAtomicLoadExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::I32AtomicStore8:
      case Opcode::I32AtomicStore16:
      case Opcode::I64AtomicStore8:
      case Opcode::I64AtomicStore16:
      case Opcode::I64AtomicStore32:
      case Opcode::I32AtomicStore:
      case Opcode::I64AtomicStore: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "store alignment""store memidx",
                                     "store offset"));
        CALLBACK(OnAtomicStoreExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::I32AtomicRmwAdd:
      case Opcode::I64AtomicRmwAdd:
      case Opcode::I32AtomicRmw8AddU:
      case Opcode::I32AtomicRmw16AddU:
      case Opcode::I64AtomicRmw8AddU:
      case Opcode::I64AtomicRmw16AddU:
      case Opcode::I64AtomicRmw32AddU:
      case Opcode::I32AtomicRmwSub:
      case Opcode::I64AtomicRmwSub:
      case Opcode::I32AtomicRmw8SubU:
      case Opcode::I32AtomicRmw16SubU:
      case Opcode::I64AtomicRmw8SubU:
      case Opcode::I64AtomicRmw16SubU:
      case Opcode::I64AtomicRmw32SubU:
      case Opcode::I32AtomicRmwAnd:
      case Opcode::I64AtomicRmwAnd:
      case Opcode::I32AtomicRmw8AndU:
      case Opcode::I32AtomicRmw16AndU:
      case Opcode::I64AtomicRmw8AndU:
      case Opcode::I64AtomicRmw16AndU:
      case Opcode::I64AtomicRmw32AndU:
      case Opcode::I32AtomicRmwOr:
      case Opcode::I64AtomicRmwOr:
      case Opcode::I32AtomicRmw8OrU:
      case Opcode::I32AtomicRmw16OrU:
      case Opcode::I64AtomicRmw8OrU:
      case Opcode::I64AtomicRmw16OrU:
      case Opcode::I64AtomicRmw32OrU:
      case Opcode::I32AtomicRmwXor:
      case Opcode::I64AtomicRmwXor:
      case Opcode::I32AtomicRmw8XorU:
      case Opcode::I32AtomicRmw16XorU:
      case Opcode::I64AtomicRmw8XorU:
      case Opcode::I64AtomicRmw16XorU:
      case Opcode::I64AtomicRmw32XorU:
      case Opcode::I32AtomicRmwXchg:
      case Opcode::I64AtomicRmwXchg:
      case Opcode::I32AtomicRmw8XchgU:
      case Opcode::I32AtomicRmw16XchgU:
      case Opcode::I64AtomicRmw8XchgU:
      case Opcode::I64AtomicRmw16XchgU:
      case Opcode::I64AtomicRmw32XchgU: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "memory alignment""memory memidx",
                                     "memory offset"));
        CALLBACK(OnAtomicRmwExpr, opcode, memidx, alignment_log2, offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::I32AtomicRmwCmpxchg:
      case Opcode::I64AtomicRmwCmpxchg:
      case Opcode::I32AtomicRmw8CmpxchgU:
      case Opcode::I32AtomicRmw16CmpxchgU:
      case Opcode::I64AtomicRmw8CmpxchgU:
      case Opcode::I64AtomicRmw16CmpxchgU:
      case Opcode::I64AtomicRmw32CmpxchgU: {
        Address alignment_log2;
        Index memidx;
        Address offset;
        CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset,
                                     "memory alignment""memory memidx",
                                     "memory offset"));
        CALLBACK(OnAtomicRmwCmpxchgExpr, opcode, memidx, alignment_log2,
                 offset);
        CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset));
        break;
      }

      case Opcode::TableInit: {
        Index segment;
        CHECK_RESULT(ReadIndex(&segment, "elem segment index"));
        Index table_index;
        CHECK_RESULT(ReadIndex(&table_index, "reserved table index"));
        CALLBACK(OnTableInitExpr, segment, table_index);
        CALLBACK(OnOpcodeUint32Uint32, segment, table_index);
        break;
      }

      case Opcode::MemoryInit: {
        Index segment;
        ERROR_IF(data_count_ == kInvalidIndex,
                 "memory.init requires data count section");
        CHECK_RESULT(ReadIndex(&segment, "elem segment index"));
        Index memidx = 0;
        if (!options_.features.multi_memory_enabled()) {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
          ERROR_UNLESS(reserved == 0, "reserved value must be 0");
        } else {
          CHECK_RESULT(ReadMemidx(&memidx, "memory.init memidx"));
        }
        CALLBACK(OnMemoryInitExpr, segment, memidx);
        CALLBACK(OnOpcodeUint32Uint32, segment, memidx);
        break;
      }

      case Opcode::DataDrop:
        ERROR_IF(data_count_ == kInvalidIndex,
                 "data.drop requires data count section");
        [[fallthrough]];
      case Opcode::ElemDrop: {
        Index segment;
        CHECK_RESULT(ReadIndex(&segment, "segment index"));
        if (opcode == Opcode::DataDrop) {
          CALLBACK(OnDataDropExpr, segment);
        } else {
          CALLBACK(OnElemDropExpr, segment);
        }
        CALLBACK(OnOpcodeUint32, segment);
        break;
      }

      case Opcode::MemoryFill: {
        Index memidx = 0;
        if (!options_.features.multi_memory_enabled()) {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "memory.fill reserved"));
          ERROR_UNLESS(reserved == 0, "memory.fill reserved value must be 0");
        } else {
          CHECK_RESULT(ReadMemidx(&memidx, "memory.fill memidx"));
        }
        CALLBACK(OnMemoryFillExpr, memidx);
        CALLBACK(OnOpcodeUint32, memidx);
        break;
      }

      case Opcode::MemoryCopy: {
        Index destmemidx = 0;
        Index srcmemidx = 0;
        if (!options_.features.multi_memory_enabled()) {
          uint8_t reserved;
          CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
          ERROR_UNLESS(reserved == 0, "reserved value must be 0");
          CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
          ERROR_UNLESS(reserved == 0, "reserved value must be 0");
        } else {
          CHECK_RESULT(ReadMemidx(&destmemidx, "memory.copy destmemindex"));
          CHECK_RESULT(ReadMemidx(&srcmemidx, "memory.copy srcmemidx"));
        }
        CALLBACK(OnMemoryCopyExpr, destmemidx, srcmemidx);
        CALLBACK(OnOpcodeUint32Uint32, destmemidx, srcmemidx);
        break;
      }

      case Opcode::TableCopy: {
        Index table_dst;
        Index table_src;
        CHECK_RESULT(ReadIndex(&table_dst, "reserved table index"));
        CHECK_RESULT(ReadIndex(&table_src, "table src"));
        CALLBACK(OnTableCopyExpr, table_dst, table_src);
        CALLBACK(OnOpcodeUint32Uint32, table_dst, table_src);
        break;
      }

      case Opcode::TableGet: {
        Index table;
        CHECK_RESULT(ReadIndex(&table, "table index"));
        CALLBACK(OnTableGetExpr, table);
        CALLBACK(OnOpcodeUint32, table);
        break;
      }

      case Opcode::TableSet: {
        Index table;
        CHECK_RESULT(ReadIndex(&table, "table index"));
        CALLBACK(OnTableSetExpr, table);
        CALLBACK(OnOpcodeUint32, table);
        break;
      }

      case Opcode::TableGrow: {
        Index table;
        CHECK_RESULT(ReadIndex(&table, "table index"));
        CALLBACK(OnTableGrowExpr, table);
        CALLBACK(OnOpcodeUint32, table);
        break;
      }

      case Opcode::TableSize: {
        Index table;
        CHECK_RESULT(ReadIndex(&table, "table index"));
        CALLBACK(OnTableSizeExpr, table);
        CALLBACK(OnOpcodeUint32, table);
        break;
      }

      case Opcode::TableFill: {
        Index table;
        CHECK_RESULT(ReadIndex(&table, "table index"));
        CALLBACK(OnTableFillExpr, table);
        CALLBACK(OnOpcodeUint32, table);
        break;
      }

      case Opcode::RefFunc: {
        Index func;
        CHECK_RESULT(ReadIndex(&func, "func index"));
        CALLBACK(OnRefFuncExpr, func);
        CALLBACK(OnOpcodeUint32, func);
        break;
      }

      case Opcode::RefNull: {
        Type type;
        CHECK_RESULT(ReadRefType(&type, "ref.null type"));
        CALLBACK(OnRefNullExpr, type);
        CALLBACK(OnOpcodeType, type);
        break;
      }

      case Opcode::RefIsNull:
        CALLBACK(OnRefIsNullExpr);
        CALLBACK(OnOpcodeBare);
        break;

      case Opcode::CallRef:
        CALLBACK(OnCallRefExpr);
        CALLBACK(OnOpcodeBare);
        break;

      default:
        return ReportUnexpectedOpcode(opcode);
    }
  }

  PrintError("%s must end with END opcode", context);
  return Result::Error;
}

Result BinaryReader::ReadNameSection(Offset section_size) {
  CALLBACK(BeginNamesSection, section_size);
  Index i = 0;
  uint32_t previous_subsection_type = 0;
  while (state_.offset < read_end_) {
    uint32_t name_type;
    Offset subsection_size;
    CHECK_RESULT(ReadU32Leb128(&name_type, "name type"));
    if (i != 0) {
      ERROR_UNLESS(name_type != previous_subsection_type,
                   "duplicate sub-section");
      ERROR_UNLESS(name_type >= previous_subsection_type,
                   "out-of-order sub-section");
    }
    previous_subsection_type = name_type;
    CHECK_RESULT(ReadOffset(&subsection_size, "subsection size"));
    size_t subsection_end = state_.offset + subsection_size;
    ERROR_UNLESS(subsection_end <= read_end_,
                 "invalid sub-section size: extends past end");
    ReadEndRestoreGuard guard(this);
    read_end_ = subsection_end;

    NameSectionSubsection type = static_cast<NameSectionSubsection>(name_type);
    if (type <= NameSectionSubsection::Last) {
      CALLBACK(OnNameSubsection, i, type, subsection_size);
    }

    switch (type) {
      case NameSectionSubsection::Module:
        CALLBACK(OnModuleNameSubsection, i, name_type, subsection_size);
        if (subsection_size) {
          std::string_view name;
          CHECK_RESULT(ReadStr(&name, "module name"));
          CALLBACK(OnModuleName, name);
        }
        break;
--> --------------------

--> maximum size reached

--> --------------------

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

¤ Dauer der Verarbeitung: 0.28 Sekunden  ¤

*© 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.