1 use crate::compile::HashedEngineCompileEnv;
2 #[cfg(feature = "component-model")]
3 use crate::component::Component;
4 use crate::prelude::*;
5 use crate::runtime::vm::MmapVec;
6 use crate::{CodeBuilder, CodeMemory, Engine, Module};
7 use object::write::WritableBuffer;
8 use std::sync::Arc;
9 use wasmtime_environ::{FinishedObject, ObjectBuilder, ObjectKind};
10 
11 impl<'a> CodeBuilder<'a> {
12     fn compile_cached<T>(
13         &self,
14         build_artifacts: fn(&Engine, &[u8], Option<&[u8]>) -> Result<(MmapVecWrapper, Option<T>)>,
15     ) -> Result<(Arc<CodeMemory>, Option<T>)> {
16         let wasm = self.wasm_binary()?;
17         let dwarf_package = self.dwarf_package_binary();
18 
19         self.engine
20             .check_compatible_with_native_host()
21             .context("compilation settings are not compatible with the native host")?;
22 
23         #[cfg(feature = "cache")]
24         {
25             let state = (
26                 HashedEngineCompileEnv(self.engine),
27                 &wasm,
28                 &dwarf_package,
29                 // Don't hash this as it's just its own "pure" function pointer.
30                 NotHashed(build_artifacts),
31             );
32             let (code, info_and_types) =
33                 wasmtime_cache::ModuleCacheEntry::new("wasmtime", self.engine.cache_config())
34                     .get_data_raw(
35                         &state,
36                         // Cache miss, compute the actual artifacts
37                         |(engine, wasm, dwarf_package, build_artifacts)| -> Result<_> {
38                             let (mmap, info) =
39                                 (build_artifacts.0)(engine.0, wasm, dwarf_package.as_deref())?;
40                             let code = publish_mmap(mmap.0)?;
41                             Ok((code, info))
42                         },
43                         // Implementation of how to serialize artifacts
44                         |(_engine, _wasm, _, _), (code, _info_and_types)| {
45                             Some(code.mmap().to_vec())
46                         },
47                         // Cache hit, deserialize the provided artifacts
48                         |(engine, wasm, _, _), serialized_bytes| {
49                             let kind = if wasmparser::Parser::is_component(&wasm) {
50                                 ObjectKind::Component
51                             } else {
52                                 ObjectKind::Module
53                             };
54                             let code = engine.0.load_code_bytes(&serialized_bytes, kind).ok()?;
55                             Some((code, None))
56                         },
57                     )?;
58             return Ok((code, info_and_types));
59         }
60 
61         #[cfg(not(feature = "cache"))]
62         {
63             let (mmap, info_and_types) =
64                 build_artifacts(self.engine, &wasm, dwarf_package.as_deref())?;
65             let code = publish_mmap(mmap.0)?;
66             return Ok((code, info_and_types));
67         }
68 
69         struct NotHashed<T>(T);
70 
71         impl<T> std::hash::Hash for NotHashed<T> {
72             fn hash<H: std::hash::Hasher>(&self, _hasher: &mut H) {}
73         }
74     }
75 
76     /// Same as [`CodeBuilder::compile_module_serialized`] except that a
77     /// [`Module`](crate::Module) is produced instead.
78     ///
79     /// Note that this method will cache compilations if the `cache` feature is
80     /// enabled and turned on in [`Config`](crate::Config).
81     pub fn compile_module(&self) -> Result<Module> {
82         let (code, info_and_types) = self.compile_cached(super::build_artifacts)?;
83         Module::from_parts(self.engine, code, info_and_types)
84     }
85 
86     /// Same as [`CodeBuilder::compile_module`] except that it compiles a
87     /// [`Component`] instead of a module.
88     #[cfg(feature = "component-model")]
89     pub fn compile_component(&self) -> Result<Component> {
90         let (code, artifacts) = self.compile_cached(super::build_component_artifacts)?;
91         Component::from_parts(self.engine, code, artifacts)
92     }
93 }
94 
95 fn publish_mmap(mmap: MmapVec) -> Result<Arc<CodeMemory>> {
96     let mut code = CodeMemory::new(mmap)?;
97     code.publish()?;
98     Ok(Arc::new(code))
99 }
100 
101 pub(crate) struct MmapVecWrapper(pub MmapVec);
102 
103 impl FinishedObject for MmapVecWrapper {
104     fn finish_object(obj: ObjectBuilder<'_>) -> Result<Self> {
105         let mut result = ObjectMmap::default();
106         return match obj.finish(&mut result) {
107             Ok(()) => {
108                 assert!(result.mmap.is_some(), "no reserve");
109                 let mmap = result.mmap.expect("reserve not called");
110                 assert_eq!(mmap.len(), result.len);
111                 Ok(MmapVecWrapper(mmap))
112             }
113             Err(e) => match result.err.take() {
114                 Some(original) => Err(original.context(e)),
115                 None => Err(e.into()),
116             },
117         };
118 
119         /// Helper struct to implement the `WritableBuffer` trait from the `object`
120         /// crate.
121         ///
122         /// This enables writing an object directly into an mmap'd memory so it's
123         /// immediately usable for execution after compilation. This implementation
124         /// relies on a call to `reserve` happening once up front with all the needed
125         /// data, and the mmap internally does not attempt to grow afterwards.
126         #[derive(Default)]
127         struct ObjectMmap {
128             mmap: Option<MmapVec>,
129             len: usize,
130             err: Option<Error>,
131         }
132 
133         impl WritableBuffer for ObjectMmap {
134             fn len(&self) -> usize {
135                 self.len
136             }
137 
138             fn reserve(&mut self, additional: usize) -> Result<(), ()> {
139                 assert!(self.mmap.is_none(), "cannot reserve twice");
140                 self.mmap = match MmapVec::with_capacity(additional) {
141                     Ok(mmap) => Some(mmap),
142                     Err(e) => {
143                         self.err = Some(e);
144                         return Err(());
145                     }
146                 };
147                 Ok(())
148             }
149 
150             fn resize(&mut self, new_len: usize) {
151                 // Resizing always appends 0 bytes and since new mmaps start out as 0
152                 // bytes we don't actually need to do anything as part of this other
153                 // than update our own length.
154                 if new_len <= self.len {
155                     return;
156                 }
157                 self.len = new_len;
158             }
159 
160             fn write_bytes(&mut self, val: &[u8]) {
161                 let mmap = self.mmap.as_mut().expect("write before reserve");
162                 mmap[self.len..][..val.len()].copy_from_slice(val);
163                 self.len += val.len();
164             }
165         }
166     }
167 }
168