diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index c0884a6723..1bbd9e164a 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -17,7 +17,7 @@ pub type Function<'a> = Func<'a, (i32, u32), i32>; #[derive(Clone)] // This structure represent the WASM State of the plugin. pub struct PluginModule { - wasm_instance: Arc>, + wasm_state: Arc>, events: HashSet, } @@ -30,10 +30,9 @@ impl PluginModule { "raw_emit_actions" => func!(read_action), }}) .map_err(PluginModuleError::Instantiate)?; - Ok(Self { events: instance.exports.into_iter().map(|(name, _)| name).collect(), - wasm_instance: Arc::new(Mutex::new(instance)), + wasm_state: Arc::new(Mutex::new(WasmState::new(instance))), }) } @@ -51,16 +50,8 @@ impl PluginModule { return None; } let bytes = { - let instance = self.wasm_instance.lock().unwrap(); - let func = match instance - .exports - .get(event_name) - .map_err(PluginModuleError::FunctionGet) - { - Ok(e) => e, - Err(e) => return Some(Err(e)), - }; - match execute_raw(&instance, &func, &request.bytes) + let mut state = self.wasm_state.lock().unwrap(); + match execute_raw(&mut state, event_name, &request.bytes) .map_err(PluginModuleError::RunFunction) { Ok(e) => e, @@ -71,6 +62,28 @@ impl PluginModule { } } +pub struct WasmMemoryContext { + memory_buffer_size: usize, + memory_pointer: i32, +} + +pub struct WasmState { + instance: Instance, + memory: WasmMemoryContext, +} + +impl WasmState { + fn new(instance: Instance) -> Self { + Self { + instance, + memory: WasmMemoryContext { + memory_buffer_size: 0, + memory_pointer: 0, + }, + } + } +} + // This structure represent a Pre-encoded event object (Useful to avoid // reencoding for each module in every plugin) pub struct PreparedEventQuery { @@ -97,17 +110,23 @@ impl PreparedEventQuery { // an interface to limit unsafe behaviours #[allow(clippy::needless_range_loop)] fn execute_raw( - instance: &Instance, - function: &Function, + context: &mut WasmState, + event_name: &str, bytes: &[u8], ) -> Result, RuntimeError> { // This reserves space for the buffer let len = bytes.len(); let start = { - let memory_pos = reserve_wasm_memory_buffer(len, instance) + let memory_pos = reserve_wasm_memory_buffer(len, &context.instance, &mut context.memory) .expect("Fatal error while allocating memory for a plugin! Closing server...") as usize; - let memory = instance.context().memory(0); + + let function: Func<(i32, u32), i32> = context + .instance + .exports + .get(event_name) + .expect("Function not found this should never happen"); + let memory = context.instance.context().memory(0); let view = memory.view::(); for (cell, byte) in view[memory_pos..memory_pos + len].iter().zip(bytes.iter()) { cell.set(*byte) @@ -115,7 +134,7 @@ fn execute_raw( function.call(memory_pos as i32, len as u32)? as usize }; - let memory = instance.context().memory(0); + let memory = context.instance.context().memory(0); let view = memory.view::(); let mut new_len_bytes = [0u8; 4]; // TODO: It is probably better to dirrectly make the new_len_bytes @@ -168,11 +187,18 @@ pub fn read_action(ctx: &mut Ctx, ptr: u32, len: u32) { fn reserve_wasm_memory_buffer<'a>( value: usize, instance: &'a Instance, + context: &mut WasmMemoryContext, ) -> Result { - instance + if context.memory_buffer_size >= value { + return Ok(context.memory_pointer); + } + let pointer = instance .exports .get::>("wasm_prepare_buffer") .map_err(MemoryAllocationError::AllocatorNotFound)? .call(value as i32) - .map_err(MemoryAllocationError::CantAllocate) + .map_err(MemoryAllocationError::CantAllocate)?; + context.memory_buffer_size = value; + context.memory_pointer = pointer; + Ok(pointer) }