wasmer_runtime_core_fl/
cache.rs1use crate::{module::ModuleInfo, sys::Memory};
6use std::{io, mem, slice};
7
8#[derive(Debug)]
10pub enum InvalidFileType {
11 InvalidSize,
13 InvalidMagic,
15}
16
17#[derive(Debug)]
19pub enum Error {
20 IoError(io::Error),
22 DeserializeError(String),
24 SerializeError(String),
26 Unknown(String),
28 InvalidFile(InvalidFileType),
30 InvalidatedCache,
32 UnsupportedBackend(String),
34}
35
36impl From<io::Error> for Error {
37 fn from(io_err: io::Error) -> Self {
38 Error::IoError(io_err)
39 }
40}
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
48pub struct WasmHash([u8; 32]);
50
51impl WasmHash {
52 pub fn generate(wasm: &[u8]) -> Self {
58 let hash = blake3::hash(wasm);
59 WasmHash(hash.into())
60 }
61
62 pub fn encode(self) -> String {
65 hex::encode(&self.into_array() as &[u8])
66 }
67
68 pub fn decode(hex_str: &str) -> Result<Self, Error> {
70 let bytes = hex::decode(hex_str).map_err(|e| {
71 Error::DeserializeError(format!(
72 "Could not decode prehashed key as hexadecimal: {}",
73 e
74 ))
75 })?;
76 if bytes.len() != 32 {
77 return Err(Error::DeserializeError(
78 "Prehashed keys must deserialze into exactly 32 bytes".to_string(),
79 ));
80 }
81 use std::convert::TryInto;
82 Ok(WasmHash(bytes[0..32].try_into().map_err(|e| {
83 Error::DeserializeError(format!("Could not get first 32 bytes: {}", e))
84 })?))
85 }
86
87 pub(crate) fn into_array(self) -> [u8; 32] {
88 let mut total = [0u8; 32];
89 total[0..32].copy_from_slice(&self.0);
90 total
91 }
92}
93
94const CURRENT_CACHE_VERSION: u64 = 0;
95static WASMER_CACHE_MAGIC: [u8; 8] = *b"WASMER\0\0";
96
97#[repr(C, packed)]
99struct ArtifactHeader {
100 magic: [u8; 8], version: u64,
102 data_len: u64,
103}
104
105impl ArtifactHeader {
106 pub fn read_from_slice(buffer: &[u8]) -> Result<(&Self, &[u8]), Error> {
107 if buffer.len() >= mem::size_of::<ArtifactHeader>() {
108 if &buffer[..8] == &WASMER_CACHE_MAGIC {
109 let (header_slice, body_slice) = buffer.split_at(mem::size_of::<ArtifactHeader>());
110 let header = unsafe { &*(header_slice.as_ptr() as *const ArtifactHeader) };
111
112 if header.version == CURRENT_CACHE_VERSION {
113 Ok((header, body_slice))
114 } else {
115 Err(Error::InvalidatedCache)
116 }
117 } else {
118 Err(Error::InvalidFile(InvalidFileType::InvalidMagic))
119 }
120 } else {
121 Err(Error::InvalidFile(InvalidFileType::InvalidSize))
122 }
123 }
124
125 pub fn read_from_slice_mut(buffer: &mut [u8]) -> Result<(&mut Self, &mut [u8]), Error> {
126 if buffer.len() >= mem::size_of::<ArtifactHeader>() {
127 if &buffer[..8] == &WASMER_CACHE_MAGIC {
128 let (header_slice, body_slice) =
129 buffer.split_at_mut(mem::size_of::<ArtifactHeader>());
130 let header = unsafe { &mut *(header_slice.as_ptr() as *mut ArtifactHeader) };
131
132 if header.version == CURRENT_CACHE_VERSION {
133 Ok((header, body_slice))
134 } else {
135 Err(Error::InvalidatedCache)
136 }
137 } else {
138 Err(Error::InvalidFile(InvalidFileType::InvalidMagic))
139 }
140 } else {
141 Err(Error::InvalidFile(InvalidFileType::InvalidSize))
142 }
143 }
144
145 pub fn as_slice(&self) -> &[u8] {
146 let ptr = self as *const ArtifactHeader as *const u8;
147 unsafe { slice::from_raw_parts(ptr, mem::size_of::<ArtifactHeader>()) }
148 }
149}
150
151#[derive(Serialize, Deserialize)]
152struct ArtifactInner {
153 info: Box<ModuleInfo>,
154 #[serde(with = "serde_bytes")]
155 backend_metadata: Box<[u8]>,
156 compiled_code: Memory,
157}
158
159pub struct Artifact {
162 inner: ArtifactInner,
163}
164
165impl Artifact {
166 pub(crate) fn from_parts(
167 info: Box<ModuleInfo>,
168 backend_metadata: Box<[u8]>,
169 compiled_code: Memory,
170 ) -> Self {
171 Self {
172 inner: ArtifactInner {
173 info,
174 backend_metadata,
175 compiled_code,
176 },
177 }
178 }
179
180 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
182 let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?;
183
184 let inner = serde_bench::deserialize(body_slice)
185 .map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?;
186
187 Ok(Artifact { inner })
188 }
189
190 pub fn info(&self) -> &ModuleInfo {
192 &self.inner.info
193 }
194
195 #[doc(hidden)]
196 pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Memory) {
197 (
198 *self.inner.info,
199 self.inner.backend_metadata,
200 self.inner.compiled_code,
201 )
202 }
203
204 pub fn serialize(&self) -> Result<Vec<u8>, Error> {
206 let cache_header = ArtifactHeader {
207 magic: WASMER_CACHE_MAGIC,
208 version: CURRENT_CACHE_VERSION,
209 data_len: 0,
210 };
211
212 let mut buffer = cache_header.as_slice().to_vec();
213
214 serde_bench::serialize(&mut buffer, &self.inner)
215 .map_err(|e| Error::SerializeError(e.to_string()))?;
216
217 let data_len = (buffer.len() - mem::size_of::<ArtifactHeader>()) as u64;
218
219 let (header, _) = ArtifactHeader::read_from_slice_mut(&mut buffer)?;
220 header.data_len = data_len;
221
222 Ok(buffer)
223 }
224}
225
226pub const WASMER_VERSION_HASH: &'static str =
228 include_str!(concat!(env!("OUT_DIR"), "/wasmer_version_hash.txt"));