mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-12 22:05:33 +00:00
Merge branch 'master' into fix/emscripten-translate
This commit is contained in:
commit
82e7ab6394
28
Cargo.lock
generated
28
Cargo.lock
generated
@ -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)",
|
||||
]
|
||||
|
@ -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 <engineering@wasmer.io>"]
|
||||
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"
|
||||
|
@ -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() })?;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 <engineering@wasmer.io>"]
|
||||
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]
|
||||
|
@ -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<Vec<Value>> {
|
||||
// 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![],
|
||||
|
@ -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 <engineering@wasmer.io>"]
|
||||
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"
|
||||
|
||||
|
@ -5,6 +5,7 @@ pub type CompileResult<T> = std::result::Result<T, Box<CompileError>>;
|
||||
pub type LinkResult<T> = std::result::Result<T, Vec<LinkError>>;
|
||||
pub type RuntimeResult<T> = std::result::Result<T, Box<RuntimeError>>;
|
||||
pub type CallResult<T> = std::result::Result<T, Box<CallError>>;
|
||||
pub type ResolveResult<T> = std::result::Result<T, Box<ResolveError>>;
|
||||
|
||||
/// 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<Type> },
|
||||
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<Type> },
|
||||
NoSuchExport { name: String },
|
||||
ExportNotFunc { name: String },
|
||||
Resolve(ResolveError),
|
||||
Runtime(RuntimeError),
|
||||
}
|
||||
|
||||
@ -162,3 +178,39 @@ impl From<Box<RuntimeError>> for Box<CallError> {
|
||||
Box::new(CallError::Runtime(*runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<ResolveError>> for Box<CallError> {
|
||||
fn from(resolve_err: Box<ResolveError>) -> Self {
|
||||
Box::new(CallError::Resolve(*resolve_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompileError> for Box<Error> {
|
||||
fn from(compile_err: CompileError) -> Self {
|
||||
Box::new(Error::CompileError(compile_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for Box<Error> {
|
||||
fn from(runtime_err: RuntimeError) -> Self {
|
||||
Box::new(Error::RuntimeError(runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CallError> for Box<Error> {
|
||||
fn from(call_err: CallError) -> Self {
|
||||
Box::new(Error::CallError(call_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for Box<CallError> {
|
||||
fn from(runtime_err: RuntimeError) -> Self {
|
||||
Box::new(CallError::Runtime(runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResolveError> for Box<CallError> {
|
||||
fn from(resolve_err: ResolveError) -> Self {
|
||||
Box::new(CallError::Resolve(resolve_err))
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,53 @@ pub trait LikeNamespace {
|
||||
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 {
|
||||
map: HashMap<String, Box<dyn LikeNamespace>>,
|
||||
}
|
||||
|
||||
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<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>>
|
||||
where
|
||||
S: Into<String>,
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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, )* ) => {{
|
||||
|
@ -42,16 +42,44 @@ pub struct ModuleInner {
|
||||
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 {
|
||||
pub(crate) fn new(inner: Rc<ModuleInner>) -> Self {
|
||||
Module(inner)
|
||||
}
|
||||
|
||||
/// Instantiate a WebAssembly module with the provided imports.
|
||||
pub fn instantiate(&self, imports: ImportObject) -> Result<Instance> {
|
||||
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> {
|
||||
Instance::new(Rc::clone(&self.0), Box::new(import_object))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<usize>, protect: Protect) -> Result<(), String> {
|
||||
pub unsafe fn protect(
|
||||
&mut self,
|
||||
range: impl RangeBounds<usize>,
|
||||
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);
|
||||
|
@ -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<usize>, protect: Protect) -> Result<(), String> {
|
||||
pub unsafe fn protect(&mut self, range: impl RangeBounds<usize>, 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.
|
||||
|
@ -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.
|
||||
|
@ -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)]
|
||||
|
@ -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 <engineering@wasmer.io>"]
|
||||
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"]
|
||||
|
@ -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<module::Module> {
|
||||
pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
|
||||
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<instance::Instance> {
|
||||
pub fn instantiate(wasm: &[u8], import_object: ImportObject) -> error::Result<Instance> {
|
||||
let module = compile(wasm)?;
|
||||
module.instantiate(import_object)
|
||||
}
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user