Revision control
Copy as Markdown
Other Tools
//! Conversions from `wasmparser` to `wasm-encoder` to [`Reencode`] parsed wasm.
//!
//! The [`RoundtripReencoder`] allows encoding identical wasm to the parsed
//! input.
use crate::CoreTypeEncoder;
use std::convert::Infallible;
#[cfg(feature = "component-model")]
mod component;
#[cfg(feature = "component-model")]
pub use self::component::*;
#[allow(missing_docs)] // FIXME
pub trait Reencode {
type Error;
fn data_index(&mut self, data: u32) -> u32 {
utils::data_index(self, data)
}
fn element_index(&mut self, element: u32) -> u32 {
utils::element_index(self, element)
}
fn function_index(&mut self, func: u32) -> u32 {
utils::function_index(self, func)
}
fn global_index(&mut self, global: u32) -> u32 {
utils::global_index(self, global)
}
fn memory_index(&mut self, memory: u32) -> u32 {
utils::memory_index(self, memory)
}
fn table_index(&mut self, table: u32) -> u32 {
utils::table_index(self, table)
}
fn tag_index(&mut self, tag: u32) -> u32 {
utils::tag_index(self, tag)
}
fn type_index(&mut self, ty: u32) -> u32 {
utils::type_index(self, ty)
}
fn type_index_unpacked(
&mut self,
ty: wasmparser::UnpackedIndex,
) -> Result<u32, Error<Self::Error>> {
utils::type_index_unpacked(self, ty)
}
fn external_index(&mut self, kind: wasmparser::ExternalKind, index: u32) -> u32 {
match kind {
wasmparser::ExternalKind::Func => self.function_index(index),
wasmparser::ExternalKind::Table => self.table_index(index),
wasmparser::ExternalKind::Memory => self.memory_index(index),
wasmparser::ExternalKind::Global => self.global_index(index),
wasmparser::ExternalKind::Tag => self.tag_index(index),
}
}
fn abstract_heap_type(
&mut self,
value: wasmparser::AbstractHeapType,
) -> crate::AbstractHeapType {
utils::abstract_heap_type(self, value)
}
fn array_type(
&mut self,
array_ty: wasmparser::ArrayType,
) -> Result<crate::ArrayType, Error<Self::Error>> {
utils::array_type(self, array_ty)
}
fn block_type(
&mut self,
arg: wasmparser::BlockType,
) -> Result<crate::BlockType, Error<Self::Error>> {
utils::block_type(self, arg)
}
fn const_expr(
&mut self,
const_expr: wasmparser::ConstExpr,
) -> Result<crate::ConstExpr, Error<Self::Error>> {
utils::const_expr(self, const_expr)
}
fn catch(&mut self, arg: wasmparser::Catch) -> crate::Catch {
utils::catch(self, arg)
}
fn composite_type(
&mut self,
composite_ty: wasmparser::CompositeType,
) -> Result<crate::CompositeType, Error<Self::Error>> {
utils::composite_type(self, composite_ty)
}
fn entity_type(
&mut self,
type_ref: wasmparser::TypeRef,
) -> Result<crate::EntityType, Error<Self::Error>> {
utils::entity_type(self, type_ref)
}
fn export_kind(&mut self, external_kind: wasmparser::ExternalKind) -> crate::ExportKind {
utils::export_kind(self, external_kind)
}
fn field_type(
&mut self,
field_ty: wasmparser::FieldType,
) -> Result<crate::FieldType, Error<Self::Error>> {
utils::field_type(self, field_ty)
}
fn func_type(
&mut self,
func_ty: wasmparser::FuncType,
) -> Result<crate::FuncType, Error<Self::Error>> {
utils::func_type(self, func_ty)
}
fn cont_type(
&mut self,
cont_ty: wasmparser::ContType,
) -> Result<crate::ContType, Error<Self::Error>> {
utils::cont_type(self, cont_ty)
}
fn global_type(
&mut self,
global_ty: wasmparser::GlobalType,
) -> Result<crate::GlobalType, Error<Self::Error>> {
utils::global_type(self, global_ty)
}
fn handle(&mut self, on: wasmparser::Handle) -> crate::Handle {
utils::handle(self, on)
}
fn heap_type(
&mut self,
heap_type: wasmparser::HeapType,
) -> Result<crate::HeapType, Error<Self::Error>> {
utils::heap_type(self, heap_type)
}
fn instruction<'a>(
&mut self,
arg: wasmparser::Operator<'a>,
) -> Result<crate::Instruction<'a>, Error<Self::Error>> {
utils::instruction(self, arg)
}
fn memory_type(&mut self, memory_ty: wasmparser::MemoryType) -> crate::MemoryType {
utils::memory_type(self, memory_ty)
}
fn mem_arg(&mut self, arg: wasmparser::MemArg) -> crate::MemArg {
utils::mem_arg(self, arg)
}
fn ordering(&mut self, arg: wasmparser::Ordering) -> crate::Ordering {
utils::ordering(self, arg)
}
fn ref_type(
&mut self,
ref_type: wasmparser::RefType,
) -> Result<crate::RefType, Error<Self::Error>> {
utils::ref_type(self, ref_type)
}
fn storage_type(
&mut self,
storage_ty: wasmparser::StorageType,
) -> Result<crate::StorageType, Error<Self::Error>> {
utils::storage_type(self, storage_ty)
}
fn struct_type(
&mut self,
struct_ty: wasmparser::StructType,
) -> Result<crate::StructType, Error<Self::Error>> {
utils::struct_type(self, struct_ty)
}
fn sub_type(
&mut self,
sub_ty: wasmparser::SubType,
) -> Result<crate::SubType, Error<Self::Error>> {
utils::sub_type(self, sub_ty)
}
fn table_type(
&mut self,
table_ty: wasmparser::TableType,
) -> Result<crate::TableType, Error<Self::Error>> {
utils::table_type(self, table_ty)
}
fn tag_kind(&mut self, kind: wasmparser::TagKind) -> crate::TagKind {
utils::tag_kind(self, kind)
}
fn tag_type(&mut self, tag_ty: wasmparser::TagType) -> crate::TagType {
utils::tag_type(self, tag_ty)
}
fn val_type(
&mut self,
val_ty: wasmparser::ValType,
) -> Result<crate::ValType, Error<Self::Error>> {
utils::val_type(self, val_ty)
}
/// Parses the input `section` given from the `wasmparser` crate and
/// adds the custom section to the `module`.
fn parse_custom_section(
&mut self,
module: &mut crate::Module,
section: wasmparser::CustomSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_custom_section(self, module, section)
}
/// Converts the input `section` given from the `wasmparser` crate into an
/// encoded custom section.
fn custom_section<'a>(
&mut self,
section: wasmparser::CustomSectionReader<'a>,
) -> crate::CustomSection<'a> {
utils::custom_section(self, section)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the code to the `code` section.
fn parse_code_section(
&mut self,
code: &mut crate::CodeSection,
section: wasmparser::CodeSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_code_section(self, code, section)
}
/// Parses a single [`wasmparser::FunctionBody`] and adds it to the `code` section.
fn parse_function_body(
&mut self,
code: &mut crate::CodeSection,
func: wasmparser::FunctionBody<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_function_body(self, code, func)
}
/// Create a new [`crate::Function`] by parsing the locals declarations from the
/// provided [`wasmparser::FunctionBody`].
fn new_function_with_parsed_locals(
&mut self,
func: &wasmparser::FunctionBody<'_>,
) -> Result<crate::Function, Error<Self::Error>> {
utils::new_function_with_parsed_locals(self, func)
}
/// Parses a single instruction from `reader` and adds it to `function`.
fn parse_instruction<'a>(
&mut self,
reader: &mut wasmparser::OperatorsReader<'a>,
) -> Result<crate::Instruction<'a>, Error<Self::Error>> {
utils::parse_instruction(self, reader)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the data to the `data` section.
fn parse_data_section(
&mut self,
data: &mut crate::DataSection,
section: wasmparser::DataSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_data_section(self, data, section)
}
/// Parses a single [`wasmparser::Data`] and adds it to the `data` section.
fn parse_data(
&mut self,
data: &mut crate::DataSection,
datum: wasmparser::Data<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_data(self, data, datum)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the elements to the `element` section.
fn parse_element_section(
&mut self,
elements: &mut crate::ElementSection,
section: wasmparser::ElementSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_element_section(self, elements, section)
}
/// Parses the single [`wasmparser::Element`] provided and adds it to the
/// `element` section.
fn parse_element(
&mut self,
elements: &mut crate::ElementSection,
element: wasmparser::Element<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_element(self, elements, element)
}
fn element_items<'a>(
&mut self,
items: wasmparser::ElementItems<'a>,
) -> Result<crate::Elements<'a>, Error<Self::Error>> {
utils::element_items(self, items)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the exports to the `exports` section.
fn parse_export_section(
&mut self,
exports: &mut crate::ExportSection,
section: wasmparser::ExportSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_export_section(self, exports, section)
}
/// Parses the single [`wasmparser::Export`] provided and adds it to the
/// `exports` section.
fn parse_export(&mut self, exports: &mut crate::ExportSection, export: wasmparser::Export<'_>) {
utils::parse_export(self, exports, export)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the functions to the `functions` section.
fn parse_function_section(
&mut self,
functions: &mut crate::FunctionSection,
section: wasmparser::FunctionSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_function_section(self, functions, section)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the globals to the `globals` section.
fn parse_global_section(
&mut self,
globals: &mut crate::GlobalSection,
section: wasmparser::GlobalSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_global_section(self, globals, section)
}
/// Parses the single [`wasmparser::Global`] provided and adds it to the
/// `globals` section.
fn parse_global(
&mut self,
globals: &mut crate::GlobalSection,
global: wasmparser::Global<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_global(self, globals, global)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the imports to the `import` section.
fn parse_import_section(
&mut self,
imports: &mut crate::ImportSection,
section: wasmparser::ImportSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_import_section(self, imports, section)
}
/// Parses the single [`wasmparser::Import`] provided and adds it to the
/// `import` section.
fn parse_import(
&mut self,
imports: &mut crate::ImportSection,
import: wasmparser::Import<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_import(self, imports, import)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the memories to the `memories` section.
fn parse_memory_section(
&mut self,
memories: &mut crate::MemorySection,
section: wasmparser::MemorySectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_memory_section(self, memories, section)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the tables to the `tables` section.
fn parse_table_section(
&mut self,
tables: &mut crate::TableSection,
section: wasmparser::TableSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_table_section(self, tables, section)
}
/// Parses a single [`wasmparser::Table`] and adds it to the `tables` section.
fn parse_table(
&mut self,
tables: &mut crate::TableSection,
table: wasmparser::Table<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_table(self, tables, table)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the tags to the `tags` section.
fn parse_tag_section(
&mut self,
tags: &mut crate::TagSection,
section: wasmparser::TagSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_tag_section(self, tags, section)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the types to the `types` section.
fn parse_type_section(
&mut self,
types: &mut crate::TypeSection,
section: wasmparser::TypeSectionReader<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_type_section(self, types, section)
}
/// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section.
fn parse_recursive_type_group(
&mut self,
encoder: CoreTypeEncoder,
rec_group: wasmparser::RecGroup,
) -> Result<(), Error<Self::Error>> {
utils::parse_recursive_type_group(self, encoder, rec_group)
}
fn parse_unknown_section(
&mut self,
module: &mut crate::Module,
id: u8,
contents: &[u8],
) -> Result<(), Error<Self::Error>> {
utils::parse_unknown_section(self, module, id, contents)
}
/// A hook method that is called inside [`Reencode::parse_core_module`]
/// before and after every non-custom core wasm section.
///
/// This method can be used to insert new custom sections in between those
/// sections, or to detect when a non-custom section is missing and insert
/// it in the [proper order].
///
/// The `after` parameter is `None` iff the hook is called before the first
/// non-custom section, and `Some(s)` afterwards, where `s` is the
/// [`SectionId`] of the previous non-custom section.
///
/// The `before` parameter is `None` iff the hook is called after the last
/// non-custom section, and `Some(s)` beforehand, where `s` is the
/// [`SectionId`] of the following non-custom section.
///
/// [`SectionId`]: crate::SectionId
fn intersperse_section_hook(
&mut self,
module: &mut crate::Module,
after: Option<crate::SectionId>,
before: Option<crate::SectionId>,
) -> Result<(), Error<Self::Error>> {
utils::intersperse_section_hook(self, module, after, before)
}
fn parse_core_module(
&mut self,
module: &mut crate::Module,
parser: wasmparser::Parser,
data: &[u8],
) -> Result<(), Error<Self::Error>> {
utils::parse_core_module(self, module, parser, data)
}
fn custom_name_section(
&mut self,
section: wasmparser::NameSectionReader<'_>,
) -> Result<crate::NameSection, Error<Self::Error>> {
utils::custom_name_section(self, section)
}
fn parse_custom_name_subsection(
&mut self,
names: &mut crate::NameSection,
section: wasmparser::Name<'_>,
) -> Result<(), Error<Self::Error>> {
utils::parse_custom_name_subsection(self, names, section)
}
fn data_count(&mut self, count: u32) -> u32 {
count
}
fn start_section(&mut self, start: u32) -> u32 {
self.function_index(start)
}
}
/// An error when re-encoding from `wasmparser` to `wasm-encoder`.
#[derive(Debug)]
pub enum Error<E = Infallible> {
/// There was a type reference that was canonicalized and no longer
/// references an index into a module's types space, so we cannot encode it
/// into a Wasm binary again.
CanonicalizedHeapTypeReference,
/// The const expression is invalid: not actually constant or something like
/// that.
InvalidConstExpr,
/// The code section size listed was not valid for the wasm binary provided.
InvalidCodeSectionSize,
/// There was a section that does not belong into a core wasm module.
UnexpectedNonCoreModuleSection,
/// There was a section that does not belong into a compoennt module.
UnexpectedNonComponentSection,
/// A core type definition was found in a component that's not supported.
UnsupportedCoreTypeInComponent,
/// There was an error when parsing.
ParseError(wasmparser::BinaryReaderError),
/// There was a user-defined error when re-encoding.
UserError(E),
}
impl<E> From<wasmparser::BinaryReaderError> for Error<E> {
fn from(err: wasmparser::BinaryReaderError) -> Self {
Self::ParseError(err)
}
}
impl<E: std::fmt::Display> std::fmt::Display for Error<E> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::ParseError(_e) => {
write!(fmt, "There was an error when parsing")
}
Self::UserError(e) => write!(fmt, "{e}"),
Self::InvalidConstExpr => write!(fmt, "The const expression was invalid"),
Self::UnexpectedNonCoreModuleSection => write!(
fmt,
"There was a section that does not belong into a core wasm module"
),
Self::UnexpectedNonComponentSection => write!(
fmt,
"There was a section that does not belong into a component"
),
Self::CanonicalizedHeapTypeReference => write!(
fmt,
"There was a canonicalized heap type reference without type index information"
),
Self::UnsupportedCoreTypeInComponent => {
fmt.write_str("unsupported core type in a component")
}
Self::InvalidCodeSectionSize => fmt.write_str("invalid code section size"),
}
}
}
impl<E: 'static + std::error::Error> std::error::Error for Error<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::ParseError(e) => Some(e),
Self::UserError(e) => Some(e),
Self::InvalidConstExpr
| Self::CanonicalizedHeapTypeReference
| Self::UnexpectedNonCoreModuleSection
| Self::UnexpectedNonComponentSection
| Self::UnsupportedCoreTypeInComponent
| Self::InvalidCodeSectionSize => None,
}
}
}
/// Reencodes `wasmparser` into `wasm-encoder` so that the encoded wasm is
/// identical to the input and can be parsed and encoded again.
#[derive(Debug)]
pub struct RoundtripReencoder;
impl Reencode for RoundtripReencoder {
type Error = Infallible;
}
#[allow(missing_docs)] // FIXME
pub mod utils {
use super::{Error, Reencode};
use crate::{CoreTypeEncoder, Encode};
use std::ops::Range;
pub fn parse_core_module<T: ?Sized + Reencode>(
reencoder: &mut T,
module: &mut crate::Module,
parser: wasmparser::Parser,
data: &[u8],
) -> Result<(), Error<T::Error>> {
fn handle_intersperse_section_hook<T: ?Sized + Reencode>(
reencoder: &mut T,
module: &mut crate::Module,
last_section: &mut Option<crate::SectionId>,
next_section: Option<crate::SectionId>,
) -> Result<(), Error<T::Error>> {
let after = std::mem::replace(last_section, next_section);
let before = next_section;
reencoder.intersperse_section_hook(module, after, before)
}
// Convert from `range` to a byte range within `data` while
// accounting for various offsets. Then create a
// `CodeSectionReader` (which notably the payload does not
// give us here) and recurse with that. This means that
// users overridding `parse_code_section` always get that
// function called.
let orig_offset = parser.offset() as usize;
let get_original_section = |range: Range<usize>| {
data.get(range.start - orig_offset..range.end - orig_offset)
.ok_or(Error::InvalidCodeSectionSize)
};
let mut last_section = None;
for section in parser.parse_all(data) {
match section? {
wasmparser::Payload::Version {
encoding: wasmparser::Encoding::Module,
..
} => (),
wasmparser::Payload::Version { .. } => {
return Err(Error::UnexpectedNonCoreModuleSection)
}
wasmparser::Payload::TypeSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Type),
)?;
let mut types = crate::TypeSection::new();
reencoder.parse_type_section(&mut types, section)?;
module.section(&types);
}
wasmparser::Payload::ImportSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Import),
)?;
let mut imports = crate::ImportSection::new();
reencoder.parse_import_section(&mut imports, section)?;
module.section(&imports);
}
wasmparser::Payload::FunctionSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Function),
)?;
let mut functions = crate::FunctionSection::new();
reencoder.parse_function_section(&mut functions, section)?;
module.section(&functions);
}
wasmparser::Payload::TableSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Table),
)?;
let mut tables = crate::TableSection::new();
reencoder.parse_table_section(&mut tables, section)?;
module.section(&tables);
}
wasmparser::Payload::MemorySection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Memory),
)?;
let mut memories = crate::MemorySection::new();
reencoder.parse_memory_section(&mut memories, section)?;
module.section(&memories);
}
wasmparser::Payload::TagSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Tag),
)?;
let mut tags = crate::TagSection::new();
reencoder.parse_tag_section(&mut tags, section)?;
module.section(&tags);
}
wasmparser::Payload::GlobalSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Global),
)?;
let mut globals = crate::GlobalSection::new();
reencoder.parse_global_section(&mut globals, section)?;
module.section(&globals);
}
wasmparser::Payload::ExportSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Export),
)?;
let mut exports = crate::ExportSection::new();
reencoder.parse_export_section(&mut exports, section)?;
module.section(&exports);
}
wasmparser::Payload::StartSection { func, .. } => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Start),
)?;
module.section(&crate::StartSection {
function_index: reencoder.start_section(func),
});
}
wasmparser::Payload::ElementSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Element),
)?;
let mut elements = crate::ElementSection::new();
reencoder.parse_element_section(&mut elements, section)?;
module.section(&elements);
}
wasmparser::Payload::DataCountSection { count, .. } => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::DataCount),
)?;
let count = reencoder.data_count(count);
module.section(&crate::DataCountSection { count });
}
wasmparser::Payload::DataSection(section) => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Data),
)?;
let mut data = crate::DataSection::new();
reencoder.parse_data_section(&mut data, section)?;
module.section(&data);
}
wasmparser::Payload::CodeSectionStart { range, .. } => {
handle_intersperse_section_hook(
reencoder,
module,
&mut last_section,
Some(crate::SectionId::Code),
)?;
let mut codes = crate::CodeSection::new();
// Convert from `range` to a byte range within `data` while
// accounting for various offsets. Then create a
// `CodeSectionReader` (which notably the payload does not
// give us here) and recurse with that. This means that
// users overridding `parse_code_section` always get that
// function called.
let section = get_original_section(range.clone())?;
let reader = wasmparser::BinaryReader::new(section, range.start);
let section = wasmparser::CodeSectionReader::new(reader)?;
reencoder.parse_code_section(&mut codes, section)?;
module.section(&codes);
}
// Parsing of code section entries (function bodies) happens
// above during the handling of the code section. That means
// that we just skip all these payloads.
wasmparser::Payload::CodeSectionEntry(_) => {}
#[cfg(feature = "component-model")]
wasmparser::Payload::ModuleSection { .. }
| wasmparser::Payload::InstanceSection(_)
| wasmparser::Payload::CoreTypeSection(_)
| wasmparser::Payload::ComponentSection { .. }
| wasmparser::Payload::ComponentInstanceSection(_)
| wasmparser::Payload::ComponentAliasSection(_)
| wasmparser::Payload::ComponentTypeSection(_)
| wasmparser::Payload::ComponentCanonicalSection(_)
| wasmparser::Payload::ComponentStartSection { .. }
| wasmparser::Payload::ComponentImportSection(_)
| wasmparser::Payload::ComponentExportSection(_) => {
return Err(Error::UnexpectedNonCoreModuleSection)
}
wasmparser::Payload::CustomSection(section) => {
reencoder.parse_custom_section(module, section)?;
}
wasmparser::Payload::End(_) => {
handle_intersperse_section_hook(reencoder, module, &mut last_section, None)?;
}
other => match other.as_section() {
Some((id, range)) => {
let section = get_original_section(range)?;
reencoder.parse_unknown_section(module, id, section)?;
}
None => unreachable!(),
},
}
}
Ok(())
}
/// A hook method that is called inside [`Reencode::parse_core_module`]
/// before and after every non-custom core wasm section.
///
/// This method can be used to insert new custom sections in between those
/// sections, or to detect when a non-custom section is missing and insert
/// it in the [proper order].
///
/// The `after` parameter is `None` iff the hook is called before the first
/// non-custom section, and `Some(s)` afterwards, where `s` is the
/// [`SectionId`] of the previous non-custom section.
///
/// The `before` parameter is `None` iff the hook is called after the last
/// non-custom section, and `Some(s)` beforehand, where `s` is the
/// [`SectionId`] of the following non-custom section.
///
/// [`SectionId`]: crate::SectionId
pub fn intersperse_section_hook<T: ?Sized + Reencode>(
_reencoder: &mut T,
_module: &mut crate::Module,
_after: Option<crate::SectionId>,
_before: Option<crate::SectionId>,
) -> Result<(), Error<T::Error>> {
Ok(())
}
pub fn memory_index<T: ?Sized + Reencode>(_reencoder: &mut T, memory: u32) -> u32 {
memory
}
pub fn mem_arg<T: ?Sized + Reencode>(
reencoder: &mut T,
arg: wasmparser::MemArg,
) -> crate::MemArg {
crate::MemArg {
offset: arg.offset,
align: arg.align.into(),
memory_index: reencoder.memory_index(arg.memory),
}
}
pub fn ordering<T: ?Sized + Reencode>(
_reencoder: &mut T,
arg: wasmparser::Ordering,
) -> crate::Ordering {
match arg {
wasmparser::Ordering::SeqCst => crate::Ordering::SeqCst,
wasmparser::Ordering::AcqRel => crate::Ordering::AcqRel,
}
}
pub fn function_index<T: ?Sized + Reencode>(_reencoder: &mut T, func: u32) -> u32 {
func
}
pub fn tag_index<T: ?Sized + Reencode>(_reencoder: &mut T, tag: u32) -> u32 {
tag
}
pub fn catch<T: ?Sized + Reencode>(reencoder: &mut T, arg: wasmparser::Catch) -> crate::Catch {
match arg {
wasmparser::Catch::One { tag, label } => crate::Catch::One {
tag: reencoder.tag_index(tag),
label,
},
wasmparser::Catch::OneRef { tag, label } => crate::Catch::OneRef {
tag: reencoder.tag_index(tag),
label,
},
wasmparser::Catch::All { label } => crate::Catch::All { label },
wasmparser::Catch::AllRef { label } => crate::Catch::AllRef { label },
}
}
pub fn handle<T: ?Sized + Reencode>(
reencoder: &mut T,
arg: wasmparser::Handle,
) -> crate::Handle {
match arg {
wasmparser::Handle::OnLabel { tag, label } => crate::Handle::OnLabel {
tag: reencoder.tag_index(tag),
label,
},
wasmparser::Handle::OnSwitch { tag } => crate::Handle::OnSwitch {
tag: reencoder.tag_index(tag),
},
}
}
/// Parses the input `section` given from the `wasmparser` crate and
/// adds the custom section to the `module`.
pub fn parse_custom_section<T: ?Sized + Reencode>(
reencoder: &mut T,
module: &mut crate::Module,
section: wasmparser::CustomSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
match section.as_known() {
wasmparser::KnownCustom::Name(name) => {
module.section(&reencoder.custom_name_section(name)?);
}
_ => {
module.section(&reencoder.custom_section(section));
}
}
Ok(())
}
/// Converts the input `section` given from the `wasmparser` crate into an
/// encoded custom section.
pub fn custom_section<'a, T: ?Sized + Reencode>(
_reencoder: &mut T,
section: wasmparser::CustomSectionReader<'a>,
) -> crate::CustomSection<'a> {
crate::CustomSection {
data: section.data().into(),
name: section.name().into(),
}
}
pub fn export_kind<T: ?Sized + Reencode>(
_reencoder: &mut T,
external_kind: wasmparser::ExternalKind,
) -> crate::ExportKind {
match external_kind {
wasmparser::ExternalKind::Func => crate::ExportKind::Func,
wasmparser::ExternalKind::Table => crate::ExportKind::Table,
wasmparser::ExternalKind::Memory => crate::ExportKind::Memory,
wasmparser::ExternalKind::Global => crate::ExportKind::Global,
wasmparser::ExternalKind::Tag => crate::ExportKind::Tag,
}
}
pub fn memory_type<T: ?Sized + Reencode>(
_reencoder: &mut T,
memory_ty: wasmparser::MemoryType,
) -> crate::MemoryType {
crate::MemoryType {
minimum: memory_ty.initial,
maximum: memory_ty.maximum,
memory64: memory_ty.memory64,
shared: memory_ty.shared,
page_size_log2: memory_ty.page_size_log2,
}
}
pub fn tag_kind<T: ?Sized + Reencode>(
_reencoder: &mut T,
kind: wasmparser::TagKind,
) -> crate::TagKind {
match kind {
wasmparser::TagKind::Exception => crate::TagKind::Exception,
}
}
pub fn type_index<T: ?Sized + Reencode>(_reencoder: &mut T, ty: u32) -> u32 {
ty
}
pub fn type_index_unpacked<T: ?Sized + Reencode>(
reencoder: &mut T,
ty: wasmparser::UnpackedIndex,
) -> Result<u32, Error<T::Error>> {
ty.as_module_index()
.map(|ty| reencoder.type_index(ty))
.ok_or(Error::CanonicalizedHeapTypeReference)
}
pub fn tag_type<T: ?Sized + Reencode>(
reencoder: &mut T,
tag_ty: wasmparser::TagType,
) -> crate::TagType {
crate::TagType {
kind: reencoder.tag_kind(tag_ty.kind),
func_type_idx: reencoder.type_index(tag_ty.func_type_idx),
}
}
pub fn abstract_heap_type<T: ?Sized + Reencode>(
_reencoder: &mut T,
value: wasmparser::AbstractHeapType,
) -> crate::AbstractHeapType {
use wasmparser::AbstractHeapType::*;
match value {
Func => crate::AbstractHeapType::Func,
Extern => crate::AbstractHeapType::Extern,
Any => crate::AbstractHeapType::Any,
None => crate::AbstractHeapType::None,
NoExtern => crate::AbstractHeapType::NoExtern,
NoFunc => crate::AbstractHeapType::NoFunc,
Eq => crate::AbstractHeapType::Eq,
Struct => crate::AbstractHeapType::Struct,
Array => crate::AbstractHeapType::Array,
I31 => crate::AbstractHeapType::I31,
Exn => crate::AbstractHeapType::Exn,
NoExn => crate::AbstractHeapType::NoExn,
Cont => crate::AbstractHeapType::Cont,
NoCont => crate::AbstractHeapType::NoCont,
}
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the types to the `types` section.
pub fn parse_type_section<T: ?Sized + Reencode>(
reencoder: &mut T,
types: &mut crate::TypeSection,
section: wasmparser::TypeSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for rec_group in section {
reencoder.parse_recursive_type_group(types.ty(), rec_group?)?;
}
Ok(())
}
/// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section.
pub fn parse_recursive_type_group<T: ?Sized + Reencode>(
reencoder: &mut T,
encoder: CoreTypeEncoder,
rec_group: wasmparser::RecGroup,
) -> Result<(), Error<T::Error>> {
if rec_group.is_explicit_rec_group() {
let subtypes = rec_group
.into_types()
.map(|t| reencoder.sub_type(t))
.collect::<Result<Vec<_>, _>>()?;
encoder.rec(subtypes);
} else {
let ty = rec_group.into_types().next().unwrap();
encoder.subtype(&reencoder.sub_type(ty)?);
}
Ok(())
}
pub fn sub_type<T: ?Sized + Reencode>(
reencoder: &mut T,
sub_ty: wasmparser::SubType,
) -> Result<crate::SubType, Error<T::Error>> {
Ok(crate::SubType {
is_final: sub_ty.is_final,
supertype_idx: sub_ty
.supertype_idx
.map(|i| reencoder.type_index_unpacked(i.unpack()))
.transpose()?,
composite_type: reencoder.composite_type(sub_ty.composite_type)?,
})
}
pub fn composite_type<T: ?Sized + Reencode>(
reencoder: &mut T,
composite_ty: wasmparser::CompositeType,
) -> Result<crate::CompositeType, Error<T::Error>> {
let inner = match composite_ty.inner {
wasmparser::CompositeInnerType::Func(f) => {
crate::CompositeInnerType::Func(reencoder.func_type(f)?)
}
wasmparser::CompositeInnerType::Array(a) => {
crate::CompositeInnerType::Array(reencoder.array_type(a)?)
}
wasmparser::CompositeInnerType::Struct(s) => {
crate::CompositeInnerType::Struct(reencoder.struct_type(s)?)
}
wasmparser::CompositeInnerType::Cont(c) => {
crate::CompositeInnerType::Cont(reencoder.cont_type(c)?)
}
};
Ok(crate::CompositeType {
inner,
shared: composite_ty.shared,
})
}
pub fn func_type<T: ?Sized + Reencode>(
reencoder: &mut T,
func_ty: wasmparser::FuncType,
) -> Result<crate::FuncType, Error<T::Error>> {
let mut buf = Vec::with_capacity(func_ty.params().len() + func_ty.results().len());
for ty in func_ty.params().iter().chain(func_ty.results()).copied() {
buf.push(reencoder.val_type(ty)?);
}
Ok(crate::FuncType::from_parts(
buf.into(),
func_ty.params().len(),
))
}
pub fn array_type<T: ?Sized + Reencode>(
reencoder: &mut T,
array_ty: wasmparser::ArrayType,
) -> Result<crate::ArrayType, Error<T::Error>> {
Ok(crate::ArrayType(reencoder.field_type(array_ty.0)?))
}
pub fn struct_type<T: ?Sized + Reencode>(
reencoder: &mut T,
struct_ty: wasmparser::StructType,
) -> Result<crate::StructType, Error<T::Error>> {
Ok(crate::StructType {
fields: struct_ty
.fields
.iter()
.map(|field_ty| reencoder.field_type(*field_ty))
.collect::<Result<_, _>>()?,
})
}
pub fn field_type<T: ?Sized + Reencode>(
reencoder: &mut T,
field_ty: wasmparser::FieldType,
) -> Result<crate::FieldType, Error<T::Error>> {
Ok(crate::FieldType {
element_type: reencoder.storage_type(field_ty.element_type)?,
mutable: field_ty.mutable,
})
}
pub fn storage_type<T: ?Sized + Reencode>(
reencoder: &mut T,
storage_ty: wasmparser::StorageType,
) -> Result<crate::StorageType, Error<T::Error>> {
Ok(match storage_ty {
wasmparser::StorageType::I8 => crate::StorageType::I8,
wasmparser::StorageType::I16 => crate::StorageType::I16,
wasmparser::StorageType::Val(v) => crate::StorageType::Val(reencoder.val_type(v)?),
})
}
pub fn cont_type<T: ?Sized + Reencode>(
reencoder: &mut T,
cont_ty: wasmparser::ContType,
) -> Result<crate::ContType, Error<T::Error>> {
Ok(crate::ContType(
reencoder.type_index_unpacked(cont_ty.0.unpack())?,
))
}
pub fn val_type<T: ?Sized + Reencode>(
reencoder: &mut T,
val_ty: wasmparser::ValType,
) -> Result<crate::ValType, Error<T::Error>> {
Ok(match val_ty {
wasmparser::ValType::I32 => crate::ValType::I32,
wasmparser::ValType::I64 => crate::ValType::I64,
wasmparser::ValType::F32 => crate::ValType::F32,
wasmparser::ValType::F64 => crate::ValType::F64,
wasmparser::ValType::V128 => crate::ValType::V128,
wasmparser::ValType::Ref(r) => crate::ValType::Ref(reencoder.ref_type(r)?),
})
}
pub fn ref_type<T: ?Sized + Reencode>(
reencoder: &mut T,
ref_type: wasmparser::RefType,
) -> Result<crate::RefType, Error<T::Error>> {
Ok(crate::RefType {
nullable: ref_type.is_nullable(),
heap_type: reencoder.heap_type(ref_type.heap_type())?,
})
}
pub fn heap_type<T: ?Sized + Reencode>(
reencoder: &mut T,
heap_type: wasmparser::HeapType,
) -> Result<crate::HeapType, Error<T::Error>> {
Ok(match heap_type {
wasmparser::HeapType::Concrete(i) => {
crate::HeapType::Concrete(reencoder.type_index_unpacked(i)?)
}
wasmparser::HeapType::Abstract { shared, ty } => crate::HeapType::Abstract {
shared,
ty: reencoder.abstract_heap_type(ty),
},
})
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the tables to the `tables` section.
pub fn parse_table_section<T: ?Sized + Reencode>(
reencoder: &mut T,
tables: &mut crate::TableSection,
section: wasmparser::TableSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for table in section {
reencoder.parse_table(tables, table?)?;
}
Ok(())
}
/// Parses a single [`wasmparser::Table`] and adds it to the `tables` section.
pub fn parse_table<T: ?Sized + Reencode>(
reencoder: &mut T,
tables: &mut crate::TableSection,
table: wasmparser::Table<'_>,
) -> Result<(), Error<T::Error>> {
let ty = reencoder.table_type(table.ty)?;
match table.init {
wasmparser::TableInit::RefNull => {
tables.table(ty);
}
wasmparser::TableInit::Expr(e) => {
tables.table_with_init(ty, &reencoder.const_expr(e)?);
}
}
Ok(())
}
pub fn table_type<T: ?Sized + Reencode>(
reencoder: &mut T,
table_ty: wasmparser::TableType,
) -> Result<crate::TableType, Error<T::Error>> {
Ok(crate::TableType {
element_type: reencoder.ref_type(table_ty.element_type)?,
minimum: table_ty.initial,
maximum: table_ty.maximum,
table64: table_ty.table64,
shared: table_ty.shared,
})
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the tags to the `tags` section.
pub fn parse_tag_section<T: ?Sized + Reencode>(
reencoder: &mut T,
tags: &mut crate::TagSection,
section: wasmparser::TagSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for tag in section {
let tag = tag?;
tags.tag(reencoder.tag_type(tag));
}
Ok(())
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the exports to the `exports` section.
pub fn parse_export_section<T: ?Sized + Reencode>(
reencoder: &mut T,
exports: &mut crate::ExportSection,
section: wasmparser::ExportSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for export in section {
reencoder.parse_export(exports, export?);
}
Ok(())
}
/// Parses the single [`wasmparser::Export`] provided and adds it to the
/// `exports` section.
pub fn parse_export<T: ?Sized + Reencode>(
reencoder: &mut T,
exports: &mut crate::ExportSection,
export: wasmparser::Export<'_>,
) {
exports.export(
export.name,
reencoder.export_kind(export.kind),
reencoder.external_index(export.kind, export.index),
);
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the globals to the `globals` section.
pub fn parse_global_section<T: ?Sized + Reencode>(
reencoder: &mut T,
globals: &mut crate::GlobalSection,
section: wasmparser::GlobalSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for global in section {
reencoder.parse_global(globals, global?)?;
}
Ok(())
}
/// Parses the single [`wasmparser::Global`] provided and adds it to the
/// `globals` section.
pub fn parse_global<T: ?Sized + Reencode>(
reencoder: &mut T,
globals: &mut crate::GlobalSection,
global: wasmparser::Global<'_>,
) -> Result<(), Error<T::Error>> {
globals.global(
reencoder.global_type(global.ty)?,
&reencoder.const_expr(global.init_expr)?,
);
Ok(())
}
pub fn global_type<T: ?Sized + Reencode>(
reencoder: &mut T,
global_ty: wasmparser::GlobalType,
) -> Result<crate::GlobalType, Error<T::Error>> {
Ok(crate::GlobalType {
val_type: reencoder.val_type(global_ty.content_type)?,
mutable: global_ty.mutable,
shared: global_ty.shared,
})
}
pub fn entity_type<T: ?Sized + Reencode>(
reencoder: &mut T,
type_ref: wasmparser::TypeRef,
) -> Result<crate::EntityType, Error<T::Error>> {
Ok(match type_ref {
wasmparser::TypeRef::Func(i) => crate::EntityType::Function(reencoder.type_index(i)),
wasmparser::TypeRef::Table(t) => crate::EntityType::Table(reencoder.table_type(t)?),
wasmparser::TypeRef::Memory(m) => crate::EntityType::Memory(reencoder.memory_type(m)),
wasmparser::TypeRef::Global(g) => crate::EntityType::Global(reencoder.global_type(g)?),
wasmparser::TypeRef::Tag(t) => crate::EntityType::Tag(reencoder.tag_type(t)),
})
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the imports to the `import` section.
pub fn parse_import_section<T: ?Sized + Reencode>(
reencoder: &mut T,
imports: &mut crate::ImportSection,
section: wasmparser::ImportSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for import in section {
reencoder.parse_import(imports, import?)?;
}
Ok(())
}
/// Parses the single [`wasmparser::Import`] provided and adds it to the
/// `import` section.
pub fn parse_import<T: ?Sized + Reencode>(
reencoder: &mut T,
imports: &mut crate::ImportSection,
import: wasmparser::Import<'_>,
) -> Result<(), Error<T::Error>> {
imports.import(
import.module,
import.name,
reencoder.entity_type(import.ty)?,
);
Ok(())
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the memories to the `memories` section.
pub fn parse_memory_section<T: ?Sized + Reencode>(
reencoder: &mut T,
memories: &mut crate::MemorySection,
section: wasmparser::MemorySectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for memory in section {
let memory = memory?;
memories.memory(reencoder.memory_type(memory));
}
Ok(())
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the functions to the `functions` section.
pub fn parse_function_section<T: ?Sized + Reencode>(
reencoder: &mut T,
functions: &mut crate::FunctionSection,
section: wasmparser::FunctionSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for func in section {
functions.function(reencoder.type_index(func?));
}
Ok(())
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the data to the `data` section.
pub fn parse_data_section<T: ?Sized + Reencode>(
reencoder: &mut T,
data: &mut crate::DataSection,
section: wasmparser::DataSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for datum in section {
reencoder.parse_data(data, datum?)?;
}
Ok(())
}
/// Parses a single [`wasmparser::Data`] and adds it to the `data` section.
pub fn parse_data<T: ?Sized + Reencode>(
reencoder: &mut T,
data: &mut crate::DataSection,
datum: wasmparser::Data<'_>,
) -> Result<(), Error<T::Error>> {
match datum.kind {
wasmparser::DataKind::Active {
memory_index,
offset_expr,
} => data.active(
reencoder.memory_index(memory_index),
&reencoder.const_expr(offset_expr)?,
datum.data.iter().copied(),
),
wasmparser::DataKind::Passive => data.passive(datum.data.iter().copied()),
};
Ok(())
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the elements to the `element` section.
pub fn parse_element_section<T: ?Sized + Reencode>(
reencoder: &mut T,
elements: &mut crate::ElementSection,
section: wasmparser::ElementSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for element in section {
reencoder.parse_element(elements, element?)?;
}
Ok(())
}
/// Parses the single [`wasmparser::Element`] provided and adds it to the
/// `element` section.
pub fn parse_element<T: ?Sized + Reencode>(
reencoder: &mut T,
elements: &mut crate::ElementSection,
element: wasmparser::Element<'_>,
) -> Result<(), Error<T::Error>> {
let elems = reencoder.element_items(element.items)?;
match element.kind {
wasmparser::ElementKind::Active {
table_index,
offset_expr,
} => elements.active(
// Inform the reencoder that a table index is being used even if
// it's not actually present here. That helps wasm-mutate for
// example which wants to track uses to know when it's ok to
// remove a table.
//
// If the table index started at `None` and is still zero then
// preserve this encoding and keep it at `None`. Otherwise if
// the result is nonzero or it was previously nonzero then keep
// that encoding too.
match (table_index, reencoder.table_index(table_index.unwrap_or(0))) {
(None, 0) => None,
(_, n) => Some(n),
},
&reencoder.const_expr(offset_expr)?,
elems,
),
wasmparser::ElementKind::Passive => elements.passive(elems),
wasmparser::ElementKind::Declared => elements.declared(elems),
};
Ok(())
}
pub fn element_items<'a, T: ?Sized + Reencode>(
reencoder: &mut T,
items: wasmparser::ElementItems<'a>,
) -> Result<crate::Elements<'a>, Error<T::Error>> {
Ok(match items {
wasmparser::ElementItems::Functions(f) => {
let mut funcs = Vec::new();
for func in f {
funcs.push(reencoder.function_index(func?));
}
crate::Elements::Functions(funcs.into())
}
wasmparser::ElementItems::Expressions(ty, e) => {
let mut exprs = Vec::new();
for expr in e {
exprs.push(reencoder.const_expr(expr?)?);
}
crate::Elements::Expressions(reencoder.ref_type(ty)?, exprs.into())
}
})
}
pub fn table_index<T: ?Sized + Reencode>(_reencoder: &mut T, table: u32) -> u32 {
table
}
pub fn global_index<T: ?Sized + Reencode>(_reencoder: &mut T, global: u32) -> u32 {
global
}
pub fn data_index<T: ?Sized + Reencode>(_reencoder: &mut T, data: u32) -> u32 {
data
}
pub fn element_index<T: ?Sized + Reencode>(_reencoder: &mut T, element: u32) -> u32 {
element
}
pub fn const_expr<T: ?Sized + Reencode>(
reencoder: &mut T,
const_expr: wasmparser::ConstExpr,
) -> Result<crate::ConstExpr, Error<T::Error>> {
let mut ops = const_expr.get_operators_reader();
let mut bytes = Vec::new();
while !ops.is_end_then_eof() {
let insn = reencoder.parse_instruction(&mut ops)?;
insn.encode(&mut bytes);
}
Ok(crate::ConstExpr::raw(bytes))
}
pub fn block_type<T: ?Sized + Reencode>(
reencoder: &mut T,
arg: wasmparser::BlockType,
) -> Result<crate::BlockType, Error<T::Error>> {
match arg {
wasmparser::BlockType::Empty => Ok(crate::BlockType::Empty),
wasmparser::BlockType::FuncType(n) => {
Ok(crate::BlockType::FunctionType(reencoder.type_index(n)))
}
wasmparser::BlockType::Type(t) => Ok(crate::BlockType::Result(reencoder.val_type(t)?)),
}
}
pub fn instruction<'a, T: ?Sized + Reencode>(
reencoder: &mut T,
arg: wasmparser::Operator<'a>,
) -> Result<crate::Instruction<'a>, Error<T::Error>> {
use crate::Instruction;
macro_rules! translate {
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
Ok(match arg {
$(
wasmparser::Operator::$op $({ $($arg),* })? => {
$(
$(let $arg = translate!(map $arg $arg);)*
)?
translate!(build $op $($($arg)*)?)
}
)*
})
};
// This case is used to map, based on the name of the field, from the
// wasmparser payload type to the wasm-encoder payload type through
// `Translator` as applicable.
(map $arg:ident tag_index) => (reencoder.tag_index($arg));
(map $arg:ident function_index) => (reencoder.function_index($arg));
(map $arg:ident table) => (reencoder.table_index($arg));
(map $arg:ident table_index) => (reencoder.table_index($arg));
(map $arg:ident dst_table) => (reencoder.table_index($arg));
(map $arg:ident src_table) => (reencoder.table_index($arg));
(map $arg:ident type_index) => (reencoder.type_index($arg));
(map $arg:ident array_type_index) => (reencoder.type_index($arg));
(map $arg:ident array_type_index_dst) => (reencoder.type_index($arg));
(map $arg:ident array_type_index_src) => (reencoder.type_index($arg));
(map $arg:ident struct_type_index) => (reencoder.type_index($arg));
(map $arg:ident global_index) => (reencoder.global_index($arg));
(map $arg:ident mem) => (reencoder.memory_index($arg));
(map $arg:ident src_mem) => (reencoder.memory_index($arg));
(map $arg:ident dst_mem) => (reencoder.memory_index($arg));
(map $arg:ident data_index) => (reencoder.data_index($arg));
(map $arg:ident elem_index) => (reencoder.element_index($arg));
(map $arg:ident array_data_index) => (reencoder.data_index($arg));
(map $arg:ident array_elem_index) => (reencoder.element_index($arg));
(map $arg:ident blockty) => (reencoder.block_type($arg)?);
(map $arg:ident relative_depth) => ($arg);
(map $arg:ident targets) => ((
$arg
.targets()
.collect::<Result<Vec<_>, wasmparser::BinaryReaderError>>()?
.into(),
$arg.default(),
));
(map $arg:ident ty) => (reencoder.val_type($arg)?);
(map $arg:ident hty) => (reencoder.heap_type($arg)?);
(map $arg:ident from_ref_type) => (reencoder.ref_type($arg)?);
(map $arg:ident to_ref_type) => (reencoder.ref_type($arg)?);
(map $arg:ident memarg) => (reencoder.mem_arg($arg));
(map $arg:ident ordering) => (reencoder.ordering($arg));
(map $arg:ident local_index) => ($arg);
(map $arg:ident value) => ($arg);
(map $arg:ident lane) => ($arg);
(map $arg:ident lanes) => ($arg);
(map $arg:ident array_size) => ($arg);
(map $arg:ident field_index) => ($arg);
(map $arg:ident try_table) => ($arg);
(map $arg:ident argument_index) => (reencoder.type_index($arg));
(map $arg:ident result_index) => (reencoder.type_index($arg));
(map $arg:ident cont_type_index) => (reencoder.type_index($arg));
(map $arg:ident resume_table) => ((
$arg.handlers.into_iter().map(|h| reencoder.handle(h)).collect::<Vec<_>>().into()
));
// This case takes the arguments of a wasmparser instruction and creates
// a wasm-encoder instruction. There are a few special cases for where
// the structure of a wasmparser instruction differs from that of
// wasm-encoder.
(build $op:ident) => (Instruction::$op);
(build BrTable $arg:ident) => (Instruction::BrTable($arg.0, $arg.1));
(build I32Const $arg:ident) => (Instruction::I32Const($arg));
(build I64Const $arg:ident) => (Instruction::I64Const($arg));
(build F32Const $arg:ident) => (Instruction::F32Const(f32::from_bits($arg.bits())));
(build F64Const $arg:ident) => (Instruction::F64Const(f64::from_bits($arg.bits())));
(build V128Const $arg:ident) => (Instruction::V128Const($arg.i128()));
(build TryTable $table:ident) => (Instruction::TryTable(reencoder.block_type($table.ty)?, {
$table.catches.into_iter().map(|c| reencoder.catch(c)).collect::<Vec<_>>().into()
}));
(build $op:ident $arg:ident) => (Instruction::$op($arg));
(build $op:ident $($arg:ident)*) => (Instruction::$op { $($arg),* });
}
wasmparser::for_each_operator!(translate)
}
/// Parses the input `section` given from the `wasmparser` crate and adds
/// all the code to the `code` section.
pub fn parse_code_section<T: ?Sized + Reencode>(
reencoder: &mut T,
code: &mut crate::CodeSection,
section: wasmparser::CodeSectionReader<'_>,
) -> Result<(), Error<T::Error>> {
for func in section {
reencoder.parse_function_body(code, func?)?;
}
Ok(())
}
/// Parses a single [`wasmparser::FunctionBody`] and adds it to the `code` section.
pub fn parse_function_body<T: ?Sized + Reencode>(
reencoder: &mut T,
code: &mut crate::CodeSection,
func: wasmparser::FunctionBody<'_>,
) -> Result<(), Error<T::Error>> {
let mut f = reencoder.new_function_with_parsed_locals(&func)?;
let mut reader = func.get_operators_reader()?;
while !reader.eof() {
f.instruction(&reencoder.parse_instruction(&mut reader)?);
}
code.function(&f);
Ok(())
}
/// Create a new [`crate::Function`] by parsing the locals declarations from the
/// provided [`wasmparser::FunctionBody`].
pub fn new_function_with_parsed_locals<T: ?Sized + Reencode>(
reencoder: &mut T,
func: &wasmparser::FunctionBody<'_>,
) -> Result<crate::Function, Error<T::Error>> {
let mut locals = Vec::new();
for pair in func.get_locals_reader()? {
let (cnt, ty) = pair?;
locals.push((cnt, reencoder.val_type(ty)?));
}
Ok(crate::Function::new(locals))
}
/// Parses a single instruction from `reader` and adds it to `function`.
pub fn parse_instruction<'a, T: ?Sized + Reencode>(
reencoder: &mut T,
reader: &mut wasmparser::OperatorsReader<'a>,
) -> Result<crate::Instruction<'a>, Error<T::Error>> {
let instruction = reencoder.instruction(reader.read()?)?;
Ok(instruction)
}
pub fn parse_unknown_section<T: ?Sized + Reencode>(
_reencoder: &mut T,
module: &mut crate::Module,
id: u8,
contents: &[u8],
) -> Result<(), Error<T::Error>> {
module.section(&crate::RawSection { id, data: contents });
Ok(())
}
pub fn custom_name_section<T: ?Sized + Reencode>(
reencoder: &mut T,
section: wasmparser::NameSectionReader<'_>,
) -> Result<crate::NameSection, Error<T::Error>> {
let mut ret = crate::NameSection::new();
for subsection in section {
reencoder.parse_custom_name_subsection(&mut ret, subsection?)?;
}
Ok(ret)
}
pub fn parse_custom_name_subsection<T: ?Sized + Reencode>(
reencoder: &mut T,
names: &mut crate::NameSection,
section: wasmparser::Name<'_>,
) -> Result<(), Error<T::Error>> {
match section {
wasmparser::Name::Module { name, .. } => {
names.module(name);
}
wasmparser::Name::Function(map) => {
names.functions(&name_map(map, |i| reencoder.function_index(i))?);
}
wasmparser::Name::Type(map) => {
names.types(&name_map(map, |i| reencoder.type_index(i))?);
}
wasmparser::Name::Local(map) => {
names.locals(&indirect_name_map(map, |i| reencoder.function_index(i))?);
}
wasmparser::Name::Label(map) => {
names.labels(&indirect_name_map(map, |i| reencoder.function_index(i))?);
}
wasmparser::Name::Table(map) => {
names.tables(&name_map(map, |i| reencoder.table_index(i))?);
}
wasmparser::Name::Memory(map) => {
names.memories(&name_map(map, |i| reencoder.memory_index(i))?);
}
wasmparser::Name::Global(map) => {
names.globals(&name_map(map, |i| reencoder.global_index(i))?);
}
wasmparser::Name::Element(map) => {
names.elements(&name_map(map, |i| reencoder.element_index(i))?);
}
wasmparser::Name::Data(map) => {
names.data(&name_map(map, |i| reencoder.data_index(i))?);
}
wasmparser::Name::Tag(map) => {
names.tags(&name_map(map, |i| reencoder.tag_index(i))?);
}
wasmparser::Name::Field(map) => {
names.fields(&indirect_name_map(map, |i| reencoder.type_index(i))?);
}
wasmparser::Name::Unknown { ty, data, .. } => {
names.raw(ty, data);
}
}
Ok(())
}
pub fn name_map(
map: wasmparser::NameMap<'_>,
mut map_index: impl FnMut(u32) -> u32,
) -> wasmparser::Result<crate::NameMap> {
let mut ret = crate::NameMap::new();
for naming in map {
let naming = naming?;
ret.append(map_index(naming.index), naming.name);
}
Ok(ret)
}
pub fn indirect_name_map(
map: wasmparser::IndirectNameMap<'_>,
mut map_index: impl FnMut(u32) -> u32,
) -> wasmparser::Result<crate::IndirectNameMap> {
let mut ret = crate::IndirectNameMap::new();
for naming in map {
let naming = naming?;
ret.append(map_index(naming.index), &name_map(naming.names, |i| i)?);
}
Ok(ret)
}
}
impl From<wasmparser::MemArg> for crate::MemArg {
fn from(arg: wasmparser::MemArg) -> Self {
RoundtripReencoder.mem_arg(arg)
}
}
impl From<wasmparser::Ordering> for crate::Ordering {
fn from(arg: wasmparser::Ordering) -> Self {
RoundtripReencoder.ordering(arg)
}
}
impl TryFrom<wasmparser::BlockType> for crate::BlockType {
type Error = Error;
fn try_from(arg: wasmparser::BlockType) -> Result<Self, Self::Error> {
RoundtripReencoder.block_type(arg)
}
}
impl<'a> TryFrom<wasmparser::Operator<'a>> for crate::Instruction<'a> {
type Error = Error;
fn try_from(arg: wasmparser::Operator<'a>) -> Result<Self, Self::Error> {
RoundtripReencoder.instruction(arg)
}
}
impl From<wasmparser::Catch> for crate::Catch {
fn from(arg: wasmparser::Catch) -> Self {
RoundtripReencoder.catch(arg)
}
}
impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for crate::ConstExpr {
type Error = Error;
fn try_from(const_expr: wasmparser::ConstExpr) -> Result<Self, Self::Error> {
RoundtripReencoder.const_expr(const_expr)
}
}
impl<'a> From<wasmparser::CustomSectionReader<'a>> for crate::CustomSection<'a> {
fn from(section: wasmparser::CustomSectionReader<'a>) -> Self {
RoundtripReencoder.custom_section(section)
}
}
impl From<wasmparser::ExternalKind> for crate::ExportKind {
fn from(external_kind: wasmparser::ExternalKind) -> Self {
RoundtripReencoder.export_kind(external_kind)
}
}
impl TryFrom<wasmparser::GlobalType> for crate::GlobalType {
type Error = Error;
fn try_from(global_ty: wasmparser::GlobalType) -> Result<Self, Self::Error> {
RoundtripReencoder.global_type(global_ty)
}
}
impl From<wasmparser::Handle> for crate::Handle {
fn from(arg: wasmparser::Handle) -> Self {
RoundtripReencoder.handle(arg)
}
}
impl TryFrom<wasmparser::TypeRef> for crate::EntityType {
type Error = Error;
fn try_from(type_ref: wasmparser::TypeRef) -> Result<Self, Self::Error> {
RoundtripReencoder.entity_type(type_ref)
}
}
impl From<wasmparser::MemoryType> for crate::MemoryType {
fn from(memory_ty: wasmparser::MemoryType) -> Self {
RoundtripReencoder.memory_type(memory_ty)
}
}
impl TryFrom<wasmparser::TableType> for crate::TableType {
type Error = Error;
fn try_from(table_ty: wasmparser::TableType) -> Result<Self, Self::Error> {
RoundtripReencoder.table_type(table_ty)
}
}
impl From<wasmparser::TagKind> for crate::TagKind {
fn from(kind: wasmparser::TagKind) -> Self {
RoundtripReencoder.tag_kind(kind)
}
}
impl From<wasmparser::TagType> for crate::TagType {
fn from(tag_ty: wasmparser::TagType) -> Self {
RoundtripReencoder.tag_type(tag_ty)
}
}
impl TryFrom<wasmparser::SubType> for crate::SubType {
type Error = Error;
fn try_from(sub_ty: wasmparser::SubType) -> Result<Self, Self::Error> {
RoundtripReencoder.sub_type(sub_ty)
}
}
impl TryFrom<wasmparser::CompositeType> for crate::CompositeType {
type Error = Error;
fn try_from(composite_ty: wasmparser::CompositeType) -> Result<Self, Self::Error> {
RoundtripReencoder.composite_type(composite_ty)
}
}
impl TryFrom<wasmparser::FuncType> for crate::FuncType {
type Error = Error;
fn try_from(func_ty: wasmparser::FuncType) -> Result<Self, Self::Error> {
RoundtripReencoder.func_type(func_ty)
}
}
impl TryFrom<wasmparser::ArrayType> for crate::ArrayType {
type Error = Error;
fn try_from(array_ty: wasmparser::ArrayType) -> Result<Self, Self::Error> {
RoundtripReencoder.array_type(array_ty)
}
}
impl TryFrom<wasmparser::StructType> for crate::StructType {
type Error = Error;
fn try_from(struct_ty: wasmparser::StructType) -> Result<Self, Self::Error> {
RoundtripReencoder.struct_type(struct_ty)
}
}
impl TryFrom<wasmparser::FieldType> for crate::FieldType {
type Error = Error;
fn try_from(field_ty: wasmparser::FieldType) -> Result<Self, Self::Error> {
RoundtripReencoder.field_type(field_ty)
}
}
impl TryFrom<wasmparser::StorageType> for crate::StorageType {
type Error = Error;
fn try_from(storage_ty: wasmparser::StorageType) -> Result<Self, Self::Error> {
RoundtripReencoder.storage_type(storage_ty)
}
}
impl TryFrom<wasmparser::ValType> for crate::ValType {
type Error = Error;
fn try_from(val_ty: wasmparser::ValType) -> Result<Self, Self::Error> {
RoundtripReencoder.val_type(val_ty)
}
}
impl TryFrom<wasmparser::RefType> for crate::RefType {
type Error = Error;
fn try_from(ref_type: wasmparser::RefType) -> Result<Self, Self::Error> {
RoundtripReencoder.ref_type(ref_type)
}
}
impl TryFrom<wasmparser::HeapType> for crate::HeapType {
type Error = Error;
fn try_from(heap_type: wasmparser::HeapType) -> Result<Self, Self::Error> {
crate::reencode::utils::heap_type(&mut crate::reencode::RoundtripReencoder, heap_type)
}
}
impl From<wasmparser::AbstractHeapType> for crate::AbstractHeapType {
fn from(value: wasmparser::AbstractHeapType) -> Self {
RoundtripReencoder.abstract_heap_type(value)
}
}