mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-26 02:42:18 +00:00
close to working
This commit is contained in:
parent
e381bbd07b
commit
3c7dc200fa
@ -2,15 +2,41 @@ use crate::relocation::{ExternalRelocation, TrapSink};
|
|||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::Memory,
|
backend::{
|
||||||
|
sys::Memory,
|
||||||
|
CacheGen,
|
||||||
|
},
|
||||||
cache::{Cache, Error},
|
cache::{Cache, Error},
|
||||||
module::ModuleInfo,
|
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};
|
||||||
|
|
||||||
|
pub struct CacheGenerator {
|
||||||
|
backend_cache: BackendCache,
|
||||||
|
memory: Arc<Memory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheGenerator {
|
||||||
|
pub fn new(backend_cache: BackendCache, memory: Arc<Memory>) -> Self {
|
||||||
|
Self { backend_cache, memory }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheGen for CacheGenerator {
|
||||||
|
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Arc<Memory>), Error> {
|
||||||
|
let info = Box::new(module.info.clone());
|
||||||
|
|
||||||
|
Err(Error::Unknown("".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct TrampolineCache {
|
pub struct TrampolineCache {
|
||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
@ -22,7 +48,7 @@ pub struct TrampolineCache {
|
|||||||
pub struct BackendCache {
|
pub struct BackendCache {
|
||||||
pub external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
pub external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
||||||
pub offsets: Map<LocalFuncIndex, usize>,
|
pub offsets: Map<LocalFuncIndex, usize>,
|
||||||
pub trap_sink: TrapSink,
|
pub trap_sink: Arc<TrapSink>,
|
||||||
pub trampolines: TrampolineCache,
|
pub trampolines: TrampolineCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,36 +62,36 @@ impl Compiler for CraneliftCompiler {
|
|||||||
module::Module::from_cache(cache)
|
module::Module::from_cache(cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
// #[cfg(feature = "cache")]
|
||||||
fn compile_to_backend_cache_data(
|
// fn compile_to_backend_cache_data(
|
||||||
&self,
|
// &self,
|
||||||
wasm: &[u8],
|
// wasm: &[u8],
|
||||||
_: Token,
|
// _: Token,
|
||||||
) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
|
// ) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
|
||||||
validate(wasm)?;
|
// validate(wasm)?;
|
||||||
|
|
||||||
let isa = get_isa();
|
// let isa = get_isa();
|
||||||
|
|
||||||
let mut module = module::Module::new(wasm);
|
// let mut module = module::Module::new(wasm);
|
||||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
// 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
|
// let (info, backend_cache, compiled_code) = module
|
||||||
.compile_to_backend_cache(&*isa, func_bodies)
|
// .compile_to_backend_cache(&*isa, func_bodies)
|
||||||
.map_err(|e| CompileError::InternalError {
|
// .map_err(|e| CompileError::InternalError {
|
||||||
msg: format!("{:?}", e),
|
// msg: format!("{:?}", e),
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
let buffer =
|
// let buffer =
|
||||||
backend_cache
|
// backend_cache
|
||||||
.into_backend_data()
|
// .into_backend_data()
|
||||||
.map_err(|e| CompileError::InternalError {
|
// .map_err(|e| CompileError::InternalError {
|
||||||
msg: format!("{:?}", e),
|
// msg: format!("{:?}", e),
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
Ok((Box::new(info), buffer, compiled_code))
|
// Ok((Box::new(info), buffer, compiled_code))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_isa() -> Box<isa::TargetIsa> {
|
fn get_isa() -> Box<isa::TargetIsa> {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
use crate::cache::BackendCache;
|
use crate::cache::{BackendCache, CacheGenerator};
|
||||||
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
|
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
|
||||||
|
|
||||||
use cranelift_codegen::{ir, isa};
|
use cranelift_codegen::{ir, isa};
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
use cranelift_wasm;
|
use cranelift_wasm;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
@ -67,42 +68,44 @@ impl Module {
|
|||||||
) -> CompileResult<ModuleInner> {
|
) -> CompileResult<ModuleInner> {
|
||||||
let (func_resolver_builder, handler_data) =
|
let (func_resolver_builder, handler_data) =
|
||||||
FuncResolverBuilder::new(isa, functions, &self.info)?;
|
FuncResolverBuilder::new(isa, functions, &self.info)?;
|
||||||
|
|
||||||
|
|
||||||
let func_resolver =
|
let trampolines = Arc::new(Trampolines::new(isa, &self.info));
|
||||||
Box::new(func_resolver_builder.finalize(&self.info.signatures)?);
|
|
||||||
|
|
||||||
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 =
|
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 {
|
Ok(ModuleInner {
|
||||||
func_resolver,
|
func_resolver: Box::new(func_resolver),
|
||||||
protected_caller,
|
protected_caller: Box::new(protected_caller),
|
||||||
|
cache_gen,
|
||||||
|
|
||||||
info: self.info,
|
info: self.info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
// #[cfg(feature = "cache")]
|
||||||
pub fn compile_to_backend_cache(
|
// pub fn compile_to_backend_cache(
|
||||||
self,
|
// self,
|
||||||
isa: &isa::TargetIsa,
|
// isa: &isa::TargetIsa,
|
||||||
functions: Map<LocalFuncIndex, ir::Function>,
|
// functions: Map<LocalFuncIndex, ir::Function>,
|
||||||
) -> CompileResult<(ModuleInfo, BackendCache, Memory)> {
|
// ) -> CompileResult<(ModuleInfo, BackendCache, Memory)> {
|
||||||
let (func_resolver_builder, handler_data) =
|
// let (func_resolver_builder, handler_data) =
|
||||||
FuncResolverBuilder::new(isa, functions, &self.info)?;
|
// 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) =
|
// let (backend_cache, compiled_code) =
|
||||||
func_resolver_builder.to_backend_cache(trampoline_cache, handler_data);
|
// 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")]
|
#[cfg(feature = "cache")]
|
||||||
pub fn from_cache(cache: Cache) -> Result<ModuleInner, CacheError> {
|
pub fn from_cache(cache: Cache) -> Result<ModuleInner, CacheError> {
|
||||||
@ -111,17 +114,19 @@ impl Module {
|
|||||||
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 = Box::new(
|
let (func_resolver, backend_cache) =
|
||||||
func_resolver_builder
|
func_resolver_builder
|
||||||
.finalize(&info.signatures)
|
.finalize(&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 = 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 {
|
Ok(ModuleInner {
|
||||||
func_resolver,
|
func_resolver: Box::new(func_resolver),
|
||||||
protected_caller,
|
protected_caller: Box::new(protected_caller),
|
||||||
|
cache_gen,
|
||||||
|
|
||||||
info,
|
info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ 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,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
@ -56,7 +57,7 @@ impl FuncResolverBuilder {
|
|||||||
backend_cache: BackendCache,
|
backend_cache: BackendCache,
|
||||||
mut code: Memory,
|
mut code: Memory,
|
||||||
info: &ModuleInfo,
|
info: &ModuleInfo,
|
||||||
) -> Result<(Self, Trampolines, HandlerData), CacheError> {
|
) -> Result<(Self, Arc<Trampolines>, HandlerData), CacheError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
code.protect(.., Protect::ReadWrite)
|
code.protect(.., Protect::ReadWrite)
|
||||||
.map_err(|e| CacheError::Unknown(e.to_string()))?;
|
.map_err(|e| CacheError::Unknown(e.to_string()))?;
|
||||||
@ -69,35 +70,17 @@ impl FuncResolverBuilder {
|
|||||||
Self {
|
Self {
|
||||||
resolver: FuncResolver {
|
resolver: FuncResolver {
|
||||||
map: backend_cache.offsets,
|
map: backend_cache.offsets,
|
||||||
memory: code,
|
memory: Arc::new(UnsafeCell::new(code)),
|
||||||
},
|
},
|
||||||
local_relocs: Map::new(),
|
local_relocs: Map::new(),
|
||||||
external_relocs: backend_cache.external_relocs,
|
external_relocs: backend_cache.external_relocs,
|
||||||
import_len: info.imported_functions.len(),
|
import_len: info.imported_functions.len(),
|
||||||
},
|
},
|
||||||
Trampolines::from_trampoline_cache(backend_cache.trampolines),
|
Arc::new(Trampolines::from_trampoline_cache(backend_cache.trampolines)),
|
||||||
handler_data,
|
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(
|
pub fn new(
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||||
@ -169,10 +152,10 @@ impl FuncResolverBuilder {
|
|||||||
previous_end = new_end;
|
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 {
|
let mut func_resolver_builder = Self {
|
||||||
resolver: FuncResolver { map, memory },
|
resolver: FuncResolver { map, memory: Arc::new(UnsafeCell::new(memory)) },
|
||||||
local_relocs,
|
local_relocs,
|
||||||
external_relocs,
|
external_relocs,
|
||||||
import_len: info.imported_functions.len(),
|
import_len: info.imported_functions.len(),
|
||||||
@ -207,128 +190,143 @@ impl FuncResolverBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn finalize(
|
pub fn finalize(
|
||||||
mut self,
|
self,
|
||||||
signatures: &SliceMap<SigIndex, Arc<FuncSig>>,
|
signatures: &SliceMap<SigIndex, Arc<FuncSig>>,
|
||||||
) -> CompileResult<FuncResolver> {
|
trampolines: Arc<Trampolines>,
|
||||||
for (index, relocs) in self.external_relocs.iter() {
|
handler_data: HandlerData,
|
||||||
for ref reloc in relocs.iter() {
|
) -> CompileResult<(FuncResolver, BackendCache)> {
|
||||||
let target_func_address: isize = match reloc.target {
|
{
|
||||||
RelocationType::LibCall(libcall) => match libcall {
|
let mut memory = unsafe { (*self.resolver.memory.get()) };
|
||||||
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 _,
|
|
||||||
|
|
||||||
VmCallKind::SharedStaticMemoryGrow => unimplemented!(),
|
for (index, relocs) in self.external_relocs.iter() {
|
||||||
VmCallKind::SharedStaticMemorySize => unimplemented!(),
|
for ref reloc in relocs.iter() {
|
||||||
|
let target_func_address: isize = match reloc.target {
|
||||||
VmCallKind::DynamicMemoryGrow => {
|
RelocationType::LibCall(libcall) => match libcall {
|
||||||
vmcalls::local_dynamic_memory_grow as _
|
LibCall::CeilF32 => libcalls::ceilf32 as isize,
|
||||||
}
|
LibCall::FloorF32 => libcalls::floorf32 as isize,
|
||||||
VmCallKind::DynamicMemorySize => {
|
LibCall::TruncF32 => libcalls::truncf32 as isize,
|
||||||
vmcalls::local_dynamic_memory_size as _
|
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 {
|
RelocationType::Intrinsic(ref name) => match name.as_str() {
|
||||||
VmCallKind::StaticMemoryGrow => {
|
"i32print" => i32_print as isize,
|
||||||
vmcalls::imported_static_memory_grow as _
|
"i64print" => i64_print as isize,
|
||||||
}
|
"f32print" => f32_print as isize,
|
||||||
VmCallKind::StaticMemorySize => {
|
"f64print" => f64_print as isize,
|
||||||
vmcalls::imported_static_memory_size as _
|
"strtdbug" => start_debug as isize,
|
||||||
}
|
"enddbug" => end_debug as isize,
|
||||||
|
_ => Err(CompileError::InternalError {
|
||||||
VmCallKind::SharedStaticMemoryGrow => unimplemented!(),
|
msg: format!("unexpected intrinsic: {}", name),
|
||||||
VmCallKind::SharedStaticMemorySize => unimplemented!(),
|
})?,
|
||||||
|
},
|
||||||
VmCallKind::DynamicMemoryGrow => {
|
RelocationType::VmCall(vmcall) => match vmcall {
|
||||||
vmcalls::imported_dynamic_memory_grow as _
|
VmCall::Local(kind) => match kind {
|
||||||
}
|
VmCallKind::StaticMemoryGrow => vmcalls::local_static_memory_grow as _,
|
||||||
VmCallKind::DynamicMemorySize => {
|
VmCallKind::StaticMemorySize => vmcalls::local_static_memory_size as _,
|
||||||
vmcalls::imported_dynamic_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 {
|
let backend_cache = BackendCache {
|
||||||
self.resolver
|
external_relocs: self.external_relocs.clone(),
|
||||||
.memory
|
offsets: self.resolver.map.clone(),
|
||||||
.protect(.., Protect::ReadExec)
|
trap_sink: handler_data.trap_data,
|
||||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
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.
|
/// Resolves a function index to a function address.
|
||||||
pub struct FuncResolver {
|
pub struct FuncResolver {
|
||||||
map: Map<LocalFuncIndex, usize>,
|
map: Map<LocalFuncIndex, usize>,
|
||||||
memory: Memory,
|
pub(crate) memory: Arc<UnsafeCell<Memory>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncResolver {
|
impl FuncResolver {
|
||||||
fn lookup(&self, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
|
fn lookup(&self, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
|
||||||
let offset = *self.map.get(local_func_index)?;
|
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())
|
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,11 @@ impl UserTrapper for Trapper {
|
|||||||
pub struct Caller {
|
pub struct Caller {
|
||||||
func_export_set: HashSet<FuncIndex>,
|
func_export_set: HashSet<FuncIndex>,
|
||||||
handler_data: HandlerData,
|
handler_data: HandlerData,
|
||||||
trampolines: Trampolines,
|
trampolines: Arc<Trampolines>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Caller {
|
impl Caller {
|
||||||
pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: 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 {
|
||||||
@ -187,15 +187,16 @@ fn get_func_from_index(
|
|||||||
unsafe impl Send for HandlerData {}
|
unsafe impl Send for HandlerData {}
|
||||||
unsafe impl Sync for HandlerData {}
|
unsafe impl Sync for HandlerData {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct HandlerData {
|
pub struct HandlerData {
|
||||||
pub trap_data: TrapSink,
|
pub trap_data: Arc<TrapSink>,
|
||||||
exec_buffer_ptr: *const c_void,
|
exec_buffer_ptr: *const c_void,
|
||||||
exec_buffer_size: usize,
|
exec_buffer_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HandlerData {
|
impl HandlerData {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
trap_data: TrapSink,
|
trap_data: Arc<TrapSink>,
|
||||||
exec_buffer_ptr: *const c_void,
|
exec_buffer_ptr: *const c_void,
|
||||||
exec_buffer_size: usize,
|
exec_buffer_size: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -58,7 +58,7 @@ impl Trampolines {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
#[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()];
|
let mut code = vec![0; self.memory.size()];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -67,7 +67,7 @@ impl Trampolines {
|
|||||||
|
|
||||||
TrampolineCache {
|
TrampolineCache {
|
||||||
code,
|
code,
|
||||||
offsets: self.offsets,
|
offsets: self.offsets.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,13 +45,6 @@ pub trait Compiler {
|
|||||||
|
|
||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError>;
|
unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError>;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
fn compile_to_backend_cache_data(
|
|
||||||
&self,
|
|
||||||
wasm: &[u8],
|
|
||||||
_: Token,
|
|
||||||
) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The functionality exposed by this trait is expected to be used
|
/// 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 {
|
pub trait CacheGen: Send + Sync {
|
||||||
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError>;
|
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Arc<Memory>), CacheError>;
|
||||||
}
|
}
|
@ -90,17 +90,17 @@ pub fn validate(wasm: &[u8]) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
// #[cfg(feature = "cache")]
|
||||||
pub fn compile_to_cache_with(
|
// pub fn compile_to_cache_with(
|
||||||
wasm: &[u8],
|
// wasm: &[u8],
|
||||||
compiler: &dyn backend::Compiler,
|
// compiler: &dyn backend::Compiler,
|
||||||
) -> CompileResult<Cache> {
|
// ) -> CompileResult<Cache> {
|
||||||
let token = backend::Token::generate();
|
// let token = backend::Token::generate();
|
||||||
let (info, backend_metadata, compiled_code) =
|
// let (info, backend_metadata, compiled_code) =
|
||||||
compiler.compile_to_backend_cache_data(wasm, token)?;
|
// 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")]
|
#[cfg(feature = "cache")]
|
||||||
pub unsafe fn load_cache_with(
|
pub unsafe fn load_cache_with(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller},
|
backend::{Backend, FuncResolver, ProtectedCaller, CacheGen},
|
||||||
error::Result,
|
error::Result,
|
||||||
import::ImportObject,
|
import::ImportObject,
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
@ -21,10 +21,12 @@ use std::sync::Arc;
|
|||||||
pub struct ModuleInner {
|
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 info: ModuleInfo,
|
pub info: ModuleInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "cache", 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.
|
||||||
|
@ -494,7 +494,8 @@ 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};
|
use crate::backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper, CacheGen, sys::Memory};
|
||||||
|
use crate::cache::Error as CacheError;
|
||||||
use crate::error::RuntimeResult;
|
use crate::error::RuntimeResult;
|
||||||
use crate::types::{FuncIndex, LocalFuncIndex, Value};
|
use crate::types::{FuncIndex, LocalFuncIndex, Value};
|
||||||
use crate::module::WasmHash;
|
use crate::module::WasmHash;
|
||||||
@ -526,10 +527,17 @@ mod vm_ctx_tests {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CacheGen for Placeholder {
|
||||||
|
fn generate_cache(&self, module: &ModuleInner) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ModuleInner {
|
ModuleInner {
|
||||||
func_resolver: Box::new(Placeholder),
|
func_resolver: Box::new(Placeholder),
|
||||||
protected_caller: Box::new(Placeholder),
|
protected_caller: Box::new(Placeholder),
|
||||||
|
cache_gen: Box::new(Placeholder),
|
||||||
info: ModuleInfo {
|
info: ModuleInfo {
|
||||||
memories: Map::new(),
|
memories: Map::new(),
|
||||||
globals: Map::new(),
|
globals: Map::new(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user