linera_wasmer_compiler/engine/
inner.rs1use crate::engine::builder::EngineBuilder;
4#[cfg(not(target_arch = "wasm32"))]
5use crate::Artifact;
6#[cfg(not(target_arch = "wasm32"))]
7use crate::BaseTunables;
8#[cfg(not(target_arch = "wasm32"))]
9use crate::CodeMemory;
10#[cfg(not(target_arch = "wasm32"))]
11use crate::GlobalFrameInfoRegistration;
12#[cfg(feature = "compiler")]
13use crate::{Compiler, CompilerConfig};
14#[cfg(not(target_arch = "wasm32"))]
15use crate::{FunctionExtent, Tunables};
16#[cfg(not(target_arch = "wasm32"))]
17use shared_buffer::OwnedBuffer;
18#[cfg(not(target_arch = "wasm32"))]
19use std::path::Path;
20use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
21use std::sync::{Arc, Mutex};
22use wasmer_types::HashAlgorithm;
23#[cfg(not(target_arch = "wasm32"))]
24use wasmer_types::{
25 entity::PrimaryMap, DeserializeError, FunctionBodyLike, FunctionIndex, FunctionType,
26 LocalFunctionIndex, SignatureIndex,
27};
28use wasmer_types::{CompileError, Features, ModuleInfo, Target};
29#[cfg(not(target_arch = "wasm32"))]
30use wasmer_types::{CustomSectionLike, CustomSectionProtection, SectionIndex};
31#[cfg(not(target_arch = "wasm32"))]
32use wasmer_vm::{
33 FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, VMFunctionBody, VMSharedSignatureIndex,
34 VMTrampoline,
35};
36
37#[derive(Clone)]
39pub struct Engine {
40 inner: Arc<Mutex<EngineInner>>,
41 target: Arc<Target>,
43 engine_id: EngineId,
44 #[cfg(not(target_arch = "wasm32"))]
45 tunables: Arc<dyn Tunables + Send + Sync>,
46 name: String,
47 hash_algorithm: Option<HashAlgorithm>,
48}
49
50impl Engine {
51 #[cfg(feature = "compiler")]
53 pub fn new(
54 compiler_config: Box<dyn CompilerConfig>,
55 target: Target,
56 features: Features,
57 ) -> Self {
58 #[cfg(not(target_arch = "wasm32"))]
59 let tunables = BaseTunables::for_target(&target);
60 let compiler = compiler_config.compiler();
61 let name = format!("engine-{}", compiler.name());
62 Self {
63 inner: Arc::new(Mutex::new(EngineInner {
64 compiler: Some(compiler),
65 features,
66 #[cfg(not(target_arch = "wasm32"))]
67 code_memory: vec![],
68 #[cfg(not(target_arch = "wasm32"))]
69 signatures: SignatureRegistry::new(),
70 })),
71 target: Arc::new(target),
72 engine_id: EngineId::default(),
73 #[cfg(not(target_arch = "wasm32"))]
74 tunables: Arc::new(tunables),
75 name,
76 hash_algorithm: None,
77 }
78 }
79
80 #[cfg(not(feature = "compiler"))]
81 pub fn new(
82 compiler_config: Box<dyn CompilerConfig>,
83 target: Target,
84 features: Features,
85 ) -> Self {
86 panic!("The engine is not compiled with any compiler support")
87 }
88
89 pub fn name(&self) -> &str {
91 self.name.as_str()
92 }
93
94 pub fn set_hash_algorithm(&mut self, hash_algorithm: Option<HashAlgorithm>) {
96 self.hash_algorithm = hash_algorithm;
97 }
98
99 pub fn hash_algorithm(&self) -> Option<HashAlgorithm> {
101 self.hash_algorithm
102 }
103
104 pub fn deterministic_id(&self) -> &str {
106 self.name.as_str()
111 }
112
113 pub fn headless() -> Self {
127 let target = Target::default();
128 #[cfg(not(target_arch = "wasm32"))]
129 let tunables = BaseTunables::for_target(&target);
130 Self {
131 inner: Arc::new(Mutex::new(EngineInner {
132 #[cfg(feature = "compiler")]
133 compiler: None,
134 #[cfg(feature = "compiler")]
135 features: Features::default(),
136 #[cfg(not(target_arch = "wasm32"))]
137 code_memory: vec![],
138 #[cfg(not(target_arch = "wasm32"))]
139 signatures: SignatureRegistry::new(),
140 })),
141 target: Arc::new(target),
142 engine_id: EngineId::default(),
143 #[cfg(not(target_arch = "wasm32"))]
144 tunables: Arc::new(tunables),
145 name: "engine-headless".to_string(),
146 hash_algorithm: None,
147 }
148 }
149
150 pub fn inner(&self) -> std::sync::MutexGuard<'_, EngineInner> {
152 self.inner.lock().unwrap()
153 }
154
155 pub fn inner_mut(&self) -> std::sync::MutexGuard<'_, EngineInner> {
157 self.inner.lock().unwrap()
158 }
159
160 pub fn target(&self) -> &Target {
162 &self.target
163 }
164
165 #[cfg(not(target_arch = "wasm32"))]
167 pub fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex {
168 let compiler = self.inner();
169 compiler.signatures().register(func_type)
170 }
171
172 #[cfg(not(target_arch = "wasm32"))]
174 pub fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
175 let compiler = self.inner();
176 compiler.signatures().lookup(sig)
177 }
178
179 #[cfg(feature = "compiler")]
181 pub fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
182 self.inner().validate(binary)
183 }
184
185 #[cfg(feature = "compiler")]
187 #[cfg(not(target_arch = "wasm32"))]
188 pub fn compile(&self, binary: &[u8]) -> Result<Arc<Artifact>, CompileError> {
189 Ok(Arc::new(Artifact::new(
190 self,
191 binary,
192 self.tunables.as_ref(),
193 self.hash_algorithm,
194 )?))
195 }
196
197 #[cfg(not(feature = "compiler"))]
199 #[cfg(not(target_arch = "wasm32"))]
200 pub fn compile(
201 &self,
202 _binary: &[u8],
203 _tunables: &dyn Tunables,
204 ) -> Result<Arc<Artifact>, CompileError> {
205 Err(CompileError::Codegen(
206 "The Engine is operating in headless mode, so it can not compile Modules.".to_string(),
207 ))
208 }
209
210 #[cfg(not(target_arch = "wasm32"))]
211 pub unsafe fn deserialize_unchecked(
218 &self,
219 bytes: OwnedBuffer,
220 ) -> Result<Arc<Artifact>, DeserializeError> {
221 Ok(Arc::new(Artifact::deserialize_unchecked(self, bytes)?))
222 }
223
224 #[cfg(not(target_arch = "wasm32"))]
231 pub unsafe fn deserialize(
232 &self,
233 bytes: OwnedBuffer,
234 ) -> Result<Arc<Artifact>, DeserializeError> {
235 Ok(Arc::new(Artifact::deserialize(self, bytes)?))
236 }
237
238 #[cfg(not(target_arch = "wasm32"))]
243 pub unsafe fn deserialize_from_file(
244 &self,
245 file_ref: &Path,
246 ) -> Result<Arc<Artifact>, DeserializeError> {
247 let file = std::fs::File::open(file_ref)?;
248 self.deserialize(
249 OwnedBuffer::from_file(&file).map_err(|e| DeserializeError::Generic(e.to_string()))?,
250 )
251 }
252
253 #[cfg(not(target_arch = "wasm32"))]
259 pub unsafe fn deserialize_from_file_unchecked(
260 &self,
261 file_ref: &Path,
262 ) -> Result<Arc<Artifact>, DeserializeError> {
263 let file = std::fs::File::open(file_ref)?;
264 self.deserialize_unchecked(
265 OwnedBuffer::from_file(&file).map_err(|e| DeserializeError::Generic(e.to_string()))?,
266 )
267 }
268
269 pub fn id(&self) -> &EngineId {
275 &self.engine_id
276 }
277
278 pub fn cloned(&self) -> Self {
280 self.clone()
281 }
282
283 #[cfg(not(target_arch = "wasm32"))]
285 pub fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) {
286 self.tunables = Arc::new(tunables);
287 }
288
289 #[cfg(not(target_arch = "wasm32"))]
291 pub fn tunables(&self) -> &dyn Tunables {
292 self.tunables.as_ref()
293 }
294}
295
296impl std::fmt::Debug for Engine {
297 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
298 f.debug_struct("Engine")
299 .field("target", &self.target)
300 .field("engine_id", &self.engine_id)
301 .field("name", &self.name)
302 .finish()
303 }
304}
305
306pub struct EngineInner {
308 #[cfg(feature = "compiler")]
309 compiler: Option<Box<dyn Compiler>>,
311 #[cfg(feature = "compiler")]
312 features: Features,
314 #[cfg(not(target_arch = "wasm32"))]
317 code_memory: Vec<CodeMemory>,
318 #[cfg(not(target_arch = "wasm32"))]
321 signatures: SignatureRegistry,
322}
323
324impl EngineInner {
325 #[cfg(feature = "compiler")]
327 pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
328 match self.compiler.as_ref() {
329 None => Err(CompileError::Codegen(
330 "No compiler compiled into executable".to_string(),
331 )),
332 Some(compiler) => Ok(&**compiler),
333 }
334 }
335
336 #[cfg(feature = "compiler")]
338 pub fn validate(&self, data: &[u8]) -> Result<(), CompileError> {
339 let compiler = self.compiler()?;
340 compiler.validate_module(&self.features, data)
341 }
342
343 #[cfg(feature = "compiler")]
345 pub fn features(&self) -> &Features {
346 &self.features
347 }
348
349 #[cfg(not(target_arch = "wasm32"))]
351 #[allow(clippy::type_complexity)]
352 pub(crate) fn allocate<'a, FunctionBody, CustomSection>(
353 &'a mut self,
354 _module: &ModuleInfo,
355 functions: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
356 function_call_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
357 dynamic_function_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
358 custom_sections: impl ExactSizeIterator<Item = &'a CustomSection> + Clone + 'a,
359 ) -> Result<
360 (
361 PrimaryMap<LocalFunctionIndex, FunctionExtent>,
362 PrimaryMap<SignatureIndex, VMTrampoline>,
363 PrimaryMap<FunctionIndex, FunctionBodyPtr>,
364 PrimaryMap<SectionIndex, SectionBodyPtr>,
365 ),
366 CompileError,
367 >
368 where
369 FunctionBody: FunctionBodyLike<'a> + 'a,
370 CustomSection: CustomSectionLike<'a> + 'a,
371 {
372 let functions_len = functions.len();
373 let function_call_trampolines_len = function_call_trampolines.len();
374
375 let function_bodies = functions
376 .chain(function_call_trampolines)
377 .chain(dynamic_function_trampolines)
378 .collect::<Vec<_>>();
379 let (executable_sections, data_sections): (Vec<_>, _) = custom_sections
380 .clone()
381 .partition(|section| *section.protection() == CustomSectionProtection::ReadExecute);
382 self.code_memory.push(CodeMemory::new());
383
384 let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
385 self.code_memory
386 .last_mut()
387 .unwrap()
388 .allocate(
389 function_bodies.as_slice(),
390 executable_sections.as_slice(),
391 data_sections.as_slice(),
392 )
393 .map_err(|message| {
394 CompileError::Resource(format!(
395 "failed to allocate memory for functions: {}",
396 message
397 ))
398 })?;
399
400 let allocated_functions_result = allocated_functions
401 .drain(0..functions_len)
402 .map(|slice| FunctionExtent {
403 ptr: FunctionBodyPtr(slice.as_ptr()),
404 length: slice.len(),
405 })
406 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
407
408 let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
409 PrimaryMap::new();
410 for ptr in allocated_functions
411 .drain(0..function_call_trampolines_len)
412 .map(|slice| slice.as_ptr())
413 {
414 let trampoline =
415 unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
416 allocated_function_call_trampolines.push(trampoline);
417 }
418
419 let allocated_dynamic_function_trampolines = allocated_functions
420 .drain(..)
421 .map(|slice| FunctionBodyPtr(slice.as_ptr()))
422 .collect::<PrimaryMap<FunctionIndex, _>>();
423
424 let mut exec_iter = allocated_executable_sections.iter();
425 let mut data_iter = allocated_data_sections.iter();
426 let allocated_custom_sections = custom_sections
427 .map(|section| {
428 SectionBodyPtr(
429 if *section.protection() == CustomSectionProtection::ReadExecute {
430 exec_iter.next()
431 } else {
432 data_iter.next()
433 }
434 .unwrap()
435 .as_ptr(),
436 )
437 })
438 .collect::<PrimaryMap<SectionIndex, _>>();
439
440 Ok((
441 allocated_functions_result,
442 allocated_function_call_trampolines,
443 allocated_dynamic_function_trampolines,
444 allocated_custom_sections,
445 ))
446 }
447
448 #[cfg(not(target_arch = "wasm32"))]
449 pub(crate) fn publish_compiled_code(&mut self) {
451 self.code_memory.last_mut().unwrap().publish();
452 }
453
454 #[cfg(not(target_arch = "wasm32"))]
455 pub(crate) fn publish_eh_frame(&mut self, eh_frame: Option<&[u8]>) -> Result<(), CompileError> {
457 self.code_memory
458 .last_mut()
459 .unwrap()
460 .unwind_registry_mut()
461 .publish(eh_frame)
462 .map_err(|e| {
463 CompileError::Resource(format!("Error while publishing the unwind code: {}", e))
464 })?;
465 Ok(())
466 }
467
468 #[cfg(not(target_arch = "wasm32"))]
470 pub fn signatures(&self) -> &SignatureRegistry {
471 &self.signatures
472 }
473
474 #[cfg(not(target_arch = "wasm32"))]
475 pub(crate) fn register_frame_info(&mut self, frame_info: GlobalFrameInfoRegistration) {
477 self.code_memory
478 .last_mut()
479 .unwrap()
480 .register_frame_info(frame_info);
481 }
482}
483
484#[cfg(feature = "compiler")]
485impl From<Box<dyn CompilerConfig>> for Engine {
486 fn from(config: Box<dyn CompilerConfig>) -> Self {
487 EngineBuilder::new(config).engine()
488 }
489}
490
491impl From<EngineBuilder> for Engine {
492 fn from(engine_builder: EngineBuilder) -> Self {
493 engine_builder.engine()
494 }
495}
496
497impl From<&Self> for Engine {
498 fn from(engine_ref: &Self) -> Self {
499 engine_ref.cloned()
500 }
501}
502
503#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
504#[repr(transparent)]
505pub struct EngineId {
507 id: usize,
508}
509
510impl EngineId {
511 pub fn id(&self) -> String {
513 format!("{}", &self.id)
514 }
515}
516
517impl Clone for EngineId {
518 fn clone(&self) -> Self {
519 Self::default()
520 }
521}
522
523impl Default for EngineId {
524 fn default() -> Self {
525 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
526 Self {
527 id: NEXT_ID.fetch_add(1, SeqCst),
528 }
529 }
530}