wasmer/lib/runtime-core/src/instance.rs

434 lines
14 KiB
Rust
Raw Normal View History

2019-01-08 17:09:47 +00:00
use crate::{
2019-01-18 20:13:01 +00:00
backend::Token,
2019-01-08 17:09:47 +00:00
backing::{ImportBacking, LocalBacking},
2019-01-23 23:30:35 +00:00
error::{CallError, CallResult, ResolveError, ResolveResult, Result},
2019-01-29 18:16:39 +00:00
export::{Context, Export, ExportIter, FuncPointer},
2019-01-28 19:55:44 +00:00
global::Global,
import::{ImportObject, LikeNamespace},
memory::Memory,
2019-01-13 03:02:19 +00:00
module::{ExportIndex, Module, ModuleInner},
2019-01-29 18:16:39 +00:00
table::Table,
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
2019-01-08 17:09:47 +00:00
vm,
};
2019-01-28 19:55:44 +00:00
use std::{mem, sync::Arc};
2019-01-08 17:09:47 +00:00
2019-01-24 04:38:43 +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-29 18:16:39 +00:00
pub(crate) vmctx: *mut vm::Ctx,
}
impl Drop for InstanceInner {
fn drop(&mut self) {
// Drop the vmctx.
unsafe { Box::from_raw(self.vmctx) };
}
2019-01-08 17:09:47 +00:00
}
/// An instantiated WebAssembly module.
///
/// An `Instance` represents a WebAssembly module that
/// has been instantiated with an [`ImportObject`] and is
/// ready to be called.
///
/// [`ImportObject`]: struct.ImportObject.html
2019-01-12 22:52:14 +00:00
pub struct Instance {
2019-01-28 19:55:44 +00:00
module: Arc<ModuleInner>,
inner: Box<InstanceInner>,
2019-01-17 22:13:28 +00:00
#[allow(dead_code)]
imports: Box<ImportObject>,
2019-01-12 22:52:14 +00:00
}
2019-01-08 17:09:47 +00:00
impl Instance {
2019-01-28 19:55:44 +00:00
pub(crate) fn new(
module: Arc<ModuleInner>,
mut imports: Box<ImportObject>,
) -> 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-29 18:16:39 +00:00
vmctx: Box::leak(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-29 18:16:39 +00:00
unsafe {
*inner.vmctx = vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module)
};
2019-01-12 22:52:14 +00:00
2019-01-29 18:16:39 +00:00
let instance = Instance {
2019-01-17 22:13:28 +00:00
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)
}
2019-01-23 23:30:35 +00:00
/// This returns the representation of a function that can be called
/// safely.
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::Instance;
2019-01-23 23:36:13 +00:00
/// # use wasmer_runtime_core::error::CallResult;
/// # fn call_foo(instance: &mut Instance) -> CallResult<()> {
2019-01-23 23:30:35 +00:00
/// instance
/// .func("foo")?
/// .call(&[])?;
2019-01-23 23:36:13 +00:00
/// # Ok(())
2019-01-23 23:30:35 +00:00
/// # }
/// ```
2019-01-29 18:16:39 +00:00
pub fn func(&self, name: &str) -> ResolveResult<Function> {
2019-01-23 23:30:35 +00:00
let export_index =
self.module
.exports
.get(name)
2019-01-24 00:51:34 +00:00
.ok_or_else(|| ResolveError::ExportNotFound {
2019-01-23 23:30:35 +00:00
name: name.to_string(),
})?;
if let ExportIndex::Func(func_index) = export_index {
let sig_index = *self
.module
.func_assoc
.get(*func_index)
.expect("broken invariant, incorrect func index");
2019-01-29 18:16:39 +00:00
let signature = self.module.sig_registry.lookup_signature(sig_index);
2019-01-23 23:30:35 +00:00
Ok(Function {
signature,
module: &self.module,
2019-01-29 18:16:39 +00:00
instance_inner: &self.inner,
2019-01-23 23:30:35 +00:00
func_index: *func_index,
})
} else {
Err(ResolveError::ExportWrongType {
name: name.to_string(),
}
.into())
}
}
2019-01-08 17:09:47 +00:00
/// Call an exported webassembly function given the export name.
/// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a [`Value`].
2019-01-08 17:09:47 +00:00
///
/// [`Value`]: enum.Value.html
2019-01-08 17:09:47 +00:00
///
/// # Note:
2019-01-18 20:13:01 +00:00
/// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature.
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::types::Value;
/// # use wasmer_runtime_core::error::Result;
/// # use wasmer_runtime_core::Instance;
/// # fn call_foo(instance: &mut Instance) -> Result<()> {
/// // ...
/// let results = instance.call("foo", &[Value::I32(42)])?;
/// // ...
/// # Ok(())
/// # }
/// ```
2019-01-29 18:16:39 +00:00
pub fn call(&self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
let export_index =
self.module
.exports
.get(name)
2019-01-24 00:51:34 +00:00
.ok_or_else(|| ResolveError::ExportNotFound {
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 {
2019-01-23 23:30:35 +00:00
return Err(CallError::Resolve(ResolveError::ExportWrongType {
name: name.to_string(),
2019-01-23 23:30:35 +00:00
})
.into());
2019-01-11 03:59:57 +00:00
};
2019-01-08 17:09:47 +00:00
self.call_with_index(func_index, args)
}
/// Returns a immutable reference to the
/// [`Ctx`] used by this Instance.
///
/// [`Ctx`]: struct.Ctx.html
pub fn context(&self) -> &vm::Ctx {
2019-01-29 18:16:39 +00:00
unsafe { &*self.inner.vmctx }
}
/// Returns a mutable reference to the
/// [`Ctx`] used by this Instance.
///
/// [`Ctx`]: struct.Ctx.html
pub fn context_mut(&mut self) -> &mut vm::Ctx {
2019-01-29 18:16:39 +00:00
unsafe { &mut *self.inner.vmctx }
}
/// Returns a iterator over all of the items
/// exported from this instance.
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
/// The module used to instantiate this Instance.
2019-01-13 03:02:19 +00:00
pub fn module(&self) -> Module {
2019-01-28 19:55:44 +00:00
Module::new(Arc::clone(&self.module))
2019-01-13 03:02:19 +00:00
}
pub fn ctx(&mut self) -> &mut vm::Ctx {
&mut self.inner.vmctx
}
2019-01-12 22:52:14 +00:00
}
impl Instance {
2019-01-29 18:16:39 +00:00
fn call_with_index(&self, func_index: FuncIndex, args: &[Value]) -> CallResult<Vec<Value>> {
2019-01-18 20:13:01 +00:00
let sig_index = *self
.module
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");
2019-01-29 18:16:39 +00:00
let signature = self.module.sig_registry.lookup_signature(sig_index);
2019-01-08 17:09:47 +00:00
2019-01-29 18:16:39 +00:00
if !signature.check_param_value_types(args) {
2019-01-23 23:30:35 +00:00
Err(ResolveError::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
2019-01-18 20:13:01 +00:00
let vmctx = match func_index.local_or_import(&self.module) {
2019-01-29 18:16:39 +00:00
LocalOrImport::Local(_) => self.inner.vmctx,
2019-01-18 20:13:01 +00:00
LocalOrImport::Import(imported_func_index) => {
self.inner.import_backing.vm_functions[imported_func_index].vmctx
2019-01-18 20:13:01 +00:00
}
};
let token = Token::generate();
let returns = self.module.protected_caller.call(
2019-01-18 20:13:01 +00:00
&self.module,
func_index,
args,
&self.inner.import_backing,
2019-01-18 20:13:01 +00:00
vmctx,
token,
)?;
Ok(returns)
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(
2019-01-29 18:16:39 +00:00
&self,
2019-01-13 21:44:14 +00:00
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-29 18:16:39 +00:00
Context::Internal => Context::External(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) => {
let memory = self.get_memory_from_index(module, *memory_index);
Export::Memory(memory)
2019-01-12 20:34:23 +00:00
}
2019-01-13 22:45:36 +00:00
ExportIndex::Global(global_index) => {
2019-01-28 19:55:44 +00:00
let global = self.get_global_from_index(module, *global_index);
Export::Global(global)
2019-01-13 22:45:36 +00:00
}
2019-01-13 16:46:04 +00:00
ExportIndex::Table(table_index) => {
2019-01-29 18:16:39 +00:00
let table = self.get_table_from_index(module, *table_index);
Export::Table(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(
2019-01-29 18:16:39 +00:00
&self,
2019-01-13 21:44:14 +00:00
module: &ModuleInner,
func_index: FuncIndex,
2019-01-29 18:16:39 +00:00
) -> (FuncPointer, Context, Arc<FuncSig>) {
2019-01-13 21:44:14 +00:00
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.vm_functions[imported_func_index];
2019-01-16 18:26:10 +00:00
(
imported_func.func as *const _,
Context::External(imported_func.vmctx),
)
}
2019-01-11 03:59:57 +00:00
};
2019-01-29 18:16:39 +00:00
let signature = module.sig_registry.lookup_signature(sig_index);
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-29 18:16:39 +00:00
fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory {
2019-01-16 18:26:10 +00:00
match mem_index.local_or_import(module) {
LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(),
2019-01-16 18:26:10 +00:00
LocalOrImport::Import(imported_mem_index) => {
self.import_backing.memories[imported_mem_index].clone()
2019-01-16 18:26:10 +00:00
}
2019-01-12 20:34:23 +00:00
}
}
2019-01-13 16:46:04 +00:00
2019-01-29 18:16:39 +00:00
fn get_global_from_index(&self, module: &ModuleInner, global_index: GlobalIndex) -> Global {
2019-01-16 18:26:10 +00:00
match global_index.local_or_import(module) {
LocalOrImport::Local(local_global_index) => {
2019-01-28 19:55:44 +00:00
self.backing.globals[local_global_index].clone()
2019-01-16 18:26:10 +00:00
}
2019-01-28 19:55:44 +00:00
LocalOrImport::Import(import_global_index) => {
self.import_backing.globals[import_global_index].clone()
2019-01-16 18:26:10 +00:00
}
2019-01-13 22:45:36 +00:00
}
}
2019-01-29 18:16:39 +00:00
fn get_table_from_index(&self, module: &ModuleInner, table_index: TableIndex) -> Table {
2019-01-16 18:26:10 +00:00
match table_index.local_or_import(module) {
LocalOrImport::Local(local_table_index) => {
2019-01-29 18:16:39 +00:00
self.backing.tables[local_table_index].clone()
2019-01-16 18:26:10 +00:00
}
LocalOrImport::Import(imported_table_index) => {
2019-01-29 18:16:39 +00:00
self.import_backing.tables[imported_table_index].clone()
2019-01-16 18:26:10 +00:00
}
2019-01-13 16:46:04 +00:00
}
}
2019-01-08 17:09:47 +00:00
}
impl LikeNamespace 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-23 23:30:35 +00:00
/// A representation of an exported WebAssembly function.
pub struct Function<'a> {
2019-01-29 18:16:39 +00:00
pub(crate) signature: Arc<FuncSig>,
2019-01-23 23:30:35 +00:00
module: &'a ModuleInner,
2019-01-29 18:16:39 +00:00
pub(crate) instance_inner: &'a InstanceInner,
2019-01-23 23:30:35 +00:00
func_index: FuncIndex,
}
impl<'a> Function<'a> {
/// Call an exported webassembly function safely.
///
/// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a [`Value`].
///
/// [`Value`]: enum.Value.html
///
/// # Note:
/// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature.
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::Instance;
2019-01-23 23:36:13 +00:00
/// # use wasmer_runtime_core::error::CallResult;
/// # fn call_foo(instance: &mut Instance) -> CallResult<()> {
2019-01-23 23:30:35 +00:00
/// instance
/// .func("foo")?
/// .call(&[])?;
2019-01-23 23:36:13 +00:00
/// # Ok(())
2019-01-23 23:30:35 +00:00
/// # }
/// ```
pub fn call(&mut self, params: &[Value]) -> CallResult<Vec<Value>> {
2019-01-29 18:16:39 +00:00
if !self.signature.check_param_value_types(params) {
2019-01-23 23:30:35 +00:00
Err(ResolveError::Signature {
expected: self.signature.clone(),
found: params.iter().map(|val| val.ty()).collect(),
})?
}
let vmctx = match self.func_index.local_or_import(self.module) {
2019-01-29 18:16:39 +00:00
LocalOrImport::Local(_) => self.instance_inner.vmctx,
2019-01-23 23:30:35 +00:00
LocalOrImport::Import(imported_func_index) => {
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
2019-01-23 23:30:35 +00:00
}
};
let token = Token::generate();
let returns = self.module.protected_caller.call(
&self.module,
self.func_index,
params,
&self.instance_inner.import_backing,
vmctx,
token,
)?;
Ok(returns)
}
pub fn signature(&self) -> &FuncSig {
2019-01-29 18:16:39 +00:00
&*self.signature
2019-01-23 23:30:35 +00:00
}
pub fn raw(&self) -> *const vm::Func {
match self.func_index.local_or_import(self.module) {
LocalOrImport::Local(local_func_index) => self
.module
.func_resolver
.get(self.module, local_func_index)
.unwrap()
.as_ptr(),
LocalOrImport::Import(import_func_index) => {
self.instance_inner.import_backing.vm_functions[import_func_index].func
2019-01-23 23:30:35 +00:00
}
}
}
}
#[doc(hidden)]
2019-01-10 01:45:48 +00:00
impl Instance {
pub fn memory_offset_addr(&self, _: u32, _: usize) -> *const u8 {
2019-01-16 11:41:06 +00:00
unimplemented!()
2019-01-10 01:45:48 +00:00
}
}