diff --git a/.travis.yml b/.travis.yml index 376a737..f4761da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,8 @@ addons: - g++-6 - cmake install: -- cargo install cargo-deadlinks +# Install `cargo-deadlinks` unless it is currently installed. +- command -v cargo-deadlinks &> /dev/null || cargo install cargo-deadlinks script: - export CC=/usr/bin/gcc-6 - export CXX=/usr/bin/g++-6 diff --git a/examples/interpret.rs b/examples/interpret.rs index d87c442..2be3018 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -4,14 +4,14 @@ extern crate wasmi; use std::env::args; use std::fs::File; -use wasmi::{ModuleInstance, NopExternals, RuntimeValue, ImportsBuilder, load_from_buffer, LoadedModule}; +use wasmi::{ModuleInstance, NopExternals, RuntimeValue, ImportsBuilder, Module}; -fn load_from_file(filename: &str) -> LoadedModule { +fn load_from_file(filename: &str) -> Module { use std::io::prelude::*; let mut file = File::open(filename).unwrap(); let mut buf = Vec::new(); file.read_to_end(&mut buf).unwrap(); - load_from_buffer(buf).unwrap() + Module::from_buffer(buf).unwrap() } fn main() { diff --git a/examples/invoke.rs b/examples/invoke.rs index 42b68c9..f037287 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -4,7 +4,7 @@ extern crate wasmi; use std::env::args; use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; -use wasmi::{RuntimeValue, ModuleInstance, NopExternals, ImportsBuilder, load_from_module}; +use wasmi::{RuntimeValue, ModuleInstance, NopExternals, ImportsBuilder}; fn main() { @@ -69,7 +69,7 @@ fn main() { }).collect::>() }; - let loaded_module = load_from_module(module).expect("Module to be valid"); + let loaded_module = wasmi::Module::from_parity_wasm_module(module).expect("Module to be valid"); // Intialize deserialized module. It adds module into It expects 3 parameters: // - a name for the module diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index 9624128..138de9c 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -195,7 +195,7 @@ fn instantiate(path: &str) -> Result { let mut file = File::open(path).unwrap(); let mut wasm_buf = Vec::new(); file.read_to_end(&mut wasm_buf).unwrap(); - wasmi::load_from_buffer(&wasm_buf)? + wasmi::Module::from_buffer(&wasm_buf)? }; let mut imports = ImportsBuilder::new(); diff --git a/spec/src/run.rs b/spec/src/run.rs index 73f2d67..14afa25 100644 --- a/spec/src/run.rs +++ b/spec/src/run.rs @@ -13,7 +13,7 @@ use wasmi::{ GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType, - load_from_buffer, LoadedModule, Signature, MemoryDescriptor, + Module, Signature, MemoryDescriptor, TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs, }; @@ -225,7 +225,7 @@ impl ImportResolver for SpecDriver { } } -fn try_load_module(base_dir: &Path, module_path: &str) -> Result { +fn try_load_module(base_dir: &Path, module_path: &str) -> Result { use std::io::prelude::*; let mut wasm_path = PathBuf::from(base_dir.clone()); @@ -233,7 +233,7 @@ fn try_load_module(base_dir: &Path, module_path: &str) -> Result FuncRef { let func = FuncInstanceInternal::Host { signature, @@ -85,6 +94,18 @@ impl FuncInstance { FuncRef(Rc::new(FuncInstance(func))) } + /// Returns [signature] of this function instance. + /// + /// This function instance can only be called with matching signatures. + /// + /// [signature]: struct.Signature.html + pub fn signature(&self) -> &Signature { + match *self.as_internal() { + FuncInstanceInternal::Internal { ref signature, .. } => signature, + FuncInstanceInternal::Host { ref signature, .. } => signature, + } + } + pub(crate) fn as_internal(&self) -> &FuncInstanceInternal { &self.0 } @@ -102,13 +123,6 @@ impl FuncInstance { FuncRef(Rc::new(FuncInstance(func))) } - pub fn signature(&self) -> &Signature { - match *self.as_internal() { - FuncInstanceInternal::Internal { ref signature, .. } => signature, - FuncInstanceInternal::Host { ref signature, .. } => signature, - } - } - pub(crate) fn body(&self) -> Option> { match *self.as_internal() { FuncInstanceInternal::Internal { ref body, .. } => Some(Rc::clone(body)), diff --git a/src/global.rs b/src/global.rs index 1edd774..e58e543 100644 --- a/src/global.rs +++ b/src/global.rs @@ -5,7 +5,7 @@ use Error; use types::ValueType; use parity_wasm::elements::{ValueType as EValueType}; -/// Reference to a [`GlobalInstance`]. +/// Reference to a global variable (See [`GlobalInstance`] for details). /// /// This reference has a reference-counting semantics. /// diff --git a/src/imports.rs b/src/imports.rs index 1028bc4..7c93b36 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -80,12 +80,12 @@ pub trait ImportResolver { /// # Examples /// /// ```rust -/// use wasmi::{load_from_buffer, ModuleInstance, ImportsBuilder}; +/// use wasmi::{ModuleInstance, ImportsBuilder}; /// # /// # struct EnvModuleResolver; /// # impl ::wasmi::ModuleImportResolver for EnvModuleResolver { } /// # fn func() -> Result<(), ::wasmi::Error> { -/// # let module = load_from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); +/// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); /// # let other_instance = ModuleInstance::new(&module, &ImportsBuilder::default())?.assert_no_start(); /// /// let imports = ImportsBuilder::new() diff --git a/src/lib.rs b/src/lib.rs index 887a8ef..e76a343 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,7 @@ //! .expect("failed to parse wat"); //! //! // Load wasm binary and prepare it for instantiation. -//! let module = wasmi::load_from_buffer(&wasm_binary) +//! let module = wasmi::Module::from_buffer(&wasm_binary) //! .expect("failed to load wasm"); //! //! // Instantiate a module with empty imports and @@ -105,7 +105,6 @@ extern crate byteorder; use std::fmt; use std::error; use std::collections::HashMap; -use parity_wasm::elements::Module; /// Internal interpreter error. #[derive(Debug)] @@ -223,7 +222,7 @@ mod tests; pub use self::memory::{MemoryInstance, MemoryRef}; pub use self::table::{TableInstance, TableRef}; -pub use self::value::{RuntimeValue, TryInto}; +pub use self::value::RuntimeValue; pub use self::host::{Externals, NopExternals, HostError, RuntimeArgs}; pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder}; pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef}; @@ -231,40 +230,96 @@ pub use self::global::{GlobalInstance, GlobalRef}; pub use self::func::{FuncInstance, FuncRef}; pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor}; -pub struct LoadedModule { +/// Deserialized module prepared for instantiation. +pub struct Module { labels: HashMap>, - module: Module, + module: parity_wasm::elements::Module, } -impl LoadedModule { - pub(crate) fn module(&self) -> &Module { +impl Module { + + /// Create `Module` from `parity_wasm::elements::Module`. + /// + /// This function will load, validate and prepare a `parity_wasm`'s `Module`. + /// + /// # Errors + /// + /// Returns `Err` if provided `Module` is not valid. + /// + /// # Examples + /// + /// ```rust + /// extern crate parity_wasm; + /// extern crate wasmi; + /// + /// use parity_wasm::builder; + /// use parity_wasm::elements; + /// + /// fn main() { + /// let parity_module = + /// builder::module() + /// .function() + /// .signature().with_param(elements::ValueType::I32).build() + /// .body().build() + /// .build() + /// .build(); + /// + /// let module = wasmi::Module::from_parity_wasm_module(parity_module) + /// .expect("parity-wasm builder generated invalid module!"); + /// + /// // Instantiate `module`, etc... + /// } + /// ``` + pub fn from_parity_wasm_module(module: parity_wasm::elements::Module) -> Result { + use validation::{validate_module, ValidatedModule}; + let ValidatedModule { + labels, + module, + } = validate_module(module)?; + + Ok(Module { + labels, + module, + }) + } + + /// Create `Module` from a given buffer. + /// + /// This function will deserialize wasm module from a given module, + /// validate and prepare it for instantiation. + /// + /// # Errors + /// + /// Returns `Err` if wasm binary in provided `buffer` is not valid wasm binary. + /// + /// # Examples + /// + /// ```rust + /// extern crate wasmi; + /// + /// fn main() { + /// let module = + /// wasmi::Module::from_buffer( + /// // Minimal module: + /// // \0asm - magic + /// // 0x01 - version (in little-endian) + /// &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00] + /// ).expect("Failed to load minimal module"); + /// + /// // Instantiate `module`, etc... + /// } + /// ``` + pub fn from_buffer>(buffer: B) -> Result { + let module = parity_wasm::elements::deserialize_buffer(buffer.as_ref()) + .map_err(|e: parity_wasm::elements::Error| Error::Validation(e.to_string()))?; + Module::from_parity_wasm_module(module) + } + + pub(crate) fn module(&self) -> &parity_wasm::elements::Module { &self.module } pub(crate) fn labels(&self) -> &HashMap> { &self.labels } - - pub fn into_module(self) -> Module { - self.module - } -} - -pub fn load_from_module(module: Module) -> Result { - use validation::{validate_module, ValidatedModule}; - let ValidatedModule { - labels, - module, - } = validate_module(module)?; - - Ok(LoadedModule { - labels, - module, - }) -} - -pub fn load_from_buffer>(buffer: B) -> Result { - let module = parity_wasm::elements::deserialize_buffer(buffer.as_ref()) - .map_err(|e: parity_wasm::elements::Error| Error::Validation(e.to_string()))?; - load_from_module(module) } diff --git a/src/memory.rs b/src/memory.rs index cf25233..9611a24 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -13,7 +13,7 @@ pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536; /// Maximal number of pages. const LINEAR_MEMORY_MAX_PAGES: u32 = 65536; -/// Reference to a [`MemoryInstance`]. +/// Reference to a memory (See [`MemoryInstance`] for details). /// /// This reference has a reference-counting semantics. /// diff --git a/src/module.rs b/src/module.rs index f2904b6..0d10d25 100644 --- a/src/module.rs +++ b/src/module.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::fmt; use std::collections::HashMap; use parity_wasm::elements::{External, InitExpr, Internal, Opcode, ResizableLimits, Type}; -use {LoadedModule, Error, Signature, MemoryInstance, RuntimeValue, TableInstance}; +use {Module, Error, Signature, MemoryInstance, RuntimeValue, TableInstance}; use imports::ImportResolver; use global::{GlobalInstance, GlobalRef}; use func::{FuncRef, FuncBody, FuncInstance}; @@ -100,9 +100,9 @@ impl ExternVal { } } -/// A module instance is the runtime representation of a [module][`LoadedModule`]. +/// A module instance is the runtime representation of a [module][`Module`]. /// -/// It is created by instantiating a [module][`LoadedModule`], and collects runtime representations +/// It is created by instantiating a [module][`Module`], and collects runtime representations /// of all entities that are imported or defined by the module, namely: /// /// - [functions][`FuncInstance`], @@ -115,7 +115,7 @@ impl ExternVal { /// /// After module is instantiated you can start invoking it's exported functions with [`invoke_export`]. /// -/// [`LoadedModule`]: struct.LoadedModule.html +/// [`Module`]: struct.Module.html /// [`FuncInstance`]: struct.FuncInstance.html /// [`MemoryInstance`]: struct.MemoryInstance.html /// [`TableInstance`]: struct.TableInstance.html @@ -188,7 +188,7 @@ impl ModuleInstance { } fn alloc_module( - loaded_module: &LoadedModule, + loaded_module: &Module, extern_vals: &[ExternVal] ) -> Result { let module = loaded_module.module(); @@ -357,7 +357,7 @@ impl ModuleInstance { } fn instantiate_with_externvals( - loaded_module: &LoadedModule, + loaded_module: &Module, extern_vals: &[ExternVal], ) -> Result { let module = loaded_module.module(); @@ -400,7 +400,7 @@ impl ModuleInstance { Ok(module_ref) } - /// Instantiate a [module][`LoadedModule`]. + /// Instantiate a [module][`Module`]. /// /// Note that in case of successful instantiation this function returns a reference to /// a module which `start` function is not called. @@ -408,6 +408,8 @@ impl ModuleInstance { /// situations where you might need to do additional setup before calling `start` function. /// For such sitations this separation might be useful. /// + /// See [`NotStartedModuleRef`] for details. + /// /// # Errors /// /// Returns `Err` if the module cannot be instantiated. @@ -420,9 +422,9 @@ impl ModuleInstance { /// # Examples /// /// ```rust - /// use wasmi::{load_from_buffer, ModuleInstance, ImportsBuilder, NopExternals}; + /// use wasmi::{ModuleInstance, ImportsBuilder, NopExternals}; /// # fn func() -> Result<(), ::wasmi::Error> { - /// # let module = load_from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); + /// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); /// /// // ModuleInstance::new returns instance which `start` function isn't called. /// let not_started = ModuleInstance::new( @@ -440,9 +442,9 @@ impl ModuleInstance { /// instantiated module without calling `start` function. /// /// ```rust - /// use wasmi::{load_from_buffer, ModuleInstance, ImportsBuilder, NopExternals}; + /// use wasmi::{ModuleInstance, ImportsBuilder, NopExternals}; /// # fn func() -> Result<(), ::wasmi::Error> { - /// # let module = load_from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); + /// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); /// /// // This will panic if the module actually contain `start` function. /// let not_started = ModuleInstance::new( @@ -454,11 +456,12 @@ impl ModuleInstance { /// # } /// ``` /// - /// [`LoadedModule`]: struct.LoadedModule.html + /// [`Module`]: struct.Module.html + /// [`NotStartedModuleRef`]: struct.NotStartedModuleRef.html /// [`ImportResolver`]: trait.ImportResolver.html /// [`assert_no_start`]: struct.NotStartedModuleRef.html#method.assert_no_start pub fn new<'m, I: ImportResolver>( - loaded_module: &'m LoadedModule, + loaded_module: &'m Module, imports: &I, ) -> Result, Error> { let module = loaded_module.module(); @@ -536,7 +539,7 @@ impl ModuleInstance { /// # ) /// # "#, /// # ).expect("failed to parse wat"); - /// # let module = wasmi::load_from_buffer(&wasm_binary).expect("failed to load wasm"); + /// # let module = wasmi::Module::from_buffer(&wasm_binary).expect("failed to load wasm"); /// # let instance = ModuleInstance::new( /// # &module, /// # &ImportsBuilder::default() @@ -583,8 +586,20 @@ impl ModuleInstance { } } +/// Mostly instantiated [`ModuleRef`]. +/// +/// The last step of instantiation is call to `start` function (if any). +/// To get [fully instantiated module instance][`ModuleRef`], [running `start` function][`run_start`] is required. +/// +/// If you sure, that there is no `start` function (e.g. because you created it without one), you can +/// call [`assert_no_start`] which returns [`ModuleRef`] without calling `start` function. However, +/// it will panic if module contains `start` function. +/// +/// [`ModuleRef`]: struct.ModuleRef.html +/// [`run_start`]: #method.run_start +/// [`assert_no_start`]: #method.assert_no_start pub struct NotStartedModuleRef<'a> { - loaded_module: &'a LoadedModule, + loaded_module: &'a Module, instance: ModuleRef, } diff --git a/src/table.rs b/src/table.rs index a4f8ad5..eac4b0b 100644 --- a/src/table.rs +++ b/src/table.rs @@ -7,7 +7,7 @@ use Error; use func::FuncRef; use module::check_limits; -/// Reference to a [`TableInstance`]. +/// Reference to a table (See [`TableInstance`] for details). /// /// This reference has a reference-counting semantics. /// diff --git a/src/tests/host.rs b/src/tests/host.rs index 2dc9ed5..27f7a72 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -1,7 +1,7 @@ use { Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, - RuntimeValue, RuntimeArgs, LoadedModule, load_from_buffer, TableDescriptor, MemoryDescriptor, + RuntimeValue, RuntimeArgs, Module, TableDescriptor, MemoryDescriptor, }; use types::ValueType; use wabt::wat2wasm; @@ -200,9 +200,9 @@ impl ModuleImportResolver for TestHost { } } -fn parse_wat(source: &str) -> LoadedModule { +fn parse_wat(source: &str) -> Module { let wasm_binary = wat2wasm(source).expect("Failed to parse wat source"); - load_from_buffer(wasm_binary).expect("Failed to load parsed module") + Module::from_buffer(wasm_binary).expect("Failed to load parsed module") } #[test] diff --git a/src/tests/wasm.rs b/src/tests/wasm.rs index f86594f..8b2573f 100644 --- a/src/tests/wasm.rs +++ b/src/tests/wasm.rs @@ -1,7 +1,7 @@ use { Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, - TableInstance, TableRef, LoadedModule, load_from_buffer, GlobalDescriptor, TableDescriptor, MemoryDescriptor, + TableInstance, TableRef, Module, GlobalDescriptor, TableDescriptor, MemoryDescriptor, }; use std::fs::File; @@ -69,12 +69,12 @@ impl ModuleImportResolver for Env { } } -fn load_from_file(filename: &str) -> LoadedModule { +fn load_from_file(filename: &str) -> Module { use std::io::prelude::*; let mut file = File::open(filename).unwrap(); let mut buf = Vec::new(); file.read_to_end(&mut buf).unwrap(); - load_from_buffer(buf).unwrap() + Module::from_buffer(buf).unwrap() } #[test] diff --git a/src/types.rs b/src/types.rs index 7e1e185..419a67c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,13 +3,14 @@ use std::borrow::Cow; use parity_wasm::elements::{ FunctionType, ValueType as EValueType, GlobalType, TableType, MemoryType}; -/// Signature of a function. +/// Signature of a [function]. /// /// Signature of a function consists of zero or more parameter [types][type] and zero or one return [type]. /// /// Two signatures are considered equal if they have equal list of parameters and equal return types. /// /// [type]: enum.ValueType.html +/// [function]: struct.FuncInstance.html #[derive(Debug, Clone, PartialEq, Eq)] pub struct Signature { params: Cow<'static, [ValueType]>, @@ -79,6 +80,12 @@ impl ValueType { } } +/// Description of a global variable. +/// +/// Primarly used to describe imports of global variables. +/// See [`ImportResolver`] for details. +/// +/// [`ImportResolver`]: trait.ImportResolver.html pub struct GlobalDescriptor { value_type: ValueType, mutable: bool, @@ -101,6 +108,12 @@ impl GlobalDescriptor { } } +/// Description of a table. +/// +/// Primarly used to describe imports of tables. +/// See [`ImportResolver`] for details. +/// +/// [`ImportResolver`]: trait.ImportResolver.html pub struct TableDescriptor { initial: u32, maximum: Option, @@ -123,6 +136,12 @@ impl TableDescriptor { } } +/// Description of a linear memory. +/// +/// Primarly used to describe imports of linear memories. +/// See [`ImportResolver`] for details. +/// +/// [`ImportResolver`]: trait.ImportResolver.html pub struct MemoryDescriptor { initial: u32, maximum: Option,