orca_wasm/ir/module/module_tables.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
//! Intermediate representation of the Tables in a Module
use crate::ir::id::TableID;
use wasmparser::{RefType, TableType};
/// Tables Section of a module
#[derive(Clone, Debug, Default)]
pub struct ModuleTables<'a> {
tables: Vec<(TableType, Option<wasmparser::ConstExpr<'a>>)>,
}
impl<'a> ModuleTables<'a> {
/// Create a new table section
pub fn new(tables: Vec<(TableType, Option<wasmparser::ConstExpr<'a>>)>) -> Self {
ModuleTables { tables }
}
/// Check if there are any tables
pub fn is_empty(&self) -> bool {
self.tables.is_empty()
}
/// Create an iterable over the table section
pub fn iter(&self) -> std::slice::Iter<'_, (TableType, Option<wasmparser::ConstExpr<'a>>)> {
self.tables.iter()
}
/// Finds a unique function table in a module.
///
/// Modules produced by compilers like LLVM typically have one function
/// table for indirect function calls. This function will look for a single
/// function table inside this module, and return that if found. If no
/// function tables are present `None` will be returned
///
/// # Errors
///
/// Returns an error if there are two function tables in this module
///
/// Inspired from [walrus' implementation]
///
/// [walrus' implementation]: https://docs.rs/walrus/latest/walrus/struct.ModuleTables.html#method.main_function_table
pub fn main_function(&self) -> Option<TableID> {
let mut tables = self
.tables
.iter()
.enumerate()
.filter(|(_, (t, _))| t.element_type == RefType::FUNCREF);
let id = match tables.next() {
Some((index, _)) => Some(TableID(index as u32)),
None => return None,
};
if tables.next().is_some() {
panic!("module contains more than one function table");
}
id
}
/// Get a table
pub fn get(&self, table_id: TableID) -> Option<TableType> {
if *table_id < self.tables.len() as u32 {
return Some(self.tables[*table_id as usize].0);
}
None
}
/// Get a mutable reference to a table
pub fn get_mut(&mut self, table_id: TableID) -> &mut TableType {
if *table_id < self.tables.len() as u32 {
return &mut self.tables[*table_id as usize].0;
}
panic!("Invalid Table ID")
}
}