1use crate::CodeMemory;
4use crate::UniversalArtifact;
5use loupe::MemoryUsage;
6use std::sync::{Arc, Mutex};
7#[cfg(feature = "compiler")]
8use wasmer_compiler::Compiler;
9use wasmer_compiler::{
10 CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, Target,
11};
12use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, FunctionExtent, Tunables};
13use wasmer_engine_universal_artifact::UniversalEngineBuilder;
14use wasmer_types::entity::PrimaryMap;
15use wasmer_types::{
16 Features, FunctionIndex, FunctionType, LocalFunctionIndex, ModuleInfo, SignatureIndex,
17};
18use wasmer_vm::{
19 FuncDataRegistry, FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, VMCallerCheckedAnyfunc,
20 VMFuncRef, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
21};
22
23#[derive(Clone, MemoryUsage)]
25pub struct UniversalEngine {
26 inner: Arc<Mutex<UniversalEngineInner>>,
27 target: Arc<Target>,
29 engine_id: EngineId,
30}
31
32impl UniversalEngine {
33 #[cfg(feature = "compiler")]
35 pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
36 Self {
37 inner: Arc::new(Mutex::new(UniversalEngineInner {
38 builder: UniversalEngineBuilder::new(Some(compiler), features),
39 code_memory: vec![],
40 signatures: SignatureRegistry::new(),
41 func_data: Arc::new(FuncDataRegistry::new()),
42 })),
43 target: Arc::new(target),
44 engine_id: EngineId::default(),
45 }
46 }
47
48 pub fn headless() -> Self {
62 Self {
63 inner: Arc::new(Mutex::new(UniversalEngineInner {
64 builder: UniversalEngineBuilder::new(None, Features::default()),
65 code_memory: vec![],
66 signatures: SignatureRegistry::new(),
67 func_data: Arc::new(FuncDataRegistry::new()),
68 })),
69 target: Arc::new(Target::default()),
70 engine_id: EngineId::default(),
71 }
72 }
73
74 pub(crate) fn inner(&self) -> std::sync::MutexGuard<'_, UniversalEngineInner> {
75 self.inner.lock().unwrap()
76 }
77
78 pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, UniversalEngineInner> {
79 self.inner.lock().unwrap()
80 }
81}
82
83impl Engine for UniversalEngine {
84 fn target(&self) -> &Target {
86 &self.target
87 }
88
89 fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex {
91 let compiler = self.inner();
92 compiler.signatures().register(func_type)
93 }
94
95 fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
96 let compiler = self.inner();
97 compiler.func_data().register(func_data)
98 }
99
100 fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
102 let compiler = self.inner();
103 compiler.signatures().lookup(sig)
104 }
105
106 fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
108 self.inner().validate(binary)
109 }
110
111 #[cfg(feature = "compiler")]
113 fn compile(
114 &self,
115 binary: &[u8],
116 tunables: &dyn Tunables,
117 ) -> Result<Arc<dyn Artifact>, CompileError> {
118 Ok(Arc::new(UniversalArtifact::new(&self, binary, tunables)?))
119 }
120
121 #[cfg(not(feature = "compiler"))]
123 fn compile(
124 &self,
125 _binary: &[u8],
126 _tunables: &dyn Tunables,
127 ) -> Result<Arc<dyn Artifact>, CompileError> {
128 Err(CompileError::Codegen(
129 "The UniversalEngine is operating in headless mode, so it can not compile Modules."
130 .to_string(),
131 ))
132 }
133
134 unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
136 Ok(Arc::new(UniversalArtifact::deserialize(&self, &bytes)?))
137 }
138
139 fn id(&self) -> &EngineId {
140 &self.engine_id
141 }
142
143 fn cloned(&self) -> Arc<dyn Engine + Send + Sync> {
144 Arc::new(self.clone())
145 }
146}
147
148#[derive(MemoryUsage)]
150pub struct UniversalEngineInner {
151 builder: UniversalEngineBuilder,
153 code_memory: Vec<CodeMemory>,
156 signatures: SignatureRegistry,
159 func_data: Arc<FuncDataRegistry>,
163}
164
165impl UniversalEngineInner {
166 #[cfg(feature = "compiler")]
168 pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
169 self.builder.compiler()
170 }
171
172 pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
174 self.builder.validate(data)
175 }
176
177 pub fn features(&self) -> &Features {
179 self.builder.features()
180 }
181
182 pub fn builder_mut(&mut self) -> &mut UniversalEngineBuilder {
183 &mut self.builder
184 }
185
186 #[allow(clippy::type_complexity)]
188 pub(crate) fn allocate(
189 &mut self,
190 _module: &ModuleInfo,
191 functions: &PrimaryMap<LocalFunctionIndex, FunctionBody>,
192 function_call_trampolines: &PrimaryMap<SignatureIndex, FunctionBody>,
193 dynamic_function_trampolines: &PrimaryMap<FunctionIndex, FunctionBody>,
194 custom_sections: &PrimaryMap<SectionIndex, CustomSection>,
195 ) -> Result<
196 (
197 PrimaryMap<LocalFunctionIndex, FunctionExtent>,
198 PrimaryMap<SignatureIndex, VMTrampoline>,
199 PrimaryMap<FunctionIndex, FunctionBodyPtr>,
200 PrimaryMap<SectionIndex, SectionBodyPtr>,
201 ),
202 CompileError,
203 > {
204 let function_bodies = functions
205 .values()
206 .chain(function_call_trampolines.values())
207 .chain(dynamic_function_trampolines.values())
208 .collect::<Vec<_>>();
209 let (executable_sections, data_sections): (Vec<_>, _) = custom_sections
210 .values()
211 .partition(|section| section.protection == CustomSectionProtection::ReadExecute);
212 self.code_memory.push(CodeMemory::new());
213
214 let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
215 self.code_memory
216 .last_mut()
217 .unwrap()
218 .allocate(
219 function_bodies.as_slice(),
220 executable_sections.as_slice(),
221 data_sections.as_slice(),
222 )
223 .map_err(|message| {
224 CompileError::Resource(format!(
225 "failed to allocate memory for functions: {}",
226 message
227 ))
228 })?;
229
230 let allocated_functions_result = allocated_functions
231 .drain(0..functions.len())
232 .map(|slice| FunctionExtent {
233 ptr: FunctionBodyPtr(slice.as_ptr()),
234 length: slice.len(),
235 })
236 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
237
238 let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
239 PrimaryMap::new();
240 for ptr in allocated_functions
241 .drain(0..function_call_trampolines.len())
242 .map(|slice| slice.as_ptr())
243 {
244 let trampoline =
245 unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
246 allocated_function_call_trampolines.push(trampoline);
247 }
248
249 let allocated_dynamic_function_trampolines = allocated_functions
250 .drain(..)
251 .map(|slice| FunctionBodyPtr(slice.as_ptr()))
252 .collect::<PrimaryMap<FunctionIndex, _>>();
253
254 let mut exec_iter = allocated_executable_sections.iter();
255 let mut data_iter = allocated_data_sections.iter();
256 let allocated_custom_sections = custom_sections
257 .iter()
258 .map(|(_, section)| {
259 SectionBodyPtr(
260 if section.protection == CustomSectionProtection::ReadExecute {
261 exec_iter.next()
262 } else {
263 data_iter.next()
264 }
265 .unwrap()
266 .as_ptr(),
267 )
268 })
269 .collect::<PrimaryMap<SectionIndex, _>>();
270
271 Ok((
272 allocated_functions_result,
273 allocated_function_call_trampolines,
274 allocated_dynamic_function_trampolines,
275 allocated_custom_sections,
276 ))
277 }
278
279 pub(crate) fn publish_compiled_code(&mut self) {
281 self.code_memory.last_mut().unwrap().publish();
282 }
283
284 pub(crate) fn publish_eh_frame(&mut self, eh_frame: Option<&[u8]>) -> Result<(), CompileError> {
286 self.code_memory
287 .last_mut()
288 .unwrap()
289 .unwind_registry_mut()
290 .publish(eh_frame)
291 .map_err(|e| {
292 CompileError::Resource(format!("Error while publishing the unwind code: {}", e))
293 })?;
294 Ok(())
295 }
296
297 pub fn signatures(&self) -> &SignatureRegistry {
299 &self.signatures
300 }
301
302 pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
304 &self.func_data
305 }
306}