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