2019-02-07 17:08:42 -08:00
|
|
|
use crate::relocation::{TrapData, TrapSink};
|
2019-01-22 15:00:27 -08:00
|
|
|
use crate::trampoline::Trampolines;
|
2019-01-18 14:30:15 -08:00
|
|
|
use hashbrown::HashSet;
|
2019-02-07 17:08:42 -08:00
|
|
|
use libc::c_void;
|
2019-02-08 13:08:03 -08:00
|
|
|
use std::{cell::Cell, sync::Arc};
|
2019-01-22 13:02:06 -06:00
|
|
|
use wasmer_runtime_core::{
|
2019-02-08 13:08:03 -08:00
|
|
|
backend::{ProtectedCaller, Token, UserTrapper},
|
2019-01-18 14:30:15 -08:00
|
|
|
error::RuntimeResult,
|
2019-01-18 13:29:43 -08:00
|
|
|
export::Context,
|
2019-02-06 16:26:45 -08:00
|
|
|
module::{ExportIndex, ModuleInfo, ModuleInner},
|
2019-01-22 15:00:27 -08:00
|
|
|
types::{FuncIndex, FuncSig, LocalOrImport, SigIndex, Type, Value},
|
2019-01-18 13:29:43 -08:00
|
|
|
vm::{self, ImportBacking},
|
|
|
|
};
|
|
|
|
|
2019-02-07 17:08:42 -08:00
|
|
|
#[cfg(unix)]
|
|
|
|
mod unix;
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
mod windows;
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
pub use self::unix::*;
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
pub use self::windows::*;
|
|
|
|
|
2019-02-08 13:08:03 -08:00
|
|
|
thread_local! {
|
|
|
|
pub static TRAP_EARLY_DATA: Cell<Option<String>> = Cell::new(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Trapper;
|
|
|
|
|
|
|
|
impl UserTrapper for Trapper {
|
|
|
|
unsafe fn do_early_trap(&self, msg: String) -> ! {
|
|
|
|
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
|
|
|
|
trigger_trap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 13:29:43 -08:00
|
|
|
pub struct Caller {
|
|
|
|
func_export_set: HashSet<FuncIndex>,
|
2019-01-18 16:45:30 -08:00
|
|
|
handler_data: HandlerData,
|
2019-02-19 09:58:01 -08:00
|
|
|
trampolines: Arc<Trampolines>,
|
2019-01-18 13:29:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Caller {
|
2019-02-19 09:58:01 -08:00
|
|
|
pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Arc<Trampolines>) -> 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-22 15:00:27 -08:00
|
|
|
trampolines,
|
2019-01-18 16:45:30 -08:00
|
|
|
}
|
2019-01-18 13:29:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProtectedCaller for Caller {
|
|
|
|
fn call(
|
|
|
|
&self,
|
|
|
|
module: &ModuleInner,
|
|
|
|
func_index: FuncIndex,
|
|
|
|
params: &[Value],
|
|
|
|
import_backing: &ImportBacking,
|
|
|
|
vmctx: *mut vm::Ctx,
|
|
|
|
_: Token,
|
2019-01-22 15:00:27 -08:00
|
|
|
) -> RuntimeResult<Vec<Value>> {
|
|
|
|
let (func_ptr, ctx, signature, sig_index) =
|
|
|
|
get_func_from_index(&module, import_backing, func_index);
|
2019-01-18 13:29:43 -08:00
|
|
|
|
|
|
|
let vmctx_ptr = match ctx {
|
|
|
|
Context::External(external_vmctx) => external_vmctx,
|
|
|
|
Context::Internal => vmctx,
|
|
|
|
};
|
|
|
|
|
|
|
|
assert!(self.func_export_set.contains(&func_index));
|
|
|
|
|
|
|
|
assert!(
|
2019-01-29 10:16:39 -08:00
|
|
|
signature.returns().len() <= 1,
|
2019-01-18 13:29:43 -08:00
|
|
|
"multi-value returns not yet supported"
|
|
|
|
);
|
|
|
|
|
2019-01-29 10:16:39 -08:00
|
|
|
assert!(
|
|
|
|
signature.check_param_value_types(params),
|
|
|
|
"incorrect signature"
|
|
|
|
);
|
2019-01-18 13:29:43 -08:00
|
|
|
|
2019-01-22 15:00:27 -08:00
|
|
|
let param_vec: Vec<u64> = params
|
2019-01-18 13:29:43 -08:00
|
|
|
.iter()
|
|
|
|
.map(|val| match val {
|
2019-01-22 15:00:27 -08:00
|
|
|
Value::I32(x) => *x as u64,
|
|
|
|
Value::I64(x) => *x as u64,
|
|
|
|
Value::F32(x) => x.to_bits() as u64,
|
|
|
|
Value::F64(x) => x.to_bits(),
|
2019-01-18 13:29:43 -08:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2019-01-29 10:16:39 -08:00
|
|
|
let mut return_vec = vec![0; signature.returns().len()];
|
2019-01-22 15:00:27 -08:00
|
|
|
|
|
|
|
let trampoline = self
|
|
|
|
.trampolines
|
|
|
|
.lookup(sig_index)
|
|
|
|
.expect("that trampoline doesn't exist");
|
|
|
|
|
2019-02-14 09:58:33 -08:00
|
|
|
#[cfg(not(target_os = "windows"))]
|
2019-01-22 15:00:27 -08:00
|
|
|
call_protected(&self.handler_data, || unsafe {
|
|
|
|
// Leap of faith.
|
|
|
|
trampoline(
|
|
|
|
vmctx_ptr,
|
|
|
|
func_ptr,
|
|
|
|
param_vec.as_ptr(),
|
|
|
|
return_vec.as_mut_ptr(),
|
|
|
|
);
|
|
|
|
})?;
|
|
|
|
|
2019-02-14 09:58:33 -08:00
|
|
|
// the trampoline is called from C on windows
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
call_protected(
|
|
|
|
&self.handler_data,
|
|
|
|
trampoline,
|
|
|
|
vmctx_ptr,
|
|
|
|
func_ptr,
|
|
|
|
param_vec.as_ptr(),
|
|
|
|
return_vec.as_mut_ptr(),
|
|
|
|
)?;
|
|
|
|
|
2019-01-22 15:00:27 -08:00
|
|
|
Ok(return_vec
|
|
|
|
.iter()
|
2019-01-29 10:16:39 -08:00
|
|
|
.zip(signature.returns().iter())
|
2019-01-22 15:00:27 -08:00
|
|
|
.map(|(&x, ty)| match ty {
|
|
|
|
Type::I32 => Value::I32(x as i32),
|
|
|
|
Type::I64 => Value::I64(x as i64),
|
|
|
|
Type::F32 => Value::F32(f32::from_bits(x as u32)),
|
|
|
|
Type::F64 => Value::F64(f64::from_bits(x as u64)),
|
|
|
|
})
|
|
|
|
.collect())
|
2019-01-18 13:29:43 -08:00
|
|
|
}
|
2019-02-08 13:08:03 -08:00
|
|
|
|
|
|
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
|
|
|
Box::new(Trapper)
|
|
|
|
}
|
2019-01-18 13:29:43 -08:00
|
|
|
}
|
|
|
|
|
2019-01-29 10:16:39 -08:00
|
|
|
fn get_func_from_index(
|
|
|
|
module: &ModuleInner,
|
2019-01-18 13:29:43 -08:00
|
|
|
import_backing: &ImportBacking,
|
|
|
|
func_index: FuncIndex,
|
2019-01-29 10:16:39 -08:00
|
|
|
) -> (*const vm::Func, Context, Arc<FuncSig>, SigIndex) {
|
2019-01-18 13:29:43 -08:00
|
|
|
let sig_index = *module
|
2019-02-06 16:26:45 -08:00
|
|
|
.info
|
2019-01-18 13:29:43 -08:00
|
|
|
.func_assoc
|
|
|
|
.get(func_index)
|
|
|
|
.expect("broken invariant, incorrect func index");
|
|
|
|
|
2019-02-18 11:56:20 -08:00
|
|
|
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
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),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-06 16:26:45 -08:00
|
|
|
let signature = Arc::clone(&module.info.signatures[sig_index]);
|
2019-01-18 13:29:43 -08:00
|
|
|
|
2019-01-22 15:00:27 -08:00
|
|
|
(func_ptr, ctx, signature, sig_index)
|
2019-01-18 14:30:15 -08:00
|
|
|
}
|
2019-02-07 17:08:42 -08:00
|
|
|
|
|
|
|
unsafe impl Send for HandlerData {}
|
|
|
|
unsafe impl Sync for HandlerData {}
|
|
|
|
|
2019-02-19 09:58:01 -08:00
|
|
|
#[derive(Clone)]
|
2019-02-07 17:08:42 -08:00
|
|
|
pub struct HandlerData {
|
2019-02-19 09:58:01 -08:00
|
|
|
pub trap_data: Arc<TrapSink>,
|
2019-02-07 17:08:42 -08:00
|
|
|
exec_buffer_ptr: *const c_void,
|
|
|
|
exec_buffer_size: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl HandlerData {
|
|
|
|
pub fn new(
|
2019-02-19 09:58:01 -08:00
|
|
|
trap_data: Arc<TrapSink>,
|
2019-02-07 17:08:42 -08:00
|
|
|
exec_buffer_ptr: *const c_void,
|
|
|
|
exec_buffer_size: usize,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
trap_data,
|
|
|
|
exec_buffer_ptr,
|
|
|
|
exec_buffer_size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lookup(&self, ip: *const c_void) -> Option<TrapData> {
|
|
|
|
let ip = ip as usize;
|
|
|
|
let buffer_ptr = self.exec_buffer_ptr as usize;
|
|
|
|
|
|
|
|
if buffer_ptr <= ip && ip < buffer_ptr + self.exec_buffer_size {
|
|
|
|
let offset = ip - buffer_ptr;
|
|
|
|
self.trap_data.lookup(offset)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|