wasmer_wasix/state/linker/instance_group/
table.rs

1use tracing::trace;
2use wasmer::{AsStoreMut, Function, RuntimeError, Value};
3
4use super::{InstanceGroupState, LinkError, LinkerState, ModuleHandle};
5
6impl InstanceGroupState {
7    /// Allocate space on the indirect function table for the given number of functions.
8    ///
9    /// table_alignment is the alignment of the table as a power of two.
10    pub(in crate::state::linker) fn allocate_function_table(
11        &mut self,
12        store: &mut impl AsStoreMut,
13        table_size: u32,
14        table_alignment: u32,
15    ) -> Result<u64, RuntimeError> {
16        trace!(table_size, "Allocating table indices");
17
18        let base_index = if table_size == 0 {
19            0
20        } else {
21            let current_size = self.indirect_function_table.size(store);
22            let alignment = 2_u32.pow(table_alignment);
23
24            let offset = if !current_size.is_multiple_of(alignment) {
25                alignment - (current_size % alignment)
26            } else {
27                0
28            };
29
30            let delta = table_size + offset;
31            trace!(?current_size, ?delta, "Growing indirect function table");
32            let start = self
33                .indirect_function_table
34                .grow(store, delta, Value::FuncRef(None))?;
35
36            (start + offset) as u64
37        };
38
39        trace!(
40            base_index,
41            new_table_size = ?self.indirect_function_table.size(store),
42            "Allocated table indices"
43        );
44
45        Ok(base_index)
46    }
47
48    pub(in crate::state::linker) fn append_to_function_table(
49        &self,
50        store: &mut impl AsStoreMut,
51        func: Function,
52    ) -> Result<u32, RuntimeError> {
53        let table = &self.indirect_function_table;
54
55        let ty = func.ty(store).to_string();
56        let index: u32 = table.size(store);
57        trace!(?index, ?ty, "Appending function in table");
58
59        table.grow(store, 1, func.into())
60    }
61
62    pub(super) fn place_in_function_table_at(
63        &self,
64        store: &mut impl AsStoreMut,
65        func: Function,
66        index: u32,
67    ) -> Result<(), RuntimeError> {
68        trace!(
69            ?index,
70            ?func,
71            "Placing function in table at pre-defined index"
72        );
73
74        let table = &self.indirect_function_table;
75        let size = table.size(store);
76
77        if size <= index {
78            let delta = index - size + 1;
79            trace!(
80                current_size = ?size,
81                ?delta,
82                "Growing indirect function table"
83            );
84            table.grow(store, delta, Value::FuncRef(None))?;
85        } else {
86            let existing = table.get(store, index).unwrap();
87            if let Value::FuncRef(Some(_)) = existing {
88                panic!("Internal error: function table index {index} already occupied");
89            }
90        }
91
92        let ty = func.ty(store).to_string();
93        trace!(?index, ?ty, "Placing function in table at index");
94        table.set(store, index, Value::FuncRef(Some(func)))
95    }
96
97    pub(super) fn allocate_function_table_for_existing_module(
98        &mut self,
99        linker_state: &LinkerState,
100        store: &mut impl AsStoreMut,
101        module_handle: ModuleHandle,
102    ) -> Result<(), LinkError> {
103        if self.side_instances.contains_key(&module_handle) {
104            panic!(
105                "Internal error: Module with handle {module_handle:?} \
106                was already instantiated in this group"
107            )
108        };
109
110        let dl_module = linker_state
111            .side_modules
112            .get(&module_handle)
113            .expect("Internal error: module not loaded into linker");
114
115        let table_base = self
116            .allocate_function_table(
117                store,
118                dl_module.dylink_info.mem_info.table_size,
119                dl_module.dylink_info.mem_info.table_alignment,
120            )
121            .map_err(LinkError::TableAllocationError)?;
122
123        if table_base != dl_module.table_base {
124            panic!("Internal error: table base out of sync with linker state");
125        }
126
127        trace!(table_base, "Allocated table indices for existing module");
128
129        Ok(())
130    }
131
132    pub(super) fn apply_resolved_function(
133        &self,
134        store: &mut impl AsStoreMut,
135        name: &str,
136        resolved_from: ModuleHandle,
137        function_table_index: u32,
138    ) -> Result<(), LinkError> {
139        trace!(
140            ?name,
141            ?resolved_from,
142            function_table_index,
143            "Applying resolved function"
144        );
145
146        let instance = &self.try_instance(resolved_from).unwrap_or_else(|| {
147            panic!("Internal error: module {resolved_from:?} not loaded by this group")
148        });
149
150        let func = instance.exports.get_function(name).unwrap_or_else(|e| {
151            panic!("Internal error: failed to resolve exported function {name}: {e:?}")
152        });
153
154        self.place_in_function_table_at(store, func.clone(), function_table_index)
155            .map_err(LinkError::TableAllocationError)?;
156
157        Ok(())
158    }
159
160    pub(super) fn apply_function_table_allocation(
161        &mut self,
162        store: &mut impl AsStoreMut,
163        index: u32,
164        size: u32,
165    ) -> Result<(), LinkError> {
166        trace!(index, "Applying function table allocation");
167        let allocated_index = self
168            .allocate_function_table(store, size, 0)
169            .map_err(LinkError::TableAllocationError)? as u32;
170        if allocated_index != index {
171            panic!(
172                "Internal error: allocated index {allocated_index} does not match expected index {index}"
173            );
174        }
175        Ok(())
176    }
177}