dusk_wasmtime/compile/
runtime.rs1use crate::compile::HashedEngineCompileEnv;
2#[cfg(feature = "component-model")]
3use crate::component::Component;
4use crate::{CodeBuilder, CodeMemory, Engine, Module};
5use anyhow::{Context, Error, Result};
6use object::write::WritableBuffer;
7use std::sync::Arc;
8use wasmtime_environ::{FinishedObject, ObjectBuilder, ObjectKind};
9use wasmtime_runtime::MmapVec;
10
11impl<'a> CodeBuilder<'a> {
12 fn compile_cached<T>(
13 &self,
14 build_artifacts: fn(&Engine, &[u8]) -> Result<(MmapVecWrapper, Option<T>)>,
15 ) -> Result<(Arc<CodeMemory>, Option<T>)> {
16 let wasm = self.wasm_binary()?;
17
18 self.engine
19 .check_compatible_with_native_host()
20 .context("compilation settings are not compatible with the native host")?;
21
22 #[cfg(feature = "cache")]
23 {
24 let state = (
25 HashedEngineCompileEnv(self.engine),
26 &wasm,
27 NotHashed(build_artifacts),
29 );
30 let (code, info_and_types) =
31 wasmtime_cache::ModuleCacheEntry::new("wasmtime", self.engine.cache_config())
32 .get_data_raw(
33 &state,
34 |(engine, wasm, build_artifacts)| -> Result<_> {
36 let (mmap, info) = (build_artifacts.0)(engine.0, wasm)?;
37 let code = publish_mmap(mmap.0)?;
38 Ok((code, info))
39 },
40 |(_engine, _wasm, _), (code, _info_and_types)| Some(code.mmap().to_vec()),
42 |(engine, wasm, _), serialized_bytes| {
44 let kind = if wasmparser::Parser::is_component(&wasm) {
45 ObjectKind::Component
46 } else {
47 ObjectKind::Module
48 };
49 let code = engine.0.load_code_bytes(&serialized_bytes, kind).ok()?;
50 Some((code, None))
51 },
52 )?;
53 return Ok((code, info_and_types));
54 }
55
56 #[cfg(not(feature = "cache"))]
57 {
58 let (mmap, info_and_types) = build_artifacts(self.engine, &wasm)?;
59 let code = publish_mmap(mmap.0)?;
60 return Ok((code, info_and_types));
61 }
62
63 struct NotHashed<T>(T);
64
65 impl<T> std::hash::Hash for NotHashed<T> {
66 fn hash<H: std::hash::Hasher>(&self, _hasher: &mut H) {}
67 }
68 }
69
70 #[cfg_attr(docsrs, doc(cfg(feature = "runtime")))]
76 pub fn compile_module(&self) -> Result<Module> {
77 let (code, info_and_types) = self.compile_cached(super::build_artifacts)?;
78 Module::from_parts(self.engine, code, info_and_types)
79 }
80
81 #[cfg(feature = "component-model")]
84 #[cfg_attr(
85 docsrs,
86 doc(cfg(all(feature = "runtime", feature = "component-model")))
87 )]
88 pub fn compile_component(&self) -> Result<Component> {
89 let (code, artifacts) = self.compile_cached(super::build_component_artifacts)?;
90 Component::from_parts(self.engine, code, artifacts)
91 }
92}
93
94fn publish_mmap(mmap: MmapVec) -> Result<Arc<CodeMemory>> {
95 let mut code = CodeMemory::new(mmap)?;
96 code.publish()?;
97 Ok(Arc::new(code))
98}
99
100pub fn finish_object(obj: ObjectBuilder<'_>) -> Result<MmapVec> {
106 Ok(<MmapVecWrapper as FinishedObject>::finish_object(obj)?.0)
107}
108
109pub(crate) struct MmapVecWrapper(pub MmapVec);
110
111impl FinishedObject for MmapVecWrapper {
112 fn finish_object(obj: ObjectBuilder<'_>) -> Result<Self> {
113 let mut result = ObjectMmap::default();
114 return match obj.finish(&mut result) {
115 Ok(()) => {
116 assert!(result.mmap.is_some(), "no reserve");
117 let mmap = result.mmap.expect("reserve not called");
118 assert_eq!(mmap.len(), result.len);
119 Ok(MmapVecWrapper(mmap))
120 }
121 Err(e) => match result.err.take() {
122 Some(original) => Err(original.context(e)),
123 None => Err(e.into()),
124 },
125 };
126
127 #[derive(Default)]
135 struct ObjectMmap {
136 mmap: Option<MmapVec>,
137 len: usize,
138 err: Option<Error>,
139 }
140
141 impl WritableBuffer for ObjectMmap {
142 fn len(&self) -> usize {
143 self.len
144 }
145
146 fn reserve(&mut self, additional: usize) -> Result<(), ()> {
147 assert!(self.mmap.is_none(), "cannot reserve twice");
148 self.mmap = match MmapVec::with_capacity(additional) {
149 Ok(mmap) => Some(mmap),
150 Err(e) => {
151 self.err = Some(e);
152 return Err(());
153 }
154 };
155 Ok(())
156 }
157
158 fn resize(&mut self, new_len: usize) {
159 if new_len <= self.len {
163 return;
164 }
165 self.len = new_len;
166 }
167
168 fn write_bytes(&mut self, val: &[u8]) {
169 let mmap = self.mmap.as_mut().expect("write before reserve");
170 mmap[self.len..][..val.len()].copy_from_slice(val);
171 self.len += val.len();
172 }
173 }
174 }
175}