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: cache:
- 'C:\Users\appveyor\.cargo' - 'C:\Users\appveyor\.cargo'
- target
install: install:
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe # uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
- rustup-init.exe -yv --default-host %target% # - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
# - rustup-init.exe -yv --default-host %target%
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin - set PATH=%PATH%;%USERPROFILE%\.cargo\bin
- rustup default stable-%target%
- rustup update
- rustc -vV - rustc -vV
- cargo -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: build_script:
- cargo build --verbose - cargo build --release --verbose
test_script: test_script:
- set RUST_BACKTRACE=1 - cargo test --package wasmer-spectests
- cd ./lib/spectests && cargo test -- --test-threads 1 && cd ../..
before_deploy: after_build:
- cd ./src/installer - cd ./src/installer
- iscc wasmer.iss - iscc wasmer.iss
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe - copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- appveyor PushArtifact WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe - appveyor PushArtifact ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
- cd ..\..\
artifacts:
- path: WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
name: WasmerInstaller.exe
deploy: deploy:
description: 'WasmerInstaller' description: 'WasmerInstaller'

1514
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -142,6 +142,14 @@ You can also run integration tests with:
make integration-tests make integration-tests
``` ```
## Benchmarking
Benchmarks can be run with:
```sh
cargo bench --all
```
## Roadmap ## 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. 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" 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 # 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 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" 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] [package]
name = "wasmer-clif-backend" name = "wasmer-clif-backend"
version = "0.1.2" version = "0.2.0"
description = "Wasmer runtime Cranelift compiler backend" description = "Wasmer runtime Cranelift compiler backend"
license = "MIT" license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"] authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018" edition = "2018"
[dependencies] [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-native = "0.26.0"
cranelift-codegen = "0.26.0" cranelift-codegen = "0.26.0"
cranelift-entity = "0.26.0" cranelift-entity = "0.26.0"
@ -18,7 +18,8 @@ target-lexicon = "0.2.0"
wasmparser = "0.23.0" wasmparser = "0.23.0"
byteorder = "1" byteorder = "1"
nix = "0.13.0" nix = "0.13.0"
libc = "0.2.48" libc = "0.2.49"
rayon = "1.0"
# Dependencies for caching. # Dependencies for caching.
[dependencies.serde] [dependencies.serde]
@ -32,7 +33,7 @@ version = "0.0.7"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } 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] [features]
debug = ["wasmer-runtime-core/debug"] debug = ["wasmer-runtime-core/debug"]

View File

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

View File

@ -7,6 +7,7 @@ use crate::{
}, },
signal::HandlerData, signal::HandlerData,
}; };
use rayon::prelude::*;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use cranelift_codegen::{ir, isa, Context}; use cranelift_codegen::{ir, isa, Context};
@ -92,25 +93,44 @@ impl FuncResolverBuilder {
function_bodies: Map<LocalFuncIndex, ir::Function>, function_bodies: Map<LocalFuncIndex, ir::Function>,
info: &ModuleInfo, info: &ModuleInfo,
) -> CompileResult<(Self, HandlerData)> { ) -> CompileResult<(Self, HandlerData)> {
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len()); let num_func_bodies = function_bodies.len();
let mut local_relocs = Map::with_capacity(function_bodies.len()); let mut local_relocs = Map::with_capacity(num_func_bodies);
let mut external_relocs = Map::new(); let mut external_relocs = Map::with_capacity(num_func_bodies);
let mut trap_sink = TrapSink::new(); let mut trap_sink = TrapSink::new();
let mut local_trap_sink = LocalTrapSink::new();
let mut ctx = Context::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();
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; let mut total_size = 0;
// We separate into two iterators, one iterable and one into iterable
for (_, func) in function_bodies { let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
ctx.func = func; compiled_functions.into_iter().unzip();
let mut code_buf = Vec::new(); for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
let mut reloc_sink = RelocSink::new(); {
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();
// Clear the local trap sink and consolidate all trap info // Clear the local trap sink and consolidate all trap info
// into a single location. // into a single location.
trap_sink.drain_local(total_size, &mut local_trap_sink); 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. // Round up each function's size to pointer alignment.
total_size += round_up(code_buf.len(), mem::size_of::<usize>()); 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()); local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice()); external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
} }
@ -145,10 +164,10 @@ impl FuncResolverBuilder {
*i = 0xCC; *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; 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>()); let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
unsafe { unsafe {
memory.as_slice_mut()[previous_end..previous_end + compiled.len()] 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 crate::trampoline::Trampolines;
use hashbrown::HashSet; use hashbrown::HashSet;
use libc::c_void; use libc::c_void;
use std::{cell::Cell, sync::Arc}; use std::{any::Any, cell::Cell, sync::Arc};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{ProtectedCaller, Token, UserTrapper}, backend::{ProtectedCaller, Token, UserTrapper},
error::RuntimeResult, error::RuntimeResult,
@ -25,14 +25,14 @@ pub use self::unix::*;
pub use self::windows::*; pub use self::windows::*;
thread_local! { 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; pub struct Trapper;
impl UserTrapper for Trapper { impl UserTrapper for Trapper {
unsafe fn do_early_trap(&self, msg: String) -> ! { unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg))); TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
trigger_trap() trigger_trap()
} }
} }

