simplify the interface and make the functions more explicit

This commit is contained in:
Christof Petig 2023-06-24 15:52:40 +02:00
parent 01223d7174
commit c9ff9e9841
3 changed files with 32 additions and 99 deletions

View File

@ -110,7 +110,7 @@ impl EcsAccessManager {
/// buffer calling the `wasm_prepare_buffer` function Note: There is /// buffer calling the `wasm_prepare_buffer` function Note: There is
/// probably optimizations that can be done using less restrictive /// probably optimizations that can be done using less restrictive
/// ordering /// ordering
pub fn get_pointer( fn get_pointer(
store: &mut StoreMut, store: &mut StoreMut,
object_length: <MemoryModel as wasmer::MemorySize>::Offset, object_length: <MemoryModel as wasmer::MemorySize>::Offset,
allocator: &TypedFunction< allocator: &TypedFunction<
@ -123,45 +123,17 @@ pub fn get_pointer(
.map_err(MemoryAllocationError::CantAllocate) .map_err(MemoryAllocationError::CantAllocate)
} }
/// This function writes an object to WASM memory returning a pointer and a
/// length. Will realloc the buffer is not wide enough
pub fn write_data<T: Serialize>(
store: &mut StoreMut,
memory: &Memory,
allocator: &TypedFunction<
<MemoryModel as wasmer::MemorySize>::Offset,
WasmPtr<u8, MemoryModel>,
>,
object: &T,
) -> Result<
(
WasmPtr<u8, MemoryModel>,
<MemoryModel as wasmer::MemorySize>::Offset,
),
PluginModuleError,
> {
write_bytes(
store,
memory,
allocator,
(
&bincode::serialize(object).map_err(PluginModuleError::Encoding)?,
&[],
),
)
}
/// This functions wraps the serialization process /// This functions wraps the serialization process
pub fn serialize_data<T: Serialize>(object: &T) -> Result<Vec<u8>, PluginModuleError> { fn serialize_data<T: Serialize>(object: &T) -> Result<Vec<u8>, PluginModuleError> {
bincode::serialize(object).map_err(PluginModuleError::Encoding) bincode::serialize(object).map_err(PluginModuleError::Encoding)
} }
/// This function writes an object to the wasm memory using the allocator if /// This function writes an object to the wasm memory using the allocator if
/// necessary using length padding. /// necessary using length padding.
/// ///
/// With length padding the first 8 bytes written are the length of the the /// With length padding the first bytes written are the length of the the
/// following slice (The object serialized). /// following slice (The object serialized).
pub fn write_data_as_pointer<T: Serialize>( pub(crate) fn write_serialized_with_length<T: Serialize>(
store: &mut StoreMut, store: &mut StoreMut,
memory: &Memory, memory: &Memory,
allocator: &TypedFunction< allocator: &TypedFunction<
@ -170,7 +142,7 @@ pub fn write_data_as_pointer<T: Serialize>(
>, >,
object: &T, object: &T,
) -> Result<WasmPtr<u8, MemoryModel>, PluginModuleError> { ) -> Result<WasmPtr<u8, MemoryModel>, PluginModuleError> {
write_bytes_as_pointer(store, memory, allocator, &serialize_data(object)?) write_length_and_bytes(store, memory, allocator, &serialize_data(object)?)
} }
/// This function writes an raw bytes to WASM memory returning a pointer and /// This function writes an raw bytes to WASM memory returning a pointer and
@ -179,7 +151,7 @@ pub fn write_data_as_pointer<T: Serialize>(
/// As this function is often called after prepending a length to an existing /// As this function is often called after prepending a length to an existing
/// object it accepts two slices and concatenates them to cut down copying in /// object it accepts two slices and concatenates them to cut down copying in
/// the caller. /// the caller.
pub fn write_bytes( pub(crate) fn write_bytes(
store: &mut StoreMut, store: &mut StoreMut,
memory: &Memory, memory: &Memory,
allocator: &TypedFunction< allocator: &TypedFunction<
@ -211,9 +183,9 @@ pub fn write_bytes(
/// This function writes bytes to the wasm memory using the allocator if /// This function writes bytes to the wasm memory using the allocator if
/// necessary using length padding. /// necessary using length padding.
/// ///
/// With length padding the first 8 bytes written are the length of the the /// With length padding the first bytes written are the length of the the
/// following slice. /// following slice.
pub fn write_bytes_as_pointer( pub(crate) fn write_length_and_bytes(
store: &mut StoreMut, store: &mut StoreMut,
memory: &Memory, memory: &Memory,
allocator: &TypedFunction< allocator: &TypedFunction<
@ -228,7 +200,7 @@ pub fn write_bytes_as_pointer(
/// This function reads data from memory at a position with the array length and /// This function reads data from memory at a position with the array length and
/// converts it to an object using bincode /// converts it to an object using bincode
pub fn read_data<'a, T: for<'b> Deserialize<'b>>( pub(crate) fn read_serialized<'a, T: for<'b> Deserialize<'b>>(
memory: &'a Memory, memory: &'a Memory,
store: &StoreRef, store: &StoreRef,
ptr: WasmPtr<u8, MemoryModel>, ptr: WasmPtr<u8, MemoryModel>,
@ -241,7 +213,7 @@ pub fn read_data<'a, T: for<'b> Deserialize<'b>>(
/// This function reads raw bytes from memory at a position with the array /// This function reads raw bytes from memory at a position with the array
/// length /// length
pub fn read_bytes( pub(crate) fn read_bytes(
memory: &Memory, memory: &Memory,
store: &StoreRef, store: &StoreRef,
ptr: WasmPtr<u8, MemoryModel>, ptr: WasmPtr<u8, MemoryModel>,
@ -253,7 +225,7 @@ pub fn read_bytes(
} }
/// This function reads a constant amount of raw bytes from memory /// This function reads a constant amount of raw bytes from memory
pub fn read_exact_bytes<const N: usize>( pub(crate) fn read_exact_bytes<const N: usize>(
memory: &Memory, memory: &Memory,
store: &StoreRef, store: &StoreRef,
ptr: WasmPtr<u8, MemoryModel>, ptr: WasmPtr<u8, MemoryModel>,

View File

@ -1,5 +1,5 @@
use hashbrown::HashSet; use hashbrown::HashSet;
use std::{convert::TryInto, marker::PhantomData, sync::Arc}; use std::{marker::PhantomData, sync::Arc};
use wasmer::{ use wasmer::{
imports, AsStoreMut, AsStoreRef, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, imports, AsStoreMut, AsStoreRef, Function, FunctionEnv, FunctionEnvMut, Instance, Memory,
@ -47,13 +47,15 @@ impl PluginModule {
ptr: WasmPtr<u8, MemoryModel>, ptr: WasmPtr<u8, MemoryModel>,
len: <MemoryModel as wasmer::MemorySize>::Offset, len: <MemoryModel as wasmer::MemorySize>::Offset,
) { ) {
handle_actions(match env.data().read_data(&env.as_store_ref(), ptr, len) { handle_actions(
match env.data().read_serialized(&env.as_store_ref(), ptr, len) {
Ok(e) => e, Ok(e) => e,
Err(e) => { Err(e) => {
tracing::error!(?e, "Can't decode action"); tracing::error!(?e, "Can't decode action");
return; return;
}, },
}); },
);
} }
fn raw_retrieve_action( fn raw_retrieve_action(
@ -62,16 +64,16 @@ impl PluginModule {
ptr: WasmPtr<u8, MemoryModel>, ptr: WasmPtr<u8, MemoryModel>,
len: <MemoryModel as wasmer::MemorySize>::Offset, len: <MemoryModel as wasmer::MemorySize>::Offset,
) -> <MemoryModel as wasmer::MemorySize>::Offset { ) -> <MemoryModel as wasmer::MemorySize>::Offset {
let out = match env.data().read_data(&env.as_store_ref(), ptr, len) { let out = match env.data().read_serialized(&env.as_store_ref(), ptr, len) {
Ok(data) => retrieve_action(&env.data().ecs, data), Ok(data) => retrieve_action(&env.data().ecs, data),
Err(e) => Err(RetrieveError::BincodeError(e.to_string())), Err(e) => Err(RetrieveError::BincodeError(e.to_string())),
}; };
let data = env.data().clone(); let data = env.data().clone();
// If an error happen set the i64 to 0 so the WASM side can tell an error data.write_serialized_with_length(&mut env.as_store_mut(), &out)
// occured .unwrap_or_else(|_e|
data.write_data_as_pointer(&mut env.as_store_mut(), &out) // return a null pointer so the WASM side can tell an error occured
.unwrap_or_else(|_e| WasmPtr::null()) WasmPtr::null())
.offset() .offset()
} }
@ -183,28 +185,6 @@ impl<T: Event> PreparedEventQuery<T> {
pub fn get_function_name(&self) -> &str { &self.function_name } pub fn get_function_name(&self) -> &str { &self.function_name }
} }
/// This function split a u128 in two u64 encoding them as le bytes
pub fn from_u128(i: u128) -> (u64, u64) {
let i = i.to_le_bytes();
(
u64::from_le_bytes(i[0..8].try_into().unwrap()),
u64::from_le_bytes(i[8..16].try_into().unwrap()),
)
}
/// This function merge two u64 encoded as le in one u128
pub fn to_u128(a: u64, b: u64) -> u128 {
let a = a.to_le_bytes();
let b = b.to_le_bytes();
u128::from_le_bytes([a, b].concat().try_into().unwrap())
}
/// This function encode a u64 into a i64 using le bytes
pub fn to_i64(i: u64) -> i64 { i64::from_le_bytes(i.to_le_bytes()) }
/// This function decode a i64 into a u64 using le bytes
pub fn from_i64(i: i64) -> u64 { u64::from_le_bytes(i.to_le_bytes()) }
// This function is not public because this function should not be used without // This function is not public because this function should not be used without
// an interface to limit unsafe behaviours // an interface to limit unsafe behaviours
fn execute_raw( fn execute_raw(

View File

@ -65,41 +65,25 @@ impl HostFunctionEnvironment {
#[inline] #[inline]
pub fn name(&self) -> &str { &self.name } pub fn name(&self) -> &str { &self.name }
/// This function is a safe interface to WASM memory that writes data to the /// This function is a safe interface to WASM memory that serializes and
/// memory returning a pointer and length /// writes an object to linear memory returning a pointer
pub fn write_data<T: Serialize>( pub fn write_serialized_with_length<T: Serialize>(
&self,
store: &mut StoreMut,
object: &T,
) -> Result<
(
WasmPtr<u8, MemoryModel>,
<MemoryModel as wasmer::MemorySize>::Offset,
),
PluginModuleError,
> {
memory_manager::write_data(store, self.memory(), self.allocator(), object)
}
/// This function is a safe interface to WASM memory that writes data to the
/// memory returning a pointer and length
pub fn write_data_as_pointer<T: Serialize>(
&self, &self,
store: &mut StoreMut, store: &mut StoreMut,
object: &T, object: &T,
) -> Result<WasmPtr<u8, MemoryModel>, PluginModuleError> { ) -> Result<WasmPtr<u8, MemoryModel>, PluginModuleError> {
memory_manager::write_data_as_pointer(store, self.memory(), self.allocator(), object) memory_manager::write_serialized_with_length(store, self.memory(), self.allocator(), object)
} }
/// This function is a safe interface to WASM memory that reads memory from /// This function is a safe interface to WASM memory that reads memory from
/// pointer and length returning an object /// pointer and length returning an object
pub fn read_data<T: DeserializeOwned>( pub fn read_serialized<T: DeserializeOwned>(
&self, &self,
store: &StoreRef, store: &StoreRef,
position: WasmPtr<u8, MemoryModel>, position: WasmPtr<u8, MemoryModel>,
length: <MemoryModel as wasmer::MemorySize>::Offset, length: <MemoryModel as wasmer::MemorySize>::Offset,
) -> Result<T, bincode::Error> { ) -> Result<T, bincode::Error> {
memory_manager::read_data(self.memory(), store, position, length) memory_manager::read_serialized(self.memory(), store, position, length)
} }
/// This function is a safe interface to WASM memory that reads memory from /// This function is a safe interface to WASM memory that reads memory from
@ -110,10 +94,7 @@ impl HostFunctionEnvironment {
ptr: WasmPtr<u8, MemoryModel>, ptr: WasmPtr<u8, MemoryModel>,
len: <MemoryModel as wasmer::MemorySize>::Offset, len: <MemoryModel as wasmer::MemorySize>::Offset,
) -> Result<Vec<u8>, PluginModuleError> { ) -> Result<Vec<u8>, PluginModuleError> {
self.memory.as_ref().map_or_else( memory_manager::read_bytes(self.memory(), store, ptr, len)
|| Err(PluginModuleError::InvalidPointer),
|m| memory_manager::read_bytes(m, store, ptr, len),
)
} }
pub fn args_from_instance( pub fn args_from_instance(