i think the memory model is fixed now? at least until arrays....

This commit is contained in:
Pat Hickey
2020-01-27 20:21:53 -08:00
parent ec456e9e50
commit c780421c28
5 changed files with 105 additions and 53 deletions

View File

@@ -105,12 +105,16 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
impl ::memory::GuestTypeCopy for #ident {} impl ::memory::GuestTypeCopy for #ident {}
impl ::memory::GuestTypeClone for #ident { impl ::memory::GuestTypeClone for #ident {
fn from_guest(location: &::memory::GuestPtr<#ident>) -> Result<#ident, ::memory::GuestError> { fn read_from_guest(location: &::memory::GuestPtr<#ident>) -> Result<#ident, ::memory::GuestError> {
use ::std::convert::TryFrom; use ::std::convert::TryFrom;
let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() };
let val = #ident::try_from(raw)?; let val = #ident::try_from(raw)?;
Ok(val) Ok(val)
} }
fn write_to_guest(&self, location: &::memory::GuestPtrMut<#ident>) {
let val: #repr = #repr::from(*self);
unsafe { (location.as_raw() as *mut #repr).write(val) };
}
} }
} }

View File

@@ -1,4 +1,4 @@
use crate::{GuestError, GuestPtr}; use crate::{GuestError, GuestPtr, GuestPtrMut};
pub trait GuestType: Sized { pub trait GuestType: Sized {
// These are morally the same as Rust ::std::mem::size_of / align_of, but they return // These are morally the same as Rust ::std::mem::size_of / align_of, but they return
@@ -12,11 +12,12 @@ pub trait GuestType: Sized {
pub trait GuestTypeCopy: GuestType + Copy {} pub trait GuestTypeCopy: GuestType + Copy {}
pub trait GuestTypeClone: GuestType + Clone { pub trait GuestTypeClone: GuestType + Clone {
fn from_guest<'a>(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError>; fn read_from_guest<'a>(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError>;
fn write_to_guest<'a>(&self, location: &GuestPtrMut<'a, Self>);
} }
pub trait GuestTypeRef<'a>: GuestType { pub trait GuestTypePtr<'a>: GuestType {
type Ref; fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError>;
fn from_guest(location: &GuestPtr<'a, Self>) -> Result<Self::Ref, GuestError>; fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>);
} }
macro_rules! builtin_type { macro_rules! builtin_type {

View File

@@ -5,6 +5,6 @@ mod memory;
mod region; mod region;
pub use error::GuestError; pub use error::GuestError;
pub use guest_type::{GuestErrorType, GuestType, GuestTypeClone, GuestTypeCopy, GuestTypeRef}; pub use guest_type::{GuestErrorType, GuestType, GuestTypeClone, GuestTypeCopy, GuestTypePtr};
pub use memory::{GuestMemory, GuestPtr, GuestPtrMut, GuestRef, GuestRefMut}; pub use memory::{GuestMemory, GuestPtr, GuestPtrMut, GuestRef, GuestRefMut};
pub use region::Region; pub use region::Region;

View File

@@ -3,7 +3,7 @@ use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
use crate::borrow::{BorrowHandle, GuestBorrows}; use crate::borrow::{BorrowHandle, GuestBorrows};
use crate::{GuestError, GuestType, GuestTypeCopy, GuestTypeRef, Region}; use crate::{GuestError, GuestType, GuestTypeClone, GuestTypeCopy, GuestTypePtr, Region};
pub struct GuestMemory<'a> { pub struct GuestMemory<'a> {
ptr: *mut u8, ptr: *mut u8,
@@ -67,6 +67,9 @@ impl<'a, T: GuestType> GuestPtr<'a, T> {
pub fn as_raw(&self) -> *const u8 { pub fn as_raw(&self) -> *const u8 {
(self.mem.ptr as usize + self.region.start as usize) as *const u8 (self.mem.ptr as usize + self.region.start as usize) as *const u8
} }
}
impl<'a, T: GuestTypeCopy> GuestPtr<'a, T> {
pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> { pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> {
T::validate(&self)?; T::validate(&self)?;
let handle = { let handle = {
@@ -84,6 +87,18 @@ impl<'a, T: GuestType> GuestPtr<'a, T> {
} }
} }
impl<'a, T: GuestTypeClone> GuestPtr<'a, T> {
pub fn clone_from_guest(&self) -> Result<T, GuestError> {
T::read_from_guest(self)
}
}
impl<'a, T: GuestTypePtr<'a>> GuestPtr<'a, T> {
pub fn read_ptr_from_guest(&self) -> Result<T, GuestError> {
T::read_from_guest(self)
}
}
impl<'a, T> GuestType for GuestPtr<'a, T> impl<'a, T> GuestType for GuestPtr<'a, T>
where where
T: GuestType, T: GuestType,
@@ -106,17 +121,24 @@ where
} }
} }
impl<'a, T> GuestTypeRef<'a> for GuestPtr<'a, T> // Operations for reading and writing Ptrs to memory:
impl<'a, T> GuestTypePtr<'a> for GuestPtr<'a, T>
where where
T: GuestType, T: GuestType,
{ {
type Ref = GuestRef<'a, T>; fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
fn from_guest(location: &GuestPtr<'a, Self>) -> Result<Self::Ref, GuestError> {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) };
// GuestMemory can validate that the raw pointer contents are legal for T: // GuestMemory can validate that the raw pointer contents are legal for T:
let guest_ptr: GuestPtr<'a, T> = location.mem.ptr(raw_ptr)?; let guest_ptr: GuestPtr<'a, T> = location.mem.ptr(raw_ptr)?;
Ok(guest_ptr.as_ref()?) Ok(guest_ptr)
}
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>) {
// location is guaranteed to be in GuestMemory and aligned to 4
unsafe {
let raw_ptr: *mut u32 = location.as_raw() as *mut u32;
raw_ptr.write(self.region.start);
}
} }
} }
@@ -139,7 +161,9 @@ impl<'a, T: GuestType> GuestPtrMut<'a, T> {
pub fn as_raw(&self) -> *const u8 { pub fn as_raw(&self) -> *const u8 {
self.as_immut().as_raw() self.as_immut().as_raw()
} }
}
impl<'a, T: GuestTypeCopy> GuestPtrMut<'a, T> {
pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> { pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> {
self.as_immut().as_ref() self.as_immut().as_ref()
} }
@@ -161,6 +185,25 @@ impl<'a, T: GuestType> GuestPtrMut<'a, T> {
} }
} }
impl<'a, T: GuestTypePtr<'a>> GuestPtrMut<'a, T> {
pub fn read_ptr_from_guest(&self) -> Result<T, GuestError> {
T::read_from_guest(&self.as_immut())
}
pub fn write_ptr_to_guest(&self, ptr: &T) {
T::write_to_guest(ptr, &self);
}
}
impl<'a, T: GuestTypeClone> GuestPtrMut<'a, T> {
pub fn clone_from_guest(&self) -> Result<T, GuestError> {
T::read_from_guest(&self.as_immut())
}
pub fn clone_to_guest(&self, val: &T) {
T::write_to_guest(val, &self)
}
}
impl<'a, T> GuestType for GuestPtrMut<'a, T> impl<'a, T> GuestType for GuestPtrMut<'a, T>
where where
T: GuestType, T: GuestType,
@@ -183,17 +226,24 @@ where
} }
} }
impl<'a, T> GuestTypeRef<'a> for GuestPtrMut<'a, T> // Reading and writing GuestPtrMuts to memory:
impl<'a, T> GuestTypePtr<'a> for GuestPtrMut<'a, T>
where where
T: GuestType, T: GuestType,
{ {
type Ref = GuestRefMut<'a, T>; fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
fn from_guest(location: &GuestPtr<'a, Self>) -> Result<Self::Ref, GuestError> {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) };
// GuestMemory can validate that the raw pointer contents are legal for T: // GuestMemory can validate that the raw pointer contents are legal for T:
let guest_ptr_mut: GuestPtrMut<'a, T> = location.mem.ptr_mut(raw_ptr)?; let guest_ptr_mut: GuestPtrMut<'a, T> = location.mem.ptr_mut(raw_ptr)?;
Ok(guest_ptr_mut.as_ref_mut()?) Ok(guest_ptr_mut)
}
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>) {
// location is guaranteed to be in GuestMemory and aligned to 4
unsafe {
let raw_ptr: *mut u32 = location.as_raw() as *mut u32;
raw_ptr.write(self.region.start);
}
} }
} }
@@ -204,6 +254,16 @@ pub struct GuestRef<'a, T> {
type_: PhantomData<T>, type_: PhantomData<T>,
} }
impl<'a, T> GuestRef<'a, T> {
pub fn as_ptr(&self) -> GuestPtr<'a, T> {
GuestPtr {
mem: self.mem,
region: self.region,
type_: self.type_,
}
}
}
impl<'a, T> ::std::ops::Deref for GuestRef<'a, T> impl<'a, T> ::std::ops::Deref for GuestRef<'a, T>
where where
T: GuestTypeCopy, T: GuestTypeCopy,
@@ -218,20 +278,6 @@ where
} }
} }
impl<'a, T> GuestRef<'a, T>
where
T: GuestTypeRef<'a>,
{
pub fn from_guest(&self) -> Result<T::Ref, GuestError> {
let ptr = GuestPtr {
mem: self.mem,
region: self.region,
type_: self.type_,
};
GuestTypeRef::from_guest(&ptr)
}
}
impl<'a, T> Drop for GuestRef<'a, T> { impl<'a, T> Drop for GuestRef<'a, T> {
fn drop(&mut self) { fn drop(&mut self) {
let mut borrows = self.mem.borrows.borrow_mut(); let mut borrows = self.mem.borrows.borrow_mut();
@@ -246,6 +292,23 @@ pub struct GuestRefMut<'a, T> {
type_: PhantomData<T>, type_: PhantomData<T>,
} }
impl<'a, T> GuestRefMut<'a, T> {
pub fn as_ptr(&self) -> GuestPtr<'a, T> {
GuestPtr {
mem: self.mem,
region: self.region,
type_: self.type_,
}
}
pub fn as_ptr_mut(&self) -> GuestPtrMut<'a, T> {
GuestPtrMut {
mem: self.mem,
region: self.region,
type_: self.type_,
}
}
}
impl<'a, T> ::std::ops::Deref for GuestRefMut<'a, T> impl<'a, T> ::std::ops::Deref for GuestRefMut<'a, T>
where where
T: GuestTypeCopy, T: GuestTypeCopy,
@@ -273,20 +336,6 @@ where
} }
} }
impl<'a, T> GuestRefMut<'a, T>
where
T: GuestTypeRef<'a>,
{
pub fn from_guest(&self) -> Result<T::Ref, GuestError> {
let ptr = GuestPtr {
mem: self.mem,
region: self.region,
type_: self.type_,
};
GuestTypeRef::from_guest(&ptr)
}
}
impl<'a, T> Drop for GuestRefMut<'a, T> { impl<'a, T> Drop for GuestRefMut<'a, T> {
fn drop(&mut self) { fn drop(&mut self) {
let mut borrows = self.mem.borrows.borrow_mut(); let mut borrows = self.mem.borrows.borrow_mut();

View File

@@ -36,22 +36,20 @@ pub mod test {
*a_better_excuse_ref = a_lamer_excuse; *a_better_excuse_ref = a_lamer_excuse;
// Read ptr value from mutable ptr: // Read ptr value from mutable ptr:
let mut one_layer_down: ::memory::GuestRefMut<::memory::GuestPtr<types::Excuse>> = let one_layer_down: ::memory::GuestPtr<types::Excuse> =
two_layers_of_excuses.as_ref_mut().map_err(|e| { two_layers_of_excuses.read_ptr_from_guest().map_err(|e| {
eprintln!("one_layer_down error: {}", e); eprintln!("one_layer_down error: {}", e);
types::Errno::InvalidArg types::Errno::InvalidArg
})?; })?;
// Read enum value from that ptr: // Read enum value from that ptr:
let two_layers_down: ::memory::GuestRef<types::Excuse> = let two_layers_down: types::Excuse = *one_layer_down.as_ref().map_err(|e| {
one_layer_down.from_guest().map_err(|e| { eprintln!("two_layers_down error: {}", e);
eprintln!("two_layers_down error: {}", e); types::Errno::InvalidArg
types::Errno::InvalidArg })?;
})?;
// Write ptr value to mutable ptr: // Write ptr value to mutable ptr:
// FIXME this is still impossible... two_layers_of_excuses.write_ptr_to_guest(&a_better_excuse_by_reference.as_immut());
// two_layers_of_excuses.write_guest(&a_better_excuse_by_reference)
println!( println!(
"BAZ: excuse: {:?}, better excuse: {:?}, lamer excuse: {:?}, two layers down: {:?}", "BAZ: excuse: {:?}, better excuse: {:?}, lamer excuse: {:?}, two layers down: {:?}",