1use crate::executable::{unrkyv, UniversalExecutableRef};
4use crate::{CodeMemory, UniversalArtifact, UniversalExecutable};
5use rkyv::de::deserializers::SharedDeserializeMap;
6use std::collections::BTreeMap;
7use std::convert::TryFrom;
8use std::sync::{Arc, Mutex};
9#[cfg(feature = "compiler")]
10use wasmer_compiler::Compiler;
11use wasmer_compiler::{
12 CompileError, CustomSectionProtection, CustomSectionRef, FunctionBodyRef, JumpTable,
13 SectionIndex, Target,
14};
15use wasmer_engine::{Engine, EngineId};
16use wasmer_types::entity::{EntityRef, PrimaryMap};
17use wasmer_types::{
18 DataInitializer, ExportIndex, Features, FunctionIndex, FunctionType, FunctionTypeRef,
19 GlobalInit, GlobalType, ImportCounts, ImportIndex, LocalFunctionIndex, LocalGlobalIndex,
20 MemoryIndex, SignatureIndex, TableIndex,
21};
22use wasmer_vm::{
23 FuncDataRegistry, FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, Tunables,
24 VMCallerCheckedAnyfunc, VMFuncRef, VMFunctionBody, VMImportType, VMLocalFunction, VMOffsets,
25 VMSharedSignatureIndex, VMTrampoline,
26};
27
28#[derive(Clone)]
30pub struct UniversalEngine {
31 inner: Arc<Mutex<UniversalEngineInner>>,
32 target: Arc<Target>,
34 engine_id: EngineId,
35}
36
37impl UniversalEngine {
38 #[cfg(feature = "compiler")]
40 pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
41 Self {
42 inner: Arc::new(Mutex::new(UniversalEngineInner {
43 compiler: Some(compiler),
44 code_memory: vec![],
45 signatures: SignatureRegistry::new(),
46 func_data: Arc::new(FuncDataRegistry::new()),
47 features,
48 })),
49 target: Arc::new(target),
50 engine_id: EngineId::default(),
51 }
52 }
53
54 pub fn headless() -> Self {
68 Self {
69 inner: Arc::new(Mutex::new(UniversalEngineInner {
70 #[cfg(feature = "compiler")]
71 compiler: None,
72 code_memory: vec![],
73 signatures: SignatureRegistry::new(),
74 func_data: Arc::new(FuncDataRegistry::new()),
75 features: Features::default(),
76 })),
77 target: Arc::new(Target::default()),
78 engine_id: EngineId::default(),
79 }
80 }
81
82 pub(crate) fn inner(&self) -> std::sync::MutexGuard<'_, UniversalEngineInner> {
83 self.inner.lock().unwrap()
84 }
85
86 pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, UniversalEngineInner> {
87 self.inner.lock().unwrap()
88 }
89
90 #[cfg(feature = "compiler")]
92 pub fn compile_universal(
93 &self,
94 binary: &[u8],
95 tunables: &dyn Tunables,
96 ) -> Result<crate::UniversalExecutable, CompileError> {
97 let inner_engine = self.inner_mut();
98 let features = inner_engine.features();
99 let compiler = inner_engine.compiler()?;
100 let environ = wasmer_compiler::ModuleEnvironment::new();
101 let translation = environ.translate(binary).map_err(CompileError::Wasm)?;
102
103 let memory_styles: PrimaryMap<wasmer_types::MemoryIndex, _> = translation
104 .module
105 .memories
106 .values()
107 .map(|memory_type| tunables.memory_style(memory_type))
108 .collect();
109 let table_styles: PrimaryMap<wasmer_types::TableIndex, _> = translation
110 .module
111 .tables
112 .values()
113 .map(|table_type| tunables.table_style(table_type))
114 .collect();
115
116 let compile_info = wasmer_compiler::CompileModuleInfo {
118 module: Arc::new(translation.module),
119 features: features.clone(),
120 memory_styles,
121 table_styles,
122 };
123 let compilation = compiler.compile_module(
124 &self.target(),
125 &compile_info,
126 translation.module_translation_state.as_ref().unwrap(),
130 translation.function_body_inputs,
131 )?;
132 let function_call_trampolines = compilation.get_function_call_trampolines();
133 let dynamic_function_trampolines = compilation.get_dynamic_function_trampolines();
134 let data_initializers = translation
135 .data_initializers
136 .iter()
137 .map(wasmer_types::OwnedDataInitializer::new)
138 .collect();
139
140 let frame_infos = compilation.get_frame_info();
141 Ok(crate::UniversalExecutable {
142 function_bodies: compilation.get_function_bodies(),
143 function_relocations: compilation.get_relocations(),
144 function_jt_offsets: compilation.get_jt_offsets(),
145 function_frame_info: frame_infos,
146 function_call_trampolines,
147 dynamic_function_trampolines,
148 custom_sections: compilation.get_custom_sections(),
149 custom_section_relocations: compilation.get_custom_section_relocations(),
150 debug: compilation.get_debug(),
151 trampolines: compilation.get_trampolines(),
152 compile_info,
153 data_initializers,
154 cpu_features: self.target().cpu_features().as_u64(),
155 })
156 }
157
158 pub fn load_universal_executable(
160 &self,
161 executable: &UniversalExecutable,
162 ) -> Result<UniversalArtifact, CompileError> {
163 let info = &executable.compile_info;
164 let module = &info.module;
165 let local_memories = (module.import_counts.memories as usize..module.memories.len())
166 .map(|idx| {
167 let idx = MemoryIndex::new(idx);
168 (module.memories[idx], info.memory_styles[idx].clone())
169 })
170 .collect();
171 let local_tables = (module.import_counts.tables as usize..module.tables.len())
172 .map(|idx| {
173 let idx = TableIndex::new(idx);
174 (module.tables[idx], info.table_styles[idx].clone())
175 })
176 .collect();
177 let local_globals: Vec<(GlobalType, GlobalInit)> = module
178 .globals
179 .iter()
180 .skip(module.import_counts.globals as usize)
181 .enumerate()
182 .map(|(idx, (_, t))| {
183 let init = module.global_initializers[LocalGlobalIndex::new(idx)];
184 (*t, init)
185 })
186 .collect();
187 let mut inner_engine = self.inner_mut();
188
189 let local_functions = executable.function_bodies.iter().map(|(_, b)| b.into());
190 let function_call_trampolines = &executable.function_call_trampolines;
191 let dynamic_function_trampolines = &executable.dynamic_function_trampolines;
192 let signatures = module
193 .signatures
194 .iter()
195 .map(|(_, sig)| inner_engine.signatures.register(sig.into()))
196 .collect::<PrimaryMap<SignatureIndex, _>>()
197 .into_boxed_slice();
198 let (functions, trampolines, dynamic_trampolines, custom_sections) = inner_engine
199 .allocate(
200 local_functions,
201 function_call_trampolines.iter().map(|(_, b)| b.into()),
202 dynamic_function_trampolines.iter().map(|(_, b)| b.into()),
203 executable.custom_sections.iter().map(|(_, s)| s.into()),
204 |idx: LocalFunctionIndex| {
205 let func_idx = module.import_counts.function_index(idx);
206 let sig_idx = module.functions[func_idx];
207 (sig_idx, signatures[sig_idx])
208 },
209 )?;
210 let imports = module
211 .imports
212 .iter()
213 .map(|((module_name, field, idx), entity)| wasmer_vm::VMImport {
214 module: String::from(module_name),
215 field: String::from(field),
216 import_no: *idx,
217 ty: match entity {
218 ImportIndex::Function(i) => {
219 let sig_idx = module.functions[*i];
220 VMImportType::Function {
221 sig: signatures[sig_idx],
222 static_trampoline: trampolines[sig_idx],
223 }
224 }
225 ImportIndex::Table(i) => VMImportType::Table(module.tables[*i]),
226 &ImportIndex::Memory(i) => {
227 let ty = module.memories[i];
228 VMImportType::Memory(ty, info.memory_styles[i].clone())
229 }
230 ImportIndex::Global(i) => VMImportType::Global(module.globals[*i]),
231 },
232 })
233 .collect();
234
235 let function_relocations = executable.function_relocations.iter();
236 let section_relocations = executable.custom_section_relocations.iter();
237 crate::link_module(
238 &functions,
239 |func_idx, jt_idx| executable.function_jt_offsets[func_idx][jt_idx],
240 function_relocations.map(|(i, rs)| (i, rs.iter().cloned())),
241 &custom_sections,
242 section_relocations.map(|(i, rs)| (i, rs.iter().cloned())),
243 &executable.trampolines,
244 );
245
246 inner_engine.publish_compiled_code();
248 if let Some(ref d) = executable.debug {
249 unsafe {
250 inner_engine.publish_eh_frame(std::slice::from_raw_parts(
252 *custom_sections[d.eh_frame],
253 executable.custom_sections[d.eh_frame].bytes.len(),
254 ))?;
255 }
256 }
257 let exports = module
258 .exports
259 .iter()
260 .map(|(s, i)| (s.clone(), i.clone()))
261 .collect::<BTreeMap<String, ExportIndex>>();
262
263 Ok(UniversalArtifact {
264 engine: self.clone(),
265 import_counts: module.import_counts,
266 start_function: module.start_function,
267 vmoffsets: VMOffsets::for_host().with_module_info(&*module),
268 imports,
269 dynamic_function_trampolines: dynamic_trampolines.into_boxed_slice(),
270 functions: functions.into_boxed_slice(),
271 exports,
272 signatures,
273 local_memories,
274 data_segments: executable.data_initializers.clone(),
275 passive_data: module.passive_data.clone(),
276 local_tables,
277 element_segments: module.table_initializers.clone(),
278 passive_elements: module.passive_elements.clone(),
279 local_globals,
280 })
281 }
282
283 pub fn load_universal_executable_ref(
285 &self,
286 executable: &UniversalExecutableRef,
287 ) -> Result<UniversalArtifact, CompileError> {
288 let info = &executable.compile_info;
289 let module = &info.module;
290 let import_counts: ImportCounts = unrkyv(&module.import_counts);
291 let local_memories = (import_counts.memories as usize..module.memories.len())
292 .map(|idx| {
293 let idx = MemoryIndex::new(idx);
294 let mty = &module.memories[&idx];
295 (unrkyv(mty), unrkyv(&info.memory_styles[&idx]))
296 })
297 .collect();
298 let local_tables = (import_counts.tables as usize..module.tables.len())
299 .map(|idx| {
300 let idx = TableIndex::new(idx);
301 let tty = &module.tables[&idx];
302 (unrkyv(tty), unrkyv(&info.table_styles[&idx]))
303 })
304 .collect();
305 let local_globals: Vec<(GlobalType, GlobalInit)> = module
306 .globals
307 .iter()
308 .skip(import_counts.globals as _)
309 .enumerate()
310 .map(|(idx, (_, t))| {
311 let init = unrkyv(&module.global_initializers[&LocalGlobalIndex::new(idx)]);
312 (*t, init)
313 })
314 .collect();
315
316 let passive_data =
317 rkyv::Deserialize::deserialize(&module.passive_data, &mut SharedDeserializeMap::new())
318 .map_err(|_| CompileError::Validate("could not deserialize passive data".into()))?;
319 let data_segments = executable.data_initializers.iter();
320 let data_segments = data_segments
321 .map(|s| DataInitializer::from(s).into())
322 .collect();
323 let element_segments = unrkyv(&module.table_initializers);
324 let passive_elements: BTreeMap<wasmer_types::ElemIndex, Box<[FunctionIndex]>> =
325 unrkyv(&module.passive_elements);
326
327 let import_counts: ImportCounts = unrkyv(&module.import_counts);
328 let mut inner_engine = self.inner_mut();
329
330 let local_functions = executable.function_bodies.iter().map(|(_, b)| b.into());
331 let call_trampolines = executable.function_call_trampolines.iter();
332 let dynamic_trampolines = executable.dynamic_function_trampolines.iter();
333 let signatures = module
334 .signatures
335 .values()
336 .map(|sig| inner_engine.signatures.register(sig.into()))
337 .collect::<PrimaryMap<SignatureIndex, _>>()
338 .into_boxed_slice();
339 let (functions, trampolines, dynamic_trampolines, custom_sections) = inner_engine
340 .allocate(
341 local_functions,
342 call_trampolines.map(|(_, b)| b.into()),
343 dynamic_trampolines.map(|(_, b)| b.into()),
344 executable.custom_sections.iter().map(|(_, s)| s.into()),
345 |idx: LocalFunctionIndex| {
346 let func_idx = import_counts.function_index(idx);
347 let sig_idx = module.functions[&func_idx];
348 (sig_idx, signatures[sig_idx])
349 },
350 )?;
351 let imports = {
352 module
353 .imports
354 .iter()
355 .map(|((module_name, field, idx), entity)| wasmer_vm::VMImport {
356 module: String::from(module_name.as_str()),
357 field: String::from(field.as_str()),
358 import_no: *idx,
359 ty: match entity {
360 ImportIndex::Function(i) => {
361 let sig_idx = module.functions[i];
362 VMImportType::Function {
363 sig: signatures[sig_idx],
364 static_trampoline: trampolines[sig_idx],
365 }
366 }
367 ImportIndex::Table(i) => VMImportType::Table(unrkyv(&module.tables[i])),
368 ImportIndex::Memory(i) => {
369 let ty = unrkyv(&module.memories[i]);
370 VMImportType::Memory(ty, unrkyv(&info.memory_styles[i]))
371 }
372 ImportIndex::Global(i) => VMImportType::Global(unrkyv(&module.globals[i])),
373 },
374 })
375 .collect()
376 };
377
378 let function_relocations = executable.function_relocations.iter();
379 let section_relocations = executable.custom_section_relocations.iter();
380 crate::link_module(
381 &functions,
382 |func_idx, jt_idx| {
383 let func_idx = rkyv::Archived::<LocalFunctionIndex>::new(func_idx.index());
384 let jt_idx = rkyv::Archived::<JumpTable>::new(jt_idx.index());
385 executable.function_jt_offsets[&func_idx][&jt_idx]
386 },
387 function_relocations.map(|(i, r)| (i, r.iter().map(unrkyv))),
388 &custom_sections,
389 section_relocations.map(|(i, r)| (i, r.iter().map(unrkyv))),
390 &unrkyv(&executable.trampolines),
391 );
392
393 inner_engine.publish_compiled_code();
395 if let rkyv::option::ArchivedOption::Some(ref d) = executable.debug {
396 unsafe {
397 let s = CustomSectionRef::from(&executable.custom_sections[&d.eh_frame]);
399 inner_engine.publish_eh_frame(std::slice::from_raw_parts(
400 *custom_sections[unrkyv(&d.eh_frame)],
401 s.bytes.len(),
402 ))?;
403 }
404 }
405 let exports = module
406 .exports
407 .iter()
408 .map(|(s, i)| (unrkyv(s), unrkyv(i)))
409 .collect::<BTreeMap<String, ExportIndex>>();
410 Ok(UniversalArtifact {
411 engine: self.clone(),
412 import_counts,
413 start_function: unrkyv(&module.start_function),
414 vmoffsets: VMOffsets::for_host().with_archived_module_info(&*module),
415 imports,
416 dynamic_function_trampolines: dynamic_trampolines.into_boxed_slice(),
417 functions: functions.into_boxed_slice(),
418 exports,
419 signatures,
420 local_memories,
421 data_segments,
422 passive_data,
423 local_tables,
424 element_segments,
425 passive_elements,
426 local_globals,
427 })
428 }
429}
430
431impl Engine for UniversalEngine {
432 fn target(&self) -> &Target {
434 &self.target
435 }
436
437 fn register_signature(&self, func_type: FunctionTypeRef<'_>) -> VMSharedSignatureIndex {
439 self.inner().signatures.register(func_type)
440 }
441
442 fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
443 self.inner().func_data().register(func_data)
444 }
445
446 fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
448 self.inner().signatures.lookup(sig).cloned()
449 }
450
451 fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
453 self.inner().validate(binary)
454 }
455
456 #[cfg(not(feature = "compiler"))]
457 fn compile(
458 &self,
459 binary: &[u8],
460 tunables: &dyn Tunables,
461 ) -> Result<Box<dyn wasmer_engine::Executable>, CompileError> {
462 return Err(CompileError::Codegen(
463 "The UniversalEngine is operating in headless mode, so it can not compile Modules."
464 .to_string(),
465 ));
466 }
467
468 #[cfg(feature = "compiler")]
470 fn compile(
471 &self,
472 binary: &[u8],
473 tunables: &dyn Tunables,
474 ) -> Result<Box<dyn wasmer_engine::Executable>, CompileError> {
475 self.compile_universal(binary, tunables)
476 .map(|ex| Box::new(ex) as _)
477 }
478
479 fn load(
480 &self,
481 executable: &(dyn wasmer_engine::Executable),
482 ) -> Result<Arc<dyn wasmer_vm::Artifact>, CompileError> {
483 executable.load(self)
484 }
485
486 fn id(&self) -> &EngineId {
487 &self.engine_id
488 }
489
490 fn cloned(&self) -> Arc<dyn Engine + Send + Sync> {
491 Arc::new(self.clone())
492 }
493}
494
495pub struct UniversalEngineInner {
497 #[cfg(feature = "compiler")]
499 compiler: Option<Box<dyn Compiler>>,
500 features: Features,
502 code_memory: Vec<CodeMemory>,
505 pub(crate) signatures: SignatureRegistry,
508 func_data: Arc<FuncDataRegistry>,
512}
513
514impl UniversalEngineInner {
515 #[cfg(feature = "compiler")]
517 pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
518 if self.compiler.is_none() {
519 return Err(CompileError::Codegen("The UniversalEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
520 }
521 Ok(&**self.compiler.as_ref().unwrap())
522 }
523
524 #[cfg(feature = "compiler")]
526 pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
527 self.compiler()?.validate_module(self.features(), data)
528 }
529
530 #[cfg(not(feature = "compiler"))]
532 pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
533 Err(CompileError::Validate(
534 "The UniversalEngine is not compiled with compiler support, which is required for validating"
535 .to_string(),
536 ))
537 }
538
539 pub fn features(&self) -> &Features {
541 &self.features
542 }
543
544 #[allow(clippy::type_complexity)]
546 pub(crate) fn allocate<'a>(
547 &mut self,
548 local_functions: impl ExactSizeIterator<Item = FunctionBodyRef<'a>>,
549 call_trampolines: impl ExactSizeIterator<Item = FunctionBodyRef<'a>>,
550 dynamic_trampolines: impl ExactSizeIterator<Item = FunctionBodyRef<'a>>,
551 custom_sections: impl ExactSizeIterator<Item = CustomSectionRef<'a>>,
552 function_signature: impl Fn(LocalFunctionIndex) -> (SignatureIndex, VMSharedSignatureIndex),
553 ) -> Result<
554 (
555 PrimaryMap<LocalFunctionIndex, VMLocalFunction>,
556 PrimaryMap<SignatureIndex, VMTrampoline>,
557 PrimaryMap<FunctionIndex, FunctionBodyPtr>,
558 PrimaryMap<SectionIndex, SectionBodyPtr>,
559 ),
560 CompileError,
561 > {
562 let code_memory = &mut self.code_memory;
563 let function_count = local_functions.len();
564 let call_trampoline_count = call_trampolines.len();
565 let function_bodies = call_trampolines
566 .chain(local_functions)
567 .chain(dynamic_trampolines)
568 .collect::<Vec<_>>();
569
570 let mut section_types = Vec::with_capacity(custom_sections.len());
572 let mut executable_sections = Vec::new();
573 let mut data_sections = Vec::new();
574 for section in custom_sections {
575 if let CustomSectionProtection::ReadExecute = section.protection {
576 executable_sections.push(section);
577 } else {
578 data_sections.push(section);
579 }
580 section_types.push(section.protection);
581 }
582 code_memory.push(CodeMemory::new());
583 let code_memory = self.code_memory.last_mut().expect("infallible");
584
585 let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
586 code_memory
587 .allocate(
588 function_bodies.as_slice(),
589 executable_sections.as_slice(),
590 data_sections.as_slice(),
591 )
592 .map_err(|message| {
593 CompileError::Resource(format!(
594 "failed to allocate memory for functions: {}",
595 message
596 ))
597 })?;
598
599 let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
600 PrimaryMap::new();
601 for ptr in allocated_functions
602 .drain(0..call_trampoline_count)
603 .map(|slice| slice.as_ptr())
604 {
605 let trampoline =
607 unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
608 allocated_function_call_trampolines.push(trampoline);
609 }
610
611 let allocated_functions_result = allocated_functions
612 .drain(0..function_count)
613 .enumerate()
614 .map(|(index, slice)| -> Result<_, CompileError> {
615 let index = LocalFunctionIndex::new(index);
616 let (sig_idx, sig) = function_signature(index);
617 Ok(VMLocalFunction {
618 body: FunctionBodyPtr(slice.as_ptr()),
619 length: u32::try_from(slice.len()).map_err(|_| {
620 CompileError::Codegen("function body length exceeds 4GiB".into())
621 })?,
622 signature: sig,
623 trampoline: allocated_function_call_trampolines[sig_idx],
624 })
625 })
626 .collect::<Result<PrimaryMap<LocalFunctionIndex, _>, _>>()?;
627
628 let allocated_dynamic_function_trampolines = allocated_functions
629 .drain(..)
630 .map(|slice| FunctionBodyPtr(slice.as_ptr()))
631 .collect::<PrimaryMap<FunctionIndex, _>>();
632
633 let mut exec_iter = allocated_executable_sections.iter();
634 let mut data_iter = allocated_data_sections.iter();
635 let allocated_custom_sections = section_types
636 .into_iter()
637 .map(|protection| {
638 SectionBodyPtr(
639 if protection == CustomSectionProtection::ReadExecute {
640 exec_iter.next()
641 } else {
642 data_iter.next()
643 }
644 .unwrap()
645 .as_ptr(),
646 )
647 })
648 .collect::<PrimaryMap<SectionIndex, _>>();
649
650 Ok((
651 allocated_functions_result,
652 allocated_function_call_trampolines,
653 allocated_dynamic_function_trampolines,
654 allocated_custom_sections,
655 ))
656 }
657
658 pub(crate) fn publish_compiled_code(&mut self) {
660 self.code_memory.last_mut().unwrap().publish();
661 }
662
663 pub(crate) fn publish_eh_frame(&mut self, eh_frame: &[u8]) -> Result<(), CompileError> {
665 self.code_memory
666 .last_mut()
667 .unwrap()
668 .unwind_registry_mut()
669 .publish(eh_frame)
670 .map_err(|e| {
671 CompileError::Resource(format!("Error while publishing the unwind code: {}", e))
672 })?;
673 Ok(())
674 }
675
676 pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
678 &self.func_data
679 }
680}