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?
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
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.
- Add a method to directly access the exported
VMMemoryDefinitiontoInstanceHandle:/// 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>
- Add a
as_sliceandas_mut_sliceto theVMMemoryDefintionobject/// 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 functionsI'm using
Box<Error>in the examples below for the sake of simplicity. We may want to go with specific error types
- Introduce a new
Allocationtype which has fundamentally the same properties asVMMemoryDefintionwith additional utility methods. I'm thinking of creating a separate object instead of re-usingVMMemoryDefinitionto prevent developers from calling potentially destructive new operations such aszeroon the entire instance memory.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, }
- The allocation method exposes an
as_slicemethod to easily read the value as well as azeromethod to zero out the memory.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 {}
- Add an alloc method to the VMMemoryDefinition that finds the next available memory location for the given value and copies the data to memroy. The output of this operation is an
Allocationobject,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