Serialize and deserialize compilation artifacts. (#2020)

* Serialize and deserialize Module
* Use bincode to serialize
* Add wasm_module_serialize; docs
* Simple tests
This commit is contained in:
Yury Delendik
2020-07-21 15:05:50 -05:00
committed by GitHub
parent c420f65214
commit 399ee0a54c
17 changed files with 528 additions and 20 deletions

View File

@@ -26,6 +26,8 @@ lazy_static = "1.4"
log = "0.4.8"
wat = { version = "1.0.18", optional = true }
smallvec = "1.4.0"
serde = { version = "1.0.94", features = ["derive"] }
bincode = "1.2.1"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.3.7"

View File

@@ -1,10 +1,10 @@
use crate::frame_info::GlobalFrameInfoRegistration;
use crate::runtime::Engine;
use crate::runtime::{Config, Engine};
use crate::types::{EntityType, ExportType, ExternType, ImportType};
use anyhow::Result;
use anyhow::{bail, Context, Result};
use std::path::Path;
use std::sync::{Arc, Mutex};
use wasmtime_jit::CompiledModule;
use wasmtime_jit::{CompilationArtifacts, CompiledModule};
/// A compiled WebAssembly module, ready to be instantiated.
///
@@ -309,6 +309,51 @@ impl Module {
})
}
/// Serialize compilation artifacts to the buffer. See also `deseriaize`.
pub fn serialize(&self) -> Result<Vec<u8>> {
let artifacts = (
compiler_fingerprint(self.engine.config()),
self.compiled.to_compilation_artifacts(),
);
let mut buffer = Vec::new();
bincode::serialize_into(&mut buffer, &artifacts)?;
Ok(buffer)
}
/// Deserializes and creates a module from the compilatio nartifacts.
/// The `serialize` saves the compilation artifacts along with the host
/// fingerprint, which consists of target, compiler flags, and wasmtime
/// package version.
///
/// The method will fail if fingerprints of current host and serialized
/// one are different. The method does not verify the serialized artifacts
/// for modifications or curruptions. All responsibily of signing and its
/// verification falls on the embedder.
pub fn deserialize(engine: &Engine, serialized: &[u8]) -> Result<Module> {
let expected_fingerprint = compiler_fingerprint(engine.config());
let (fingerprint, artifacts) =
bincode::deserialize_from::<_, (u64, CompilationArtifacts)>(serialized)
.context("Deserialize compilation artifacts")?;
if fingerprint != expected_fingerprint {
bail!("Incompatible compilation artifact");
}
let compiled = CompiledModule::from_artifacts(
artifacts,
engine.compiler().isa(),
&*engine.config().profiler,
)?;
Ok(Module {
engine: engine.clone(),
compiled: Arc::new(compiled),
frame_info_registration: Arc::new(Mutex::new(None)),
})
}
pub(crate) fn compiled_module(&self) -> &CompiledModule {
&self.compiled
}
@@ -535,6 +580,13 @@ impl Module {
}
}
fn compiler_fingerprint(config: &Config) -> u64 {
use std::hash::Hasher;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
config.compiler_fingerprint(&mut hasher);
hasher.finish()
}
fn _assert_send_sync() {
fn _assert<T: Send + Sync>() {}
_assert::<Module>();

View File

@@ -10,6 +10,7 @@ use std::hash::{Hash, Hasher};
use std::path::Path;
use std::rc::{Rc, Weak};
use std::sync::Arc;
use target_lexicon::Triple;
use wasmparser::Validator;
use wasmtime_environ::settings::{self, Configurable, SetError};
use wasmtime_environ::{ir, isa, isa::TargetIsa, wasm, CacheConfig, Tunables};
@@ -634,6 +635,22 @@ impl Config {
self.tunables.clone(),
)
}
/// Hashes/fingerprints compiler setting to ensure that compatible
/// compilation artifacts are used.
pub(crate) fn compiler_fingerprint<H>(&self, state: &mut H)
where
H: Hasher,
{
self.flags.hash(state);
self.tunables.hash(state);
let triple = Triple::host();
triple.hash(state);
// Catch accidental bugs of reusing across wasmtime versions.
env!("CARGO_PKG_VERSION").hash(state);
}
}
fn round_up_to_pages(val: u64) -> u64 {