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")
    }
}