Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

c-api: Expose host memory creation #7115

Merged
merged 4 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
67 changes: 67 additions & 0 deletions crates/c-api/include/wasmtime/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,73 @@ WASM_API_EXTERN void wasmtime_config_cranelift_flag_enable(wasm_config_t*, const
*/
WASM_API_EXTERN void wasmtime_config_cranelift_flag_set(wasm_config_t*, const char *key, const char *value);

/**
* A callback to create a new LinearMemory from the specified parameters.
*
* The result should be written to `memory_ret` and optionally a finalizer for the returned memory
* can be returned in the finalizer pointer.
*
* For more information about the parameters see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.MemoryCreator.html#tymethod.new_memory
*/
typedef wasmtime_error_t *(*wasmtime_new_memory_callback_t)(
wasm_memorytype_t *ty,
size_t minimum,
size_t maximum,
size_t reserved_size_in_bytes,
size_t guard_size_in_bytes,
void **memory_ret,
void (**finalizer)(void*));

/**
* Return the data from a LinearMemory instance created from a #wasmtime_new_memory_t callback.
*
* The size in bytes as well as the maximum number of bytes that can be allocated should be
* returned as well.
*
* For more information about the parameters see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html
*/
typedef void *(*wasmtime_memory_get_callback_t)(
void *memory_ptr,
size_t *byte_size,
size_t *maximum_byte_size);

/**
* Grow the memory to the `new_size` in bytes.
*
* For more information about the parameters see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html#tymethod.grow_to
*/
typedef wasmtime_error_t *(*wasmtime_memory_grow_callback_t)(
void *memory_ptr,
size_t new_size);

/**
* A representation of custom memory creator and methods for an instance of LinearMemory.
*
* For more information see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.MemoryCreator.html
*/
typedef struct {
wasmtime_new_memory_callback_t new_memory;
wasmtime_memory_get_callback_t get_memory;
wasmtime_memory_grow_callback_t grow_memory;
} wasmtime_memory_creator_t;
rockwotj marked this conversation as resolved.
Show resolved Hide resolved

/**
* Sets a custom memory creator.
*
* Custom memory creators are used when creating host Memory objects or when creating instance
* linear memories for the on-demand instance allocation strategy.
*
* For more information see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.with_host_memory
*/
WASM_API_EXTERN void wasmtime_config_host_memory_creator_set(
wasm_config_t*,
wasmtime_memory_creator_t*);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
146 changes: 143 additions & 3 deletions crates/c-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
// them with the default set of features enabled.
#![cfg_attr(not(feature = "cache"), allow(unused_imports))]

use crate::{handle_result, wasmtime_error_t};
use std::ffi::CStr;
use crate::{handle_result, wasm_memorytype_t, wasmtime_error_t};
use std::ops::Range;
use std::os::raw::c_char;
use wasmtime::{Config, OptLevel, ProfilingStrategy, Strategy};
use std::ptr;
use std::{ffi::CStr, sync::Arc};
use wasmtime::{
Config, LinearMemory, MemoryCreator, OptLevel, ProfilingStrategy, Result, Strategy,
};

#[repr(C)]
#[derive(Clone)]
Expand Down Expand Up @@ -255,3 +259,139 @@ pub unsafe extern "C" fn wasmtime_config_cranelift_flag_set(
let value = CStr::from_ptr(value).to_str().expect("not valid utf-8");
c.config.cranelift_flag_set(flag, value);
}

pub type wasmtime_new_memory_callback_t = extern "C" fn(
ty: &wasm_memorytype_t,
minimum: usize,
maximum: usize,
reserved_size_in_bytes: usize,
guard_size_in_bytes: usize,
memory_ret: &mut *mut std::ffi::c_void,
finalizer_ret: &mut Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
) -> Option<Box<wasmtime_error_t>>;

pub type wasmtime_memory_get_callback_t = extern "C" fn(
memory_ptr: *mut std::ffi::c_void,
byte_size: &mut usize,
maximum_byte_size: &mut usize,
) -> *mut u8;
rockwotj marked this conversation as resolved.
Show resolved Hide resolved

pub type wasmtime_memory_grow_callback_t = extern "C" fn(
memory_ptr: *mut std::ffi::c_void,
new_size: usize,
) -> Option<Box<wasmtime_error_t>>;

#[repr(C)]
pub struct wasmtime_memory_creator_t {
new_memory: wasmtime_new_memory_callback_t,
get_memory: wasmtime_memory_get_callback_t,
grow_memory: wasmtime_memory_grow_callback_t,
}

struct CHostLinearMemory {
foreign: crate::ForeignData,
get_memory: wasmtime_memory_get_callback_t,
grow_memory: wasmtime_memory_grow_callback_t,
}

unsafe impl LinearMemory for CHostLinearMemory {
fn byte_size(&self) -> usize {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size);
return byte_size;
}
fn maximum_byte_size(&self) -> Option<usize> {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size);
if maximum_byte_size == 0 {
None
} else {
Some(maximum_byte_size)
}
}
fn as_ptr(&self) -> *mut u8 {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size)
}
fn wasm_accessible(&self) -> Range<usize> {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
let ptr = cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size);
Range {
start: ptr as usize,
end: ptr as usize + byte_size,
}
}
fn grow_to(&mut self, new_size: usize) -> Result<()> {
let cb = self.grow_memory;
let error = cb(self.foreign.data, new_size);
if let Some(err) = error {
Err((*err).into())
} else {
Ok(())
}
}
}

struct CHostMemoryCreator {
creator: Box<wasmtime_memory_creator_t>,
}
unsafe impl Send for CHostMemoryCreator {}
unsafe impl Sync for CHostMemoryCreator {}
rockwotj marked this conversation as resolved.
Show resolved Hide resolved

unsafe impl MemoryCreator for CHostMemoryCreator {
fn new_memory(
&self,
ty: wasmtime::MemoryType,
minimum: usize,
maximum: Option<usize>,
reserved_size_in_bytes: Option<usize>,
guard_size_in_bytes: usize,
) -> Result<Box<dyn wasmtime::LinearMemory>, String> {
let mut memory = ptr::null_mut();
let mut finalizer = None;
let cb = self.creator.new_memory;
let error = cb(
&wasm_memorytype_t::new(ty),
minimum,
maximum.unwrap_or(usize::MAX),
reserved_size_in_bytes.unwrap_or(0),
guard_size_in_bytes,
&mut memory,
&mut finalizer,
);
match error {
None => {
let foreign = crate::ForeignData {
data: memory,
finalizer,
};
Ok(Box::new(CHostLinearMemory {
foreign,
get_memory: self.creator.get_memory,
grow_memory: self.creator.grow_memory,
}))
}
Some(err) => {
let err: anyhow::Error = (*err).into();
Err(format!("{}", err))
}
}
}
}

#[no_mangle]
pub unsafe extern "C" fn wasmtime_config_host_memory_creator_set(
c: &mut wasm_config_t,
creator: Box<wasmtime_memory_creator_t>,
) {
c.config
.with_host_memory(Arc::new(CHostMemoryCreator { creator }));
}