we can handle one layer of pointers!
This commit is contained in:
@@ -111,21 +111,25 @@ fn marshal_arg(
|
||||
let interface_typename = names.type_ref(&tref);
|
||||
let name = names.func_param(¶m.name);
|
||||
|
||||
let value_error_handling = if let Some(tref) = error_type {
|
||||
let abi_ret = match tref.type_().passed_by() {
|
||||
witx::TypePassedBy::Value(atom) => names.atom_type(atom),
|
||||
_ => unreachable!("err should always be passed by value"),
|
||||
};
|
||||
let err_typename = names.type_ref(&tref);
|
||||
quote! {
|
||||
let err: #err_typename = ::memory::GuestError::from_value_error(e, ctx);
|
||||
return #abi_ret::from(err);
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
panic!("memory error: {:?}", e)
|
||||
let error_handling = |method| -> TokenStream {
|
||||
if let Some(tref) = error_type {
|
||||
let abi_ret = match tref.type_().passed_by() {
|
||||
witx::TypePassedBy::Value(atom) => names.atom_type(atom),
|
||||
_ => unreachable!("err should always be passed by value"),
|
||||
};
|
||||
let err_typename = names.type_ref(&tref);
|
||||
quote! {
|
||||
let err: #err_typename = ::memory::GuestError::#method(e, ctx);
|
||||
return #abi_ret::from(err);
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
panic!("error: {:?}", e)
|
||||
}
|
||||
}
|
||||
};
|
||||
let value_error_handling = error_handling(quote!(from_value_error));
|
||||
let memory_error_handling = error_handling(quote!(from_memory_error));
|
||||
|
||||
let try_into_conversion = quote! {
|
||||
use ::std::convert::TryInto;
|
||||
@@ -162,6 +166,28 @@ fn marshal_arg(
|
||||
},
|
||||
witx::BuiltinType::String => unimplemented!("string types unimplemented"),
|
||||
},
|
||||
_ => unimplemented!("only enums and builtins so far"),
|
||||
witx::Type::Pointer(pointee) => {
|
||||
let pointee_type = names.type_ref(pointee);
|
||||
quote! {
|
||||
let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
#memory_error_handling
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
witx::Type::ConstPointer(pointee) => {
|
||||
let pointee_type = names.type_ref(pointee);
|
||||
quote! {
|
||||
let #name = match memory.ptr::<#pointee_type>(#name as u32) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
#memory_error_handling
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("argument type marshalling"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ impl Names {
|
||||
}
|
||||
TypeRef::Value(ty) => match &**ty {
|
||||
witx::Type::Builtin(builtin) => self.builtin_type(*builtin),
|
||||
witx::Type::Pointer(pointee) => {
|
||||
let pointee_type = self.type_ref(&pointee);
|
||||
quote!(::memory::GuestPtrMut<#pointee_type>)
|
||||
}
|
||||
witx::Type::ConstPointer(pointee) => {
|
||||
let pointee_type = self.type_ref(&pointee);
|
||||
quote!(::memory::GuestPtr<#pointee_type>)
|
||||
}
|
||||
_ => unimplemented!("anonymous type ref"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -95,12 +95,12 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
|
||||
}
|
||||
|
||||
impl ::memory::GuestTypeCopy for #ident {
|
||||
fn read_val(src: ::memory::GuestPtr<#ident>) -> Result<#ident, ::memory::GuestValueError> {
|
||||
fn read_val<P: ::memory::GuestPtrRead<#ident>>(src: &P) -> Result<#ident, ::memory::GuestValueError> {
|
||||
use ::std::convert::TryInto;
|
||||
let val = unsafe { ::std::ptr::read_unaligned(src.ptr() as *const #repr) };
|
||||
val.try_into()
|
||||
}
|
||||
fn write_val(val: #ident, dest: ::memory::GuestPtrMut<#ident>) {
|
||||
fn write_val(val: #ident, dest: &::memory::GuestPtrMut<#ident>) {
|
||||
let val: #repr = val.into();
|
||||
unsafe {
|
||||
::std::ptr::write_unaligned(dest.ptr_mut() as *mut #repr, val)
|
||||
|
||||
@@ -1,59 +1,66 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::region::Region;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct BorrowHandle(usize);
|
||||
|
||||
pub struct GuestBorrows {
|
||||
immutable: Vec<Region>,
|
||||
mutable: Vec<Region>,
|
||||
immutable: HashMap<BorrowHandle, Region>,
|
||||
mutable: HashMap<BorrowHandle, Region>,
|
||||
next_handle: BorrowHandle,
|
||||
}
|
||||
|
||||
impl GuestBorrows {
|
||||
pub fn new() -> Self {
|
||||
GuestBorrows {
|
||||
immutable: Vec::new(),
|
||||
mutable: Vec::new(),
|
||||
immutable: HashMap::new(),
|
||||
mutable: HashMap::new(),
|
||||
next_handle: BorrowHandle(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_borrowed_immut(&self, r: Region) -> bool {
|
||||
!self.immutable.iter().all(|b| !b.overlaps(r))
|
||||
!self.immutable.values().all(|b| !b.overlaps(r))
|
||||
}
|
||||
|
||||
fn is_borrowed_mut(&self, r: Region) -> bool {
|
||||
!self.mutable.iter().all(|b| !b.overlaps(r))
|
||||
!self.mutable.values().all(|b| !b.overlaps(r))
|
||||
}
|
||||
|
||||
pub fn borrow_immut(&mut self, r: Region) -> bool {
|
||||
fn new_handle(&mut self) -> BorrowHandle {
|
||||
let h = self.next_handle;
|
||||
self.next_handle = BorrowHandle(h.0 + 1);
|
||||
h
|
||||
}
|
||||
|
||||
pub fn borrow_immut(&mut self, r: Region) -> Option<BorrowHandle> {
|
||||
if self.is_borrowed_mut(r) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
self.immutable.push(r);
|
||||
true
|
||||
let h = self.new_handle();
|
||||
self.immutable.insert(h, r);
|
||||
Some(h)
|
||||
}
|
||||
|
||||
pub fn unborrow_immut(&mut self, r: Region) {
|
||||
let (ix, _) = self
|
||||
.immutable
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, reg)| r == **reg)
|
||||
.expect("region exists in borrows");
|
||||
self.immutable.remove(ix);
|
||||
pub fn unborrow_immut(&mut self, h: BorrowHandle) {
|
||||
self.immutable
|
||||
.remove(&h)
|
||||
.expect("handle exists in immutable borrows");
|
||||
}
|
||||
|
||||
pub fn borrow_mut(&mut self, r: Region) -> bool {
|
||||
pub fn borrow_mut(&mut self, r: Region) -> Option<BorrowHandle> {
|
||||
if self.is_borrowed_immut(r) || self.is_borrowed_mut(r) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
self.mutable.push(r);
|
||||
true
|
||||
let h = self.new_handle();
|
||||
self.mutable.insert(h, r);
|
||||
Some(h)
|
||||
}
|
||||
|
||||
pub fn unborrow_mut(&mut self, r: Region) {
|
||||
let (ix, _) = self
|
||||
.mutable
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, reg)| r == **reg)
|
||||
.expect("region exists in borrows");
|
||||
self.mutable.remove(ix);
|
||||
pub fn unborrow_mut(&mut self, h: BorrowHandle) {
|
||||
self.mutable
|
||||
.remove(&h)
|
||||
.expect("handle exists in mutable borrows");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{GuestPtr, GuestPtrMut, MemoryError};
|
||||
use crate::{GuestPtrMut, GuestPtrRead, MemoryError};
|
||||
use thiserror::Error;
|
||||
|
||||
pub trait GuestType: Sized {
|
||||
@@ -13,25 +13,25 @@ pub enum GuestValueError {
|
||||
}
|
||||
|
||||
pub trait GuestTypeCopy: GuestType + Copy {
|
||||
fn read_val(src: GuestPtr<Self>) -> Result<Self, GuestValueError>;
|
||||
fn write_val(val: Self, dest: GuestPtrMut<Self>);
|
||||
fn read_val<P: GuestPtrRead<Self>>(src: &P) -> Result<Self, GuestValueError>;
|
||||
fn write_val(val: Self, dest: &GuestPtrMut<Self>);
|
||||
}
|
||||
|
||||
pub trait GuestTypeClone: GuestType + Clone {
|
||||
fn read_ref(src: GuestPtr<Self>, dest: &mut Self) -> Result<(), GuestValueError>;
|
||||
fn write_ref(val: &Self, dest: GuestPtrMut<Self>);
|
||||
fn read_ref<P: GuestPtrRead<Self>>(src: &P, dest: &mut Self) -> Result<(), GuestValueError>;
|
||||
fn write_ref(val: &Self, dest: &GuestPtrMut<Self>);
|
||||
}
|
||||
|
||||
impl<T> GuestTypeClone for T
|
||||
where
|
||||
T: GuestTypeCopy,
|
||||
{
|
||||
fn read_ref(src: GuestPtr<T>, dest: &mut T) -> Result<(), GuestValueError> {
|
||||
fn read_ref<P: GuestPtrRead<Self>>(src: &P, dest: &mut T) -> Result<(), GuestValueError> {
|
||||
let val = GuestTypeCopy::read_val(src)?;
|
||||
*dest = val;
|
||||
Ok(())
|
||||
}
|
||||
fn write_ref(val: &T, dest: GuestPtrMut<T>) {
|
||||
fn write_ref(val: &T, dest: &GuestPtrMut<T>) {
|
||||
GuestTypeCopy::write_val(*val, dest)
|
||||
}
|
||||
}
|
||||
@@ -49,12 +49,12 @@ macro_rules! builtin_copy {
|
||||
}
|
||||
|
||||
impl GuestTypeCopy for $t {
|
||||
fn read_val(src: GuestPtr<$t>) -> Result<$t, GuestValueError> {
|
||||
fn read_val<P: GuestPtrRead<$t>>(src: &P) -> Result<$t, GuestValueError> {
|
||||
Ok(unsafe {
|
||||
::std::ptr::read_unaligned(src.ptr() as *const $t)
|
||||
})
|
||||
}
|
||||
fn write_val(val: $t, dest: GuestPtrMut<$t>) {
|
||||
fn write_val(val: $t, dest: &GuestPtrMut<$t>) {
|
||||
unsafe {
|
||||
::std::ptr::write_unaligned(dest.ptr_mut() as *mut $t, val)
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ mod memory;
|
||||
mod region;
|
||||
|
||||
pub use guest_type::{GuestError, GuestType, GuestTypeClone, GuestTypeCopy, GuestValueError};
|
||||
pub use memory::{GuestMemory, GuestPtr, GuestPtrMut, MemoryError};
|
||||
pub use memory::{GuestMemory, GuestPtr, GuestPtrMut, GuestPtrRead, MemoryError};
|
||||
pub use region::Region;
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::borrow::GuestBorrows;
|
||||
use crate::borrow::{BorrowHandle, GuestBorrows};
|
||||
use crate::guest_type::GuestType;
|
||||
use crate::region::Region;
|
||||
|
||||
@@ -31,80 +31,85 @@ impl<'a> GuestMemory<'a> {
|
||||
}
|
||||
|
||||
pub fn ptr<T: GuestType>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, MemoryError> {
|
||||
let r = Region {
|
||||
let region = Region {
|
||||
start: at,
|
||||
len: T::size(),
|
||||
};
|
||||
let mut borrows = self.borrows.borrow_mut();
|
||||
if !self.contains(r) {
|
||||
Err(MemoryError::OutOfBounds(r))?;
|
||||
if !self.contains(region) {
|
||||
Err(MemoryError::OutOfBounds(region))?;
|
||||
}
|
||||
if borrows.borrow_immut(r) {
|
||||
let mut borrows = self.borrows.borrow_mut();
|
||||
if let Some(handle) = borrows.borrow_immut(region) {
|
||||
Ok(GuestPtr {
|
||||
mem: &self,
|
||||
region: r,
|
||||
region,
|
||||
handle,
|
||||
type_: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(MemoryError::Borrowed(r))
|
||||
Err(MemoryError::Borrowed(region))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptr_mut<T: GuestType>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, MemoryError> {
|
||||
let r = Region {
|
||||
let region = Region {
|
||||
start: at,
|
||||
len: T::size(),
|
||||
};
|
||||
let mut borrows = self.borrows.borrow_mut();
|
||||
if !self.contains(r) {
|
||||
Err(MemoryError::OutOfBounds(r))?;
|
||||
if !self.contains(region) {
|
||||
Err(MemoryError::OutOfBounds(region))?;
|
||||
}
|
||||
if borrows.borrow_mut(r) {
|
||||
let mut borrows = self.borrows.borrow_mut();
|
||||
if let Some(handle) = borrows.borrow_mut(region) {
|
||||
Ok(GuestPtrMut {
|
||||
mem: &self,
|
||||
region: r,
|
||||
region,
|
||||
handle,
|
||||
type_: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(MemoryError::Borrowed(r))
|
||||
Err(MemoryError::Borrowed(region))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GuestPtrRead<T> {
|
||||
fn ptr(&self) -> *const u8;
|
||||
}
|
||||
|
||||
pub struct GuestPtr<'a, T> {
|
||||
mem: &'a GuestMemory<'a>,
|
||||
region: Region,
|
||||
handle: BorrowHandle,
|
||||
type_: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: GuestType> GuestPtr<'a, T> {
|
||||
pub fn ptr(&self) -> *const u8 {
|
||||
impl<'a, T: GuestType> GuestPtrRead<T> for GuestPtr<'a, T> {
|
||||
fn ptr(&self) -> *const u8 {
|
||||
(self.mem.ptr as usize + self.region.start as usize) as *const u8
|
||||
}
|
||||
|
||||
pub unsafe fn downcast<Q: GuestType>(self) -> GuestPtr<'a, Q> {
|
||||
debug_assert!(T::size() == Q::size(), "downcast to type of same size");
|
||||
GuestPtr {
|
||||
mem: self.mem,
|
||||
region: self.region,
|
||||
type_: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for GuestPtr<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let mut borrows = self.mem.borrows.borrow_mut();
|
||||
borrows.unborrow_immut(self.region);
|
||||
borrows.unborrow_immut(self.handle);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GuestPtrMut<'a, T> {
|
||||
mem: &'a GuestMemory<'a>,
|
||||
region: Region,
|
||||
handle: BorrowHandle,
|
||||
type_: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: GuestType> GuestPtrRead<T> for GuestPtrMut<'a, T> {
|
||||
fn ptr(&self) -> *const u8 {
|
||||
(self.mem.ptr as usize + self.region.start as usize) as *const u8
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> GuestPtrMut<'a, T> {
|
||||
pub fn ptr_mut(&self) -> *mut u8 {
|
||||
(self.mem.ptr as usize + self.region.start as usize) as *mut u8
|
||||
@@ -113,7 +118,7 @@ impl<'a, T> GuestPtrMut<'a, T> {
|
||||
impl<'a, T> Drop for GuestPtrMut<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let mut borrows = self.mem.borrows.borrow_mut();
|
||||
borrows.unborrow_mut(self.region);
|
||||
borrows.unborrow_mut(self.handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user