Wasynth/wasm-ast/src/module.rs
wackbyte bbaa60e8c2
Update dependencies (#30)
* dev-test: update dependencies

* update wasmparser: 0.99.0 -> 0.101.1

Remove `i64` generation fix for elements as they only contain `reftype` and not `i64`

* update wasmparser: 0.101.1 -> 0.103.0

See <https://github.com/bytecodealliance/wasm-tools/pull/957> for more information

* update wasmparser: 0.103.0 -> 0.106.0

* update wasmparser: 0.106.0 -> 0.107.0
2023-06-26 17:19:12 -04:00

283 lines
6.6 KiB
Rust

use std::collections::HashMap;
use wasmparser::{
BlockType, Data, Element, Export, ExternalKind, FunctionBody, Global, Import, LocalsReader,
MemoryType, Name, NameSectionReader, Parser, Payload, Result, Table, Type, TypeRef, ValType,
};
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum External {
Func,
Table,
Memory,
Global,
Tag,
}
impl From<TypeRef> for External {
fn from(value: TypeRef) -> Self {
match value {
TypeRef::Func(_) => Self::Func,
TypeRef::Table(_) => Self::Table,
TypeRef::Memory(_) => Self::Memory,
TypeRef::Global(_) => Self::Global,
TypeRef::Tag(_) => Self::Tag,
}
}
}
impl From<ExternalKind> for External {
fn from(value: ExternalKind) -> Self {
match value {
ExternalKind::Func => Self::Func,
ExternalKind::Table => Self::Table,
ExternalKind::Memory => Self::Memory,
ExternalKind::Global => Self::Global,
ExternalKind::Tag => Self::Tag,
}
}
}
pub(crate) fn read_checked<T, I>(reader: I) -> Result<Vec<T>>
where
I: IntoIterator<Item = Result<T>>,
{
reader.into_iter().collect()
}
pub(crate) fn read_checked_locals(reader: LocalsReader) -> Result<Vec<ValType>> {
read_checked(reader).map(|locals| {
let convert = |(a, b)| std::iter::repeat(b).take(usize::try_from(a).unwrap());
locals.into_iter().flat_map(convert).collect()
})
}
pub struct Module<'a> {
type_section: Vec<Type>,
import_section: Vec<Import<'a>>,
func_section: Vec<u32>,
table_section: Vec<Table<'a>>,
memory_section: Vec<MemoryType>,
global_section: Vec<Global<'a>>,
export_section: Vec<Export<'a>>,
element_section: Vec<Element<'a>>,
data_section: Vec<Data<'a>>,
code_section: Vec<FunctionBody<'a>>,
name_section: HashMap<u32, &'a str>,
start_section: Option<u32>,
}
impl<'a> Module<'a> {
/// # Errors
///
/// Returns a `BinaryReaderError` if any module section is malformed.
pub fn try_from_data(data: &'a [u8]) -> Result<Self> {
let mut temp = Module {
type_section: Vec::new(),
import_section: Vec::new(),
func_section: Vec::new(),
table_section: Vec::new(),
memory_section: Vec::new(),
global_section: Vec::new(),
export_section: Vec::new(),
element_section: Vec::new(),
data_section: Vec::new(),
code_section: Vec::new(),
name_section: HashMap::new(),
start_section: None,
};
temp.load_data(data)?;
Ok(temp)
}
fn load_data(&mut self, data: &'a [u8]) -> Result<()> {
for payload in Parser::new(0).parse_all(data) {
match payload? {
Payload::TypeSection(v) => self.type_section = read_checked(v)?,
Payload::ImportSection(v) => self.import_section = read_checked(v)?,
Payload::FunctionSection(v) => self.func_section = read_checked(v)?,
Payload::TableSection(v) => self.table_section = read_checked(v)?,
Payload::MemorySection(v) => self.memory_section = read_checked(v)?,
Payload::GlobalSection(v) => self.global_section = read_checked(v)?,
Payload::ExportSection(v) => self.export_section = read_checked(v)?,
Payload::ElementSection(v) => self.element_section = read_checked(v)?,
Payload::DataSection(v) => self.data_section = read_checked(v)?,
Payload::CodeSectionEntry(v) => {
self.code_section.push(v);
}
Payload::StartSection { func, .. } => {
self.start_section = Some(func);
}
Payload::CustomSection(v) if v.name() == "name" => {
for name in NameSectionReader::new(v.data(), v.data_offset()) {
if let Name::Function(map) = name? {
let mut iter = map.into_iter();
while let Some(Ok(elem)) = iter.next() {
self.name_section.insert(elem.index, elem.name);
}
}
}
}
_ => {}
}
}
Ok(())
}
#[must_use]
pub fn import_count(&self, ext: External) -> usize {
let predicate = |v: &&Import| External::from(v.ty) == ext;
self.import_section.iter().filter(predicate).count()
}
#[must_use]
pub fn function_space(&self) -> usize {
self.import_count(External::Func) + self.func_section.len()
}
#[must_use]
pub fn table_space(&self) -> usize {
self.import_count(External::Table) + self.table_section.len()
}
#[must_use]
pub fn memory_space(&self) -> usize {
self.import_count(External::Memory) + self.memory_section.len()
}
#[must_use]
pub fn global_space(&self) -> usize {
self.import_count(External::Global) + self.global_section.len()
}
#[must_use]
pub fn type_section(&self) -> &[Type] {
&self.type_section
}
#[must_use]
pub fn import_section(&self) -> &[Import] {
&self.import_section
}
#[must_use]
pub fn func_section(&self) -> &[u32] {
&self.func_section
}
#[must_use]
pub fn table_section(&self) -> &[Table] {
&self.table_section
}
#[must_use]
pub fn memory_section(&self) -> &[MemoryType] {
&self.memory_section
}
#[must_use]
pub fn global_section(&self) -> &[Global] {
&self.global_section
}
#[must_use]
pub fn export_section(&self) -> &[Export] {
&self.export_section
}
#[must_use]
pub fn element_section(&self) -> &[Element] {
&self.element_section
}
#[must_use]
pub fn data_section(&self) -> &[Data] {
&self.data_section
}
#[must_use]
pub fn code_section(&self) -> &[FunctionBody] {
&self.code_section
}
#[must_use]
pub const fn name_section(&self) -> &HashMap<u32, &'a str> {
&self.name_section
}
#[must_use]
pub const fn start_section(&self) -> Option<u32> {
self.start_section
}
}
pub struct TypeInfo<'a> {
type_list: &'a [Type],
func_list: Vec<usize>,
}
impl<'a> TypeInfo<'a> {
#[must_use]
pub fn from_module(wasm: &'a Module) -> Self {
let mut temp = Self {
type_list: &wasm.type_section,
func_list: Vec::new(),
};
temp.load_import_list(&wasm.import_section);
temp.load_func_list(&wasm.func_section);
temp
}
fn load_import_list(&mut self, list: &[Import]) {
let iter = list
.iter()
.copied()
.filter_map(|v| match v.ty {
TypeRef::Func(v) => Some(v),
_ => None,
})
.map(|v| usize::try_from(v).unwrap());
self.func_list.extend(iter);
}
fn load_func_list(&mut self, list: &[u32]) {
let iter = list.iter().copied().map(|v| usize::try_from(v).unwrap());
self.func_list.extend(iter);
}
pub(crate) fn by_type_index(&self, index: usize) -> (usize, usize) {
let Type::Func(ty) = &self.type_list[index] else {
unreachable!("type at func index must be a func type");
};
(ty.params().len(), ty.results().len())
}
pub(crate) fn by_func_index(&self, index: usize) -> (usize, usize) {
let adjusted = self.func_list[index];
self.by_type_index(adjusted)
}
pub(crate) fn by_block_type(&self, ty: BlockType) -> (usize, usize) {
match ty {
BlockType::Empty => (0, 0),
BlockType::Type(_) => (0, 1),
BlockType::FuncType(i) => {
let id = i.try_into().unwrap();
self.by_type_index(id)
}
}
}
}