1use 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
20pub struct UniversalArtifact {
22 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 pub(crate) passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
40 pub(crate) local_globals: Vec<(GlobalType, GlobalInit)>,
41}
42
43impl UniversalArtifact {
44 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 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 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 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 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 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}