merge upstream/master into wasmer-private/feature/llvm-backend

This commit is contained in:
Lachlan Sneff 2019-03-04 13:03:32 -08:00
commit 4e198bca8b
60 changed files with 1827 additions and 2087 deletions

View File

@ -14,30 +14,36 @@ environment:
cache:
- 'C:\Users\appveyor\.cargo'
- target
install:
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init.exe -yv --default-host %target%
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
# - rustup-init.exe -yv --default-host %target%
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
- rustup default stable-%target%
- rustup update
- rustc -vV
- cargo -vV
# Install InnoSetup
- appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-08-22-is.exe
- 2017-08-22-is.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
- set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
# uncomment to RDP to appveyor
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
build_script:
- cargo build --verbose
- cargo build --release --verbose
test_script:
- set RUST_BACKTRACE=1
- cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
- cargo test --package wasmer-spectests
before_deploy:
after_build:
- cd ./src/installer
- iscc wasmer.iss
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
artifacts:
- path: WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
name: WasmerInstaller.exe
- appveyor PushArtifact ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- cd ..\..\
deploy:
description: 'WasmerInstaller'

1514
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer"
version = "0.1.4"
version = "0.2.1"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
repository = "https://github.com/wasmerio/wasmer"
@ -36,6 +36,6 @@ glob = "0.2.11"
[features]
default = ["fast-tests"]
debug = []
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
# This feature will allow cargo test to run much faster
fast-tests = []

View File

@ -19,7 +19,7 @@ capi:
# rm -rf artifacts
build:
cargo build
cargo build --features debug
install:
cargo install --path .
@ -47,6 +47,9 @@ release:
# brew install mingw-w64
cargo build --release
debug-release:
cargo build --release --features debug
debug-release:
cargo build --release --features "debug"

View File

