Stream: git-wasmtime

Topic: wasmtime / issue #106 Simplifying memory access


view this post on Zulip Wasmtime GitHub notifications bot (Jun 25 2024 at 05:01):

vados-cosmonic commented on issue #106:

Hey @sapessi there's a bunch of work going on on the GC proposal -- maybe the information there would be useful? A lot has happened in the last 4 years that may help answer the allocation management question!

As far as the API goes, are you still interested in pages/bytes types or does the Memory API as it stands today work well enough to resolve the issue?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 15 2026 at 17:52):

fitzgen commented on issue #106:

I think this issue is out of date. We now have slice-returning accessors for linear memory, e.g. https://docs.rs/wasmtime/latest/wasmtime/struct.Memory.html#method.data

view this post on Zulip Wasmtime GitHub notifications bot (Jan 15 2026 at 17:52):

fitzgen closed issue #106:

I'm using wasmtime on a project that requires me to write to linear memory directly before invoking the wasm function. While this is possible today, the APIs are not easy to use. Below is a proposal to simplify memory interaction for discussion.

/// Returns the exported module memory for the given name.
/// When the export_name parameter is not passed defaults to "memory".
/// Returns None if the memory export could not be found
pub fn memory(&mut self, export_name: Option<&str>) -> Option<&VMMemoryDefinition>
/// Converts the raw pointer to a u8 slice
pub fn as_slice(&self) -> &[u8] {}

/// Returns a mutable u8 slice pointing to the VMMemoryDefinition index.
pub fn as_mut_slice(&mut self) -> &mut [u8] {}

With these basic changes in place, after initializing a module, developers can quickly access its linear memory for reading and doing a lot of "unsafe" writing.

The next evolution of this would be to encapsulate all unsafe code in wasmtime's memory objects and give high-level abstractions for developers to use. The proposal below is informed by my use-case and I would like to hear others thoughts on what I'm missing or not understanding correctly. My objectives are:
1. Make allocations easy and, whenever possible, automatically zero out the memory once the object is out of scope
2. Make it easy to find the next available memory location and grow the memory when necessary
3. Make it easy to read return values from functions

I'm using Box<Error> in the examples below for the sake of simplicity. We may want to go with specific error types

pub struct Allocation {
    pub base: *const u8,
    pub current_length: usize,

    /// The index in linear memory where the allocation occurred
    pub idx: i32,

    // Tells whether the Drop trait should execute the zero operation on this object.
    // See VMMemoryDefinition changes for the purpose of this flag.
    auto_deallocate: bool,
}
impl Allocation {
    /// Returns a slice containing the allocation data
    pub fn as_slice(&self) -> &[u8] {}
    /// Zeros out the memory this aloocation points to
    pub fn zero(&mut self) -> Result<(), Box<Error>> {}
}

impl Into<DefinedMemoryIndex> for Allocation {}
impl Into<RuntimeValue::I32> for Allocation {}
impl Drop for Allocation {}

impl VMMemoryDefintion {
    /// Writes the given u8 slice in the first available location in linear memory.
    /// When the grow parameter is set to true the method automatically grows the instance memory
    /// if it cannot find an appropriate location for the data.
    /// The auto_deallocate parameter activates the `Drop` trait implementation for the returned
    /// `Allocation` object. `drop` automatically zeroes out the memory when the object goes out of scope.
    pub fn alloc(&mut self, data: &[u8], grow: bool, auto_deallocate: bool) -> Result<Allocation, Box<Error>> {}

    /// Returns a raw pointer to the next available memory location of the given length. None if there isn't one.
    pub fn next_available(&self, data_len: usize) -> Option<*mut u8> {}

    /// Grows the instance memory by the given number of pages
    pub fn grow(&mut self, pages: u32) -> Result<(), Box<Error>> {}

    /// Grows the instnace memory by a number of pages sufficient to contain the given byte length
    pub fn grow_by_bytes(&mut self, bytes: u32) -> Result<(), Box<Error>> {}

    /// Returns an allocation object that points to the value returned in the given ActionOutcome
    pub fn get_output(&self, out_value: ActionOutcome) -> Result<Allocation, Box<Error>> {}
}


Last updated: Feb 24 2026 at 05:28 UTC