2019-01-18 13:29:43 -08:00
|
|
|
mod recovery;
|
|
|
|
mod sighandler;
|
|
|
|
|
2019-01-18 16:45:30 -08:00
|
|
|
pub use self::recovery::HandlerData;
|
|
|
|
|
2019-01-18 13:29:43 -08:00
|
|
|
use crate::call::recovery::call_protected;
|
2019-01-18 14:30:15 -08:00
|
|
|
use hashbrown::HashSet;
|
|
|
|
use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr};
|
|
|
|
use std::iter;
|
2019-01-22 13:02:06 -06:00
|
|
|
use wasmer_runtime_core::{
|
2019-01-18 14:30:15 -08:00
|
|
|
backend::{ProtectedCaller, Token},
|
|
|
|
error::RuntimeResult,
|
2019-01-18 13:29:43 -08:00
|
|
|
export::Context,
|
2019-01-18 14:30:15 -08:00
|
|
|
module::{ExportIndex, ModuleInner},
|
|
|
|
types::{FuncIndex, FuncSig, LocalOrImport, Type, Value},
|
2019-01-18 13:29:43 -08:00
|
|
|
vm::{self, ImportBacking},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct Caller {
|
|
|
|
func_export_set: HashSet<FuncIndex>,
|
2019-01-18 16:45:30 -08:00
|
|
|
handler_data: HandlerData,
|
2019-01-18 13:29:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Caller {
|
2019-01-18 16:45:30 -08:00
|
|
|
pub fn new(module: &ModuleInner, handler_data: HandlerData) -> Self {
|
2019-01-18 14:30:15 -08:00
|
|
|
let mut func_export_set = HashSet::new();
|
|
|
|
for export_index in module.exports.values() {
|
|
|
|
if let ExportIndex::Func(func_index) = export_index {
|
|
|
|
func_export_set.insert(*func_index);
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 14:53:46 -08:00
|
|
|
if let Some(start_func_index) = module.start_func {
|
|
|
|
func_export_set.insert(start_func_index);
|
|
|
|
}
|
2019-01-18 14:30:15 -08:00
|
|
|
|
2019-01-18 16:45:30 -08:00
|
|
|
Self {
|
|
|
|
func_export_set,
|
|
|
|
handler_data,
|
|
|
|
}
|
2019-01-18 13:29:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProtectedCaller for Caller {
|
|
|
|
fn call(
|
|
|
|
&self,
|
|
|
|
module: &ModuleInner,
|
|
|
|
func_index: FuncIndex,
|
|
|
|
params: &[Value],
|
|
|
|
returns: &mut [Value],
|
|
|
|
import_backing: &ImportBacking,
|
|
|
|
vmctx: *mut vm::Ctx,
|
|
|
|
_: Token,
|
|
|
|
) -> RuntimeResult<()> {
|
|
|
|
let (func_ptr, ctx, signature) = get_func_from_index(&module, import_backing, func_index);
|
|
|
|
|
|
|
|
let vmctx_ptr = match ctx {
|
|
|
|
Context::External(external_vmctx) => external_vmctx,
|
|
|
|
Context::Internal => vmctx,
|
|
|
|
};
|
|
|
|
|
|
|
|
assert!(self.func_export_set.contains(&func_index));
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
returns.len() == signature.returns.len() && signature.returns.len() <= 1,
|
|
|
|
"multi-value returns not yet supported"
|
|
|
|
);
|
|
|
|
|
|
|
|
assert!(signature.check_sig(params), "incorrect signature");
|
|
|
|
|
|
|
|
let libffi_args: Vec<_> = params
|
|
|
|
.iter()
|
|
|
|
.map(|val| match val {
|
|
|
|
Value::I32(ref x) => libffi_arg(x),
|
|
|
|
Value::I64(ref x) => libffi_arg(x),
|
|
|
|
Value::F32(ref x) => libffi_arg(x),
|
|
|
|
Value::F64(ref x) => libffi_arg(x),
|
|
|
|
})
|
|
|
|
.chain(iter::once(libffi_arg(&vmctx_ptr)))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let code_ptr = CodePtr::from_ptr(func_ptr as _);
|
|
|
|
|
2019-01-18 16:45:30 -08:00
|
|
|
call_protected(&self.handler_data, || {
|
2019-01-18 13:29:43 -08:00
|
|
|
// Only supports zero or one return values for now.
|
2019-01-18 14:30:15 -08:00
|
|
|
// To support multiple returns, we will have to
|
2019-01-18 13:29:43 -08:00
|
|
|
// generate trampolines instead of using libffi.
|
|
|
|
match signature.returns.first() {
|
|
|
|
Some(ty) => {
|
|
|
|
let val = match ty {
|
|
|
|
Type::I32 => Value::I32(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
|
|
|
Type::I64 => Value::I64(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
|
|
|
Type::F32 => Value::F32(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
|
|
|
Type::F64 => Value::F64(unsafe { libffi_call(code_ptr, &libffi_args) }),
|
|
|
|
};
|
|
|
|
returns[0] = val;
|
2019-01-18 14:30:15 -08:00
|
|
|
}
|
2019-01-18 13:29:43 -08:00
|
|
|
// call with no returns
|
|
|
|
None => unsafe {
|
|
|
|
libffi_call::<()>(code_ptr, &libffi_args);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_func_from_index<'a>(
|
|
|
|
module: &'a ModuleInner,
|
|
|
|
import_backing: &ImportBacking,
|
|
|
|
func_index: FuncIndex,
|
|
|
|
) -> (*const vm::Func, Context, &'a FuncSig) {
|
|
|
|
let sig_index = *module
|
|
|
|
.func_assoc
|
|
|
|
.get(func_index)
|
|
|
|
.expect("broken invariant, incorrect func index");
|
|
|
|
|
|
|
|
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
2019-01-18 14:30:15 -08:00
|
|
|
LocalOrImport::Local(local_func_index) => (
|
|
|
|
module
|
|
|
|
.func_resolver
|
|
|
|
.get(&module, local_func_index)
|
|
|
|
.expect("broken invariant, func resolver not synced with module.exports")
|
|
|
|
.cast()
|
|
|
|
.as_ptr() as *const _,
|
|
|
|
Context::Internal,
|
|
|
|
),
|
2019-01-18 13:29:43 -08:00
|
|
|
LocalOrImport::Import(imported_func_index) => {
|
|
|
|
let imported_func = import_backing.imported_func(imported_func_index);
|
|
|
|
(
|
|
|
|
imported_func.func as *const _,
|
|
|
|
Context::External(imported_func.vmctx),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let signature = module.sig_registry.lookup_func_sig(sig_index);
|
|
|
|
|
|
|
|
(func_ptr, ctx, signature)
|
2019-01-18 14:30:15 -08:00
|
|
|
}
|