mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 14:11:32 +00:00
Func::new_polymorphic
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
//! The loader module functions are used to load an instance.
|
||||
use crate::{backend::RunnableModule, module::ModuleInfo, types::Type, types::Value, vm::Ctx};
|
||||
#[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::{
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
@ -169,7 +171,7 @@ impl CodeMemory {
|
||||
std::ptr::null_mut(),
|
||||
size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
@ -196,6 +198,20 @@ impl CodeMemory {
|
||||
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)]
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
error::RuntimeError,
|
||||
export::{Context, Export, FuncPointer},
|
||||
import::IsExport,
|
||||
types::{FuncSig, NativeWasmType, Type, WasmExternType},
|
||||
types::{FuncSig, NativeWasmType, Type, Value, WasmExternType},
|
||||
vm,
|
||||
};
|
||||
use std::{
|
||||
@ -240,6 +240,78 @@ where
|
||||
_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>
|
||||
|
@ -545,13 +545,13 @@ impl Ctx {
|
||||
/// `typed_func` module within the `wrap` functions, to wrap imported
|
||||
/// functions.
|
||||
#[repr(transparent)]
|
||||
pub struct Func(pub(self) *mut c_void);
|
||||
pub struct Func(*mut c_void);
|
||||
|
||||
/// Represents a function environment pointer, like a captured
|
||||
/// environment of a closure. It is mostly used in the `typed_func`
|
||||
/// module within the `wrap` functions, to wrap imported functions.
|
||||
#[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
|
||||
/// only.
|
||||
|
Reference in New Issue
Block a user