Refine the runtime api and document the exposed items (#115)

* private module, remove unused method, docs on compile_with

* refine runtime api and document exposed items

* Fix integration test build

* Fix lint
This commit is contained in:
Lachlan Sneff
2019-01-23 12:34:15 -08:00
committed by GitHub
parent 7632beced8
commit ab65477d1f
10 changed files with 205 additions and 53 deletions

28
Cargo.lock generated
View File

@ -489,15 +489,15 @@ dependencies = [
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.1.0", "wasmer-clif-backend 0.2.0",
"wasmer-emscripten 0.1.1", "wasmer-emscripten 0.2.0",
"wasmer-runtime 0.1.0", "wasmer-runtime 0.2.0",
"wasmer-runtime-core 0.1.0", "wasmer-runtime-core 0.2.0",
] ]
[[package]] [[package]]
name = "wasmer-clif-backend" name = "wasmer-clif-backend"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -507,13 +507,13 @@ dependencies = [
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.1.0", "wasmer-runtime-core 0.2.0",
"wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "wasmer-emscripten" name = "wasmer-emscripten"
version = "0.1.1" version = "0.2.0"
dependencies = [ dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -521,21 +521,21 @@ dependencies = [
"libc 0.2.44 (git+https://github.com/rust-lang/libc)", "libc 0.2.44 (git+https://github.com/rust-lang/libc)",
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.1.0", "wasmer-clif-backend 0.2.0",
"wasmer-runtime-core 0.1.0", "wasmer-runtime-core 0.2.0",
] ]
[[package]] [[package]]
name = "wasmer-runtime" name = "wasmer-runtime"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"wasmer-clif-backend 0.1.0", "wasmer-clif-backend 0.2.0",
"wasmer-runtime-core 0.1.0", "wasmer-runtime-core 0.2.0",
] ]
[[package]] [[package]]
name = "wasmer-runtime-core" name = "wasmer-runtime-core"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -543,7 +543,7 @@ dependencies = [
"nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.1.0", "wasmer-clif-backend 0.2.0",
"wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -5,17 +5,53 @@ pub trait LikeNamespace {
fn get_export(&mut self, name: &str) -> Option<Export>; fn get_export(&mut self, name: &str) -> Option<Export>;
} }
/// All of the import data used when instantiating.
///
/// It's suggested that you use the [`imports!`] macro
/// instead of creating an `ImportObject` by hand.
///
/// [`imports!`]: macro.imports.html
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::imports;
/// # use wasmer_runtime_core::vm::Ctx;
/// let import_object = imports! {
/// "env" => {
/// "foo" => foo<[i32] -> [i32]>,
/// },
/// };
///
/// extern fn foo(n: i32, _: &mut Ctx) -> i32 {
/// n
/// }
/// ```
pub struct ImportObject { pub struct ImportObject {
map: HashMap<String, Box<dyn LikeNamespace>>, map: HashMap<String, Box<dyn LikeNamespace>>,
} }
impl ImportObject { impl ImportObject {
/// Create a new `ImportObject`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
map: HashMap::new(), map: HashMap::new(),
} }
} }
/// Register anything that implements `LikeNamespace` as a namespace.
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::Instance;
/// # use wasmer_runtime_core::import::{ImportObject, Namespace};
/// fn register(instance: Instance, namespace: Namespace) {
/// let mut import_object = ImportObject::new();
///
/// import_object.register("namespace0", instance);
/// import_object.register("namespace1", namespace);
/// // ...
/// }
/// ```
pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>> pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>>
where where
S: Into<String>, S: Into<String>,

View File

