Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 8 additions & 18 deletions fix/procedure/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,14 @@ static ALLOCATOR: GlobalDlmalloc = GlobalDlmalloc;
use fixutils::*;

num_memories!(1);
num_tables!(1);

const HELLO: &[u8] = b"hello";
num_tables!(2);

#[fix_entrypoint]
pub fn _fixpoint_apply(combination: RustHandle<'static>) -> RustHandle<'static> {
let memory_1 = Memory::new(1).expect("expected 1 memory");
let table_1 = Table::new(1).expect("expected 1 table");

let num_entries = combination.len();
table_1.attach_tree(combination);
table_1.grow(1);

memory_1.write(HELLO);
let blob = memory_1.create_blob(HELLO.len());
table_1.set(num_entries, blob);

create_strict_encode(create_identification_thunk(
table_1.create_tree(num_entries + 1),
))
pub fn _fixpoint_apply(combination: RustHandle<'static>) -> Result<RustHandle<'static>, FixError> {
let blob_handle = RustHandle::from_bytes(b"hello")?;
let mut entries = combination.to_entries()?;
entries.push(blob_handle);
Ok(create_strict_encode(create_identification_thunk(
RustHandle::from_entries(&entries)?,
)))
}
121 changes: 24 additions & 97 deletions fix/utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
extern crate alloc;
#[cfg(target_arch = "wasm32")]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
core::arch::wasm32::unreachable()
}

use alloc::vec::Vec;
use core::marker::PhantomData;
use fixhandle::{
BitPack, Blob, BlobName, Encode, Handle, Object, RawName, Ref, Thunk, Tree, TreeName,
};
pub use macros::{fix_entrypoint, num_memories, num_tables};

pub mod memory;
pub mod table;

pub use memory::*;
pub use table::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FixError {
AllOcuppied, // All memories/tables occupied
Unavailable, // Resource unavilable
GrowFailed, // Memory/Table growth failed
OutOfBounds, // Memory/Table access out of bounds
}

#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Producer {
Expand Down Expand Up @@ -60,110 +76,21 @@ impl<'a> RustHandle<'a> {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}

unsafe extern "C" {
fn fix_memory_slot(index: u16) -> *mut Memory;
fn fix_table_slot(index: u16) -> *mut Table;
}

#[repr(transparent)]
pub struct Memory(u16);

impl Memory {
#[doc(hidden)]
pub const EMPTY: Self = Self(0);

pub fn new(index: u16) -> Option<&'static mut Self> {
let slot = unsafe { fix_memory_slot(index) };
if !slot.is_null() {
let memory = unsafe { &mut *slot };
memory.0 = index;
return Some(memory);
}
None
}

// Borrows the memory until the handle is consumed
pub fn create_blob(&self, length: usize) -> RustHandle<'_> {
RustHandle::new(Handle::Object(Object::Blob(Blob::Blob(unsafe {
BlobName::new(encode_args(Producer::CreateBlob, self.0, length))
}))))
}

pub fn read(&self, destination: &mut [u8]) {
unsafe {
fix_memory_read(
self.0 as u32,
destination.as_mut_ptr() as u32,
destination.len(),
)
}
}

pub fn write(&mut self, source: &[u8]) {
unsafe { fix_memory_write(self.0 as u32, source.as_ptr() as u32, source.len()) }
}

pub fn size(&self) -> usize {
unsafe { fix_memory_size(self.0 as u32) }
}

pub fn grow(&mut self, num_pages: usize) -> usize {
unsafe { fix_memory_grow(self.0 as u32, num_pages) }
}

pub fn attach_blob(&mut self, handle: RustHandle<'_>) {
unsafe { fix_attach_blob(self.0 as u32, &handle.raw_handle) }
}
}

#[repr(transparent)]
pub struct Table(u16);

impl Table {
#[doc(hidden)]
pub const EMPTY: Self = Self(0);

pub fn new(index: u16) -> Option<&'static mut Self> {
let slot = unsafe { fix_table_slot(index) };
if !slot.is_null() {
let table = unsafe { &mut *slot };
table.0 = index;
return Some(table);
}
None
}

// Borrows the table until the handle is consumed
pub fn create_tree(&self, length: usize) -> RustHandle<'_> {
RustHandle::new(Handle::Object(Object::Tree(Tree::Tree(unsafe {
TreeName::new(encode_args(Producer::CreateTree, self.0, length))
}))))
}

pub fn get(&self, entry: usize) -> RustHandle<'_> {
assert!(entry < self.size());
RustHandle::new(Handle::Object(Object::Tree(Tree::Tree(unsafe {
TreeName::new(encode_args(Producer::TableGet, self.0, entry))
}))))
}

