From e36b7d5ecbbbca5c3e5897eeed49fc524c549920 Mon Sep 17 00:00:00 2001 From: Jimmy Bourassa Date: Sun, 23 Apr 2023 16:41:23 -0400 Subject: [PATCH] Try out unsafe approach from #169 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After: ``` $ rake compile:release && rake bench:host_call [...] Calculating ------------------------------------- Call host func (4 args) 519.910k (± 1.3%) i/s - 2.608M in 5.016526s Call host func (16 args) 440.924k (± 0.6%) i/s - 2.243M in 5.086693s Call host func (64 args) 277.404k (± 1.2%) i/s - 1.412M in 5.089372s Call host func (128 args) 144.274k (± 0.7%) i/s - 734.910k in 5.094121s Call host func (256 args) 55.141k (± 1.1%) i/s - 279.990k in 5.078321s ``` --- ext/src/ruby_api/func.rs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/ext/src/ruby_api/func.rs b/ext/src/ruby_api/func.rs index a5d0ee2a..c15f8567 100644 --- a/ext/src/ruby_api/func.rs +++ b/ext/src/ruby_api/func.rs @@ -192,17 +192,39 @@ impl<'a> Func<'a> { [] => Ok(().into_value()), [result] => result.to_ruby_value(store), _ => { - let mut ruby_values : Vec = Vec::with_capacity(results.len()); - for result in results { - // Q: can this trigger GC? - ruby_values.push(result.to_ruby_value(store)?); + let fake_values = unsafe { std::mem::transmute(results.as_slice()) }; + let array = RArray::from_slice::(fake_values); + let array_slice = unsafe { rarray_as_mut_slice(array, results.len()) }; + let results_iter = results.iter().enumerate(); + assert!(array_slice.len() == results_iter.len()); + + for (i, result) in results.iter().enumerate() { + array_slice[i] = result.to_ruby_value(store).map_err(|e| { + // If we fail along the way, zero out the array just to be safe + let _ = array.clear(); + e + })?; } - Ok(*RArray::from_slice(&ruby_values)) + + Ok(array.into()) } } } } +/// Converts an `RArray` into a mutable slice. +/// +/// # Safety +/// The capacity of the array must be known in advance for this to be safe, since we provide mutable access to the array's contents. +unsafe fn rarray_as_mut_slice<'a>(array: RArray, capacity: usize) -> &'a mut [Value] { + let array_slice = unsafe { array.as_slice() }; + let ptr = array_slice.as_ptr(); + let array_slice = unsafe { std::slice::from_raw_parts_mut(ptr as *mut Value, capacity) }; + + array_slice +} + + impl From<&Func<'_>> for wasmtime::Extern { fn from(func: &Func) -> Self { Self::Func(func.get())