diff --git a/Cargo.lock b/Cargo.lock index cff878ec4..ed117b2dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,15 +489,15 @@ dependencies = [ "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)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.2.0", - "wasmer-emscripten 0.2.0", - "wasmer-runtime 0.2.0", - "wasmer-runtime-core 0.2.0", + "wasmer-clif-backend 0.1.1", + "wasmer-emscripten 0.1.0", + "wasmer-runtime 0.1.1", + "wasmer-runtime-core 0.1.1", ] [[package]] name = "wasmer-clif-backend" -version = "0.2.0" +version = "0.1.1" dependencies = [ "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)", @@ -507,13 +507,13 @@ dependencies = [ "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)", "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.2.0", + "wasmer-runtime-core 0.1.1", "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.2.0" +version = "0.1.0" dependencies = [ "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)", @@ -521,21 +521,21 @@ dependencies = [ "libc 0.2.44 (git+https://github.com/rust-lang/libc)", "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)", - "wasmer-clif-backend 0.2.0", - "wasmer-runtime-core 0.2.0", + "wasmer-clif-backend 0.1.1", + "wasmer-runtime-core 0.1.1", ] [[package]] name = "wasmer-runtime" -version = "0.2.0" +version = "0.1.1" dependencies = [ - "wasmer-clif-backend 0.2.0", - "wasmer-runtime-core 0.2.0", + "wasmer-clif-backend 0.1.1", + "wasmer-runtime-core 0.1.1", ] [[package]] name = "wasmer-runtime-core" -version = "0.2.0" +version = "0.1.1" dependencies = [ "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)", @@ -543,7 +543,7 @@ dependencies = [ "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)", "wabt 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.2.0", + "wasmer-clif-backend 0.1.1", "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)", ] diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index d8ff392b5..28fb0fbd2 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,11 +1,14 @@ [package] name = "wasmer-clif-backend" -version = "0.2.0" +version = "0.1.1" +description = "Wasmer runtime Cranelift compiler backend" +license = "MIT" authors = ["The Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" edition = "2018" [dependencies] -wasmer-runtime-core = { path = "../runtime-core" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.1.1" } cranelift-native = "0.26.0" cranelift-codegen = "0.26.0" cranelift-entity = "0.26.0" diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 8aca94ce0..85663fc30 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -65,7 +65,7 @@ impl FuncResolverBuilder { .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; unsafe { memory - .protect(0..memory.size(), Protect::ReadWrite) + .protect(.., Protect::ReadWrite) .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; } @@ -186,7 +186,7 @@ impl FuncResolverBuilder { unsafe { self.resolver .memory - .protect(0..self.resolver.memory.size(), Protect::ReadExec) + .protect(.., Protect::ReadExec) .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; } diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index e44bcde2c..562a49f6d 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -66,9 +66,7 @@ impl Trampolines { let mut memory = Memory::with_size(total_size).unwrap(); unsafe { - memory - .protect(0..memory.size(), Protect::ReadWrite) - .unwrap(); + memory.protect(.., Protect::ReadWrite).unwrap(); } // "\xCC" disassembles to "int3", which will immediately cause @@ -91,7 +89,7 @@ impl Trampolines { } unsafe { - memory.protect(0..memory.size(), Protect::ReadExec).unwrap(); + memory.protect(.., Protect::ReadExec).unwrap(); } Self { diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index 42fbaf9b1..e082c65cb 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,19 +1,22 @@ [package] name = "wasmer-emscripten" -version = "0.2.0" +version = "0.1.0" +description = "Wasmer runtime emscripten implementation library" +license = "MIT" authors = ["The Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" edition = "2018" build = "build/mod.rs" [dependencies] hashbrown = "0.1" -wasmer-runtime-core = { path = "../runtime-core" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.1.0" } libc = { git = "https://github.com/rust-lang/libc" } byteorder = "1" time = "0.1.41" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.1.0" } wabt = "0.7.2" [build-dependencies] diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 1da2e6aba..0d777e79d 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -7,7 +7,7 @@ use std::mem; use std::ptr; use std::{mem::size_of, panic, slice}; use wasmer_runtime_core::{ - error::{CallError, CallResult}, + error::{CallError, CallResult, ResolveError}, export::{Context, Export, FuncPointer, GlobalPointer, MemoryPointer, TablePointer}, import::{ImportObject, Namespace}, instance::Instance, @@ -117,7 +117,9 @@ fn get_main_args( instance: &mut Instance, ) -> CallResult> { // Getting main function signature. - let func_sig = instance.get_signature(main_name)?; + + let func = instance.func(main_name)?; + let func_sig = func.signature(); let params = &func_sig.params; // Check for a () or (i32, i32) sig. @@ -138,7 +140,7 @@ fn get_main_args( ]) } &[] => Ok(vec![]), - _ => Err(CallError::Signature { + _ => Err(ResolveError::Signature { expected: FuncSig { params: vec![Type::I32, Type::I32], returns: vec![], diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index a515c6ea2..76b1b8d96 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "wasmer-runtime-core" -version = "0.2.0" +version = "0.1.1" +description = "Wasmer runtime core library" +license = "MIT" authors = ["The Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" edition = "2018" build = "build/mod.rs" @@ -21,7 +24,7 @@ errno = "0.2.4" wabt = "0.7.2" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.1.1" } wabt = "0.7.2" field-offset = "0.1.1" diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index 47ed4592a..dc0972d43 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -5,6 +5,7 @@ pub type CompileResult = std::result::Result>; pub type LinkResult = std::result::Result>; pub type RuntimeResult = std::result::Result>; pub type CallResult = std::result::Result>; +pub type ResolveResult = std::result::Result>; /// This is returned when the chosen compiler is unable to /// successfully compile the provided webassembly module into @@ -93,6 +94,23 @@ impl PartialEq for RuntimeError { } } +/// This error type is produced by resolving a wasm function +/// given its name. +/// +/// Comparing two `ResolveError`s always evaluates to false. +#[derive(Debug, Clone)] +pub enum ResolveError { + Signature { expected: FuncSig, found: Vec }, + ExportNotFound { name: String }, + ExportWrongType { name: String }, +} + +impl PartialEq for ResolveError { + fn eq(&self, _other: &ResolveError) -> bool { + false + } +} + /// This error type is produced by calling a wasm function /// exported from a module. /// @@ -102,9 +120,7 @@ impl PartialEq for RuntimeError { /// Comparing two `CallError`s always evaluates to false. #[derive(Debug, Clone)] pub enum CallError { - Signature { expected: FuncSig, found: Vec }, - NoSuchExport { name: String }, - ExportNotFunc { name: String }, + Resolve(ResolveError), Runtime(RuntimeError), } @@ -162,3 +178,39 @@ impl From> for Box { Box::new(CallError::Runtime(*runtime_err)) } } + +impl From> for Box { + fn from(resolve_err: Box) -> Self { + Box::new(CallError::Resolve(*resolve_err)) + } +} + +impl From for Box { + fn from(compile_err: CompileError) -> Self { + Box::new(Error::CompileError(compile_err)) + } +} + +impl From for Box { + fn from(runtime_err: RuntimeError) -> Self { + Box::new(Error::RuntimeError(runtime_err)) + } +} + +impl From for Box { + fn from(call_err: CallError) -> Self { + Box::new(Error::CallError(call_err)) + } +} + +impl From for Box { + fn from(runtime_err: RuntimeError) -> Self { + Box::new(CallError::Runtime(runtime_err)) + } +} + +impl From for Box { + fn from(resolve_err: ResolveError) -> Self { + Box::new(CallError::Resolve(resolve_err)) + } +} diff --git a/lib/runtime-core/src/import.rs b/lib/runtime-core/src/import.rs index a7ecf23ef..e2b76f6a6 100644 --- a/lib/runtime-core/src/import.rs +++ b/lib/runtime-core/src/import.rs @@ -5,17 +5,53 @@ pub trait LikeNamespace { fn get_export(&mut self, name: &str) -> Option; } +/// 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 { map: HashMap>, } impl ImportObject { + /// Create a new `ImportObject`. pub fn new() -> Self { Self { 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(&mut self, name: S, namespace: N) -> Option> where S: Into, diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 0f57699a7..ed88bbe8c 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -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, } -/// 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, inner: Box, @@ -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 { + 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>` 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> { 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>` 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> { + 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!() } } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 5840b40a4..261556116 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -42,7 +42,12 @@ pub mod prelude { 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( wasm: &[u8], compiler: &dyn backend::Compiler, @@ -53,9 +58,9 @@ pub fn compile_with( .map(|inner| module::Module::new(Rc::new(inner))) } -/// This function performs validation as defined by the -/// WebAssembly specification and returns true if validation -/// succeeded, false if validation failed. +/// Perform validation as defined by the +/// WebAssembly specification. Returns `true` if validation +/// succeeded, `false` if validation failed. pub fn validate(wasm: &[u8]) -> bool { use wasmparser::WasmDecoder; let mut parser = wasmparser::ValidatingParser::new(wasm, None); diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index cc4a5b1bd..9da01c254 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -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_rules! imports { ( $( $ns_name:expr => $ns:tt, )* ) => {{ diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 187e7f092..b178e9f94 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -42,16 +42,44 @@ pub struct ModuleInner { pub sig_registry: SigRegistry, } -pub struct Module(pub Rc); +/// 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); impl Module { pub(crate) fn new(inner: Rc) -> Self { Module(inner) } - /// Instantiate a WebAssembly module with the provided imports. - pub fn instantiate(&self, imports: ImportObject) -> Result { - Instance::new(Rc::clone(&self.0), Box::new(imports)) + /// Instantiate a WebAssembly module with the provided [`ImportObject`]. + /// + /// [`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::new(Rc::clone(&self.0), Box::new(import_object)) } } diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 062dcba0d..6001bbfcf 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -1,7 +1,7 @@ use errno; use nix::libc; use page_size; -use std::ops::Range; +use std::ops::{Bound, RangeBounds}; use std::{ptr, slice}; #[derive(Debug)] @@ -42,13 +42,30 @@ impl Memory { } } - pub unsafe fn protect(&mut self, range: Range, protect: Protect) -> Result<(), String> { + pub unsafe fn protect( + &mut self, + range: impl RangeBounds, + protect: Protect, + ) -> Result<(), String> { let protect = protect.to_protect_const(); + + let range_start = match range.start_bound() { + Bound::Included(start) => *start, + Bound::Excluded(start) => *start, + Bound::Unbounded => 0, + }; + + let range_end = match range.end_bound() { + Bound::Included(end) => *end, + Bound::Excluded(end) => *end, + Bound::Unbounded => self.size(), + }; + let page_size = page_size::get(); let start = self .ptr - .add(round_down_to_page_size(range.start, page_size)); - let size = round_up_to_page_size(range.end - range.start, page_size); + .add(round_down_to_page_size(range_start, page_size)); + let size = round_up_to_page_size(range_end - range_start, page_size); assert!(size <= self.size); let success = libc::mprotect(start as _, size, protect as i32); diff --git a/lib/runtime-core/src/sys/windows/memory.rs b/lib/runtime-core/src/sys/windows/memory.rs index 971da9007..5a2a243b4 100644 --- a/lib/runtime-core/src/sys/windows/memory.rs +++ b/lib/runtime-core/src/sys/windows/memory.rs @@ -4,7 +4,7 @@ use winapi::um::memoryapi::{ PAGE_NOACCESS, PAGE_EXECUTE_READ, PAGE_READWRITE, PAGE_READONLY, }; use page_size; -use std::ops::Range; +use std::ops::{Bound, RangeBounds}; use std::{ptr, slice}; #[derive(Debug)] @@ -43,13 +43,26 @@ impl Memory { } } - pub unsafe fn protect(&mut self, range: Range, protect: Protect) -> Result<(), String> { + pub unsafe fn protect(&mut self, range: impl RangeBounds, protect: Protect) -> Result<(), String> { let protect = protect.to_protect_const(); + + let range_start = match range.start_bound() { + Bound::Included(start) => *start, + Bound::Excluded(start) => *start, + Bound::Unbounded => 0, + }; + + let range_end = match range.end_bound() { + Bound::Included(end) => *end, + Bound::Excluded(end) => *end, + Bound::Unbounded => self.size(), + }; + let page_size = page_size::get(); let start = self .ptr - .add(round_down_to_page_size(range.start, page_size)); - let size = round_up_to_page_size(range.end - range.start, page_size); + .add(round_down_to_page_size(range_start, page_size)); + let size = round_up_to_page_size(range_end - range_start, page_size); assert!(size <= self.size); // Commit the virtual memory. diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 0d49668fb..c762cd87b 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -1,5 +1,6 @@ use crate::{module::ModuleInner, structures::TypedIndex}; +/// Represents a WebAssembly type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Type { /// The `i32` type. @@ -12,6 +13,10 @@ pub enum Type { F64, } +/// Represents a WebAssembly value. +/// +/// As the number of types in WebAssembly expand, +/// this structure will expand as well. #[derive(Debug, Clone, PartialEq)] pub enum Value { /// The `i32` type. diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index a55bcbb08..1d6bcdc7d 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -6,6 +6,9 @@ use crate::{ }; use std::{ffi::c_void, mem, ptr, slice}; +/// The context of the currently running WebAssembly instance. +/// +/// #[derive(Debug)] #[repr(C)] pub struct Ctx { @@ -39,6 +42,7 @@ pub struct Ctx { } impl Ctx { + #[doc(hidden)] pub unsafe fn new( local_backing: &mut LocalBacking, import_backing: &mut ImportBacking, @@ -63,6 +67,7 @@ impl Ctx { } } + #[doc(hidden)] pub unsafe fn new_with_data( local_backing: &mut LocalBacking, import_backing: &mut ImportBacking, @@ -89,7 +94,64 @@ impl Ctx { } } - pub fn memory<'a>(&'a mut self, mem_index: u32) -> &'a mut [u8] { + /// This exposes the specified memory of the WebAssembly instance + /// as a immutable slice. + /// + /// WebAssembly will soon support multiple linear memories, so this + /// forces the user to specify. + /// + /// # Usage: + /// + /// ``` + /// # use wasmer_runtime_core::{ + /// # vm::Ctx, + /// # }; + /// fn read_memory(ctx: &Ctx) -> u8 { + /// let first_memory = ctx.memory(0); + /// // Read the first byte of that linear memory. + /// first_memory[0] + /// } + /// ``` + pub fn memory<'a>(&'a self, mem_index: u32) -> &'a [u8] { + let module = unsafe { &*self.module }; + let mem_index = MemoryIndex::new(mem_index as usize); + match mem_index.local_or_import(module) { + LocalOrImport::Local(local_mem_index) => { + let local_backing = unsafe { &*self.local_backing }; + &local_backing.memories[local_mem_index][..] + } + LocalOrImport::Import(import_mem_index) => { + let import_backing = unsafe { &mut *self.import_backing }; + let vm_memory_import = import_backing.memories[import_mem_index].clone(); + unsafe { + let memory = &*vm_memory_import.memory; + + slice::from_raw_parts(memory.base, memory.size) + } + } + } + } + + /// 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_mut(0); + /// // Set the first byte of that linear memory. + /// first_memory[0] = 42; + /// } + /// ``` + pub fn memory_mut<'a>(&'a mut self, mem_index: u32) -> &'a mut [u8] { let module = unsafe { &*self.module }; let mem_index = MemoryIndex::new(mem_index as usize); match mem_index.local_or_import(module) { @@ -110,6 +172,7 @@ impl Ctx { } } +#[doc(hidden)] impl Ctx { #[allow(clippy::erasing_op)] // TODO pub fn offset_memories() -> u8 { @@ -145,10 +208,11 @@ impl Ctx { } } +enum InnerFunc {} /// Used to provide type safety (ish) for passing around function pointers. /// The typesystem ensures this cannot be dereferenced since an /// empty enum cannot actually exist. -pub enum Func {} +pub struct Func(InnerFunc); /// An imported function, which contains the vmctx that owns this function. #[derive(Debug, Clone)] diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 14b88cc63..b7cafc895 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,12 +1,15 @@ [package] name = "wasmer-runtime" -version = "0.2.0" +version = "0.1.1" +description = "Wasmer runtime library" +license = "MIT" authors = ["The Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" edition = "2018" [dependencies] -wasmer-runtime-core = { path = "../runtime-core" } -wasmer-clif-backend = { path = "../clif-backend", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.1.1" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.1.1", optional = true } [features] default = ["wasmer-clif-backend"] diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index af8311cec..fd40a8b4a 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -1,47 +1,58 @@ -#[doc(inline)] -pub use wasmer_runtime_core::*; - -pub use wasmer_runtime_core::instance::Instance; +pub use wasmer_runtime_core::import::ImportObject; +pub use wasmer_runtime_core::instance::{Function, Instance}; 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` -/// from WebAssembly binary code. This function is useful if it -/// is necessary to a compile a module before it can be instantiated -/// (otherwise, the webassembly::instantiate() function should be used). +pub use wasmer_runtime_core::{compile_with, validate}; + +pub use wasmer_runtime_core::error; +pub use wasmer_runtime_core::imports; + +pub mod wasm { + pub use wasmer_runtime_core::instance::Function; + pub use wasmer_runtime_core::types::{FuncSig, 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 /// binary code of the wasm module you want to compile. -/// Errors: -/// If the operation fails, the function returns `Err(error::CompileError::...).` +/// # Errors: +/// If the operation fails, the function returns `Err(error::CompileError::...)`. #[cfg(feature = "wasmer-clif-backend")] -pub fn compile(wasm: &[u8]) -> error::CompileResult { +pub fn compile(wasm: &[u8]) -> error::CompileResult { use wasmer_clif_backend::CraneliftCompiler; wasmer_runtime_core::compile_with(&wasm[..], &CraneliftCompiler::new()) } -/// The `instantiate(...)` function allows you to compile and -/// instantiate WebAssembly code in one go. +/// Compile and instantiate WebAssembly code without +/// creating a [`Module`]. /// -/// Params: +/// [`Module`]: struct.Module.html +/// +/// # Params: /// * `wasm`: A `&[u8]` containing the /// binary code of the wasm module you want to compile. /// * `import_object`: An object containing the values to be imported /// 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 -/// webassembly::LinkError is thrown. -/// Errors: +/// LinkError is thrown. +/// # Errors: /// If the operation fails, the function returns a /// `error::CompileError`, `error::LinkError`, or /// `error::RuntimeError` (all combined into an `error::Error`), /// depending on the cause of the failure. #[cfg(feature = "wasmer-clif-backend")] -pub fn instantiate( - wasm: &[u8], - import_object: import::ImportObject, -) -> error::Result { +pub fn instantiate(wasm: &[u8], import_object: ImportObject) -> error::Result { let module = compile(wasm)?; module.instantiate(import_object) } diff --git a/src/webassembly/mod.rs b/src/webassembly/mod.rs index 628114614..6e9234988 100644 --- a/src/webassembly/mod.rs +++ b/src/webassembly/mod.rs @@ -5,10 +5,7 @@ use wasmer_runtime::{ self as runtime, error::CallError, error::{CallResult, Result}, - import::ImportObject, - instance::Instance, - module::Module, - types::{FuncSig, Type, Value}, + ImportObject, Instance, Module, }; use wasmer_emscripten::{is_emscripten_module, run_emscripten_instance};