mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-09 14:18:20 +00:00
Implement host functions in 1 case, optimize NativeFunc::call
`NativeFunc::call` is about 8% faster in the case we're benchmarking by avoiding allocating a vector for the params / returns, instead we do logic to determine which is larger and use that, conditionally copying it back to the rets array if needed.
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
use std::sync::Arc;
|
|
||||||
use test_utils::{get_compiler_config_from_str, wasmer_compilers};
|
use test_utils::{get_compiler_config_from_str, wasmer_compilers};
|
||||||
use wasmer::*;
|
use wasmer::*;
|
||||||
use wasmer_engine_jit::JITEngine;
|
use wasmer_engine_jit::JITEngine;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::marker::PhantomData;
|
|||||||
|
|
||||||
use crate::exports::{ExportError, Exportable};
|
use crate::exports::{ExportError, Exportable};
|
||||||
use crate::externals::function::{FunctionDefinition, WasmFunctionDefinition};
|
use crate::externals::function::{FunctionDefinition, WasmFunctionDefinition};
|
||||||
use crate::{Extern, Function, FunctionType, Store};
|
use crate::{Extern, Function, FunctionType, RuntimeError, Store};
|
||||||
use wasm_common::{NativeWasmType, WasmExternType, WasmTypeList};
|
use wasm_common::{NativeWasmType, WasmExternType, WasmTypeList};
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
wasmer_call_trampoline, Export, ExportFunction, VMContext, VMFunctionBody, VMFunctionKind,
|
wasmer_call_trampoline, Export, ExportFunction, VMContext, VMFunctionBody, VMFunctionKind,
|
||||||
@@ -27,7 +27,11 @@ pub struct NativeFunc<'a, Args = UnprovidedArgs, Rets = UnprovidedRets> {
|
|||||||
|
|
||||||
unsafe impl<'a, Args, Rets> Send for NativeFunc<'a, Args, Rets> {}
|
unsafe impl<'a, Args, Rets> Send for NativeFunc<'a, Args, Rets> {}
|
||||||
|
|
||||||
impl<'a, Args, Rets> NativeFunc<'a, Args, Rets> {
|
impl<'a, Args, Rets> NativeFunc<'a, Args, Rets>
|
||||||
|
where
|
||||||
|
Args: WasmTypeList,
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
store: Store,
|
store: Store,
|
||||||
address: *const VMFunctionBody,
|
address: *const VMFunctionBody,
|
||||||
@@ -115,56 +119,70 @@ macro_rules! impl_native_traits {
|
|||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
/// Call the typed func and return results.
|
/// Call the typed func and return results.
|
||||||
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, ()> {
|
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
||||||
let params = [ $( $x.to_native().to_binary() ),* ];
|
// TODO: when `const fn` related features mature more, we can declare a single array
|
||||||
let mut values_vec: Vec<i128> = vec![0; std::cmp::max(params.len(), Rets::wasm_types().len())];
|
// of the correct size here.
|
||||||
|
let mut params_list = [ $( $x.to_native().to_binary() ),* ];
|
||||||
for (i, &arg) in params.iter().enumerate() {
|
let mut rets_list_array = Rets::empty_array();
|
||||||
values_vec[i] = arg;
|
let rets_list = rets_list_array.as_mut();
|
||||||
}
|
let using_rets_array;
|
||||||
|
let args_rets: &mut [i128] = if params_list.len() > rets_list.len() {
|
||||||
|
using_rets_array = false;
|
||||||
|
params_list.as_mut()
|
||||||
|
} else {
|
||||||
|
using_rets_array = true;
|
||||||
|
for (i, &arg) in params_list.iter().enumerate() {
|
||||||
|
rets_list[i] = arg;
|
||||||
|
}
|
||||||
|
rets_list.as_mut()
|
||||||
|
};
|
||||||
|
|
||||||
match self.definition {
|
match self.definition {
|
||||||
FunctionDefinition::Wasm(WasmFunctionDefinition {
|
FunctionDefinition::Wasm(WasmFunctionDefinition {
|
||||||
trampoline
|
trampoline
|
||||||
}) => {
|
}) => {
|
||||||
if let Err(error) = unsafe {
|
unsafe {
|
||||||
wasmer_call_trampoline(
|
wasmer_call_trampoline(
|
||||||
self.vmctx,
|
self.vmctx,
|
||||||
trampoline,
|
trampoline,
|
||||||
self.address,
|
self.address,
|
||||||
values_vec.as_mut_ptr() as *mut u8,
|
args_rets.as_mut_ptr() as *mut u8,
|
||||||
)
|
)
|
||||||
} {
|
}?;
|
||||||
dbg!(error);
|
let num_rets = rets_list.len();
|
||||||
return Err(());
|
if !using_rets_array && num_rets > 0 {
|
||||||
} else {
|
let src_pointer = params_list.as_ptr();
|
||||||
let mut results = Rets::empty_array();
|
let rets_list = &mut rets_list_array.as_mut()[0] as *mut i128;
|
||||||
let num_results = Rets::wasm_types().len();
|
unsafe {
|
||||||
if num_results > 0 {
|
// TODO: we can probably remove this copy by doing some clever `transmute`s.
|
||||||
unsafe {
|
// we know it's not overlapping because `using_rets_array` is false
|
||||||
std::ptr::copy_nonoverlapping(values_vec.as_ptr(),
|
std::ptr::copy_nonoverlapping(src_pointer,
|
||||||
&mut results.as_mut()[0] as *mut i128,
|
rets_list,
|
||||||
num_results);
|
num_rets);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Ok(Rets::from_array(results));
|
|
||||||
}
|
}
|
||||||
|
return Ok(Rets::from_array(rets_list_array));
|
||||||
}
|
}
|
||||||
FunctionDefinition::Host => {
|
FunctionDefinition::Host => {
|
||||||
/*unsafe {
|
if self.arg_kind == VMFunctionKind::Static {
|
||||||
let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Result<Rets, RuntimeError>>(self.address);
|
unsafe {
|
||||||
match f( self.vmctx, $( $x, )* ) {
|
let f = std::mem::transmute::<_, unsafe fn( $( $x, )*) -> Rets>(self.address);
|
||||||
Err(error) => {
|
|
||||||
dbg!(error);
|
let results = f( $( $x, )* );
|
||||||
return Err(());
|
return Ok(results);
|
||||||
}
|
/* match f( $( $x, )* ) {
|
||||||
Ok(results) => {
|
Err(error) => {
|
||||||
return Ok(results);
|
dbg!(error);
|
||||||
}
|
return Err(());
|
||||||
|
}
|
||||||
|
Ok(results) => {
|
||||||
|
return Ok(results);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
todo!("dynamic host functions not yet implemented")
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
todo!("host functions not yet implemented")
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -331,7 +331,6 @@ fn function_new_dynamic_env() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: unignore this when calling host functions has been implemented
|
// TODO: unignore this when calling host functions has been implemented
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn native_function_works() -> Result<()> {
|
fn native_function_works() -> Result<()> {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
|
|||||||
Reference in New Issue
Block a user