Get caching working again

This commit is contained in:
Lachlan Sneff 2019-02-20 16:41:41 -08:00
parent 82eea00a02
commit 9f40eedba8
21 changed files with 244 additions and 246 deletions

View File

@ -1,20 +1,14 @@
use crate::relocation::{ExternalRelocation, TrapSink}; use crate::relocation::{ExternalRelocation, TrapSink};
use hashbrown::HashMap; use hashbrown::HashMap;
use std::sync::Arc;
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{ backend::{sys::Memory, CacheGen},
sys::Memory,
CacheGen,
},
cache::{Cache, Error}, cache::{Cache, Error},
module::{ModuleInfo, ModuleInner}, module::{ModuleInfo, ModuleInner},
structures::Map, structures::Map,
types::{LocalFuncIndex, SigIndex}, types::{LocalFuncIndex, SigIndex},
}; };
use std::{
sync::Arc,
cell::UnsafeCell,
};
use serde_bench::{deserialize, serialize}; use serde_bench::{deserialize, serialize};
@ -25,14 +19,29 @@ pub struct CacheGenerator {
impl CacheGenerator { impl CacheGenerator {
pub fn new(backend_cache: BackendCache, memory: Arc<Memory>) -> Self { pub fn new(backend_cache: BackendCache, memory: Arc<Memory>) -> Self {
Self { backend_cache, memory } Self {
backend_cache,
memory,
}
} }
} }
impl CacheGen for CacheGenerator { impl CacheGen for CacheGenerator {
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Arc<Memory>), Error> { fn generate_cache(
&self,
module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), Error> {
let info = Box::new(module.info.clone()); 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 { impl BackendCache {
pub fn from_cache(cache: Cache) -> Result<(ModuleInfo, Memory, Self), Error> { 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. let backend_cache =
// else, clone the memory to a new location. This could take a long time, deserialize(&backend_data).map_err(|e| Error::DeserializeError(e.to_string()))?;
// 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)) Ok((info, compiled_code, backend_cache))
} }

View File

@ -145,7 +145,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
let ptr_type = self.pointer_type(); let ptr_type = self.pointer_type();
let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(&self.env.module.info) { let (local_memory_ptr_ptr, description) =
match mem_index.local_or_import(&self.env.module.info) {
LocalOrImport::Local(local_mem_index) => { LocalOrImport::Local(local_mem_index) => {
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx, base: vmctx,
@ -253,7 +254,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
let ptr_type = self.pointer_type(); 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) => { LocalOrImport::Local(local_table_index) => {
let tables_base = func.create_global_value(ir::GlobalValueData::Load { let tables_base = func.create_global_value(ir::GlobalValueData::Load {
@ -568,7 +570,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let mem_index: MemoryIndex = Converter(clif_mem_index).into(); let mem_index: MemoryIndex = Converter(clif_mem_index).into();
let (namespace, mem_index, description) = match mem_index.local_or_import(&self.env.module.info) { let (namespace, mem_index, description) =
match mem_index.local_or_import(&self.env.module.info) {
LocalOrImport::Local(local_mem_index) => ( LocalOrImport::Local(local_mem_index) => (
call_names::LOCAL_NAMESPACE, call_names::LOCAL_NAMESPACE,
local_mem_index.index(), local_mem_index.index(),
@ -631,7 +634,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
let mem_index: MemoryIndex = Converter(clif_mem_index).into(); let mem_index: MemoryIndex = Converter(clif_mem_index).into();
let (namespace, mem_index, description) = match mem_index.local_or_import(&self.env.module.info) { let (namespace, mem_index, description) =
match mem_index.local_or_import(&self.env.module.info) {
LocalOrImport::Local(local_mem_index) => ( LocalOrImport::Local(local_mem_index) => (
call_names::LOCAL_NAMESPACE, call_names::LOCAL_NAMESPACE,
local_mem_index.index(), local_mem_index.index(),

View File

@ -1,4 +1,3 @@
mod cache; mod cache;
mod func_env; mod func_env;
mod libcalls; mod libcalls;
@ -15,11 +14,7 @@ use cranelift_codegen::{
}; };
use target_lexicon::Triple; use target_lexicon::Triple;
use wasmer_runtime_core::{ use wasmer_runtime_core::cache::{Cache, Error as CacheError};
backend::sys::Memory,
cache::{Cache, Error as CacheError},
module::ModuleInfo,
};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{Compiler, Token}, backend::{Compiler, Token},
error::{CompileError, CompileResult}, error::{CompileError, CompileResult},

View File

@ -1,4 +1,3 @@
use crate::cache::{BackendCache, CacheGenerator}; use crate::cache::{BackendCache, CacheGenerator};
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines}; use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
@ -8,11 +7,7 @@ use cranelift_wasm;
use hashbrown::HashMap; use hashbrown::HashMap;
use std::sync::Arc; use std::sync::Arc;
use wasmer_runtime_core::cache::{Cache, Error as CacheError};
use wasmer_runtime_core::{
backend::sys::Memory,
cache::{Cache, Error as CacheError},
};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::Backend, backend::Backend,
@ -58,7 +53,6 @@ impl Module {
namespace_table: StringTable::new(), namespace_table: StringTable::new(),
name_table: StringTable::new(), name_table: StringTable::new(),
wasm_hash: WasmHash::generate(wasm), wasm_hash: WasmHash::generate(wasm),
}, },
} }
@ -74,14 +68,18 @@ impl Module {
let trampolines = Arc::new(Trampolines::new(isa, &self.info)); let trampolines = Arc::new(Trampolines::new(isa, &self.info));
let (func_resolver, backend_cache) = let (func_resolver, backend_cache) = func_resolver_builder.finalize(
func_resolver_builder.finalize(&self.info.signatures, Arc::clone(&trampolines), handler_data.clone())?; &self.info.signatures,
Arc::clone(&trampolines),
handler_data.clone(),
)?;
let protected_caller = let protected_caller = Caller::new(&self.info, handler_data, trampolines);
Caller::new(&self.info, handler_data, trampolines);
let cache_gen = Box::new(CacheGenerator::new(
let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); backend_cache,
Arc::clone(&func_resolver.memory),
));
Ok(ModuleInner { Ok(ModuleInner {
func_resolver: Box::new(func_resolver), func_resolver: Box::new(func_resolver),
@ -92,22 +90,26 @@ impl Module {
}) })
} }
pub fn from_cache(cache: Cache) -> Result<ModuleInner, CacheError> { pub fn from_cache(cache: Cache) -> Result<ModuleInner, CacheError> {
let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?;
let (func_resolver_builder, trampolines, handler_data) = let (func_resolver_builder, trampolines, handler_data) =
FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?; FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?;
let (func_resolver, backend_cache) = let (func_resolver, backend_cache) = func_resolver_builder
func_resolver_builder .finalize(
.finalize(&info.signatures, Arc::clone(&trampolines), handler_data.clone()) &info.signatures,
Arc::clone(&trampolines),
handler_data.clone(),
)
.map_err(|e| CacheError::Unknown(format!("{:?}", e)))?; .map_err(|e| CacheError::Unknown(format!("{:?}", e)))?;
let protected_caller = Caller::new(&info, handler_data, trampolines); let protected_caller = Caller::new(&info, handler_data, trampolines);
let cache_gen = Box::new(CacheGenerator::new(
let cache_gen = Box::new(CacheGenerator::new(backend_cache, Arc::clone(&func_resolver.memory))); backend_cache,
Arc::clone(&func_resolver.memory),
));
Ok(ModuleInner { Ok(ModuleInner {
func_resolver: Box::new(func_resolver), func_resolver: Box::new(func_resolver),

View File

@ -22,16 +22,14 @@ pub mod call_names {
pub const DYNAMIC_MEM_SIZE: u32 = 5; pub const DYNAMIC_MEM_SIZE: u32 = 5;
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Reloc { pub enum Reloc {
Abs8, Abs8,
X86PCRel4, X86PCRel4,
X86CallPCRel4, X86CallPCRel4,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone)]
pub enum LibCall { pub enum LibCall {
Probestack, Probestack,
CeilF32, CeilF32,
@ -44,8 +42,7 @@ pub enum LibCall {
NearestF64, NearestF64,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct ExternalRelocation { pub struct ExternalRelocation {
/// The relocation code. /// The relocation code.
pub reloc: Reloc, pub reloc: Reloc,
@ -66,8 +63,7 @@ pub struct LocalRelocation {
pub target: FuncIndex, pub target: FuncIndex,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub enum VmCallKind { pub enum VmCallKind {
StaticMemoryGrow, StaticMemoryGrow,
StaticMemorySize, StaticMemorySize,
@ -79,16 +75,14 @@ pub enum VmCallKind {
DynamicMemorySize, DynamicMemorySize,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub enum VmCall { pub enum VmCall {
Local(VmCallKind), Local(VmCallKind),
Import(VmCallKind), Import(VmCallKind),
} }
/// Specify the type of relocation /// Specify the type of relocation
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub enum RelocationType { pub enum RelocationType {
Intrinsic(String), Intrinsic(String),
LibCall(LibCall), LibCall(LibCall),
@ -218,8 +212,7 @@ impl binemit::RelocSink for RelocSink {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub enum TrapCode { pub enum TrapCode {
StackOverflow, StackOverflow,
HeapOutOfBounds, HeapOutOfBounds,
@ -244,8 +237,7 @@ impl RelocSink {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct TrapData { pub struct TrapData {
pub trapcode: TrapCode, pub trapcode: TrapCode,
pub srcloc: u32, pub srcloc: u32,

View File

@ -1,8 +1,4 @@
use crate::{cache::BackendCache, trampoline::Trampolines};
use crate::{
cache::{BackendCache, TrampolineCache},
trampoline::Trampolines,
};
use crate::{ use crate::{
libcalls, libcalls,
relocation::{ relocation::{
@ -17,7 +13,6 @@ use cranelift_codegen::{ir, isa, Context};
use std::{ use std::{
mem, mem,
ptr::{write_unaligned, NonNull}, ptr::{write_unaligned, NonNull},
cell::UnsafeCell,
sync::Arc, sync::Arc,
}; };
@ -43,7 +38,11 @@ extern "C" {
pub fn __chkstk(); pub fn __chkstk();
} }
fn lookup_func(map: &SliceMap<LocalFuncIndex, usize>, memory: &Memory, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> { fn lookup_func(
map: &SliceMap<LocalFuncIndex, usize>,
memory: &Memory,
local_func_index: LocalFuncIndex,
) -> Option<NonNull<vm::Func>> {
let offset = *map.get(local_func_index)?; let offset = *map.get(local_func_index)?;
let ptr = unsafe { memory.as_ptr().add(offset) }; let ptr = unsafe { memory.as_ptr().add(offset) };
@ -60,7 +59,6 @@ pub struct FuncResolverBuilder {
} }
impl FuncResolverBuilder { impl FuncResolverBuilder {
pub fn new_from_backend_cache( pub fn new_from_backend_cache(
backend_cache: BackendCache, backend_cache: BackendCache,
mut code: Memory, mut code: Memory,
@ -82,7 +80,9 @@ impl FuncResolverBuilder {
external_relocs: backend_cache.external_relocs, external_relocs: backend_cache.external_relocs,
import_len: info.imported_functions.len(), 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, handler_data,
)) ))
} }
@ -158,7 +158,8 @@ impl FuncResolverBuilder {
previous_end = new_end; 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 { let mut func_resolver_builder = Self {
map, map,
@ -177,12 +178,15 @@ impl FuncResolverBuilder {
for (index, relocs) in self.local_relocs.iter() { for (index, relocs) in self.local_relocs.iter() {
for ref reloc in relocs.iter() { for ref reloc in relocs.iter() {
let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len); let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len);
let target_func_address = let target_func_address = lookup_func(&self.map, &self.memory, local_func_index)
lookup_func(&self.map, &self.memory, local_func_index).unwrap().as_ptr() as usize; .unwrap()
.as_ptr() as usize;
// We need the address of the current function // We need the address of the current function
// because these calls are relative. // 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 { unsafe {
let reloc_address = func_addr + reloc.offset as usize; let reloc_address = func_addr + reloc.offset as usize;
@ -273,7 +277,9 @@ impl FuncResolverBuilder {
// We need the address of the current function // We need the address of the current function
// because some of these calls are relative. // 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. // Determine relocation type and apply relocation.
match reloc.reloc { match reloc.reloc {
@ -313,10 +319,13 @@ impl FuncResolverBuilder {
trampolines: trampolines.to_trampoline_cache(), trampolines: trampolines.to_trampoline_cache(),
}; };
Ok((FuncResolver { Ok((
FuncResolver {
map: self.map, map: self.map,
memory: Arc::new(self.memory), memory: Arc::new(self.memory),
}, backend_cache)) },
backend_cache,
))
} }
} }

View File

@ -44,7 +44,11 @@ pub struct Caller {
} }
impl Caller { impl Caller {
pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Arc<Trampolines>) -> Self { pub fn new(
module: &ModuleInfo,
handler_data: HandlerData,
trampolines: Arc<Trampolines>,
) -> Self {
let mut func_export_set = HashSet::new(); let mut func_export_set = HashSet::new();
for export_index in module.exports.values() { for export_index in module.exports.values() {
if let ExportIndex::Func(func_index) = export_index { if let ExportIndex::Func(func_index) = export_index {

View File

@ -1,4 +1,3 @@
use crate::cache::TrampolineCache; use crate::cache::TrampolineCache;
use cranelift_codegen::{ use cranelift_codegen::{
binemit::{NullTrapSink, Reloc, RelocSink}, binemit::{NullTrapSink, Reloc, RelocSink},
@ -33,7 +32,6 @@ pub struct Trampolines {
} }
impl Trampolines { impl Trampolines {
pub fn from_trampoline_cache(cache: TrampolineCache) -> Self { pub fn from_trampoline_cache(cache: TrampolineCache) -> Self {
// pub struct TrampolineCache { // pub struct TrampolineCache {
// #[serde(with = "serde_bytes")] // #[serde(with = "serde_bytes")]
@ -57,7 +55,6 @@ impl Trampolines {
} }
} }
pub fn to_trampoline_cache(&self) -> TrampolineCache { pub fn to_trampoline_cache(&self) -> TrampolineCache {
let mut code = vec![0; self.memory.size()]; let mut code = vec![0; self.memory.size()];

View File

@ -220,13 +220,13 @@ impl EmscriptenGlobals {
namespace_index, namespace_index,
name_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 namespace = module.info().namespace_table.get(*namespace_index);
let name = module.0.info.name_table.get(*name_index); let name = module.info().name_table.get(*name_index);
if name == "abortOnCannotGrowMemory" && namespace == "env" { if name == "abortOnCannotGrowMemory" && namespace == "env" {
let sig_index = module.0.info.func_assoc[index.convert_up(&module.0)]; let sig_index = module.info().func_assoc[index.convert_up(module.info())];
let expected_sig = &module.0.info.signatures[sig_index]; let expected_sig = &module.info().signatures[sig_index];
if **expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG { if **expected_sig == *OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG {
use_old_abort_on_cannot_grow_memory = true; use_old_abort_on_cannot_grow_memory = true;
} }

View File

@ -16,13 +16,12 @@ use wasmer_runtime_core::{
/// We check if a provided module is an Emscripten generated one /// We check if a provided module is an Emscripten generated one
pub fn is_emscripten_module(module: &Module) -> bool { 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 let namespace = module
.0 .info()
.info
.namespace_table .namespace_table
.get(import_name.namespace_index); .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" { if field == "_emscripten_memcpy_big" && namespace == "env" {
return true; return true;
} }
@ -31,12 +30,12 @@ pub fn is_emscripten_module(module: &Module) -> bool {
} }
pub fn get_emscripten_table_size(module: &Module) -> (u32, Option<u32>) { pub fn get_emscripten_table_size(module: &Module) -> (u32, Option<u32>) {
let (_, table) = &module.0.info.imported_tables[ImportedTableIndex::new(0)]; let (_, table) = &module.info().imported_tables[ImportedTableIndex::new(0)];
(table.minimum, table.maximum) (table.minimum, table.maximum)
} }
pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) { pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) {
let (_, memory) = &module.0.info.imported_memories[ImportedMemoryIndex::new(0)]; let (_, memory) = &module.info().imported_memories[ImportedMemoryIndex::new(0)];
(memory.minimum, memory.maximum) (memory.minimum, memory.maximum)
} }

View File

@ -2,7 +2,7 @@ use crate::{
backing::ImportBacking, backing::ImportBacking,
error::CompileResult, error::CompileResult,
error::RuntimeResult, error::RuntimeResult,
module::{ModuleInner}, module::ModuleInner,
types::{FuncIndex, LocalFuncIndex, Value}, types::{FuncIndex, LocalFuncIndex, Value},
vm, vm,
}; };
@ -21,8 +21,7 @@ pub mod sys {
} }
pub use crate::sig_registry::SigRegistry; pub use crate::sig_registry::SigRegistry;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Backend { pub enum Backend {
Cranelift, Cranelift,
} }
@ -45,7 +44,6 @@ pub trait Compiler {
/// be called from inside the runtime. /// be called from inside the runtime.
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner>; fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner>;
unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError>; unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError>;
} }
@ -95,7 +93,9 @@ pub trait FuncResolver: Send + Sync {
) -> Option<NonNull<vm::Func>>; ) -> Option<NonNull<vm::Func>>;
} }
pub trait CacheGen: Send + Sync { pub trait CacheGen: Send + Sync {
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Arc<Memory>), CacheError>; fn generate_cache(
&self,
module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError>;
} }

View File

@ -6,9 +6,9 @@ use std::{
fs::File, fs::File,
io::{self, Seek, SeekFrom, Write}, io::{self, Seek, SeekFrom, Write},
mem, mem,
sync::Arc,
path::Path, path::Path,
slice, slice,
sync::Arc,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -69,7 +69,7 @@ struct CacheInner {
info: Box<ModuleInfo>, info: Box<ModuleInfo>,
#[serde(with = "serde_bytes")] #[serde(with = "serde_bytes")]
backend_metadata: Box<[u8]>, backend_metadata: Box<[u8]>,
compiled_code: Arc<Memory>, compiled_code: Memory,
} }
pub struct Cache { pub struct Cache {
@ -80,7 +80,7 @@ impl Cache {
pub(crate) fn from_parts( pub(crate) fn from_parts(
info: Box<ModuleInfo>, info: Box<ModuleInfo>,
backend_metadata: Box<[u8]>, backend_metadata: Box<[u8]>,
compiled_code: Arc<Memory>, compiled_code: Memory,
) -> Self { ) -> Self {
Self { Self {
inner: CacheInner { inner: CacheInner {
@ -104,9 +104,7 @@ impl Cache {
let inner = let inner =
deserialize(body_slice).map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?; deserialize(body_slice).map_err(|e| Error::DeserializeError(format!("{:#?}", e)))?;
Ok(Cache { Ok(Cache { inner })
inner,
})
} }
pub fn info(&self) -> &ModuleInfo { pub fn info(&self) -> &ModuleInfo {
@ -114,7 +112,7 @@ impl Cache {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Arc<Memory>) { pub fn consume(self) -> (ModuleInfo, Box<[u8]>, Memory) {
( (
*self.inner.info, *self.inner.info,
self.inner.backend_metadata, self.inner.backend_metadata,

View File

@ -2,7 +2,6 @@
#[macro_use] #[macro_use]
extern crate field_offset; extern crate field_offset;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
@ -44,7 +43,6 @@ pub use self::module::Module;
pub use self::typed_func::Func; pub use self::typed_func::Func;
use std::sync::Arc; use std::sync::Arc;
use self::cache::{Cache, Error as CacheError}; use self::cache::{Cache, Error as CacheError};
pub mod prelude { pub mod prelude {
@ -102,7 +100,6 @@ pub fn validate(wasm: &[u8]) -> bool {
// Ok(Cache::new(wasm, info, backend_metadata, compiled_code)) // Ok(Cache::new(wasm, info, backend_metadata, compiled_code))
// } // }
pub unsafe fn load_cache_with( pub unsafe fn load_cache_with(
cache: Cache, cache: Cache,
compiler: &dyn backend::Compiler, compiler: &dyn backend::Compiler,

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
backend::{Backend, FuncResolver, ProtectedCaller}, backend::{Backend, FuncResolver, ProtectedCaller},
cache::{Cache, Error as CacheError},
error, error,
import::ImportObject, import::ImportObject,
structures::{Map, TypedIndex}, structures::{Map, TypedIndex},
@ -10,7 +11,6 @@ use crate::{
LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryDescriptor, MemoryIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryDescriptor, MemoryIndex,
SigIndex, TableDescriptor, TableIndex, SigIndex, TableDescriptor, TableIndex,
}, },
cache::{Cache, Error as CacheError},
Instance, Instance,
}; };
@ -25,14 +25,12 @@ pub struct ModuleInner {
pub func_resolver: Box<dyn FuncResolver>, pub func_resolver: Box<dyn FuncResolver>,
pub protected_caller: Box<dyn ProtectedCaller>, pub protected_caller: Box<dyn ProtectedCaller>,
pub cache_gen: Box<dyn CacheGen>, pub cache_gen: Box<dyn CacheGen>,
pub info: ModuleInfo, pub info: ModuleInfo,
} }
#[derive(Clone)] #[derive(Clone, Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct ModuleInfo { pub struct ModuleInfo {
// This are strictly local and the typsystem ensures that. // This are strictly local and the typsystem ensures that.
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>, pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
@ -62,12 +60,9 @@ pub struct ModuleInfo {
pub wasm_hash: WasmHash, pub wasm_hash: WasmHash,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Serialize, Deserialize)]
pub struct WasmHash([u8; 32]); pub struct WasmHash([u8; 32]);
impl WasmHash { impl WasmHash {
pub fn generate(wasm: &[u8]) -> Self { pub fn generate(wasm: &[u8]) -> Self {
WasmHash(crate::cache::hash_data(wasm)) WasmHash(crate::cache::hash_data(wasm))
@ -125,23 +120,25 @@ impl Module {
} }
pub fn cache(&self) -> Result<Cache, CacheError> { pub fn cache(&self) -> Result<Cache, CacheError> {
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 {} impl ModuleInner {}
#[doc(hidden)] #[doc(hidden)]
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct ImportName { pub struct ImportName {
pub namespace_index: NamespaceIndex, pub namespace_index: NamespaceIndex,
pub name_index: NameIndex, pub name_index: NameIndex,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportIndex { pub enum ExportIndex {
Func(FuncIndex), Func(FuncIndex),
Memory(MemoryIndex), Memory(MemoryIndex),
@ -150,8 +147,7 @@ pub enum ExportIndex {
} }
/// A data initializer for linear memory. /// A data initializer for linear memory.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct DataInitializer { pub struct DataInitializer {
/// The index of the memory to initialize. /// The index of the memory to initialize.
pub memory_index: MemoryIndex, pub memory_index: MemoryIndex,
@ -163,8 +159,7 @@ pub struct DataInitializer {
} }
/// A WebAssembly table initializer. /// A WebAssembly table initializer.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct TableInitializer { pub struct TableInitializer {
/// The index of a table to initialize. /// The index of a table to initialize.
pub table_index: TableIndex, pub table_index: TableIndex,
@ -225,8 +220,7 @@ impl<K: TypedIndex> StringTableBuilder<K> {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct StringTable<K: TypedIndex> { pub struct StringTable<K: TypedIndex> {
table: Map<K, (u32, u32)>, table: Map<K, (u32, u32)>,
buffer: String, buffer: String,
@ -249,8 +243,7 @@ impl<K: TypedIndex> StringTable<K> {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct NamespaceIndex(u32); pub struct NamespaceIndex(u32);
impl TypedIndex for NamespaceIndex { impl TypedIndex for NamespaceIndex {
@ -265,8 +258,7 @@ impl TypedIndex for NamespaceIndex {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct NameIndex(u32); pub struct NameIndex(u32);
impl TypedIndex for NameIndex { impl TypedIndex for NameIndex {

View File

@ -8,8 +8,7 @@ use std::{
}; };
/// Dense item map /// Dense item map
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct Map<K, V> pub struct Map<K, V>
where where
K: TypedIndex, K: TypedIndex,

View File

@ -10,7 +10,6 @@ pub use self::unix::*;
#[cfg(windows)] #[cfg(windows)]
pub use self::windows::*; pub use self::windows::*;
use serde::{ use serde::{
de::{self, SeqAccess, Visitor}, de::{self, SeqAccess, Visitor},
ser::SerializeStruct, ser::SerializeStruct,
@ -21,7 +20,6 @@ use serde_bytes::Bytes;
use std::fmt; use std::fmt;
impl Serialize for Memory { impl Serialize for Memory {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -36,7 +34,6 @@ impl Serialize for Memory {
} }
} }
impl<'de> Deserialize<'de> for Memory { impl<'de> Deserialize<'de> for Memory {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where

View File

@ -207,16 +207,26 @@ impl Drop for Memory {
impl Clone for Memory { impl Clone for Memory {
fn clone(&self) -> Self { 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 { unsafe {
new.as_slice_mut().copy_from_slice(self.as_slice()); new.as_slice_mut().copy_from_slice(self.as_slice());
if temp_protection != self.protection {
new.protect(.., self.protection).unwrap();
} }
}
new new
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(dead_code)] #[allow(dead_code)]
pub enum Protect { pub enum Protect {
None, None,

View File

@ -158,16 +158,26 @@ impl Drop for Memory {
impl Clone for Memory { impl Clone for Memory {
fn clone(&self) -> Self { 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 { unsafe {
new.as_slice_mut().copy_from_slice(self.as_slice()); new.as_slice_mut().copy_from_slice(self.as_slice());
if temp_protection != self.protection {
new.protect(.., self.protection).unwrap();
} }
}
new new
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(dead_code)] #[allow(dead_code)]
pub enum Protect { pub enum Protect {
None, None,

View File

@ -2,8 +2,7 @@ use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, unit
use std::{borrow::Cow, mem}; use std::{borrow::Cow, mem};
/// Represents a WebAssembly type. /// Represents a WebAssembly type.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Type { pub enum Type {
/// The `i32` type. /// The `i32` type.
I32, I32,
@ -25,8 +24,7 @@ impl std::fmt::Display for Type {
/// ///
/// As the number of types in WebAssembly expand, /// As the number of types in WebAssembly expand,
/// this structure will expand as well. /// this structure will expand as well.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum Value { pub enum Value {
/// The `i32` type. /// The `i32` type.
I32(i32), I32(i32),
@ -171,15 +169,13 @@ impl ValueType for f64 {
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementType { pub enum ElementType {
/// Any wasm function. /// Any wasm function.
Anyfunc, Anyfunc,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct TableDescriptor { pub struct TableDescriptor {
/// Type of data stored in this table. /// Type of data stored in this table.
pub element: ElementType, pub element: ElementType,
@ -203,8 +199,7 @@ impl TableDescriptor {
/// A const value initializer. /// A const value initializer.
/// Over time, this will be able to represent more and more /// Over time, this will be able to represent more and more
/// complex expressions. /// complex expressions.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum Initializer { pub enum Initializer {
/// Corresponds to a `const.*` instruction. /// Corresponds to a `const.*` instruction.
Const(Value), Const(Value),
@ -212,24 +207,21 @@ pub enum Initializer {
GetGlobal(ImportedGlobalIndex), GetGlobal(ImportedGlobalIndex),
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GlobalDescriptor { pub struct GlobalDescriptor {
pub mutable: bool, pub mutable: bool,
pub ty: Type, pub ty: Type,
} }
/// A wasm global. /// A wasm global.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub struct GlobalInit { pub struct GlobalInit {
pub desc: GlobalDescriptor, pub desc: GlobalDescriptor,
pub init: Initializer, pub init: Initializer,
} }
/// A wasm memory. /// A wasm memory.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MemoryDescriptor { pub struct MemoryDescriptor {
/// The minimum number of allowed pages. /// The minimum number of allowed pages.
pub minimum: Pages, pub minimum: Pages,
@ -261,8 +253,7 @@ impl MemoryDescriptor {
/// The signature of a function that is either implemented /// The signature of a function that is either implemented
/// in a wasm module or exposed to wasm by the host. /// in a wasm module or exposed to wasm by the host.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FuncSig { pub struct FuncSig {
params: Cow<'static, [Type]>, params: Cow<'static, [Type]>,
returns: Cow<'static, [Type]>, returns: Cow<'static, [Type]>,
@ -400,8 +391,7 @@ define_local_or_import![
(GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals), (GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
]; ];
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct SigIndex(u32); pub struct SigIndex(u32);
impl TypedIndex for SigIndex { impl TypedIndex for SigIndex {
#[doc(hidden)] #[doc(hidden)]

View File

@ -7,8 +7,7 @@ const WASM_PAGE_SIZE: usize = 65_536;
const WASM_MAX_PAGES: usize = 65_536; const WASM_MAX_PAGES: usize = 65_536;
/// Units of WebAssembly pages (as specified to be 65,536 bytes). /// Units of WebAssembly pages (as specified to be 65,536 bytes).
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pages(pub u32); pub struct Pages(pub u32);
impl Pages { impl Pages {
@ -33,8 +32,7 @@ impl fmt::Debug for Pages {
} }
/// Units of WebAssembly memory in terms of 8-bit bytes. /// Units of WebAssembly memory in terms of 8-bit bytes.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bytes(pub usize); pub struct Bytes(pub usize);
impl fmt::Debug for Bytes { impl fmt::Debug for Bytes {

View File

@ -494,11 +494,13 @@ mod vm_ctx_tests {
fn generate_module() -> ModuleInner { fn generate_module() -> ModuleInner {
use super::Func; 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::cache::Error as CacheError;
use crate::error::RuntimeResult; use crate::error::RuntimeResult;
use crate::types::{FuncIndex, LocalFuncIndex, Value};
use crate::module::WasmHash; use crate::module::WasmHash;
use crate::types::{FuncIndex, LocalFuncIndex, Value};
use hashbrown::HashMap; use hashbrown::HashMap;
use std::ptr::NonNull; use std::ptr::NonNull;
struct Placeholder; struct Placeholder;
@ -528,12 +530,14 @@ mod vm_ctx_tests {
} }
} }
impl CacheGen for Placeholder { impl CacheGen for Placeholder {
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> { fn generate_cache(
&self,
module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
unimplemented!() unimplemented!()
} }
} }
ModuleInner { ModuleInner {
func_resolver: Box::new(Placeholder), func_resolver: Box::new(Placeholder),
protected_caller: Box::new(Placeholder), protected_caller: Box::new(Placeholder),