wasmer/lib/runtime/src/instance.rs

358 lines
12 KiB
Rust
Raw Normal View History

2019-01-08 17:09:47 +00:00
use crate::recovery::call_protected;
use crate::{
backing::{ImportBacking, LocalBacking},
error::{CallError, CallResult, Result},
2019-01-13 22:45:36 +00:00
export::{
Context, Export, ExportIter, FuncPointer, GlobalPointer, MemoryPointer, TablePointer,
},
2019-01-13 03:02:19 +00:00
import::{Imports, Namespace},
module::{ExportIndex, Module, ModuleInner},
2019-01-13 22:45:36 +00:00
types::{
2019-01-16 18:26:10 +00:00
FuncIndex, FuncSig, GlobalDesc, GlobalIndex, LocalOrImport, Memory, MemoryIndex, Table,
2019-01-13 22:45:36 +00:00
TableIndex, Type, Value,
},
2019-01-08 17:09:47 +00:00
vm,
};
use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr};
2019-01-11 03:59:57 +00:00
use std::rc::Rc;
use std::{iter, mem};
2019-01-08 17:09:47 +00:00
2019-01-13 21:44:14 +00:00
pub(crate) struct InstanceInner {
2019-01-11 03:59:57 +00:00
#[allow(dead_code)]
2019-01-08 17:09:47 +00:00
pub(crate) backing: LocalBacking,
import_backing: ImportBacking,
2019-01-11 03:59:57 +00:00
vmctx: Box<vm::Ctx>,
2019-01-08 17:09:47 +00:00
}
2019-01-12 22:52:14 +00:00
pub struct Instance {
2019-01-17 18:55:25 +00:00
pub module: Rc<ModuleInner>,
2019-01-12 22:52:14 +00:00
inner: Box<InstanceInner>,
2019-01-17 22:13:28 +00:00
#[allow(dead_code)]
imports: Box<Imports>,
2019-01-12 22:52:14 +00:00
}
2019-01-08 17:09:47 +00:00
impl Instance {
pub(crate) fn new(module: Rc<ModuleInner>, mut imports: Box<Imports>) -> Result<Instance> {
2019-01-11 03:59:57 +00:00
// We need the backing and import_backing to create a vm::Ctx, but we need
// a vm::Ctx to create a backing and an import_backing. The solution is to create an
// uninitialized vm::Ctx and then initialize it in-place.
let mut vmctx = unsafe { Box::new(mem::uninitialized()) };
2019-01-08 17:09:47 +00:00
2019-01-17 22:13:28 +00:00
let import_backing = ImportBacking::new(&module, &mut imports, &mut *vmctx)?;
2019-01-11 03:59:57 +00:00
let backing = LocalBacking::new(&module, &import_backing, &mut *vmctx);
2019-01-08 17:09:47 +00:00
2019-01-11 03:59:57 +00:00
// When Pin is stablized, this will use `Box::pinned` instead of `Box::new`.
2019-01-12 22:52:14 +00:00
let mut inner = Box::new(InstanceInner {
2019-01-08 17:09:47 +00:00
backing,
import_backing,
2019-01-11 03:59:57 +00:00
vmctx,
2019-01-08 17:09:47 +00:00
});
2019-01-12 23:02:47 +00:00
// Initialize the vm::Ctx in-place after the backing
2019-01-11 03:59:57 +00:00
// has been boxed.
2019-01-13 03:02:19 +00:00
*inner.vmctx = unsafe { vm::Ctx::new(&mut inner.backing, &mut inner.import_backing) };
2019-01-12 22:52:14 +00:00
2019-01-17 22:13:28 +00:00
let mut instance = Instance {
module,
inner,
imports,
};
2019-01-11 03:59:57 +00:00
if let Some(start_index) = instance.module.start_func {
2019-01-08 17:09:47 +00:00
instance.call_with_index(start_index, &[])?;
}
Ok(instance)
}
/// Call an exported webassembly function given the export name.
/// Pass arguments by wrapping each one in the `Value` enum.
/// The returned value is also returned in a `Value`.
2019-01-08 17:09:47 +00:00
///
/// This will eventually return `Result<Option<Vec<Value>>, String>` in
2019-01-08 17:09:47 +00:00
/// order to support multi-value returns.
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Option<Value>> {
let export_index =
self.module
.exports
.get(name)
.ok_or_else(|| CallError::NoSuchExport {
name: name.to_string(),
})?;
2019-01-11 03:59:57 +00:00
let func_index = if let ExportIndex::Func(func_index) = export_index {
*func_index
} else {
return Err(CallError::ExportNotFunc {
name: name.to_string(),
}
.into());
2019-01-11 03:59:57 +00:00
};
2019-01-08 17:09:47 +00:00
self.call_with_index(func_index, args)
}
2019-01-13 21:44:14 +00:00
pub fn exports(&mut self) -> ExportIter {
ExportIter::new(&self.module, &mut self.inner)
2019-01-12 22:52:14 +00:00
}
2019-01-13 03:02:19 +00:00
pub fn module(&self) -> Module {
Module::new(Rc::clone(&self.module))
}
2019-01-12 22:52:14 +00:00
}
impl Instance {
2019-01-08 17:09:47 +00:00
fn call_with_index(
&mut self,
func_index: FuncIndex,
args: &[Value],
) -> CallResult<Option<Value>> {
2019-01-13 21:44:14 +00:00
let (func_ref, ctx, signature) = self.inner.get_func_from_index(&self.module, func_index);
2019-01-08 17:09:47 +00:00
2019-01-11 03:59:57 +00:00
let func_ptr = CodePtr::from_ptr(func_ref.inner() as _);
let vmctx_ptr = match ctx {
Context::External(vmctx) => vmctx,
2019-01-12 22:52:14 +00:00
Context::Internal => &mut *self.inner.vmctx,
2019-01-11 03:59:57 +00:00
};
assert!(
signature.returns.len() <= 1,
"multi-value returns not yet supported"
);
2019-01-08 17:09:47 +00:00
2019-01-11 03:59:57 +00:00
if !signature.check_sig(args) {
Err(CallError::Signature {
expected: signature.clone(),
found: args.iter().map(|val| val.ty()).collect(),
})?
2019-01-11 03:59:57 +00:00
}
2019-01-08 17:09:47 +00:00
let libffi_args: Vec<_> = args
.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();
call_protected(|| {
2019-01-11 03:59:57 +00:00
signature
2019-01-08 17:09:47 +00:00
.returns
.first()
.map(|ty| match ty {
Type::I32 => Value::I32(unsafe { libffi_call(func_ptr, &libffi_args) }),
Type::I64 => Value::I64(unsafe { libffi_call(func_ptr, &libffi_args) }),
Type::F32 => Value::F32(unsafe { libffi_call(func_ptr, &libffi_args) }),
Type::F64 => Value::F64(unsafe { libffi_call(func_ptr, &libffi_args) }),
})
.or_else(|| {
// call with no returns
unsafe {
libffi_call::<()>(func_ptr, &libffi_args);
}
None
})
})
.map_err(|e| CallError::Runtime(e).into())
2019-01-08 17:09:47 +00:00
}
2019-01-13 21:44:14 +00:00
}
2019-01-11 03:59:57 +00:00
2019-01-13 21:44:14 +00:00
impl InstanceInner {
pub(crate) fn get_export_from_index(
&mut self,
module: &ModuleInner,
export_index: &ExportIndex,
) -> Export {
2019-01-11 03:59:57 +00:00
match export_index {
ExportIndex::Func(func_index) => {
2019-01-13 21:44:14 +00:00
let (func, ctx, signature) = self.get_func_from_index(module, *func_index);
2019-01-11 03:59:57 +00:00
Export::Function {
func,
ctx: match ctx {
2019-01-13 21:52:25 +00:00
Context::Internal => Context::External(&mut *self.vmctx),
2019-01-11 03:59:57 +00:00
ctx @ Context::External(_) => ctx,
},
signature,
}
}
2019-01-12 20:34:23 +00:00
ExportIndex::Memory(memory_index) => {
2019-01-13 21:44:14 +00:00
let (local, ctx, memory) = self.get_memory_from_index(module, *memory_index);
2019-01-12 20:34:23 +00:00
Export::Memory {
local,
ctx: match ctx {
2019-01-13 21:52:25 +00:00
Context::Internal => Context::External(&mut *self.vmctx),
2019-01-12 20:34:23 +00:00
ctx @ Context::External(_) => ctx,
},
memory,
}
}
2019-01-13 22:45:36 +00:00
ExportIndex::Global(global_index) => {
let (local, global) = self.get_global_from_index(module, *global_index);
Export::Global { local, global }
}
2019-01-13 16:46:04 +00:00
ExportIndex::Table(table_index) => {
2019-01-13 21:52:25 +00:00
let (local, ctx, table) = self.get_table_from_index(module, *table_index);
2019-01-13 16:46:04 +00:00
Export::Table {
local,
ctx: match ctx {
2019-01-13 21:52:25 +00:00
Context::Internal => Context::External(&mut *self.vmctx),
2019-01-13 16:46:04 +00:00
ctx @ Context::External(_) => ctx,
},
table,
}
2019-01-13 21:52:25 +00:00
}
2019-01-11 03:59:57 +00:00
}
}
2019-01-13 21:44:14 +00:00
fn get_func_from_index(
&mut self,
module: &ModuleInner,
func_index: FuncIndex,
) -> (FuncPointer, Context, FuncSig) {
let sig_index = *module
2019-01-11 03:59:57 +00:00
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");
2019-01-16 18:26:10 +00:00
let (func_ptr, ctx) = match func_index.local_or_import(module) {
LocalOrImport::Local(local_func_index) => (
2019-01-13 21:44:14 +00:00
module
2019-01-11 03:59:57 +00:00
.func_resolver
2019-01-16 18:26:10 +00:00
.get(&module, local_func_index)
2019-01-11 03:59:57 +00:00
.expect("broken invariant, func resolver not synced with module.exports")
.cast()
.as_ptr() as *const _,
Context::Internal,
2019-01-16 18:26:10 +00:00
),
LocalOrImport::Import(imported_func_index) => {
let imported_func = &self.import_backing.functions[imported_func_index];
(
imported_func.func as *const _,
Context::External(imported_func.vmctx),
)
}
2019-01-11 03:59:57 +00:00
};
2019-01-13 21:44:14 +00:00
let signature = module.sig_registry.lookup_func_sig(sig_index).clone();
2019-01-11 03:59:57 +00:00
2019-01-12 22:52:14 +00:00
(unsafe { FuncPointer::new(func_ptr) }, ctx, signature)
2019-01-11 03:59:57 +00:00
}
2019-01-12 20:34:23 +00:00
2019-01-13 21:44:14 +00:00
fn get_memory_from_index(
&mut self,
module: &ModuleInner,
mem_index: MemoryIndex,
) -> (MemoryPointer, Context, Memory) {
2019-01-16 18:26:10 +00:00
match mem_index.local_or_import(module) {
LocalOrImport::Local(local_mem_index) => {
let vm_mem = &mut self.backing.memories[local_mem_index];
(
2019-01-17 21:09:05 +00:00
unsafe { MemoryPointer::new(&mut vm_mem.into_vm_memory(local_mem_index)) },
2019-01-16 18:26:10 +00:00
Context::Internal,
*module
.memories
.get(local_mem_index)
.expect("broken invariant, memories"),
)
}
LocalOrImport::Import(imported_mem_index) => {
let &(_, mem) = &module
.imported_memories
.get(imported_mem_index)
.expect("missing imported memory index");
let vm::ImportedMemory { memory, vmctx } =
&self.import_backing.memories[imported_mem_index];
(
unsafe { MemoryPointer::new(*memory) },
Context::External(*vmctx),
*mem,
)
}
2019-01-12 20:34:23 +00:00
}
}
2019-01-13 16:46:04 +00:00
2019-01-13 22:45:36 +00:00
fn get_global_from_index(
&mut self,
module: &ModuleInner,
global_index: GlobalIndex,
) -> (GlobalPointer, GlobalDesc) {
2019-01-16 18:26:10 +00:00
match global_index.local_or_import(module) {
LocalOrImport::Local(local_global_index) => {
let vm_global = &mut self.backing.vm_globals[local_global_index];
(
unsafe { GlobalPointer::new(vm_global) },
module
.globals
.get(local_global_index)
.expect("broken invariant, globals")
.desc,
)
}
LocalOrImport::Import(imported_global_index) => {
2019-01-17 01:59:12 +00:00
let &(_, imported_global_desc) = &module
2019-01-16 18:26:10 +00:00
.imported_globals
.get(imported_global_index)
.expect("missing imported global index");
let vm::ImportedGlobal { global } =
&self.import_backing.globals[imported_global_index];
2019-01-17 01:59:12 +00:00
(
unsafe { GlobalPointer::new(*global) },
*imported_global_desc,
)
2019-01-16 18:26:10 +00:00
}
2019-01-13 22:45:36 +00:00
}
}
2019-01-13 21:52:25 +00:00
fn get_table_from_index(
&mut self,
module: &ModuleInner,
table_index: TableIndex,
) -> (TablePointer, Context, Table) {
2019-01-16 18:26:10 +00:00
match table_index.local_or_import(module) {
LocalOrImport::Local(local_table_index) => {
let vm_table = &mut self.backing.tables[local_table_index];
(
unsafe { TablePointer::new(&mut vm_table.into_vm_table()) },
Context::Internal,
*module
.tables
.get(local_table_index)
.expect("broken invariant, tables"),
)
}
LocalOrImport::Import(imported_table_index) => {
let &(_, tab) = &module
.imported_tables
.get(imported_table_index)
.expect("missing imported table index");
let vm::ImportedTable { table, vmctx } =
&self.import_backing.tables[imported_table_index];
(
unsafe { TablePointer::new(*table) },
Context::External(*vmctx),
*tab,
)
}
2019-01-13 16:46:04 +00:00
}
}
2019-01-08 17:09:47 +00:00
}
2019-01-12 22:52:14 +00:00
impl Namespace for Instance {
2019-01-13 21:44:14 +00:00
fn get_export(&mut self, name: &str) -> Option<Export> {
2019-01-12 21:24:17 +00:00
let export_index = self.module.exports.get(name)?;
2019-01-13 21:44:14 +00:00
Some(self.inner.get_export_from_index(&self.module, export_index))
2019-01-12 21:24:17 +00:00
}
}
2019-01-10 01:45:48 +00:00
// TODO Remove this later, only needed for compilation till emscripten is updated
impl Instance {
2019-01-11 16:10:59 +00:00
pub fn memory_offset_addr(&self, index: usize, offset: usize) -> *const u8 {
2019-01-16 11:41:06 +00:00
unimplemented!()
2019-01-10 01:45:48 +00:00
}
}