unc_vm_engine/universal/
artifact.rs

1//! Define `UniversalArtifact` to allow compiling and instantiating to be
2//! done as separate steps.
3
4use crate::InstantiationError;
5use std::collections::BTreeMap;
6use std::convert::TryFrom;
7use std::sync::Arc;
8use unc_vm_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
9use unc_vm_types::{
10    DataIndex, ElemIndex, FunctionIndex, GlobalInit, GlobalType, ImportCounts, LocalFunctionIndex,
11    LocalGlobalIndex, MemoryType, OwnedDataInitializer, OwnedTableInitializer, SignatureIndex,
12    TableType,
13};
14use unc_vm_vm::{
15    Artifact, FunctionBodyPtr, FunctionExtent, InstanceHandle, Instantiatable, MemoryStyle,
16    Resolver, TableStyle, Tunables, VMImport, VMImportType, VMLocalFunction, VMOffsets,
17    VMSharedSignatureIndex,
18};
19
20/// A compiled wasm module, containing everything necessary for instantiation.
21pub struct UniversalArtifact {
22    // TODO: figure out how to allocate fewer distinct structures onto heap. Maybe have an arena…?
23    pub(crate) engine: super::UniversalEngine,
24    pub(crate) _code_memory: super::CodeMemory,
25    pub(crate) import_counts: ImportCounts,
26    pub(crate) start_function: Option<FunctionIndex>,
27    pub(crate) vmoffsets: VMOffsets,
28    pub(crate) imports: Vec<VMImport>,
29    pub(crate) dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
30    pub(crate) functions: BoxedSlice<LocalFunctionIndex, VMLocalFunction>,
31    pub(crate) exports: BTreeMap<String, unc_vm_types::ExportIndex>,
32    pub(crate) signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
33    pub(crate) local_memories: Vec<(MemoryType, MemoryStyle)>,
34    pub(crate) data_segments: Vec<OwnedDataInitializer>,
35    pub(crate) passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
36    pub(crate) local_tables: Vec<(TableType, TableStyle)>,
37    pub(crate) element_segments: Vec<OwnedTableInitializer>,
38    // TODO: does this need to be a BTreeMap? Can it be a plain vector?
39    pub(crate) passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
40    pub(crate) local_globals: Vec<(GlobalType, GlobalInit)>,
41}
42
43impl UniversalArtifact {
44    /// Return the extents of the specified local function.
45    pub fn function_extent(&self, index: LocalFunctionIndex) -> Option<FunctionExtent> {
46        let func = self.functions.get(index)?;
47        Some(FunctionExtent { address: func.body, length: usize::try_from(func.length).unwrap() })
48    }
49
50    /// Return the engine instance this artifact is loaded into.
51    pub fn engine(&self) -> &super::UniversalEngine {
52        &self.engine
53    }
54}
55
56impl Instantiatable for UniversalArtifact {
57    type Error = InstantiationError;
58
59    unsafe fn instantiate(
60        self: Arc<Self>,
61        tunables: &dyn Tunables,
62        resolver: &dyn Resolver,
63        host_state: Box<dyn std::any::Any>,
64        config: unc_vm_types::InstanceConfig,
65    ) -> Result<InstanceHandle, Self::Error> {
66        let (imports, import_function_envs) = {
67            let mut imports = crate::resolve_imports(
68                &self.engine,
69                resolver,
70                &self.import_counts,
71                &self.imports,
72                &self.dynamic_function_trampolines,
73            )
74            .map_err(InstantiationError::Link)?;
75
76            // Get the `WasmerEnv::init_with_instance` function pointers and the pointers
77            // to the envs to call it on.
78            let import_function_envs = imports.get_imported_function_envs();
79
80            (imports, import_function_envs)
81        };
82
83        let (allocator, memory_definition_locations, table_definition_locations) =
84            unc_vm_vm::InstanceAllocator::new(self.vmoffsets.clone());
85
86        // Memories
87        let mut memories: PrimaryMap<unc_vm_types::LocalMemoryIndex, _> =
88            PrimaryMap::with_capacity(self.local_memories.len());
89        for (idx, (ty, style)) in (self.import_counts.memories..).zip(self.local_memories.iter()) {
90            let memory = tunables
91                .create_vm_memory(&ty, &style, memory_definition_locations[idx as usize])
92                .map_err(|e| {
93                    InstantiationError::Link(crate::LinkError::Resource(format!(
94                        "Failed to create memory: {}",
95                        e
96                    )))
97                })?;
98            memories.push(memory);
99        }
100
101        // Tables
102        let mut tables: PrimaryMap<unc_vm_types::LocalTableIndex, _> =
103            PrimaryMap::with_capacity(self.local_tables.len());
104        for (idx, (ty, style)) in (self.import_counts.tables..).zip(self.local_tables.iter()) {
105            let table = tunables
106                .create_vm_table(ty, style, table_definition_locations[idx as usize])
107                .map_err(|e| InstantiationError::Link(crate::LinkError::Resource(e)))?;
108            tables.push(table);
109        }
110
111        // Globals
112        let mut globals =
113            PrimaryMap::<LocalGlobalIndex, _>::with_capacity(self.local_globals.len());
114        for (ty, _) in self.local_globals.iter() {
115            globals.push(Arc::new(unc_vm_vm::Global::new(*ty)));
116        }
117
118        let passive_data = self.passive_data.clone();
119        Ok(InstanceHandle::new(
120            self,
121            allocator,
122            memories.into_boxed_slice(),
123            tables.into_boxed_slice(),
124            globals.into_boxed_slice(),
125            imports,
126            passive_data,
127            host_state,
128            import_function_envs,
129            config,
130        ))
131    }
132}
133
134impl Artifact for UniversalArtifact {
135    fn offsets(&self) -> &unc_vm_vm::VMOffsets {
136        &self.vmoffsets
137    }
138
139    fn import_counts(&self) -> &ImportCounts {
140        &self.import_counts
141    }
142
143    fn functions(&self) -> &BoxedSlice<LocalFunctionIndex, VMLocalFunction> {
144        &self.functions
145    }
146
147    fn passive_elements(&self) -> &BTreeMap<ElemIndex, Box<[FunctionIndex]>> {
148        &self.passive_elements
149    }
150
151    fn element_segments(&self) -> &[OwnedTableInitializer] {
152        &self.element_segments[..]
153    }
154
155    fn data_segments(&self) -> &[OwnedDataInitializer] {
156        &self.data_segments[..]
157    }
158
159    fn globals(&self) -> &[(GlobalType, GlobalInit)] {
160        &self.local_globals[..]
161    }
162
163    fn start_function(&self) -> Option<FunctionIndex> {
164        self.start_function
165    }
166
167    fn export_field(&self, name: &str) -> Option<unc_vm_types::ExportIndex> {
168        self.exports.get(name).cloned()
169    }
170
171    fn signatures(&self) -> &[unc_vm_vm::VMSharedSignatureIndex] {
172        self.signatures.values().as_slice()
173    }
174
175    fn function_signature(&self, index: FunctionIndex) -> Option<VMSharedSignatureIndex> {
176        match self.import_counts().local_function_index(index) {
177            Ok(local) => Some(self.functions[local].signature),
178            Err(import) => self
179                .imports
180                .iter()
181                .filter_map(|im| {
182                    if let VMImportType::Function { sig, .. } = im.ty {
183                        Some(sig)
184                    } else {
185                        None
186                    }
187                })
188                .nth(import.index()),
189        }
190    }
191}