View File

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

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "wasmer-emscripten" name = "wasmer-emscripten"
version = "0.1.0" version = "0.2.1"
description = "Wasmer runtime emscripten implementation library" description = "Wasmer runtime emscripten implementation library"
license = "MIT" license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"] authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,9 +9,9 @@ edition = "2018"
build = "build/mod.rs" build = "build/mod.rs"
[dependencies] [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" lazy_static = "1.2.0"
libc = { git = "https://github.com/rust-lang/libc" } libc = "0.2.49"
byteorder = "1" byteorder = "1"
time = "0.1.41" time = "0.1.41"
@ -19,7 +19,7 @@ time = "0.1.41"
rand = "0.6" rand = "0.6"
[dev-dependencies] [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" wabt = "0.7.2"
[build-dependencies] [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), "___syscall168" => func!(crate::syscalls::___syscall168),
"___syscall180" => func!(crate::syscalls::___syscall180), "___syscall180" => func!(crate::syscalls::___syscall180),
"___syscall181" => func!(crate::syscalls::___syscall181), "___syscall181" => func!(crate::syscalls::___syscall181),
"___syscall183" => func!(crate::syscalls::___syscall183),
"___syscall191" => func!(crate::syscalls::___syscall191), "___syscall191" => func!(crate::syscalls::___syscall191),
"___syscall192" => func!(crate::syscalls::___syscall192), "___syscall192" => func!(crate::syscalls::___syscall192),
"___syscall194" => func!(crate::syscalls::___syscall194), "___syscall194" => func!(crate::syscalls::___syscall194),

View File

@ -46,8 +46,13 @@ use std::slice;
// Another conditional constant for name resolution: Macos et iOS use // Another conditional constant for name resolution: Macos et iOS use
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. // SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
// Other platforms do otherwise. // 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")] #[cfg(target_os = "darwin")]
use libc::SO_NOSIGPIPE; use libc::SO_NOSIGPIPE;
use std::ffi::CString;
#[cfg(not(target_os = "darwin"))] #[cfg(not(target_os = "darwin"))]
const SO_NOSIGPIPE: c_int = 0; 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); debug!("emscripten::___syscall3 (read) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let buf: u32 = 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); debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void; 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); debug!("=> ret: {}", ret);
ret as _ 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); debug!("emscripten::___syscall4 (write) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let buf: u32 = 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); debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count);
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void; 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 /// close
@ -186,6 +191,25 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1 -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 // mmap2
pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { pub fn ___syscall192(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall192 (mmap2) {}", which); debug!("emscripten::___syscall192 (mmap2) {}", which);
@ -217,10 +241,10 @@ pub fn ___syscall140(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 {
// -> c_int // -> c_int
debug!("emscripten::___syscall140 (lseek) {}", which); debug!("emscripten::___syscall140 (lseek) {}", which);
let fd: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx);
let offset = varargs.get(ctx); let offset: i32 = varargs.get(ctx);
let whence: i32 = varargs.get(ctx); let whence: i32 = varargs.get(ctx);
debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence); debug!("=> fd: {}, offset: {}, whence = {}", fd, offset, whence);
unsafe { lseek(fd, offset, whence) as _ } unsafe { lseek(fd, offset as _, whence) as _ }
} }
/// readv /// readv

View File

@ -54,6 +54,7 @@ mod test_funcptrfunc;
mod test_funcs; mod test_funcs;
mod test_functionpointer_libfunc_varargs; mod test_functionpointer_libfunc_varargs;
mod test_fwrite_0; mod test_fwrite_0;
mod test_getcwd;
mod test_getgep; mod test_getgep;
mod test_getloadavg; mod test_getloadavg;
mod test_getopt; 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] [package]
name = "wasmer-runtime-c-api" name = "wasmer-runtime-c-api"
version = "0.1.4" version = "0.2.1"
description = "Wasmer c-api library" description = "Wasmer c-api library"
license = "MIT" license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"] authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,8 +9,8 @@ edition = "2018"
readme = "README.md" readme = "README.md"
[dependencies] [dependencies]
wasmer-runtime = { path = "../runtime", version = "0.1.2" } wasmer-runtime = { path = "../runtime", version = "0.2.1" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" } wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
libc = "0.2" libc = "0.2"
[lib] [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::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value};
use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::export::{Context, Export, FuncPointer};
use wasmer_runtime_core::import::Namespace; 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::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type};
use wasmer_runtime_core::units::{Bytes, Pages}; use wasmer_runtime_core::units::{Bytes, Pages};
#[allow(non_camel_case_types)]
pub struct wasmer_import_object_t();
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub struct wasmer_module_t(); pub struct wasmer_module_t();
@ -78,7 +76,11 @@ pub struct wasmer_table_t();
#[repr(C)] #[repr(C)]
#[derive(Clone)] #[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)] #[repr(C)]
#[derive(Clone)] #[derive(Clone)]
@ -96,14 +98,6 @@ pub struct wasmer_limit_option_t {
pub some: uint32_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)] #[repr(C)]
pub struct wasmer_import_t { pub struct wasmer_import_t {
module_name: wasmer_byte_array, module_name: wasmer_byte_array,
@ -112,6 +106,14 @@ pub struct wasmer_import_t {
value: wasmer_import_export_value, 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)] #[repr(C)]
#[derive(Clone)] #[derive(Clone)]
pub struct wasmer_export_t; pub struct wasmer_export_t;
@ -120,6 +122,14 @@ pub struct wasmer_export_t;
#[derive(Clone)] #[derive(Clone)]
pub struct wasmer_exports_t; 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)] #[repr(u32)]
#[derive(Clone)] #[derive(Clone)]
pub enum wasmer_import_export_kind { pub enum wasmer_import_export_kind {
@ -132,7 +142,7 @@ pub enum wasmer_import_export_kind {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub union wasmer_import_export_value { pub union wasmer_import_export_value {
func: *const wasmer_func_t, func: *const wasmer_import_func_t,
table: *const wasmer_table_t, table: *const wasmer_table_t,
memory: *const wasmer_memory_t, memory: *const wasmer_memory_t,
global: *const wasmer_global_t, global: *const wasmer_global_t,
@ -208,14 +218,13 @@ pub extern "C" fn wasmer_memory_grow(
delta: uint32_t, delta: uint32_t,
) -> wasmer_result_t { ) -> wasmer_result_t {
let memory = unsafe { &*(memory as *mut Memory) }; let memory = unsafe { &*(memory as *mut Memory) };
let maybe_delta = memory.grow(Pages(delta)); let delta_result = memory.grow(Pages(delta));
if let Some(_delta) = maybe_delta { match delta_result {
wasmer_result_t::WASMER_OK Ok(_) => wasmer_result_t::WASMER_OK,
} else { Err(grow_error) => {
update_last_error(CApiError { update_last_error(grow_error);
msg: "unable to grow memory".to_string(), wasmer_result_t::WASMER_ERROR
}); }
wasmer_result_t::WASMER_ERROR
} }
} }
@ -277,14 +286,13 @@ pub extern "C" fn wasmer_table_grow(
delta: uint32_t, delta: uint32_t,
) -> wasmer_result_t { ) -> wasmer_result_t {
let table = unsafe { &*(table as *mut Table) }; let table = unsafe { &*(table as *mut Table) };
let maybe_delta = table.grow(delta); let delta_result = table.grow(delta);
if let Some(_delta) = maybe_delta { match delta_result {
wasmer_result_t::WASMER_OK Ok(_) => wasmer_result_t::WASMER_OK,
} else { Err(grow_error) => {
update_last_error(CApiError { update_last_error(grow_error);
msg: "unable to grow table".to_string(), wasmer_result_t::WASMER_ERROR
}); }
wasmer_result_t::WASMER_ERROR
} }
} }
@ -446,12 +454,24 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
.or_insert_with(|| Namespace::new()); .or_insert_with(|| Namespace::new());
let export = match import.tag { let export = match import.tag {
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export, wasmer_import_export_kind::WASM_MEMORY => {
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export, let mem = import.value.memory as *mut Memory;
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, Export::Memory((&*mem).clone())
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, }
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() { for (module_name, namespace) in namespaces.into_iter() {
import_object.register(module_name, namespace); import_object.register(module_name, namespace);
@ -470,6 +490,91 @@ pub unsafe extern "C" fn wasmer_module_instantiate(
wasmer_result_t::WASMER_OK 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 /// Frees memory for the given Module
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
#[no_mangle] #[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. /// Creates a new Instance from the given wasm bytes and imports.
/// ///
/// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_OK` upon success.
@ -534,12 +818,24 @@ pub unsafe extern "C" fn wasmer_instantiate(
.or_insert_with(|| Namespace::new()); .or_insert_with(|| Namespace::new());
let export = match import.tag { let export = match import.tag {
wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export, wasmer_import_export_kind::WASM_MEMORY => {
wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export, let mem = import.value.memory as *mut Memory;
wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, Export::Memory((&*mem).clone())
wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, }
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() { for (module_name, namespace) in namespaces.into_iter() {
import_object.register(module_name, namespace); import_object.register(module_name, namespace);
@ -649,9 +945,16 @@ pub unsafe extern "C" fn wasmer_instance_exports(
instance: *mut wasmer_instance_t, instance: *mut wasmer_instance_t,
exports: *mut *mut wasmer_exports_t, exports: *mut *mut wasmer_exports_t,
) { ) {
let mut instance = unsafe { &mut *(instance as *mut Instance) }; let mut instance_ref = unsafe { &mut *(instance as *mut Instance) };
let named_exports: Box<NamedExports> = let mut exports_vec: Vec<NamedExport> = Vec::with_capacity(instance_ref.exports().count());
Box::new(NamedExports(instance.exports().map(|e| e.into()).collect())); 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 }; 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] #[no_mangle]
#[allow(clippy::cast_ptr_alignment)] #[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), func: extern "C" fn(data: *mut c_void),
params: *const wasmer_value_tag, params: *const wasmer_value_tag,
params_len: c_int, params_len: c_int,
returns: *const wasmer_value_tag, returns: *const wasmer_value_tag,
returns_len: c_int, 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: &[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 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); 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, ctx: Context::Internal,
signature: Arc::new(FuncSig::new(params, returns)), 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. /// 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. /// and `wasmer_last_error_message` to get an error message.
#[no_mangle] #[no_mangle]
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_params_arity( pub unsafe extern "C" fn wasmer_import_func_params(
func: *mut wasmer_func_t, 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_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,
params: *mut wasmer_value_tag, params: *mut wasmer_value_tag,
params_len: c_int, params_len: c_int,
) -> wasmer_result_t { ) -> wasmer_result_t {
@ -779,14 +1196,14 @@ pub unsafe extern "C" fn wasmer_func_params(
wasmer_result_t::WASMER_OK wasmer_result_t::WASMER_OK
} else { } else {
update_last_error(CApiError { 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 wasmer_result_t::WASMER_ERROR
}; };
result 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. /// 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. /// and `wasmer_last_error_message` to get an error message.
#[no_mangle] #[no_mangle]
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_returns( pub unsafe extern "C" fn wasmer_import_func_returns(
func: *mut wasmer_func_t, func: *mut wasmer_import_func_t,
returns: *mut wasmer_value_tag, returns: *mut wasmer_value_tag,
returns_len: c_int, returns_len: c_int,
) -> wasmer_result_t { ) -> wasmer_result_t {
@ -809,14 +1226,14 @@ pub unsafe extern "C" fn wasmer_func_returns(
wasmer_result_t::WASMER_OK wasmer_result_t::WASMER_OK
} else { } else {
update_last_error(CApiError { 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 wasmer_result_t::WASMER_ERROR
}; };
result 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. /// 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. /// and `wasmer_last_error_message` to get an error message.
#[no_mangle] #[no_mangle]
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_func_returns_arity( pub unsafe extern "C" fn wasmer_import_func_returns_arity(
func: *mut wasmer_func_t, func: *mut wasmer_import_func_t,
result: *mut uint32_t, result: *mut uint32_t,
) -> wasmer_result_t { ) -> wasmer_result_t {
let mut export = unsafe { &*(func as *mut Export) }; 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 wasmer_result_t::WASMER_OK
} else { } else {
update_last_error(CApiError { 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 wasmer_result_t::WASMER_ERROR
}; };
@ -844,20 +1261,19 @@ pub unsafe extern "C" fn wasmer_func_returns_arity(
/// Frees memory for the given Func /// Frees memory for the given Func
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
#[no_mangle] #[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() { if !func.is_null() {
drop(unsafe { Box::from_raw(func as *mut Export) }); drop(unsafe { Box::from_raw(func as *mut Export) });
} }
} }
/// Gets func from wasm_export /// Gets export func from export
#[no_mangle] #[no_mangle]
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_export_to_func( pub unsafe extern "C" fn wasmer_export_to_func(
export: *mut wasmer_export_t, export: *mut wasmer_export_t,
) -> *const wasmer_func_t { ) -> *const wasmer_export_func_t {
let named_export = &*(export as *mut NamedExport); export as *const wasmer_export_func_t
&named_export.export as *const Export as *const wasmer_func_t
} }
/// Gets name from wasmer_export /// 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. /// and `wasmer_last_error_message` to get an error message.
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasmer_func_call( pub unsafe extern "C" fn wasmer_export_func_call(
func: *mut wasmer_func_t, func: *mut wasmer_export_func_t,
params: *const wasmer_value_t, params: *const wasmer_value_t,
params_len: c_int, params_len: c_int,
results: *mut wasmer_value_t, 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: &[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 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); let results: &mut [wasmer_value_t] = slice::from_raw_parts_mut(results, results_len as usize);
// TODO implement func.call
update_last_error(CApiError { let instance = &*named_export.instance;
msg: "wasmer_func_call not yet implemented".to_string(), let result = instance.call(&named_export.name, &params[..]);
}); match result {
wasmer_result_t::WASMER_ERROR Ok(results_vec) => {
// let result = instance.call(func_name_r, &params[..]); if results_vec.len() > 0 {
// Box::into_raw(export_func); let ret = match results_vec[0] {
// match result { Value::I32(x) => wasmer_value_t {
// Ok(results_vec) => { tag: wasmer_value_tag::WASM_I32,
// if results_vec.len() > 0 { value: wasmer_value { I32: x },
// let ret = match results_vec[0] { },
// Value::I32(x) => wasmer_value_t { Value::I64(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_I32, tag: wasmer_value_tag::WASM_I64,
// value: wasmer_value { I32: x }, value: wasmer_value { I64: x },
// }, },
// Value::I64(x) => wasmer_value_t { Value::F32(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_I64, tag: wasmer_value_tag::WASM_F32,
// value: wasmer_value { I64: x }, value: wasmer_value { F32: x },
// }, },
// Value::F32(x) => wasmer_value_t { Value::F64(x) => wasmer_value_t {
// tag: wasmer_value_tag::WASM_F32, tag: wasmer_value_tag::WASM_F64,
// value: wasmer_value { F32: x }, value: wasmer_value { F64: x },
// }, },
// Value::F64(x) => wasmer_value_t { };
// tag: wasmer_value_tag::WASM_F64, results[0] = ret;
// value: wasmer_value { F64: x }, }
// }, wasmer_result_t::WASMER_OK
// }; }
// results[0] = ret; Err(err) => {
// } update_last_error(err);
// wasmer_result_t::WASMER_OK wasmer_result_t::WASMER_ERROR
// } }
// Err(err) => { }
// update_last_error(err);
// wasmer_result_t::WASMER_ERROR
// }
// }
} }
/// Gets the memory within the context at the index `memory_idx`. /// 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 { impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag {
fn from(ty: &Type) -> Self { fn from(ty: &Type) -> Self {
match *ty { 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 // Error reporting
thread_local! { thread_local! {
@ -1171,7 +1592,19 @@ impl fmt::Display for CApiError {
impl Error for CApiError {} impl Error for CApiError {}
struct NamedImportDescriptor {
module: String,
name: String,
kind: wasmer_import_export_kind,
}
struct NamedExport { struct NamedExport {
name: String, name: String,
export: Export, export: Export,
instance: *mut Instance,
}
struct NamedExportDescriptor {
name: String,
kind: wasmer_import_export_kind,
} }

View File

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

View File

@ -1,12 +1,15 @@
cmake_minimum_required (VERSION 2.6) cmake_minimum_required (VERSION 2.6)
project (WasmerCApiTests) project (WasmerCApiTests)
add_executable(test-imports test-imports.c)
add_executable(test-exports test-exports.c) add_executable(test-exports test-exports.c)
add_executable(test-globals test-globals.c) add_executable(test-globals test-globals.c)
add_executable(test-instantiate test-instantiate.c) add_executable(test-instantiate test-instantiate.c)
add_executable(test-import-function test-import-function.c) add_executable(test-import-function test-import-function.c)
add_executable(test-memory test-memory.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 test-module.c)
add_executable(test-module-exports test-module-exports.c)
add_executable(test-validate test-validate.c) add_executable(test-validate test-validate.c)
add_executable(test-tables test-tables.c) add_executable(test-tables test-tables.c)
@ -19,6 +22,8 @@ if(NOT WASMER_LIB)
message(FATAL_ERROR "wasmer library not found") message(FATAL_ERROR "wasmer library not found")
endif() endif()
target_link_libraries(test-imports
general ${WASMER_LIB})
target_link_libraries(test-exports target_link_libraries(test-exports
general ${WASMER_LIB}) general ${WASMER_LIB})
target_link_libraries(test-globals target_link_libraries(test-globals
@ -29,20 +34,27 @@ target_link_libraries(test-import-function
general ${WASMER_LIB}) general ${WASMER_LIB})
target_link_libraries(test-memory target_link_libraries(test-memory
general ${WASMER_LIB}) general ${WASMER_LIB})
target_link_libraries(test-module-imports
general ${WASMER_LIB})
target_link_libraries(test-module target_link_libraries(test-module
general ${WASMER_LIB}) general ${WASMER_LIB})
target_link_libraries(test-module-exports
general ${WASMER_LIB})
target_link_libraries(test-validate target_link_libraries(test-validate
general ${WASMER_LIB}) general ${WASMER_LIB})
target_link_libraries(test-tables target_link_libraries(test-tables
general ${WASMER_LIB}) general ${WASMER_LIB})
enable_testing() enable_testing()
add_test(test-imports test-imports)
add_test(test-exports test-exports) add_test(test-exports test-exports)
add_test(test-globals test-globals) add_test(test-globals test-globals)
add_test(test-instantiate test-instantiate) add_test(test-instantiate test-instantiate)
add_test(test-import-function test-import-function) add_test(test-import-function test-import-function)
add_test(test-memory test-memory) add_test(test-memory test-memory)
add_test(test-module-imports test-module-imports)
add_test(test-module test-module) add_test(test-module test-module)
add_test(test-module-exports test-module-exports)
add_test(test-validate test-validate) add_test(test-validate test-validate)
add_test(test-tables test-tables) 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); wasmer_import_export_kind kind = wasmer_export_kind(export);
assert(kind == WASM_FUNCTION); 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); wasmer_byte_array name_bytes = wasmer_export_name(export);
assert(name_bytes.bytes_len == 3); assert(name_bytes.bytes_len == 3);
@ -42,40 +42,40 @@ int main()
} }
uint32_t params_arity; uint32_t params_arity;
wasmer_func_params_arity(func, &params_arity); wasmer_export_func_params_arity(func, &params_arity);
assert(params_arity == 2); assert(params_arity == 2);
wasmer_value_tag *params_sig = malloc(sizeof(wasmer_value_tag) * params_arity); 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[0] == WASM_I32);
assert(params_sig[1] == WASM_I32); assert(params_sig[1] == WASM_I32);
free(params_sig); free(params_sig);
uint32_t returns_arity; uint32_t returns_arity;
wasmer_func_returns_arity(func, &returns_arity); wasmer_export_func_returns_arity(func, &returns_arity);
assert(returns_arity == 1); assert(returns_arity == 1);
wasmer_value_tag *returns_sig = malloc(sizeof(wasmer_value_tag) * returns_arity); 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); assert(returns_sig[0] == WASM_I32);
free(returns_sig); free(returns_sig);
// wasmer_value_t param_one; wasmer_value_t param_one;
// param_one.tag = WASM_I32; param_one.tag = WASM_I32;
// param_one.value.I32 = 7; param_one.value.I32 = 7;
// wasmer_value_t param_two; wasmer_value_t param_two;
// param_two.tag = WASM_I32; param_two.tag = WASM_I32;
// param_two.value.I32 = 8; param_two.value.I32 = 8;
// wasmer_value_t params[] = {param_one, param_two}; wasmer_value_t params[] = {param_one, param_two};
// wasmer_value_t result_one; wasmer_value_t result_one;
// wasmer_value_t results[] = {result_one}; wasmer_value_t results[] = {result_one};
//
// wasmer_result_t call_result = wasmer_func_call(func, params, 2, results, 1); wasmer_result_t call_result = wasmer_export_func_call(func, params, 2, results, 1);
// printf("Call result: %d\n", call_result); printf("Call result: %d\n", call_result);
// printf("Result: %d\n", results[0].value.I32); printf("Result: %d\n", results[0].value.I32);
// assert(results[0].value.I32 == 15); assert(results[0].value.I32 == 15);
// assert(call_result == WASMER_OK); assert(call_result == WASMER_OK);
printf("Destroy instance\n"); printf("Destroy instance\n");

View File

@ -31,7 +31,7 @@ int main()
wasmer_value_tag returns_sig[] = {}; wasmer_value_tag returns_sig[] = {};
printf("Creating new func\n"); 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; wasmer_import_t import;
char *module_name = "env"; char *module_name = "env";
@ -84,7 +84,7 @@ int main()
assert(0 == strcmp(actual_str, "Hello, World!")); assert(0 == strcmp(actual_str, "Hello, World!"));
printf("Destroying func\n"); printf("Destroying func\n");
wasmer_func_destroy(func); wasmer_import_func_destroy(func);
printf("Destroy instance\n"); printf("Destroy instance\n");
wasmer_instance_destroy(instance); wasmer_instance_destroy(instance);
return 0; 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

@ -23,13 +23,13 @@ int main()
wasmer_result_t grow_result = wasmer_memory_grow(memory, 2); wasmer_result_t grow_result = wasmer_memory_grow(memory, 2);
assert(grow_result == WASMER_OK); assert(grow_result == WASMER_OK);
uint32_t new_len = wasmer_memory_length(memory); uint32_t new_len = wasmer_memory_length(memory);
printf("Memory pages length: %d\n", new_len); printf("Memory pages length: %d\n", new_len);
assert(new_len == 12); assert(new_len == 12);
uint32_t bytes_len = wasmer_memory_data_length(memory); uint32_t bytes_len = wasmer_memory_data_length(memory);
printf("Memory bytes length: %d\n", bytes_len); printf("Memory bytes length: %d\n", bytes_len);
assert(bytes_len == 12 * 65536); assert(bytes_len == 12 * 65536);
// Err, grow beyond max // Err, grow beyond max
wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10); wasmer_result_t grow_result2 = wasmer_memory_grow(memory, 10);
@ -38,23 +38,26 @@ int main()
char *error_str = malloc(error_len); char *error_str = malloc(error_len);
wasmer_last_error_message(error_str, error_len); wasmer_last_error_message(error_str, error_len);
printf("Error str: `%s`\n", error_str); 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); 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; int error_len2 = wasmer_last_error_length();
// wasmer_limits_t bad_descriptor; char *error_str2 = malloc(error_len2);
// bad_descriptor.min = 15; wasmer_last_error_message(error_str2, error_len2);
// bad_descriptor.max = 10; printf("Error str 2: `%s`\n", error_str2);
// wasmer_result_t bad_memory_result = wasmer_memory_new(&bad_memory, bad_descriptor); 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\""));
// printf("Bad memory result: %d\n", bad_memory_result); free(error_str2);
// 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);
printf("Destroy memory\n"); printf("Destroy memory\n");
wasmer_memory_destroy(memory); 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; wasmer_limits_t descriptor;
descriptor.min = 10; descriptor.min = 10;
wasmer_limit_option_t max; wasmer_limit_option_t max;
// max.has_some = false; // max.has_some = false;
max.has_some = true; max.has_some = true;
max.some = 15; max.some = 15;
descriptor.max = max; descriptor.max = max;
@ -21,26 +21,29 @@ int main()
printf("Table length: %d\n", len); printf("Table length: %d\n", len);
assert(len == 10); assert(len == 10);
// wasmer_result_t grow_result1 = wasmer_table_grow(table, 5); wasmer_result_t grow_result1 = wasmer_table_grow(table, 5);
// assert(grow_result1 == WASMER_OK); assert(grow_result1 == WASMER_OK);
// uint32_t len_grow1 = wasmer_table_length(table); uint32_t len_grow1 = wasmer_table_length(table);
// printf("Table length: %d\n", len_grow1); printf("Table length: %d\n", len_grow1);
// assert(len_grow1 == 15); assert(len_grow1 == 15);
// // Try to grow beyond max // Try to grow beyond max
// wasmer_result_t grow_result2 = wasmer_table_grow(&table, 1); wasmer_result_t grow_result2 = wasmer_table_grow(table, 1);
// assert(grow_result2 == WASMER_ERROR); assert(grow_result2 == WASMER_ERROR);
// uint32_t len_grow2 = wasmer_table_length(table); uint32_t len_grow2 = wasmer_table_length(table);
// printf("Table length: %d\n", len_grow2); printf("Table length: %d\n", len_grow2);
// assert(len_grow2 == 15); assert(len_grow2 == 15);
// wasmer_table_t *table_bad = NULL; wasmer_table_t *table_bad = NULL;
// wasmer_limits_t bad_descriptor; wasmer_limits_t bad_descriptor;
// bad_descriptor.min = 15; bad_descriptor.min = 15;
// bad_descriptor.max = 10; wasmer_limit_option_t max2;
// wasmer_result_t table_bad_result = wasmer_table_new(&table_bad, bad_descriptor); max2.has_some = true;
// printf("Table result: %d\n", table_bad_result); max2.some = 10;
// assert(table_result == WASMER_ERROR); 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"); printf("Destroy table\n");
wasmer_table_destroy(table); wasmer_table_destroy(table);

View File

@ -35,7 +35,7 @@ typedef struct wasmer_module_t wasmer_module_t;
typedef struct { typedef struct {
} wasmer_export_t; } wasmer_export_descriptor_t;
typedef struct { typedef struct {
const uint8_t *bytes; const uint8_t *bytes;
@ -44,11 +44,11 @@ typedef struct {
typedef struct { typedef struct {
} wasmer_func_t; } wasmer_export_descriptors_t;
typedef struct { typedef struct {
} wasmer_exports_t; } wasmer_export_func_t;
typedef union { typedef union {
int32_t I32; int32_t I32;
@ -64,6 +64,14 @@ typedef struct {
typedef struct { typedef struct {
} wasmer_export_t;
typedef struct {
} wasmer_exports_t;
typedef struct {
} wasmer_global_t; } wasmer_global_t;
typedef struct { typedef struct {
@ -73,6 +81,18 @@ typedef struct {
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; } wasmer_memory_t;
typedef struct { typedef struct {
@ -80,7 +100,7 @@ typedef struct {
} wasmer_table_t; } wasmer_table_t;
typedef union { typedef union {
const wasmer_func_t *func; const wasmer_import_func_t *func;
const wasmer_table_t *table; const wasmer_table_t *table;
const wasmer_memory_t *memory; const wasmer_memory_t *memory;
const wasmer_global_t *global; const wasmer_global_t *global;
@ -113,6 +133,88 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
uint8_t *wasm_bytes, uint8_t *wasm_bytes,
uint32_t wasm_bytes_len); 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 * 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_); 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 * 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); 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 * 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); 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. * Calls an instances exported function by `name` with the provided parameters.
* Results are set using the provided `results` pointer. * Results are set using the provided `results` pointer.

View File

@ -30,7 +30,7 @@ struct wasmer_instance_t;
struct wasmer_module_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; 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; wasmer_value value;
}; };
struct wasmer_export_t {
};
struct wasmer_exports_t {
};
struct wasmer_global_t { struct wasmer_global_t {
}; };
@ -68,6 +76,18 @@ struct wasmer_global_descriptor_t {
wasmer_value_tag kind; wasmer_value_tag kind;
}; };
struct wasmer_import_descriptor_t {
};
struct wasmer_import_descriptors_t {
};
struct wasmer_import_func_t {
};
struct wasmer_memory_t { struct wasmer_memory_t {
}; };
@ -77,7 +97,7 @@ struct wasmer_table_t {
}; };
union wasmer_import_export_value { union wasmer_import_export_value {
const wasmer_func_t *func; const wasmer_import_func_t *func;
const wasmer_table_t *table; const wasmer_table_t *table;
const wasmer_memory_t *memory; const wasmer_memory_t *memory;
const wasmer_global_t *global; const wasmer_global_t *global;
@ -110,14 +130,74 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
uint8_t *wasm_bytes, uint8_t *wasm_bytes,
uint32_t wasm_bytes_len); 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 /// Gets wasmer_export kind
wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);
/// Gets name from wasmer_export /// Gets name from wasmer_export
wasmer_byte_array wasmer_export_name(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 /// Frees the memory for the given exports
void wasmer_exports_destroy(wasmer_exports_t *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 /// Gets the length of the exports
int wasmer_exports_len(wasmer_exports_t *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 /// Frees memory for the given Global
void wasmer_global_destroy(wasmer_global_t *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 /// Sets the value stored by the given Global
void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); 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. /// Calls an instances exported function by `name` with the provided parameters.
/// Results are set using the provided `results` pointer. /// Results are set using the provided `results` pointer.
/// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_OK` upon success.

View File

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

View File

@ -12,7 +12,7 @@ use crate::{
module::ModuleInfo, module::ModuleInfo,
sys::Memory, sys::Memory,
}; };
use std::ptr::NonNull; use std::{any::Any, ptr::NonNull};
pub mod sys { pub mod sys {
pub use crate::sys::*; pub use crate::sys::*;
@ -79,7 +79,7 @@ pub trait ProtectedCaller: Send + Sync {
} }
pub trait UserTrapper { 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 { pub trait FuncResolver: Send + Sync {

View File

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

View File

@ -1,8 +1,9 @@
use crate::types::{ use crate::types::{
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type, FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
Value,
}; };
use core::borrow::Borrow; 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 Result<T> = std::result::Result<T, Error>;
pub type CompileResult<T> = std::result::Result<T, CompileError>; 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`. /// The main way to do this is `Instance.call`.
/// ///
/// Comparing two `RuntimeError`s always evaluates to false. /// Comparing two `RuntimeError`s always evaluates to false.
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum RuntimeError { pub enum RuntimeError {
OutOfBoundsAccess { Trap { msg: Box<str> },
memory: MemoryIndex, Exception { data: Box<[Value]> },
addr: Option<u32>, Panic { data: Box<dyn Any> },
},
TableOutOfBounds {
table: TableIndex,
},
IndirectCallSignature {
table: TableIndex,
},
IndirectCallToNull {
table: TableIndex,
},
IllegalArithmeticOperation,
User {
msg: String,
},
Unknown {
msg: String,
},
} }
impl PartialEq for RuntimeError { impl PartialEq for RuntimeError {
@ -153,30 +137,13 @@ impl PartialEq for RuntimeError {
impl std::fmt::Display for RuntimeError { impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
RuntimeError::IndirectCallSignature { table } => write!( RuntimeError::Trap { ref msg } => {
f, write!(f, "WebAssembly trap occured during runtime: {}", msg)
"Indirect call signature error with Table Index \"{:?}\"",
table
),
RuntimeError::IndirectCallToNull { table } => {
write!(f, "Indirect call to null with table index \"{:?}\"", table)
} }
RuntimeError::IllegalArithmeticOperation => write!(f, "Illegal arithmetic operation"), RuntimeError::Exception { ref data } => {
RuntimeError::OutOfBoundsAccess { memory, addr } => match addr { write!(f, "Uncaught WebAssembly exception: {:?}", data)
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::Unknown { msg } => { RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""),
write!(f, "Unknown runtime error with message: \"{}\"", msg)
}
RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg),
} }
} }
} }
@ -232,7 +199,7 @@ impl std::error::Error for ResolveError {}
/// be the `CallError::Runtime(RuntimeError)` variant. /// be the `CallError::Runtime(RuntimeError)` variant.
/// ///
/// Comparing two `CallError`s always evaluates to false. /// Comparing two `CallError`s always evaluates to false.
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum CallError { pub enum CallError {
Resolve(ResolveError), Resolve(ResolveError),
Runtime(RuntimeError), Runtime(RuntimeError),
@ -291,7 +258,7 @@ impl std::error::Error for CreationError {}
/// of a webassembly module. /// of a webassembly module.
/// ///
/// Comparing two `Error`s always evaluates to false. /// Comparing two `Error`s always evaluates to false.
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum Error { pub enum Error {
CompileError(CompileError), CompileError(CompileError),
LinkError(Vec<LinkError>), LinkError(Vec<LinkError>),
@ -357,8 +324,127 @@ impl From<ResolveError> for CallError {
impl std::fmt::Display for Error { impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 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 {} 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::{ use crate::{
error::CreationError, error::CreationError,
sys, sys,
@ -14,9 +15,9 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096;
/// when first created. Over time, as it grows, it may reallocate to /// when first created. Over time, as it grows, it may reallocate to
/// a different location and size. /// 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 /// 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 /// While, a dynamic memory could use a vector of some sort as its
/// backing memory, we use mmap (or the platform-equivalent) to allow /// backing memory, we use mmap (or the platform-equivalent) to allow
@ -65,26 +66,29 @@ impl DynamicMemory {
self.current 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) { 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 let Some(max) = self.max {
if new_pages > max { if new_pages > max {
return None; return Err(GrowError::ExceededMaxPagesForMemory(
new_pages.0 as usize,
max.0 as usize,
));
} }
} }
let mut new_memory = let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?; .map_err(|e| e.into())?;
unsafe { unsafe {
new_memory new_memory
.protect(0..new_pages.bytes().0, sys::Protect::ReadWrite) .protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
.ok()?; .map_err(|e| e.into())?;
new_memory.as_slice_mut()[..self.current.bytes().0] new_memory.as_slice_mut()[..self.current.bytes().0]
.copy_from_slice(&self.memory.as_slice()[..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; let old_pages = self.current;
self.current = new_pages; self.current = new_pages;
Some(old_pages) Ok(old_pages)
} }
pub fn as_slice(&self) -> &[u8] { pub fn as_slice(&self) -> &[u8] {

View File

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

View File

@ -1,3 +1,4 @@
use crate::error::GrowError;
use crate::{ use crate::{
error::CreationError, error::CreationError,
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
@ -61,27 +62,30 @@ impl StaticMemory {
self.current 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) { 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 let Some(max) = self.max {
if new_pages > 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 self.memory
.protect( .protect(
self.current.bytes().0..new_pages.bytes().0, self.current.bytes().0..new_pages.bytes().0,
sys::Protect::ReadWrite, sys::Protect::ReadWrite,
) )
.ok()?; .map_err(|e| e.into())
} }?;
local.bound = new_pages.bytes().0; local.bound = new_pages.bytes().0;
@ -89,7 +93,7 @@ impl StaticMemory {
self.current = new_pages; self.current = new_pages;
Some(old_pages) Ok(old_pages)
} }
pub fn as_slice(&self) -> &[u8] { pub fn as_slice(&self) -> &[u8] {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ use crate::{
types::{FuncSig, Type, WasmExternType}, types::{FuncSig, Type, WasmExternType},
vm::Ctx, 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! { thread_local! {
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None); pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
@ -40,14 +40,14 @@ pub trait TrapEarly<Rets>
where where
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
fn report(self) -> Result<Rets, String>; fn report(self) -> Result<Rets, Box<dyn Any>>;
} }
impl<Rets> TrapEarly<Rets> for Rets impl<Rets> TrapEarly<Rets> for Rets
where where
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
fn report(self) -> Result<Rets, String> { fn report(self) -> Result<Rets, Box<dyn Any>> {
Ok(self) Ok(self)
} }
} }
@ -55,10 +55,10 @@ where
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E> impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
where where
Rets: WasmTypeList, Rets: WasmTypeList,
E: fmt::Debug, E: Any,
{ {
fn report(self) -> Result<Rets, String> { fn report(self) -> Result<Rets, Box<dyn Any>> {
self.map_err(|err| format!("Error: {:?}", err)) 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 { 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 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() f( ctx $( ,$x )* ).report()
})) { })) {
Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Ok(returns)) => return returns.into_c_struct(),
Ok(Err(err)) => err, Ok(Err(err)) => err,
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()
}
},
}; };
unsafe { unsafe {
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) { if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
early_trapper.do_early_trap(msg) early_trapper.do_early_trap(err)
} else { } else {
eprintln!("panic handling not setup"); eprintln!("panic handling not setup");
std::process::exit(1) std::process::exit(1)

View File

@ -1,3 +1,4 @@
use crate::error::PageError;
use std::{ use std::{
fmt, fmt,
ops::{Add, Sub}, ops::{Add, Sub},
@ -11,12 +12,16 @@ const WASM_MAX_PAGES: usize = 65_536;
pub struct Pages(pub u32); pub struct Pages(pub u32);
impl Pages { 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); let added = (self.0 as usize) + (rhs.0 as usize);
if added <= WASM_MAX_PAGES { if added <= WASM_MAX_PAGES {
Some(Pages(added as u32)) Ok(Pages(added as u32))
} else { } 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 local_memory = *ctx.memories.add(memory_index.index());
let memory = (*local_memory).memory as *mut StaticMemory; let memory = (*local_memory).memory as *mut StaticMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) { match (*memory).grow(delta, &mut *local_memory) {
old.0 as i32 Ok(old) => old.0 as i32,
} else { Err(_) => -1,
-1
} }
} }
@ -45,10 +44,9 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
let local_memory = *ctx.memories.add(memory_index.index()); let local_memory = *ctx.memories.add(memory_index.index());
let memory = (*local_memory).memory as *mut DynamicMemory; let memory = (*local_memory).memory as *mut DynamicMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) { match (*memory).grow(delta, &mut *local_memory) {
old.0 as i32 Ok(old) => old.0 as i32,
} else { Err(_) => -1,
-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 local_memory = *ctx.imported_memories.add(import_memory_index.index());
let memory = (*local_memory).memory as *mut StaticMemory; let memory = (*local_memory).memory as *mut StaticMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) { match (*memory).grow(delta, &mut *local_memory) {
old.0 as i32 Ok(old) => old.0 as i32,
} else { Err(_) => -1,
-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 local_memory = *ctx.imported_memories.add(memory_index.index());
let memory = (*local_memory).memory as *mut DynamicMemory; let memory = (*local_memory).memory as *mut DynamicMemory;
if let Some(old) = (*memory).grow(delta, &mut *local_memory) { match (*memory).grow(delta, &mut *local_memory) {
old.0 as i32 Ok(old) => old.0 as i32,
} else { Err(_) => -1,
-1
} }
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "wasmer-runtime" name = "wasmer-runtime"
version = "0.1.4" version = "0.2.1"
description = "Wasmer runtime library" description = "Wasmer runtime library"
license = "MIT" license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"] authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -14,11 +14,16 @@ memmap = "0.7.0"
[dependencies.wasmer-runtime-core] [dependencies.wasmer-runtime-core]
path = "../runtime-core" path = "../runtime-core"
version = "0.1.2" version = "0.2.1"
[dependencies.wasmer-clif-backend] [dependencies.wasmer-clif-backend]
path = "../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] [dependencies.wasmer-llvm-backend]
path = "../llvm-backend" path = "../llvm-backend"
@ -26,5 +31,6 @@ path = "../llvm-backend"
[features] [features]
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
[dev-dependencies] [[bench]]
wabt = "0.7.4" 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. // We're not importing anything, so make an empty import object.
let import_object = imports! {}; let import_object = imports! {};
let mut instance = instantiate(WASM, import_object)?; let mut instance = instantiate(WASM, &import_object)?;
let values = instance let values = instance
.func("add_one")? .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] [package]
name = "wasmer-spectests" name = "wasmer-spectests"
version = "0.1.2" version = "0.2.0"
description = "Wasmer spectests library" description = "Wasmer spectests library"
license = "MIT" license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"] authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,13 +9,13 @@ edition = "2018"
build = "build/mod.rs" build = "build/mod.rs"
[dependencies] [dependencies]
wasmer-runtime-core = { path = "../runtime-core" } wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
[build-dependencies] [build-dependencies]
wabt = "0.7.2" wabt = "0.7.2"
[dev-dependencies] [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" } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
wabt = "0.7.2" wabt = "0.7.2"

View File

@ -569,7 +569,7 @@ fn {}_assert_malformed() {{
let assertion = if expected.len() > 0 && is_nan(&expected[0]) { let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
format!( format!(
"let expected = {expected_result}; "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!((*result as {return_type}).is_nan());
assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive()); assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive());
}} else {{ }} else {{

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
extern crate structopt; extern crate structopt;
use std::env; use std::env;
use std::fs;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::io::Read; use std::io::Read;
@ -14,7 +13,6 @@ use wasmer::webassembly::InstanceABI;
use wasmer::*; use wasmer::*;
use wasmer_emscripten; use wasmer_emscripten;
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash}; use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash};
use wasmer_runtime::error::CacheError;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt(name = "wasmer", about = "Wasm execution runtime.")] #[structopt(name = "wasmer", about = "Wasm execution runtime.")]
@ -35,9 +33,6 @@ enum CLIOptions {
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
struct Run { struct Run {
#[structopt(short = "d", long = "debug")]
debug: bool,
// Disable the cache // Disable the cache
#[structopt(long = "disable-cache")] #[structopt(long = "disable-cache")]
disable_cache: bool, disable_cache: bool,
@ -84,6 +79,12 @@ fn get_cache_dir() -> PathBuf {
/// Execute a wasm/wat file /// Execute a wasm/wat file
fn execute_wasm(options: &Run) -> Result<(), String> { 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 wasm_path = &options.path;
let mut wasm_binary: Vec<u8> = read_file_contents(wasm_path).map_err(|err| { 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))?; .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 // If we have cache enabled
// We generate a hash for the given binary, so we can use it as key // We generate a hash for the given binary, so we can use it as key
@ -188,8 +189,10 @@ fn main() {
CLIOptions::SelfUpdate => { CLIOptions::SelfUpdate => {
println!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io"); 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 { CLIOptions::Cache(cache) => match cache {
Cache::Clean => { Cache::Clean => {
use std::fs;
let cache_dir = get_cache_dir(); let cache_dir = get_cache_dir();
fs::remove_dir_all(cache_dir.clone()).expect("Can't remove 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"); 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()); 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 OutputBaseFilename=WasmerInstaller
[Files] [Files]
Source: "..\target\release\wasmer.exe"; DestDir: "{app}\bin" Source: "..\..\target\release\wasmer.exe"; DestDir: "{app}\bin"
[Code] [Code]
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';