mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 22:21:32 +00:00
Func::new_polymorphic
This commit is contained in:
@ -1,6 +1,13 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
compile_with, error::RuntimeError, imports, memory::Memory, typed_func::Func,
|
compile_with,
|
||||||
types::MemoryDescriptor, units::Pages, vm, Instance,
|
error::RuntimeError,
|
||||||
|
imports,
|
||||||
|
memory::Memory,
|
||||||
|
typed_func::Func,
|
||||||
|
types::{FuncSig, MemoryDescriptor, Type, Value},
|
||||||
|
units::Pages,
|
||||||
|
vm, Instance,
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core_tests::{get_compiler, wat2wasm};
|
use wasmer_runtime_core_tests::{get_compiler, wat2wasm};
|
||||||
|
|
||||||
@ -68,6 +75,7 @@ fn imported_functions_forms(test: &dyn Fn(&Instance)) {
|
|||||||
(import "env" "memory" (memory 1 1))
|
(import "env" "memory" (memory 1 1))
|
||||||
(import "env" "callback_fn" (func $callback_fn (type $type)))
|
(import "env" "callback_fn" (func $callback_fn (type $type)))
|
||||||
(import "env" "callback_closure" (func $callback_closure (type $type)))
|
(import "env" "callback_closure" (func $callback_closure (type $type)))
|
||||||
|
(import "env" "callback_closure_polymorphic" (func $callback_closure_polymorphic (type $type)))
|
||||||
(import "env" "callback_closure_with_env" (func $callback_closure_with_env (type $type)))
|
(import "env" "callback_closure_with_env" (func $callback_closure_with_env (type $type)))
|
||||||
(import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type)))
|
(import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type)))
|
||||||
(import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type)))
|
(import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type)))
|
||||||
@ -86,6 +94,10 @@ fn imported_functions_forms(test: &dyn Fn(&Instance)) {
|
|||||||
get_local 0
|
get_local 0
|
||||||
call $callback_closure)
|
call $callback_closure)
|
||||||
|
|
||||||
|
(func (export "function_closure_polymorphic") (type $type)
|
||||||
|
get_local 0
|
||||||
|
call $callback_closure_polymorphic)
|
||||||
|
|
||||||
(func (export "function_closure_with_env") (type $type)
|
(func (export "function_closure_with_env") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_closure_with_env)
|
call $callback_closure_with_env)
|
||||||
@ -142,6 +154,16 @@ fn imported_functions_forms(test: &dyn Fn(&Instance)) {
|
|||||||
Ok(n + 1)
|
Ok(n + 1)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
"callback_closure_polymorphic" => Func::<i32, i32, _>::new_polymorphic(
|
||||||
|
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
||||||
|
|_, params| -> Vec<Value> {
|
||||||
|
match params[0] {
|
||||||
|
Value::I32(x) => vec![Value::I32(x + 1)],
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
// Closure with a captured environment (a single variable + an instance of `Memory`).
|
// Closure with a captured environment (a single variable + an instance of `Memory`).
|
||||||
"callback_closure_with_env" => Func::new(move |n: i32| -> Result<i32, ()> {
|
"callback_closure_with_env" => Func::new(move |n: i32| -> Result<i32, ()> {
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
@ -236,6 +258,11 @@ macro_rules! test {
|
|||||||
|
|
||||||
test!(test_fn, function_fn, Ok(2));
|
test!(test_fn, function_fn, Ok(2));
|
||||||
test!(test_closure, function_closure, Ok(2));
|
test!(test_closure, function_closure, Ok(2));
|
||||||
|
test!(
|
||||||
|
test_closure_polymorphic,
|
||||||
|
function_closure_polymorphic,
|
||||||
|
Ok(2)
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_with_env,
|
test_closure_with_env,
|
||||||
function_closure_with_env,
|
function_closure_with_env,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
//! The loader module functions are used to load an instance.
|
//! The loader module functions are used to load an instance.
|
||||||
use crate::{backend::RunnableModule, module::ModuleInfo, types::Type, types::Value, vm::Ctx};
|
use crate::{backend::RunnableModule, module::ModuleInfo, types::Type, types::Value, vm::Ctx};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use libc::{mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE};
|
use libc::{
|
||||||
|
mmap, mprotect, munmap, MAP_ANON, MAP_NORESERVE, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
@ -169,7 +171,7 @@ impl CodeMemory {
|
|||||||
std::ptr::null_mut(),
|
std::ptr::null_mut(),
|
||||||
size,
|
size,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_PRIVATE | MAP_ANON,
|
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
@ -196,6 +198,20 @@ impl CodeMemory {
|
|||||||
panic!("cannot set code memory to writable");
|
panic!("cannot set code memory to writable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes this code memory both writable and executable.
|
||||||
|
///
|
||||||
|
/// Avoid using this if a combination `make_executable` and `make_writable` can be used.
|
||||||
|
pub fn make_writable_executable(&self) {
|
||||||
|
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_WRITE | PROT_EXEC) } != 0 {
|
||||||
|
panic!("cannot set code memory to writable and executable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the backing pointer of this code memory.
|
||||||
|
pub fn get_backing_ptr(&self) -> *mut u8 {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
error::RuntimeError,
|
error::RuntimeError,
|
||||||
export::{Context, Export, FuncPointer},
|
export::{Context, Export, FuncPointer},
|
||||||
import::IsExport,
|
import::IsExport,
|
||||||
types::{FuncSig, NativeWasmType, Type, WasmExternType},
|
types::{FuncSig, NativeWasmType, Type, Value, WasmExternType},
|
||||||
vm,
|
vm,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
@ -240,6 +240,78 @@ where
|
|||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a polymorphic function.
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
|
pub fn new_polymorphic<F>(signature: Arc<FuncSig>, func: F) -> Func<'a, Args, Rets, Host>
|
||||||
|
where
|
||||||
|
F: Fn(&mut vm::Ctx, &[Value]) -> Vec<Value> + 'static,
|
||||||
|
{
|
||||||
|
use crate::trampoline_x64::*;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
struct PolymorphicContext {
|
||||||
|
arg_types: Vec<Type>,
|
||||||
|
func: Box<Fn(&mut vm::Ctx, &[Value]) -> Vec<Value>>,
|
||||||
|
}
|
||||||
|
unsafe extern "C" fn enter_host_polymorphic(
|
||||||
|
ctx: *const CallContext,
|
||||||
|
args: *const u64,
|
||||||
|
) -> u64 {
|
||||||
|
let ctx = &*(ctx as *const PolymorphicContext);
|
||||||
|
let vmctx = &mut *(*args.offset(0) as *mut vm::Ctx);
|
||||||
|
let args: Vec<Value> = ctx
|
||||||
|
.arg_types
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, t)| {
|
||||||
|
let i = i + 1; // skip vmctx
|
||||||
|
match *t {
|
||||||
|
Type::I32 => Value::I32(*args.offset(i as _) as i32),
|
||||||
|
Type::I64 => Value::I64(*args.offset(i as _) as i64),
|
||||||
|
Type::F32 => Value::F32(f32::from_bits(*args.offset(i as _) as u32)),
|
||||||
|
Type::F64 => Value::F64(f64::from_bits(*args.offset(i as _) as u64)),
|
||||||
|
Type::V128 => {
|
||||||
|
panic!("enter_host_polymorphic: 128-bit types are not supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let rets = (ctx.func)(vmctx, &args);
|
||||||
|
if rets.len() == 0 {
|
||||||
|
0
|
||||||
|
} else if rets.len() == 1 {
|
||||||
|
u64::try_from(rets[0].to_u128()).expect(
|
||||||
|
"128-bit return value from polymorphic host functions is not yet supported",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"multiple return values from polymorphic host functions is not yet supported"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut builder = TrampolineBufferBuilder::new();
|
||||||
|
let ctx = Box::new(PolymorphicContext {
|
||||||
|
arg_types: signature.params().to_vec(),
|
||||||
|
func: Box::new(func),
|
||||||
|
});
|
||||||
|
builder.add_callinfo_trampoline(
|
||||||
|
enter_host_polymorphic,
|
||||||
|
Box::into_raw(ctx) as *const _,
|
||||||
|
(signature.params().len() + 1) as u32, // +vmctx
|
||||||
|
);
|
||||||
|
let ptr = builder
|
||||||
|
.append_global()
|
||||||
|
.expect("cannot bump-allocate global trampoline memory");
|
||||||
|
Func {
|
||||||
|
inner: Host(()),
|
||||||
|
func: ptr.cast::<vm::Func>(),
|
||||||
|
func_env: None,
|
||||||
|
vmctx: ptr::null_mut(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Args, Rets, Inner> Func<'a, Args, Rets, Inner>
|
impl<'a, Args, Rets, Inner> Func<'a, Args, Rets, Inner>
|
||||||
|
@ -545,13 +545,13 @@ impl Ctx {
|
|||||||
/// `typed_func` module within the `wrap` functions, to wrap imported
|
/// `typed_func` module within the `wrap` functions, to wrap imported
|
||||||
/// functions.
|
/// functions.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Func(pub(self) *mut c_void);
|
pub struct Func(*mut c_void);
|
||||||
|
|
||||||
/// Represents a function environment pointer, like a captured
|
/// Represents a function environment pointer, like a captured
|
||||||
/// environment of a closure. It is mostly used in the `typed_func`
|
/// environment of a closure. It is mostly used in the `typed_func`
|
||||||
/// module within the `wrap` functions, to wrap imported functions.
|
/// module within the `wrap` functions, to wrap imported functions.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct FuncEnv(pub(self) *mut c_void);
|
pub struct FuncEnv(*mut c_void);
|
||||||
|
|
||||||
/// Represents a function context. It is used by imported functions
|
/// Represents a function context. It is used by imported functions
|
||||||
/// only.
|
/// only.
|
||||||
|
Reference in New Issue
Block a user