Add caching. (#134)

* Allow a module to have a different signature registry than the process-specific

* Add core ability to build compiled code caches

* Remove timing printouts

* Serialize/Deserialize memories to reduce copies

* Work more on api

* Relocate local functions relatively before external functions

* Fix incorrect definition in test

* merge errors caused by merge

* Fix emscripten compile

* Fix review comments
This commit is contained in:
Lachlan Sneff
2019-02-06 16:26:45 -08:00
committed by GitHub
parent 2f2f86a4de
commit 8fe9b7eac2
34 changed files with 1768 additions and 291 deletions

128
lib/runtime/src/cache.rs Normal file
View File

@ -0,0 +1,128 @@
use crate::Module;
use std::path::Path;
use wasmer_runtime_core::cache::{hash_data, Cache as CoreCache};
pub use wasmer_runtime_core::cache::Error;
/// On-disk storage of compiled WebAssembly.
///
/// A `Cache` can be used to quickly reload already
/// compiled WebAssembly from a previous execution
/// during which the wasm was explicitly compiled
/// as a `Cache`.
///
/// # Usage:
///
/// ```
/// use wasmer_runtime::{compile_cache, Cache};
///
/// # use wasmer_runtime::error::{CompileResult, CacheError};
/// # fn make_cache(wasm: &[u8]) -> CompileResult<()> {
/// // Make a cache.
/// let cache = compile_cache(wasm)?;
///
/// # Ok(())
/// # }
/// # fn usage_cache(cache: Cache) -> Result<(), CacheError> {
/// // Store the cache in a file.
/// cache.store("some_cache_file")?;
///
/// // Load the cache.
/// let cache = Cache::load("some_cache_file")?;
/// let module = unsafe { cache.into_module()? };
/// # Ok(())
/// # }
/// ```
///
/// # Performance Characteristics:
///
/// Loading caches from files has been optimized for latency.
/// There is still more work to do that will reduce
/// loading time, especially for very large modules,
/// but it will require signifigant internal work.
///
/// # Drawbacks:
///
/// Due to internal shortcomings, you cannot convert
/// a module into a `Cache`. This means that compiling
/// into a `Cache` and then converting into a module
/// has more overhead than directly compiling
/// into a [`Module`].
///
/// [`Module`]: struct.Module.html
pub struct Cache(pub(crate) CoreCache);
impl Cache {
/// Load a `Cache` from the file specified by `path`.
///
/// # Usage:
///
/// ```
/// use wasmer_runtime::Cache;
/// # use wasmer_runtime::error::CacheError;
///
/// # fn load_cache() -> Result<(), CacheError> {
/// let cache = Cache::load("some_file.cache")?;
/// # Ok(())
/// # }
/// ```
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
CoreCache::open(path).map(|core_cache| Cache(core_cache))
}
/// Convert a `Cache` into a [`Module`].
///
/// [`Module`]: struct.Module.html
///
/// # Usage:
///
/// ```
/// use wasmer_runtime::Cache;
///
/// # use wasmer_runtime::error::CacheError;
/// # fn cache2module(cache: Cache) -> Result<(), CacheError> {
/// let module = unsafe { cache.into_module()? };
/// # Ok(())
/// # }
/// ```
///
/// # Notes:
///
/// This method is unsafe because the runtime cannot confirm
/// that this cache was not tampered with or corrupted.
pub unsafe fn into_module(self) -> Result<Module, Error> {
let default_compiler = super::default_compiler();
wasmer_runtime_core::load_cache_with(self.0, default_compiler)
}
/// Compare the Sha256 hash of the wasm this cache was build
/// from with some other WebAssembly.
///
/// The main use-case for this is invalidating old caches.
pub fn compare_wasm(&self, wasm: &[u8]) -> bool {
let param_wasm_hash = hash_data(wasm);
self.0.wasm_hash() as &[u8] == &param_wasm_hash as &[u8]
}
/// Store this cache in a file.
///
/// # Notes:
///
/// If a file exists at the specified path, it will be overwritten.
///
/// # Usage:
///
/// ```
/// use wasmer_runtime::Cache;
///
/// # use wasmer_runtime::error::CacheError;
/// # fn store_cache(cache: Cache) -> Result<(), CacheError> {
/// cache.store("some_file.cache")?;
/// # Ok(())
/// # }
/// ```
pub fn store<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
self.0.store(path)
}
}

