From e381bbd07bb8f2a12b1f2ef10b1fe26cfe174bec Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 18 Feb 2019 11:56:20 -0800 Subject: [PATCH 01/14] Use ModuleInfo instead of ModuleInner when possible --- lib/clif-backend/src/func_env.rs | 12 +- lib/clif-backend/src/lib.rs | 4 +- lib/clif-backend/src/module.rs | 130 +++++---------- lib/clif-backend/src/module_env.rs | 8 +- lib/clif-backend/src/signal/mod.rs | 2 +- lib/runtime-core/src/backend.rs | 4 + lib/runtime-core/src/backing.rs | 10 +- lib/runtime-core/src/instance.rs | 18 +-- lib/runtime-core/src/module.rs | 20 ++- lib/runtime-core/src/types.rs | 14 +- lib/runtime-core/src/vm.rs | 5 +- lib/runtime/Cargo.toml | 6 +- lib/runtime/src/cache.rs | 243 +++++++++++++++-------------- lib/runtime/src/lib.rs | 52 +++--- 14 files changed, 252 insertions(+), 276 deletions(-) diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs index 8670e0000..e222f2e07 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/func_env.rs @@ -75,7 +75,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let local_global_addr = match global_index.local_or_import(self.env.module) { + let local_global_addr = match global_index.local_or_import(&self.env.module.info) { LocalOrImport::Local(local_global_index) => { let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { base: vmctx, @@ -145,7 +145,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(self.env.module) { + let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(&self.env.module.info) { LocalOrImport::Local(local_mem_index) => { let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { base: vmctx, @@ -253,7 +253,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let (table_struct_ptr_ptr, description) = match table_index.local_or_import(self.env.module) + let (table_struct_ptr_ptr, description) = match table_index.local_or_import(&self.env.module.info) { LocalOrImport::Local(local_table_index) => { let tables_base = func.create_global_value(ir::GlobalValueData::Load { @@ -476,7 +476,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { ) -> cranelift_wasm::WasmResult { let callee_index: FuncIndex = Converter(clif_callee_index).into(); - match callee_index.local_or_import(self.env.module) { + match callee_index.local_or_import(&self.env.module.info) { LocalOrImport::Local(_) => { // this is an internal function let vmctx = pos @@ -568,7 +568,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) { + let (namespace, mem_index, description) = match mem_index.local_or_import(&self.env.module.info) { LocalOrImport::Local(local_mem_index) => ( call_names::LOCAL_NAMESPACE, local_mem_index.index(), @@ -631,7 +631,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) { + let (namespace, mem_index, description) = match mem_index.local_or_import(&self.env.module.info) { LocalOrImport::Local(local_mem_index) => ( call_names::LOCAL_NAMESPACE, local_mem_index.index(), diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 07bae97c6..cbe455b93 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -48,7 +48,7 @@ impl Compiler for CraneliftCompiler { let isa = get_isa(); - let mut module = module::Module::empty(); + let mut module = module::Module::new(wasm); let module_env = module_env::ModuleEnv::new(&mut module, &*isa); let func_bodies = module_env.translate(wasm)?; @@ -72,7 +72,7 @@ impl Compiler for CraneliftCompiler { let isa = get_isa(); - let mut module = module::Module::empty(); + let mut module = module::Module::new(wasm); let module_env = module_env::ModuleEnv::new(&mut module, &*isa); let func_bodies = module_env.translate(wasm)?; diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index c48072ac8..e2ee8efe8 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -6,115 +6,83 @@ use cranelift_codegen::{ir, isa}; use cranelift_entity::EntityRef; use cranelift_wasm; use hashbrown::HashMap; -use std::{ - ops::{Deref, DerefMut}, - ptr::NonNull, -}; + #[cfg(feature = "cache")] use wasmer_runtime_core::{ backend::sys::Memory, cache::{Cache, Error as CacheError}, }; + use wasmer_runtime_core::{ - backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper}, - error::{CompileResult, RuntimeResult}, - module::{ModuleInfo, ModuleInner, StringTable}, + backend::Backend, + error::CompileResult, + module::{ModuleInfo, ModuleInner, StringTable, WasmHash}, structures::{Map, TypedIndex}, types::{ FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type, - Value, }, - vm::{self, ImportBacking}, }; -struct Placeholder; - -impl FuncResolver for Placeholder { - fn get( - &self, - _module: &ModuleInner, - _local_func_index: LocalFuncIndex, - ) -> Option> { - None - } -} - -impl ProtectedCaller for Placeholder { - fn call( - &self, - _module: &ModuleInner, - _func_index: FuncIndex, - _params: &[Value], - _import_backing: &ImportBacking, - _vmctx: *mut vm::Ctx, - _: Token, - ) -> RuntimeResult> { - Ok(vec![]) - } - - fn get_early_trapper(&self) -> Box { - unimplemented!() - } -} - /// This contains all of the items in a `ModuleInner` except the `func_resolver`. pub struct Module { - pub module: ModuleInner, + pub info: ModuleInfo, } impl Module { - pub fn empty() -> Self { + pub fn new(wasm: &[u8]) -> Self { Self { - module: ModuleInner { - // this is a placeholder - func_resolver: Box::new(Placeholder), - protected_caller: Box::new(Placeholder), + info: ModuleInfo { + memories: Map::new(), + globals: Map::new(), + tables: Map::new(), - info: ModuleInfo { - memories: Map::new(), - globals: Map::new(), - tables: Map::new(), + imported_functions: Map::new(), + imported_memories: Map::new(), + imported_tables: Map::new(), + imported_globals: Map::new(), - imported_functions: Map::new(), - imported_memories: Map::new(), - imported_tables: Map::new(), - imported_globals: Map::new(), + exports: HashMap::new(), - exports: HashMap::new(), + data_initializers: Vec::new(), + elem_initializers: Vec::new(), - data_initializers: Vec::new(), - elem_initializers: Vec::new(), + start_func: None, - start_func: None, + func_assoc: Map::new(), + signatures: Map::new(), + backend: Backend::Cranelift, - func_assoc: Map::new(), - signatures: Map::new(), - backend: Backend::Cranelift, + namespace_table: StringTable::new(), + name_table: StringTable::new(), - namespace_table: StringTable::new(), - name_table: StringTable::new(), - }, + wasm_hash: WasmHash::generate(wasm), }, } } pub fn compile( - mut self, + self, isa: &isa::TargetIsa, functions: Map, ) -> CompileResult { let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(isa, functions, &self.module.info)?; + FuncResolverBuilder::new(isa, functions, &self.info)?; + - self.module.func_resolver = - Box::new(func_resolver_builder.finalize(&self.module.info.signatures)?); + let func_resolver = + Box::new(func_resolver_builder.finalize(&self.info.signatures)?); - let trampolines = Trampolines::new(isa, &self.module.info); + let trampolines = Trampolines::new(isa, &self.info); - self.module.protected_caller = - Box::new(Caller::new(&self.module.info, handler_data, trampolines)); + let protected_caller = + Box::new(Caller::new(&self.info, handler_data, trampolines)); - Ok(self.module) + Ok(ModuleInner { + func_resolver, + protected_caller, + + info: self.info, + }) } #[cfg(feature = "cache")] @@ -124,16 +92,16 @@ impl Module { functions: Map, ) -> CompileResult<(ModuleInfo, BackendCache, Memory)> { let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(isa, functions, &self.module.info)?; + FuncResolverBuilder::new(isa, functions, &self.info)?; - let trampolines = Trampolines::new(isa, &self.module.info); + let trampolines = Trampolines::new(isa, &self.info); let trampoline_cache = trampolines.to_trampoline_cache(); let (backend_cache, compiled_code) = func_resolver_builder.to_backend_cache(trampoline_cache, handler_data); - Ok((self.module.info, backend_cache, compiled_code)) + Ok((self.info, backend_cache, compiled_code)) } #[cfg(feature = "cache")] @@ -159,20 +127,6 @@ impl Module { } } -impl Deref for Module { - type Target = ModuleInner; - - fn deref(&self) -> &ModuleInner { - &self.module - } -} - -impl DerefMut for Module { - fn deref_mut(&mut self) -> &mut ModuleInner { - &mut self.module - } -} - pub struct Converter(pub T); macro_rules! convert_clif_to_runtime_index { diff --git a/lib/clif-backend/src/module_env.rs b/lib/clif-backend/src/module_env.rs index 65bd5f839..b80e8826d 100644 --- a/lib/clif-backend/src/module_env.rs +++ b/lib/clif-backend/src/module_env.rs @@ -139,7 +139,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> // assert!(!desc.mutable); let global_index: GlobalIndex = Converter(global_index).into(); let imported_global_index = global_index - .local_or_import(self.module) + .local_or_import(&self.module.info) .import() .expect("invalid global initializer when declaring an imported global"); Initializer::GetGlobal(imported_global_index) @@ -249,7 +249,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> let base = match base { Some(global_index) => { let global_index: GlobalIndex = Converter(global_index).into(); - Initializer::GetGlobal(match global_index.local_or_import(self.module) { + Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) { LocalOrImport::Import(imported_global_index) => imported_global_index, LocalOrImport::Local(_) => { panic!("invalid global initializer when declaring an imported global") @@ -319,7 +319,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> let base = match base { Some(global_index) => { let global_index: GlobalIndex = Converter(global_index).into(); - Initializer::GetGlobal(match global_index.local_or_import(self.module) { + Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) { LocalOrImport::Import(imported_global_index) => imported_global_index, LocalOrImport::Local(_) => { panic!("invalid global initializer when declaring an imported global") @@ -389,7 +389,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> let name = ir::ExternalName::user(0, func_index.index() as u32); let sig = func_env.generate_signature( - self.get_func_type(Converter(func_index.convert_up(self.module)).into()), + self.get_func_type(Converter(func_index.convert_up(&self.module.info)).into()), ); let mut func = ir::Function::with_name_signature(name, sig); diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 31dbb44dd..1468d99eb 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -160,7 +160,7 @@ fn get_func_from_index( .get(func_index) .expect("broken invariant, incorrect func index"); - let (func_ptr, ctx) = match func_index.local_or_import(module) { + let (func_ptr, ctx) = match func_index.local_or_import(&module.info) { LocalOrImport::Local(local_func_index) => ( module .func_resolver diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 9b5ec049e..328e3c826 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -99,3 +99,7 @@ pub trait FuncResolver: Send + Sync { local_func_index: LocalFuncIndex, ) -> Option>; } + +pub trait CacheGen: Send + Sync { + fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Memory), CacheError>; +} \ No newline at end of file diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index d81e33065..ef2556895 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -91,7 +91,7 @@ impl LocalBacking { } } as usize; - match init.memory_index.local_or_import(module) { + match init.memory_index.local_or_import(&module.info) { LocalOrImport::Local(local_memory_index) => { let memory_desc = module.info.memories[local_memory_index]; let data_top = init_base + init.data.len(); @@ -159,7 +159,7 @@ impl LocalBacking { } } as usize; - match init.table_index.local_or_import(module) { + match init.table_index.local_or_import(&module.info) { LocalOrImport::Local(local_table_index) => { let table = &tables[local_table_index]; @@ -177,7 +177,7 @@ impl LocalBacking { SigRegistry.lookup_sig_index(Arc::clone(&signature)).index() as u32, ); - let (func, ctx) = match func_index.local_or_import(module) { + let (func, ctx) = match func_index.local_or_import(&module.info) { LocalOrImport::Local(local_func_index) => ( module .func_resolver @@ -215,7 +215,7 @@ impl LocalBacking { SigRegistry.lookup_sig_index(Arc::clone(&signature)).index() as u32, ); - let (func, ctx) = match func_index.local_or_import(module) { + let (func, ctx) = match func_index.local_or_import(&module.info) { LocalOrImport::Local(local_func_index) => ( module .func_resolver @@ -364,7 +364,7 @@ fn import_functions( }, ) in &module.info.imported_functions { - let sig_index = module.info.func_assoc[index.convert_up(module)]; + let sig_index = module.info.func_assoc[index.convert_up(&module.info)]; let expected_sig = &module.info.signatures[sig_index]; let namespace = module.info.namespace_table.get(*namespace_index); diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index a8f36325a..a634b21e5 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -121,14 +121,14 @@ impl Instance { })?; } - let ctx = match func_index.local_or_import(&*self.module) { + let ctx = match func_index.local_or_import(&self.module.info) { LocalOrImport::Local(_) => self.inner.vmctx, LocalOrImport::Import(imported_func_index) => { self.inner.import_backing.vm_functions[imported_func_index].vmctx } }; - let func_ptr = match func_index.local_or_import(&self.module) { + let func_ptr = match func_index.local_or_import(&self.module.info) { LocalOrImport::Local(local_func_index) => self .module .func_resolver @@ -288,7 +288,7 @@ impl Instance { })? } - let vmctx = match func_index.local_or_import(&self.module) { + let vmctx = match func_index.local_or_import(&self.module.info) { LocalOrImport::Local(_) => self.inner.vmctx, LocalOrImport::Import(imported_func_index) => { self.inner.import_backing.vm_functions[imported_func_index].vmctx @@ -355,7 +355,7 @@ impl InstanceInner { .get(func_index) .expect("broken invariant, incorrect func index"); - let (func_ptr, ctx) = match func_index.local_or_import(module) { + let (func_ptr, ctx) = match func_index.local_or_import(&module.info) { LocalOrImport::Local(local_func_index) => ( module .func_resolver @@ -384,7 +384,7 @@ impl InstanceInner { } fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory { - match mem_index.local_or_import(module) { + match mem_index.local_or_import(&module.info) { LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(), LocalOrImport::Import(imported_mem_index) => { self.import_backing.memories[imported_mem_index].clone() @@ -393,7 +393,7 @@ impl InstanceInner { } fn get_global_from_index(&self, module: &ModuleInner, global_index: GlobalIndex) -> Global { - match global_index.local_or_import(module) { + match global_index.local_or_import(&module.info) { LocalOrImport::Local(local_global_index) => { self.backing.globals[local_global_index].clone() } @@ -404,7 +404,7 @@ impl InstanceInner { } fn get_table_from_index(&self, module: &ModuleInner, table_index: TableIndex) -> Table { - match table_index.local_or_import(module) { + match table_index.local_or_import(&module.info) { LocalOrImport::Local(local_table_index) => { self.backing.tables[local_table_index].clone() } @@ -462,7 +462,7 @@ impl<'a> DynFunc<'a> { })? } - let vmctx = match self.func_index.local_or_import(self.module) { + let vmctx = match self.func_index.local_or_import(&self.module.info) { LocalOrImport::Local(_) => self.instance_inner.vmctx, LocalOrImport::Import(imported_func_index) => { self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx @@ -488,7 +488,7 @@ impl<'a> DynFunc<'a> { } pub fn raw(&self) -> *const vm::Func { - match self.func_index.local_or_import(self.module) { + match self.func_index.local_or_import(&self.module.info) { LocalOrImport::Local(local_func_index) => self .module .func_resolver diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 0fdb24018..aca3fc221 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -51,6 +51,18 @@ pub struct ModuleInfo { pub namespace_table: StringTable, pub name_table: StringTable, + + pub wasm_hash: WasmHash, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +pub struct WasmHash([u8; 32]); + +impl WasmHash { + pub fn generate(wasm: &[u8]) -> Self { + WasmHash(super::cache::hash_data(wasm)) + } } /// A compiled WebAssembly module. @@ -60,7 +72,9 @@ pub struct ModuleInfo { /// /// [`compile`]: fn.compile.html /// [`compile_with`]: fn.compile_with.html -pub struct Module(#[doc(hidden)] pub Arc); +pub struct Module { + inner: Arc, +} impl Module { pub(crate) fn new(inner: Arc) -> Self { @@ -68,7 +82,7 @@ impl Module { EARLY_TRAPPER .with(|ucell| *ucell.get() = Some(inner.protected_caller.get_early_trapper())); } - Module(inner) + Module { inner } } /// Instantiate a WebAssembly module with the provided [`ImportObject`]. @@ -94,7 +108,7 @@ impl Module { /// # } /// ``` pub fn instantiate(&self, import_object: &ImportObject) -> Result { - Instance::new(Arc::clone(&self.0), import_object) + Instance::new(Arc::clone(&self.inner), import_object) } } diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index fd57bf12c..271b336ba 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -1,4 +1,4 @@ -use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex, units::Pages}; +use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages}; use std::{borrow::Cow, mem}; /// Represents a WebAssembly type. @@ -364,23 +364,23 @@ define_map_index![ macro_rules! define_local_or_import { ($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => { impl $ty { - pub fn local_or_import(self, module: &ModuleInner) -> LocalOrImport<$ty> { - if self.index() < module.info.$imports.len() { + pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> { + if self.index() < info.$imports.len() { LocalOrImport::Import(::Import::new(self.index())) } else { - LocalOrImport::Local(::Local::new(self.index() - module.info.$imports.len())) + LocalOrImport::Local(::Local::new(self.index() - info.$imports.len())) } } } impl $local_ty { - pub fn convert_up(self, module: &ModuleInner) -> $ty { - $ty ((self.index() + module.info.$imports.len()) as u32) + pub fn convert_up(self, info: &ModuleInfo) -> $ty { + $ty ((self.index() + info.$imports.len()) as u32) } } impl $imported_ty { - pub fn convert_up(self, _module: &ModuleInner) -> $ty { + pub fn convert_up(self, _info: &ModuleInfo) -> $ty { $ty (self.index() as u32) } } diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index faee819be..abea76db8 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -116,7 +116,7 @@ impl Ctx { pub fn memory(&self, mem_index: u32) -> &Memory { let module = unsafe { &*self.module }; let mem_index = MemoryIndex::new(mem_index as usize); - match mem_index.local_or_import(module) { + match mem_index.local_or_import(&module.info) { LocalOrImport::Local(local_mem_index) => unsafe { let local_backing = &*self.local_backing; &local_backing.memories[local_mem_index] @@ -497,6 +497,7 @@ mod vm_ctx_tests { use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper}; use crate::error::RuntimeResult; use crate::types::{FuncIndex, LocalFuncIndex, Value}; + use crate::module::WasmHash; use hashbrown::HashMap; use std::ptr::NonNull; struct Placeholder; @@ -553,6 +554,8 @@ mod vm_ctx_tests { namespace_table: StringTable::new(), name_table: StringTable::new(), + + wasm_hash: WasmHash::generate(&[]), }, } } diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 2a2478193..fe6cc80d2 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -10,11 +10,9 @@ readme = "README.md" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2", optional = true } +wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" } lazy_static = "1.2.0" [features] -default = ["default-compiler", "cache"] -default-compiler = ["wasmer-clif-backend/cache", "wasmer-runtime-core/cache"] -cache = ["default-compiler"] +default = ["wasmer-clif-backend/cache", "wasmer-runtime-core/cache"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index ceb6d171e..b0db19fe8 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -1,128 +1,139 @@ use crate::Module; use std::path::Path; use wasmer_runtime_core::cache::{hash_data, Cache as CoreCache}; +use wasmer_runtime_core::module::{WasmHash}; 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); +// /// 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>(path: P) -> Result { - CoreCache::open(path).map(|core_cache| Cache(core_cache)) - } +// 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>(path: P) -> Result { +// 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 { - let default_compiler = super::default_compiler(); +// /// 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 { +// let default_compiler = super::default_compiler(); - wasmer_runtime_core::load_cache_with(self.0, 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] == ¶m_wasm_hash as &[u8] - } +// /// 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] == ¶m_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>(&self, path: P) -> Result<(), Error> { - self.0.store(path) - } +// /// 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>(&self, path: P) -> Result<(), Error> { +// self.0.store(path) +// } +// } + +pub trait Cache { + type Key; + type LoadError; + type StoreError; + + unsafe fn load(&self, key: Self::Key) -> Result; + fn store(&mut self, module: Module) -> Result; } + diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index f100a5bad..48a4c27f5 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -99,7 +99,6 @@ pub mod wasm { } pub mod error { - #[cfg(feature = "cache")] pub use super::cache::Error as CacheError; pub use wasmer_runtime_core::error::*; } @@ -109,13 +108,10 @@ pub mod units { 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`]. @@ -131,7 +127,6 @@ pub use self::cache::Cache; /// binary code of the wasm module you want to compile. /// # Errors: /// If the operation fails, the function returns `Err(error::CompileError::...)`. -#[cfg(feature = "default-compiler")] pub fn compile(wasm: &[u8]) -> error::CompileResult { wasmer_runtime_core::compile_with(&wasm[..], default_compiler()) } @@ -154,38 +149,35 @@ pub fn compile(wasm: &[u8]) -> error::CompileResult { /// `error::CompileError`, `error::LinkError`, or /// `error::RuntimeError` (all combined into an `error::Error`), /// depending on the cause of the failure. -#[cfg(feature = "default-compiler")] pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result { 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 { - let default_compiler = default_compiler(); +// /// 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(()) +// /// # } +// /// ``` +// pub fn compile_cache(wasm: &[u8]) -> error::CompileResult { +// let default_compiler = default_compiler(); - wasmer_runtime_core::compile_to_cache_with(wasm, default_compiler) - .map(|core_cache| Cache(core_cache)) -} +// 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; From 3c7dc200fa615bd21ec11f17cc2e36988e7a859e Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Tue, 19 Feb 2019 09:58:01 -0800 Subject: [PATCH 02/14] close to working --- lib/clif-backend/src/cache.rs | 32 +++- lib/clif-backend/src/lib.rs | 48 +++--- lib/clif-backend/src/module.rs | 63 ++++---- lib/clif-backend/src/resolver.rs | 246 ++++++++++++++--------------- lib/clif-backend/src/signal/mod.rs | 9 +- lib/clif-backend/src/trampoline.rs | 4 +- lib/runtime-core/src/backend.rs | 9 +- lib/runtime-core/src/lib.rs | 20 +-- lib/runtime-core/src/module.rs | 4 +- lib/runtime-core/src/vm.rs | 10 +- 10 files changed, 239 insertions(+), 206 deletions(-) diff --git a/lib/clif-backend/src/cache.rs b/lib/clif-backend/src/cache.rs index aef6adf4c..cf1b9c919 100644 --- a/lib/clif-backend/src/cache.rs +++ b/lib/clif-backend/src/cache.rs @@ -2,15 +2,41 @@ use crate::relocation::{ExternalRelocation, TrapSink}; use hashbrown::HashMap; use wasmer_runtime_core::{ - backend::sys::Memory, + backend::{ + sys::Memory, + CacheGen, + }, cache::{Cache, Error}, - module::ModuleInfo, + module::{ModuleInfo, ModuleInner}, structures::Map, types::{LocalFuncIndex, SigIndex}, }; +use std::{ + sync::Arc, + cell::UnsafeCell, +}; use serde_bench::{deserialize, serialize}; +pub struct CacheGenerator { + backend_cache: BackendCache, + memory: Arc, +} + +impl CacheGenerator { + pub fn new(backend_cache: BackendCache, memory: Arc) -> Self { + Self { backend_cache, memory } + } +} + +impl CacheGen for CacheGenerator { + fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Arc), Error> { + let info = Box::new(module.info.clone()); + + Err(Error::Unknown("".to_string())) + } +} + #[derive(Serialize, Deserialize)] pub struct TrampolineCache { #[serde(with = "serde_bytes")] @@ -22,7 +48,7 @@ pub struct TrampolineCache { pub struct BackendCache { pub external_relocs: Map>, pub offsets: Map, - pub trap_sink: TrapSink, + pub trap_sink: Arc, pub trampolines: TrampolineCache, } diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index cbe455b93..621d5b59e 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -62,36 +62,36 @@ impl Compiler for CraneliftCompiler { module::Module::from_cache(cache) } - #[cfg(feature = "cache")] - fn compile_to_backend_cache_data( - &self, - wasm: &[u8], - _: Token, - ) -> CompileResult<(Box, Vec, Memory)> { - validate(wasm)?; + // #[cfg(feature = "cache")] + // fn compile_to_backend_cache_data( + // &self, + // wasm: &[u8], + // _: Token, + // ) -> CompileResult<(Box, Vec, Memory)> { + // validate(wasm)?; - let isa = get_isa(); + // let isa = get_isa(); - let mut module = module::Module::new(wasm); - let module_env = module_env::ModuleEnv::new(&mut module, &*isa); + // let mut module = module::Module::new(wasm); + // let module_env = module_env::ModuleEnv::new(&mut module, &*isa); - let func_bodies = module_env.translate(wasm)?; + // let func_bodies = module_env.translate(wasm)?; - let (info, backend_cache, compiled_code) = module - .compile_to_backend_cache(&*isa, func_bodies) - .map_err(|e| CompileError::InternalError { - msg: format!("{:?}", e), - })?; + // let (info, backend_cache, compiled_code) = module + // .compile_to_backend_cache(&*isa, func_bodies) + // .map_err(|e| CompileError::InternalError { + // msg: format!("{:?}", e), + // })?; - let buffer = - backend_cache - .into_backend_data() - .map_err(|e| CompileError::InternalError { - msg: format!("{:?}", e), - })?; + // let buffer = + // backend_cache + // .into_backend_data() + // .map_err(|e| CompileError::InternalError { + // msg: format!("{:?}", e), + // })?; - Ok((Box::new(info), buffer, compiled_code)) - } + // Ok((Box::new(info), buffer, compiled_code)) + // } } fn get_isa() -> Box { diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index e2ee8efe8..23f07eac9 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -1,11 +1,12 @@ #[cfg(feature = "cache")] -use crate::cache::BackendCache; +use crate::cache::{BackendCache, CacheGenerator}; use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines}; use cranelift_codegen::{ir, isa}; use cranelift_entity::EntityRef; use cranelift_wasm; use hashbrown::HashMap; +use std::sync::Arc; #[cfg(feature = "cache")] use wasmer_runtime_core::{ @@ -67,42 +68,44 @@ impl Module { ) -> CompileResult { let (func_resolver_builder, handler_data) = FuncResolverBuilder::new(isa, functions, &self.info)?; - - let func_resolver = - Box::new(func_resolver_builder.finalize(&self.info.signatures)?); + let trampolines = Arc::new(Trampolines::new(isa, &self.info)); - let trampolines = Trampolines::new(isa, &self.info); + let (func_resolver, backend_cache) = + func_resolver_builder.finalize(&self.info.signatures, Arc::clone(&trampolines), handler_data.clone())?; let protected_caller = - Box::new(Caller::new(&self.info, handler_data, trampolines)); + Caller::new(&self.info, handler_data, trampolines); + + let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); Ok(ModuleInner { - func_resolver, - protected_caller, + func_resolver: Box::new(func_resolver), + protected_caller: Box::new(protected_caller), + cache_gen, info: self.info, }) } - #[cfg(feature = "cache")] - pub fn compile_to_backend_cache( - self, - isa: &isa::TargetIsa, - functions: Map, - ) -> CompileResult<(ModuleInfo, BackendCache, Memory)> { - let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(isa, functions, &self.info)?; + // #[cfg(feature = "cache")] + // pub fn compile_to_backend_cache( + // self, + // isa: &isa::TargetIsa, + // functions: Map, + // ) -> CompileResult<(ModuleInfo, BackendCache, Memory)> { + // let (func_resolver_builder, handler_data) = + // FuncResolverBuilder::new(isa, functions, &self.info)?; - let trampolines = Trampolines::new(isa, &self.info); + // let trampolines = Trampolines::new(isa, &self.info); - let trampoline_cache = trampolines.to_trampoline_cache(); + // let trampoline_cache = trampolines.to_trampoline_cache(); - let (backend_cache, compiled_code) = - func_resolver_builder.to_backend_cache(trampoline_cache, handler_data); + // let (backend_cache, compiled_code) = + // func_resolver_builder.to_backend_cache(trampoline_cache, handler_data); - Ok((self.info, backend_cache, compiled_code)) - } + // Ok((self.info, backend_cache, compiled_code)) + // } #[cfg(feature = "cache")] pub fn from_cache(cache: Cache) -> Result { @@ -111,17 +114,19 @@ impl Module { let (func_resolver_builder, trampolines, handler_data) = FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?; - let func_resolver = Box::new( + let (func_resolver, backend_cache) = func_resolver_builder - .finalize(&info.signatures) - .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?, - ); + .finalize(&info.signatures, Arc::clone(&trampolines), handler_data.clone()) + .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?; - let protected_caller = Box::new(Caller::new(&info, handler_data, trampolines)); + let protected_caller = Caller::new(&info, handler_data, trampolines); + let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); Ok(ModuleInner { - func_resolver, - protected_caller, + func_resolver: Box::new(func_resolver), + protected_caller: Box::new(protected_caller), + cache_gen, + info, }) } diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 48ea5c7e5..1eccb2715 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -17,6 +17,7 @@ use cranelift_codegen::{ir, isa, Context}; use std::{ mem, ptr::{write_unaligned, NonNull}, + cell::UnsafeCell, sync::Arc, }; #[cfg(feature = "cache")] @@ -56,7 +57,7 @@ impl FuncResolverBuilder { backend_cache: BackendCache, mut code: Memory, info: &ModuleInfo, - ) -> Result<(Self, Trampolines, HandlerData), CacheError> { + ) -> Result<(Self, Arc, HandlerData), CacheError> { unsafe { code.protect(.., Protect::ReadWrite) .map_err(|e| CacheError::Unknown(e.to_string()))?; @@ -69,35 +70,17 @@ impl FuncResolverBuilder { Self { resolver: FuncResolver { map: backend_cache.offsets, - memory: code, + memory: Arc::new(UnsafeCell::new(code)), }, local_relocs: Map::new(), external_relocs: backend_cache.external_relocs, import_len: info.imported_functions.len(), }, - Trampolines::from_trampoline_cache(backend_cache.trampolines), + Arc::new(Trampolines::from_trampoline_cache(backend_cache.trampolines)), handler_data, )) } - #[cfg(feature = "cache")] - pub fn to_backend_cache( - mut self, - trampolines: TrampolineCache, - handler_data: HandlerData, - ) -> (BackendCache, Memory) { - self.relocate_locals(); - ( - BackendCache { - external_relocs: self.external_relocs, - offsets: self.resolver.map, - trap_sink: handler_data.trap_data, - trampolines, - }, - self.resolver.memory, - ) - } - pub fn new( isa: &isa::TargetIsa, function_bodies: Map, @@ -169,10 +152,10 @@ impl FuncResolverBuilder { previous_end = new_end; } - let handler_data = HandlerData::new(trap_sink, memory.as_ptr() as _, memory.size()); + let handler_data = HandlerData::new(Arc::new(trap_sink), memory.as_ptr() as _, memory.size()); let mut func_resolver_builder = Self { - resolver: FuncResolver { map, memory }, + resolver: FuncResolver { map, memory: Arc::new(UnsafeCell::new(memory)) }, local_relocs, external_relocs, import_len: info.imported_functions.len(), @@ -207,128 +190,143 @@ impl FuncResolverBuilder { } pub fn finalize( - mut self, + self, signatures: &SliceMap>, - ) -> CompileResult { - for (index, relocs) in self.external_relocs.iter() { - for ref reloc in relocs.iter() { - let target_func_address: isize = match reloc.target { - RelocationType::LibCall(libcall) => match libcall { - LibCall::CeilF32 => libcalls::ceilf32 as isize, - LibCall::FloorF32 => libcalls::floorf32 as isize, - LibCall::TruncF32 => libcalls::truncf32 as isize, - LibCall::NearestF32 => libcalls::nearbyintf32 as isize, - LibCall::CeilF64 => libcalls::ceilf64 as isize, - LibCall::FloorF64 => libcalls::floorf64 as isize, - LibCall::TruncF64 => libcalls::truncf64 as isize, - LibCall::NearestF64 => libcalls::nearbyintf64 as isize, - #[cfg(all(target_pointer_width = "64", target_os = "windows"))] - LibCall::Probestack => __chkstk as isize, - #[cfg(not(target_os = "windows"))] - LibCall::Probestack => __rust_probestack as isize, - }, - RelocationType::Intrinsic(ref name) => match name.as_str() { - "i32print" => i32_print as isize, - "i64print" => i64_print as isize, - "f32print" => f32_print as isize, - "f64print" => f64_print as isize, - "strtdbug" => start_debug as isize, - "enddbug" => end_debug as isize, - _ => Err(CompileError::InternalError { - msg: format!("unexpected intrinsic: {}", name), - })?, - }, - RelocationType::VmCall(vmcall) => match vmcall { - VmCall::Local(kind) => match kind { - VmCallKind::StaticMemoryGrow => vmcalls::local_static_memory_grow as _, - VmCallKind::StaticMemorySize => vmcalls::local_static_memory_size as _, + trampolines: Arc, + handler_data: HandlerData, + ) -> CompileResult<(FuncResolver, BackendCache)> { + { + let mut memory = unsafe { (*self.resolver.memory.get()) }; - VmCallKind::SharedStaticMemoryGrow => unimplemented!(), - VmCallKind::SharedStaticMemorySize => unimplemented!(), - - VmCallKind::DynamicMemoryGrow => { - vmcalls::local_dynamic_memory_grow as _ - } - VmCallKind::DynamicMemorySize => { - vmcalls::local_dynamic_memory_size as _ - } + for (index, relocs) in self.external_relocs.iter() { + for ref reloc in relocs.iter() { + let target_func_address: isize = match reloc.target { + RelocationType::LibCall(libcall) => match libcall { + LibCall::CeilF32 => libcalls::ceilf32 as isize, + LibCall::FloorF32 => libcalls::floorf32 as isize, + LibCall::TruncF32 => libcalls::truncf32 as isize, + LibCall::NearestF32 => libcalls::nearbyintf32 as isize, + LibCall::CeilF64 => libcalls::ceilf64 as isize, + LibCall::FloorF64 => libcalls::floorf64 as isize, + LibCall::TruncF64 => libcalls::truncf64 as isize, + LibCall::NearestF64 => libcalls::nearbyintf64 as isize, + #[cfg(all(target_pointer_width = "64", target_os = "windows"))] + LibCall::Probestack => __chkstk as isize, + #[cfg(not(target_os = "windows"))] + LibCall::Probestack => __rust_probestack as isize, }, - VmCall::Import(kind) => match kind { - VmCallKind::StaticMemoryGrow => { - vmcalls::imported_static_memory_grow as _ - } - VmCallKind::StaticMemorySize => { - vmcalls::imported_static_memory_size as _ - } - - VmCallKind::SharedStaticMemoryGrow => unimplemented!(), - VmCallKind::SharedStaticMemorySize => unimplemented!(), - - VmCallKind::DynamicMemoryGrow => { - vmcalls::imported_dynamic_memory_grow as _ - } - VmCallKind::DynamicMemorySize => { - vmcalls::imported_dynamic_memory_size as _ - } + RelocationType::Intrinsic(ref name) => match name.as_str() { + "i32print" => i32_print as isize, + "i64print" => i64_print as isize, + "f32print" => f32_print as isize, + "f64print" => f64_print as isize, + "strtdbug" => start_debug as isize, + "enddbug" => end_debug as isize, + _ => Err(CompileError::InternalError { + msg: format!("unexpected intrinsic: {}", name), + })?, + }, + RelocationType::VmCall(vmcall) => match vmcall { + VmCall::Local(kind) => match kind { + VmCallKind::StaticMemoryGrow => vmcalls::local_static_memory_grow as _, + VmCallKind::StaticMemorySize => vmcalls::local_static_memory_size as _, + + VmCallKind::SharedStaticMemoryGrow => unimplemented!(), + VmCallKind::SharedStaticMemorySize => unimplemented!(), + + VmCallKind::DynamicMemoryGrow => { + vmcalls::local_dynamic_memory_grow as _ + } + VmCallKind::DynamicMemorySize => { + vmcalls::local_dynamic_memory_size as _ + } + }, + VmCall::Import(kind) => match kind { + VmCallKind::StaticMemoryGrow => { + vmcalls::imported_static_memory_grow as _ + } + VmCallKind::StaticMemorySize => { + vmcalls::imported_static_memory_size as _ + } + + VmCallKind::SharedStaticMemoryGrow => unimplemented!(), + VmCallKind::SharedStaticMemorySize => unimplemented!(), + + VmCallKind::DynamicMemoryGrow => { + vmcalls::imported_dynamic_memory_grow as _ + } + VmCallKind::DynamicMemorySize => { + vmcalls::imported_dynamic_memory_size as _ + } + }, + }, + RelocationType::Signature(sig_index) => { + let sig_index = + SigRegistry.lookup_sig_index(Arc::clone(&signatures[sig_index])); + sig_index.index() as _ + } + }; + + // We need the address of the current function + // because some of these calls are relative. + let func_addr = self.resolver.lookup(index).unwrap().as_ptr(); + + // Determine relocation type and apply relocation. + match reloc.reloc { + Reloc::Abs8 => { + let ptr_to_write = (target_func_address as u64) + .checked_add(reloc.addend as u64) + .unwrap(); + let empty_space_offset = self.resolver.map[index] + reloc.offset as usize; + let ptr_slice = unsafe { + &mut memory.as_slice_mut() + [empty_space_offset..empty_space_offset + 8] + }; + LittleEndian::write_u64(ptr_slice, ptr_to_write); + } + Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => unsafe { + let reloc_address = (func_addr as usize) + reloc.offset as usize; + let reloc_delta = target_func_address + .wrapping_sub(reloc_address as isize) + .wrapping_add(reloc.addend as isize); + + write_unaligned(reloc_address as *mut u32, reloc_delta as u32); }, - }, - RelocationType::Signature(sig_index) => { - let sig_index = - SigRegistry.lookup_sig_index(Arc::clone(&signatures[sig_index])); - sig_index.index() as _ } - }; - - // We need the address of the current function - // because some of these calls are relative. - let func_addr = self.resolver.lookup(index).unwrap().as_ptr(); - - // Determine relocation type and apply relocation. - match reloc.reloc { - Reloc::Abs8 => { - let ptr_to_write = (target_func_address as u64) - .checked_add(reloc.addend as u64) - .unwrap(); - let empty_space_offset = self.resolver.map[index] + reloc.offset as usize; - let ptr_slice = unsafe { - &mut self.resolver.memory.as_slice_mut() - [empty_space_offset..empty_space_offset + 8] - }; - LittleEndian::write_u64(ptr_slice, ptr_to_write); - } - Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => unsafe { - let reloc_address = (func_addr as usize) + reloc.offset as usize; - let reloc_delta = target_func_address - .wrapping_sub(reloc_address as isize) - .wrapping_add(reloc.addend as isize); - - write_unaligned(reloc_address as *mut u32, reloc_delta as u32); - }, } } + + unsafe { + memory + .protect(.., Protect::ReadExec) + .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; + } } - unsafe { - self.resolver - .memory - .protect(.., Protect::ReadExec) - .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; - } + let backend_cache = BackendCache { + external_relocs: self.external_relocs.clone(), + offsets: self.resolver.map.clone(), + trap_sink: handler_data.trap_data, + trampolines: trampolines.to_trampoline_cache(), + }; - Ok(self.resolver) + Ok((self.resolver, backend_cache)) } } +unsafe impl Sync for FuncResolver {} +unsafe impl Send for FuncResolver {} + /// Resolves a function index to a function address. pub struct FuncResolver { map: Map, - memory: Memory, + pub(crate) memory: Arc>, } impl FuncResolver { fn lookup(&self, local_func_index: LocalFuncIndex) -> Option> { let offset = *self.map.get(local_func_index)?; - let ptr = unsafe { self.memory.as_ptr().add(offset) }; + let ptr = unsafe { (*self.memory.get()).as_ptr().add(offset) }; NonNull::new(ptr).map(|nonnull| nonnull.cast()) } diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 1468d99eb..bedcff87a 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -40,11 +40,11 @@ impl UserTrapper for Trapper { pub struct Caller { func_export_set: HashSet, handler_data: HandlerData, - trampolines: Trampolines, + trampolines: Arc, } impl Caller { - pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Trampolines) -> Self { + pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Arc) -> Self { let mut func_export_set = HashSet::new(); for export_index in module.exports.values() { if let ExportIndex::Func(func_index) = export_index { @@ -187,15 +187,16 @@ fn get_func_from_index( unsafe impl Send for HandlerData {} unsafe impl Sync for HandlerData {} +#[derive(Clone)] pub struct HandlerData { - pub trap_data: TrapSink, + pub trap_data: Arc, exec_buffer_ptr: *const c_void, exec_buffer_size: usize, } impl HandlerData { pub fn new( - trap_data: TrapSink, + trap_data: Arc, exec_buffer_ptr: *const c_void, exec_buffer_size: usize, ) -> Self { diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index 76fb521d6..492314c14 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -58,7 +58,7 @@ impl Trampolines { } #[cfg(feature = "cache")] - pub fn to_trampoline_cache(self) -> TrampolineCache { + pub fn to_trampoline_cache(&self) -> TrampolineCache { let mut code = vec![0; self.memory.size()]; unsafe { @@ -67,7 +67,7 @@ impl Trampolines { TrampolineCache { code, - offsets: self.offsets, + offsets: self.offsets.clone(), } } diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 328e3c826..769281ff2 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -45,13 +45,6 @@ pub trait Compiler { #[cfg(feature = "cache")] unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result; - - #[cfg(feature = "cache")] - fn compile_to_backend_cache_data( - &self, - wasm: &[u8], - _: Token, - ) -> CompileResult<(Box, Vec, Memory)>; } /// The functionality exposed by this trait is expected to be used @@ -101,5 +94,5 @@ pub trait FuncResolver: Send + Sync { } pub trait CacheGen: Send + Sync { - fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Memory), CacheError>; + fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Arc), CacheError>; } \ No newline at end of file diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index d130b8899..6edc85e9b 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -90,17 +90,17 @@ pub fn validate(wasm: &[u8]) -> bool { } } -#[cfg(feature = "cache")] -pub fn compile_to_cache_with( - wasm: &[u8], - compiler: &dyn backend::Compiler, -) -> CompileResult { - let token = backend::Token::generate(); - let (info, backend_metadata, compiled_code) = - compiler.compile_to_backend_cache_data(wasm, token)?; +// #[cfg(feature = "cache")] +// pub fn compile_to_cache_with( +// wasm: &[u8], +// compiler: &dyn backend::Compiler, +// ) -> CompileResult { +// let token = backend::Token::generate(); +// let (info, backend_metadata, compiled_code) = +// compiler.compile_to_backend_cache_data(wasm, token)?; - Ok(Cache::new(wasm, info, backend_metadata, compiled_code)) -} +// Ok(Cache::new(wasm, info, backend_metadata, compiled_code)) +// } #[cfg(feature = "cache")] pub unsafe fn load_cache_with( diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index aca3fc221..2a398d53e 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -1,5 +1,5 @@ use crate::{ - backend::{Backend, FuncResolver, ProtectedCaller}, + backend::{Backend, FuncResolver, ProtectedCaller, CacheGen}, error::Result, import::ImportObject, structures::{Map, TypedIndex}, @@ -21,10 +21,12 @@ use std::sync::Arc; pub struct ModuleInner { pub func_resolver: Box, pub protected_caller: Box, + pub cache_gen: Box, pub info: ModuleInfo, } +#[derive(Clone)] #[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] pub struct ModuleInfo { // This are strictly local and the typsystem ensures that. diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index abea76db8..79d18255a 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -494,7 +494,8 @@ mod vm_ctx_tests { fn generate_module() -> ModuleInner { use super::Func; - use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper}; + use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper, CacheGen, sys::Memory}; + use crate::cache::Error as CacheError; use crate::error::RuntimeResult; use crate::types::{FuncIndex, LocalFuncIndex, Value}; use crate::module::WasmHash; @@ -526,10 +527,17 @@ mod vm_ctx_tests { unimplemented!() } } + impl CacheGen for Placeholder { + fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Memory), CacheError> { + unimplemented!() + } + } + ModuleInner { func_resolver: Box::new(Placeholder), protected_caller: Box::new(Placeholder), + cache_gen: Box::new(Placeholder), info: ModuleInfo { memories: Map::new(), globals: Map::new(), From 82eea00a023779bc353d69ef47c17e87d6cc308c Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Tue, 19 Feb 2019 15:36:22 -0800 Subject: [PATCH 03/14] Saved --- lib/clif-backend/Cargo.toml | 8 - lib/clif-backend/src/cache.rs | 19 +- lib/clif-backend/src/lib.rs | 12 +- lib/clif-backend/src/module.rs | 37 +--- lib/clif-backend/src/relocation.rs | 18 +- lib/clif-backend/src/resolver.rs | 245 ++++++++++----------- lib/clif-backend/src/trampoline.rs | 6 +- lib/runtime-core/Cargo.toml | 12 +- lib/runtime-core/src/backend.rs | 11 +- lib/runtime-core/src/cache.rs | 29 +-- lib/runtime-core/src/lib.rs | 10 +- lib/runtime-core/src/module.rs | 42 ++-- lib/runtime-core/src/structures/map.rs | 2 +- lib/runtime-core/src/sys/mod.rs | 10 +- lib/runtime-core/src/sys/unix/memory.rs | 12 +- lib/runtime-core/src/sys/windows/memory.rs | 12 +- lib/runtime-core/src/types.rs | 22 +- lib/runtime-core/src/units.rs | 4 +- lib/runtime/Cargo.toml | 11 +- lib/spectests/Cargo.toml | 2 +- 20 files changed, 267 insertions(+), 257 deletions(-) diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index becb71a04..701f821fc 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -23,24 +23,16 @@ libc = "0.2.48" # Dependencies for caching. [dependencies.serde] version = "1.0" -optional = true [dependencies.serde_derive] version = "1.0" -optional = true [dependencies.serde_bytes] version = "0.10" -optional = true -# [dependencies.bincode] -# version = "1.0.1" -# optional = true [dependencies.serde-bench] version = "0.0.7" -optional = true [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" } [features] -cache = ["serde", "serde_derive", "serde_bytes", "serde-bench", "wasmer-runtime-core/cache"] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/clif-backend/src/cache.rs b/lib/clif-backend/src/cache.rs index cf1b9c919..7e805271b 100644 --- a/lib/clif-backend/src/cache.rs +++ b/lib/clif-backend/src/cache.rs @@ -32,8 +32,7 @@ impl CacheGenerator { impl CacheGen for CacheGenerator { fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Arc), Error> { let info = Box::new(module.info.clone()); - - Err(Error::Unknown("".to_string())) + Ok((info, self.backend_cache.into_backend_data()?.into_boxed_slice(), Arc::clone(&self.memory))) } } @@ -54,18 +53,26 @@ pub struct BackendCache { impl BackendCache { pub fn from_cache(cache: Cache) -> Result<(ModuleInfo, Memory, Self), Error> { - let (info, backend_data, compiled_code) = cache.consume(); + let (info, backend_data, compiled_code_arc) = cache.consume(); - let backend_cache = deserialize(backend_data.as_slice()) + // If this is the only references to this arc, move the memory out. + // else, clone the memory to a new location. This could take a long time, + // depending on the throughput of your memcpy implementation. + let compiled_code = match Arc::try_unwrap(compiled_code_arc) { + Ok(code) => code, + Err(arc) => (*arc).clone(), + }; + + let backend_cache = deserialize(&backend_data) .map_err(|e| Error::DeserializeError(e.to_string()))?; Ok((info, compiled_code, backend_cache)) } - pub fn into_backend_data(self) -> Result, Error> { + pub fn into_backend_data(&self) -> Result, Error> { let mut buffer = Vec::new(); - serialize(&mut buffer, &self).map_err(|e| Error::SerializeError(e.to_string()))?; + serialize(&mut buffer, self).map_err(|e| Error::SerializeError(e.to_string()))?; Ok(buffer) } diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 621d5b59e..42d56552b 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "cache")] + mod cache; mod func_env; mod libcalls; @@ -14,7 +14,7 @@ use cranelift_codegen::{ settings::{self, Configurable}, }; use target_lexicon::Triple; -#[cfg(feature = "cache")] + use wasmer_runtime_core::{ backend::sys::Memory, cache::{Cache, Error as CacheError}, @@ -25,10 +25,10 @@ use wasmer_runtime_core::{ error::{CompileError, CompileResult}, module::ModuleInner, }; -#[cfg(feature = "cache")] + #[macro_use] extern crate serde_derive; -#[cfg(feature = "cache")] + extern crate serde; use wasmparser::{self, WasmDecoder}; @@ -57,12 +57,12 @@ impl Compiler for CraneliftCompiler { } /// Create a wasmer Module from an already-compiled cache. - #[cfg(feature = "cache")] + unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result { module::Module::from_cache(cache) } - // #[cfg(feature = "cache")] + // // fn compile_to_backend_cache_data( // &self, // wasm: &[u8], diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index 23f07eac9..29eea5f2c 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "cache")] + use crate::cache::{BackendCache, CacheGenerator}; use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines}; @@ -8,7 +8,7 @@ use cranelift_wasm; use hashbrown::HashMap; use std::sync::Arc; -#[cfg(feature = "cache")] + use wasmer_runtime_core::{ backend::sys::Memory, cache::{Cache, Error as CacheError}, @@ -17,13 +17,15 @@ use wasmer_runtime_core::{ use wasmer_runtime_core::{ backend::Backend, error::CompileResult, - module::{ModuleInfo, ModuleInner, StringTable, WasmHash}, + module::{ModuleInfo, ModuleInner, StringTable}, structures::{Map, TypedIndex}, types::{ FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type, }, }; +use wasmer_runtime_core::module::WasmHash; + /// This contains all of the items in a `ModuleInner` except the `func_resolver`. pub struct Module { pub info: ModuleInfo, @@ -56,6 +58,7 @@ impl Module { namespace_table: StringTable::new(), name_table: StringTable::new(), + wasm_hash: WasmHash::generate(wasm), }, } @@ -77,37 +80,19 @@ impl Module { let protected_caller = Caller::new(&self.info, handler_data, trampolines); + let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); Ok(ModuleInner { func_resolver: Box::new(func_resolver), protected_caller: Box::new(protected_caller), - cache_gen, + cache_gen, info: self.info, }) } - // #[cfg(feature = "cache")] - // pub fn compile_to_backend_cache( - // self, - // isa: &isa::TargetIsa, - // functions: Map, - // ) -> CompileResult<(ModuleInfo, BackendCache, Memory)> { - // let (func_resolver_builder, handler_data) = - // FuncResolverBuilder::new(isa, functions, &self.info)?; - - // let trampolines = Trampolines::new(isa, &self.info); - - // let trampoline_cache = trampolines.to_trampoline_cache(); - - // let (backend_cache, compiled_code) = - // func_resolver_builder.to_backend_cache(trampoline_cache, handler_data); - - // Ok((self.info, backend_cache, compiled_code)) - // } - - #[cfg(feature = "cache")] + pub fn from_cache(cache: Cache) -> Result { let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; @@ -120,12 +105,14 @@ impl Module { .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?; let protected_caller = Caller::new(&info, handler_data, trampolines); + + let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); Ok(ModuleInner { func_resolver: Box::new(func_resolver), protected_caller: Box::new(protected_caller), - cache_gen, + cache_gen, info, }) diff --git a/lib/clif-backend/src/relocation.rs b/lib/clif-backend/src/relocation.rs index 840255e61..03adbc4bb 100644 --- a/lib/clif-backend/src/relocation.rs +++ b/lib/clif-backend/src/relocation.rs @@ -22,7 +22,7 @@ pub mod call_names { pub const DYNAMIC_MEM_SIZE: u32 = 5; } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Reloc { Abs8, @@ -30,7 +30,7 @@ pub enum Reloc { X86CallPCRel4, } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone)] pub enum LibCall { Probestack, @@ -44,7 +44,7 @@ pub enum LibCall { NearestF64, } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct ExternalRelocation { /// The relocation code. @@ -66,7 +66,7 @@ pub struct LocalRelocation { pub target: FuncIndex, } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy)] pub enum VmCallKind { StaticMemoryGrow, @@ -79,7 +79,7 @@ pub enum VmCallKind { DynamicMemorySize, } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy)] pub enum VmCall { Local(VmCallKind), @@ -87,7 +87,7 @@ pub enum VmCall { } /// Specify the type of relocation -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub enum RelocationType { Intrinsic(String), @@ -218,7 +218,7 @@ impl binemit::RelocSink for RelocSink { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy)] pub enum TrapCode { StackOverflow, @@ -244,7 +244,7 @@ impl RelocSink { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy)] pub struct TrapData { pub trapcode: TrapCode, @@ -253,7 +253,7 @@ pub struct TrapData { /// Simple implementation of a TrapSink /// that saves the info for later. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] pub struct TrapSink { trap_datas: Vec<(usize, TrapData)>, } diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 1eccb2715..06b678a5b 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "cache")] + use crate::{ cache::{BackendCache, TrampolineCache}, trampoline::Trampolines, @@ -20,7 +20,7 @@ use std::{ cell::UnsafeCell, sync::Arc, }; -#[cfg(feature = "cache")] + use wasmer_runtime_core::cache::Error as CacheError; use wasmer_runtime_core::{ self, @@ -43,16 +43,24 @@ extern "C" { pub fn __chkstk(); } +fn lookup_func(map: &SliceMap, memory: &Memory, local_func_index: LocalFuncIndex) -> Option> { + let offset = *map.get(local_func_index)?; + let ptr = unsafe { memory.as_ptr().add(offset) }; + + NonNull::new(ptr).map(|nonnull| nonnull.cast()) +} + #[allow(dead_code)] pub struct FuncResolverBuilder { - resolver: FuncResolver, + map: Map, + memory: Memory, local_relocs: Map>, external_relocs: Map>, import_len: usize, } impl FuncResolverBuilder { - #[cfg(feature = "cache")] + pub fn new_from_backend_cache( backend_cache: BackendCache, mut code: Memory, @@ -68,10 +76,8 @@ impl FuncResolverBuilder { Ok(( Self { - resolver: FuncResolver { - map: backend_cache.offsets, - memory: Arc::new(UnsafeCell::new(code)), - }, + map: backend_cache.offsets, + memory: code, local_relocs: Map::new(), external_relocs: backend_cache.external_relocs, import_len: info.imported_functions.len(), @@ -155,7 +161,8 @@ impl FuncResolverBuilder { let handler_data = HandlerData::new(Arc::new(trap_sink), memory.as_ptr() as _, memory.size()); let mut func_resolver_builder = Self { - resolver: FuncResolver { map, memory: Arc::new(UnsafeCell::new(memory)) }, + map, + memory, local_relocs, external_relocs, import_len: info.imported_functions.len(), @@ -171,11 +178,11 @@ impl FuncResolverBuilder { for ref reloc in relocs.iter() { let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len); let target_func_address = - self.resolver.lookup(local_func_index).unwrap().as_ptr() as usize; + lookup_func(&self.map, &self.memory, local_func_index).unwrap().as_ptr() as usize; // We need the address of the current function // because these calls are relative. - let func_addr = self.resolver.lookup(index).unwrap().as_ptr() as usize; + let func_addr = lookup_func(&self.map, &self.memory, index).unwrap().as_ptr() as usize; unsafe { let reloc_address = func_addr + reloc.offset as usize; @@ -190,127 +197,126 @@ impl FuncResolverBuilder { } pub fn finalize( - self, + mut self, signatures: &SliceMap>, trampolines: Arc, handler_data: HandlerData, ) -> CompileResult<(FuncResolver, BackendCache)> { - { - let mut memory = unsafe { (*self.resolver.memory.get()) }; + for (index, relocs) in self.external_relocs.iter() { + for ref reloc in relocs.iter() { + let target_func_address: isize = match reloc.target { + RelocationType::LibCall(libcall) => match libcall { + LibCall::CeilF32 => libcalls::ceilf32 as isize, + LibCall::FloorF32 => libcalls::floorf32 as isize, + LibCall::TruncF32 => libcalls::truncf32 as isize, + LibCall::NearestF32 => libcalls::nearbyintf32 as isize, + LibCall::CeilF64 => libcalls::ceilf64 as isize, + LibCall::FloorF64 => libcalls::floorf64 as isize, + LibCall::TruncF64 => libcalls::truncf64 as isize, + LibCall::NearestF64 => libcalls::nearbyintf64 as isize, + #[cfg(all(target_pointer_width = "64", target_os = "windows"))] + LibCall::Probestack => __chkstk as isize, + #[cfg(not(target_os = "windows"))] + LibCall::Probestack => __rust_probestack as isize, + }, + RelocationType::Intrinsic(ref name) => match name.as_str() { + "i32print" => i32_print as isize, + "i64print" => i64_print as isize, + "f32print" => f32_print as isize, + "f64print" => f64_print as isize, + "strtdbug" => start_debug as isize, + "enddbug" => end_debug as isize, + _ => Err(CompileError::InternalError { + msg: format!("unexpected intrinsic: {}", name), + })?, + }, + RelocationType::VmCall(vmcall) => match vmcall { + VmCall::Local(kind) => match kind { + VmCallKind::StaticMemoryGrow => vmcalls::local_static_memory_grow as _, + VmCallKind::StaticMemorySize => vmcalls::local_static_memory_size as _, - for (index, relocs) in self.external_relocs.iter() { - for ref reloc in relocs.iter() { - let target_func_address: isize = match reloc.target { - RelocationType::LibCall(libcall) => match libcall { - LibCall::CeilF32 => libcalls::ceilf32 as isize, - LibCall::FloorF32 => libcalls::floorf32 as isize, - LibCall::TruncF32 => libcalls::truncf32 as isize, - LibCall::NearestF32 => libcalls::nearbyintf32 as isize, - LibCall::CeilF64 => libcalls::ceilf64 as isize, - LibCall::FloorF64 => libcalls::floorf64 as isize, - LibCall::TruncF64 => libcalls::truncf64 as isize, - LibCall::NearestF64 => libcalls::nearbyintf64 as isize, - #[cfg(all(target_pointer_width = "64", target_os = "windows"))] - LibCall::Probestack => __chkstk as isize, - #[cfg(not(target_os = "windows"))] - LibCall::Probestack => __rust_probestack as isize, + VmCallKind::SharedStaticMemoryGrow => unimplemented!(), + VmCallKind::SharedStaticMemorySize => unimplemented!(), + + VmCallKind::DynamicMemoryGrow => { + vmcalls::local_dynamic_memory_grow as _ + } + VmCallKind::DynamicMemorySize => { + vmcalls::local_dynamic_memory_size as _ + } }, - RelocationType::Intrinsic(ref name) => match name.as_str() { - "i32print" => i32_print as isize, - "i64print" => i64_print as isize, - "f32print" => f32_print as isize, - "f64print" => f64_print as isize, - "strtdbug" => start_debug as isize, - "enddbug" => end_debug as isize, - _ => Err(CompileError::InternalError { - msg: format!("unexpected intrinsic: {}", name), - })?, - }, - RelocationType::VmCall(vmcall) => match vmcall { - VmCall::Local(kind) => match kind { - VmCallKind::StaticMemoryGrow => vmcalls::local_static_memory_grow as _, - VmCallKind::StaticMemorySize => vmcalls::local_static_memory_size as _, - - VmCallKind::SharedStaticMemoryGrow => unimplemented!(), - VmCallKind::SharedStaticMemorySize => unimplemented!(), - - VmCallKind::DynamicMemoryGrow => { - vmcalls::local_dynamic_memory_grow as _ - } - VmCallKind::DynamicMemorySize => { - vmcalls::local_dynamic_memory_size as _ - } - }, - VmCall::Import(kind) => match kind { - VmCallKind::StaticMemoryGrow => { - vmcalls::imported_static_memory_grow as _ - } - VmCallKind::StaticMemorySize => { - vmcalls::imported_static_memory_size as _ - } - - VmCallKind::SharedStaticMemoryGrow => unimplemented!(), - VmCallKind::SharedStaticMemorySize => unimplemented!(), - - VmCallKind::DynamicMemoryGrow => { - vmcalls::imported_dynamic_memory_grow as _ - } - VmCallKind::DynamicMemorySize => { - vmcalls::imported_dynamic_memory_size as _ - } - }, - }, - RelocationType::Signature(sig_index) => { - let sig_index = - SigRegistry.lookup_sig_index(Arc::clone(&signatures[sig_index])); - sig_index.index() as _ - } - }; - - // We need the address of the current function - // because some of these calls are relative. - let func_addr = self.resolver.lookup(index).unwrap().as_ptr(); - - // Determine relocation type and apply relocation. - match reloc.reloc { - Reloc::Abs8 => { - let ptr_to_write = (target_func_address as u64) - .checked_add(reloc.addend as u64) - .unwrap(); - let empty_space_offset = self.resolver.map[index] + reloc.offset as usize; - let ptr_slice = unsafe { - &mut memory.as_slice_mut() - [empty_space_offset..empty_space_offset + 8] - }; - LittleEndian::write_u64(ptr_slice, ptr_to_write); - } - Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => unsafe { - let reloc_address = (func_addr as usize) + reloc.offset as usize; - let reloc_delta = target_func_address - .wrapping_sub(reloc_address as isize) - .wrapping_add(reloc.addend as isize); - - write_unaligned(reloc_address as *mut u32, reloc_delta as u32); + VmCall::Import(kind) => match kind { + VmCallKind::StaticMemoryGrow => { + vmcalls::imported_static_memory_grow as _ + } + VmCallKind::StaticMemorySize => { + vmcalls::imported_static_memory_size as _ + } + + VmCallKind::SharedStaticMemoryGrow => unimplemented!(), + VmCallKind::SharedStaticMemorySize => unimplemented!(), + + VmCallKind::DynamicMemoryGrow => { + vmcalls::imported_dynamic_memory_grow as _ + } + VmCallKind::DynamicMemorySize => { + vmcalls::imported_dynamic_memory_size as _ + } }, + }, + RelocationType::Signature(sig_index) => { + let sig_index = + SigRegistry.lookup_sig_index(Arc::clone(&signatures[sig_index])); + sig_index.index() as _ } + }; + + // We need the address of the current function + // because some of these calls are relative. + let func_addr = lookup_func(&self.map, &self.memory, index).unwrap().as_ptr() as usize; + + // Determine relocation type and apply relocation. + match reloc.reloc { + Reloc::Abs8 => { + let ptr_to_write = (target_func_address as u64) + .checked_add(reloc.addend as u64) + .unwrap(); + let empty_space_offset = self.map[index] + reloc.offset as usize; + let ptr_slice = unsafe { + &mut self.memory.as_slice_mut() + [empty_space_offset..empty_space_offset + 8] + }; + LittleEndian::write_u64(ptr_slice, ptr_to_write); + } + Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => unsafe { + let reloc_address = (func_addr as usize) + reloc.offset as usize; + let reloc_delta = target_func_address + .wrapping_sub(reloc_address as isize) + .wrapping_add(reloc.addend as isize); + + write_unaligned(reloc_address as *mut u32, reloc_delta as u32); + }, } } + } - unsafe { - memory - .protect(.., Protect::ReadExec) - .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; - } + unsafe { + self.memory + .protect(.., Protect::ReadExec) + .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; } let backend_cache = BackendCache { external_relocs: self.external_relocs.clone(), - offsets: self.resolver.map.clone(), + offsets: self.map.clone(), trap_sink: handler_data.trap_data, trampolines: trampolines.to_trampoline_cache(), }; - Ok((self.resolver, backend_cache)) + Ok((FuncResolver { + map: self.map, + memory: Arc::new(self.memory), + }, backend_cache)) } } @@ -320,16 +326,7 @@ unsafe impl Send for FuncResolver {} /// Resolves a function index to a function address. pub struct FuncResolver { map: Map, - pub(crate) memory: Arc>, -} - -impl FuncResolver { - fn lookup(&self, local_func_index: LocalFuncIndex) -> Option> { - let offset = *self.map.get(local_func_index)?; - let ptr = unsafe { (*self.memory.get()).as_ptr().add(offset) }; - - NonNull::new(ptr).map(|nonnull| nonnull.cast()) - } + pub(crate) memory: Arc, } // Implements FuncResolver trait. @@ -339,7 +336,7 @@ impl backend::FuncResolver for FuncResolver { _module: &wasmer_runtime_core::module::ModuleInner, index: LocalFuncIndex, ) -> Option> { - self.lookup(index) + lookup_func(&self.map, &self.memory, index) } } diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index 492314c14..7a90c085e 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "cache")] + use crate::cache::TrampolineCache; use cranelift_codegen::{ binemit::{NullTrapSink, Reloc, RelocSink}, @@ -33,7 +33,7 @@ pub struct Trampolines { } impl Trampolines { - #[cfg(feature = "cache")] + pub fn from_trampoline_cache(cache: TrampolineCache) -> Self { // pub struct TrampolineCache { // #[serde(with = "serde_bytes")] @@ -57,7 +57,7 @@ impl Trampolines { } } - #[cfg(feature = "cache")] + pub fn to_trampoline_cache(&self) -> TrampolineCache { let mut code = vec![0; self.memory.size()]; diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 9a748eb62..4781751af 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -8,7 +8,6 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [dependencies] -hashbrown = "0.1" nix = "0.12.0" page_size = "0.4.1" wasmparser = "0.23.0" @@ -21,22 +20,20 @@ libc = "0.2.48" # Dependencies for caching. [dependencies.serde] version = "1.0" -optional = true +features = ["rc"] [dependencies.serde_derive] version = "1.0" -optional = true [dependencies.serde_bytes] version = "0.10" -optional = true [dependencies.serde-bench] version = "0.0.7" -optional = true [dependencies.memmap] version = "0.7.0" -optional = true [dependencies.sha2] version = "0.8.0" -optional = true +[dependencies.hashbrown] +version = "0.1" +features = ["serde"] [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["memoryapi"] } @@ -47,5 +44,4 @@ field-offset = "0.1.1" [features] debug = [] -cache = ["serde/rc", "serde_derive", "serde_bytes", "hashbrown/serde", "serde-bench", "memmap", "sha2"] diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 769281ff2..a4afe2ee5 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -2,11 +2,11 @@ use crate::{ backing::ImportBacking, error::CompileResult, error::RuntimeResult, - module::ModuleInner, + module::{ModuleInner}, types::{FuncIndex, LocalFuncIndex, Value}, vm, }; -#[cfg(feature = "cache")] + use crate::{ cache::{Cache, Error as CacheError}, module::ModuleInfo, @@ -14,12 +14,14 @@ use crate::{ }; use std::ptr::NonNull; +use std::sync::Arc; + pub mod sys { pub use crate::sys::*; } pub use crate::sig_registry::SigRegistry; -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Backend { Cranelift, @@ -43,7 +45,7 @@ pub trait Compiler { /// be called from inside the runtime. fn compile(&self, wasm: &[u8], _: Token) -> CompileResult; - #[cfg(feature = "cache")] + unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result; } @@ -93,6 +95,7 @@ pub trait FuncResolver: Send + Sync { ) -> Option>; } + pub trait CacheGen: Send + Sync { fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Arc), CacheError>; } \ No newline at end of file diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index e166599e8..b60301e94 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -6,6 +6,7 @@ use std::{ fs::File, io::{self, Seek, SeekFrom, Write}, mem, + sync::Arc, path::Path, slice, }; @@ -67,31 +68,26 @@ impl CacheHeader { struct CacheInner { info: Box, #[serde(with = "serde_bytes")] - backend_metadata: Vec, - compiled_code: Memory, + backend_metadata: Box<[u8]>, + compiled_code: Arc, } pub struct Cache { inner: CacheInner, - wasm_hash: Box<[u8; 32]>, } impl Cache { - pub(crate) fn new( - wasm: &[u8], + pub(crate) fn from_parts( info: Box, - backend_metadata: Vec, - compiled_code: Memory, + backend_metadata: Box<[u8]>, + compiled_code: Arc, ) -> Self { - let wasm_hash = hash_data(wasm); - Self { inner: CacheInner { info, backend_metadata, compiled_code, }, - wasm_hash: Box::new(wasm_hash), } } @@ -110,7 +106,6 @@ impl Cache { Ok(Cache { inner, - wasm_hash: Box::new(header.wasm_hash), }) } @@ -118,12 +113,8 @@ impl Cache { &self.inner.info } - pub fn wasm_hash(&self) -> &[u8; 32] { - &self.wasm_hash - } - #[doc(hidden)] - pub fn consume(self) -> (ModuleInfo, Vec, Memory) { + pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Arc) { ( *self.inner.info, self.inner.backend_metadata, @@ -152,11 +143,7 @@ impl Cache { file.seek(SeekFrom::Start(0)) .map_err(|e| Error::Unknown(e.to_string()))?; - let wasm_hash = { - let mut array = [0u8; 32]; - array.copy_from_slice(&*self.wasm_hash); - array - }; + let wasm_hash = self.inner.info.wasm_hash.into_array(); let cache_header = CacheHeader { magic: [ diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 6edc85e9b..18cf2a703 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -2,7 +2,7 @@ #[macro_use] extern crate field_offset; -#[cfg(feature = "cache")] + #[macro_use] extern crate serde_derive; @@ -11,7 +11,7 @@ mod macros; #[doc(hidden)] pub mod backend; mod backing; -#[cfg(feature = "cache")] + pub mod cache; pub mod error; pub mod export; @@ -44,7 +44,7 @@ pub use self::module::Module; pub use self::typed_func::Func; use std::sync::Arc; -#[cfg(feature = "cache")] + use self::cache::{Cache, Error as CacheError}; pub mod prelude { @@ -90,7 +90,7 @@ pub fn validate(wasm: &[u8]) -> bool { } } -// #[cfg(feature = "cache")] +// // pub fn compile_to_cache_with( // wasm: &[u8], // compiler: &dyn backend::Compiler, @@ -102,7 +102,7 @@ pub fn validate(wasm: &[u8]) -> bool { // Ok(Cache::new(wasm, info, backend_metadata, compiled_code)) // } -#[cfg(feature = "cache")] + pub unsafe fn load_cache_with( cache: Cache, compiler: &dyn backend::Compiler, diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 2a398d53e..0526c0ad4 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -1,6 +1,6 @@ use crate::{ - backend::{Backend, FuncResolver, ProtectedCaller, CacheGen}, - error::Result, + backend::{Backend, FuncResolver, ProtectedCaller}, + error, import::ImportObject, structures::{Map, TypedIndex}, typed_func::EARLY_TRAPPER, @@ -10,8 +10,11 @@ use crate::{ LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, TableIndex, }, + cache::{Cache, Error as CacheError}, Instance, }; + +use crate::backend::CacheGen; use hashbrown::HashMap; use indexmap::IndexMap; use std::sync::Arc; @@ -21,13 +24,15 @@ use std::sync::Arc; pub struct ModuleInner { pub func_resolver: Box, pub protected_caller: Box, + + pub cache_gen: Box, pub info: ModuleInfo, } #[derive(Clone)] -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] pub struct ModuleInfo { // This are strictly local and the typsystem ensures that. pub memories: Map, @@ -57,13 +62,19 @@ pub struct ModuleInfo { pub wasm_hash: WasmHash, } + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] pub struct WasmHash([u8; 32]); + impl WasmHash { pub fn generate(wasm: &[u8]) -> Self { - WasmHash(super::cache::hash_data(wasm)) + WasmHash(crate::cache::hash_data(wasm)) + } + + pub(crate) fn into_array(self) -> [u8; 32] { + self.0 } } @@ -109,22 +120,27 @@ impl Module { /// # Ok(()) /// # } /// ``` - pub fn instantiate(&self, import_object: &ImportObject) -> Result { + pub fn instantiate(&self, import_object: &ImportObject) -> error::Result { Instance::new(Arc::clone(&self.inner), import_object) } + + pub fn cache(&self) -> Result { + let (info, backend_cache, code) = self.inner.cache_gen.generate_cache(&self.inner)?; + + } } impl ModuleInner {} #[doc(hidden)] -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct ImportName { pub namespace_index: NamespaceIndex, pub name_index: NameIndex, } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExportIndex { Func(FuncIndex), @@ -134,7 +150,7 @@ pub enum ExportIndex { } /// A data initializer for linear memory. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct DataInitializer { /// The index of the memory to initialize. @@ -147,7 +163,7 @@ pub struct DataInitializer { } /// A WebAssembly table initializer. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct TableInitializer { /// The index of a table to initialize. @@ -209,7 +225,7 @@ impl StringTableBuilder { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct StringTable { table: Map, @@ -233,7 +249,7 @@ impl StringTable { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NamespaceIndex(u32); @@ -249,7 +265,7 @@ impl TypedIndex for NamespaceIndex { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NameIndex(u32); diff --git a/lib/runtime-core/src/structures/map.rs b/lib/runtime-core/src/structures/map.rs index f67000b6d..df95fe652 100644 --- a/lib/runtime-core/src/structures/map.rs +++ b/lib/runtime-core/src/structures/map.rs @@ -8,7 +8,7 @@ use std::{ }; /// Dense item map -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct Map where diff --git a/lib/runtime-core/src/sys/mod.rs b/lib/runtime-core/src/sys/mod.rs index 4079a506d..2fdc1ef0f 100644 --- a/lib/runtime-core/src/sys/mod.rs +++ b/lib/runtime-core/src/sys/mod.rs @@ -10,18 +10,18 @@ pub use self::unix::*; #[cfg(windows)] pub use self::windows::*; -#[cfg(feature = "cache")] + use serde::{ de::{self, SeqAccess, Visitor}, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer, }; -#[cfg(feature = "cache")] + use serde_bytes::Bytes; -#[cfg(feature = "cache")] + use std::fmt; -#[cfg(feature = "cache")] + impl Serialize for Memory { fn serialize(&self, serializer: S) -> Result where @@ -36,7 +36,7 @@ impl Serialize for Memory { } } -#[cfg(feature = "cache")] + impl<'de> Deserialize<'de> for Memory { fn deserialize(deserializer: D) -> Result where diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index d1579d958..7154f34f9 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -205,7 +205,17 @@ impl Drop for Memory { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +impl Clone for Memory { + fn clone(&self) -> Self { + let mut new = Memory::with_size_protect(self.size, self.protection).unwrap(); + unsafe { + new.as_slice_mut().copy_from_slice(self.as_slice()); + } + new + } +} + +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { diff --git a/lib/runtime-core/src/sys/windows/memory.rs b/lib/runtime-core/src/sys/windows/memory.rs index c8fd197eb..578070a3e 100644 --- a/lib/runtime-core/src/sys/windows/memory.rs +++ b/lib/runtime-core/src/sys/windows/memory.rs @@ -156,7 +156,17 @@ impl Drop for Memory { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +impl Clone for Memory { + fn clone(&self) -> Self { + let mut new = Memory::with_size_protect(self.size, self.protection).unwrap(); + unsafe { + new.as_slice_mut().copy_from_slice(self.as_slice()); + } + new + } +} + +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 271b336ba..f19e73a6e 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -2,7 +2,7 @@ use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, unit use std::{borrow::Cow, mem}; /// Represents a WebAssembly type. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Type { /// The `i32` type. @@ -25,7 +25,7 @@ impl std::fmt::Display for Type { /// /// As the number of types in WebAssembly expand, /// this structure will expand as well. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq)] pub enum Value { /// The `i32` type. @@ -171,14 +171,14 @@ impl ValueType for f64 { } } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ElementType { /// Any wasm function. Anyfunc, } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy)] pub struct TableDescriptor { /// Type of data stored in this table. @@ -203,7 +203,7 @@ impl TableDescriptor { /// A const value initializer. /// Over time, this will be able to represent more and more /// complex expressions. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq)] pub enum Initializer { /// Corresponds to a `const.*` instruction. @@ -212,7 +212,7 @@ pub enum Initializer { GetGlobal(ImportedGlobalIndex), } -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct GlobalDescriptor { pub mutable: bool, @@ -220,7 +220,7 @@ pub struct GlobalDescriptor { } /// A wasm global. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone)] pub struct GlobalInit { pub desc: GlobalDescriptor, @@ -228,7 +228,7 @@ pub struct GlobalInit { } /// A wasm memory. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MemoryDescriptor { /// The minimum number of allowed pages. @@ -261,7 +261,7 @@ impl MemoryDescriptor { /// The signature of a function that is either implemented /// in a wasm module or exposed to wasm by the host. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FuncSig { params: Cow<'static, [Type]>, @@ -324,7 +324,7 @@ pub trait LocalImport { #[rustfmt::skip] macro_rules! define_map_index { ($ty:ident) => { - #[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] + #[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct $ty (u32); impl TypedIndex for $ty { @@ -400,7 +400,7 @@ define_local_or_import![ (GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals), ]; -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct SigIndex(u32); impl TypedIndex for SigIndex { diff --git a/lib/runtime-core/src/units.rs b/lib/runtime-core/src/units.rs index 8fa54474b..6a1582e9e 100644 --- a/lib/runtime-core/src/units.rs +++ b/lib/runtime-core/src/units.rs @@ -7,7 +7,7 @@ const WASM_PAGE_SIZE: usize = 65_536; const WASM_MAX_PAGES: usize = 65_536; /// Units of WebAssembly pages (as specified to be 65,536 bytes). -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Pages(pub u32); @@ -33,7 +33,7 @@ impl fmt::Debug for Pages { } /// Units of WebAssembly memory in terms of 8-bit bytes. -#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Bytes(pub usize); diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index fe6cc80d2..29af96844 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -9,10 +9,15 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" } lazy_static = "1.2.0" +[dependencies.wasmer-runtime-core] +path = "../runtime-core" +version = "0.1.2" + +[dependencies.wasmer-clif-backend] +path = "../clif-backend" +version = "0.1.2" + [features] -default = ["wasmer-clif-backend/cache", "wasmer-runtime-core/cache"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] diff --git a/lib/spectests/Cargo.toml b/lib/spectests/Cargo.toml index c02e8269d..f69782b40 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -19,5 +19,5 @@ wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" } wabt = "0.7.2" [features] -default = ["fast-tests", "wasmer-runtime-core/cache", "wasmer-clif-backend/cache"] +default = ["fast-tests"] fast-tests = [] \ No newline at end of file From 9f40eedba87a1ca4a810f537cf712fbbaadf16bd Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Wed, 20 Feb 2019 16:41:41 -0800 Subject: [PATCH 04/14] Get caching working again --- lib/clif-backend/src/cache.rs | 45 +++---- lib/clif-backend/src/func_env.rs | 130 +++++++++++---------- lib/clif-backend/src/lib.rs | 11 +- lib/clif-backend/src/module.rs | 48 ++++---- lib/clif-backend/src/relocation.rs | 24 ++-- lib/clif-backend/src/resolver.rs | 45 ++++--- lib/clif-backend/src/signal/mod.rs | 6 +- lib/clif-backend/src/trampoline.rs | 3 - lib/emscripten/src/lib.rs | 10 +- lib/emscripten/src/utils.rs | 11 +- lib/runtime-core/src/backend.rs | 14 +-- lib/runtime-core/src/cache.rs | 12 +- lib/runtime-core/src/lib.rs | 5 +- lib/runtime-core/src/module.rs | 40 +++---- lib/runtime-core/src/structures/map.rs | 3 +- lib/runtime-core/src/sys/mod.rs | 3 - lib/runtime-core/src/sys/unix/memory.rs | 16 ++- lib/runtime-core/src/sys/windows/memory.rs | 16 ++- lib/runtime-core/src/types.rs | 30 ++--- lib/runtime-core/src/units.rs | 6 +- lib/runtime-core/src/vm.rs | 12 +- 21 files changed, 244 insertions(+), 246 deletions(-) diff --git a/lib/clif-backend/src/cache.rs b/lib/clif-backend/src/cache.rs index 7e805271b..84db980b0 100644 --- a/lib/clif-backend/src/cache.rs +++ b/lib/clif-backend/src/cache.rs @@ -1,20 +1,14 @@ use crate::relocation::{ExternalRelocation, TrapSink}; use hashbrown::HashMap; +use std::sync::Arc; use wasmer_runtime_core::{ - backend::{ - sys::Memory, - CacheGen, - }, + backend::{sys::Memory, CacheGen}, cache::{Cache, Error}, module::{ModuleInfo, ModuleInner}, structures::Map, types::{LocalFuncIndex, SigIndex}, }; -use std::{ - sync::Arc, - cell::UnsafeCell, -}; use serde_bench::{deserialize, serialize}; @@ -25,14 +19,29 @@ pub struct CacheGenerator { impl CacheGenerator { pub fn new(backend_cache: BackendCache, memory: Arc) -> Self { - Self { backend_cache, memory } + Self { + backend_cache, + memory, + } } } impl CacheGen for CacheGenerator { - fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Arc), Error> { + fn generate_cache( + &self, + module: &ModuleInner, + ) -> Result<(Box, Box<[u8]>, Memory), Error> { let info = Box::new(module.info.clone()); - Ok((info, self.backend_cache.into_backend_data()?.into_boxed_slice(), Arc::clone(&self.memory))) + + // Clone the memory to a new location. This could take a long time, + // depending on the throughput of your memcpy implementation. + let compiled_code = (*self.memory).clone(); + + Ok(( + info, + self.backend_cache.into_backend_data()?.into_boxed_slice(), + compiled_code, + )) } } @@ -53,18 +62,10 @@ pub struct BackendCache { impl BackendCache { pub fn from_cache(cache: Cache) -> Result<(ModuleInfo, Memory, Self), Error> { - let (info, backend_data, compiled_code_arc) = cache.consume(); + let (info, backend_data, compiled_code) = cache.consume(); - // If this is the only references to this arc, move the memory out. - // else, clone the memory to a new location. This could take a long time, - // depending on the throughput of your memcpy implementation. - let compiled_code = match Arc::try_unwrap(compiled_code_arc) { - Ok(code) => code, - Err(arc) => (*arc).clone(), - }; - - let backend_cache = deserialize(&backend_data) - .map_err(|e| Error::DeserializeError(e.to_string()))?; + let backend_cache = + deserialize(&backend_data).map_err(|e| Error::DeserializeError(e.to_string()))?; Ok((info, compiled_code, backend_cache)) } diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs index e222f2e07..b08f56dd2 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/func_env.rs @@ -145,48 +145,49 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_memories() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let local_memory_ptr_offset = - local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), + let (local_memory_ptr_ptr, description) = + match mem_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_memories() as i32).into(), global_type: ptr_type, - }), - self.env.module.info.memories[local_mem_index], - ) - } - LocalOrImport::Import(import_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_memories() as i32).into(), - global_type: ptr_type, - readonly: true, - }); + readonly: true, + }); - let local_memory_ptr_offset = - import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + let local_memory_ptr_offset = + local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), + global_type: ptr_type, + }), + self.env.module.info.memories[local_mem_index], + ) + } + LocalOrImport::Import(import_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_memories() as i32).into(), global_type: ptr_type, - }), - self.env.module.info.imported_memories[import_mem_index].1, - ) - } - }; + readonly: true, + }); + + let local_memory_ptr_offset = + import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), + global_type: ptr_type, + }), + self.env.module.info.imported_memories[import_mem_index].1, + ) + } + }; let (local_memory_ptr, local_memory_base) = { let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load { @@ -253,7 +254,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let (table_struct_ptr_ptr, description) = match table_index.local_or_import(&self.env.module.info) + let (table_struct_ptr_ptr, description) = match table_index + .local_or_import(&self.env.module.info) { LocalOrImport::Local(local_table_index) => { let tables_base = func.create_global_value(ir::GlobalValueData::Load { @@ -568,18 +570,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.env.module.info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.env.module.info.imported_memories[import_mem_index].1, - ), - }; + let (namespace, mem_index, description) = + match mem_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.env.module.info.memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.env.module.info.imported_memories[import_mem_index].1, + ), + }; let name_index = match description.memory_type() { MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW, @@ -631,18 +634,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.env.module.info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.env.module.info.imported_memories[import_mem_index].1, - ), - }; + let (namespace, mem_index, description) = + match mem_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.env.module.info.memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.env.module.info.imported_memories[import_mem_index].1, + ), + }; let name_index = match description.memory_type() { MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE, diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 42d56552b..8d756420e 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,4 +1,3 @@ - mod cache; mod func_env; mod libcalls; @@ -15,11 +14,7 @@ use cranelift_codegen::{ }; use target_lexicon::Triple; -use wasmer_runtime_core::{ - backend::sys::Memory, - cache::{Cache, Error as CacheError}, - module::ModuleInfo, -}; +use wasmer_runtime_core::cache::{Cache, Error as CacheError}; use wasmer_runtime_core::{ backend::{Compiler, Token}, error::{CompileError, CompileResult}, @@ -57,12 +52,12 @@ impl Compiler for CraneliftCompiler { } /// Create a wasmer Module from an already-compiled cache. - + unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result { module::Module::from_cache(cache) } - // + // // fn compile_to_backend_cache_data( // &self, // wasm: &[u8], diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index 29eea5f2c..0d0c66d7c 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -1,4 +1,3 @@ - use crate::cache::{BackendCache, CacheGenerator}; use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines}; @@ -8,11 +7,7 @@ use cranelift_wasm; use hashbrown::HashMap; use std::sync::Arc; - -use wasmer_runtime_core::{ - backend::sys::Memory, - cache::{Cache, Error as CacheError}, -}; +use wasmer_runtime_core::cache::{Cache, Error as CacheError}; use wasmer_runtime_core::{ backend::Backend, @@ -58,7 +53,6 @@ impl Module { namespace_table: StringTable::new(), name_table: StringTable::new(), - wasm_hash: WasmHash::generate(wasm), }, } @@ -74,45 +68,53 @@ impl Module { let trampolines = Arc::new(Trampolines::new(isa, &self.info)); - let (func_resolver, backend_cache) = - func_resolver_builder.finalize(&self.info.signatures, Arc::clone(&trampolines), handler_data.clone())?; + let (func_resolver, backend_cache) = func_resolver_builder.finalize( + &self.info.signatures, + Arc::clone(&trampolines), + handler_data.clone(), + )?; - let protected_caller = - Caller::new(&self.info, handler_data, trampolines); - - - let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); + let protected_caller = Caller::new(&self.info, handler_data, trampolines); + + let cache_gen = Box::new(CacheGenerator::new( + backend_cache, + Arc::clone(&func_resolver.memory), + )); Ok(ModuleInner { func_resolver: Box::new(func_resolver), protected_caller: Box::new(protected_caller), - cache_gen, + cache_gen, info: self.info, }) } - pub fn from_cache(cache: Cache) -> Result { let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; let (func_resolver_builder, trampolines, handler_data) = FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?; - let (func_resolver, backend_cache) = - func_resolver_builder - .finalize(&info.signatures, Arc::clone(&trampolines), handler_data.clone()) - .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?; + let (func_resolver, backend_cache) = func_resolver_builder + .finalize( + &info.signatures, + Arc::clone(&trampolines), + handler_data.clone(), + ) + .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?; let protected_caller = Caller::new(&info, handler_data, trampolines); - - let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); + let cache_gen = Box::new(CacheGenerator::new( + backend_cache, + Arc::clone(&func_resolver.memory), + )); Ok(ModuleInner { func_resolver: Box::new(func_resolver), protected_caller: Box::new(protected_caller), - cache_gen, + cache_gen, info, }) diff --git a/lib/clif-backend/src/relocation.rs b/lib/clif-backend/src/relocation.rs index 03adbc4bb..92ef0485a 100644 --- a/lib/clif-backend/src/relocation.rs +++ b/lib/clif-backend/src/relocation.rs @@ -22,16 +22,14 @@ pub mod call_names { pub const DYNAMIC_MEM_SIZE: u32 = 5; } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] pub enum Reloc { Abs8, X86PCRel4, X86CallPCRel4, } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone)] pub enum LibCall { Probestack, CeilF32, @@ -44,8 +42,7 @@ pub enum LibCall { NearestF64, } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct ExternalRelocation { /// The relocation code. pub reloc: Reloc, @@ -66,8 +63,7 @@ pub struct LocalRelocation { pub target: FuncIndex, } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum VmCallKind { StaticMemoryGrow, StaticMemorySize, @@ -79,16 +75,14 @@ pub enum VmCallKind { DynamicMemorySize, } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum VmCall { Local(VmCallKind), Import(VmCallKind), } /// Specify the type of relocation -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub enum RelocationType { Intrinsic(String), LibCall(LibCall), @@ -218,8 +212,7 @@ impl binemit::RelocSink for RelocSink { } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum TrapCode { StackOverflow, HeapOutOfBounds, @@ -244,8 +237,7 @@ impl RelocSink { } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct TrapData { pub trapcode: TrapCode, pub srcloc: u32, diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 06b678a5b..604778f01 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -1,8 +1,4 @@ - -use crate::{ - cache::{BackendCache, TrampolineCache}, - trampoline::Trampolines, -}; +use crate::{cache::BackendCache, trampoline::Trampolines}; use crate::{ libcalls, relocation::{ @@ -17,7 +13,6 @@ use cranelift_codegen::{ir, isa, Context}; use std::{ mem, ptr::{write_unaligned, NonNull}, - cell::UnsafeCell, sync::Arc, }; @@ -43,7 +38,11 @@ extern "C" { pub fn __chkstk(); } -fn lookup_func(map: &SliceMap, memory: &Memory, local_func_index: LocalFuncIndex) -> Option> { +fn lookup_func( + map: &SliceMap, + memory: &Memory, + local_func_index: LocalFuncIndex, +) -> Option> { let offset = *map.get(local_func_index)?; let ptr = unsafe { memory.as_ptr().add(offset) }; @@ -60,7 +59,6 @@ pub struct FuncResolverBuilder { } impl FuncResolverBuilder { - pub fn new_from_backend_cache( backend_cache: BackendCache, mut code: Memory, @@ -82,7 +80,9 @@ impl FuncResolverBuilder { external_relocs: backend_cache.external_relocs, import_len: info.imported_functions.len(), }, - Arc::new(Trampolines::from_trampoline_cache(backend_cache.trampolines)), + Arc::new(Trampolines::from_trampoline_cache( + backend_cache.trampolines, + )), handler_data, )) } @@ -158,7 +158,8 @@ impl FuncResolverBuilder { previous_end = new_end; } - let handler_data = HandlerData::new(Arc::new(trap_sink), memory.as_ptr() as _, memory.size()); + let handler_data = + HandlerData::new(Arc::new(trap_sink), memory.as_ptr() as _, memory.size()); let mut func_resolver_builder = Self { map, @@ -177,12 +178,15 @@ impl FuncResolverBuilder { for (index, relocs) in self.local_relocs.iter() { for ref reloc in relocs.iter() { let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len); - let target_func_address = - lookup_func(&self.map, &self.memory, local_func_index).unwrap().as_ptr() as usize; + let target_func_address = lookup_func(&self.map, &self.memory, local_func_index) + .unwrap() + .as_ptr() as usize; // We need the address of the current function // because these calls are relative. - let func_addr = lookup_func(&self.map, &self.memory, index).unwrap().as_ptr() as usize; + let func_addr = lookup_func(&self.map, &self.memory, index) + .unwrap() + .as_ptr() as usize; unsafe { let reloc_address = func_addr + reloc.offset as usize; @@ -273,7 +277,9 @@ impl FuncResolverBuilder { // We need the address of the current function // because some of these calls are relative. - let func_addr = lookup_func(&self.map, &self.memory, index).unwrap().as_ptr() as usize; + let func_addr = lookup_func(&self.map, &self.memory, index) + .unwrap() + .as_ptr() as usize; // Determine relocation type and apply relocation. match reloc.reloc { @@ -313,10 +319,13 @@ impl FuncResolverBuilder { trampolines: trampolines.to_trampoline_cache(), }; - Ok((FuncResolver { - map: self.map, - memory: Arc::new(self.memory), - }, backend_cache)) + Ok(( + FuncResolver { + map: self.map, + memory: Arc::new(self.memory), + }, + backend_cache, + )) } } diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index bedcff87a..9ccbf1822 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -44,7 +44,11 @@ pub struct Caller { } impl Caller { - pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Arc) -> Self { + pub fn new( + module: &ModuleInfo, + handler_data: HandlerData, + trampolines: Arc, + ) -> Self { let mut func_export_set = HashSet::new(); for export_index in module.exports.values() { if let ExportIndex::Func(func_index) = export_index { diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index 7a90c085e..b20109ef0 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -1,4 +1,3 @@ - use crate::cache::TrampolineCache; use cranelift_codegen::{ binemit::{NullTrapSink, Reloc, RelocSink}, @@ -33,7 +32,6 @@ pub struct Trampolines { } impl Trampolines { - pub fn from_trampoline_cache(cache: TrampolineCache) -> Self { // pub struct TrampolineCache { // #[serde(with = "serde_bytes")] @@ -57,7 +55,6 @@ impl Trampolines { } } - pub fn to_trampoline_cache(&self) -> TrampolineCache { let mut code = vec![0; self.memory.size()]; diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 3ed5c36dd..5c2a04e57 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -220,13 +220,13 @@ impl EmscriptenGlobals { namespace_index, name_index, }, - ) in &module.0.info.imported_functions + ) in &module.info().imported_functions { - let namespace = module.0.info.namespace_table.get(*namespace_index); - let name = module.0.info.name_table.get(*name_index); + let namespace = module.info().namespace_table.get(*namespace_index); + let name = module.info().name_table.get(*name_index); if name == "abortOnCannotGrowMemory" && namespace == "env" { - let sig_index = module.0.info.func_assoc[index.convert_up(&module.0)]; - let expected_sig = &module.0.info.signatures[sig_index]; + let sig_index = module.info().func_assoc[index.convert_up(module.info())]; + let expected_sig = &module.info().signatures[sig_index]; if **expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG { use_old_abort_on_cannot_grow_memory = true; } diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index 82ab0f251..678032374 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -16,13 +16,12 @@ use wasmer_runtime_core::{ /// We check if a provided module is an Emscripten generated one pub fn is_emscripten_module(module: &Module) -> bool { - for (_, import_name) in &module.0.info.imported_functions { + for (_, import_name) in &module.info().imported_functions { let namespace = module - .0 - .info + .info() .namespace_table .get(import_name.namespace_index); - let field = module.0.info.name_table.get(import_name.name_index); + let field = module.info().name_table.get(import_name.name_index); if field == "_emscripten_memcpy_big" && namespace == "env" { return true; } @@ -31,12 +30,12 @@ pub fn is_emscripten_module(module: &Module) -> bool { } pub fn get_emscripten_table_size(module: &Module) -> (u32, Option) { - let (_, table) = &module.0.info.imported_tables[ImportedTableIndex::new(0)]; + let (_, table) = &module.info().imported_tables[ImportedTableIndex::new(0)]; (table.minimum, table.maximum) } pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option) { - let (_, memory) = &module.0.info.imported_memories[ImportedMemoryIndex::new(0)]; + let (_, memory) = &module.info().imported_memories[ImportedMemoryIndex::new(0)]; (memory.minimum, memory.maximum) } diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index a4afe2ee5..e490b5e3e 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -2,7 +2,7 @@ use crate::{ backing::ImportBacking, error::CompileResult, error::RuntimeResult, - module::{ModuleInner}, + module::ModuleInner, types::{FuncIndex, LocalFuncIndex, Value}, vm, }; @@ -21,8 +21,7 @@ pub mod sys { } pub use crate::sig_registry::SigRegistry; -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] pub enum Backend { Cranelift, } @@ -45,7 +44,6 @@ pub trait Compiler { /// be called from inside the runtime. fn compile(&self, wasm: &[u8], _: Token) -> CompileResult; - unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result; } @@ -95,7 +93,9 @@ pub trait FuncResolver: Send + Sync { ) -> Option>; } - pub trait CacheGen: Send + Sync { - fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Arc), CacheError>; -} \ No newline at end of file + fn generate_cache( + &self, + module: &ModuleInner, + ) -> Result<(Box, Box<[u8]>, Memory), CacheError>; +} diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index b60301e94..d49dd4215 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -6,9 +6,9 @@ use std::{ fs::File, io::{self, Seek, SeekFrom, Write}, mem, - sync::Arc, path::Path, slice, + sync::Arc, }; #[derive(Debug)] @@ -69,7 +69,7 @@ struct CacheInner { info: Box, #[serde(with = "serde_bytes")] backend_metadata: Box<[u8]>, - compiled_code: Arc, + compiled_code: Memory, } pub struct Cache { @@ -80,7 +80,7 @@ impl Cache { pub(crate) fn from_parts( info: Box, backend_metadata: Box<[u8]>, - compiled_code: Arc, + compiled_code: Memory, ) -> Self { Self { inner: CacheInner { @@ -104,9 +104,7 @@ impl Cache { let inner = deserialize(body_slice).map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?; - Ok(Cache { - inner, - }) + Ok(Cache { inner }) } pub fn info(&self) -> &ModuleInfo { @@ -114,7 +112,7 @@ impl Cache { } #[doc(hidden)] - pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Arc) { + pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Memory) { ( *self.inner.info, self.inner.backend_metadata, diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 18cf2a703..7025acf5a 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -2,7 +2,6 @@ #[macro_use] extern crate field_offset; - #[macro_use] extern crate serde_derive; @@ -44,7 +43,6 @@ pub use self::module::Module; pub use self::typed_func::Func; use std::sync::Arc; - use self::cache::{Cache, Error as CacheError}; pub mod prelude { @@ -90,7 +88,7 @@ pub fn validate(wasm: &[u8]) -> bool { } } -// +// // pub fn compile_to_cache_with( // wasm: &[u8], // compiler: &dyn backend::Compiler, @@ -102,7 +100,6 @@ pub fn validate(wasm: &[u8]) -> bool { // Ok(Cache::new(wasm, info, backend_metadata, compiled_code)) // } - pub unsafe fn load_cache_with( cache: Cache, compiler: &dyn backend::Compiler, diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 0526c0ad4..5cb1b5b21 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -1,5 +1,6 @@ use crate::{ backend::{Backend, FuncResolver, ProtectedCaller}, + cache::{Cache, Error as CacheError}, error, import::ImportObject, structures::{Map, TypedIndex}, @@ -10,7 +11,6 @@ use crate::{ LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, TableIndex, }, - cache::{Cache, Error as CacheError}, Instance, }; @@ -25,14 +25,12 @@ pub struct ModuleInner { pub func_resolver: Box, pub protected_caller: Box, - pub cache_gen: Box, pub info: ModuleInfo, } -#[derive(Clone)] -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct ModuleInfo { // This are strictly local and the typsystem ensures that. pub memories: Map, @@ -62,12 +60,9 @@ pub struct ModuleInfo { pub wasm_hash: WasmHash, } - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[derive(Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct WasmHash([u8; 32]); - impl WasmHash { pub fn generate(wasm: &[u8]) -> Self { WasmHash(crate::cache::hash_data(wasm)) @@ -125,23 +120,25 @@ impl Module { } pub fn cache(&self) -> Result { - let (info, backend_cache, code) = self.inner.cache_gen.generate_cache(&self.inner)?; - + let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?; + Ok(Cache::from_parts(info, backend_metadata, code)) + } + + pub fn info(&self) -> &ModuleInfo { + &self.inner.info } } impl ModuleInner {} #[doc(hidden)] -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct ImportName { pub namespace_index: NamespaceIndex, pub name_index: NameIndex, } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub enum ExportIndex { Func(FuncIndex), Memory(MemoryIndex), @@ -150,8 +147,7 @@ pub enum ExportIndex { } /// A data initializer for linear memory. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct DataInitializer { /// The index of the memory to initialize. pub memory_index: MemoryIndex, @@ -163,8 +159,7 @@ pub struct DataInitializer { } /// A WebAssembly table initializer. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct TableInitializer { /// The index of a table to initialize. pub table_index: TableIndex, @@ -225,8 +220,7 @@ impl StringTableBuilder { } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct StringTable { table: Map, buffer: String, @@ -249,8 +243,7 @@ impl StringTable { } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NamespaceIndex(u32); impl TypedIndex for NamespaceIndex { @@ -265,8 +258,7 @@ impl TypedIndex for NamespaceIndex { } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NameIndex(u32); impl TypedIndex for NameIndex { diff --git a/lib/runtime-core/src/structures/map.rs b/lib/runtime-core/src/structures/map.rs index df95fe652..d7177c427 100644 --- a/lib/runtime-core/src/structures/map.rs +++ b/lib/runtime-core/src/structures/map.rs @@ -8,8 +8,7 @@ use std::{ }; /// Dense item map -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct Map where K: TypedIndex, diff --git a/lib/runtime-core/src/sys/mod.rs b/lib/runtime-core/src/sys/mod.rs index 2fdc1ef0f..0bfc134c2 100644 --- a/lib/runtime-core/src/sys/mod.rs +++ b/lib/runtime-core/src/sys/mod.rs @@ -10,7 +10,6 @@ pub use self::unix::*; #[cfg(windows)] pub use self::windows::*; - use serde::{ de::{self, SeqAccess, Visitor}, ser::SerializeStruct, @@ -21,7 +20,6 @@ use serde_bytes::Bytes; use std::fmt; - impl Serialize for Memory { fn serialize(&self, serializer: S) -> Result where @@ -36,7 +34,6 @@ impl Serialize for Memory { } } - impl<'de> Deserialize<'de> for Memory { fn deserialize(deserializer: D) -> Result where diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 7154f34f9..8c76e6c14 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -207,16 +207,26 @@ impl Drop for Memory { impl Clone for Memory { fn clone(&self) -> Self { - let mut new = Memory::with_size_protect(self.size, self.protection).unwrap(); + let temp_protection = if self.protection.is_writable() { + self.protection + } else { + Protect::ReadWrite + }; + + let mut new = Memory::with_size_protect(self.size, temp_protection).unwrap(); unsafe { new.as_slice_mut().copy_from_slice(self.as_slice()); + + if temp_protection != self.protection { + new.protect(.., self.protection).unwrap(); + } } + new } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { None, diff --git a/lib/runtime-core/src/sys/windows/memory.rs b/lib/runtime-core/src/sys/windows/memory.rs index 578070a3e..771ac6788 100644 --- a/lib/runtime-core/src/sys/windows/memory.rs +++ b/lib/runtime-core/src/sys/windows/memory.rs @@ -158,16 +158,26 @@ impl Drop for Memory { impl Clone for Memory { fn clone(&self) -> Self { - let mut new = Memory::with_size_protect(self.size, self.protection).unwrap(); + let temp_protection = if self.protection.is_writable() { + self.protection + } else { + Protect::ReadWrite + }; + + let mut new = Memory::with_size_protect(self.size, temp_protection).unwrap(); unsafe { new.as_slice_mut().copy_from_slice(self.as_slice()); + + if temp_protection != self.protection { + new.protect(.., self.protection).unwrap(); + } } + new } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { None, diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index f19e73a6e..9ee5270dd 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -2,8 +2,7 @@ use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, unit use std::{borrow::Cow, mem}; /// Represents a WebAssembly type. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Type { /// The `i32` type. I32, @@ -25,8 +24,7 @@ impl std::fmt::Display for Type { /// /// As the number of types in WebAssembly expand, /// this structure will expand as well. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum Value { /// The `i32` type. I32(i32), @@ -171,15 +169,13 @@ impl ValueType for f64 { } } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub enum ElementType { /// Any wasm function. Anyfunc, } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct TableDescriptor { /// Type of data stored in this table. pub element: ElementType, @@ -203,8 +199,7 @@ impl TableDescriptor { /// A const value initializer. /// Over time, this will be able to represent more and more /// complex expressions. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub enum Initializer { /// Corresponds to a `const.*` instruction. Const(Value), @@ -212,24 +207,21 @@ pub enum Initializer { GetGlobal(ImportedGlobalIndex), } -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub struct GlobalDescriptor { pub mutable: bool, pub ty: Type, } /// A wasm global. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct GlobalInit { pub desc: GlobalDescriptor, pub init: Initializer, } /// A wasm memory. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub struct MemoryDescriptor { /// The minimum number of allowed pages. pub minimum: Pages, @@ -261,8 +253,7 @@ impl MemoryDescriptor { /// The signature of a function that is either implemented /// in a wasm module or exposed to wasm by the host. -#[derive(Serialize, Deserialize)] -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] pub struct FuncSig { params: Cow<'static, [Type]>, returns: Cow<'static, [Type]>, @@ -400,8 +391,7 @@ define_local_or_import![ (GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals), ]; -#[derive(Serialize, Deserialize)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct SigIndex(u32); impl TypedIndex for SigIndex { #[doc(hidden)] diff --git a/lib/runtime-core/src/units.rs b/lib/runtime-core/src/units.rs index 6a1582e9e..2486c5738 100644 --- a/lib/runtime-core/src/units.rs +++ b/lib/runtime-core/src/units.rs @@ -7,8 +7,7 @@ const WASM_PAGE_SIZE: usize = 65_536; const WASM_MAX_PAGES: usize = 65_536; /// Units of WebAssembly pages (as specified to be 65,536 bytes). -#[derive(Serialize, Deserialize)] -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Pages(pub u32); impl Pages { @@ -33,8 +32,7 @@ impl fmt::Debug for Pages { } /// Units of WebAssembly memory in terms of 8-bit bytes. -#[derive(Serialize, Deserialize)] -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Bytes(pub usize); impl fmt::Debug for Bytes { diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 79d18255a..4d6e6880d 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -494,11 +494,13 @@ mod vm_ctx_tests { fn generate_module() -> ModuleInner { use super::Func; - use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper, CacheGen, sys::Memory}; + use crate::backend::{ + sys::Memory, Backend, CacheGen, FuncResolver, ProtectedCaller, Token, UserTrapper, + }; use crate::cache::Error as CacheError; use crate::error::RuntimeResult; - use crate::types::{FuncIndex, LocalFuncIndex, Value}; use crate::module::WasmHash; + use crate::types::{FuncIndex, LocalFuncIndex, Value}; use hashbrown::HashMap; use std::ptr::NonNull; struct Placeholder; @@ -528,11 +530,13 @@ mod vm_ctx_tests { } } impl CacheGen for Placeholder { - fn generate_cache(&self, module: &ModuleInner) -> Result<(Box, Box<[u8]>, Memory), CacheError> { + fn generate_cache( + &self, + module: &ModuleInner, + ) -> Result<(Box, Box<[u8]>, Memory), CacheError> { unimplemented!() } } - ModuleInner { func_resolver: Box::new(Placeholder), From 336c1d9c5f6b8f78d788a033f403e49370cb9f4f Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Wed, 20 Feb 2019 17:00:48 -0800 Subject: [PATCH 05/14] Fix lint --- lib/runtime/src/cache.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index b0db19fe8..01bf90c25 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -1,7 +1,7 @@ use crate::Module; use std::path::Path; use wasmer_runtime_core::cache::{hash_data, Cache as CoreCache}; -use wasmer_runtime_core::module::{WasmHash}; +use wasmer_runtime_core::module::WasmHash; pub use wasmer_runtime_core::cache::Error; @@ -136,4 +136,3 @@ pub trait Cache { unsafe fn load(&self, key: Self::Key) -> Result; fn store(&mut self, module: Module) -> Result; } - From 7fa818ea06559dc0f84da38647336d4feaca7e87 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 11:47:28 -0800 Subject: [PATCH 06/14] Finalize new cache api --- Cargo.lock | 13 +++- lib/clif-backend/src/cache.rs | 4 +- lib/clif-backend/src/lib.rs | 8 ++- lib/clif-backend/src/module.rs | 6 +- lib/runtime-core/Cargo.toml | 1 + lib/runtime-core/src/backend.rs | 10 +-- lib/runtime-core/src/cache.rs | 76 +++++++++++++++------- lib/runtime-core/src/lib.rs | 16 +---- lib/runtime-core/src/module.rs | 19 +----- lib/runtime/src/cache.rs | 112 ++++++++++++++++++-------------- lib/runtime/src/lib.rs | 6 +- 11 files changed, 150 insertions(+), 121 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d301f57f..2eaad2339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "block-buffer" -version = "0.7.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -360,6 +360,11 @@ dependencies = [ "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "humantime" version = "1.2.0" @@ -791,7 +796,7 @@ name = "sha2" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1060,6 +1065,7 @@ dependencies = [ "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1172,7 +1178,7 @@ dependencies = [ "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bindgen 0.46.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7f7f0701772b17de73e4f5cbcb1dd6926f4706cba4c1ab62c5367f8bdc94e1" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "509de513cca6d92b6aacf9c61acfe7eaa160837323a81068d690cc1f8e5740da" +"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" @@ -1206,6 +1212,7 @@ dependencies = [ "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" diff --git a/lib/clif-backend/src/cache.rs b/lib/clif-backend/src/cache.rs index 84db980b0..3c38a5266 100644 --- a/lib/clif-backend/src/cache.rs +++ b/lib/clif-backend/src/cache.rs @@ -4,7 +4,7 @@ use hashbrown::HashMap; use std::sync::Arc; use wasmer_runtime_core::{ backend::{sys::Memory, CacheGen}, - cache::{Cache, Error}, + cache::{Error, SerializedCache}, module::{ModuleInfo, ModuleInner}, structures::Map, types::{LocalFuncIndex, SigIndex}, @@ -61,7 +61,7 @@ pub struct BackendCache { } impl BackendCache { - pub fn from_cache(cache: Cache) -> Result<(ModuleInfo, Memory, Self), Error> { + pub fn from_cache(cache: SerializedCache) -> Result<(ModuleInfo, Memory, Self), Error> { let (info, backend_data, compiled_code) = cache.consume(); let backend_cache = diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 8d756420e..daef34c5d 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -14,7 +14,7 @@ use cranelift_codegen::{ }; use target_lexicon::Triple; -use wasmer_runtime_core::cache::{Cache, Error as CacheError}; +use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache}; use wasmer_runtime_core::{ backend::{Compiler, Token}, error::{CompileError, CompileResult}, @@ -53,7 +53,11 @@ impl Compiler for CraneliftCompiler { /// Create a wasmer Module from an already-compiled cache. - unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result { + unsafe fn from_cache( + &self, + cache: SerializedCache, + _: Token, + ) -> Result { module::Module::from_cache(cache) } diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index 0d0c66d7c..002d5185c 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -7,7 +7,7 @@ use cranelift_wasm; use hashbrown::HashMap; use std::sync::Arc; -use wasmer_runtime_core::cache::{Cache, Error as CacheError}; +use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache, WasmHash}; use wasmer_runtime_core::{ backend::Backend, @@ -19,8 +19,6 @@ use wasmer_runtime_core::{ }, }; -use wasmer_runtime_core::module::WasmHash; - /// This contains all of the items in a `ModuleInner` except the `func_resolver`. pub struct Module { pub info: ModuleInfo, @@ -90,7 +88,7 @@ impl Module { }) } - pub fn from_cache(cache: Cache) -> Result { + pub fn from_cache(cache: SerializedCache) -> Result { let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; let (func_resolver_builder, trampolines, handler_data) = diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 4781751af..75e49840c 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -16,6 +16,7 @@ lazy_static = "1.2.0" indexmap = "1.0.2" errno = "0.2.4" libc = "0.2.48" +hex = "0.3.2" # Dependencies for caching. [dependencies.serde] diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index e490b5e3e..ab7c27d53 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -8,14 +8,12 @@ use crate::{ }; use crate::{ - cache::{Cache, Error as CacheError}, + cache::{Error as CacheError, SerializedCache}, module::ModuleInfo, sys::Memory, }; use std::ptr::NonNull; -use std::sync::Arc; - pub mod sys { pub use crate::sys::*; } @@ -44,7 +42,11 @@ pub trait Compiler { /// be called from inside the runtime. fn compile(&self, wasm: &[u8], _: Token) -> CompileResult; - unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result; + unsafe fn from_cache( + &self, + cache: SerializedCache, + _: Token, + ) -> Result; } /// The functionality exposed by this trait is expected to be used diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index d49dd4215..34c09c3aa 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -1,4 +1,7 @@ -use crate::{module::ModuleInfo, sys::Memory}; +use crate::{ + module::{Module, ModuleInfo}, + sys::Memory, +}; use memmap::Mmap; use serde_bench::{deserialize, serialize}; use sha2::{Digest, Sha256}; @@ -8,7 +11,6 @@ use std::{ mem, path::Path, slice, - sync::Arc, }; #[derive(Debug)] @@ -27,23 +29,43 @@ pub enum Error { InvalidatedCache, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct WasmHash([u8; 32]); + +impl WasmHash { + pub fn generate(wasm: &[u8]) -> Self { + let mut array = [0u8; 32]; + array.copy_from_slice(Sha256::digest(wasm).as_slice()); + WasmHash(array) + } + + pub fn encode(self) -> String { + hex::encode(self.0) + } + + pub(crate) fn into_array(self) -> [u8; 32] { + self.0 + } +} + const CURRENT_CACHE_VERSION: u64 = 0; /// The header of a cache file. #[repr(C, packed)] -struct CacheHeader { +struct SerializedCacheHeader { magic: [u8; 8], // [W, A, S, M, E, R, \0, \0] version: u64, data_len: u64, wasm_hash: [u8; 32], // Sha256 of the wasm in binary format. } -impl CacheHeader { - pub fn read_from_slice(buffer: &[u8]) -> Result<(&CacheHeader, &[u8]), Error> { - if buffer.len() >= mem::size_of::() { +impl SerializedCacheHeader { + pub fn read_from_slice(buffer: &[u8]) -> Result<(&Self, &[u8]), Error> { + if buffer.len() >= mem::size_of::() { if &buffer[..8] == "WASMER\0\0".as_bytes() { - let (header_slice, body_slice) = buffer.split_at(mem::size_of::()); - let header = unsafe { &*(header_slice.as_ptr() as *const CacheHeader) }; + let (header_slice, body_slice) = + buffer.split_at(mem::size_of::()); + let header = unsafe { &*(header_slice.as_ptr() as *const SerializedCacheHeader) }; if header.version == CURRENT_CACHE_VERSION { Ok((header, body_slice)) @@ -59,31 +81,31 @@ impl CacheHeader { } pub fn as_slice(&self) -> &[u8] { - let ptr = self as *const CacheHeader as *const u8; - unsafe { slice::from_raw_parts(ptr, mem::size_of::()) } + let ptr = self as *const SerializedCacheHeader as *const u8; + unsafe { slice::from_raw_parts(ptr, mem::size_of::()) } } } #[derive(Serialize, Deserialize)] -struct CacheInner { +struct SerializedCacheInner { info: Box, #[serde(with = "serde_bytes")] backend_metadata: Box<[u8]>, compiled_code: Memory, } -pub struct Cache { - inner: CacheInner, +pub struct SerializedCache { + inner: SerializedCacheInner, } -impl Cache { +impl SerializedCache { pub(crate) fn from_parts( info: Box, backend_metadata: Box<[u8]>, compiled_code: Memory, ) -> Self { Self { - inner: CacheInner { + inner: SerializedCacheInner { info, backend_metadata, compiled_code, @@ -91,7 +113,7 @@ impl Cache { } } - pub fn open

(path: P) -> Result + pub fn open

(path: P) -> Result where P: AsRef, { @@ -99,12 +121,12 @@ impl Cache { let mmap = unsafe { Mmap::map(&file).map_err(|e| Error::IoError(e))? }; - let (header, body_slice) = CacheHeader::read_from_slice(&mmap[..])?; + let (_header, body_slice) = SerializedCacheHeader::read_from_slice(&mmap[..])?; let inner = deserialize(body_slice).map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?; - Ok(Cache { inner }) + Ok(SerializedCache { inner }) } pub fn info(&self) -> &ModuleInfo { @@ -132,8 +154,10 @@ impl Cache { let data_len = buffer.len() as u64; - file.seek(SeekFrom::Start(mem::size_of::() as u64)) - .map_err(|e| Error::IoError(e))?; + file.seek(SeekFrom::Start( + mem::size_of::() as u64 + )) + .map_err(|e| Error::IoError(e))?; file.write(buffer.as_slice()) .map_err(|e| Error::IoError(e))?; @@ -143,7 +167,7 @@ impl Cache { let wasm_hash = self.inner.info.wasm_hash.into_array(); - let cache_header = CacheHeader { + let cache_header = SerializedCacheHeader { magic: [ 'W' as u8, 'A' as u8, 'S' as u8, 'M' as u8, 'E' as u8, 'R' as u8, 0, 0, ], @@ -159,8 +183,10 @@ impl Cache { } } -pub fn hash_data(data: &[u8]) -> [u8; 32] { - let mut array = [0u8; 32]; - array.copy_from_slice(Sha256::digest(data).as_slice()); - array +pub trait Cache { + type LoadError; + type StoreError; + + unsafe fn load(&self, key: WasmHash) -> Result; + fn store(&mut self, module: Module) -> Result; } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 7025acf5a..0e42531b8 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -43,7 +43,7 @@ pub use self::module::Module; pub use self::typed_func::Func; use std::sync::Arc; -use self::cache::{Cache, Error as CacheError}; +use self::cache::{Error as CacheError, SerializedCache}; pub mod prelude { pub use crate::import::{ImportObject, Namespace}; @@ -88,20 +88,8 @@ pub fn validate(wasm: &[u8]) -> bool { } } -// -// pub fn compile_to_cache_with( -// wasm: &[u8], -// compiler: &dyn backend::Compiler, -// ) -> CompileResult { -// let token = backend::Token::generate(); -// let (info, backend_metadata, compiled_code) = -// compiler.compile_to_backend_cache_data(wasm, token)?; - -// Ok(Cache::new(wasm, info, backend_metadata, compiled_code)) -// } - pub unsafe fn load_cache_with( - cache: Cache, + cache: SerializedCache, compiler: &dyn backend::Compiler, ) -> std::result::Result { let token = backend::Token::generate(); diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 5cb1b5b21..43deb7c4d 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -1,6 +1,6 @@ use crate::{ backend::{Backend, FuncResolver, ProtectedCaller}, - cache::{Cache, Error as CacheError}, + cache::{Error as CacheError, SerializedCache, WasmHash}, error, import::ImportObject, structures::{Map, TypedIndex}, @@ -60,19 +60,6 @@ pub struct ModuleInfo { pub wasm_hash: WasmHash, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct WasmHash([u8; 32]); - -impl WasmHash { - pub fn generate(wasm: &[u8]) -> Self { - WasmHash(crate::cache::hash_data(wasm)) - } - - pub(crate) fn into_array(self) -> [u8; 32] { - self.0 - } -} - /// A compiled WebAssembly module. /// /// `Module` is returned by the [`compile`] and @@ -119,9 +106,9 @@ impl Module { Instance::new(Arc::clone(&self.inner), import_object) } - pub fn cache(&self) -> Result { + pub fn cache(&self) -> Result { let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?; - Ok(Cache::from_parts(info, backend_metadata, code)) + Ok(SerializedCache::from_parts(info, backend_metadata, code)) } pub fn info(&self) -> &ModuleInfo { diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index 01bf90c25..2fbf7f47b 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -1,46 +1,9 @@ use crate::Module; -use std::path::Path; -use wasmer_runtime_core::cache::{hash_data, Cache as CoreCache}; -use wasmer_runtime_core::module::WasmHash; +use std::{fs::create_dir_all, io, path::PathBuf}; -pub use wasmer_runtime_core::cache::Error; +pub use wasmer_runtime_core::cache::{Cache, WasmHash}; +use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache}; -// /// 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: // /// @@ -128,11 +91,66 @@ pub use wasmer_runtime_core::cache::Error; // } // } -pub trait Cache { - type Key; - type LoadError; - type StoreError; - - unsafe fn load(&self, key: Self::Key) -> Result; - fn store(&mut self, module: Module) -> Result; +pub struct FSCache { + path: PathBuf, +} + +impl FSCache { + pub fn open>(path: P) -> io::Result { + let path: PathBuf = path.into(); + + if path.exists() { + let metadata = path.metadata()?; + if metadata.is_dir() { + if !metadata.permissions().readonly() { + Ok(Self { path }) + } else { + // This directory is readonly. + Err(io::Error::new( + io::ErrorKind::PermissionDenied, + format!("the supplied path is readonly: {}", path.display()), + )) + } + } else { + // This path points to a file. + Err(io::Error::new( + io::ErrorKind::PermissionDenied, + format!( + "the supplied path already points to a file: {}", + path.display() + ), + )) + } + } else { + // Create the directory and any parent directories if they don't yet exist. + create_dir_all(&path)?; + Ok(Self { path }) + } + } +} + +impl Cache for FSCache { + type LoadError = CacheError; + type StoreError = CacheError; + + unsafe fn load(&self, key: WasmHash) -> Result { + let filename = key.encode(); + let mut new_path_buf = self.path.clone(); + new_path_buf.push(filename); + + let serialized_cache = SerializedCache::open(new_path_buf)?; + wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) + } + + fn store(&mut self, module: Module) -> Result { + let key = module.info().wasm_hash; + let filename = key.encode(); + let mut new_path_buf = self.path.clone(); + new_path_buf.push(filename); + + let serialized_cache = module.cache()?; + serialized_cache.store(new_path_buf)?; + + Ok(key) + } } diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 48a4c27f5..012bdb593 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -99,7 +99,7 @@ pub mod wasm { } pub mod error { - pub use super::cache::Error as CacheError; + pub use wasmer_runtime_core::cache::Error as CacheError; pub use wasmer_runtime_core::error::*; } @@ -108,12 +108,10 @@ pub mod units { pub use wasmer_runtime_core::units::{Bytes, Pages}; } -mod cache; +pub mod cache; use wasmer_runtime_core::backend::Compiler; -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 From f18da0690e7c1306dffd9ef0571be372c426f412 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 11:54:39 -0800 Subject: [PATCH 07/14] Fix test compilation --- lib/runtime-core/src/vm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 4d6e6880d..6646b3271 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -497,9 +497,8 @@ mod vm_ctx_tests { use crate::backend::{ sys::Memory, Backend, CacheGen, FuncResolver, ProtectedCaller, Token, UserTrapper, }; - use crate::cache::Error as CacheError; + use crate::cache::{Error as CacheError, WashHash}; use crate::error::RuntimeResult; - use crate::module::WasmHash; use crate::types::{FuncIndex, LocalFuncIndex, Value}; use hashbrown::HashMap; use std::ptr::NonNull; From c78d4a8674d9fb147ba12f0a48e1f1b35598098c Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 12:54:53 -0800 Subject: [PATCH 08/14] Fix test compilation 2 --- lib/runtime-core/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 6646b3271..ab386401b 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -497,7 +497,7 @@ mod vm_ctx_tests { use crate::backend::{ sys::Memory, Backend, CacheGen, FuncResolver, ProtectedCaller, Token, UserTrapper, }; - use crate::cache::{Error as CacheError, WashHash}; + use crate::cache::{Error as CacheError, WasmHash}; use crate::error::RuntimeResult; use crate::types::{FuncIndex, LocalFuncIndex, Value}; use hashbrown::HashMap; From f9d7d56195a487331cd1ae6ad76f2ea3ac0ac8f6 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 14:00:33 -0800 Subject: [PATCH 09/14] Add documentation and make load safe --- lib/runtime-core/src/cache.rs | 23 ++++++++++++++++++- lib/runtime/src/cache.rs | 42 ++++++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index 34c09c3aa..2e9b29250 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -29,16 +29,34 @@ pub enum Error { InvalidatedCache, } +impl From for Error { + fn from(io_err: io::Error) -> Self { + Error::IoError(io_err) + } +} + +/// The hash of a wasm module. +/// +/// Used as a key when loading and storing modules in a [`Cache`]. +/// +/// [`Cache`]: trait.Cache.html #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct WasmHash([u8; 32]); impl WasmHash { + /// Hash a wasm module. + /// + /// # Note: + /// This does no verification that the supplied data + /// is, in fact, a wasm module. pub fn generate(wasm: &[u8]) -> Self { let mut array = [0u8; 32]; array.copy_from_slice(Sha256::digest(wasm).as_slice()); WasmHash(array) } + /// Create the hexadecimal representation of the + /// stored hash. pub fn encode(self) -> String { hex::encode(self.0) } @@ -183,10 +201,13 @@ impl SerializedCache { } } +/// A generic cache for storing and loading compiled wasm modules. +/// +/// The `wasmer-runtime` supplies a naive `FileSystemCache` api. pub trait Cache { type LoadError; type StoreError; - unsafe fn load(&self, key: WasmHash) -> Result; + fn load(&self, key: WasmHash) -> Result; fn store(&mut self, module: Module) -> Result; } diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index 2fbf7f47b..e6664d046 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -91,12 +91,42 @@ use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache}; // } // } -pub struct FSCache { +/// Representation of a directory that contains compiled wasm artifacts. +/// +/// The `FileSystemCache` type implements the [`Cache`] trait, which allows it to be used +/// generically when some sort of cache is required. +/// +/// [`Cache`]: trait.Cache.html +/// +/// # Usage: +/// +/// ```rust +/// use wasmer_runtime::cache::{Cache, FileSystemCache}; +/// +/// # use wasmer_runtime::{Module, error::CacheError}; +/// fn store_and_load_module(module: Module) -> Result { +/// // Create a new file system cache. +/// // This is unsafe because we can't ensure that the artifact wasn't +/// // corrupted or tampered with. +/// let mut fs_cache = unsafe { FileSystemCache::new("some/directory/goes/here")? }; +/// // Store a module into the cache. +/// // The returned `key` is equivalent to `module.info().wasm_hash`. +/// let key = fs_cache.store(module)?; +/// // Load the module back from the cache with the `key`. +/// fs_cache.load(key) +/// } +/// ``` +pub struct FileSystemCache { path: PathBuf, } -impl FSCache { - pub fn open>(path: P) -> io::Result { +impl FileSystemCache { + /// Construct a new `FileSystemCache` around the specified directory. + /// + /// # Note: + /// This method is unsafe because there's no way to ensure the artifacts + /// stored in this cache haven't been corrupted or tampered with. + pub unsafe fn new>(path: P) -> io::Result { let path: PathBuf = path.into(); if path.exists() { @@ -129,17 +159,17 @@ impl FSCache { } } -impl Cache for FSCache { +impl Cache for FileSystemCache { type LoadError = CacheError; type StoreError = CacheError; - unsafe fn load(&self, key: WasmHash) -> Result { + fn load(&self, key: WasmHash) -> Result { let filename = key.encode(); let mut new_path_buf = self.path.clone(); new_path_buf.push(filename); let serialized_cache = SerializedCache::open(new_path_buf)?; - wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) + unsafe { wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) } } fn store(&mut self, module: Module) -> Result { From 244308374c94fc6020d8c1f9e0b01a3875d81206 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 15:27:20 -0800 Subject: [PATCH 10/14] Fix formatting --- lib/runtime-core/src/cache.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index 2e9b29250..a58cc05f1 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -36,17 +36,17 @@ impl From for Error { } /// The hash of a wasm module. -/// +/// /// Used as a key when loading and storing modules in a [`Cache`]. -/// +/// /// [`Cache`]: trait.Cache.html #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct WasmHash([u8; 32]); impl WasmHash { /// Hash a wasm module. - /// - /// # Note: + /// + /// # Note: /// This does no verification that the supplied data /// is, in fact, a wasm module. pub fn generate(wasm: &[u8]) -> Self { @@ -202,7 +202,7 @@ impl SerializedCache { } /// A generic cache for storing and loading compiled wasm modules. -/// +/// /// The `wasmer-runtime` supplies a naive `FileSystemCache` api. pub trait Cache { type LoadError; From 64eadad7fa78390e729f88f034c90d1eef3941f4 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 15:31:20 -0800 Subject: [PATCH 11/14] Fix review comments --- lib/runtime/src/cache.rs | 87 ---------------------------------------- lib/runtime/src/lib.rs | 24 ----------- 2 files changed, 111 deletions(-) diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index e6664d046..b8f261c95 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -4,93 +4,6 @@ use std::{fs::create_dir_all, io, path::PathBuf}; pub use wasmer_runtime_core::cache::{Cache, WasmHash}; use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache}; -// /// -// /// # 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>(path: P) -> Result { -// 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 { -// 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] == ¶m_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>(&self, path: P) -> Result<(), Error> { -// self.0.store(path) -// } -// } - /// Representation of a directory that contains compiled wasm artifacts. /// /// The `FileSystemCache` type implements the [`Cache`] trait, which allows it to be used diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 012bdb593..c7e3b3826 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -152,30 +152,6 @@ pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result CompileResult<()> { -// /// let cache = compile_cache(wasm)?; -// /// # Ok(()) -// /// # } -// /// ``` -// pub fn compile_cache(wasm: &[u8]) -> error::CompileResult { -// let default_compiler = default_compiler(); - -// wasmer_runtime_core::compile_to_cache_with(wasm, default_compiler) -// .map(|core_cache| Cache(core_cache)) -// } - fn default_compiler() -> &'static dyn Compiler { use lazy_static::lazy_static; use wasmer_clif_backend::CraneliftCompiler; From 696fd8fce35173fca4c3a6d4cd829b256cff10fb Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 17:06:49 -0800 Subject: [PATCH 12/14] Update api again and change SerializedCache to Artifact --- Cargo.lock | 2 +- lib/clif-backend/src/cache.rs | 4 +- lib/clif-backend/src/lib.rs | 8 +-- lib/clif-backend/src/module.rs | 4 +- lib/runtime-core/Cargo.toml | 2 - lib/runtime-core/src/backend.rs | 8 +-- lib/runtime-core/src/cache.rs | 122 ++++++++++++++------------------ lib/runtime-core/src/lib.rs | 4 +- lib/runtime-core/src/module.rs | 6 +- lib/runtime/Cargo.toml | 1 + lib/runtime/src/cache.rs | 20 ++++-- 11 files changed, 84 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebfe7ac0d..aa14e70be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1101,6 +1101,7 @@ name = "wasmer-runtime" version = "0.1.4" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-backend 0.1.2", "wasmer-runtime-core 0.1.2", ] @@ -1126,7 +1127,6 @@ dependencies = [ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/clif-backend/src/cache.rs b/lib/clif-backend/src/cache.rs index 3c38a5266..5af708703 100644 --- a/lib/clif-backend/src/cache.rs +++ b/lib/clif-backend/src/cache.rs @@ -4,7 +4,7 @@ use hashbrown::HashMap; use std::sync::Arc; use wasmer_runtime_core::{ backend::{sys::Memory, CacheGen}, - cache::{Error, SerializedCache}, + cache::{Artifact, Error}, module::{ModuleInfo, ModuleInner}, structures::Map, types::{LocalFuncIndex, SigIndex}, @@ -61,7 +61,7 @@ pub struct BackendCache { } impl BackendCache { - pub fn from_cache(cache: SerializedCache) -> Result<(ModuleInfo, Memory, Self), Error> { + pub fn from_cache(cache: Artifact) -> Result<(ModuleInfo, Memory, Self), Error> { let (info, backend_data, compiled_code) = cache.consume(); let backend_cache = diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index daef34c5d..df2e4e208 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -14,7 +14,7 @@ use cranelift_codegen::{ }; use target_lexicon::Triple; -use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache}; +use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; use wasmer_runtime_core::{ backend::{Compiler, Token}, error::{CompileError, CompileResult}, @@ -53,11 +53,7 @@ impl Compiler for CraneliftCompiler { /// Create a wasmer Module from an already-compiled cache. - unsafe fn from_cache( - &self, - cache: SerializedCache, - _: Token, - ) -> Result { + unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result { module::Module::from_cache(cache) } diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index 002d5185c..6f95ea828 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -7,7 +7,7 @@ use cranelift_wasm; use hashbrown::HashMap; use std::sync::Arc; -use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache, WasmHash}; +use wasmer_runtime_core::cache::{Artifact, Error as CacheError, WasmHash}; use wasmer_runtime_core::{ backend::Backend, @@ -88,7 +88,7 @@ impl Module { }) } - pub fn from_cache(cache: SerializedCache) -> Result { + pub fn from_cache(cache: Artifact) -> Result { let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; let (func_resolver_builder, trampolines, handler_data) = diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 75e49840c..03d4e5ae6 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -28,8 +28,6 @@ version = "1.0" version = "0.10" [dependencies.serde-bench] version = "0.0.7" -[dependencies.memmap] -version = "0.7.0" [dependencies.sha2] version = "0.8.0" [dependencies.hashbrown] diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index ab7c27d53..e88383800 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -8,7 +8,7 @@ use crate::{ }; use crate::{ - cache::{Error as CacheError, SerializedCache}, + cache::{Artifact, Error as CacheError}, module::ModuleInfo, sys::Memory, }; @@ -42,11 +42,7 @@ pub trait Compiler { /// be called from inside the runtime. fn compile(&self, wasm: &[u8], _: Token) -> CompileResult; - unsafe fn from_cache( - &self, - cache: SerializedCache, - _: Token, - ) -> Result; + unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result; } /// The functionality exposed by this trait is expected to be used diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index a58cc05f1..3d894bb09 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -2,16 +2,8 @@ use crate::{ module::{Module, ModuleInfo}, sys::Memory, }; -use memmap::Mmap; -use serde_bench::{deserialize, serialize}; use sha2::{Digest, Sha256}; -use std::{ - fs::File, - io::{self, Seek, SeekFrom, Write}, - mem, - path::Path, - slice, -}; +use std::{io, mem, slice}; #[derive(Debug)] pub enum InvalidFileType { @@ -67,23 +59,43 @@ impl WasmHash { } const CURRENT_CACHE_VERSION: u64 = 0; +static WASMER_CACHE_MAGIC: [u8; 8] = *b"WASMER\0\0"; /// The header of a cache file. #[repr(C, packed)] -struct SerializedCacheHeader { +struct ArtifactHeader { magic: [u8; 8], // [W, A, S, M, E, R, \0, \0] version: u64, data_len: u64, wasm_hash: [u8; 32], // Sha256 of the wasm in binary format. } -impl SerializedCacheHeader { +impl ArtifactHeader { pub fn read_from_slice(buffer: &[u8]) -> Result<(&Self, &[u8]), Error> { - if buffer.len() >= mem::size_of::() { - if &buffer[..8] == "WASMER\0\0".as_bytes() { + if buffer.len() >= mem::size_of::() { + if &buffer[..8] == &WASMER_CACHE_MAGIC { + let (header_slice, body_slice) = buffer.split_at(mem::size_of::()); + let header = unsafe { &*(header_slice.as_ptr() as *const ArtifactHeader) }; + + if header.version == CURRENT_CACHE_VERSION { + Ok((header, body_slice)) + } else { + Err(Error::InvalidatedCache) + } + } else { + Err(Error::InvalidFile(InvalidFileType::InvalidMagic)) + } + } else { + Err(Error::InvalidFile(InvalidFileType::InvalidSize)) + } + } + + pub fn read_from_slice_mut(buffer: &mut [u8]) -> Result<(&mut Self, &mut [u8]), Error> { + if buffer.len() >= mem::size_of::() { + if &buffer[..8] == &WASMER_CACHE_MAGIC { let (header_slice, body_slice) = - buffer.split_at(mem::size_of::()); - let header = unsafe { &*(header_slice.as_ptr() as *const SerializedCacheHeader) }; + buffer.split_at_mut(mem::size_of::()); + let header = unsafe { &mut *(header_slice.as_ptr() as *mut ArtifactHeader) }; if header.version == CURRENT_CACHE_VERSION { Ok((header, body_slice)) @@ -99,31 +111,31 @@ impl SerializedCacheHeader { } pub fn as_slice(&self) -> &[u8] { - let ptr = self as *const SerializedCacheHeader as *const u8; - unsafe { slice::from_raw_parts(ptr, mem::size_of::()) } + let ptr = self as *const ArtifactHeader as *const u8; + unsafe { slice::from_raw_parts(ptr, mem::size_of::()) } } } #[derive(Serialize, Deserialize)] -struct SerializedCacheInner { +struct ArtifactInner { info: Box, #[serde(with = "serde_bytes")] backend_metadata: Box<[u8]>, compiled_code: Memory, } -pub struct SerializedCache { - inner: SerializedCacheInner, +pub struct Artifact { + inner: ArtifactInner, } -impl SerializedCache { +impl Artifact { pub(crate) fn from_parts( info: Box, backend_metadata: Box<[u8]>, compiled_code: Memory, ) -> Self { Self { - inner: SerializedCacheInner { + inner: ArtifactInner { info, backend_metadata, compiled_code, @@ -131,20 +143,13 @@ impl SerializedCache { } } - pub fn open

(path: P) -> Result - where - P: AsRef, - { - let file = File::open(path).map_err(|e| Error::IoError(e))?; + pub fn deserialize(bytes: &[u8]) -> Result { + let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?; - let mmap = unsafe { Mmap::map(&file).map_err(|e| Error::IoError(e))? }; + let inner = serde_bench::deserialize(body_slice) + .map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?; - let (_header, body_slice) = SerializedCacheHeader::read_from_slice(&mmap[..])?; - - let inner = - deserialize(body_slice).map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?; - - Ok(SerializedCache { inner }) + Ok(Artifact { inner }) } pub fn info(&self) -> &ModuleInfo { @@ -160,44 +165,25 @@ impl SerializedCache { ) } - pub fn store

(&self, path: P) -> Result<(), Error> - where - P: AsRef, - { - let mut file = File::create(path).map_err(|e| Error::IoError(e))?; - - let mut buffer = Vec::new(); - - serialize(&mut buffer, &self.inner).map_err(|e| Error::SerializeError(e.to_string()))?; - - let data_len = buffer.len() as u64; - - file.seek(SeekFrom::Start( - mem::size_of::() as u64 - )) - .map_err(|e| Error::IoError(e))?; - - file.write(buffer.as_slice()) - .map_err(|e| Error::IoError(e))?; - - file.seek(SeekFrom::Start(0)) - .map_err(|e| Error::Unknown(e.to_string()))?; - - let wasm_hash = self.inner.info.wasm_hash.into_array(); - - let cache_header = SerializedCacheHeader { - magic: [ - 'W' as u8, 'A' as u8, 'S' as u8, 'M' as u8, 'E' as u8, 'R' as u8, 0, 0, - ], + pub fn serialize(&self) -> Result, Error> { + let cache_header = ArtifactHeader { + magic: WASMER_CACHE_MAGIC, version: CURRENT_CACHE_VERSION, - data_len, - wasm_hash, + data_len: 0, + wasm_hash: self.inner.info.wasm_hash.into_array(), }; - file.write(cache_header.as_slice()) - .map_err(|e| Error::IoError(e))?; + let mut buffer = cache_header.as_slice().to_vec(); - Ok(()) + serde_bench::serialize(&mut buffer, &self.inner) + .map_err(|e| Error::SerializeError(e.to_string()))?; + + let data_len = (buffer.len() - mem::size_of::()) as u64; + + let (header, _) = ArtifactHeader::read_from_slice_mut(&mut buffer)?; + header.data_len = data_len; + + Ok(buffer) } } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 0e42531b8..663e17534 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -43,7 +43,7 @@ pub use self::module::Module; pub use self::typed_func::Func; use std::sync::Arc; -use self::cache::{Error as CacheError, SerializedCache}; +use self::cache::{Artifact, Error as CacheError}; pub mod prelude { pub use crate::import::{ImportObject, Namespace}; @@ -89,7 +89,7 @@ pub fn validate(wasm: &[u8]) -> bool { } pub unsafe fn load_cache_with( - cache: SerializedCache, + cache: Artifact, compiler: &dyn backend::Compiler, ) -> std::result::Result { let token = backend::Token::generate(); diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 43deb7c4d..130082491 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -1,6 +1,6 @@ use crate::{ backend::{Backend, FuncResolver, ProtectedCaller}, - cache::{Error as CacheError, SerializedCache, WasmHash}, + cache::{Artifact, Error as CacheError, WasmHash}, error, import::ImportObject, structures::{Map, TypedIndex}, @@ -106,9 +106,9 @@ impl Module { Instance::new(Arc::clone(&self.inner), import_object) } - pub fn cache(&self) -> Result { + pub fn cache(&self) -> Result { let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?; - Ok(SerializedCache::from_parts(info, backend_metadata, code)) + Ok(Artifact::from_parts(info, backend_metadata, code)) } pub fn info(&self) -> &ModuleInfo { diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 29af96844..e4169a652 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" [dependencies] lazy_static = "1.2.0" +memmap = "0.7.0" [dependencies.wasmer-runtime-core] path = "../runtime-core" diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index b8f261c95..50507d802 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -1,8 +1,13 @@ use crate::Module; -use std::{fs::create_dir_all, io, path::PathBuf}; +use memmap::Mmap; +use std::{ + fs::{create_dir_all, File}, + io::{self, Write}, + path::PathBuf, +}; -pub use wasmer_runtime_core::cache::{Cache, WasmHash}; -use wasmer_runtime_core::cache::{Error as CacheError, SerializedCache}; +use wasmer_runtime_core::cache::Error as CacheError; +pub use wasmer_runtime_core::cache::{Artifact, Cache, WasmHash}; /// Representation of a directory that contains compiled wasm artifacts. /// @@ -80,8 +85,10 @@ impl Cache for FileSystemCache { let filename = key.encode(); let mut new_path_buf = self.path.clone(); new_path_buf.push(filename); + let file = File::open(new_path_buf)?; + let mmap = unsafe { Mmap::map(&file)? }; - let serialized_cache = SerializedCache::open(new_path_buf)?; + let serialized_cache = Artifact::deserialize(&mmap[..])?; unsafe { wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) } } @@ -92,7 +99,10 @@ impl Cache for FileSystemCache { new_path_buf.push(filename); let serialized_cache = module.cache()?; - serialized_cache.store(new_path_buf)?; + let buffer = serialized_cache.serialize()?; + + let mut file = File::create(new_path_buf)?; + file.write(&buffer)?; Ok(key) } From 199cabd0af05ca55439ab485d75efc9ae8f75054 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 17:09:32 -0800 Subject: [PATCH 13/14] Add comment about serde feature --- lib/runtime-core/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 03d4e5ae6..cb5a6b4b1 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -21,6 +21,7 @@ hex = "0.3.2" # Dependencies for caching. [dependencies.serde] version = "1.0" +# This feature is required for serde to support serializing/deserializing reference counted pointers (e.g. Rc and Arc). features = ["rc"] [dependencies.serde_derive] version = "1.0" From f1b190743bcad7331d4fdfe9aaf12800d2eac096 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 21 Feb 2019 17:11:28 -0800 Subject: [PATCH 14/14] Change file.write to file.write_all --- lib/runtime/src/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index 50507d802..09a93356b 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -102,7 +102,7 @@ impl Cache for FileSystemCache { let buffer = serialized_cache.serialize()?; let mut file = File::create(new_path_buf)?; - file.write(&buffer)?; + file.write_all(&buffer)?; Ok(key) }