mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-25 06:31:32 +00:00
Add caching. (#134)
* Allow a module to have a different signature registry than the process-specific * Add core ability to build compiled code caches * Remove timing printouts * Serialize/Deserialize memories to reduce copies * Work more on api * Relocate local functions relatively before external functions * Fix incorrect definition in test * merge errors caused by merge * Fix emscripten compile * Fix review comments
This commit is contained in:
@ -9,3 +9,77 @@ 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
assert!(self.protection().is_readable());
|
||||
|
||||
let mut state = serializer.serialize_struct("Memory", 2)?;
|
||||
state.serialize_field("protection", &self.protection())?;
|
||||
state.serialize_field("data", &Bytes::new(unsafe { self.as_slice() }))?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "cache")]
|
||||
impl<'de> Deserialize<'de> for Memory {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct MemoryVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for MemoryVisitor {
|
||||
type Value = Memory;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "struct Memory")
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut seq: V) -> Result<Memory, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
let original_protection = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||
|
||||
let bytes: Bytes = seq
|
||||
.next_element()?
|
||||
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||
|
||||
let mut memory = Memory::with_size_protect(bytes.len(), Protect::ReadWrite)
|
||||
.expect("Could not create a memory");
|
||||
|
||||
unsafe {
|
||||
memory.as_slice_mut().copy_from_slice(&*bytes);
|
||||
|
||||
if memory.protection() != original_protection {
|
||||
memory
|
||||
.protect(.., original_protection)
|
||||
.expect("Could not protect memory as its original protection");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(memory)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_struct("Memory", &["protection", "data"], MemoryVisitor)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use errno;
|
||||
use nix::libc;
|
||||
use page_size;
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::{ptr, slice};
|
||||
use std::{fs::File, os::unix::io::IntoRawFd, path::Path, ptr, rc::Rc, slice};
|
||||
|
||||
unsafe impl Send for Memory {}
|
||||
unsafe impl Sync for Memory {}
|
||||
@ -11,14 +11,86 @@ unsafe impl Sync for Memory {}
|
||||
pub struct Memory {
|
||||
ptr: *mut u8,
|
||||
size: usize,
|
||||
protection: Protect,
|
||||
fd: Option<Rc<RawFd>>,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, String>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(path).map_err(|e| e.to_string())?;
|
||||
|
||||
let file_len = file.metadata().map_err(|e| e.to_string())?.len();
|
||||
|
||||
let raw_fd = RawFd::from_file(file);
|
||||
|
||||
let ptr = unsafe {
|
||||
libc::mmap(
|
||||
ptr::null_mut(),
|
||||
file_len as usize,
|
||||
protection.to_protect_const() as i32,
|
||||
libc::MAP_PRIVATE,
|
||||
raw_fd.0,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
if ptr == -1 as _ {
|
||||
Err(errno::errno().to_string())
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
size: file_len as usize,
|
||||
protection,
|
||||
fd: Some(Rc::new(raw_fd)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size_protect(size: usize, protection: Protect) -> Result<Self, String> {
|
||||
if size == 0 {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
size: 0,
|
||||
protection,
|
||||
fd: None,
|
||||
});
|
||||
}
|
||||
|
||||
let size = round_up_to_page_size(size, page_size::get());
|
||||
|
||||
let ptr = unsafe {
|
||||
libc::mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
protection.to_protect_const() as i32,
|
||||
libc::MAP_PRIVATE | libc::MAP_ANON,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
if ptr == -1 as _ {
|
||||
Err(errno::errno().to_string())
|
||||
} else {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
size,
|
||||
protection,
|
||||
fd: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(size: usize) -> Result<Self, String> {
|
||||
if size == 0 {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
size: 0,
|
||||
protection: Protect::None,
|
||||
fd: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -41,6 +113,8 @@ impl Memory {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
size,
|
||||
protection: Protect::None,
|
||||
fd: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -48,9 +122,9 @@ impl Memory {
|
||||
pub unsafe fn protect(
|
||||
&mut self,
|
||||
range: impl RangeBounds<usize>,
|
||||
protect: Protect,
|
||||
protection: Protect,
|
||||
) -> Result<(), String> {
|
||||
let protect = protect.to_protect_const();
|
||||
let protect = protection.to_protect_const();
|
||||
|
||||
let range_start = match range.start_bound() {
|
||||
Bound::Included(start) => *start,
|
||||
@ -75,10 +149,32 @@ impl Memory {
|
||||
if success == -1 {
|
||||
Err(errno::errno().to_string())
|
||||
} else {
|
||||
self.protection = protection;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_at(mut self, offset: usize) -> (Memory, Memory) {
|
||||
let page_size = page_size::get();
|
||||
if offset % page_size == 0 {
|
||||
let second_ptr = unsafe { self.ptr.add(offset) };
|
||||
let second_size = self.size - offset;
|
||||
|
||||
self.size = offset;
|
||||
|
||||
let second = Memory {
|
||||
ptr: second_ptr,
|
||||
size: second_size,
|
||||
protection: self.protection,
|
||||
fd: self.fd.clone(),
|
||||
};
|
||||
|
||||
(self, second)
|
||||
} else {
|
||||
panic!("offset must be multiple of page size: {}", offset)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
@ -91,6 +187,10 @@ impl Memory {
|
||||
slice::from_raw_parts_mut(self.ptr, self.size)
|
||||
}
|
||||
|
||||
pub fn protection(&self) -> Protect {
|
||||
self.protection
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut u8 {
|
||||
self.ptr
|
||||
}
|
||||
@ -105,6 +205,7 @@ impl Drop for Memory {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Protect {
|
||||
@ -123,6 +224,41 @@ impl Protect {
|
||||
Protect::ReadExec => 1 | 4,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_readable(self) -> bool {
|
||||
match self {
|
||||
Protect::Read | Protect::ReadWrite | Protect::ReadExec => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_writable(self) -> bool {
|
||||
match self {
|
||||
Protect::ReadWrite => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RawFd(i32);
|
||||
|
||||
impl RawFd {
|
||||
fn from_file(f: File) -> Self {
|
||||
RawFd(f.into_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawFd {
|
||||
fn drop(&mut self) {
|
||||
let success = unsafe { libc::close(self.0) };
|
||||
assert_eq!(
|
||||
success,
|
||||
0,
|
||||
"failed to close mmapped file descriptor: {}",
|
||||
errno::errno()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Round `size` up to the nearest multiple of `page_size`.
|
||||
|
@ -14,6 +14,7 @@ unsafe impl Sync for Memory {}
|
||||
pub struct Memory {
|
||||
ptr: *mut u8,
|
||||
size: usize,
|
||||
protection: Protect,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
@ -22,6 +23,7 @@ impl Memory {
|
||||
return Ok(Self {
|
||||
ptr: ptr::null_mut(),
|
||||
size: 0,
|
||||
protection: Protect::None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -35,6 +37,7 @@ impl Memory {
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
size,
|
||||
protection: Protect::None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -71,10 +74,31 @@ impl Memory {
|
||||
if ptr.is_null() {
|
||||
Err("unable to protect memory".to_string())
|
||||
} else {
|
||||
self.protection = protection;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_at(mut self, offset: usize) -> (Memory, Memory) {
|
||||
let page_size = page_size::get();
|
||||
if offset % page_size == 0 {
|
||||
let second_ptr = unsafe { self.ptr.add(offset) };
|
||||
let second_size = self.size - offset;
|
||||
|
||||
self.size = offset;
|
||||
|
||||
let second = Memory {
|
||||
ptr: second_ptr,
|
||||
size: second_size,
|
||||
protection: self.protection,
|
||||
};
|
||||
|
||||
(self, second)
|
||||
} else {
|
||||
panic!("offset must be multiple of page size: {}", offset)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
@ -87,6 +111,10 @@ impl Memory {
|
||||
slice::from_raw_parts_mut(self.ptr, self.size)
|
||||
}
|
||||
|
||||
pub fn protection(&self) -> Protect {
|
||||
self.protection
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut u8 {
|
||||
self.ptr
|
||||
}
|
||||
@ -101,6 +129,7 @@ impl Drop for Memory {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Protect {
|
||||
@ -119,6 +148,20 @@ impl Protect {
|
||||
Protect::ReadExec => PAGE_EXECUTE_READ,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_readable(self) -> bool {
|
||||
match self {
|
||||
Protect::Read | Protect::ReadWrite | Protect::ReadExec => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_writable(self) -> bool {
|
||||
match self {
|
||||
Protect::ReadWrite => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Round `size` up to the nearest multiple of `page_size`.
|
||||
|
Reference in New Issue
Block a user