mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-21 20:51:32 +00:00
add wasmptr memory abstraction to emscripten; update wasi array access
This commit is contained in:
@ -42,6 +42,7 @@ mod lock;
|
||||
mod math;
|
||||
mod memory;
|
||||
mod process;
|
||||
mod ptr;
|
||||
mod signal;
|
||||
mod storage;
|
||||
mod syscalls;
|
||||
|
119
lib/emscripten/src/ptr.rs
Normal file
119
lib/emscripten/src/ptr.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
||||
use wasmer_runtime_core::{
|
||||
memory::Memory,
|
||||
types::{ValueType, WasmExternType},
|
||||
};
|
||||
|
||||
pub struct Array;
|
||||
pub struct Item;
|
||||
|
||||
// TODO: before shipping, refactor this and the wasi code into a common crate
|
||||
// and wrap it when used in the context of wasi to return the proper error codes
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct WasmPtr<T: Copy, Ty = Item> {
|
||||
offset: u32,
|
||||
_phantom: PhantomData<(T, Ty)>,
|
||||
}
|
||||
|
||||
impl<T: Copy, Ty> WasmPtr<T, Ty> {
|
||||
#[inline]
|
||||
pub fn new(offset: u32) -> Self {
|
||||
Self {
|
||||
offset,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(self) -> i32 {
|
||||
self.offset as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn align_pointer(ptr: usize, align: usize) -> usize {
|
||||
// clears bits below aligment amount (assumes power of 2) to align pointer
|
||||
debug_assert!(align.count_ones() == 1);
|
||||
ptr & !(align - 1)
|
||||
}
|
||||
|
||||
impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||
#[inline]
|
||||
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
|
||||
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
||||
return None;
|
||||
}
|
||||
unsafe {
|
||||
let cell_ptr = align_pointer(
|
||||
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
|
||||
mem::align_of::<T>(),
|
||||
) as *const Cell<T>;
|
||||
Some(&*cell_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
||||
#[inline]
|
||||
pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell<T>]> {
|
||||
if (self.offset as usize) + (mem::size_of::<T>() * ((index + length) as usize))
|
||||
>= memory.size().bytes().0
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
// gets the size of the item in the array with padding added such that
|
||||
// for any index, we will always result an aligned memory access
|
||||
let item_size = mem::size_of::<T>() + (mem::size_of::<T>() % mem::align_of::<T>());
|
||||
let base_idx = (self.offset as usize) / item_size;
|
||||
unsafe {
|
||||
let cell_ptrs = memory
|
||||
.view::<T>()
|
||||
.get_unchecked(base_idx + (index as usize)..base_idx + ((index + length) as usize))
|
||||
as *const _;
|
||||
Some(&*cell_ptrs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Copy, Ty> WasmExternType for WasmPtr<T, Ty> {
|
||||
type Native = i32;
|
||||
|
||||
fn to_native(self) -> Self::Native {
|
||||
self.offset as i32
|
||||
}
|
||||
fn from_native(n: Self::Native) -> Self {
|
||||
Self {
|
||||
offset: n as u32,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Copy, Ty> ValueType for WasmPtr<T, Ty> {}
|
||||
|
||||
impl<T: Copy, Ty> Clone for WasmPtr<T, Ty> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
offset: self.offset,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, Ty> Copy for WasmPtr<T, Ty> {}
|
||||
|
||||
impl<T: Copy, Ty> PartialEq for WasmPtr<T, Ty> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.offset == other.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, Ty> Eq for WasmPtr<T, Ty> {}
|
||||
|
||||
impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "WasmPtr({:#x})", self.offset)
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ pub use self::unix::*;
|
||||
#[cfg(windows)]
|
||||
pub use self::windows::*;
|
||||
|
||||
use crate::ptr::{Array, WasmPtr};
|
||||
use crate::utils::{copy_stat_into_wasm, get_cstr_path, get_current_directory};
|
||||
|
||||
use super::varargs::VarArgs;
|
||||
@ -77,7 +78,7 @@ pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 {
|
||||
pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int {
|
||||
debug!("emscripten::___syscall4 (write) {}", _which);
|
||||
let fd: i32 = varargs.get(ctx);
|
||||
let buf: u32 = varargs.get(ctx);
|
||||
let buf: i32 = varargs.get(ctx);
|
||||
let count: i32 = varargs.get(ctx);
|
||||
debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count);
|
||||
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void;
|
||||
@ -270,21 +271,18 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
|
||||
// getcwd
|
||||
pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
|
||||
debug!("emscripten::___syscall183");
|
||||
let buf_offset: c_int = varargs.get(ctx);
|
||||
let buf_offset: WasmPtr<libc::c_char, Array> = varargs.get(ctx);
|
||||
let _size: c_int = varargs.get(ctx);
|
||||
let path = get_current_directory(ctx);
|
||||
let path_string = path.unwrap().display().to_string();
|
||||
let len = path_string.len();
|
||||
unsafe {
|
||||
let pointer_to_buffer =
|
||||
emscripten_memory_pointer!(ctx.memory(0), buf_offset) as *mut libc::c_char;
|
||||
let slice = slice::from_raw_parts_mut(pointer_to_buffer, len.clone());
|
||||
for (byte, loc) in path_string.bytes().zip(slice.iter_mut()) {
|
||||
*loc = byte as _;
|
||||
|
||||
let buf_writer = buf_offset.deref(ctx.memory(0), 0, len as u32 + 1).unwrap();
|
||||
for (i, byte) in path_string.bytes().enumerate() {
|
||||
buf_writer[i].set(byte as i8);
|
||||
}
|
||||
*pointer_to_buffer.add(len.clone()) = 0;
|
||||
}
|
||||
buf_offset
|
||||
buf_writer[len].set(0);
|
||||
buf_offset.offset()
|
||||
}
|
||||
|
||||
// mmap2
|
||||
|
@ -29,6 +29,13 @@ impl<T: Copy, Ty> WasmPtr<T, Ty> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn align_pointer(ptr: usize, align: usize) -> usize {
|
||||
// clears bits below aligment amount (assumes power of 2) to align pointer
|
||||
debug_assert!(align.count_ones() == 1);
|
||||
ptr & !(align - 1)
|
||||
}
|
||||
|
||||
impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||
#[inline]
|
||||
pub fn deref<'a>(self, memory: &'a Memory) -> Result<&'a Cell<T>, __wasi_errno_t> {
|
||||
@ -36,9 +43,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||
return Err(__WASI_EFAULT);
|
||||
}
|
||||
unsafe {
|
||||
// clears bits below aligment amount (assumes power of 2) to align pointer
|
||||
let aligner = |ptr: usize, align: usize| ptr & !(align - 1);
|
||||
let cell_ptr = aligner(
|
||||
let cell_ptr = align_pointer(
|
||||
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
|
||||
mem::align_of::<T>(),
|
||||
) as *const Cell<T>;
|
||||
@ -61,12 +66,15 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
||||
return Err(__WASI_EFAULT);
|
||||
}
|
||||
|
||||
// gets the size of the item in the array with padding added such that
|
||||
// for any index, we will always result an aligned memory access
|
||||
let item_size = mem::size_of::<T>() + (mem::size_of::<T>() % mem::align_of::<T>());
|
||||
let base_idx = (self.offset as usize) / item_size;
|
||||
unsafe {
|
||||
let cell_ptrs = memory.view::<T>().get_unchecked(
|
||||
((self.offset as usize) / mem::size_of::<T>()) + (index as usize)
|
||||
..((self.offset() as usize) / mem::size_of::<T>())
|
||||
+ ((index + length) as usize),
|
||||
) as *const _;
|
||||
let cell_ptrs = memory
|
||||
.view::<T>()
|
||||
.get_unchecked(base_idx + (index as usize)..base_idx + ((index + length) as usize))
|
||||
as *const _;
|
||||
Ok(&*cell_ptrs)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user