View File

@ -83,10 +83,8 @@ pub use wasmer_runtime_core::table::Table;
pub use wasmer_runtime_core::types::Value;
pub use wasmer_runtime_core::vm::Ctx;
pub use wasmer_runtime_core::{compile_with, validate};
pub use wasmer_runtime_core::error;
pub use wasmer_runtime_core::Func;
pub use wasmer_runtime_core::{compile_with, validate};
pub use wasmer_runtime_core::{func, imports};
pub mod memory {
@ -100,12 +98,26 @@ pub mod wasm {
pub use wasmer_runtime_core::types::{FuncSig, MemoryDescriptor, TableDescriptor, Type, Value};
}
pub mod error {
#[cfg(feature = "cache")]
pub use super::cache::Error as CacheError;
pub use wasmer_runtime_core::error::*;
}
pub mod units {
//! Various unit types.
pub use wasmer_runtime_core::units::{Bytes, Pages};
}
#[cfg(feature = "cache")]
mod cache;
#[cfg(feature = "default-compiler")]
use wasmer_runtime_core::backend::Compiler;
#[cfg(feature = "cache")]
pub use self::cache::Cache;
/// Compile WebAssembly binary code into a [`Module`].
/// This function is useful if it is necessary to
/// compile a module before it can be instantiated
@ -119,10 +131,9 @@ pub mod units {
/// binary code of the wasm module you want to compile.
/// # Errors:
/// If the operation fails, the function returns `Err(error::CompileError::...)`.
#[cfg(feature = "wasmer-clif-backend")]
#[cfg(feature = "default-compiler")]
pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
use wasmer_clif_backend::CraneliftCompiler;
wasmer_runtime_core::compile_with(&wasm[..], &CraneliftCompiler::new())
wasmer_runtime_core::compile_with(&wasm[..], default_compiler())
}
/// Compile and instantiate WebAssembly code without
@ -143,11 +154,48 @@ pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
/// `error::CompileError`, `error::LinkError`, or
/// `error::RuntimeError` (all combined into an `error::Error`),
/// depending on the cause of the failure.
#[cfg(feature = "wasmer-clif-backend")]
#[cfg(feature = "default-compiler")]
pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result<Instance> {
let module = compile(wasm)?;
module.instantiate(import_object)
}
/// Compile wasm into a [`Cache`] that can be stored to a file or
/// converted into [`Module`].
///
/// [`Cache`]: struct.Cache.html
/// [`Module`]: struct.Module.html
///
/// # Usage:
///
/// ```
/// # use wasmer_runtime::error::CompileResult;
/// use wasmer_runtime::compile_cache;
///
/// # fn make_cache(wasm: &[u8]) -> CompileResult<()> {
/// let cache = compile_cache(wasm)?;
/// # Ok(())
/// # }
/// ```
#[cfg(feature = "cache")]
pub fn compile_cache(wasm: &[u8]) -> error::CompileResult<Cache> {
let default_compiler = default_compiler();
wasmer_runtime_core::compile_to_cache_with(wasm, default_compiler)
.map(|core_cache| Cache(core_cache))
}
#[cfg(feature = "default-compiler")]
fn default_compiler() -> &'static dyn Compiler {
use lazy_static::lazy_static;
use wasmer_clif_backend::CraneliftCompiler;
lazy_static! {
static ref DEFAULT_COMPILER: CraneliftCompiler = { CraneliftCompiler::new() };
}
&*DEFAULT_COMPILER as &dyn Compiler
}
/// The current version of this crate
pub const VERSION: &str = env!("CARGO_PKG_VERSION");