Add (hopefully-working) support for windows

This commit is contained in:
Lachlan Sneff
2019-01-21 11:51:41 -08:00
parent a3821a90c1
commit b74a08f097
12 changed files with 201 additions and 38 deletions

1
Cargo.lock generated
View File

@ -1145,6 +1145,7 @@ dependencies = [
"page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.1.0", "wasmer-clif-backend 0.1.0",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View File

@ -6,7 +6,10 @@ use std::mem;
use std::ptr::{write_unaligned, NonNull}; use std::ptr::{write_unaligned, NonNull};
use wasmer_runtime::{ use wasmer_runtime::{
self, self,
backend::{self, Mmap, Protect}, backend::{
self,
sys::{Memory, Protect},
},
error::{CompileError, CompileResult}, error::{CompileError, CompileResult},
structures::Map, structures::Map,
types::LocalFuncIndex, types::LocalFuncIndex,
@ -49,7 +52,7 @@ impl FuncResolverBuilder {
trap_sinks.push(trap_sink); trap_sinks.push(trap_sink);
} }
let mut memory = Mmap::with_size(total_size) let mut memory = Memory::with_size(total_size)
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?; .map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
unsafe { unsafe {
memory memory
@ -176,7 +179,7 @@ impl FuncResolverBuilder {
/// 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: Mmap, memory: Memory,
} }
impl FuncResolver { impl FuncResolver {

View File

@ -10,6 +10,11 @@ hashbrown = "0.1"
libffi = "0.6.4" libffi = "0.6.4"
nix = "0.12.0" nix = "0.12.0"
page_size = "0.4.1" page_size = "0.4.1"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["memoryapi"] }
[target.'cfg(unix)'.dependencies]
errno = "0.2.4" errno = "0.2.4"
[build-dependencies] [build-dependencies]

View File

@ -1,7 +1,9 @@
use crate::{error::CompileResult, module::ModuleInner, types::LocalFuncIndex, vm}; use crate::{error::CompileResult, module::ModuleInner, types::LocalFuncIndex, vm};
use std::ptr::NonNull; use std::ptr::NonNull;
pub use crate::mmap::{Mmap, Protect}; pub mod sys {
pub use crate::sys::*;
}
pub use crate::sig_registry::SigRegistry; pub use crate::sig_registry::SigRegistry;
pub trait Compiler { pub trait Compiler {

View File

@ -12,12 +12,12 @@ pub mod export;
pub mod import; pub mod import;
pub mod instance; pub mod instance;
pub mod memory; pub mod memory;
mod mmap;
pub mod module; pub mod module;
mod recovery; mod recovery;
mod sig_registry; mod sig_registry;
mod sighandler; mod sighandler;
pub mod structures; pub mod structures;
mod sys;
pub mod table; pub mod table;
pub mod types; pub mod types;
pub mod vm; pub mod vm;

View File

@ -1,7 +1,7 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::{ use crate::{
mmap::{Mmap, Protect}, sys,
types::{LocalMemoryIndex, Memory}, types::{LocalMemoryIndex, Memory},
vm, vm,
}; };
@ -10,7 +10,7 @@ use crate::{
#[derive(Debug)] #[derive(Debug)]
pub struct LinearMemory { pub struct LinearMemory {
/// The actual memory allocation. /// The actual memory allocation.
mmap: Mmap, memory: sys::Memory,
/// The current number of wasm pages. /// The current number of wasm pages.
current: u32, current: u32,
@ -66,21 +66,22 @@ impl LinearMemory {
) )
}; };
let mut mmap = Mmap::with_size(mmap_size).unwrap(); let mut memory = sys::Memory::with_size(mmap_size).unwrap();
// map initial pages as readwrite since the inital mmap is mapped as not accessible. // map initial pages as readwrite since the inital mmap is mapped as not accessible.
if initial_pages != 0 { if initial_pages != 0 {
unsafe { unsafe {
mmap.protect( memory
0..(initial_pages as usize * Self::PAGE_SIZE as usize), .protect(
Protect::ReadWrite, 0..(initial_pages as usize * Self::PAGE_SIZE as usize),
) sys::Protect::ReadWrite,
.expect("unable to make memory accessible"); )
.expect("unable to make memory accessible");
} }
} }
Self { Self {
mmap, memory,
current: initial_pages, current: initial_pages,
max: mem.max, max: mem.max,
offset_guard_size, offset_guard_size,
@ -90,7 +91,7 @@ impl LinearMemory {
/// Returns an base address of this linear memory. /// Returns an base address of this linear memory.
fn base(&mut self) -> *mut u8 { fn base(&mut self) -> *mut u8 {
self.mmap.as_ptr() self.memory.as_ptr()
} }
/// Returns the size in bytes /// Returns the size in bytes
@ -146,21 +147,23 @@ impl LinearMemory {
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize; let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
if new_bytes > self.mmap.size() - self.offset_guard_size { if new_bytes > self.memory.size() - self.offset_guard_size {
let mmap_size = new_bytes.checked_add(self.offset_guard_size)?; let memory_size = new_bytes.checked_add(self.offset_guard_size)?;
let mut new_mmap = Mmap::with_size(mmap_size).ok()?; let mut new_memory = sys::Memory::with_size(memory_size).ok()?;
unsafe { unsafe {
new_mmap.protect(0..new_bytes, Protect::ReadWrite).ok()?; new_memory
.protect(0..new_bytes, sys::Protect::ReadWrite)
.ok()?;
} }
let copy_size = self.mmap.size() - self.offset_guard_size; let copy_size = self.memory.size() - self.offset_guard_size;
unsafe { unsafe {
new_mmap.as_slice_mut()[..copy_size] new_memory.as_slice_mut()[..copy_size]
.copy_from_slice(&self.mmap.as_slice()[..copy_size]); .copy_from_slice(&self.memory.as_slice()[..copy_size]);
} }
self.mmap = new_mmap; self.memory = new_memory;
} }
self.current = new_pages; self.current = new_pages;
@ -197,8 +200,8 @@ impl LinearMemory {
let new_bytes = (new_pages * Self::PAGE_SIZE) as usize; let new_bytes = (new_pages * Self::PAGE_SIZE) as usize;
unsafe { unsafe {
self.mmap self.memory
.protect(prev_bytes..new_bytes, Protect::ReadWrite) .protect(prev_bytes..new_bytes, sys::Protect::ReadWrite)
.ok()?; .ok()?;
} }
@ -211,12 +214,12 @@ impl LinearMemory {
impl Deref for LinearMemory { impl Deref for LinearMemory {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &[u8] { fn deref(&self) -> &[u8] {
unsafe { self.mmap.as_slice() } unsafe { self.memory.as_slice() }
} }
} }
impl DerefMut for LinearMemory { impl DerefMut for LinearMemory {
fn deref_mut(&mut self) -> &mut [u8] { fn deref_mut(&mut self) -> &mut [u8] {
unsafe { self.mmap.as_slice_mut() } unsafe { self.memory.as_slice_mut() }
} }
} }

View File

@ -0,0 +1,11 @@
#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;
#[cfg(unix)]
pub use self::unix::*;
#[cfg(windows)]
pub use self::windows::*;

View File

@ -5,12 +5,12 @@ use std::ops::Range;
use std::{ptr, slice}; use std::{ptr, slice};
#[derive(Debug)] #[derive(Debug)]
pub struct Mmap { pub struct Memory {
ptr: *mut u8, ptr: *mut u8,
size: usize, size: usize,
} }
impl Mmap { impl Memory {
pub fn with_size(size: usize) -> Result<Self, String> { pub fn with_size(size: usize) -> Result<Self, String> {
if size == 0 { if size == 0 {
return Ok(Self { return Ok(Self {
@ -43,6 +43,7 @@ impl Mmap {
} }
pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> { pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> {
let protect = protect.to_protect_const();
let page_size = page_size::get(); let page_size = page_size::get();
let start = self let start = self
.ptr .ptr
@ -75,7 +76,7 @@ impl Mmap {
} }
} }
impl Drop for Mmap { impl Drop for Memory {
fn drop(&mut self) { fn drop(&mut self) {
if !self.ptr.is_null() { if !self.ptr.is_null() {
let success = unsafe { libc::munmap(self.ptr as _, self.size) }; let success = unsafe { libc::munmap(self.ptr as _, self.size) };
@ -87,12 +88,21 @@ impl Drop for Mmap {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(dead_code)] #[allow(dead_code)]
pub enum Protect { pub enum Protect {
None = 0, None,
Read = 1, Read,
Write = 2, ReadWrite,
ReadWrite = 1 | 2, ReadExec,
Exec = 4, }
ReadExec = 1 | 4,
impl Protect {
fn to_protect_const(self) -> u32 {
match self {
Protect::None => 0,
Protect::Read => 1,
Protect::ReadWrite => 1 | 2,
Protect::ReadExec => 1 | 4,
}
}
} }
/// Round `size` up to the nearest multiple of `page_size`. /// Round `size` up to the nearest multiple of `page_size`.

View File

@ -0,0 +1,3 @@
mod memory;
pub use self::memory::{Memory, Protect};

View File

@ -0,0 +1,124 @@
use winapi::um::memoryapi::{
VirtualAlloc,
MEM_RESERVE, MEM_COMMIT,
PAGE_NOACCESS, PAGE_EXECUTE_READ, PAGE_READWRITE, PAGE_READONLY,
};
use page_size;
use std::ops::Range;
use std::{ptr, slice};
#[derive(Debug)]
pub struct Memory {
ptr: *mut u8,
size: usize,
}
impl Memory {
pub fn with_size(size: usize) -> Result<Self, String> {
if size == 0 {
return Ok(Self {
ptr: ptr::null_mut(),
size: 0,
});
}
let size = round_up_to_page_size(size, page_size::get());
let ptr = unsafe {
VirtualAlloc(
ptr::null_mut(),
size,
MEM_RESERVE,
PAGE_NOACCESS,
)
};
if ptr.is_null() {
Err("unable to allocate memory")
} else {
Ok(Self {
ptr: ptr as *mut u8,
size,
})
}
}
pub unsafe fn protect(&mut self, range: Range<usize>, protect: Protect) -> Result<(), String> {
let protect = protect.to_protect_const();
let page_size = page_size::get();
let start = self
.ptr
.add(round_down_to_page_size(range.start, page_size));
let size = round_up_to_page_size(range.end - range.start, page_size);
assert!(size <= self.size);
// Commit the virtual memory.
let ptr = VirtualAlloc(
start as _,
size,
MEM_COMMIT,
protect,
);
if ptr.is_null() {
Err("unable to protect memory")
} else {
Ok(())
}
}
pub fn size(&self) -> usize {
self.size
}
pub unsafe fn as_slice(&self) -> &[u8] {
slice::from_raw_parts(self.ptr, self.size)
}
pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.ptr, self.size)
}
pub fn as_ptr(&self) -> *mut u8 {
self.ptr
}
}
impl Drop for Memory {
fn drop(&mut self) {
if !self.ptr.is_null() {
let success = unsafe { libc::munmap(self.ptr as _, self.size) };
assert_eq!(success, 0, "failed to unmap memory: {}", errno::errno());
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Protect {
None,
Read,
ReadWrite,
ReadExec,
}
impl Protect {
fn to_protect_const(self) -> u32 {
match self {
Protect::None => PAGE_NOACCESS,
Protect::Read => PAGE_READONLY,
Protect::ReadWrite => PAGE_READWRITE,
Protect::ReadExec => PAGE_EXECUTE_READ,
}
}
}
/// Round `size` up to the nearest multiple of `page_size`.
fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
(size + (page_size - 1)) & !(page_size - 1)
}
/// Round `size` down to the nearest multiple of `page_size`.
fn round_down_to_page_size(size: usize, page_size: usize) -> usize {
size & !(page_size - 1)
}

View File

@ -0,0 +1 @@
pub use self::memory::{Memory, Protect};

View File

@ -572,8 +572,8 @@ mod vm_ctx_tests {
impl FuncResolver for Placeholder { impl FuncResolver for Placeholder {
fn get( fn get(
&self, &self,
module: &ModuleInner, _module: &ModuleInner,
local_func_index: LocalFuncIndex, _local_func_index: LocalFuncIndex,
) -> Option<NonNull<Func>> { ) -> Option<NonNull<Func>> {
None None
} }