Merge branch 'master' into fix/emscripten-translate

This commit is contained in:
Brandon Fish
2019-01-23 22:57:00 -06:00
20 changed files with 521 additions and 120 deletions

View File

@ -1,7 +1,7 @@
use crate::{
backend::Token,
backing::{ImportBacking, LocalBacking},
error::{CallError, CallResult, Result},
error::{CallError, CallResult, ResolveError, ResolveResult, Result},
export::{
Context, Export, ExportIter, FuncPointer, GlobalPointer, MemoryPointer, TablePointer,
},
@ -13,8 +13,7 @@ use crate::{
},
vm,
};
use std::mem;
use std::rc::Rc;
use std::{mem, rc::Rc};
pub(crate) struct InstanceInner {
#[allow(dead_code)]
@ -23,7 +22,13 @@ pub(crate) struct InstanceInner {
vmctx: Box<vm::Ctx>,
}
/// A WebAssembly instance
/// 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
pub struct Instance {
module: Rc<ModuleInner>,
inner: Box<InstanceInner>,
@ -66,37 +71,117 @@ impl Instance {
Ok(instance)
}
/// 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`.
/// This returns the representation of a function that can be called
/// safely.
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::Instance;
/// # use wasmer_runtime_core::error::CallResult;
/// # fn call_foo(instance: &mut Instance) -> CallResult<()> {
/// instance
/// .func("foo")?
/// .call(&[])?;
/// # Ok(())
/// # }
/// ```
pub fn func(&mut self, name: &str) -> ResolveResult<Function> {
let export_index =
self.module
.exports
.get(name)
.ok_or_else(|| ResolveError::ExportNotFound {
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");
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
Ok(Function {
signature,
module: &self.module,
instance_inner: &mut self.inner,
func_index: *func_index,
})
} else {
Err(ResolveError::ExportWrongType {
name: name.to_string(),
}
.into())
}
}
/// 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`].
///
/// [`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::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(())
/// # }
/// ```
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
let export_index =
self.module
.exports
.get(name)
.ok_or_else(|| CallError::NoSuchExport {
.ok_or_else(|| ResolveError::ExportNotFound {
name: name.to_string(),
})?;
let func_index = if let ExportIndex::Func(func_index) = export_index {
*func_index
} else {
return Err(CallError::ExportNotFunc {
return Err(CallError::Resolve(ResolveError::ExportWrongType {
name: name.to_string(),
}
})
.into());
};
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 {
&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 {
&mut self.inner.vmctx
}
/// Returns a iterator over all of the items
/// exported from this instance.
pub fn exports(&mut self) -> ExportIter {
ExportIter::new(&self.module, &mut self.inner)
}
/// The module used to instantiate this Instance.
pub fn module(&self) -> Module {
Module::new(Rc::clone(&self.module))
}
@ -116,7 +201,7 @@ impl Instance {
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
if !signature.check_sig(args) {
Err(CallError::Signature {
Err(ResolveError::Signature {
expected: signature.clone(),
found: args.iter().map(|val| val.ty()).collect(),
})?
@ -143,32 +228,6 @@ impl Instance {
Ok(returns)
}
pub fn get_signature(&self, name: &str) -> CallResult<&FuncSig> {
let export_index =
self.module
.exports
.get(name)
.ok_or_else(|| CallError::NoSuchExport {
name: name.to_string(),
})?;
let func_index = if let ExportIndex::Func(func_index) = export_index {
*func_index
} else {
return Err(CallError::ExportNotFunc {
name: name.to_string(),
}
.into());
};
let sig_index = *self
.module
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");
Ok(self.module.sig_registry.lookup_func_sig(sig_index))
}
}
impl InstanceInner {
@ -360,9 +419,88 @@ impl LikeNamespace for Instance {
}
}
// TODO Remove this later, only needed for compilation till emscripten is updated
/// A representation of an exported WebAssembly function.
pub struct Function<'a> {
signature: &'a FuncSig,
module: &'a ModuleInner,
instance_inner: &'a mut InstanceInner,
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;
/// # use wasmer_runtime_core::error::CallResult;
/// # fn call_foo(instance: &mut Instance) -> CallResult<()> {
/// instance
/// .func("foo")?
/// .call(&[])?;
/// # Ok(())
/// # }
/// ```
pub fn call(&mut self, params: &[Value]) -> CallResult<Vec<Value>> {
if !self.signature.check_sig(params) {
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) {
LocalOrImport::Local(_) => &mut *self.instance_inner.vmctx,
LocalOrImport::Import(imported_func_index) => {
self.instance_inner.import_backing.functions[imported_func_index].vmctx
}
};
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 {
self.signature
}
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.functions[import_func_index].func
}
}
}
}
#[doc(hidden)]
impl Instance {
pub fn memory_offset_addr(&self, _index: usize, _offset: usize) -> *const u8 {
pub fn memory_offset_addr(&self, _: u32, _: usize) -> *const u8 {
unimplemented!()
}
}