1#[cfg(feature = "component-model")]
2use crate::component::Component;
3use crate::prelude::*;
4use crate::runtime::vm::MmapVec;
5use crate::{CodeBuilder, CodeMemory, Engine, Module};
6use object::write::WritableBuffer;
7use std::sync::Arc;
8use wasmtime_environ::{FinishedObject, ObjectBuilder};
9
10impl<'a> CodeBuilder<'a> {
11 fn compile_cached<T, S>(
12 &self,
13 build_artifacts: fn(
14 &Engine,
15 &[u8],
16 Option<&[u8]>,
17 &S,
18 ) -> Result<(MmapVecWrapper, Option<T>)>,
19 state: &S,
20 ) -> Result<(Arc<CodeMemory>, Option<T>)> {
21 let wasm = self.get_wasm()?;
22 let dwarf_package = self.get_dwarf_package();
23
24 self.engine
25 .check_compatible_with_native_host()
26 .context("compilation settings are not compatible with the native host")?;
27
28 #[cfg(feature = "cache")]
29 {
30 let state = (
31 crate::compile::HashedEngineCompileEnv(self.engine),
32 &wasm,
33 &dwarf_package,
34 NotHashed(build_artifacts),
36 NotHashed(state),
40 );
41 let (code, info_and_types) =
42 wasmtime_cache::ModuleCacheEntry::new("wasmtime", self.engine.cache_config())
43 .get_data_raw(
44 &state,
45 |(engine, wasm, dwarf_package, build_artifacts, state)| -> Result<_> {
47 let (mmap, info) = (build_artifacts.0)(
48 engine.0,
49 wasm,
50 dwarf_package.as_deref(),
51 state.0,
52 )?;
53 let code = publish_mmap(engine.0, mmap.0)?;
54 Ok((code, info))
55 },
56 |(_engine, _wasm, _, _, _), (code, _info_and_types)| {
58 Some(code.mmap().to_vec())
59 },
60 |(engine, wasm, _, _, _), serialized_bytes| {
62 let kind = if wasmparser::Parser::is_component(&wasm) {
63 wasmtime_environ::ObjectKind::Component
64 } else {
65 wasmtime_environ::ObjectKind::Module
66 };
67 let code = engine.0.load_code_bytes(&serialized_bytes, kind).ok()?;
68 Some((code, None))
69 },
70 )?;
71 return Ok((code, info_and_types));
72
73 struct NotHashed<T>(T);
74
75 impl<T> std::hash::Hash for NotHashed<T> {
76 fn hash<H: std::hash::Hasher>(&self, _hasher: &mut H) {}
77 }
78 }
79
80 #[cfg(not(feature = "cache"))]
81 {
82 let (mmap, info_and_types) =
83 build_artifacts(self.engine, &wasm, dwarf_package.as_deref(), state)?;
84 let code = publish_mmap(self.engine, mmap.0)?;
85 return Ok((code, info_and_types));
86 }
87 }
88
89 pub fn compile_module(&self) -> Result<Module> {
95 let custom_alignment = self.custom_alignment();
96 let (code, info_and_types) =
97 self.compile_cached(super::build_artifacts, &custom_alignment)?;
98 Module::from_parts(self.engine, code, info_and_types)
99 }
100
101 #[cfg(feature = "component-model")]
104 pub fn compile_component(&self) -> Result<Component> {
105 let custom_alignment = self.custom_alignment();
106 let (code, artifacts) =
107 self.compile_cached(super::build_component_artifacts, &custom_alignment)?;
108 Component::from_parts(self.engine, code, artifacts)
109 }
110
111 fn custom_alignment(&self) -> CustomAlignment {
112 CustomAlignment {
113 alignment: self
114 .engine
115 .custom_code_memory()
116 .map(|c| c.required_alignment())
117 .unwrap_or(1),
118 }
119 }
120}
121
122fn publish_mmap(engine: &Engine, mmap: MmapVec) -> Result<Arc<CodeMemory>> {
123 let mut code = CodeMemory::new(engine, mmap)?;
124 code.publish()?;
125 Ok(Arc::new(code))
126}
127
128pub(crate) struct MmapVecWrapper(pub MmapVec);
129
130pub(crate) struct CustomAlignment {
133 alignment: usize,
134}
135
136impl FinishedObject for MmapVecWrapper {
137 type State = CustomAlignment;
138 fn finish_object(obj: ObjectBuilder<'_>, align: &CustomAlignment) -> Result<Self> {
139 let mut result = ObjectMmap::default();
140 result.alignment = align.alignment;
141 return match obj.finish(&mut result) {
142 Ok(()) => {
143 assert!(result.mmap.is_some(), "no reserve");
144 let mmap = result.mmap.expect("reserve not called");
145 assert_eq!(mmap.len(), result.len);
146 Ok(MmapVecWrapper(mmap))
147 }
148 Err(e) => match result.err.take() {
149 Some(original) => Err(original.context(e)),
150 None => Err(e.into()),
151 },
152 };
153
154 #[derive(Default)]
162 struct ObjectMmap {
163 mmap: Option<MmapVec>,
164 len: usize,
165 alignment: usize,
166 err: Option<Error>,
167 }
168
169 impl WritableBuffer for ObjectMmap {
170 fn len(&self) -> usize {
171 self.len
172 }
173
174 fn reserve(&mut self, additional: usize) -> Result<(), ()> {
175 assert!(self.mmap.is_none(), "cannot reserve twice");
176 self.mmap = match MmapVec::with_capacity_and_alignment(additional, self.alignment) {
177 Ok(mmap) => Some(mmap),
178 Err(e) => {
179 self.err = Some(e);
180 return Err(());
181 }
182 };
183 Ok(())
184 }
185
186 fn resize(&mut self, new_len: usize) {
187 if new_len <= self.len {
191 return;
192 }
193 self.len = new_len;
194 }
195
196 fn write_bytes(&mut self, val: &[u8]) {
197 let mmap = self.mmap.as_mut().expect("write before reserve");
198 unsafe {
201 mmap.as_mut_slice()[self.len..][..val.len()].copy_from_slice(val);
202 }
203 self.len += val.len();
204 }
205 }
206 }
207}