pub fn set(&mut self, entry: usize, handle: RustHandle<'_>) {
assert!(entry < self.size());
unsafe { fix_table_set(self.0 as u32, entry, &handle.raw_handle) }
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FixError> {
Memory::from_bytes(bytes)?.to_blob(bytes.len())
}

pub fn size(&self) -> usize {
unsafe { fix_table_size(self.0 as u32) }
pub fn from_entries(entries: &[RustHandle<'_>]) -> Result<Self, FixError> {
Table::from_entries(entries)?.to_tree(entries.len())
}

pub fn grow(&mut self, entries: usize) -> usize {
unsafe { fix_table_grow(self.0 as u32, entries) }
pub fn to_bytes(&self) -> Result<Vec<u8>, FixError> {
Memory::from_blob(*self)?.to_bytes(self.len())
}

pub fn attach_tree(&mut self, handle: RustHandle<'_>) {
unsafe { fix_attach_tree(self.0 as u32, &handle.raw_handle) }
pub fn to_entries(&self) -> Result<Vec<RustHandle<'_>>, FixError> {
Table::from_tree(*self)?.to_entries(self.len())
}
}

Expand Down
129 changes: 129 additions & 0 deletions fix/utils/src/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use crate::*;

unsafe extern "C" {
fn fix_allocate_memory(index: u16) -> *mut Memory;
static FIX_NUM_MEMORIES: u16;
}
static mut POSITION: u16 = 0;
const PAGE_SIZE: usize = 65536;

pub fn fix_next_memory() -> Result<&'static mut Memory, FixError> {
unsafe {
while POSITION < FIX_NUM_MEMORIES {
POSITION += 1;
if let Ok(memory) = Memory::new(POSITION) {
return Ok(memory);
}
}
}
Err(FixError::AllOcuppied)
}

#[repr(transparent)]
pub struct Memory(u16);

impl Memory {
#[doc(hidden)]
pub const EMPTY: Self = Self(0);

pub fn new(index: u16) -> Result<&'static mut Self, FixError> {
let slot = unsafe { fix_allocate_memory(index) };
if slot.is_null() {
return Err(FixError::Unavailable);
}
let memory = unsafe { &mut *slot };
memory.0 = index;
Ok(memory)
}

/// Calls the fixshell's create_blob function when resolved.
/// Borrows the memory until the handle is consumed.
///
/// # Safety
///
/// `length` must be <= size() * PAGE_SIZE
pub unsafe fn create_blob(&self, length: usize) -> RustHandle<'_> {
RustHandle::new(Handle::Object(Object::Blob(Blob::Blob(unsafe {
BlobName::new(encode_args(Producer::CreateBlob, self.0, length))
}))))
}

/// Fills the destination slice by copying bytes from the memory
///
/// # Safety
///
/// The `destination` slice's length must be <= size() * PAGE_SIZE
pub unsafe fn read(&self, destination: &mut [u8]) {
unsafe {
fix_memory_read(
self.0 as u32,
destination.as_mut_ptr() as u32,
destination.len(),
)
}
}

/// Copies the bytes from the source slice into the memory
///
/// # Safety
///
/// The `source` slice's length must be <= size() * PAGE_SIZE
pub unsafe fn write(&mut self, source: &[u8]) {
unsafe { fix_memory_write(self.0 as u32, source.as_ptr() as u32, source.len()) }
}

/// Calls the fixshell's attach_blob after resolving the provided `handle`
///
/// # Safety
///
/// `handle` must refer to a blob
pub unsafe fn attach_blob(&mut self, handle: RustHandle<'_>) {
unsafe { fix_attach_blob(self.0 as u32, &handle.raw_handle) }
}

pub fn size(&self) -> usize {
unsafe { fix_memory_size(self.0 as u32) }
}

pub fn grow(&mut self, num_pages: usize) -> usize {
unsafe { fix_memory_grow(self.0 as u32, num_pages) }
}

pub fn from_bytes(bytes: &[u8]) -> Result<&'static mut Self, FixError> {
let memory = fix_next_memory()?;
let mapped = memory.size();
let required = bytes.len().div_ceil(PAGE_SIZE);
if required > mapped && memory.grow(required - mapped) == usize::MAX {
return Err(FixError::GrowFailed);
}
unsafe { memory.write(bytes) };
Ok(memory)
}

pub fn from_blob(handle: RustHandle<'_>) -> Result<&'static mut Self, FixError> {
let memory = fix_next_memory()?;
let mapped = memory.size();
let required = handle.len().div_ceil(PAGE_SIZE);
if required > mapped && memory.grow(required - mapped) == usize::MAX {
return Err(FixError::GrowFailed);
}
unsafe { memory.attach_blob(handle) };
Ok(memory)
}

pub fn to_bytes(&self, length: usize) -> Result<Vec<u8>, FixError> {
if length > self.size() * PAGE_SIZE {
return Err(FixError::OutOfBounds);
}
let mut bytes = alloc::vec![0; length];
unsafe { self.read(&mut bytes) };
Ok(bytes)
}

pub fn to_blob(&self, length: usize) -> Result<RustHandle<'_>, FixError> {
if length > self.size() * PAGE_SIZE {
return Err(FixError::OutOfBounds);
}
Ok(unsafe { self.create_blob(length) })
}
}
Loading
Loading