@ -142,6 +142,14 @@ You can also run integration tests with:
make integration-tests
```
## Benchmarking
Benchmarks can be run with:
```sh
cargo bench --all
```
## Roadmap
Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction.

26
examples/nginx/LICENSE Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2002-2019 Igor Sysoev
* Copyright (C) 2011-2019 Nginx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

View File

@ -133,7 +133,7 @@ wasmer_link() {
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"\$HOME/.wasmer\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\nexport PATH=\"\$HOME/.wasmer/bin:\$PATH\"\n"
# We create the wasmer.sh file
echo "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
printf "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
if [ -z "${WASMER_PROFILE-}" ] ; then
printf "${red}Profile not found. Tried:\n* ${WASMER_PROFILE} (as defined in \$PROFILE)\n* ~/.bashrc\n* ~/.bash_profile\n* ~/.zshrc\n* ~/.profile.\n"

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-clif-backend"
version = "0.1.2"
version = "0.2.0"
description = "Wasmer runtime Cranelift compiler backend"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
cranelift-native = "0.26.0"
cranelift-codegen = "0.26.0"
cranelift-entity = "0.26.0"
@ -18,7 +18,8 @@ target-lexicon = "0.2.0"
wasmparser = "0.23.0"
byteorder = "1"
nix = "0.13.0"
libc = "0.2.48"
libc = "0.2.49"
rayon = "1.0"
# Dependencies for caching.
[dependencies.serde]
@ -32,7 +33,7 @@ version = "0.0.7"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.0.1" }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.2.0" }
[features]
debug = ["wasmer-runtime-core/debug"]

View File

@ -24,6 +24,7 @@ use wasmer_runtime_core::{
#[macro_use]
extern crate serde_derive;
extern crate rayon;
extern crate serde;
use wasmparser::{self, WasmDecoder};

View File

@ -7,6 +7,7 @@ use crate::{
},
signal::HandlerData,
};
use rayon::prelude::*;
use byteorder::{ByteOrder, LittleEndian};
use cranelift_codegen::{ir, isa, Context};
@ -92,25 +93,44 @@ impl FuncResolverBuilder {
function_bodies: Map<LocalFuncIndex, ir::Function>,
info: &ModuleInfo,
) -> CompileResult<(Self, HandlerData)> {
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
let mut local_relocs = Map::with_capacity(function_bodies.len());
let mut external_relocs = Map::new();
let num_func_bodies = function_bodies.len();
let mut local_relocs = Map::with_capacity(num_func_bodies);
let mut external_relocs = Map::with_capacity(num_func_bodies);
let mut trap_sink = TrapSink::new();
let compiled_functions: Result<Vec<(Vec<u8>, (RelocSink, LocalTrapSink))>, CompileError> =
function_bodies
.into_vec()
.par_iter()
.map_init(
|| Context::new(),
|ctx, func| {
let mut code_buf = Vec::new();
ctx.func = func.to_owned();
let mut reloc_sink = RelocSink::new();
let mut local_trap_sink = LocalTrapSink::new();
let mut ctx = Context::new();
let mut total_size = 0;
for (_, func) in function_bodies {
ctx.func = func;
let mut code_buf = Vec::new();
let mut reloc_sink = RelocSink::new();
ctx.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut local_trap_sink)
ctx.compile_and_emit(
isa,
&mut code_buf,
&mut reloc_sink,
&mut local_trap_sink,
)
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
ctx.clear();
Ok((code_buf, (reloc_sink, local_trap_sink)))
},
)
.collect();
let compiled_functions = compiled_functions?;
let mut total_size = 0;
// We separate into two iterators, one iterable and one into iterable
let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
compiled_functions.into_iter().unzip();
for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
{
// Clear the local trap sink and consolidate all trap info
// into a single location.
trap_sink.drain_local(total_size, &mut local_trap_sink);
@ -118,7 +138,6 @@ impl FuncResolverBuilder {
// Round up each function's size to pointer alignment.
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
compiled_functions.push(code_buf);
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
}
@ -145,10 +164,10 @@ impl FuncResolverBuilder {
*i = 0xCC;
}
let mut map = Map::with_capacity(compiled_functions.len());
let mut map = Map::with_capacity(num_func_bodies);
let mut previous_end = 0;
for compiled in compiled_functions.iter() {
for compiled in code_bufs.iter() {
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
unsafe {
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]

View File

@ -2,7 +2,7 @@ use crate::relocation::{TrapData, TrapSink};
use crate::trampoline::Trampolines;
use hashbrown::HashSet;
use libc::c_void;
use std::{cell::Cell, sync::Arc};
use std::{any::Any, cell::Cell, sync::Arc};
use wasmer_runtime_core::{
backend::{ProtectedCaller, Token, UserTrapper},
error::RuntimeResult,
@ -25,14 +25,14 @@ pub use self::unix::*;
pub use self::windows::*;
thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<String>> = Cell::new(None);
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
}
pub struct Trapper;
impl UserTrapper for Trapper {
unsafe fn do_early_trap(&self, msg: String) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
trigger_trap()
}
}

View File

@ -79,8 +79,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
if signum != 0 {
*jmp_buf = prev_jmp_buf;
if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(RuntimeError::User { msg })
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(RuntimeError::Panic { data })
} else {
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
@ -91,28 +91,28 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
{
Err(match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode {
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
table: TableIndex::new(0),
TrapCode::BadSignature => RuntimeError::Trap {
msg: "incorrect call_indirect signature".into(),
},
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
table: TableIndex::new(0),
TrapCode::IndirectCallToNull => RuntimeError::Trap {
msg: "indirect call to null".into(),
},
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
table: TableIndex::new(0),
TrapCode::TableOutOfBounds => RuntimeError::Trap {
msg: "table out-of-bounds access".into(),
},
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
_ => RuntimeError::Trap {
msg: "unknown trap".into(),
},
},
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
Ok(SIGFPE) => RuntimeError::Trap {
msg: "illegal arithmetic operation".into(),
},
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
_ => unimplemented!(),
}
.into())
@ -126,8 +126,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
_ => "unkown trapped signal",
};
// When the trap-handler is fully implemented, this will return more information.
Err(RuntimeError::Unknown {
msg: format!("trap at {:p} - {}", faulting_addr, signal),
Err(RuntimeError::Trap {
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
}
.into())
}

View File

@ -57,35 +57,34 @@ pub fn call_protected(
}) = handler_data.lookup(instruction_pointer as _)
{
Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
table: TableIndex::new(0),
TrapCode::BadSignature => RuntimeError::Trap {
msg: "incorrect call_indirect signature".into(),
},
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
table: TableIndex::new(0),
TrapCode::IndirectCallToNull => RuntimeError::Trap {
msg: "indirect call to null".into(),
},
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
memory: MemoryIndex::new(0),
addr: None,
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
table: TableIndex::new(0),
TrapCode::TableOutOfBounds => RuntimeError::Trap {
msg: "table out-of-bounds access".into(),
},
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
_ => RuntimeError::Trap {
msg: "unknown trap".into(),
},
},
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap {
msg: "stack overflow trap".into(),
},
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation,
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation,
_ => RuntimeError::Unknown {
msg: "unknown trap".to_string(),
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap {
msg: "illegal arithmetic operation".into(),
},
_ => RuntimeError::Trap {
msg: "unknown trap".into(),
},
}
.into())
@ -103,8 +102,8 @@ pub fn call_protected(
_ => "unkown trapped signal",
};
Err(RuntimeError::Unknown {
msg: format!("trap at {} - {}", exception_address, signal),
Err(RuntimeError::Trap {
msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
}
.into())
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-emscripten"
version = "0.1.0"
version = "0.2.1"
description = "Wasmer runtime emscripten implementation library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,9 +9,9 @@ edition = "2018"
build = "build/mod.rs"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
lazy_static = "1.2.0"
libc = { git = "https://github.com/rust-lang/libc" }
libc = "0.2.49"
byteorder = "1"
time = "0.1.41"
@ -19,7 +19,7 @@ time = "0.1.41"
rand = "0.6"
[dev-dependencies]
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.0" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
wabt = "0.7.2"
[build-dependencies]

10
lib/emscripten/emtests/test_getcwd.c vendored Normal file
View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include <unistd.h>
int main() {
const unsigned int size = 256;
char cwd[size] = {};
char* buf = getcwd(cwd, size);
printf("getcwd\n");
return 0;
}

View File

@ -0,0 +1 @@
getcwd

BIN
lib/emscripten/emtests/test_getcwd.wasm vendored Normal file

Binary file not shown.

View File

@ -502,6 +502,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
"___syscall168" => func!(crate::syscalls::___syscall168),
"___syscall180" => func!(crate::syscalls::___syscall180),
"___syscall181" => func!(crate::syscalls::___syscall181),
"___syscall183" => func!(crate::syscalls::___syscall183),
"___syscall191" => func!(crate::syscalls::___syscall191),
"___syscall192" => func!(crate::syscalls::___syscall192),
"___syscall194" => func!(crate::syscalls::___syscall194),

View File

@ -46,8 +46,13 @@ use std::slice;
// Another conditional constant for name resolution: Macos et iOS use
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
// Other platforms do otherwise.
use crate::env::get_emscripten_data;
use crate::utils::copy_cstr_into_wasm;
use crate::utils::read_string_from_wasm;
#[cfg(target_os = "darwin")]
use libc::SO_NOSIGPIPE;
use std::ffi::CString;
#[cfg(not(target_os = "darwin"))]
const SO_NOSIGPIPE: c_int = 0;
@ -66,10 +71,10 @@ pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall3 (read) {}", which);
let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx);
let count = varargs.get(ctx);
let count: i32 = varargs.get(ctx);
debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void;
let ret = unsafe { read(fd, buf_addr, count) };
let ret = unsafe { read(fd, buf_addr, count as _) };
debug!("=> ret: {}", ret);
ret as _
}
@ -79,10 +84,10 @@ pub fn ___syscall4(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall4 (write) {}", which);
let fd: i32 = varargs.get(ctx);
let buf: u32 = varargs.get(ctx);
let count = varargs.get(ctx);
let count: i32 = varargs.get(ctx);
debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void;
unsafe { write(fd, buf_addr, count) as i32 }
unsafe { write(fd, buf_addr, count as _) as i32 }
}
/// close
@ -186,6 +191,25 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1
}
// getcwd
pub fn ___syscall183(ctx: &mut Ctx, buf_offset: u32, _size: u32) -> u32 {
debug!("emscripten::___syscall183");
use std::env;
let path = env::current_dir();
let path_string = path.unwrap().display().to_string();
let len = path_string.len();
unsafe {
let pointer_to_buffer =
emscripten_memory_pointer!(ctx.memory(0), buf_offset) as *mut libc::c_char;
let slice = slice::from_raw_parts_mut(pointer_to_buffer, len.clone());
for (byte, loc) in path_string.bytes().zip(slice.iter_mut()) {
*loc = byte as _;
}
*pointer_to_buffer.add(len.clone()) = 0;
}
buf_offset
}
// mmap2
pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall192 (mmap2) {}", which);
@ -217,10 +241,10 @@ pub fn ___syscall140(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
// -> c_int
debug!("emscripten::___syscall140 (lseek) {}", which);
let fd: i32 = varargs.get(ctx);
let offset = varargs.get(ctx);
let offset: i32 = varargs.get(ctx);
let whence: i32 = varargs.get(ctx);
debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence);
unsafe { lseek(fd, offset, whence) as _ }
unsafe { lseek(fd, offset as _, whence) as _ }
}
/// readv

View File

@ -54,6 +54,7 @@ mod test_funcptrfunc;
mod test_funcs;
mod test_functionpointer_libfunc_varargs;
mod test_fwrite_0;
mod test_getcwd;
mod test_getgep;
mod test_getloadavg;
mod test_getopt;

View File

@ -0,0 +1,9 @@
#[test]
fn test_getcwd() {
assert_emscripten_output!(
"../../emtests/test_getcwd.wasm",
"getcwd",
vec![],
"../../emtests/test_getcwd.out"
);
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-c-api"
version = "0.1.4"
version = "0.2.1"
description = "Wasmer c-api library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,8 +9,8 @@ edition = "2018"
readme = "README.md"
[dependencies]
wasmer-runtime = { path = "../runtime", version = "0.1.2" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
wasmer-runtime = { path = "../runtime", version = "0.2.1" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
libc = "0.2"
[lib]

View File

@ -13,12 +13,10 @@ use std::{ffi::c_void, ptr};
use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value};
use wasmer_runtime_core::export::{Context, Export, FuncPointer};
use wasmer_runtime_core::import::Namespace;
use wasmer_runtime_core::module::{ExportIndex, ImportName};
use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type};
use wasmer_runtime_core::units::{Bytes, Pages};
#[allow(non_camel_case_types)]
pub struct wasmer_import_object_t();
#[allow(non_camel_case_types)]
pub struct wasmer_module_t();
@ -78,7 +76,11 @@ pub struct wasmer_table_t();
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_func_t();
pub struct wasmer_import_func_t();
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_export_func_t();
#[repr(C)]
#[derive(Clone)]
@ -96,14 +98,6 @@ pub struct wasmer_limit_option_t {
pub some: uint32_t,
}
#[repr(C)]
pub struct wasmer_func_signature {
pub params: *const wasmer_value_tag,
pub params_len: c_int,
pub returns: *const wasmer_value_tag,
pub returns_len: c_int,
}
#[repr(C)]
pub struct wasmer_import_t {
module_name: wasmer_byte_array,
@ -112,6 +106,14 @@ pub struct wasmer_import_t {
value: wasmer_import_export_value,
}
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_import_descriptor_t;
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_import_descriptors_t;
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_export_t;
@ -120,6 +122,14 @@ pub struct wasmer_export_t;
#[derive(Clone)]
pub struct wasmer_exports_t;
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_export_descriptor_t;
#[repr(C)]
#[derive(Clone)]
pub struct wasmer_export_descriptors_t;
#[repr(u32)]
#[derive(Clone)]
pub enum wasmer_import_export_kind {
@ -132,7 +142,7 @@ pub enum wasmer_import_export_kind {
#[repr(C)]
#[derive(Clone, Copy)]
pub union wasmer_import_export_value {
func: *const wasmer_func_t,
func: *const wasmer_import_func_t,
table: *const wasmer_table_t,
memory: *const wasmer_memory_t,
global: *const wasmer_global_t,
@ -208,15 +218,14 @@ pub extern "C" fn wasmer_memory_grow(
delta: uint32_t,
) -> wasmer_result_t {
let memory = unsafe { &*(memory as *mut Memory) };
let maybe_delta = memory.grow(Pages(delta));
if let Some(_delta) = maybe_delta {
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "unable to grow memory".to_string(),
});
let delta_result = memory.grow(Pages(delta));
match delta_result {
Ok(_) => wasmer_result_t::WASMER_OK,
Err(grow_error) => {
update_last_error(grow_error);
wasmer_result_t::WASMER_ERROR
}
}
}
/// Returns the current length in pages of the given memory
@ -277,15 +286,14 @@ pub extern "C" fn wasmer_table_grow(
delta: uint32_t,
) -> wasmer_result_t {
let table = unsafe { &*(table as *mut Table) };
let maybe_delta = table.grow(delta);
if let Some(_delta) = maybe_delta {
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "unable to grow table".to_string(),
});
let delta_result = table.grow(delta);
match delta_result {
Ok(_) => wasmer_result_t::WASMER_OK,
Err(grow_error) => {
update_last_error(grow_error);
wasmer_result_t::WASMER_ERROR
}
}
}
/// Returns the current length of the given Table
@ -446,12 +454,24 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
.or_insert_with(|| Namespace::new());
let export = match import.tag {
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export,
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export,
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export,
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export,
wasmer_import_export_kind::WASM_MEMORY => {
let mem = import.value.memory as *mut Memory;
Export::Memory((&*mem).clone())
}
wasmer_import_export_kind::WASM_FUNCTION => {
let func_export = import.value.func as *mut Export;
(&*func_export).clone()
}
wasmer_import_export_kind::WASM_GLOBAL => {
let global = import.value.global as *mut Global;
Export::Global((&*global).clone())
}
wasmer_import_export_kind::WASM_TABLE => {
let table = import.value.table as *mut Table;
Export::Table((&*table).clone())
}
};
namespace.insert(import_name, unsafe { (&*export).clone() });
namespace.insert(import_name, export);
}
for (module_name, namespace) in namespaces.into_iter() {
import_object.register(module_name, namespace);
@ -470,6 +490,91 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
wasmer_result_t::WASMER_OK
}
/// Gets export descriptors for the given module
///
/// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_export_descriptors(
module: *mut wasmer_module_t,
export_descriptors: *mut *mut wasmer_export_descriptors_t,
) {
let mut module = unsafe { &*(module as *mut Module) };
let named_export_descriptors: Box<NamedExportDescriptors> = Box::new(NamedExportDescriptors(
module.info().exports.iter().map(|e| e.into()).collect(),
));
unsafe {
*export_descriptors =
Box::into_raw(named_export_descriptors) as *mut wasmer_export_descriptors_t
};
}
pub struct NamedExportDescriptors(Vec<NamedExportDescriptor>);
/// Frees the memory for the given export descriptors
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_export_descriptors_destroy(
export_descriptors: *mut wasmer_export_descriptors_t,
) {
if !export_descriptors.is_null() {
drop(unsafe { Box::from_raw(export_descriptors as *mut NamedExportDescriptors) });
}
}
/// Gets the length of the export descriptors
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_export_descriptors_len(
exports: *mut wasmer_export_descriptors_t,
) -> c_int {
if exports.is_null() {
return 0;
}
(*(exports as *mut NamedExportDescriptors)).0.len() as c_int
}
/// Gets export descriptor by index
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_export_descriptors_get(
export_descriptors: *mut wasmer_export_descriptors_t,
idx: c_int,
) -> *mut wasmer_export_descriptor_t {
if export_descriptors.is_null() {
return ptr::null_mut();
}
let mut named_export_descriptors =
unsafe { &mut *(export_descriptors as *mut NamedExportDescriptors) };
let ptr = &mut (*named_export_descriptors).0[idx as usize] as *mut NamedExportDescriptor
as *mut wasmer_export_descriptor_t;
ptr
}
/// Gets name for the export descriptor
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_descriptor_name(
export_descriptor: *mut wasmer_export_descriptor_t,
) -> wasmer_byte_array {
let named_export_descriptor = &*(export_descriptor as *mut NamedExportDescriptor);
wasmer_byte_array {
bytes: named_export_descriptor.name.as_ptr(),
bytes_len: named_export_descriptor.name.len() as u32,
}
}
/// Gets export descriptor kind
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_descriptor_kind(
export: *mut wasmer_export_descriptor_t,
) -> wasmer_import_export_kind {
let named_export_descriptor = &*(export as *mut NamedExportDescriptor);
named_export_descriptor.kind.clone()
}
/// Frees memory for the given Module
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
@ -479,6 +584,185 @@ pub extern "C" fn wasmer_module_destroy(module: *mut wasmer_module_t) {
}
}
/// Gets import descriptors for the given module
///
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_descriptors(
module: *mut wasmer_module_t,
import_descriptors: *mut *mut wasmer_import_descriptors_t,
) {
let mut module = unsafe { &*(module as *mut Module) };
let total_imports = module.info().imported_functions.len()
+ module.info().imported_tables.len()
+ module.info().imported_globals.len()
+ module.info().imported_memories.len();
let mut descriptors: Vec<NamedImportDescriptor> = Vec::with_capacity(total_imports);
for (
index,
ImportName {
namespace_index,
name_index,
},
) in &module.info().imported_functions
{
let namespace = module.info().namespace_table.get(*namespace_index);
let name = module.info().name_table.get(*name_index);
descriptors.push(NamedImportDescriptor {
module: namespace.to_string(),
name: name.to_string(),
kind: wasmer_import_export_kind::WASM_FUNCTION,
});
}
for (
index,
(
ImportName {
namespace_index,
name_index,
},
_,
),
) in &module.info().imported_tables
{
let namespace = module.info().namespace_table.get(*namespace_index);
let name = module.info().name_table.get(*name_index);
descriptors.push(NamedImportDescriptor {
module: namespace.to_string(),
name: name.to_string(),
kind: wasmer_import_export_kind::WASM_TABLE,
});
}
for (
index,
(
ImportName {
namespace_index,
name_index,
},
_,
),
) in &module.info().imported_globals
{
let namespace = module.info().namespace_table.get(*namespace_index);
let name = module.info().name_table.get(*name_index);
descriptors.push(NamedImportDescriptor {
module: namespace.to_string(),
name: name.to_string(),
kind: wasmer_import_export_kind::WASM_GLOBAL,
});
}
for (
index,
(
ImportName {
namespace_index,
name_index,
},
_,
),
) in &module.info().imported_memories
{
let namespace = module.info().namespace_table.get(*namespace_index);
let name = module.info().name_table.get(*name_index);
descriptors.push(NamedImportDescriptor {
module: namespace.to_string(),
name: name.to_string(),
kind: wasmer_import_export_kind::WASM_MEMORY,
});
}
let named_import_descriptors: Box<NamedImportDescriptors> =
Box::new(NamedImportDescriptors(descriptors));
unsafe {
*import_descriptors =
Box::into_raw(named_import_descriptors) as *mut wasmer_import_descriptors_t
};
}
pub struct NamedImportDescriptors(Vec<NamedImportDescriptor>);
/// Frees the memory for the given import descriptors
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_descriptors_destroy(
import_descriptors: *mut wasmer_import_descriptors_t,
) {
if !import_descriptors.is_null() {
drop(unsafe { Box::from_raw(import_descriptors as *mut NamedImportDescriptors) });
}
}
/// Gets the length of the import descriptors
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_descriptors_len(
exports: *mut wasmer_import_descriptors_t,
) -> c_int {
if exports.is_null() {
return 0;
}
(*(exports as *mut NamedImportDescriptors)).0.len() as c_int
}
/// Gets import descriptor by index
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_descriptors_get(
import_descriptors: *mut wasmer_import_descriptors_t,
idx: c_int,
) -> *mut wasmer_import_descriptor_t {
if import_descriptors.is_null() {
return ptr::null_mut();
}
let mut named_import_descriptors =
unsafe { &mut *(import_descriptors as *mut NamedImportDescriptors) };
let ptr = &mut (*named_import_descriptors).0[idx as usize] as *mut NamedImportDescriptor
as *mut wasmer_import_descriptor_t;
ptr
}
/// Gets name for the import descriptor
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_import_descriptor_name(
import_descriptor: *mut wasmer_import_descriptor_t,
) -> wasmer_byte_array {
let named_import_descriptor = &*(import_descriptor as *mut NamedImportDescriptor);
wasmer_byte_array {
bytes: named_import_descriptor.name.as_ptr(),
bytes_len: named_import_descriptor.name.len() as u32,
}
}
/// Gets module name for the import descriptor
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_import_descriptor_module_name(
import_descriptor: *mut wasmer_import_descriptor_t,
) -> wasmer_byte_array {
let named_import_descriptor = &*(import_descriptor as *mut NamedImportDescriptor);
wasmer_byte_array {
bytes: named_import_descriptor.module.as_ptr(),
bytes_len: named_import_descriptor.module.len() as u32,
}
}
/// Gets export descriptor kind
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_import_descriptor_kind(
export: *mut wasmer_import_descriptor_t,
) -> wasmer_import_export_kind {
let named_import_descriptor = &*(export as *mut NamedImportDescriptor);
named_import_descriptor.kind.clone()
}
/// Creates a new Instance from the given wasm bytes and imports.
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
@ -534,12 +818,24 @@ pub unsafe extern "C" fn wasmer_instantiate(
.or_insert_with(|| Namespace::new());
let export = match import.tag {
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export,
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export,
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export,
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export,
wasmer_import_export_kind::WASM_MEMORY => {
let mem = import.value.memory as *mut Memory;
Export::Memory((&*mem).clone())
}
wasmer_import_export_kind::WASM_FUNCTION => {
let func_export = import.value.func as *mut Export;
(&*func_export).clone()
}
wasmer_import_export_kind::WASM_GLOBAL => {
let global = import.value.global as *mut Global;
Export::Global((&*global).clone())
}
wasmer_import_export_kind::WASM_TABLE => {
let table = import.value.table as *mut Table;
Export::Table((&*table).clone())
}
};
namespace.insert(import_name, unsafe { (&*export).clone() });
namespace.insert(import_name, unsafe { export });
}
for (module_name, namespace) in namespaces.into_iter() {
import_object.register(module_name, namespace);
@ -649,9 +945,16 @@ pub unsafe extern "C" fn wasmer_instance_exports(
instance: *mut wasmer_instance_t,
exports: *mut *mut wasmer_exports_t,
) {
let mut instance = unsafe { &mut *(instance as *mut Instance) };
let named_exports: Box<NamedExports> =
Box::new(NamedExports(instance.exports().map(|e| e.into()).collect()));
let mut instance_ref = unsafe { &mut *(instance as *mut Instance) };
let mut exports_vec: Vec<NamedExport> = Vec::with_capacity(instance_ref.exports().count());
for (name, export) in instance_ref.exports() {
exports_vec.push(NamedExport {
name: name.clone(),
export: export.clone(),
instance: instance as *mut Instance,
});
}
let named_exports: Box<NamedExports> = Box::new(NamedExports(exports_vec));
unsafe { *exports = Box::into_raw(named_exports) as *mut wasmer_exports_t };
}
@ -706,18 +1009,157 @@ pub unsafe extern "C" fn wasmer_export_kind(
}
}
/// Creates new func
/// Sets the result parameter to the arity of the params of the wasmer_export_func_t
///
/// The caller owns the object and should call `wasmer_func_destroy` to free it.
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_new(
pub unsafe extern "C" fn wasmer_export_func_params_arity(
func: *mut wasmer_export_func_t,
result: *mut uint32_t,
) -> wasmer_result_t {
let mut named_export = unsafe { &*(func as *mut NamedExport) };
let mut export = &named_export.export;
let result = if let Export::Function { ref signature, .. } = *export {
unsafe { *result = signature.params().len() as uint32_t };
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_export_func_params_arity".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the params buffer to the parameter types of the given wasmer_export_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_func_params(
func: *mut wasmer_export_func_t,
params: *mut wasmer_value_tag,
params_len: c_int,
) -> wasmer_result_t {
let mut named_export = unsafe { &*(func as *mut NamedExport) };
let mut export = &named_export.export;
let result = if let Export::Function { ref signature, .. } = *export {
let params: &mut [wasmer_value_tag] =
slice::from_raw_parts_mut(params, params_len as usize);
for (i, item) in signature.params().iter().enumerate() {
params[i] = item.into();
}
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_export_func_params".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the returns buffer to the parameter types of the given wasmer_export_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_func_returns(
func: *mut wasmer_export_func_t,
returns: *mut wasmer_value_tag,
returns_len: c_int,
) -> wasmer_result_t {
let mut named_export = unsafe { &*(func as *mut NamedExport) };
let mut export = &named_export.export;
let result = if let Export::Function { ref signature, .. } = *export {
let returns: &mut [wasmer_value_tag] =
slice::from_raw_parts_mut(returns, returns_len as usize);
for (i, item) in signature.returns().iter().enumerate() {
returns[i] = item.into();
}
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_export_func_returns".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the result parameter to the arity of the returns of the wasmer_export_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_func_returns_arity(
func: *mut wasmer_export_func_t,
result: *mut uint32_t,
) -> wasmer_result_t {
let mut named_export = unsafe { &*(func as *mut NamedExport) };
let mut export = &named_export.export;
let result = if let Export::Function { ref signature, .. } = *export {
unsafe { *result = signature.returns().len() as uint32_t };
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_export_func_results_arity".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the result parameter to the arity of the params of the wasmer_import_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_import_func_params_arity(
func: *mut wasmer_import_func_t,
result: *mut uint32_t,
) -> wasmer_result_t {
let mut export = unsafe { &mut *(func as *mut Export) };
let result = if let Export::Function { ref signature, .. } = *export {
unsafe { *result = signature.params().len() as uint32_t };
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_import_func_params_arity".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Creates new func
///
/// The caller owns the object and should call `wasmer_import_func_destroy` to free it.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_import_func_new(
func: extern "C" fn(data: *mut c_void),
params: *const wasmer_value_tag,
params_len: c_int,
returns: *const wasmer_value_tag,
returns_len: c_int,
) -> *const wasmer_func_t {
) -> *const wasmer_import_func_t {
let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize);
let params: Vec<Type> = params.iter().cloned().map(|x| x.into()).collect();
let returns: &[wasmer_value_tag] = slice::from_raw_parts(returns, returns_len as usize);
@ -728,10 +1170,10 @@ pub unsafe extern "C" fn wasmer_func_new(
ctx: Context::Internal,
signature: Arc::new(FuncSig::new(params, returns)),
});
Box::into_raw(export) as *mut wasmer_func_t
Box::into_raw(export) as *mut wasmer_import_func_t
}
/// Sets the result parameter to the arity of the params of the wasmer_func_t
/// Sets the params buffer to the parameter types of the given wasmer_import_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
@ -739,33 +1181,8 @@ pub unsafe extern "C" fn wasmer_func_new(
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_params_arity(
func: *mut wasmer_func_t,
result: *mut uint32_t,
) -> wasmer_result_t {
let mut export = unsafe { &mut *(func as *mut Export) };
let result = if let Export::Function { ref signature, .. } = *export {
unsafe { *result = signature.params().len() as uint32_t };
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_func_params_arity".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the params buffer to the parameter types of the given wasmer_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_params(
func: *mut wasmer_func_t,
pub unsafe extern "C" fn wasmer_import_func_params(
func: *mut wasmer_import_func_t,
params: *mut wasmer_value_tag,
params_len: c_int,
) -> wasmer_result_t {
@ -779,14 +1196,14 @@ pub unsafe extern "C" fn wasmer_func_params(
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_func_params".to_string(),
msg: "func ptr error in wasmer_import_func_params".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the returns buffer to the parameter types of the given wasmer_func_t
/// Sets the returns buffer to the parameter types of the given wasmer_import_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
@ -794,8 +1211,8 @@ pub unsafe extern "C" fn wasmer_func_params(
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_returns(
func: *mut wasmer_func_t,
pub unsafe extern "C" fn wasmer_import_func_returns(
func: *mut wasmer_import_func_t,
returns: *mut wasmer_value_tag,
returns_len: c_int,
) -> wasmer_result_t {
@ -809,14 +1226,14 @@ pub unsafe extern "C" fn wasmer_func_returns(
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_func_returns".to_string(),
msg: "func ptr error in wasmer_import_func_returns".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
result
}
/// Sets the result parameter to the arity of the returns of the wasmer_func_t
/// Sets the result parameter to the arity of the returns of the wasmer_import_func_t
///
/// Returns `wasmer_result_t::WASMER_OK` upon success.
///
@ -824,8 +1241,8 @@ pub unsafe extern "C" fn wasmer_func_returns(
/// and `wasmer_last_error_message` to get an error message.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_returns_arity(
func: *mut wasmer_func_t,
pub unsafe extern "C" fn wasmer_import_func_returns_arity(
func: *mut wasmer_import_func_t,
result: *mut uint32_t,
) -> wasmer_result_t {
let mut export = unsafe { &*(func as *mut Export) };
@ -834,7 +1251,7 @@ pub unsafe extern "C" fn wasmer_func_returns_arity(
wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: "func ptr error in wasmer_func_results_arity".to_string(),
msg: "func ptr error in wasmer_import_func_results_arity".to_string(),
});
wasmer_result_t::WASMER_ERROR
};
@ -844,20 +1261,19 @@ pub unsafe extern "C" fn wasmer_func_returns_arity(
/// Frees memory for the given Func
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub extern "C" fn wasmer_func_destroy(func: *mut wasmer_func_t) {
pub extern "C" fn wasmer_import_func_destroy(func: *mut wasmer_import_func_t) {
if !func.is_null() {
drop(unsafe { Box::from_raw(func as *mut Export) });
}
}
/// Gets func from wasm_export
/// Gets export func from export
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_to_func(
export: *mut wasmer_export_t,
) -> *const wasmer_func_t {
let named_export = &*(export as *mut NamedExport);
&named_export.export as *const Export as *const wasmer_func_t
) -> *const wasmer_export_func_t {
export as *const wasmer_export_func_t
}
/// Gets name from wasmer_export
@ -880,8 +1296,8 @@ pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) -> was
/// and `wasmer_last_error_message` to get an error message.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_func_call(
func: *mut wasmer_func_t,
pub unsafe extern "C" fn wasmer_export_func_call(
func: *mut wasmer_export_func_t,
params: *const wasmer_value_t,
params_len: c_int,
results: *mut wasmer_value_t,
@ -903,46 +1319,42 @@ pub unsafe extern "C" fn wasmer_func_call(
let params: &[wasmer_value_t] = slice::from_raw_parts(params, params_len as usize);
let params: Vec<Value> = params.iter().cloned().map(|x| x.into()).collect();
let export_func = unsafe { &*(func as *mut Export) };
let named_export = unsafe { &*(func as *mut NamedExport) };
let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize);
// TODO implement func.call
update_last_error(CApiError {
msg: "wasmer_func_call not yet implemented".to_string(),
});
let instance = &*named_export.instance;
let result = instance.call(&named_export.name, &params[..]);
match result {
Ok(results_vec) => {
if results_vec.len() > 0 {
let ret = match results_vec[0] {
Value::I32(x) => wasmer_value_t {
tag: wasmer_value_tag::WASM_I32,
value: wasmer_value { I32: x },
},
Value::I64(x) => wasmer_value_t {
tag: wasmer_value_tag::WASM_I64,
value: wasmer_value { I64: x },
},
Value::F32(x) => wasmer_value_t {
tag: wasmer_value_tag::WASM_F32,
value: wasmer_value { F32: x },
},
Value::F64(x) => wasmer_value_t {
tag: wasmer_value_tag::WASM_F64,
value: wasmer_value { F64: x },
},
};
results[0] = ret;
}
wasmer_result_t::WASMER_OK
}
Err(err) => {
update_last_error(err);
wasmer_result_t::WASMER_ERROR
// let result = instance.call(func_name_r, &params[..]);
// Box::into_raw(export_func);
// match result {
// Ok(results_vec) => {
// if results_vec.len() > 0 {
// let ret = match results_vec[0] {
// Value::I32(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_I32,
// value: wasmer_value { I32: x },
// },
// Value::I64(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_I64,
// value: wasmer_value { I64: x },
// },
// Value::F32(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_F32,
// value: wasmer_value { F32: x },
// },
// Value::F64(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_F64,
// value: wasmer_value { F64: x },
// },
// };
// results[0] = ret;
// }
// wasmer_result_t::WASMER_OK
// }
// Err(err) => {
// update_last_error(err);
// wasmer_result_t::WASMER_ERROR
// }
// }
}
}
}
/// Gets the memory within the context at the index `memory_idx`.
@ -1060,12 +1472,6 @@ impl From<wasmer_value_tag> for Type {
}
}
impl From<(std::string::String, wasmer_runtime_core::export::Export)> for NamedExport {
fn from((name, export): (String, Export)) -> Self {
NamedExport { name, export }
}
}
impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
fn from(ty: &Type) -> Self {
match *ty {
@ -1077,6 +1483,21 @@ impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
}
}
impl From<(&std::string::String, &ExportIndex)> for NamedExportDescriptor {
fn from((name, export_index): (&String, &ExportIndex)) -> Self {
let kind = match *export_index {
ExportIndex::Memory(_) => wasmer_import_export_kind::WASM_MEMORY,
ExportIndex::Global(_) => wasmer_import_export_kind::WASM_GLOBAL,
ExportIndex::Table(_) => wasmer_import_export_kind::WASM_TABLE,
ExportIndex::Func(_) => wasmer_import_export_kind::WASM_FUNCTION,
};
NamedExportDescriptor {
name: name.clone(),
kind,
}
}
}
// Error reporting
thread_local! {
@ -1171,7 +1592,19 @@ impl fmt::Display for CApiError {
impl Error for CApiError {}
struct NamedImportDescriptor {
module: String,
name: String,
kind: wasmer_import_export_kind,
}
struct NamedExport {
name: String,
export: Export,
instance: *mut Instance,
}
struct NamedExportDescriptor {
name: String,
kind: wasmer_import_export_kind,
}

View File

@ -12,9 +12,12 @@ _deps
test-globals
test-exports
test-instantiate
test-imports
test-import-function
test-memory
test-module-imports
test-module
test-module-exports
test-tables
test-validate
rust-build

View File

@ -1,12 +1,15 @@
cmake_minimum_required (VERSION 2.6)
project (WasmerCApiTests)
add_executable(test-imports test-imports.c)
add_executable(test-exports test-exports.c)
add_executable(test-globals test-globals.c)
add_executable(test-instantiate test-instantiate.c)
add_executable(test-import-function test-import-function.c)
add_executable(test-memory test-memory.c)
add_executable(test-module-imports test-module-imports.c)
add_executable(test-module test-module.c)
add_executable(test-module-exports test-module-exports.c)
add_executable(test-validate test-validate.c)
add_executable(test-tables test-tables.c)
@ -19,6 +22,8 @@ if(NOT WASMER_LIB)
message(FATAL_ERROR "wasmer library not found")
endif()
target_link_libraries(test-imports
general ${WASMER_LIB})
target_link_libraries(test-exports
general ${WASMER_LIB})
target_link_libraries(test-globals
@ -29,20 +34,27 @@ target_link_libraries(test-import-function
general ${WASMER_LIB})
target_link_libraries(test-memory
general ${WASMER_LIB})
target_link_libraries(test-module-imports
general ${WASMER_LIB})
target_link_libraries(test-module
general ${WASMER_LIB})
target_link_libraries(test-module-exports
general ${WASMER_LIB})
target_link_libraries(test-validate
general ${WASMER_LIB})
target_link_libraries(test-tables
general ${WASMER_LIB})
enable_testing()
add_test(test-imports test-imports)
add_test(test-exports test-exports)
add_test(test-globals test-globals)
add_test(test-instantiate test-instantiate)
add_test(test-import-function test-import-function)
add_test(test-memory test-memory)
add_test(test-module-imports test-module-imports)
add_test(test-module test-module)
add_test(test-module-exports test-module-exports)
add_test(test-validate test-validate)
add_test(test-tables test-tables)

Binary file not shown.

View File

@ -31,7 +31,7 @@ int main()
wasmer_import_export_kind kind = wasmer_export_kind(export);
assert(kind == WASM_FUNCTION);
wasmer_func_t *func = wasmer_export_to_func(export);
wasmer_export_func_t *func = wasmer_export_to_func(export);
wasmer_byte_array name_bytes = wasmer_export_name(export);
assert(name_bytes.bytes_len == 3);
@ -42,40 +42,40 @@ int main()
}
uint32_t params_arity;
wasmer_func_params_arity(func, &params_arity);
wasmer_export_func_params_arity(func, &params_arity);
assert(params_arity == 2);
wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity);
wasmer_func_params(func, params_sig , params_arity);
wasmer_export_func_params(func, params_sig , params_arity);
assert(params_sig[0] == WASM_I32);
assert(params_sig[1] == WASM_I32);
free(params_sig);
uint32_t returns_arity;
wasmer_func_returns_arity(func, &returns_arity);
wasmer_export_func_returns_arity(func, &returns_arity);
assert(returns_arity == 1);
wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity);
wasmer_func_returns(func, returns_sig , returns_arity);
wasmer_export_func_returns(func, returns_sig , returns_arity);
assert(returns_sig[0] == WASM_I32);
free(returns_sig);
// wasmer_value_t param_one;
// param_one.tag = WASM_I32;
// param_one.value.I32 = 7;
// wasmer_value_t param_two;
// param_two.tag = WASM_I32;
// param_two.value.I32 = 8;
// wasmer_value_t params[] = {param_one, param_two};
// wasmer_value_t result_one;
// wasmer_value_t results[] = {result_one};
//
// wasmer_result_t call_result = wasmer_func_call(func, params, 2, results, 1);
// printf("Call result: %d\n", call_result);
// printf("Result: %d\n", results[0].value.I32);
// assert(results[0].value.I32 == 15);
// assert(call_result == WASMER_OK);
wasmer_value_t param_one;
param_one.tag = WASM_I32;
param_one.value.I32 = 7;
wasmer_value_t param_two;
param_two.tag = WASM_I32;
param_two.value.I32 = 8;
wasmer_value_t params[] = {param_one, param_two};
wasmer_value_t result_one;
wasmer_value_t results[] = {result_one};
wasmer_result_t call_result = wasmer_export_func_call(func, params, 2, results, 1);
printf("Call result: %d\n", call_result);
printf("Result: %d\n", results[0].value.I32);
assert(results[0].value.I32 == 15);
assert(call_result == WASMER_OK);
printf("Destroy instance\n");

View File

@ -31,7 +31,7 @@ int main()
wasmer_value_tag returns_sig[] = {};
printf("Creating new func\n");
wasmer_func_t *func = wasmer_func_new(print_str, params_sig, 2, returns_sig, 0);
wasmer_import_func_t *func = wasmer_import_func_new(print_str, params_sig, 2, returns_sig, 0);
wasmer_import_t import;
char *module_name = "env";
@ -84,7 +84,7 @@ int main()
assert(0 == strcmp(actual_str, "Hello, World!"));
printf("Destroying func\n");
wasmer_func_destroy(func);
wasmer_import_func_destroy(func);
printf("Destroy instance\n");
wasmer_instance_destroy(instance);
return 0;

View File

@ -0,0 +1,154 @@
#include <stdio.h>
#include "../wasmer.h"
#include <assert.h>
#include <stdint.h>
static print_str_called = false;
// Host function that will be imported into the Web Assembly Instance
void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len)
{
print_str_called = true;
wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0);
uint32_t mem_len = wasmer_memory_length(memory);
uint8_t *mem_bytes = wasmer_memory_data(memory);
printf("%.*s", len, mem_bytes + ptr);
}
// Use the last_error API to retrieve error messages
void print_wasmer_error()
{
int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char *error_str = malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("Error str: `%s`\n", error_str);
}
int main()
{
// Create a new func to hold the parameter and signature
// of our `print_str` host function
wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32};
wasmer_value_tag returns_sig[] = {};
wasmer_import_func_t *func = wasmer_import_func_new(print_str, params_sig, 2, returns_sig, 0);
// Create module name for our imports
// represented in bytes for UTF-8 compatability
char *module_name = "env";
wasmer_byte_array module_name_bytes;
module_name_bytes.bytes = module_name;
module_name_bytes.bytes_len = strlen(module_name);
// Define a function import
char *import_name = "_print_str";
wasmer_byte_array import_name_bytes;
import_name_bytes.bytes = import_name;
import_name_bytes.bytes_len = strlen(import_name);
wasmer_import_t func_import;
func_import.module_name = module_name_bytes;
func_import.import_name = import_name_bytes;
func_import.tag = WASM_FUNCTION;
func_import.value.func = func;
// Define a memory import
char *import_memory_name = "memory";
wasmer_byte_array import_memory_name_bytes;
import_memory_name_bytes.bytes = import_memory_name;
import_memory_name_bytes.bytes_len = strlen(import_memory_name);
wasmer_import_t memory_import;
memory_import.module_name = module_name_bytes;
memory_import.import_name = import_memory_name_bytes;
memory_import.tag = WASM_MEMORY;
wasmer_memory_t *memory = NULL;
wasmer_limits_t descriptor;
descriptor.min = 256;
wasmer_limit_option_t max;
max.has_some = true;
max.some = 256;
descriptor.max = max;
wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor);
if (memory_result != WASMER_OK)
{
print_wasmer_error();
}
memory_import.value.memory = memory;
// Define a global import
char *import_global_name = "__memory_base";
wasmer_byte_array import_global_name_bytes;
import_global_name_bytes.bytes = import_global_name;
import_global_name_bytes.bytes_len = strlen(import_global_name);
wasmer_import_t global_import;
global_import.module_name = module_name_bytes;
global_import.import_name = import_global_name_bytes;
global_import.tag = WASM_GLOBAL;
wasmer_value_t val;
val.tag = WASM_I32;
val.value.I32 = 1024;
wasmer_global_t *global = wasmer_global_new(val, false);
global_import.value.global = global;
// Define a table import
char *import_table_name = "table";
wasmer_byte_array import_table_name_bytes;
import_table_name_bytes.bytes = import_table_name;
import_table_name_bytes.bytes_len = strlen(import_table_name);
wasmer_import_t table_import;
table_import.module_name = module_name_bytes;
table_import.import_name = import_table_name_bytes;
table_import.tag = WASM_TABLE;
wasmer_table_t *table = NULL;
wasmer_limits_t table_descriptor;
table_descriptor.min = 256;
wasmer_limit_option_t table_max;
table_max.has_some = true;
table_max.some = 256;
table_descriptor.max = table_max;
wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor);
if (table_result != WASMER_OK)
{
print_wasmer_error();
}
table_import.value.table = table;
// Define an array containing our imports
wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import};
// Read the wasm file bytes
FILE *file = fopen("hello_wasm.wasm", "r");
fseek(file, 0, SEEK_END);
long len = ftell(file);
uint8_t *bytes = malloc(len);
fseek(file, 0, SEEK_SET);
fread(bytes, 1, len, file);
fclose(file);
// Creates a WebAssembly Instance from wasm bytes and imports
wasmer_instance_t *instance = NULL;
wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 3);
printf("Compile result: %d\n", compile_result);
if (compile_result != WASMER_OK)
{
print_wasmer_error();
}
assert(compile_result == WASMER_OK);
// Call the exported "hello_wasm" function of our instance
wasmer_value_t params[] = {};
wasmer_value_t result_one;
wasmer_value_t results[] = {result_one};
wasmer_result_t call_result = wasmer_instance_call(instance, "_hello_wasm", params, 0, results, 1);
printf("Call result: %d\n", call_result);
assert(call_result == WASMER_OK);
assert(print_str_called);
// Use *_destroy methods to cleanup as specified in the header documentation
wasmer_import_func_destroy(func);
wasmer_global_destroy(global);
wasmer_memory_destroy(memory);
wasmer_table_destroy(table);
wasmer_instance_destroy(instance);
return 0;
}

View File

@ -38,23 +38,26 @@ int main()
char *error_str = malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("Error str: `%s`\n", error_str);
assert(0 == strcmp(error_str, "unable to grow memory"));
assert(0 == strcmp(error_str, "Failed to add pages because would exceed maximum number of pages for the memory. Left: 22, Added: 15"));
free(error_str);
wasmer_memory_t *bad_memory = NULL;
wasmer_limits_t bad_descriptor;
bad_descriptor.min = 15;
wasmer_limit_option_t max2;
max2.has_some = true;
max2.some = 10;
bad_descriptor.max = max2;
wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor);
printf("Bad memory result: %d\n", bad_memory_result);
assert(bad_memory_result == WASMER_ERROR);
// wasmer_memory_t *bad_memory = NULL;
// wasmer_limits_t bad_descriptor;
// bad_descriptor.min = 15;
// bad_descriptor.max = 10;
// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor);
// printf("Bad memory result: %d\n", bad_memory_result);
// assert(memory_result == WASMER_MEMORY_ERROR);
//
// int error_len = wasmer_last_error_length();
// char *error_str = malloc(error_len);
// wasmer_last_error_message(error_str, error_len);
// assert(0 == strcmp(error_str, "Creation error"));
// free(error_str);
int error_len2 = wasmer_last_error_length();
char *error_str2 = malloc(error_len2);
wasmer_last_error_message(error_str2, error_len2);
printf("Error str 2: `%s`\n", error_str2);
assert(0 == strcmp(error_str2, "Unable to create because the supplied descriptor is invalid: \"Max number of memory pages is less than the minimum number of pages\""));
free(error_str2);
printf("Destroy memory\n");
wasmer_memory_destroy(memory);

View File

@ -0,0 +1,53 @@
#include <stdio.h>
#include "../wasmer.h"
#include <assert.h>
#include <stdint.h>
int main()
{
// Read the wasm file bytes
FILE *file = fopen("sum.wasm", "r");
fseek(file, 0, SEEK_END);
long len = ftell(file);
uint8_t *bytes = malloc(len);
fseek(file, 0, SEEK_SET);
fread(bytes, 1, len, file);
fclose(file);
wasmer_module_t *module = NULL;
wasmer_result_t compile_result = wasmer_compile(&module, bytes, len);
printf("Compile result: %d\n", compile_result);
assert(compile_result == WASMER_OK);
wasmer_import_t imports[] = {};
wasmer_instance_t *instance = NULL;
wasmer_result_t instantiate_result = wasmer_module_instantiate(module, &instance, imports, 0);
printf("Instantiate result: %d\n", compile_result);
assert(instantiate_result == WASMER_OK);
wasmer_export_descriptors_t *exports = NULL;
wasmer_export_descriptors(module, &exports);
int exports_len = wasmer_export_descriptors_len(exports);
printf("exports_len: %d\n", exports_len);
assert(exports_len == 1);
wasmer_export_descriptor_t *export = wasmer_export_descriptors_get(exports, 0);
wasmer_import_export_kind kind = wasmer_export_descriptor_kind(export);
assert(kind == WASM_FUNCTION);
wasmer_byte_array name_bytes = wasmer_export_descriptor_name(export);
assert(name_bytes.bytes_len == 3);
char expected[] = {'s', 'u', 'm'};
for(int idx = 0; idx < 3; idx++){
printf("%c\n", name_bytes.bytes[idx]);
assert(name_bytes.bytes[idx] == expected[idx]);
}
printf("Destroy module\n");
wasmer_module_destroy(module);
printf("Destroy exports\n");
wasmer_export_descriptors_destroy(exports);
return 0;
}

View File

@ -0,0 +1,56 @@
#include <stdio.h>
#include "../wasmer.h"
#include <assert.h>
#include <stdint.h>
int main()
{
// Read the wasm file bytes
FILE *file = fopen("wasm_sample_app.wasm", "r");
fseek(file, 0, SEEK_END);
long len = ftell(file);
uint8_t *bytes = malloc(len);
fseek(file, 0, SEEK_SET);
fread(bytes, 1, len, file);
fclose(file);
wasmer_module_t *module = NULL;
wasmer_result_t compile_result = wasmer_compile(&module, bytes, len);
printf("Compile result: %d\n", compile_result);
assert(compile_result == WASMER_OK);
wasmer_import_descriptors_t *imports = NULL;
wasmer_import_descriptors(module, &imports);
int imports_len = wasmer_import_descriptors_len(imports);
printf("imports_len: %d\n", imports_len);
assert(imports_len == 1);
wasmer_import_descriptor_t *import = wasmer_import_descriptors_get(imports, 0);
wasmer_import_export_kind kind = wasmer_import_descriptor_kind(import);
assert(kind == WASM_FUNCTION);
wasmer_byte_array name_bytes = wasmer_import_descriptor_name(import);
assert(name_bytes.bytes_len == 9);
char expected[] = {'p', 'r', 'i', 'n', 't', '_', 's', 't', 'r'};
for(int idx = 0; idx < 9; idx++){
printf("%c\n", name_bytes.bytes[idx]);
assert(name_bytes.bytes[idx] == expected[idx]);
}
wasmer_byte_array module_name_bytes = wasmer_import_descriptor_module_name(import);
assert(module_name_bytes.bytes_len == 3);
char module_expected[] = {'e', 'n', 'v'};
for(int idx = 0; idx < 3; idx++){
printf("%c\n", module_name_bytes.bytes[idx]);
assert(module_name_bytes.bytes[idx] == module_expected[idx]);
}
printf("Destroy module\n");
wasmer_module_destroy(module);
printf("Destroy imports\n");
wasmer_import_descriptors_destroy(imports);
return 0;
}

View File

@ -9,7 +9,7 @@ int main()
wasmer_limits_t descriptor;
descriptor.min = 10;
wasmer_limit_option_t max;
// max.has_some = false;
// max.has_some = false;
max.has_some = true;
max.some = 15;
descriptor.max = max;
@ -21,26 +21,29 @@ int main()
printf("Table length: %d\n", len);
assert(len == 10);
// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
// assert(grow_result1 == WASMER_OK);
// uint32_t len_grow1 = wasmer_table_length(table);
// printf("Table length: %d\n", len_grow1);
// assert(len_grow1 == 15);
wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
assert(grow_result1 == WASMER_OK);
uint32_t len_grow1 = wasmer_table_length(table);
printf("Table length: %d\n", len_grow1);
assert(len_grow1 == 15);
// // Try to grow beyond max
// wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1);
// assert(grow_result2 == WASMER_ERROR);
// uint32_t len_grow2 = wasmer_table_length(table);
// printf("Table length: %d\n", len_grow2);
// assert(len_grow2 == 15);
// Try to grow beyond max
wasmer_result_t grow_result2 = wasmer_table_grow(table, 1);
assert(grow_result2 == WASMER_ERROR);
uint32_t len_grow2 = wasmer_table_length(table);
printf("Table length: %d\n", len_grow2);
assert(len_grow2 == 15);
// wasmer_table_t *table_bad = NULL;
// wasmer_limits_t bad_descriptor;
// bad_descriptor.min = 15;
// bad_descriptor.max = 10;
// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor);
// printf("Table result: %d\n", table_bad_result);
// assert(table_result == WASMER_ERROR);
wasmer_table_t *table_bad = NULL;
wasmer_limits_t bad_descriptor;
bad_descriptor.min = 15;
wasmer_limit_option_t max2;
max2.has_some = true;
max2.some = 10;
bad_descriptor.max = max2;
wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor);
printf("Table result: %d\n", table_bad_result);
assert(table_bad_result == WASMER_ERROR);
printf("Destroy table\n");
wasmer_table_destroy(table);

View File

@ -35,7 +35,7 @@ typedef struct wasmer_module_t wasmer_module_t;
typedef struct {
} wasmer_export_t;
} wasmer_export_descriptor_t;
typedef struct {
const uint8_t *bytes;
@ -44,11 +44,11 @@ typedef struct {
typedef struct {
} wasmer_func_t;
} wasmer_export_descriptors_t;
typedef struct {
} wasmer_exports_t;
} wasmer_export_func_t;
typedef union {
int32_t I32;
@ -64,6 +64,14 @@ typedef struct {
typedef struct {
} wasmer_export_t;
typedef struct {
} wasmer_exports_t;
typedef struct {
} wasmer_global_t;
typedef struct {
@ -73,6 +81,18 @@ typedef struct {
typedef struct {
} wasmer_import_descriptor_t;
typedef struct {
} wasmer_import_descriptors_t;
typedef struct {
} wasmer_import_func_t;
typedef struct {
} wasmer_memory_t;
typedef struct {
@ -80,7 +100,7 @@ typedef struct {
} wasmer_table_t;
typedef union {
const wasmer_func_t *func;
const wasmer_import_func_t *func;
const wasmer_table_t *table;
const wasmer_memory_t *memory;
const wasmer_global_t *global;
@ -113,6 +133,88 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
uint8_t *wasm_bytes,
uint32_t wasm_bytes_len);
/**
* Gets export descriptor kind
*/
wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);
/**
* Gets name for the export descriptor
*/
wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor);
/**
* Gets export descriptors for the given module
* The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it.
*/
void wasmer_export_descriptors(wasmer_module_t *module,
wasmer_export_descriptors_t **export_descriptors);
/**
* Frees the memory for the given export descriptors
*/
void wasmer_export_descriptors_destroy(wasmer_export_descriptors_t *export_descriptors);
/**
* Gets export descriptor by index
*/
wasmer_export_descriptor_t *wasmer_export_descriptors_get(wasmer_export_descriptors_t *export_descriptors,
int idx);
/**
* Gets the length of the export descriptors
*/
int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports);
/**
* Calls a `func` with the provided parameters.
* Results are set using the provided `results` pointer.
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_export_func_call(wasmer_export_func_t *func,
const wasmer_value_t *params,
int params_len,
wasmer_value_t *results,
int results_len);
/**
* Sets the params buffer to the parameter types of the given wasmer_export_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_export_func_params(wasmer_export_func_t *func,
wasmer_value_tag *params,
int params_len);
/**
* Sets the result parameter to the arity of the params of the wasmer_export_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_export_func_params_arity(wasmer_export_func_t *func, uint32_t *result);
/**
* Sets the returns buffer to the parameter types of the given wasmer_export_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_export_func_returns(wasmer_export_func_t *func,
wasmer_value_tag *returns,
int returns_len);
/**
* Sets the result parameter to the arity of the returns of the wasmer_export_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_export_func_returns_arity(wasmer_export_func_t *func, uint32_t *result);
/**
* Gets wasmer_export kind
*/
@ -124,9 +226,9 @@ wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
wasmer_byte_array wasmer_export_name(wasmer_export_t *export_);
/**
* Gets func from wasm_export
* Gets export func from export
*/
const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_);
const wasmer_export_func_t *wasmer_export_to_func(wasmer_export_t *export_);
/**
* Frees the memory for the given exports
@ -143,68 +245,6 @@ wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx);
*/
int wasmer_exports_len(wasmer_exports_t *exports);
/**
* Calls a `func` with the provided parameters.
* Results are set using the provided `results` pointer.
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_func_call(wasmer_func_t *func,
const wasmer_value_t *params,
int params_len,
wasmer_value_t *results,
int results_len);
/**
* Frees memory for the given Func
*/
void wasmer_func_destroy(wasmer_func_t *func);
/**
* Creates new func
* The caller owns the object and should call `wasmer_func_destroy` to free it.
*/
const wasmer_func_t *wasmer_func_new(void (*func)(void *data),
const wasmer_value_tag *params,
int params_len,
const wasmer_value_tag *returns,
int returns_len);
/**
* Sets the params buffer to the parameter types of the given wasmer_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len);
/**
* Sets the result parameter to the arity of the params of the wasmer_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result);
/**
* Sets the returns buffer to the parameter types of the given wasmer_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_func_returns(wasmer_func_t *func,
wasmer_value_tag *returns,
int returns_len);
/**
* Sets the result parameter to the arity of the returns of the wasmer_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result);
/**
* Frees memory for the given Global
*/
@ -231,6 +271,95 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_);
*/
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
/**
* Gets export descriptor kind
*/
wasmer_import_export_kind wasmer_import_descriptor_kind(wasmer_import_descriptor_t *export_);
/**
* Gets module name for the import descriptor
*/
wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_t *import_descriptor);
/**
* Gets name for the import descriptor
*/
wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor);
/**
* Gets import descriptors for the given module
* The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
*/
void wasmer_import_descriptors(wasmer_module_t *module,
wasmer_import_descriptors_t **import_descriptors);
/**
* Frees the memory for the given import descriptors
*/
void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descriptors);
/**
* Gets import descriptor by index
*/
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
int idx);
/**
* Gets the length of the import descriptors
*/
int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
/**
* Frees memory for the given Func
*/
void wasmer_import_func_destroy(wasmer_import_func_t *func);
/**
* Creates new func
* The caller owns the object and should call `wasmer_import_func_destroy` to free it.
*/
const wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
const wasmer_value_tag *params,
int params_len,
const wasmer_value_tag *returns,
int returns_len);
/**
* Sets the params buffer to the parameter types of the given wasmer_import_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_import_func_params(wasmer_import_func_t *func,
wasmer_value_tag *params,
int params_len);
/**
* Sets the result parameter to the arity of the params of the wasmer_import_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_import_func_params_arity(wasmer_import_func_t *func, uint32_t *result);
/**
* Sets the returns buffer to the parameter types of the given wasmer_import_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_import_func_returns(wasmer_import_func_t *func,
wasmer_value_tag *returns,
int returns_len);
/**
* Sets the result parameter to the arity of the returns of the wasmer_import_func_t
* Returns `wasmer_result_t::WASMER_OK` upon success.
* Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
* and `wasmer_last_error_message` to get an error message.
*/
wasmer_result_t wasmer_import_func_returns_arity(wasmer_import_func_t *func, uint32_t *result);
/**
* Calls an instances exported function by `name` with the provided parameters.
* Results are set using the provided `results` pointer.

View File

@ -30,7 +30,7 @@ struct wasmer_instance_t;
struct wasmer_module_t;
struct wasmer_export_t {
struct wasmer_export_descriptor_t {
};
@ -39,11 +39,11 @@ struct wasmer_byte_array {
uint32_t bytes_len;
};
struct wasmer_func_t {
struct wasmer_export_descriptors_t {
};
struct wasmer_exports_t {
struct wasmer_export_func_t {
};
@ -59,6 +59,14 @@ struct wasmer_value_t {
wasmer_value value;
};
struct wasmer_export_t {
};
struct wasmer_exports_t {
};
struct wasmer_global_t {
};
@ -68,6 +76,18 @@ struct wasmer_global_descriptor_t {
wasmer_value_tag kind;
};
struct wasmer_import_descriptor_t {
};
struct wasmer_import_descriptors_t {
};
struct wasmer_import_func_t {
};
struct wasmer_memory_t {
};
@ -77,7 +97,7 @@ struct wasmer_table_t {
};
union wasmer_import_export_value {
const wasmer_func_t *func;
const wasmer_import_func_t *func;
const wasmer_table_t *table;
const wasmer_memory_t *memory;
const wasmer_global_t *global;
@ -110,14 +130,74 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
uint8_t *wasm_bytes,
uint32_t wasm_bytes_len);
/// Gets export descriptor kind
wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);
/// Gets name for the export descriptor
wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor);
/// Gets export descriptors for the given module
/// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it.
void wasmer_export_descriptors(wasmer_module_t *module,
wasmer_export_descriptors_t **export_descriptors);
/// Frees the memory for the given export descriptors
void wasmer_export_descriptors_destroy(wasmer_export_descriptors_t *export_descriptors);
/// Gets export descriptor by index
wasmer_export_descriptor_t *wasmer_export_descriptors_get(wasmer_export_descriptors_t *export_descriptors,
int idx);
/// Gets the length of the export descriptors
int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports);
/// Calls a `func` with the provided parameters.
/// Results are set using the provided `results` pointer.
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_export_func_call(wasmer_export_func_t *func,
const wasmer_value_t *params,
int params_len,
wasmer_value_t *results,
int results_len);
/// Sets the params buffer to the parameter types of the given wasmer_export_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_export_func_params(wasmer_export_func_t *func,
wasmer_value_tag *params,
int params_len);
/// Sets the result parameter to the arity of the params of the wasmer_export_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_export_func_params_arity(wasmer_export_func_t *func, uint32_t *result);
/// Sets the returns buffer to the parameter types of the given wasmer_export_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_export_func_returns(wasmer_export_func_t *func,
wasmer_value_tag *returns,
int returns_len);
/// Sets the result parameter to the arity of the returns of the wasmer_export_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_export_func_returns_arity(wasmer_export_func_t *func, uint32_t *result);
/// Gets wasmer_export kind
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
/// Gets name from wasmer_export
wasmer_byte_array wasmer_export_name(wasmer_export_t *export_);
/// Gets func from wasm_export
const wasmer_func_t *wasmer_export_to_func(wasmer_export_t *export_);
/// Gets export func from export
const wasmer_export_func_t *wasmer_export_to_func(wasmer_export_t *export_);
/// Frees the memory for the given exports
void wasmer_exports_destroy(wasmer_exports_t *exports);
@ -128,54 +208,6 @@ wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx);
/// Gets the length of the exports
int wasmer_exports_len(wasmer_exports_t *exports);
/// Calls a `func` with the provided parameters.
/// Results are set using the provided `results` pointer.
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_func_call(wasmer_func_t *func,
const wasmer_value_t *params,
int params_len,
wasmer_value_t *results,
int results_len);
/// Frees memory for the given Func
void wasmer_func_destroy(wasmer_func_t *func);
/// Creates new func
/// The caller owns the object and should call `wasmer_func_destroy` to free it.
const wasmer_func_t *wasmer_func_new(void (*func)(void *data),
const wasmer_value_tag *params,
int params_len,
const wasmer_value_tag *returns,
int returns_len);
/// Sets the params buffer to the parameter types of the given wasmer_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_func_params(wasmer_func_t *func, wasmer_value_tag *params, int params_len);
/// Sets the result parameter to the arity of the params of the wasmer_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_func_params_arity(wasmer_func_t *func, uint32_t *result);
/// Sets the returns buffer to the parameter types of the given wasmer_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_func_returns(wasmer_func_t *func,
wasmer_value_tag *returns,
int returns_len);
/// Sets the result parameter to the arity of the returns of the wasmer_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_func_returns_arity(wasmer_func_t *func, uint32_t *result);
/// Frees memory for the given Global
void wasmer_global_destroy(wasmer_global_t *global);
@ -192,6 +224,69 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_);
/// Sets the value stored by the given Global
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value);
/// Gets export descriptor kind
wasmer_import_export_kind wasmer_import_descriptor_kind(wasmer_import_descriptor_t *export_);
/// Gets module name for the import descriptor
wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_t *import_descriptor);
/// Gets name for the import descriptor
wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor);
/// Gets import descriptors for the given module
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
void wasmer_import_descriptors(wasmer_module_t *module,
wasmer_import_descriptors_t **import_descriptors);
/// Frees the memory for the given import descriptors
void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descriptors);
/// Gets import descriptor by index
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
int idx);
/// Gets the length of the import descriptors
int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
/// Frees memory for the given Func
void wasmer_import_func_destroy(wasmer_import_func_t *func);
/// Creates new func
/// The caller owns the object and should call `wasmer_import_func_destroy` to free it.
const wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
const wasmer_value_tag *params,
int params_len,
const wasmer_value_tag *returns,
int returns_len);
/// Sets the params buffer to the parameter types of the given wasmer_import_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_import_func_params(wasmer_import_func_t *func,
wasmer_value_tag *params,
int params_len);
/// Sets the result parameter to the arity of the params of the wasmer_import_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_import_func_params_arity(wasmer_import_func_t *func, uint32_t *result);
/// Sets the returns buffer to the parameter types of the given wasmer_import_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_import_func_returns(wasmer_import_func_t *func,
wasmer_value_tag *returns,
int returns_len);
/// Sets the result parameter to the arity of the returns of the wasmer_import_func_t
/// Returns `wasmer_result_t::WASMER_OK` upon success.
/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_import_func_returns_arity(wasmer_import_func_t *func, uint32_t *result);
/// Calls an instances exported function by `name` with the provided parameters.
/// Results are set using the provided `results` pointer.
/// Returns `wasmer_result_t::WASMER_OK` upon success.

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-core"
version = "0.1.2"
version = "0.2.1"
description = "Wasmer runtime core library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -15,7 +15,7 @@ parking_lot = "0.7.1"
lazy_static = "1.2.0"
indexmap = "1.0.2"
errno = "0.2.4"
libc = "0.2.48"
libc = "0.2.49"
hex = "0.3.2"
# Dependencies for caching.
@ -29,7 +29,9 @@ version = "1.0"
version = "0.10"
[dependencies.serde-bench]
version = "0.0.7"
[dependencies.sha2]
[dependencies.blake2b_simd]
version = "0.4.1"
[dependencies.digest]
version = "0.8.0"
[dependencies.hashbrown]
version = "0.1"
@ -39,7 +41,6 @@ features = ["serde"]
winapi = { version = "0.3", features = ["memoryapi"] }
[dev-dependencies]
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" }
field-offset = "0.1.1"
[features]

View File

@ -12,7 +12,7 @@ use crate::{
module::ModuleInfo,
sys::Memory,
};
use std::ptr::NonNull;
use std::{any::Any, ptr::NonNull};
pub mod sys {
pub use crate::sys::*;
@ -79,7 +79,7 @@ pub trait ProtectedCaller: Send + Sync {
}
pub trait UserTrapper {
unsafe fn do_early_trap(&self, msg: String) -> !;
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
}
pub trait FuncResolver: Send + Sync {

View File

@ -2,8 +2,8 @@ use crate::{
module::{Module, ModuleInfo},
sys::Memory,
};
use sha2::{Digest, Sha256};
use std::{io, mem, slice};
use blake2b_simd::blake2bp;
use std::{fmt, io, mem, slice};
#[derive(Debug)]
pub enum InvalidFileType {
@ -33,7 +33,7 @@ impl From<io::Error> for Error {
///
/// [`Cache`]: trait.Cache.html
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct WasmHash([u8; 32]);
pub struct WasmHash([u8; 32], [u8; 32]);
impl WasmHash {
/// Hash a wasm module.
@ -42,19 +42,31 @@ impl WasmHash {
/// This does no verification that the supplied data
/// is, in fact, a wasm module.
pub fn generate(wasm: &[u8]) -> Self {
let mut array = [0u8; 32];
array.copy_from_slice(Sha256::digest(wasm).as_slice());
WasmHash(array)
let mut first_part = [0u8; 32];
let mut second_part = [0u8; 32];
let mut state = blake2bp::State::new();
state.update(wasm);
let hasher = state.finalize();
let generic_array = hasher.as_bytes();
first_part.copy_from_slice(&generic_array[0..32]);
second_part.copy_from_slice(&generic_array[32..64]);
WasmHash(first_part, second_part)
}
/// Create the hexadecimal representation of the
/// stored hash.
pub fn encode(self) -> String {
hex::encode(self.0)
hex::encode(&self.into_array() as &[u8])
}
pub(crate) fn into_array(self) -> [u8; 32] {
self.0
pub(crate) fn into_array(self) -> [u8; 64] {
let mut total = [0u8; 64];
total[0..32].copy_from_slice(&self.0);
total[32..64].copy_from_slice(&self.1);
total
}
}
@ -189,8 +201,8 @@ impl Artifact {
///
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
pub trait Cache {
type LoadError;
type StoreError;
type LoadError: fmt::Debug;
type StoreError: fmt::Debug;
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;

View File

@ -1,8 +1,9 @@
use crate::types::{
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
Value,
};
use core::borrow::Borrow;
use std::sync::Arc;
use std::{any::Any, sync::Arc};
pub type Result<T> = std::result::Result<T, Error>;
pub type CompileResult<T> = std::result::Result<T, CompileError>;
@ -120,28 +121,11 @@ impl std::error::Error for LinkError {}
/// The main way to do this is `Instance.call`.
///
/// Comparing two `RuntimeError`s always evaluates to false.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum RuntimeError {
OutOfBoundsAccess {
memory: MemoryIndex,
addr: Option<u32>,
},
TableOutOfBounds {
table: TableIndex,
},
IndirectCallSignature {
table: TableIndex,
},
IndirectCallToNull {
table: TableIndex,
},
IllegalArithmeticOperation,
User {
msg: String,
},
Unknown {
msg: String,
},
Trap { msg: Box<str> },
Exception { data: Box<[Value]> },
Panic { data: Box<dyn Any> },
}
impl PartialEq for RuntimeError {
@ -153,30 +137,13 @@ impl PartialEq for RuntimeError {
impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RuntimeError::IndirectCallSignature { table } => write!(
f,
"Indirect call signature error with Table Index \"{:?}\"",
table
),
RuntimeError::IndirectCallToNull { table } => {
write!(f, "Indirect call to null with table index \"{:?}\"", table)
RuntimeError::Trap { ref msg } => {
write!(f, "WebAssembly trap occured during runtime: {}", msg)
}
RuntimeError::IllegalArithmeticOperation => write!(f, "Illegal arithmetic operation"),
RuntimeError::OutOfBoundsAccess { memory, addr } => match addr {
Some(addr) => write!(
f,
"Out-of-bounds access with memory index {:?} and address {}",
memory, addr
),
None => write!(f, "Out-of-bounds access with memory index {:?}", memory),
},
RuntimeError::TableOutOfBounds { table } => {
write!(f, "Table out of bounds with table index \"{:?}\"", table)
RuntimeError::Exception { ref data } => {
write!(f, "Uncaught WebAssembly exception: {:?}", data)
}
RuntimeError::Unknown { msg } => {
write!(f, "Unknown runtime error with message: \"{}\"", msg)
}
RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg),
RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""),
}
}
}
@ -232,7 +199,7 @@ impl std::error::Error for ResolveError {}
/// be the `CallError::Runtime(RuntimeError)` variant.
///
/// Comparing two `CallError`s always evaluates to false.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum CallError {
Resolve(ResolveError),
Runtime(RuntimeError),
@ -291,7 +258,7 @@ impl std::error::Error for CreationError {}
/// of a webassembly module.
///
/// Comparing two `Error`s always evaluates to false.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum Error {
CompileError(CompileError),
LinkError(Vec<LinkError>),
@ -357,8 +324,127 @@ impl From<ResolveError> for CallError {
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self)
match self {
Error::CompileError(err) => write!(f, "compile error: {}", err),
Error::LinkError(errs) => {
if errs.len() == 1 {
write!(f, "link error: {}", errs[0])
} else {
write!(f, "{} link errors:", errs.len())?;
for (i, err) in errs.iter().enumerate() {
write!(f, " ({} of {}) {}", i + 1, errs.len(), err)?;
}
Ok(())
}
}
Error::RuntimeError(err) => write!(f, "runtime error: {}", err),
Error::ResolveError(err) => write!(f, "resolve error: {}", err),
Error::CallError(err) => write!(f, "call error: {}", err),
Error::CreationError(err) => write!(f, "creation error: {}", err),
}
}
}
impl std::error::Error for Error {}
#[derive(Debug)]
pub enum GrowError {
MemoryGrowError,
TableGrowError,
ExceededMaxPages(PageError),
ExceededMaxPagesForMemory(usize, usize),
CouldNotProtectMemory(MemoryProtectionError),
CouldNotCreateMemory(MemoryCreationError),
}
impl std::fmt::Display for GrowError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
GrowError::MemoryGrowError => write!(f, "Unable to grow memory"),
GrowError::TableGrowError => write!(f, "Unable to grow table"),
GrowError::ExceededMaxPages(e) => write!(f, "Grow Error: {}", e),
GrowError::ExceededMaxPagesForMemory(left, added) => write!(f, "Failed to add pages because would exceed maximum number of pages for the memory. Left: {}, Added: {}", left, added),
GrowError::CouldNotCreateMemory(e) => write!(f, "Grow Error: {}", e),
GrowError::CouldNotProtectMemory(e) => write!(f, "Grow Error: {}", e),
}
}
}
impl std::error::Error for GrowError {}
#[derive(Debug)]
pub enum PageError {
// left, right, added
ExceededMaxPages(usize, usize, usize),
}
impl std::fmt::Display for PageError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
PageError::ExceededMaxPages(left, right, added) => write!(f, "Failed to add pages because would exceed maximum number of pages. Left: {}, Right: {}, Pages added: {}", left, right, added),
}
}
}
impl std::error::Error for PageError {}
impl Into<GrowError> for PageError {
fn into(self) -> GrowError {
GrowError::ExceededMaxPages(self)
}
}
#[derive(Debug)]
pub enum MemoryCreationError {
VirtualMemoryAllocationFailed(usize, String),
CouldNotCreateMemoryFromFile(std::io::Error),
}
impl std::fmt::Display for MemoryCreationError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MemoryCreationError::VirtualMemoryAllocationFailed(size, msg) => write!(
f,
"Allocation virtual memory with size {} failed. \nErrno message: {}",
size, msg
),
MemoryCreationError::CouldNotCreateMemoryFromFile(e) => write!(f, "IO Error: {}", e),
}
}
}
impl std::error::Error for MemoryCreationError {}
impl Into<GrowError> for MemoryCreationError {
fn into(self) -> GrowError {
GrowError::CouldNotCreateMemory(self)
}
}
impl From<std::io::Error> for MemoryCreationError {
fn from(io_error: std::io::Error) -> Self {
MemoryCreationError::CouldNotCreateMemoryFromFile(io_error)
}
}
#[derive(Debug)]
pub enum MemoryProtectionError {
ProtectionFailed(usize, usize, String),
}
impl std::fmt::Display for MemoryProtectionError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MemoryProtectionError::ProtectionFailed(start, size, msg) => write!(
f,
"Allocation virtual memory starting at {} with size {} failed. \nErrno message: {}",
start, size, msg
),
}
}
}
impl std::error::Error for MemoryProtectionError {}
impl Into<GrowError> for MemoryProtectionError {
fn into(self) -> GrowError {
GrowError::CouldNotProtectMemory(self)
}
}

View File

@ -1,3 +1,4 @@
use crate::error::GrowError;
use crate::{
error::CreationError,
sys,
@ -14,9 +15,9 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096;
/// when first created. Over time, as it grows, it may reallocate to
/// a different location and size.
///
/// Dynamic memories are signifigantly faster to create than static
/// Dynamic memories are significantly faster to create than static
/// memories and use much less virtual memory, however, they require
/// the webassembly module to bounds-check memory accesses.
/// the WebAssembly module to bounds-check memory accesses.
///
/// While, a dynamic memory could use a vector of some sort as its
/// backing memory, we use mmap (or the platform-equivalent) to allow
@ -65,26 +66,29 @@ impl DynamicMemory {
self.current
}
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option<Pages> {
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
if delta == Pages(0) {
return Some(self.current);
return Ok(self.current);
}
let new_pages = self.current.checked_add(delta)?;
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
if let Some(max) = self.max {
if new_pages > max {
return None;
return Err(GrowError::ExceededMaxPagesForMemory(
new_pages.0 as usize,
max.0 as usize,
));
}
}
let mut new_memory =
sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?;
let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
.map_err(|e| e.into())?;
unsafe {
new_memory
.protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
.ok()?;
.map_err(|e| e.into())?;
new_memory.as_slice_mut()[..self.current.bytes().0]
.copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]);
@ -97,7 +101,7 @@ impl DynamicMemory {
let old_pages = self.current;
self.current = new_pages;
Some(old_pages)
Ok(old_pages)
}
pub fn as_slice(&self) -> &[u8] {

View File

@ -1,5 +1,5 @@
use crate::{
error::CreationError,
error::{CreationError, GrowError},
export::Export,
import::IsExport,
memory::dynamic::DYNAMIC_GUARD_SIZE,
@ -89,8 +89,8 @@ impl Memory {
self.desc
}
/// Grow this memory by the specfied number of pages.
pub fn grow(&self, delta: Pages) -> Option<Pages> {
/// Grow this memory by the specified number of pages.
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
match &self.variant {
MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta),
MemoryVariant::Shared(shared_mem) => shared_mem.grow(delta),
@ -244,7 +244,7 @@ impl UnsharedMemory {
})
}
pub fn grow(&self, delta: Pages) -> Option<Pages> {
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
let mut storage = self.internal.storage.borrow_mut();
let mut local = self.internal.local.get();
@ -292,7 +292,7 @@ impl SharedMemory {
Ok(Self { desc })
}
pub fn grow(&self, _delta: Pages) -> Option<Pages> {
pub fn grow(&self, _delta: Pages) -> Result<Pages, GrowError> {
unimplemented!()
}

View File

@ -1,3 +1,4 @@
use crate::error::GrowError;
use crate::{
error::CreationError,
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
@ -61,27 +62,30 @@ impl StaticMemory {
self.current
}
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option<Pages> {
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
if delta == Pages(0) {
return Some(self.current);
return Ok(self.current);
}
let new_pages = self.current.checked_add(delta)?;
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
if let Some(max) = self.max {
if new_pages > max {
return None;
return Err(GrowError::ExceededMaxPagesForMemory(
new_pages.0 as usize,
max.0 as usize,
));
}
}
unsafe {
let _ = unsafe {
self.memory
.protect(
self.current.bytes().0..new_pages.bytes().0,
sys::Protect::ReadWrite,
)
.ok()?;
}
.map_err(|e| e.into())
}?;
local.bound = new_pages.bytes().0;
@ -89,7 +93,7 @@ impl StaticMemory {
self.current = new_pages;
Some(old_pages)
Ok(old_pages)
}
pub fn as_slice(&self) -> &[u8] {

View File

@ -1,6 +1,6 @@
use crate::{
backend::{Backend, FuncResolver, ProtectedCaller},
cache::{Artifact, Error as CacheError, WasmHash},
cache::{Artifact, Error as CacheError},
error,
import::ImportObject,
structures::{Map, TypedIndex},

View File

@ -56,6 +56,10 @@ where
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
BoxedMap::new(self.elems.into_boxed_slice())
}
pub fn into_vec(self) -> Vec<V> {
self.elems
}
}
impl<K, V> Map<K, V>

View File

@ -1,3 +1,5 @@
use crate::error::MemoryCreationError;
use crate::error::MemoryProtectionError;
use errno;
use nix::libc;
use page_size;
@ -16,13 +18,13 @@ pub struct Memory {
}
impl Memory {
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, String>
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, MemoryCreationError>
where
P: AsRef<Path>,
{
let file = File::open(path).map_err(|e| e.to_string())?;
let file = File::open(path)?;
let file_len = file.metadata().map_err(|e| e.to_string())?.len();
let file_len = file.metadata()?.len();
let raw_fd = RawFd::from_file(file);
@ -38,7 +40,10 @@ impl Memory {
};
if ptr == -1 as _ {
Err(errno::errno().to_string())
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
file_len as usize,
errno::errno().to_string(),
))
} else {
Ok(Self {
ptr: ptr as *mut u8,
@ -84,7 +89,7 @@ impl Memory {
}
}
pub fn with_size(size: usize) -> Result<Self, String> {
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
if size == 0 {
return Ok(Self {
ptr: ptr::null_mut(),
@ -108,7 +113,10 @@ impl Memory {
};
if ptr == -1 as _ {
Err(errno::errno().to_string())
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
size,
errno::errno().to_string(),
))
} else {
Ok(Self {
ptr: ptr as *mut u8,
@ -123,7 +131,7 @@ impl Memory {
&mut self,
range: impl RangeBounds<usize>,
protection: Protect,
) -> Result<(), String> {
) -> Result<(), MemoryProtectionError> {
let protect = protection.to_protect_const();
let range_start = match range.start_bound() {
@ -147,7 +155,11 @@ impl Memory {
let success = libc::mprotect(start as _, size, protect as i32);
if success == -1 {
Err(errno::errno().to_string())
Err(MemoryProtectionError::ProtectionFailed(
start as usize,
size,
errno::errno().to_string(),
))
} else {
self.protection = protection;
Ok(())

View File

@ -1,3 +1,5 @@
use crate::error::MemoryCreationError;
use crate::error::MemoryProtectionError;
use page_size;
use std::ops::{Bound, RangeBounds};
use std::{ptr, slice};
@ -44,7 +46,7 @@ impl Memory {
}
}
pub fn with_size(size: usize) -> Result<Self, String> {
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
if size == 0 {
return Ok(Self {
ptr: ptr::null_mut(),
@ -58,7 +60,10 @@ impl Memory {
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, PAGE_NOACCESS) };
if ptr.is_null() {
Err("unable to allocate memory".to_string())
Err(MemoryCreationError::VirtualMemoryAllocationFailed(
size,
"unable to allocate memory".to_string(),
))
} else {
Ok(Self {
ptr: ptr as *mut u8,
@ -72,7 +77,7 @@ impl Memory {
&mut self,
range: impl RangeBounds<usize>,
protect: Protect,
) -> Result<(), String> {
) -> Result<(), MemoryProtectionError> {
let protect_const = protect.to_protect_const();
let range_start = match range.start_bound() {
@ -98,7 +103,11 @@ impl Memory {
let ptr = VirtualAlloc(start as _, size, MEM_COMMIT, protect_const);
if ptr.is_null() {
Err("unable to protect memory".to_string())
Err(MemoryProtectionError::ProtectionFailed(
start as usize,
size,
"unable to protect memory".to_string(),
))
} else {
self.protection = protect;
Ok(())

View File

@ -11,6 +11,7 @@ mod anyfunc;
pub use self::anyfunc::Anyfunc;
use self::anyfunc::AnyfuncTable;
use crate::error::GrowError;
pub enum Element<'a> {
Anyfunc(Anyfunc<'a>),
@ -108,15 +109,15 @@ impl Table {
}
/// Grow this table by `delta`.
pub fn grow(&self, delta: u32) -> Option<u32> {
pub fn grow(&self, delta: u32) -> Result<u32, GrowError> {
if delta == 0 {
return Some(self.size());
return Ok(self.size());
}
match &mut *self.storage.borrow_mut() {
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => {
anyfunc_table.grow(delta, local)
}
(TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => anyfunc_table
.grow(delta, local)
.ok_or(GrowError::TableGrowError),
}
}

View File

@ -6,7 +6,7 @@ use crate::{
types::{FuncSig, Type, WasmExternType},
vm::Ctx,
};
use std::{cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
use std::{any::Any, cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
thread_local! {
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
@ -40,14 +40,14 @@ pub trait TrapEarly<Rets>
where
Rets: WasmTypeList,
{
fn report(self) -> Result<Rets, String>;
fn report(self) -> Result<Rets, Box<dyn Any>>;
}
impl<Rets> TrapEarly<Rets> for Rets
where
Rets: WasmTypeList,
{
fn report(self) -> Result<Rets, String> {
fn report(self) -> Result<Rets, Box<dyn Any>> {
Ok(self)
}
}
@ -55,10 +55,10 @@ where
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
where
Rets: WasmTypeList,
E: fmt::Debug,
E: Any,
{
fn report(self) -> Result<Rets, String> {
self.map_err(|err| format!("Error: {:?}", err))
fn report(self) -> Result<Rets, Box<dyn Any>> {
self.map_err(|err| Box::new(err) as Box<dyn Any>)
}
}
@ -191,25 +191,17 @@ macro_rules! impl_traits {
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct {
let f: FN = unsafe { mem::transmute_copy(&()) };
let msg = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
f( ctx $( ,$x )* ).report()
})) {
Ok(Ok(returns)) => return returns.into_c_struct(),
Ok(Err(err)) => err,
Err(err) => {
if let Some(s) = err.downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = err.downcast_ref::<String>() {
s.clone()
} else {
"a panic occurred, but no additional information is available".to_string()
}
},
Err(err) => err,
};
unsafe {
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
early_trapper.do_early_trap(msg)
early_trapper.do_early_trap(err)
} else {
eprintln!("panic handling not setup");
std::process::exit(1)

View File

@ -1,3 +1,4 @@
use crate::error::PageError;
use std::{
fmt,
ops::{Add, Sub},
@ -11,12 +12,16 @@ const WASM_MAX_PAGES: usize = 65_536;
pub struct Pages(pub u32);
impl Pages {
pub fn checked_add(self, rhs: Pages) -> Option<Pages> {
pub fn checked_add(self, rhs: Pages) -> Result<Pages, PageError> {
let added = (self.0 as usize) + (rhs.0 as usize);
if added <= WASM_MAX_PAGES {
Some(Pages(added as u32))
Ok(Pages(added as u32))
} else {
None
Err(PageError::ExceededMaxPages(
self.0 as usize,
rhs.0 as usize,
added,
))
}
}

View File

@ -20,10 +20,9 @@ pub unsafe extern "C" fn local_static_memory_grow(
let local_memory = *ctx.memories.add(memory_index.index());
let memory = (*local_memory).memory as *mut StaticMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
old.0 as i32
} else {
-1
match (*memory).grow(delta, &mut *local_memory) {
Ok(old) => old.0 as i32,
Err(_) => -1,
}
}
@ -45,10 +44,9 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
let local_memory = *ctx.memories.add(memory_index.index());
let memory = (*local_memory).memory as *mut DynamicMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
old.0 as i32
} else {
-1
match (*memory).grow(delta, &mut *local_memory) {
Ok(old) => old.0 as i32,
Err(_) => -1,
}
}
@ -74,10 +72,9 @@ pub unsafe extern "C" fn imported_static_memory_grow(
let local_memory = *ctx.imported_memories.add(import_memory_index.index());
let memory = (*local_memory).memory as *mut StaticMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
old.0 as i32
} else {
-1
match (*memory).grow(delta, &mut *local_memory) {
Ok(old) => old.0 as i32,
Err(_) => -1,
}
}
@ -99,10 +96,9 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
let local_memory = *ctx.imported_memories.add(memory_index.index());
let memory = (*local_memory).memory as *mut DynamicMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) {
old.0 as i32
} else {
-1
match (*memory).grow(delta, &mut *local_memory) {
Ok(old) => old.0 as i32,
Err(_) => -1,
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime"
version = "0.1.4"
version = "0.2.1"
description = "Wasmer runtime library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -14,11 +14,16 @@ memmap = "0.7.0"
[dependencies.wasmer-runtime-core]
path = "../runtime-core"
version = "0.1.2"
version = "0.2.1"
[dependencies.wasmer-clif-backend]
path = "../clif-backend"
version = "0.1.2"
version = "0.2.0"
[dev-dependencies]
tempfile = "3.0.7"
criterion = "0.2"
wabt = "0.7.4"
[dependencies.wasmer-llvm-backend]
path = "../llvm-backend"
@ -26,5 +31,6 @@ path = "../llvm-backend"
[features]
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
[dev-dependencies]
wabt = "0.7.4"
[[bench]]
name = "nginx"
harness = false

View File

@ -51,7 +51,7 @@ fn main() -> error::Result<()> {
// We're not importing anything, so make an empty import object.
let import_object = imports! {};
let mut instance = instantiate(WASM, import_object)?;
let mut instance = instantiate(WASM, &import_object)?;
let values = instance
.func("add_one")?

View File

@ -0,0 +1,53 @@
#[macro_use]
extern crate criterion;
use criterion::Criterion;
use tempfile::tempdir;
use wasmer_runtime::{
cache::{Cache, FileSystemCache, WasmHash},
compile, validate,
};
static NGINX_WASM: &'static [u8] = include_bytes!("../../../examples/nginx/nginx.wasm");
fn compile_module() {
compile(NGINX_WASM).unwrap();
}
fn load_module(hash: WasmHash, cache: &impl Cache) {
cache.load(hash).expect("could not load module");
}
fn hashing_benchmark(c: &mut Criterion) {
c.bench_function("nginx HASH", |b| b.iter(|| WasmHash::generate(NGINX_WASM)));
}
fn validate_benchmark(c: &mut Criterion) {
c.bench_function("nginx validate", |b| b.iter(|| validate(NGINX_WASM)));
}
fn compile_benchmark(c: &mut Criterion) {
c.bench_function("nginx compile", |b| b.iter(|| compile_module()));
}
fn load_benchmark(c: &mut Criterion) {
c.bench_function("nginx load", |b| {
let tempdir = tempdir().unwrap();
let mut cache = unsafe {
FileSystemCache::new(tempdir.path()).expect("unable to create file system cache")
};
let module = compile(NGINX_WASM).unwrap();
let wasm_hash = WasmHash::generate(NGINX_WASM);
cache
.store(wasm_hash, module)
.expect("unable to store into cache");
b.iter(|| load_module(wasm_hash, &cache))
});
}
criterion_group! {
name = benches;
config = Criterion::default().sample_size(10);
targets = validate_benchmark, hashing_benchmark, compile_benchmark, load_benchmark
}
criterion_main!(benches);

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-spectests"
version = "0.1.2"
version = "0.2.0"
description = "Wasmer spectests library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,13 +9,13 @@ edition = "2018"
build = "build/mod.rs"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
[build-dependencies]
wabt = "0.7.2"
[dev-dependencies]
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.2" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
wabt = "0.7.2"

View File

@ -569,7 +569,7 @@ fn {}_assert_malformed() {{
let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
format!(
"let expected = {expected_result};
if let {return_type_destructure} = result.clone().unwrap().first().unwrap() {{
if let {return_type_destructure} = result.as_ref().unwrap().first().unwrap() {{
assert!((*result as {return_type}).is_nan());
assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive());
}} else {{

View File

@ -31,7 +31,7 @@ mod tests {
match result {
Err(err) => match err {
CallError::Runtime(RuntimeError::Unknown { msg }) => {
CallError::Runtime(RuntimeError::Trap { msg }) => {
assert!(!msg.contains("segmentation violation"));
assert!(!msg.contains("bus error"));
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-win-exception-handler"
version = "0.0.1"
version = "0.2.0"
description = "Wasmer runtime exception handling for Windows"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -8,9 +8,9 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[target.'cfg(windows)'.dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
libc = "0.2.48"
libc = "0.2.49"
[build-dependencies]
cmake = "0.1.35"

View File

@ -10,6 +10,7 @@ __declspec(thread) DWORD64 caughtInstructionPointer;
__declspec(thread) PVOID savedStackPointer;
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
__declspec(thread) BOOL alreadyHandlingException = FALSE;
__declspec(thread) PVOID handle;
void longjmpOutOfHere() {
longjmp(jmpBuf, 1);
@ -38,6 +39,14 @@ exceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) {
return EXCEPTION_CONTINUE_EXECUTION;
}
static void removeExceptionHandler() {
if (exceptionHandlerInstalled == FALSE) {
return;
}
RemoveVectoredExceptionHandler(handle);
exceptionHandlerInstalled = FALSE;
}
uint8_t callProtected(trampoline_t trampoline,
const struct wasmer_instance_context_t* ctx,
const struct func_t* func,
@ -48,7 +57,7 @@ uint8_t callProtected(trampoline_t trampoline,
// install exception handler
if (exceptionHandlerInstalled == FALSE) {
exceptionHandlerInstalled = TRUE;
AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
handle = AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
}
// jmp jmp jmp!
@ -60,6 +69,8 @@ uint8_t callProtected(trampoline_t trampoline,
out_result->code = 0;
out_result->exceptionAddress = 0;
out_result->instructionPointer = 0;
removeExceptionHandler();
return TRUE;
}
@ -70,5 +81,6 @@ uint8_t callProtected(trampoline_t trampoline,
caughtExceptionAddress = 0;
caughtInstructionPointer = 0;
removeExceptionHandler();
return FALSE;
}

View File

@ -1,7 +1,6 @@
extern crate structopt;
use std::env;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
@ -14,7 +13,6 @@ use wasmer::webassembly::InstanceABI;
use wasmer::*;
use wasmer_emscripten;
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash};
use wasmer_runtime::error::CacheError;
#[derive(Debug, StructOpt)]
#[structopt(name = "wasmer", about = "Wasm execution runtime.")]
@ -35,9 +33,6 @@ enum CLIOptions {
#[derive(Debug, StructOpt)]
struct Run {
#[structopt(short = "d", long = "debug")]
debug: bool,
// Disable the cache
#[structopt(long = "disable-cache")]
disable_cache: bool,
@ -84,6 +79,12 @@ fn get_cache_dir() -> PathBuf {
/// Execute a wasm/wat file
fn execute_wasm(options: &Run) -> Result<(), String> {
// force disable caching on windows
#[cfg(target_os = "windows")]
let disable_cache = true;
#[cfg(not(target_os = "windows"))]
let disable_cache = options.disable_cache;
let wasm_path = &options.path;
let mut wasm_binary: Vec<u8> = read_file_contents(wasm_path).map_err(|err| {
@ -99,7 +100,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
.map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?;
}
let module = if !options.disable_cache {
let module = if !disable_cache {
// If we have cache enabled
// We generate a hash for the given binary, so we can use it as key
@ -188,8 +189,10 @@ fn main() {
CLIOptions::SelfUpdate => {
println!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io");
}
#[cfg(not(target_os = "windows"))]
CLIOptions::Cache(cache) => match cache {
Cache::Clean => {
use std::fs;
let cache_dir = get_cache_dir();
fs::remove_dir_all(cache_dir.clone()).expect("Can't remove cache dir");
fs::create_dir(cache_dir.clone()).expect("Can't create cache dir");
@ -198,5 +201,9 @@ fn main() {
println!("{}", get_cache_dir().to_string_lossy());
}
},
#[cfg(target_os = "windows")]
CLIOptions::Cache(_) => {
println!("Caching is disabled for Windows.");
}
}
}

View File

@ -11,7 +11,7 @@ ChangesEnvironment=yes
OutputBaseFilename=WasmerInstaller
[Files]
Source: "..\target\release\wasmer.exe"; DestDir: "{app}\bin"
Source: "..\..\target\release\wasmer.exe"; DestDir: "{app}\bin"
[Code]
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';