@ -23,9 +23,15 @@ pub(crate) struct InstanceInner {
vmctx: Box<vm::Ctx>, 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 { pub struct Instance {
pub module: Rc<ModuleInner>, module: Rc<ModuleInner>,
inner: Box<InstanceInner>, inner: Box<InstanceInner>,
#[allow(dead_code)] #[allow(dead_code)]
imports: Box<ImportObject>, imports: Box<ImportObject>,
@ -67,11 +73,27 @@ impl Instance {
} }
/// Call an exported webassembly function given the export name. /// Call an exported webassembly function given the export name.
/// Pass arguments by wrapping each one in the `Value` enum. /// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a `Value`. /// The returned values are also each wrapped in a [`Value`].
/// ///
/// [`Value`]: enum.Value.html
///
/// # Note:
/// This returns `CallResult<Vec<Value>>` in order to support /// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature. /// 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>> { pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
let export_index = let export_index =
self.module self.module
@ -329,9 +351,9 @@ impl LikeNamespace for Instance {
} }
} }
// TODO Remove this later, only needed for compilation till emscripten is updated #[doc(hidden)]
impl Instance { 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!() unimplemented!()
} }
} }

View File

@ -42,7 +42,12 @@ pub mod prelude {
pub use crate::{export_func, imports}; pub use crate::{export_func, imports};
} }
/// Compile a webassembly module using the provided compiler. /// Compile a [`Module`] using the provided compiler from
/// WebAssembly binary code. This function is useful if it
/// is necessary to a compile a module before it can be instantiated
/// and must be used if you wish to use a different backend from the default.
///
/// [`Module`]: struct.Module.html
pub fn compile_with( pub fn compile_with(
wasm: &[u8], wasm: &[u8],
compiler: &dyn backend::Compiler, compiler: &dyn backend::Compiler,
@ -53,9 +58,9 @@ pub fn compile_with(
.map(|inner| module::Module::new(Rc::new(inner))) .map(|inner| module::Module::new(Rc::new(inner)))
} }
/// This function performs validation as defined by the /// Perform validation as defined by the
/// WebAssembly specification and returns true if validation /// WebAssembly specification. Returns `true` if validation
/// succeeded, false if validation failed. /// succeeded, `false` if validation failed.
pub fn validate(wasm: &[u8]) -> bool { pub fn validate(wasm: &[u8]) -> bool {
use wasmparser::WasmDecoder; use wasmparser::WasmDecoder;
let mut parser = wasmparser::ValidatingParser::new(wasm, None); let mut parser = wasmparser::ValidatingParser::new(wasm, None);

View File

@ -51,6 +51,29 @@ macro_rules! __export_func_convert_type {
}; };
} }
/// Generate an [`ImportObject`] safely.
///
/// [`ImportObject`]: struct.ImportObject.html
///
/// # Note:
/// The `import` macro currently only supports
/// importing functions.
///
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::imports;
/// # use wasmer_runtime_core::vm::Ctx;
/// let import_object = imports! {
/// "env" => {
/// "foo" => foo<[i32] -> [i32]>,
/// },
/// };
///
/// extern fn foo(n: i32, _: &mut Ctx) -> i32 {
/// n
/// }
/// ```
#[macro_export] #[macro_export]
macro_rules! imports { macro_rules! imports {
( $( $ns_name:expr => $ns:tt, )* ) => {{ ( $( $ns_name:expr => $ns:tt, )* ) => {{

View File

@ -42,16 +42,44 @@ pub struct ModuleInner {
pub sig_registry: SigRegistry, pub sig_registry: SigRegistry,
} }
pub struct Module(pub Rc<ModuleInner>); /// A compiled WebAssembly module.
///
/// `Module` is returned by the [`compile`] and
/// [`compile_with`] functions.
///
/// [`compile`]: fn.compile.html
/// [`compile_with`]: fn.compile_with.html
pub struct Module(#[doc(hidden)] pub Rc<ModuleInner>);
impl Module { impl Module {
pub(crate) fn new(inner: Rc<ModuleInner>) -> Self { pub(crate) fn new(inner: Rc<ModuleInner>) -> Self {
Module(inner) Module(inner)
} }
/// Instantiate a WebAssembly module with the provided imports. /// Instantiate a WebAssembly module with the provided [`ImportObject`].
pub fn instantiate(&self, imports: ImportObject) -> Result<Instance> { ///
Instance::new(Rc::clone(&self.0), Box::new(imports)) /// [`ImportObject`]: struct.ImportObject.html
///
/// # Note:
/// Instantiating a `Module` will also call the function designated as `start`
/// in the WebAssembly module, if there is one.
///
/// # Usage:
/// ```
/// # use wasmer_runtime_core::error::Result;
/// # use wasmer_runtime_core::Module;
/// # use wasmer_runtime_core::imports;
/// # fn instantiate(module: &Module) -> Result<()> {
/// let import_object = imports! {
/// // ...
/// };
/// let instance = module.instantiate(import_object)?;
/// // ...
/// # Ok(())
/// # }
/// ```
pub fn instantiate(&self, import_object: ImportObject) -> Result<Instance> {
Instance::new(Rc::clone(&self.0), Box::new(import_object))
} }
} }

View File

@ -1,5 +1,6 @@
use crate::{module::ModuleInner, structures::TypedIndex}; use crate::{module::ModuleInner, structures::TypedIndex};
/// Represents a WebAssembly type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Type { pub enum Type {
/// The `i32` type. /// The `i32` type.
@ -12,6 +13,10 @@ pub enum Type {
F64, F64,
} }
/// Represents a WebAssembly value.
///
/// As the number of types in WebAssembly expand,
/// this structure will expand as well.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Value { pub enum Value {
/// The `i32` type. /// The `i32` type.

View File

@ -6,6 +6,9 @@ use crate::{
}; };
use std::{ffi::c_void, mem, ptr, slice}; use std::{ffi::c_void, mem, ptr, slice};
/// The context of the currently running WebAssembly instance.
///
///
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct Ctx { pub struct Ctx {
@ -39,6 +42,7 @@ pub struct Ctx {
} }
impl Ctx { impl Ctx {
#[doc(hidden)]
pub unsafe fn new( pub unsafe fn new(
local_backing: &mut LocalBacking, local_backing: &mut LocalBacking,
import_backing: &mut ImportBacking, import_backing: &mut ImportBacking,
@ -63,6 +67,7 @@ impl Ctx {
} }
} }
#[doc(hidden)]
pub unsafe fn new_with_data( pub unsafe fn new_with_data(
local_backing: &mut LocalBacking, local_backing: &mut LocalBacking,
import_backing: &mut ImportBacking, import_backing: &mut ImportBacking,
@ -89,6 +94,25 @@ impl Ctx {
} }
} }
/// This exposes the specified memory of the WebAssembly instance
/// as a mutable slice.
///
/// WebAssembly will soon support multiple linear memories, so this
/// forces the user to specify.
///
/// # Usage:
///
/// ```
/// # use wasmer_runtime_core::{
/// # vm::Ctx,
/// # error::Result,
/// # };
/// extern fn host_func(ctx: &mut Ctx) {
/// let first_memory = ctx.memory(0);
/// // Set the first byte of that linear memory.
/// first_memory[0] = 42;
/// }
/// ```
pub fn memory<'a>(&'a mut self, mem_index: u32) -> &'a mut [u8] { pub fn memory<'a>(&'a mut self, mem_index: u32) -> &'a mut [u8] {
let module = unsafe { &*self.module }; let module = unsafe { &*self.module };
let mem_index = MemoryIndex::new(mem_index as usize); let mem_index = MemoryIndex::new(mem_index as usize);
@ -110,6 +134,7 @@ impl Ctx {
} }
} }
#[doc(hidden)]
impl Ctx { impl Ctx {
#[allow(clippy::erasing_op)] // TODO #[allow(clippy::erasing_op)] // TODO
pub fn offset_memories() -> u8 { pub fn offset_memories() -> u8 {

View File

@ -1,47 +1,57 @@
#[doc(inline)] pub use wasmer_runtime_core::import::ImportObject;
pub use wasmer_runtime_core::*;
pub use wasmer_runtime_core::instance::Instance; pub use wasmer_runtime_core::instance::Instance;
pub use wasmer_runtime_core::module::Module; pub use wasmer_runtime_core::module::Module;
pub use wasmer_runtime_core::validate; pub use wasmer_runtime_core::types::Value;
pub use wasmer_runtime_core::vm::Ctx;
/// The `compile(...)` function compiles a `Module` pub use wasmer_runtime_core::{compile_with, validate};
/// from WebAssembly binary code. This function is useful if it
/// is necessary to a compile a module before it can be instantiated pub use wasmer_runtime_core::error;
/// (otherwise, the webassembly::instantiate() function should be used). pub use wasmer_runtime_core::imports;
pub mod value {
pub use wasmer_runtime_core::types::{Type, Value};
}
/// Compile WebAssembly binary code into a [`Module`].
/// This function is useful if it is necessary to
/// compile a module before it can be instantiated
/// (otherwise, the [`instantiate`] function should be used).
/// ///
/// Params: /// [`Module`]: struct.Module.html
/// [`instantiate`]: fn.instantiate.html
///
/// # Params:
/// * `wasm`: A `&[u8]` containing the /// * `wasm`: A `&[u8]` containing the
/// binary code of the wasm module you want to compile. /// binary code of the wasm module you want to compile.
/// Errors: /// # Errors:
/// If the operation fails, the function returns `Err(error::CompileError::...).` /// If the operation fails, the function returns `Err(error::CompileError::...)`.
#[cfg(feature = "wasmer-clif-backend")] #[cfg(feature = "wasmer-clif-backend")]
pub fn compile(wasm: &[u8]) -> error::CompileResult<module::Module> { pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
use wasmer_clif_backend::CraneliftCompiler; use wasmer_clif_backend::CraneliftCompiler;
wasmer_runtime_core::compile_with(&wasm[..], &CraneliftCompiler::new()) wasmer_runtime_core::compile_with(&wasm[..], &CraneliftCompiler::new())
} }
/// The `instantiate(...)` function allows you to compile and /// Compile and instantiate WebAssembly code without
/// instantiate WebAssembly code in one go. /// creating a [`Module`].
/// ///
/// Params: /// [`Module`]: struct.Module.html
///
/// # Params:
/// * `wasm`: A `&[u8]` containing the /// * `wasm`: A `&[u8]` containing the
/// binary code of the wasm module you want to compile. /// binary code of the wasm module you want to compile.
/// * `import_object`: An object containing the values to be imported /// * `import_object`: An object containing the values to be imported
/// into the newly-created Instance, such as functions or /// into the newly-created Instance, such as functions or
/// webassembly::Memory objects. There must be one matching property /// Memory objects. There must be one matching property
/// for each declared import of the compiled module or else a /// for each declared import of the compiled module or else a
/// webassembly::LinkError is thrown. /// LinkError is thrown.
/// Errors: /// # Errors:
/// If the operation fails, the function returns a /// If the operation fails, the function returns a
/// `error::CompileError`, `error::LinkError`, or /// `error::CompileError`, `error::LinkError`, or
/// `error::RuntimeError` (all combined into an `error::Error`), /// `error::RuntimeError` (all combined into an `error::Error`),
/// depending on the cause of the failure. /// depending on the cause of the failure.
#[cfg(feature = "wasmer-clif-backend")] #[cfg(feature = "wasmer-clif-backend")]
pub fn instantiate( pub fn instantiate(wasm: &[u8], import_object: ImportObject) -> error::Result<Instance> {
wasm: &[u8],
import_object: import::ImportObject,
) -> error::Result<instance::Instance> {
let module = compile(wasm)?; let module = compile(wasm)?;
module.instantiate(import_object) module.instantiate(import_object)
} }

View File

@ -3,9 +3,7 @@ pub mod utils;
use wasmer_runtime::{ use wasmer_runtime::{
self as runtime, self as runtime,
error::{CallResult, Result}, error::{CallResult, Result},
import::ImportObject, ImportObject, Instance, Module,
instance::Instance,
module::Module,
}; };
use std::panic; use std::panic;