Func::new_polymorphic

This commit is contained in:
losfair
2020-02-15 01:31:49 +08:00
parent 2fe6e6f039
commit 12373bb872
4 changed files with 122 additions and 7 deletions

View File

@ -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)]

View File

@ -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>

View File

@ -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.