Merge remote-tracking branch 'origin/master' into feature/remote-code-load

This commit is contained in:
losfair
2019-05-14 15:46:15 +08:00
79 changed files with 1646 additions and 1299 deletions

View File

@ -5,6 +5,16 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.
## **[Unreleased]**
- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs
- [#432](https://github.com/wasmerio/wasmer/pull/432) Fix returned value of `wasmer_last_error_message` in the runtime C API
- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements
- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits
## 0.4.1 - 2018-05-06
- [#426](https://github.com/wasmerio/wasmer/pull/426) Update wapm-cli submodule, bump version to 0.4.1
- [#422](https://github.com/wasmerio/wasmer/pull/422) Improved Emscripten functions to run optipng and pngquant compiled to wasm
- [#409](https://github.com/wasmerio/wasmer/pull/409) Improved Emscripten functions to run JavascriptCore compiled to wasm
- [#399](https://github.com/wasmerio/wasmer/pull/399) Add example of using a plugin extended from WASI
- [#397](https://github.com/wasmerio/wasmer/pull/397) Fix WASI fs abstraction to work on Windows

88
Cargo.lock generated
View File

@ -2256,7 +2256,7 @@ dependencies = [
[[package]]
name = "wasmer"
version = "0.4.0"
version = "0.4.1"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2266,20 +2266,20 @@ dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.3.0",
"wasmer-emscripten 0.3.0",
"wasmer-llvm-backend 0.3.0",
"wasmer-middleware-common 0.3.0",
"wasmer-runtime 0.3.0",
"wasmer-runtime-abi 0.3.0",
"wasmer-runtime-core 0.3.0",
"wasmer-singlepass-backend 0.3.0",
"wasmer-wasi 0.3.0",
"wasmer-clif-backend 0.4.1",
"wasmer-emscripten 0.4.1",
"wasmer-llvm-backend 0.4.1",
"wasmer-middleware-common 0.4.1",
"wasmer-runtime 0.4.1",
"wasmer-runtime-abi 0.4.1",
"wasmer-runtime-core 0.4.1",
"wasmer-singlepass-backend 0.4.1",
"wasmer-wasi 0.4.1",
]
[[package]]
name = "wasmer-clif-backend"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2295,15 +2295,15 @@ dependencies = [
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.3.0",
"wasmer-win-exception-handler 0.3.0",
"wasmer-runtime-core 0.4.1",
"wasmer-win-exception-handler 0.4.1",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmer-emscripten"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2312,15 +2312,15 @@ dependencies = [
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.3.0",
"wasmer-llvm-backend 0.3.0",
"wasmer-runtime-core 0.3.0",
"wasmer-singlepass-backend 0.3.0",
"wasmer-clif-backend 0.4.1",
"wasmer-llvm-backend 0.4.1",
"wasmer-runtime-core 0.4.1",
"wasmer-singlepass-backend 0.4.1",
]
[[package]]
name = "wasmer-llvm-backend"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"capstone 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2335,42 +2335,42 @@ dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.3.0",
"wasmer-runtime-core 0.4.1",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmer-middleware-common"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"wasmer-runtime-core 0.3.0",
"wasmer-runtime-core 0.4.1",
]
[[package]]
name = "wasmer-runtime"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.3.0",
"wasmer-llvm-backend 0.3.0",
"wasmer-runtime-core 0.3.0",
"wasmer-singlepass-backend 0.3.0",
"wasmer-clif-backend 0.4.1",
"wasmer-llvm-backend 0.4.1",
"wasmer-runtime-core 0.4.1",
"wasmer-singlepass-backend 0.4.1",
]
[[package]]
name = "wasmer-runtime-abi"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.3.0",
"wasmer-runtime-core 0.4.1",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
"zbox 0.6.1 (git+https://github.com/wasmerio/zbox?branch=bundle-libsodium)",
"zstd 0.4.22+zstd.1.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2378,17 +2378,17 @@ dependencies = [
[[package]]
name = "wasmer-runtime-c-api"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"cbindgen 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime 0.3.0",
"wasmer-runtime-core 0.3.0",
"wasmer-runtime 0.4.1",
"wasmer-runtime-core 0.4.1",
]
[[package]]
name = "wasmer-runtime-core"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"blake2b_simd 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2414,7 +2414,7 @@ dependencies = [
[[package]]
name = "wasmer-singlepass-backend"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2424,24 +2424,24 @@ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.3.0",
"wasmer-runtime-core 0.4.1",
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmer-spectests"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-backend 0.3.0",
"wasmer-llvm-backend 0.3.0",
"wasmer-runtime-core 0.3.0",
"wasmer-singlepass-backend 0.3.0",
"wasmer-clif-backend 0.4.1",
"wasmer-llvm-backend 0.4.1",
"wasmer-runtime-core 0.4.1",
"wasmer-singlepass-backend 0.4.1",
]
[[package]]
name = "wasmer-wasi"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"generational-arena 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2449,18 +2449,18 @@ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.3.0",
"wasmer-runtime-core 0.4.1",
]
[[package]]
name = "wasmer-win-exception-handler"
version = "0.3.0"
version = "0.4.1"
dependencies = [
"bindgen 0.46.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.3.0",
"wasmer-runtime-core 0.4.1",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer"
version = "0.4.0"
version = "0.4.1"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
repository = "https://github.com/wasmerio/wasmer"
@ -45,7 +45,8 @@ rustc_version = "0.2.3"
[features]
default = ["fast-tests", "wasi"]
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
debug = ["wasmer-runtime-core/debug"]
extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
# This feature will allow cargo test to run much faster
fast-tests = []
"backend:llvm" = ["wasmer-llvm-backend"]

View File

@ -84,5 +84,8 @@ production-release:
debug-release:
cargo build --release --features "debug"
extra-debug-release:
cargo build --release --features "extra-debug"
publish-release:
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/

View File

@ -27,10 +27,12 @@ curl https://get.wasmer.io -sSfL | sh
```
Wasmer runtime can also be embedded in different languages, so you can use WebAssembly anywhere ✨:
* [**Rust**](https://github.com/wasmerio/wasmer-rust-example)
* [**C/C++**](https://github.com/wasmerio/wasmer-c-api)
* [**PHP**](https://github.com/wasmerio/php-ext-wasm)
* [**Python**](https://github.com/wasmerio/python-ext-wasm)
* [**🐘 PHP**](https://github.com/wasmerio/php-ext-wasm)
* [**🐍 Python**](https://github.com/wasmerio/python-ext-wasm)
* [**💎 Ruby**](https://github.com/wasmerio/ruby-ext-wasm)
### Usage
@ -53,6 +55,24 @@ wasmer run examples/sqlite.wasm
wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
```
#### With WAPM
Installing Wasmer through `wasmer.io` includes
[wapm](https://github.com/wasmerio/wapm-cli), the WebAssembly package manager.
Wapm allows you to easily download, run, and distribute WebAssembly binaries.
```sh
# Install cowsay globally
wapm install -g cowsay
# Run cowsay
wapm run cowsay "Hello, world!"
```
For more information about wapm, check out the [website](https://www.wapm.io)
and this [example program](https://github.com/wapm-packages/rust-wasi-example).
## Code Structure
Wasmer is structured into different directories:

9
examples/README.md Normal file
View File

@ -0,0 +1,9 @@
# WebAssembly Examples
In this directory you can find a set of different examples that can run on the Wasmer WebAssembly runtime:
* Cowsay (WASI ABI) [[source-code](https://github.com/wapm-packages/cowsay)] [[wapm-package](https://wapm.io/package/cowsay)]
* Nginx (Emscripten ABI) [[source-code](https://github.com/wapm-packages/nginx)] [[wapm-package](https://wapm.io/package/nginx)]
* Lua (Emscripten ABI) [[source-code](https://github.com/wapm-packages/lua)] [[wapm-package](https://wapm.io/package/lua)]
* PHP (Emscripten ABI) [[source-code](https://github.com/wapm-packages/php)] [[wapm-package](https://wapm.io/package/php)]
* SQLite (Emscripten ABI) [[source-code](https://github.com/wapm-packages/sqlite)] [[wapm-package](https://wapm.io/package/sqlite)]

View File

@ -130,11 +130,11 @@ wasmer_detect_profile() {
wasmer_link() {
printf "$cyan> Adding to bash profile...$reset\n"
WASMER_PROFILE="$(wasmer_detect_profile)"
LOAD_STR="\n# Wasmer\nexport WASMER_DIR=\"\$HOME/.wasmer\"\n[ -s \"\$WASMER_DIR/wasmer.sh\" ] && source \"\$WASMER_DIR/wasmer.sh\" # This loads wasmer\n"
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"\$HOME/.wasmer\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\nexport PATH=\"\$HOME/.wasmer/bin:\$HOME/.wasmer/globals/wapm_packages/.bin:\$PATH\"\n"
LOAD_STR="\n# Wasmer\nexport WASMER_DIR=\"$INSTALL_DIRECTORY\"\n[ -s \"\$WASMER_DIR/wasmer.sh\" ] && source \"\$WASMER_DIR/wasmer.sh\" # This loads wasmer\n"
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"$INSTALL_DIRECTORY\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\nexport PATH=\"\$WASMER_DIR/bin:\$WASMER_DIR/globals/wapm_packages/.bin:\$PATH\"\n"
# We create the wasmer.sh file
printf "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
printf "$SOURCE_STR" > "$INSTALL_DIRECTORY/wasmer.sh"
if [ -z "${WASMER_PROFILE-}" ] ; then
printf "${red}Profile not found. Tried:\n* ${WASMER_PROFILE} (as defined in \$PROFILE)\n* ~/.bashrc\n* ~/.bash_profile\n* ~/.zshrc\n* ~/.profile.\n"
@ -156,12 +156,12 @@ wasmer_link() {
echo "If this isn't the profile of your current shell then please add the following to your correct profile:"
printf "$LOAD_STR$reset\n"
version=`$HOME/.wasmer/bin/wasmer --version` || (
version=`$INSTALL_DIRECTORY/bin/wasmer --version` || (
printf "$red> wasmer was installed, but doesn't seem to be working :($reset\n"
exit 1;
)
printf "$green> Successfully installed $version!\n\n${reset}If you want to have the command available now please execute:\nsource $HOME/.wasmer/wasmer.sh$reset\n"
printf "$green> Successfully installed $version!\n\n${reset}If you want to have the command available now please execute:\nsource $INSTALL_DIRECTORY/wasmer.sh$reset\n"
printf "\nOtherwise, wasmer and wapm will be available the next time you open the terminal.\n"
echo "Note: during the alpha release of wapm, telemetry is enabled by default; if you would like to opt out, run \`wapm config set telemetry.enabled false\`."
echo "If you notice anything wrong or have any issues, please file a bug at https://github.com/wasmerio/wapm-cli :)"
@ -257,7 +257,7 @@ wasmer_install() {
"
fi
# if [ -d "$HOME/.wasmer" ]; then
# if [ -d "$INSTALL_DIRECTORY" ]; then
# if which wasmer; then
# local latest_url
# local specified_version
@ -286,11 +286,11 @@ wasmer_install() {
# exit 0
# else
# printf "$yellow> $wasmer_alt_version is already installed, Specified version: $specified_version.$reset\n"
# rm -rf "$HOME/.wasmer"
# rm -rf "$INSTALL_DIRECTORY"
# fi
# else
# printf "$red> $HOME/.wasmer already exists, possibly from a past Wasmer install.$reset\n"
# printf "$red> Remove it (rm -rf $HOME/.wasmer) and run this script again.$reset\n"
# printf "$red> $INSTALL_DIRECTORY already exists, possibly from a past Wasmer install.$reset\n"
# printf "$red> Remove it (rm -rf $INSTALL_DIRECTORY) and run this script again.$reset\n"
# exit 0
# fi
# fi

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-clif-backend"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer runtime Cranelift compiler backend"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
cranelift-native = "0.30.0"
cranelift-codegen = "0.30.0"
cranelift-entity = "0.30.0"
@ -33,7 +33,7 @@ version = "0.0.7"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.3.0" }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.4.1" }
[features]
debug = ["wasmer-runtime-core/debug"]

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
mod cache;
mod func_env;
mod libcalls;

View File

@ -1,5 +1,5 @@
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
//! accesses that occur when runniing webassembly.
//! accesses that occur when running WebAssembly.
//!
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
//!
@ -107,7 +107,7 @@ pub fn call_protected<T>(
Ok(SIGSEGV) => "segmentation violation",
Ok(SIGBUS) => "bus error",
Err(_) => "error while getting the Signal",
_ => "unkown trapped signal",
_ => "unknown trapped signal",
};
// When the trap-handler is fully implemented, this will return more information.
let s = format!("unknown trap at {:p} - {}", faulting_addr, signal);

View File

@ -4,7 +4,6 @@ use crate::trampoline::Trampoline;
use std::cell::Cell;
use std::ffi::c_void;
use std::ptr::{self, NonNull};
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
use wasmer_runtime_core::typed_func::WasmTrapInfo;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::vm::Func;
@ -12,10 +11,14 @@ use wasmer_win_exception_handler::CallProtectedData;
pub use wasmer_win_exception_handler::_call_protected;
use winapi::shared::minwindef::DWORD;
use winapi::um::minwinbase::{
EXCEPTION_ACCESS_VIOLATION, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT,
EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW,
EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_ILLEGAL_INSTRUCTION,
EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_STACK_OVERFLOW,
EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE,
EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW,
EXCEPTION_INVALID_HANDLE, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION,
EXCEPTION_POSSIBLE_DEADLOCK, EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP,
EXCEPTION_STACK_OVERFLOW,
};
thread_local! {
@ -43,7 +46,7 @@ pub fn call_protected(
}
let CallProtectedData {
code: signum,
code,
exception_address,
instruction_pointer,
} = result.unwrap_err();
@ -53,7 +56,7 @@ pub fn call_protected(
srcloc: _,
}) = handler_data.lookup(instruction_pointer as _)
{
Err(CallProtError::Trap(match signum as DWORD {
Err(CallProtError::Trap(match code as DWORD {
EXCEPTION_ACCESS_VIOLATION => WasmTrapInfo::MemoryOutOfBounds,
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature,
@ -70,7 +73,7 @@ pub fn call_protected(
_ => WasmTrapInfo::Unknown,
}))
} else {
let signal = match signum as DWORD {
let signal = match code as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND
| EXCEPTION_FLT_DIVIDE_BY_ZERO
| EXCEPTION_FLT_INEXACT_RESULT
@ -80,10 +83,26 @@ pub fn call_protected(
| EXCEPTION_FLT_UNDERFLOW => "floating-point exception",
EXCEPTION_ILLEGAL_INSTRUCTION => "illegal instruction",
EXCEPTION_ACCESS_VIOLATION => "segmentation violation",
_ => "unkown trapped signal",
EXCEPTION_DATATYPE_MISALIGNMENT => "datatype misalignment",
EXCEPTION_BREAKPOINT => "breakpoint",
EXCEPTION_SINGLE_STEP => "single step",
EXCEPTION_ARRAY_BOUNDS_EXCEEDED => "array bounds exceeded",
EXCEPTION_INT_DIVIDE_BY_ZERO => "int div by zero",
EXCEPTION_INT_OVERFLOW => "int overflow",
EXCEPTION_PRIV_INSTRUCTION => "priv instruction",
EXCEPTION_IN_PAGE_ERROR => "in page error",
EXCEPTION_NONCONTINUABLE_EXCEPTION => "non continuable exception",
EXCEPTION_STACK_OVERFLOW => "stack overflow",
EXCEPTION_GUARD_PAGE => "guard page",
EXCEPTION_INVALID_HANDLE => "invalid handle",
EXCEPTION_POSSIBLE_DEADLOCK => "possible deadlock",
_ => "unknown exception code",
};
let s = format!("unknown trap at {} - {}", exception_address, signal);
let s = format!(
"unhandled trap at {:x} - code #{:x}: {}",
exception_address, code, signal,
);
Err(CallProtError::Error(Box::new(s)))
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-emscripten"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer runtime emscripten implementation library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,14 +9,14 @@ edition = "2018"
build = "build/mod.rs"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
lazy_static = "1.2.0"
libc = "0.2.49"
byteorder = "1"
time = "0.1.41"
wasmer-clif-backend = { path = "../clif-backend", version = "0.3.0" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.3.0", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.3.0", optional = true }
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.1" }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.1", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.1", optional = true }
[target.'cfg(windows)'.dependencies]
rand = "0.6"

View File

@ -55,7 +55,7 @@ pub fn _dladdr(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
0
}
pub fn _pthread_attr_init(_ctx: &mut Ctx, _a: i32) -> i32 {
debug!("emscripten::_pthread_attr_init");
debug!("emscripten::_pthread_attr_init({})", _a);
0
}
pub fn _pthread_attr_destroy(_ctx: &mut Ctx, _a: i32) -> i32 {
@ -68,7 +68,10 @@ pub fn _pthread_attr_getstack(
_stacksize: i32,
_other: i32,
) -> i32 {
debug!("emscripten::_pthread_attr_getstack");
debug!(
"emscripten::_pthread_attr_getstack({}, {}, {})",
_stackaddr, _stacksize, _other
);
// TODO: Translate from Emscripten
// HEAP32[stackaddr >> 2] = STACK_BASE;
// HEAP32[stacksize >> 2] = TOTAL_STACK;
@ -87,7 +90,7 @@ pub fn _pthread_getspecific(_ctx: &mut Ctx, _a: i32) -> i32 {
0
}
pub fn _pthread_getattr_np(_ctx: &mut Ctx, _thread: i32, _attr: i32) -> i32 {
debug!("emscripten::_pthread_getattr_np");
debug!("emscripten::_pthread_getattr_np({}, {})", _thread, _attr);
0
}
pub fn _pthread_setspecific(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
@ -732,6 +735,10 @@ pub fn invoke_vj(ctx: &mut Ctx, index: i32, a1: i32, a2: i32) {
panic!("dyn_call_vj is set to None");
}
}
pub fn invoke_vjji(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) {
debug!("emscripten::invoke_vjji");
invoke_no_return!(ctx, dyn_call_vjji, index, a1, a2, a3, a4, a5)
}
pub fn invoke_vij(ctx: &mut Ctx, index: i32, a1: i32, a2: i32, a3: i32) {
debug!("emscripten::invoke_vij");
if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij {

View File

@ -60,21 +60,51 @@ pub fn ___build_environment(ctx: &mut Ctx, environ: c_int) {
const MAX_ENV_VALUES: u32 = 64;
const TOTAL_ENV_SIZE: u32 = 1024;
let environment = emscripten_memory_pointer!(ctx.memory(0), environ) as *mut c_int;
unsafe {
let (mut pool_offset, env_ptr, mut pool_ptr) = unsafe {
let (pool_offset, _pool_slice): (u32, &mut [u8]) =
allocate_on_stack(ctx, TOTAL_ENV_SIZE as u32);
let (env_offset, _env_slice): (u32, &mut [u8]) =
allocate_on_stack(ctx, (MAX_ENV_VALUES * 4) as u32);
let env_ptr = emscripten_memory_pointer!(ctx.memory(0), env_offset) as *mut c_int;
let mut _pool_ptr = emscripten_memory_pointer!(ctx.memory(0), pool_offset) as *mut c_int;
let pool_ptr = emscripten_memory_pointer!(ctx.memory(0), pool_offset) as *mut u8;
*env_ptr = pool_offset as i32;
*environment = env_offset as i32;
// *env_ptr = 0;
(pool_offset, env_ptr, pool_ptr)
};
// unsafe {
// *env_ptr = 0;
// };
// *env_ptr = 0;
let default_vars = vec![
["USER", "web_user"],
["LOGNAME", "web_user"],
["PATH", "/"],
["PWD", "/"],
["HOME", "/home/web_user"],
["LANG", "C.UTF-8"],
["_", "thisProgram"],
];
let mut strings = vec![];
let mut total_size = 0;
for [key, val] in &default_vars {
let line = key.to_string() + "=" + val;
total_size += line.len();
strings.push(line);
}
if total_size as u32 > TOTAL_ENV_SIZE {
panic!("Environment size exceeded TOTAL_ENV_SIZE!");
}
unsafe {
for (i, s) in strings.iter().enumerate() {
for (j, c) in s.chars().enumerate() {
debug_assert!(c < u8::max_value() as char);
*pool_ptr.add(j) = c as u8;
}
*env_ptr.add(i * 4) = pool_offset as i32;
pool_offset += s.len() as u32 + 1;
pool_ptr = pool_ptr.add(s.len() + 1);
}
*env_ptr.add(strings.len() * 4) = 0;
}
}
pub fn ___assert_fail(_ctx: &mut Ctx, _a: c_int, _b: c_int, _c: c_int, _d: c_int) {

View File

@ -7,7 +7,7 @@ use wasmer_runtime_core::vm::Ctx;
/// setjmp
pub fn __setjmp(ctx: &mut Ctx, _env_addr: u32) -> c_int {
debug!("emscripten::__setjmp (setjmp)");
abort_with_message(ctx, "missing function: _longjmp");
abort_with_message(ctx, "missing function: _setjmp");
unreachable!()
// unsafe {
// // Rather than using the env as the holder of the jump buffer pointer,

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#[macro_use]
extern crate wasmer_runtime_core;
@ -50,7 +52,7 @@ mod varargs;
pub use self::storage::{align_memory, static_alloc};
pub use self::utils::{
allocate_cstr_on_stack, allocate_on_stack, get_emscripten_memory_size,
allocate_cstr_on_stack, allocate_on_stack, get_emscripten_memory_size, get_emscripten_metadata,
get_emscripten_table_size, is_emscripten_module,
};
@ -127,6 +129,7 @@ pub struct EmscriptenData<'a> {
pub dyn_call_viijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_viijj: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vj: Option<Func<'a, (i32, i32, i32)>>,
pub dyn_call_vjji: Option<Func<'a, (i32, i32, i32, i32, i32, i32)>>,
pub dyn_call_vij: Option<Func<'a, (i32, i32, i32, i32)>>,
pub dyn_call_viji: Option<Func<'a, (i32, i32, i32, i32, i32)>>,
pub dyn_call_vijiii: Option<Func<'a, (i32, i32, i32, i32, i32, i32, i32)>>,
@ -146,11 +149,7 @@ impl<'a> EmscriptenData<'a> {
pub fn new(instance: &'a mut Instance) -> EmscriptenData<'a> {
let malloc = instance.func("_malloc").unwrap();
let free = instance.func("_free").unwrap();
let memalign = if let Ok(func) = instance.func("_memalign") {
Some(func)
} else {
None
};
let memalign = instance.func("_memalign").ok();
let memset = instance.func("_memset").unwrap();
let stack_alloc = instance.func("stackAlloc").unwrap();
@ -198,6 +197,7 @@ impl<'a> EmscriptenData<'a> {
let dyn_call_viijiii = instance.func("dynCall_viijiii").ok();
let dyn_call_viijj = instance.func("dynCall_viijj").ok();
let dyn_call_vj = instance.func("dynCall_vj").ok();
let dyn_call_vjji = instance.func("dynCall_vjji").ok();
let dyn_call_vij = instance.func("dynCall_vij").ok();
let dyn_call_viji = instance.func("dynCall_viji").ok();
let dyn_call_vijiii = instance.func("dynCall_vijiii").ok();
@ -261,6 +261,7 @@ impl<'a> EmscriptenData<'a> {
dyn_call_viijiii,
dyn_call_viijj,
dyn_call_vj,
dyn_call_vjji,
dyn_call_vij,
dyn_call_viji,
dyn_call_vijiii,
@ -282,6 +283,7 @@ pub fn run_emscripten_instance(
instance: &mut Instance,
path: &str,
args: Vec<&str>,
entrypoint: Option<String>,
) -> CallResult<()> {
let mut data = EmscriptenData::new(instance);
let data_ptr = &mut data as *mut _ as *mut c_void;
@ -299,52 +301,58 @@ pub fn run_emscripten_instance(
// println!("running emscripten instance");
let main_func = instance.dyn_func("_main")?;
let num_params = main_func.signature().params().len();
let _result = match num_params {
2 => {
let (argc, argv) = store_module_arguments(instance.context_mut(), path, args);
instance.call("_main", &[Value::I32(argc as i32), Value::I32(argv as i32)])?;
}
0 => {
instance.call("_main", &[])?;
}
_ => panic!(
"The emscripten main function has received an incorrect number of params {}",
num_params
),
};
if let Some(ep) = entrypoint {
debug!("Running entry point: {}", &ep);
let arg = unsafe { allocate_cstr_on_stack(instance.context_mut(), args[0]).0 };
//let (argc, argv) = store_module_arguments(instance.context_mut(), args);
instance.call(&ep, &[Value::I32(arg as i32)])?;
} else {
let main_func = instance.dyn_func("_main")?;
let num_params = main_func.signature().params().len();
let _result = match num_params {
2 => {
let mut new_args = vec![path];
new_args.extend(args);
let (argc, argv) = store_module_arguments(instance.context_mut(), new_args);
instance.call("_main", &[Value::I32(argc as i32), Value::I32(argv as i32)])?;
}
0 => {
instance.call("_main", &[])?;
}
_ => panic!(
"The emscripten main function has received an incorrect number of params {}",
num_params
),
};
}
// TODO atexit for emscripten
// println!("{:?}", data);
Ok(())
}
fn store_module_arguments(ctx: &mut Ctx, path: &str, args: Vec<&str>) -> (u32, u32) {
fn store_module_arguments(ctx: &mut Ctx, args: Vec<&str>) -> (u32, u32) {
let argc = args.len() + 1;
let mut args_slice = vec![0; argc];
args_slice[0] = unsafe { allocate_cstr_on_stack(ctx, path).0 };
for (slot, arg) in args_slice[1..argc].iter_mut().zip(args.iter()) {
for (slot, arg) in args_slice[0..argc].iter_mut().zip(args.iter()) {
*slot = unsafe { allocate_cstr_on_stack(ctx, &arg).0 };
}
let (argv_offset, argv_slice): (_, &mut [u32]) =
unsafe { allocate_on_stack(ctx, ((argc + 1) * 4) as u32) };
unsafe { allocate_on_stack(ctx, ((argc) * 4) as u32) };
assert!(!argv_slice.is_empty());
for (slot, arg) in argv_slice[0..argc].iter_mut().zip(args_slice.iter()) {
*slot = *arg
}
argv_slice[argc] = 0;
(argc as u32, argv_offset)
(argc as u32 - 1, argv_offset)
}
pub fn emscripten_set_up_memory(memory: &Memory, globals: &EmscriptenGlobalsData) {
let dynamictop_ptr = globals.dynamictop_ptr;
let stack_max = globals.stack_max;
let dynamic_base = align_memory(stack_max);
let dynamic_base = globals.dynamic_base;
memory.view::<u32>()[(dynamictop_ptr / 4) as usize].set(dynamic_base);
}
@ -355,6 +363,7 @@ pub struct EmscriptenGlobalsData {
stacktop: u32,
stack_max: u32,
dynamictop_ptr: u32,
dynamic_base: u32,
memory_base: u32,
table_base: u32,
temp_double_ptr: u32,
@ -424,7 +433,14 @@ impl EmscriptenGlobals {
let temp_double_ptr = static_top;
static_top += 16;
let dynamictop_ptr = static_alloc(&mut static_top, 4);
let (dynamic_base, dynamictop_ptr) =
get_emscripten_metadata(&module).unwrap_or_else(|| {
let dynamictop_ptr = static_alloc(&mut static_top, 4);
(
align_memory(align_memory(static_top) + TOTAL_STACK),
dynamictop_ptr,
)
});
let stacktop = align_memory(static_top);
let stack_max = stacktop + TOTAL_STACK;
@ -434,6 +450,7 @@ impl EmscriptenGlobals {
stacktop,
stack_max,
dynamictop_ptr,
dynamic_base,
memory_base,
table_base,
temp_double_ptr,
@ -597,6 +614,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
"___syscall272" => func!(crate::syscalls::___syscall272),
"___syscall295" => func!(crate::syscalls::___syscall295),
"___syscall300" => func!(crate::syscalls::___syscall300),
"___syscall320" => func!(crate::syscalls::___syscall320),
"___syscall324" => func!(crate::syscalls::___syscall324),
"___syscall330" => func!(crate::syscalls::___syscall330),
"___syscall334" => func!(crate::syscalls::___syscall334),
@ -718,6 +736,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
"invoke_v" => func!(crate::emscripten_target::invoke_v),
"invoke_vi" => func!(crate::emscripten_target::invoke_vi),
"invoke_vj" => func!(crate::emscripten_target::invoke_vj),
"invoke_vjji" => func!(crate::emscripten_target::invoke_vjji),
"invoke_vii" => func!(crate::emscripten_target::invoke_vii),
"invoke_viii" => func!(crate::emscripten_target::invoke_viii),
"invoke_viiii" => func!(crate::emscripten_target::invoke_viiii),

View File

@ -21,8 +21,11 @@ pub fn _emscripten_memcpy_big(ctx: &mut Ctx, dest: u32, src: u32, len: u32) -> u
/// emscripten: _emscripten_get_heap_size
pub fn _emscripten_get_heap_size(ctx: &mut Ctx) -> u32 {
debug!("emscripten::_emscripten_get_heap_size",);
ctx.memory(0).size().bytes().0 as u32
debug!("emscripten::_emscripten_get_heap_size");
let result = ctx.memory(0).size().bytes().0 as u32;
debug!("=> {}", result);
result
}
// From emscripten implementation

View File

@ -82,7 +82,7 @@ pub fn _raise(_ctx: &mut Ctx, _one: i32) -> i32 {
}
pub fn _sem_init(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 {
debug!("emscripten::_sem_init");
debug!("emscripten::_sem_init: {}, {}, {}", _one, _two, _three);
0
}

View File

@ -31,12 +31,13 @@ use libc::{
off_t,
// open,
read,
rename,
// sockaddr_in,
// readv,
rmdir,
// writev,
stat,
write,
// sockaddr_in,
};
use wasmer_runtime_core::vm::Ctx;
@ -118,9 +119,21 @@ pub fn ___syscall20(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
unsafe { getpid() }
}
pub fn ___syscall38(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall38");
-1
// rename
pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 {
debug!("emscripten::___syscall38 (rename)");
let old_path_addr: u32 = varargs.get(ctx);
let new_path_addr: u32 = varargs.get(ctx);
let old_path = emscripten_memory_pointer!(ctx.memory(0), old_path_addr) as *const i8;
let new_path = emscripten_memory_pointer!(ctx.memory(0), new_path_addr) as *const i8;
let result = unsafe { rename(old_path, new_path) };
debug!(
"=> old_path: {}, new_path: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(old_path).to_str().unwrap() },
unsafe { std::ffi::CStr::from_ptr(new_path).to_str().unwrap() },
result
);
result
}
// rmdir
@ -246,12 +259,21 @@ pub fn ___syscall192(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
if fd == -1 {
let ptr = env::call_memalign(ctx, 16384, len);
if ptr == 0 {
return -1;
// ENOMEM
return -12;
}
let real_ptr = emscripten_memory_pointer!(ctx.memory(0), ptr) as *const u8;
env::call_memset(ctx, ptr, 0, len);
ptr as _
for i in 0..(len as usize) {
unsafe {
assert_eq!(*real_ptr.add(i), 0);
}
}
debug!("=> ptr: {}", ptr);
return ptr as i32;
} else {
-1
// return ENODEV
return -19;
}
}
@ -461,6 +483,12 @@ pub fn ___syscall300(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
-1
}
// utimensat
pub fn ___syscall320(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int {
debug!("emscripten::___syscall320 (utimensat), {}", _which);
0
}
pub fn ___syscall334(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
debug!("emscripten::___syscall334");
-1

View File

@ -1,4 +1,6 @@
use crate::varargs::VarArgs;
#[cfg(target_os = "macos")]
use libc::size_t;
/// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32
/// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html
use libc::{
@ -53,7 +55,6 @@ use libc::{
sendto,
setpgid,
setsockopt,
size_t,
sockaddr,
socket,
socklen_t,
@ -251,8 +252,9 @@ pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
let path = emscripten_memory_pointer!(ctx.memory(0), path_ptr) as *const i8;
let result = unsafe { access(path, amode) };
debug!(
"=> path: {}, result: {}",
"=> path: {}, amode: {}, result: {}",
unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() },
amode,
result
);
result
@ -354,8 +356,13 @@ pub fn ___syscall54(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int
debug!("emscripten::___syscall54 (ioctl) {}", _which);
let fd: i32 = varargs.get(ctx);
let request: u32 = varargs.get(ctx);
debug!("fd: {}, op: {}", fd, request);
debug!("=> fd: {}, op: {}", fd, request);
// Got the equivalents here: https://code.woboq.org/linux/linux/include/uapi/asm-generic/ioctls.h.html
// let argp: u32 = varargs.get(ctx);
// let argp_ptr = emscripten_memory_pointer!(ctx.memory(0), argp) as *mut c_void;
// let ret = unsafe { ioctl(fd, request as _, argp_ptr) };
// debug!("=> {}", ret);
// ret
match request as _ {
21537 => {
// FIONBIO

View File

@ -28,7 +28,9 @@ use wasmer_runtime_core::vm::Ctx;
use libc::{CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_REALTIME};
#[cfg(target_os = "macos")]
use libc::{CLOCK_MONOTONIC, CLOCK_REALTIME};
use libc::CLOCK_REALTIME;
#[cfg(target_os = "macos")]
const CLOCK_MONOTONIC: clockid_t = 1;
#[cfg(target_os = "macos")]
const CLOCK_MONOTONIC_COARSE: clockid_t = 6;

View File

@ -1,5 +1,6 @@
use super::env;
use super::env::get_emscripten_data;
use crate::storage::align_memory;
use libc::stat;
use std::ffi::CStr;
use std::mem::size_of;
@ -39,6 +40,43 @@ pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option<Pages>) {
(memory.minimum, memory.maximum)
}
/// Reads values written by `-s EMIT_EMSCRIPTEN_METADATA=1`
/// Assumes values start from the end in this order:
/// Last export: Dynamic Base
/// Second-to-Last export: Dynamic top pointer
pub fn get_emscripten_metadata(module: &Module) -> Option<(u32, u32)> {
let max_idx = &module.info().globals.iter().map(|(k, _)| k).max()?;
let snd_max_idx = &module
.info()
.globals
.iter()
.map(|(k, _)| k)
.filter(|k| k != max_idx)
.max()?;
use wasmer_runtime_core::types::{GlobalInit, Initializer::Const, Value::I32};
if let (
GlobalInit {
init: Const(I32(dynamic_base)),
..
},
GlobalInit {
init: Const(I32(dynamictop_ptr)),
..
},
) = (
&module.info().globals[*max_idx],
&module.info().globals[*snd_max_idx],
) {
Some((
align_memory(*dynamic_base as u32 - 32),
align_memory(*dynamictop_ptr as u32 - 32),
))
} else {
None
}
}
pub unsafe fn write_to_buf(ctx: &mut Ctx, string: *const c_char, buf: u32, max: u32) -> u32 {
let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_char;

View File

@ -53,6 +53,7 @@ macro_rules! assert_emscripten_output {
&mut instance,
$name,
$args,
None,
).expect("run_emscripten_instance finishes");
let output = capturer.end().unwrap().0;

View File

@ -1,11 +1,11 @@
[package]
name = "wasmer-llvm-backend"
version = "0.3.0"
version = "0.4.1"
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm7-0" }
wasmparser = "0.29.2"
hashbrown = "0.1.8"

File diff suppressed because it is too large Load Diff

View File

@ -369,31 +369,6 @@ impl Intrinsics {
ctx_ptr_ty,
}
}
pub fn ctx<'a>(
&'a self,
info: &'a ModuleInfo,
builder: &'a Builder,
func_value: &'a FunctionValue,
cache_builder: Builder,
) -> CtxType<'a> {
CtxType {
ctx_ptr_value: func_value.get_nth_param(0).unwrap().into_pointer_value(),
builder,
intrinsics: self,
info,
cache_builder,
cached_memories: HashMap::new(),
cached_tables: HashMap::new(),
cached_sigindices: HashMap::new(),
cached_globals: HashMap::new(),
cached_imported_functions: HashMap::new(),
_phantom: PhantomData,
}
}
}
#[derive(Clone, Copy)]
@ -429,8 +404,6 @@ struct ImportedFuncCache {
pub struct CtxType<'a> {
ctx_ptr_value: PointerValue,
builder: &'a Builder,
intrinsics: &'a Intrinsics,
info: &'a ModuleInfo,
cache_builder: Builder,
@ -444,16 +417,36 @@ pub struct CtxType<'a> {
}
impl<'a> CtxType<'a> {
pub fn new(
info: &'a ModuleInfo,
func_value: &'a FunctionValue,
cache_builder: Builder,
) -> CtxType<'a> {
CtxType {
ctx_ptr_value: func_value.get_nth_param(0).unwrap().into_pointer_value(),
info,
cache_builder,
cached_memories: HashMap::new(),
cached_tables: HashMap::new(),
cached_sigindices: HashMap::new(),
cached_globals: HashMap::new(),
cached_imported_functions: HashMap::new(),
_phantom: PhantomData,
}
}
pub fn basic(&self) -> BasicValueEnum {
self.ctx_ptr_value.as_basic_value_enum()
}
pub fn memory(&mut self, index: MemoryIndex) -> MemoryCache {
let (cached_memories, info, ctx_ptr_value, intrinsics, cache_builder) = (
pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache {
let (cached_memories, info, ctx_ptr_value, cache_builder) = (
&mut self.cached_memories,
self.info,
self.ctx_ptr_value,
self.intrinsics,
&self.cache_builder,
);
@ -514,13 +507,16 @@ impl<'a> CtxType<'a> {
})
}
pub fn table(&mut self, index: TableIndex) -> (PointerValue, IntValue) {
let (cached_tables, builder, info, ctx_ptr_value, intrinsics, cache_builder) = (
pub fn table(
&mut self,
index: TableIndex,
intrinsics: &Intrinsics,
builder: &Builder,
) -> (PointerValue, IntValue) {
let (cached_tables, info, ctx_ptr_value, cache_builder) = (
&mut self.cached_tables,
self.builder,
self.info,
self.ctx_ptr_value,
self.intrinsics,
&self.cache_builder,
);
@ -575,41 +571,39 @@ impl<'a> CtxType<'a> {
)
}
pub fn local_func(&mut self, index: LocalFuncIndex, fn_ty: FunctionType) -> PointerValue {
let local_func_array_ptr_ptr = unsafe {
self.builder
.build_struct_gep(self.ctx_ptr_value, 8, "local_func_array_ptr_ptr")
};
let local_func_array_ptr = self
.builder
pub fn local_func(
&mut self,
index: LocalFuncIndex,
fn_ty: FunctionType,
intrinsics: &Intrinsics,
builder: &Builder,
) -> PointerValue {
let local_func_array_ptr_ptr =
unsafe { builder.build_struct_gep(self.ctx_ptr_value, 8, "local_func_array_ptr_ptr") };
let local_func_array_ptr = builder
.build_load(local_func_array_ptr_ptr, "local_func_array_ptr")
.into_pointer_value();
let local_func_ptr_ptr = unsafe {
self.builder.build_in_bounds_gep(
builder.build_in_bounds_gep(
local_func_array_ptr,
&[self
.intrinsics
.i32_ty
.const_int(index.index() as u64, false)],
&[intrinsics.i32_ty.const_int(index.index() as u64, false)],
"local_func_ptr_ptr",
)
};
let local_func_ptr = self
.builder
let local_func_ptr = builder
.build_load(local_func_ptr_ptr, "local_func_ptr")
.into_pointer_value();
self.builder.build_pointer_cast(
builder.build_pointer_cast(
local_func_ptr,
fn_ty.ptr_type(AddressSpace::Generic),
"local_func_ptr",
)
}
pub fn dynamic_sigindex(&mut self, index: SigIndex) -> IntValue {
let (cached_sigindices, ctx_ptr_value, intrinsics, cache_builder) = (
pub fn dynamic_sigindex(&mut self, index: SigIndex, intrinsics: &Intrinsics) -> IntValue {
let (cached_sigindices, ctx_ptr_value, cache_builder) = (
&mut self.cached_sigindices,
self.ctx_ptr_value,
self.intrinsics,
&self.cache_builder,
);
@ -636,12 +630,11 @@ impl<'a> CtxType<'a> {
})
}
pub fn global_cache(&mut self, index: GlobalIndex) -> GlobalCache {
let (cached_globals, ctx_ptr_value, info, intrinsics, cache_builder) = (
pub fn global_cache(&mut self, index: GlobalIndex, intrinsics: &Intrinsics) -> GlobalCache {
let (cached_globals, ctx_ptr_value, info, cache_builder) = (
&mut self.cached_globals,
self.ctx_ptr_value,
self.info,
self.intrinsics,
&self.cache_builder,
);
@ -712,11 +705,14 @@ impl<'a> CtxType<'a> {
})
}
pub fn imported_func(&mut self, index: ImportedFuncIndex) -> (PointerValue, PointerValue) {
let (cached_imported_functions, ctx_ptr_value, intrinsics, cache_builder) = (
pub fn imported_func(
&mut self,
index: ImportedFuncIndex,
intrinsics: &Intrinsics,
) -> (PointerValue, PointerValue) {
let (cached_imported_functions, ctx_ptr_value, cache_builder) = (
&mut self.cached_imported_functions,
self.ctx_ptr_value,
self.intrinsics,
&self.cache_builder,
);

View File

@ -1,13 +1,6 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#![cfg_attr(nightly, feature(unwind_attributes))]
use wasmer_runtime_core::{
backend::{Compiler, CompilerConfig, Token},
cache::{Artifact, Error as CacheError},
error::CompileError,
module::ModuleInner,
};
use wasmparser::{self, WasmDecoder};
mod backend;
mod code;
mod intrinsics;
@ -16,111 +9,11 @@ mod read_info;
mod state;
mod trampolines;
pub struct LLVMCompiler {
_private: (),
}
use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen;
impl LLVMCompiler {
pub fn new() -> Self {
Self { _private: () }
}
}
impl Compiler for LLVMCompiler {
fn compile(
&self,
wasm: &[u8],
compiler_config: CompilerConfig,
_: Token,
) -> Result<ModuleInner, CompileError> {
validate(wasm)?;
let (info, code_reader) = read_info::read_module(wasm, compiler_config).unwrap();
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
let (backend, cache_gen) = backend::LLVMBackend::new(module, intrinsics);
Ok(ModuleInner {
runnable_module: Box::new(backend),
cache_gen: Box::new(cache_gen),
info,
})
}
unsafe fn from_cache(&self, artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
let (info, _, memory) = artifact.consume();
let (backend, cache_gen) =
backend::LLVMBackend::from_buffer(memory).map_err(CacheError::DeserializeError)?;
Ok(ModuleInner {
runnable_module: Box::new(backend),
cache_gen: Box::new(cache_gen),
info,
})
}
}
fn validate(bytes: &[u8]) -> Result<(), CompileError> {
let mut parser = wasmparser::ValidatingParser::new(
bytes,
Some(wasmparser::ValidatingParserConfig {
operator_config: wasmparser::OperatorValidatorConfig {
enable_threads: false,
enable_reference_types: false,
enable_simd: false,
enable_bulk_memory: false,
},
mutable_global_imports: false,
}),
);
loop {
let state = parser.read();
match *state {
wasmparser::ParserState::EndWasm => break Ok(()),
wasmparser::ParserState::Error(err) => Err(CompileError::ValidationError {
msg: err.message.to_string(),
})?,
_ => {}
}
}
}
#[test]
fn test_read_module() {
use std::mem::transmute;
use wabt::wat2wasm;
use wasmer_runtime_core::{
backend::RunnableModule, structures::TypedIndex, types::LocalFuncIndex, vm,
};
// let wasm = include_bytes!("../../spectests/examples/simple/simple.wasm") as &[u8];
let wat = r#"
(module
(type $t0 (func (param i32) (result i32)))
(type $t1 (func (result i32)))
(memory 1)
(global $g0 (mut i32) (i32.const 0))
(func $foo (type $t0) (param i32) (result i32)
get_local 0
))
"#;
let wasm = wat2wasm(wat).unwrap();
let (info, code_reader) = read_info::read_module(&wasm, Default::default()).unwrap();
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
let (backend, _) = backend::LLVMBackend::new(module, intrinsics);
let func_ptr = backend.get_func(&info, LocalFuncIndex::new(0)).unwrap();
println!("func_ptr: {:p}", func_ptr.as_ptr());
unsafe {
let func: unsafe extern "C" fn(*mut vm::Ctx, i32) -> i32 = transmute(func_ptr);
let result = func(0 as _, 42);
println!("result: {}", result);
}
}
pub type LLVMCompiler = SimpleStreamingCompilerGen<
code::LLVMModuleCodeGenerator,
code::LLVMFunctionCodeGenerator,
backend::LLVMBackend,
code::CodegenError,
>;

View File

@ -34,7 +34,7 @@ pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut
}
#[cfg(not(target_os = "macos"))]
pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) {
pub unsafe fn visit_fde(addr: *mut u8, _size: usize, visitor: extern "C" fn(*mut u8)) {
visitor(addr);
}

View File

@ -1,289 +1,5 @@
use wasmer_runtime_core::{
backend::{Backend, CompilerConfig},
module::{
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
TableInitializer,
},
structures::{Map, TypedIndex},
types::{
ElementType, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit,
ImportedGlobalIndex, Initializer, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor,
TableIndex, Type, Value,
},
units::Pages,
};
use wasmparser::{
BinaryReaderError, CodeSectionReader, Data, DataKind, Element, ElementKind, Export,
ExternalKind, FuncType, Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator,
SectionCode, Type as WpType,
};
use hashbrown::HashMap;
pub fn read_module(
wasm: &[u8],
compiler_config: CompilerConfig,
) -> Result<(ModuleInfo, CodeSectionReader), BinaryReaderError> {
let mut info = ModuleInfo {
memories: Map::new(),
globals: Map::new(),
tables: Map::new(),
imported_functions: Map::new(),
imported_memories: Map::new(),
imported_tables: Map::new(),
imported_globals: Map::new(),
exports: Default::default(),
data_initializers: Vec::new(),
elem_initializers: Vec::new(),
start_func: None,
func_assoc: Map::new(),
signatures: Map::new(),
backend: Backend::LLVM,
namespace_table: StringTable::new(),
name_table: StringTable::new(),
em_symbol_map: compiler_config.symbol_map.clone(),
custom_sections: HashMap::new(),
};
let mut reader = ModuleReader::new(wasm)?;
let mut code_reader = None;
loop {
if reader.eof() {
return Ok((info, code_reader.unwrap()));
}
let section = reader.read()?;
match section.code {
SectionCode::Type => {
let type_reader = section.get_type_section_reader()?;
for ty in type_reader {
let ty = ty?;
info.signatures.push(func_type_to_func_sig(ty)?);
}
}
SectionCode::Import => {
let import_reader = section.get_import_section_reader()?;
let mut namespace_builder = StringTableBuilder::new();
let mut name_builder = StringTableBuilder::new();
for import in import_reader {
let Import { module, field, ty } = import?;
let namespace_index = namespace_builder.register(module);
let name_index = name_builder.register(field);
let import_name = ImportName {
namespace_index,
name_index,
};
match ty {
ImportSectionEntryType::Function(sigindex) => {
let sigindex = SigIndex::new(sigindex as usize);
info.imported_functions.push(import_name);
info.func_assoc.push(sigindex);
}
ImportSectionEntryType::Table(table_ty) => {
assert_eq!(table_ty.element_type, WpType::AnyFunc);
let table_desc = TableDescriptor {
element: ElementType::Anyfunc,
minimum: table_ty.limits.initial,
maximum: table_ty.limits.maximum,
};
info.imported_tables.push((import_name, table_desc));
}
ImportSectionEntryType::Memory(memory_ty) => {
let mem_desc = MemoryDescriptor {
minimum: Pages(memory_ty.limits.initial),
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
shared: memory_ty.shared,
};
info.imported_memories.push((import_name, mem_desc));
}
ImportSectionEntryType::Global(global_ty) => {
let global_desc = GlobalDescriptor {
mutable: global_ty.mutable,
ty: type_to_type(global_ty.content_type)?,
};
info.imported_globals.push((import_name, global_desc));
}
}
}
info.namespace_table = namespace_builder.finish();
info.name_table = name_builder.finish();
}
SectionCode::Function => {
let func_decl_reader = section.get_function_section_reader()?;
for sigindex in func_decl_reader {
let sigindex = sigindex?;
let sigindex = SigIndex::new(sigindex as usize);
info.func_assoc.push(sigindex);
}
}
SectionCode::Table => {
let table_decl_reader = section.get_table_section_reader()?;
for table_ty in table_decl_reader {
let table_ty = table_ty?;
let table_desc = TableDescriptor {
element: ElementType::Anyfunc,
minimum: table_ty.limits.initial,
maximum: table_ty.limits.maximum,
};
info.tables.push(table_desc);
}
}
SectionCode::Memory => {
let mem_decl_reader = section.get_memory_section_reader()?;
for memory_ty in mem_decl_reader {
let memory_ty = memory_ty?;
let mem_desc = MemoryDescriptor {
minimum: Pages(memory_ty.limits.initial),
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
shared: memory_ty.shared,
};
info.memories.push(mem_desc);
}
}
SectionCode::Global => {
let global_decl_reader = section.get_global_section_reader()?;
for global in global_decl_reader {
let global = global?;
let desc = GlobalDescriptor {
mutable: global.ty.mutable,
ty: type_to_type(global.ty.content_type)?,
};
let global_init = GlobalInit {
desc,
init: eval_init_expr(&global.init_expr)?,
};
info.globals.push(global_init);
}
}
SectionCode::Export => {
let export_reader = section.get_export_section_reader()?;
for export in export_reader {
let Export { field, kind, index } = export?;
let export_index = match kind {
ExternalKind::Function => ExportIndex::Func(FuncIndex::new(index as usize)),
ExternalKind::Table => ExportIndex::Table(TableIndex::new(index as usize)),
ExternalKind::Memory => {
ExportIndex::Memory(MemoryIndex::new(index as usize))
}
ExternalKind::Global => {
ExportIndex::Global(GlobalIndex::new(index as usize))
}
};
info.exports.insert(field.to_string(), export_index);
}
}
SectionCode::Start => {
let start_index = section.get_start_section_content()?;
info.start_func = Some(FuncIndex::new(start_index as usize));
}
SectionCode::Element => {
let element_reader = section.get_element_section_reader()?;
for element in element_reader {
let Element { kind, items } = element?;
match kind {
ElementKind::Active {
table_index,
init_expr,
} => {
let table_index = TableIndex::new(table_index as usize);
let base = eval_init_expr(&init_expr)?;
let items_reader = items.get_items_reader()?;
let elements: Vec<_> = items_reader
.into_iter()
.map(|res| res.map(|index| FuncIndex::new(index as usize)))
.collect::<Result<_, _>>()?;
let table_init = TableInitializer {
table_index,
base,
elements,
};
info.elem_initializers.push(table_init);
}
ElementKind::Passive(_ty) => {
return Err(BinaryReaderError {
message: "passive tables are not yet supported",
offset: -1isize as usize,
});
}
}
}
}
SectionCode::Code => {
code_reader = Some(section.get_code_section_reader()?);
}
SectionCode::Data => {
let data_reader = section.get_data_section_reader()?;
for data in data_reader {
let Data { kind, data } = data?;
match kind {
DataKind::Active {
memory_index,
init_expr,
} => {
let memory_index = MemoryIndex::new(memory_index as usize);
let base = eval_init_expr(&init_expr)?;
let data_init = DataInitializer {
memory_index,
base,
data: data.to_vec(),
};
info.data_initializers.push(data_init);
}
DataKind::Passive => {
return Err(BinaryReaderError {
message: "passive memories are not yet supported",
offset: -1isize as usize,
});
}
}
}
}
SectionCode::DataCount => {}
SectionCode::Custom { .. } => {}
}
}
}
use wasmer_runtime_core::types::Type;
use wasmparser::{BinaryReaderError, Type as WpType};
pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
Ok(match ty {
@ -305,46 +21,3 @@ pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
}
})
}
fn func_type_to_func_sig(func_ty: FuncType) -> Result<FuncSig, BinaryReaderError> {
assert_eq!(func_ty.form, WpType::Func);
Ok(FuncSig::new(
func_ty
.params
.iter()
.cloned()
.map(type_to_type)
.collect::<Result<Vec<_>, _>>()?,
func_ty
.returns
.iter()
.cloned()
.map(type_to_type)
.collect::<Result<Vec<_>, _>>()?,
))
}
fn eval_init_expr(expr: &InitExpr) -> Result<Initializer, BinaryReaderError> {
let mut reader = expr.get_operators_reader();
let (op, offset) = reader.read_with_offset()?;
Ok(match op {
Operator::GetGlobal { global_index } => {
Initializer::GetGlobal(ImportedGlobalIndex::new(global_index as usize))
}
Operator::I32Const { value } => Initializer::Const(Value::I32(value)),
Operator::I64Const { value } => Initializer::Const(Value::I64(value)),
Operator::F32Const { value } => {
Initializer::Const(Value::F32(f32::from_bits(value.bits())))
}
Operator::F64Const { value } => {
Initializer::Const(Value::F64(f64::from_bits(value.bits())))
}
_ => {
return Err(BinaryReaderError {
message: "init expr evaluation failed: unsupported opcode",
offset,
});
}
})
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-middleware-common"
version = "0.3.0"
version = "0.4.1"
repository = "https://github.com/wasmerio/wasmer"
description = "Wasmer runtime common middlewares"
license = "MIT"
@ -8,4 +8,4 @@ authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }

View File

@ -10,7 +10,7 @@ impl FunctionMiddleware for CallTrace {
fn feed_event<'a, 'b: 'a>(
&mut self,
op: Event<'a, 'b>,
module_info: &ModuleInfo,
_module_info: &ModuleInfo,
sink: &mut EventSink<'a, 'b>,
) -> Result<(), Self::Error> {
match op {

View File

@ -1 +1,3 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
pub mod call_trace;

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-abi"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer runtime core library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#[cfg(not(target_os = "windows"))]
#[macro_use]
extern crate failure;

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-c-api"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer C API library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -16,11 +16,11 @@ libc = "0.2"
[dependencies.wasmer-runtime]
path = "../runtime"
version = "0.3.0"
version = "0.4.1"
[dependencies.wasmer-runtime-core]
path = "../runtime-core"
version = "0.3.0"
version = "0.4.1"
[features]
debug = ["wasmer-runtime/debug"]

View File

@ -1,4 +1,4 @@
//! Errors.
//! Read runtime errors.
use libc::{c_char, c_int};
use std::cell::RefCell;
@ -61,20 +61,20 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length:
return -1;
}
let last_error = match take_last_error() {
Some(err) => err,
let error_message = match take_last_error() {
Some(err) => err.to_string(),
None => return 0,
};
let error_message = last_error.to_string();
let length = length as usize;
let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length as usize);
if error_message.len() >= buffer.len() {
// buffer to small for err message
if error_message.len() >= length {
// buffer is too small to hold the error message
return -1;
}
let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length);
ptr::copy_nonoverlapping(
error_message.as_ptr(),
buffer.as_mut_ptr(),
@ -85,7 +85,7 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length:
// accidentally read into garbage.
buffer[error_message.len()] = 0;
error_message.len() as c_int
error_message.len() as c_int + 1
}
#[derive(Debug)]

View File

@ -1,4 +1,5 @@
//! Wasm exports.
//! Create, read, destroy export definitions (function, global, memory
//! and table) on an instance.
use crate::{
error::{update_last_error, CApiError},

View File

@ -1,4 +1,4 @@
//! Wasm global.
//! Create, set, get and destroy global variables of an instance.
use crate::value::{wasmer_value_t, wasmer_value_tag};
use wasmer_runtime::Global;

View File

@ -1,4 +1,5 @@
//! Wasm imports.
//! Create, read, destroy import definitions (function, global, memory
//! and table) on an instance.
use crate::{
error::{update_last_error, CApiError},

View File

@ -1,4 +1,4 @@
//! Wasm instance.
//! Instantiate a module, call functions, and read exports.
use crate::{
error::{update_last_error, CApiError},

View File

@ -1,3 +1,87 @@
//! # Wasmer Runtime C API
//!
//! Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
//! compatible with Emscripten, Rust and Go. [Learn
//! more](https://github.com/wasmerio/wasmer).
//!
//! This crate exposes a C and C++ API for the Wasmer runtime.
//!
//! # Usage
//!
//! The C and C++ header files can be found in the source tree of this
//! crate, respectively [`wasmer.h`][wasmer_h] and
//! [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always
//! up-to-date in this repository.
//!
//! Here is a simple example to use the C API:
//!
//! ```c
//! #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);
//!
//! // Prepare the imports.
//! wasmer_import_t imports[] = {};
//!
//! // Instantiate!
//! wasmer_instance_t *instance = NULL;
//! wasmer_result_t instantiation_result = wasmer_instantiate(&instance, bytes, len, imports, 0);
//!
//! assert(instantiation_result == WASMER_OK);
//!
//! // Let's call a function.
//! // Start by preparing the arguments.
//!
//! // Value of argument #1 is `7i32`.
//! wasmer_value_t argument_one;
//! argument_one.tag = WASM_I32;
//! argument_one.value.I32 = 7;
//!
//! // Value of argument #2 is `8i32`.
//! wasmer_value_t argument_two;
//! argument_two.tag = WASM_I32;
//! argument_two.value.I32 = 8;
//!
//! // Prepare the arguments.
//! wasmer_value_t arguments[] = {argument_one, argument_two};
//!
//! // Prepare the return value.
//! wasmer_value_t result_one;
//! wasmer_value_t results[] = {result_one};
//!
//! // Call the `sum` function with the prepared arguments and the return value.
//! wasmer_result_t call_result = wasmer_instance_call(instance, "sum", arguments, 2, results, 1);
//!
//! // Let's display the result.
//! printf("Call result: %d\n", call_result);
//! printf("Result: %d\n", results[0].value.I32);
//!
//! // `sum(7, 8) == 15`.
//! assert(results[0].value.I32 == 15);
//! assert(call_result == WASMER_OK);
//!
//! wasmer_instance_destroy(instance);
//!
//! return 0;
//! }
//! ```
//!
//! [wasmer_h]: ./wasmer.h
//! [wasmer_hh]: ./wasmer.hh
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
extern crate wasmer_runtime;
extern crate wasmer_runtime_core;

View File

@ -1,4 +1,4 @@
//! Wasm memory.o
//! Create, read, write, grow, destroy memory of an instance.
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
use libc::{uint32_t, uint8_t};

View File

@ -1,4 +1,4 @@
//! Wasm module.
//! Compile, validate, instantiate, serialize, and destroy modules.
use crate::{
error::{update_last_error, CApiError},

View File

@ -1,4 +1,4 @@
//! Wasm tables.
//! Create, grow, destroy tables of an instance.
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
use libc::uint32_t;

View File

@ -1,4 +1,4 @@
//! Wasm values.
//! Create and map Rust to WebAssembly values.
use libc::{int32_t, int64_t};
use wasmer_runtime::Value;

View File

@ -46,7 +46,8 @@ int main()
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);
int error_result = wasmer_last_error_message(error_str, error_len);
assert(error_len == error_result);
printf("Error str: `%s`\n", error_str);
assert(0 == strcmp(error_str, "Call error: Parameters of type [I32] did not match signature [I32, I32] -> [I32]"));
free(error_str);

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-core"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer runtime core library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]

View File

@ -17,30 +17,31 @@ use crate::{
};
use std::slice;
/// The `LocalBacking` "owns" the memory used by all the local resources of an Instance.
/// That is, local memories, tables, and globals (as well as some additional
/// data for the virtual call machinery).
#[derive(Debug)]
pub struct LocalBacking {
/// This is a map from the local resource index to actual memory,
/// table, and globals.
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
/// This own the memory containing the pointers to the local memories.
/// While simplifying implementation, this adds indirection and may hurt
/// performance, especially on cache-starved systems.
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
/// The dynamic sigindices are used to efficiently support caching and
/// the `call_indirect` wasm instruction. This field (and local_functions
/// as well) are subject to change.
pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,
}
// impl LocalBacking {
// pub fn memory(&mut self, local_memory_index: LocalMemoryIndex) -> &mut Memory {
// &mut self.memories[local_memory_index]
// }
// pub fn table(&mut self, local_table_index: LocalTableIndex) -> &mut TableBacking {
// &mut self.tables[local_table_index]
// }
// }
impl LocalBacking {
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
let mut memories = Self::generate_memories(module);
@ -102,6 +103,9 @@ impl LocalBacking {
memories.into_boxed_map()
}
/// Initialize each locally-defined memory in the Module.
///
/// This involves copying in the data initializers.
fn finalize_memories(
module: &ModuleInner,
imports: &ImportBacking,
@ -174,6 +178,9 @@ impl LocalBacking {
tables.into_boxed_map()
}
/// This initializes all of the locally-defined tables in the Module, e.g.
/// putting all the table elements (function pointers)
/// in the right places.
#[allow(clippy::cast_ptr_alignment)]
fn finalize_tables(
module: &ModuleInner,

View File

@ -1,18 +1,19 @@
use crate::{
backend::RunnableModule,
backend::{sys::Memory, Backend, CacheGen, Compiler, CompilerConfig, Token},
backend::{Backend, CacheGen, Compiler, CompilerConfig, Token},
cache::{Artifact, Error as CacheError},
error::{CompileError, CompileResult},
module::{ModuleInfo, ModuleInner},
parse::LoadError,
structures::Map,
types::{FuncIndex, FuncSig, SigIndex},
};
use smallvec::SmallVec;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use wasmparser::{Operator, Type as WpType};
#[derive(Debug)]
pub enum Event<'a, 'b> {
Internal(InternalEvent),
Wasm(&'b Operator<'a>),
@ -26,6 +27,18 @@ pub enum InternalEvent {
GetInternal(u32),
}
impl fmt::Debug for InternalEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InternalEvent::FunctionBegin(_) => write!(f, "FunctionBegin"),
InternalEvent::FunctionEnd => write!(f, "FunctionEnd"),
InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"),
InternalEvent::SetInternal(_) => write!(f, "SetInternal"),
InternalEvent::GetInternal(_) => write!(f, "GetInternal"),
}
}
}
pub struct BkptInfo {}
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
@ -35,7 +48,7 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
/// Creates a new function and returns the function-scope code generator for it.
fn next_function(&mut self) -> Result<&mut FCG, E>;
fn finalize(self, module_info: &ModuleInfo) -> Result<RM, E>;
fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box<dyn CacheGen>), E>;
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
/// Sets function signatures.
@ -44,7 +57,8 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
/// Adds an import function.
fn feed_import_function(&mut self) -> Result<(), E>;
fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), E> { Ok(()) }
fn feed_compiler_config(&mut self, _config: &CompilerConfig) -> Result<(), E> { Ok(()) }
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
}
pub struct StreamingCompiler<
@ -118,15 +132,6 @@ impl<
compiler_config: CompilerConfig,
_: Token,
) -> CompileResult<ModuleInner> {
struct Placeholder;
impl CacheGen for Placeholder {
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
Err(CacheError::Unknown(
"the streaming compiler API doesn't support caching yet".to_string(),
))
}
}
let mut mcg = MCG::new();
let mut chain = (self.middleware_chain_generator)();
let info = crate::parse::read_module(
@ -136,22 +141,24 @@ impl<
&mut chain,
&compiler_config,
)?;
let exec_context = mcg
.finalize(&info)
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
let (exec_context, cache_gen) =
mcg.finalize(&info)
.map_err(|x| CompileError::InternalError {
msg: format!("{:?}", x),
})?;
Ok(ModuleInner {
cache_gen: Box::new(Placeholder),
cache_gen,
runnable_module: Box::new(exec_context),
info: info,
info,
})
}
unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
Err(CacheError::Unknown(
"the streaming compiler API doesn't support caching yet".to_string(),
))
unsafe fn from_cache(
&self,
artifact: Artifact,
token: Token,
) -> Result<ModuleInner, CacheError> {
MCG::from_cache(artifact, token)
}
}
@ -248,7 +255,7 @@ pub trait FunctionCodeGenerator<E: Debug> {
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), E>;
/// Called before the first call to `feed_opcode`.
fn begin_body(&mut self) -> Result<(), E>;
fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
/// Called for each operator.
fn feed_event(&mut self, op: Event, module_info: &ModuleInfo) -> Result<(), E>;

View File

@ -11,7 +11,7 @@ pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
pub type ParseResult<T> = std::result::Result<T, ParseError>;
/// This is returned when the chosen compiler is unable to
/// successfully compile the provided webassembly module into
/// successfully compile the provided WebAssembly module into
/// a `Module`.
///
/// Comparing two `CompileError`s always evaluates to false.
@ -114,7 +114,7 @@ impl std::fmt::Display for LinkError {
impl std::error::Error for LinkError {}
/// This is the error type returned when calling
/// a webassembly function.
/// a WebAssembly function.
///
/// The main way to do this is `Instance.call`.
///
@ -270,7 +270,7 @@ impl std::error::Error for CreationError {}
/// The amalgamation of all errors that can occur
/// during the compilation, instantiation, or execution
/// of a webassembly module.
/// of a WebAssembly module.
///
/// Comparing two `Error`s always evaluates to false.
#[derive(Debug)]

View File

@ -12,7 +12,7 @@ use crate::{
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
vm,
loader::{self, Loader, Instance as _},
loader::Loader,
structures::TypedIndex,
};
use smallvec::{smallvec, SmallVec};
@ -288,7 +288,7 @@ impl Instance {
}
}
/// Call an exported webassembly function given the export name.
/// Call an exported WebAssembly function given the export name.
/// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a [`Value`].
///
@ -296,7 +296,7 @@ impl Instance {
///
/// # Note:
/// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature.
/// the future multi-value returns WebAssembly feature.
///
/// # Usage:
/// ```
@ -627,7 +627,7 @@ pub struct DynFunc<'a> {
}
impl<'a> DynFunc<'a> {
/// Call an exported webassembly function safely.
/// Call an exported WebAssembly function safely.
///
/// Pass arguments by wrapping each one in the [`Value`] enum.
/// The returned values are also each wrapped in a [`Value`].
@ -636,7 +636,7 @@ impl<'a> DynFunc<'a> {
///
/// # Note:
/// This returns `CallResult<Vec<Value>>` in order to support
/// the future multi-value returns webassembly feature.
/// the future multi-value returns WebAssembly feature.
///
/// # Usage:
/// ```

View File

@ -1,3 +1,4 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#![cfg_attr(nightly, feature(unwind_attributes))]
#[cfg(test)]

View File

@ -9,7 +9,7 @@ use crate::{
types::Value,
};
use libc::{
c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ,
mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ,
PROT_WRITE,
};
@ -23,11 +23,11 @@ pub trait Loader {
pub trait Instance {
type Error: Debug;
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, Self::Error>;
fn read_memory(&mut self, offset: u32, len: u32) -> Result<Vec<u8>, Self::Error> {
fn read_memory(&mut self, _offset: u32, _len: u32) -> Result<Vec<u8>, Self::Error> {
unimplemented!()
}
fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> Result<(), Self::Error> {
fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> {
unimplemented!()
}
}
@ -38,7 +38,7 @@ impl Loader for LocalLoader {
type Instance = LocalInstance;
type Error = String;
fn load(&self, rm: &dyn RunnableModule, module: &ModuleInfo, ctx: &Ctx) -> Result<Self::Instance, Self::Error> {
fn load(&self, rm: &dyn RunnableModule, _module: &ModuleInfo, _ctx: &Ctx) -> Result<Self::Instance, Self::Error> {
let code = rm.get_code().unwrap();
let mut code_mem = CodeMemory::new(code.len());
code_mem[..code.len()].copy_from_slice(code);

View File

@ -11,7 +11,7 @@ use crate::{
/// This is an internal-only api.
///
/// A static memory allocates 6GB of *virtual* memory when created
/// in order to allow the webassembly module to contain no bounds-checks.
/// in order to allow the WebAssembly module to contain no bounds-checks.
///
/// Additionally, static memories stay at a single virtual address, so there is no need
/// to reload its address on each use.

View File

@ -246,7 +246,7 @@ pub fn read_module<
ParserState::CodeOperator(ref op) => {
if !body_begun {
body_begun = true;
fcg.begin_body()
fcg.begin_body(&info)
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
}
middlewares

View File

@ -23,10 +23,18 @@ struct GlobalSigRegistry {
sig_assoc: Map<SigIndex, Arc<FuncSig>>,
}
/// The `SigRegistry` represents a process-global map of function signatures
/// to signature indexes and vice versa (the map goes both ways).
///
/// This exists for two reasons:
/// 1. The `call_indirect` wasm instruction can compare two signature indices
/// to do signature validation very quickly.
/// 2. To intern function signatures, which may be expensive to create.
#[derive(Debug)]
pub struct SigRegistry;
impl SigRegistry {
/// Map a `FuncSig` to a global `SigIndex`.
pub fn lookup_sig_index<Sig>(&self, func_sig: Sig) -> SigIndex
where
Sig: Into<Arc<FuncSig>>,
@ -45,11 +53,15 @@ impl SigRegistry {
sig_index
}
/// Map a global `SigIndex` to an interned `FuncSig`.
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
let global = (*GLOBAL_SIG_REGISTRY).read();
Arc::clone(&global.sig_assoc[sig_index])
}
/// Register a function signature with the global signature registry.
///
/// This will return an interned `FuncSig`.
pub fn lookup_signature_ref(&self, func_sig: &FuncSig) -> Arc<FuncSig> {
let mut global = (*GLOBAL_SIG_REGISTRY).write();
let global = &mut *global;

View File

@ -33,7 +33,13 @@ impl Memory {
let protect = protection.to_protect_const();
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, MEM_RESERVE, protect) };
let flags = if protection == Protect::None {
MEM_RESERVE
} else {
MEM_RESERVE | MEM_COMMIT
};
let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size, flags, protect) };
if ptr.is_null() {
Err("unable to allocate memory".to_string())
@ -229,3 +235,25 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
fn round_down_to_page_size(size: usize, page_size: usize) -> usize {
size & !(page_size - 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clone() {
// these should work
let _ = Memory::with_size_protect(200_000, Protect::Read)
.unwrap()
.clone();
let _ = Memory::with_size_protect(200_000, Protect::ReadWrite)
.unwrap()
.clone();
let _ = Memory::with_size_protect(200_000, Protect::ReadExec)
.unwrap()
.clone();
// this would cause segmentation fault as uncommited memory with no access
//let _ = Memory::with_size_protect(200_000, Protect::None).unwrap().clone();
}
}

View File

@ -247,7 +247,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
type CStruct = S1<A>;
type RetArray = [u64; 1];
fn from_ret_array(array: Self::RetArray) -> Self {
(WasmExternType::from_native(NativeWasmType::from_bits(
(WasmExternType::from_native(NativeWasmType::from_binary(
array[0],
)),)
}
@ -274,7 +274,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
ctx: *mut Ctx,
) -> Result<Rets, RuntimeError> {
let (a,) = self;
let args = [a.to_native().to_bits()];
let args = [a.to_native().to_binary()];
let mut rets = Rets::empty_ret_array();
let mut trap = WasmTrapInfo::Unknown;
let mut user_error = None;
@ -322,7 +322,7 @@ macro_rules! impl_traits {
fn from_ret_array(array: Self::RetArray) -> Self {
#[allow(non_snake_case)]
let [ $( $x ),* ] = array;
( $( WasmExternType::from_native(NativeWasmType::from_bits($x)) ),* )
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
}
fn empty_ret_array() -> Self::RetArray {
[0; count_idents!( $( $x ),* )]
@ -344,7 +344,7 @@ macro_rules! impl_traits {
unsafe fn call<Rets: WasmTypeList>(self, f: NonNull<vm::Func>, wasm: Wasm, ctx: *mut Ctx) -> Result<Rets, RuntimeError> {
#[allow(unused_parens)]
let ( $( $x ),* ) = self;
let args = [ $( $x.to_native().to_bits() ),* ];
let args = [ $( $x.to_native().to_binary()),* ];
let mut rets = Rets::empty_ret_array();
let mut trap = WasmTrapInfo::Unknown;
let mut user_error = None;

View File

@ -85,44 +85,44 @@ where
Self: Sized,
{
const TYPE: Type;
fn from_bits(bits: u64) -> Self;
fn to_bits(self) -> u64;
fn from_binary(bits: u64) -> Self;
fn to_binary(self) -> u64;
}
unsafe impl NativeWasmType for i32 {
const TYPE: Type = Type::I32;
fn from_bits(bits: u64) -> Self {
fn from_binary(bits: u64) -> Self {
bits as _
}
fn to_bits(self) -> u64 {
fn to_binary(self) -> u64 {
self as _
}
}
unsafe impl NativeWasmType for i64 {
const TYPE: Type = Type::I64;
fn from_bits(bits: u64) -> Self {
fn from_binary(bits: u64) -> Self {
bits as _
}
fn to_bits(self) -> u64 {
fn to_binary(self) -> u64 {
self as _
}
}
unsafe impl NativeWasmType for f32 {
const TYPE: Type = Type::F32;
fn from_bits(bits: u64) -> Self {
bits as _
fn from_binary(bits: u64) -> Self {
f32::from_bits(bits as u32)
}
fn to_bits(self) -> u64 {
self as _
fn to_binary(self) -> u64 {
self.to_bits() as _
}
}
unsafe impl NativeWasmType for f64 {
const TYPE: Type = Type::F64;
fn from_bits(bits: u64) -> Self {
bits as _
fn from_binary(bits: u64) -> Self {
f64::from_bits(bits)
}
fn to_bits(self) -> u64 {
self as _
fn to_binary(self) -> u64 {
self.to_bits()
}
}
@ -410,7 +410,7 @@ pub trait LocalImport {
macro_rules! define_map_index {
($ty:ident) => {
#[derive(Serialize, Deserialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $ty (u32);
impl TypedIndex for $ty {
#[doc(hidden)]
@ -525,3 +525,58 @@ where
}
}
}
#[cfg(test)]
mod tests {
use crate::types::NativeWasmType;
use crate::types::WasmExternType;
#[test]
fn test_native_types_round_trip() {
assert_eq!(
42i32,
i32::from_native(i32::from_binary((42i32).to_native().to_binary()))
);
assert_eq!(
-42i32,
i32::from_native(i32::from_binary((-42i32).to_native().to_binary()))
);
use std::i64;
let xi64 = i64::MAX;
assert_eq!(
xi64,
i64::from_native(i64::from_binary((xi64).to_native().to_binary()))
);
let yi64 = i64::MIN;
assert_eq!(
yi64,
i64::from_native(i64::from_binary((yi64).to_native().to_binary()))
);
assert_eq!(
16.5f32,
f32::from_native(f32::from_binary((16.5f32).to_native().to_binary()))
);
assert_eq!(
-16.5f32,
f32::from_native(f32::from_binary((-16.5f32).to_native().to_binary()))
);
use std::f64;
let xf64: f64 = f64::MAX;
assert_eq!(
xf64,
f64::from_native(f64::from_binary((xf64).to_native().to_binary()))
);
let yf64: f64 = f64::MIN;
assert_eq!(
yf64,
f64::from_native(f64::from_binary((yf64).to_native().to_binary()))
);
}
}

View File

@ -3,8 +3,7 @@ use crate::{
memory::{Memory, MemoryType},
module::{ModuleInfo, ModuleInner},
structures::TypedIndex,
types::{LocalOrImport, MemoryIndex, LocalMemoryIndex},
units::{Pages},
types::{LocalOrImport, MemoryIndex},
vmcalls,
};
use std::{ffi::c_void, mem, ptr};
@ -13,7 +12,16 @@ use hashbrown::HashMap;
/// The context of the currently running WebAssembly instance.
///
/// This is implicitly passed to every WebAssembly function.
/// Since this is per-instance, each field has a statically
/// (as in after compiling the wasm) known size, so no
/// runtime checks are necessary.
///
/// While the runtime currently just passes this around
/// as the first, implicit parameter of every function,
/// it may someday be pinned to a register (especially
/// on arm, which has a ton of registers) to reduce
/// register shuffling.
#[derive(Debug)]
#[repr(C)]
pub struct Ctx {
@ -22,11 +30,25 @@ pub struct Ctx {
pub(crate) local_functions: *const *const Func,
/// These are pointers to things that are known to be owned
/// by the owning `Instance`.
local_backing: *mut LocalBacking,
import_backing: *mut ImportBacking,
pub module: *const ModuleInner,
//// This is intended to be user-supplied, per-instance
/// contextual data. There are currently some issue with it,
/// notably that it cannot be set before running the `start`
/// function in a WebAssembly module.
///
/// [#219](https://github.com/wasmerio/wasmer/pull/219) fixes that
/// issue, as well as allowing the user to have *per-function*
/// context, instead of just per-instance.
pub data: *mut c_void,
/// If there's a function set in this field, it gets called
/// when the context is destructed, e.g. when an `Instance`
/// is dropped.
pub data_finalizer: Option<fn(data: *mut c_void)>,
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer runtime library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,17 +9,17 @@ edition = "2018"
readme = "README.md"
[dependencies]
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.3.0", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.1", optional = true }
lazy_static = "1.2.0"
memmap = "0.7.0"
[dependencies.wasmer-runtime-core]
path = "../runtime-core"
version = "0.3.0"
version = "0.4.1"
[dependencies.wasmer-clif-backend]
path = "../clif-backend"
version = "0.3.0"
version = "0.4.1"
optional = true
[dev-dependencies]

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
//! Wasmer-runtime is a library that makes embedding WebAssembly
//! in your application easy, efficient, and safe.
//!

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-singlepass-backend"
version = "0.3.0"
version = "0.4.1"
repository = "https://github.com/wasmerio/wasmer"
description = "Wasmer runtime single pass compiler backend"
license = "MIT"
@ -8,7 +8,7 @@ authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
wasmparser = "0.29.2"
dynasm = "0.3.2"
dynasmrt = "0.3.1"

View File

@ -10,18 +10,18 @@ use smallvec::SmallVec;
use std::ptr::NonNull;
use std::{any::Any, collections::HashMap, sync::Arc};
use wasmer_runtime_core::{
backend::{Backend, RunnableModule, CompilerConfig, MemoryBoundCheckMode},
backend::{sys::Memory, Backend, CacheGen, Token, RunnableModule, CompilerConfig, MemoryBoundCheckMode},
cache::{Artifact, Error as CacheError},
codegen::*,
memory::MemoryType,
module::ModuleInfo,
module::{ModuleInfo, ModuleInner},
structures::{Map, TypedIndex},
typed_func::Wasm,
types::{
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
TableIndex, Type,
},
vm::{self, LocalGlobal, LocalMemory, LocalTable},
vmcalls,
vm::{self, LocalGlobal, LocalTable},
};
use wasmparser::{Operator, Type as WpType};
@ -214,10 +214,10 @@ impl RunnableModule for X64ExecutionContext {
user_error: *mut Option<Box<dyn Any>>,
num_params_plus_one: Option<NonNull<c_void>>,
) -> bool {
let rm: &Box<dyn RunnableModule> = &unsafe { &*(*ctx).module }.runnable_module;
let execution_context = unsafe {
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm)
};
let rm: &Box<dyn RunnableModule> = &(&*(*ctx).module).runnable_module;
let execution_context =
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm);
let args = ::std::slice::from_raw_parts(
args,
num_params_plus_one.unwrap().as_ptr() as usize - 1,
@ -365,7 +365,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
Ok(self.functions.last_mut().unwrap())
}
fn finalize(mut self, _: &ModuleInfo) -> Result<X64ExecutionContext, CodegenError> {
fn finalize(mut self, _: &ModuleInfo) -> Result<(X64ExecutionContext, Box<dyn CacheGen>), CodegenError> {
let (assembler, breakpoints) = match self.functions.last_mut() {
Some(x) => (
x.assembler.take().unwrap(),
@ -415,15 +415,26 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
.collect(),
);
Ok(X64ExecutionContext {
code: output,
functions: self.functions,
signatures: self.signatures.as_ref().unwrap().clone(),
breakpoints: breakpoints,
func_import_count: self.func_import_count,
function_pointers: out_labels,
function_offsets: out_offsets,
})
struct Placeholder;
impl CacheGen for Placeholder {
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
Err(CacheError::Unknown(
"the singlepass backend doesn't support caching yet".to_string(),
))
}
}
Ok((
X64ExecutionContext {
code: output,
functions: self.functions,
signatures: self.signatures.as_ref().unwrap().clone(),
breakpoints: breakpoints,
func_import_count: self.func_import_count,
function_pointers: out_labels,
function_offsets: out_offsets,
},
Box::new(Placeholder),
))
}
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), CodegenError> {
@ -480,6 +491,11 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
}));
Ok(())
}
unsafe fn from_cache(_artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
Err(CacheError::Unknown(
"the singlepass compiler API doesn't support caching yet".to_string(),
))
}
}
impl X64FunctionCode {
@ -1400,7 +1416,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
Ok(())
}
fn begin_body(&mut self) -> Result<(), CodegenError> {
fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
let a = self.assembler.as_mut().unwrap();
a.emit_push(Size::S64, Location::GPR(GPR::RBP));
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP));
@ -4062,7 +4078,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
let (targets, default_target) = table.read_table().unwrap();
let cond =
get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
let mut table_label = a.get_label();
let table_label = a.get_label();
let mut table: Vec<DynamicLabel> = vec![];
let default_br = a.get_label();
Self::emit_relaxed_binop(
@ -4084,7 +4100,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
a.emit_add(Size::S64, Location::GPR(GPR::RCX), Location::GPR(GPR::RDX));
a.emit_jmp_location(Location::GPR(GPR::RDX));
for (i, target) in targets.iter().enumerate() {
for target in targets.iter() {
let label = a.get_label();
a.emit_label(label);
table.push(label);

View File

@ -1,3 +1,4 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#![feature(proc_macro_hygiene)]
#[cfg(not(any(

View File

@ -1,5 +1,5 @@
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
//! accesses that occur when runniing webassembly.
//! accesses that occur when runniing WebAssembly.
//!
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
//!
@ -111,7 +111,7 @@ pub fn call_protected<T>(f: impl FnOnce() -> T) -> Result<T, CallProtError> {
// Ok(SIGSEGV) => "segmentation violation",
// Ok(SIGBUS) => "bus error",
// Err(_) => "error while getting the Signal",
// _ => "unkown trapped signal",
// _ => "unknown trapped signal",
// };
// // When the trap-handler is fully implemented, this will return more information.
// Err(RuntimeError::Trap {

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-wasi"
version = "0.3.0"
version = "0.4.1"
description = "Wasmer runtime WASI implementation library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.3.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
libc = "0.2.50"
rand = "0.6.5"
# wasmer-runtime-abi = { path = "../runtime-abi" }

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#[macro_use]
extern crate log;

View File

@ -279,7 +279,7 @@ pub fn fd_allocate(
len: __wasi_filesize_t,
) -> __wasi_errno_t {
debug!("wasi::fd_allocate");
unimplemented!()
unimplemented!("wasi::fd_allocate")
}
/// ### `fd_close()`
@ -434,7 +434,7 @@ pub fn fd_filestat_set_size(
st_size: __wasi_filesize_t,
) -> __wasi_errno_t {
debug!("wasi::fd_filestat_set_size");
unimplemented!()
unimplemented!("wasi::fd_filestat_set_size")
}
/// ### `fd_filestat_set_times()`
@ -474,14 +474,14 @@ pub fn fd_filestat_set_times(
inode.stat.st_atim = st_atim;
} else if fst_flags & __WASI_FILESTAT_SET_ATIM_NOW != 0 {
// set to current real time
unimplemented!();
unimplemented!("Set filestat time to the current real time");
}
if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 {
inode.stat.st_mtim = st_mtim;
} else if fst_flags & __WASI_FILESTAT_SET_MTIM_NOW != 0 {
// set to current real time
unimplemented!();
unimplemented!("Set filestat time to the current real time");
}
__WASI_ESUCCESS
@ -501,7 +501,7 @@ pub fn fd_pread(
let iov_cells = wasi_try!(iovs.deref(memory, 0, iovs_len));
let nread_cell = wasi_try!(nread.deref(memory));
unimplemented!();
unimplemented!("wasi::fd_pread");
__WASI_ESUCCESS
}
@ -637,7 +637,7 @@ pub fn fd_pwrite(
// TODO: verify
return __WASI_EISDIR;
}
Kind::Symlink { .. } => unimplemented!(),
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pwrite"),
Kind::Buffer { buffer } => wasi_try!(write_bytes(
&mut buffer[(offset as usize)..],
memory,
@ -725,7 +725,7 @@ pub fn fd_read(
// TODO: verify
return __WASI_EISDIR;
}
Kind::Symlink { .. } => unimplemented!(),
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"),
Kind::Buffer { buffer } => {
wasi_try!(read_bytes(&buffer[offset..], memory, iovs_arr_cell))
}
@ -771,7 +771,7 @@ pub fn fd_readdir(
if let (Ok(buf_arr_cell), Ok(bufused_cell)) =
(buf.deref(memory, 0, buf_len), bufused.deref(memory))
{
unimplemented!()
unimplemented!("wasi::fd_readdir")
} else {
__WASI_EFAULT
}
@ -833,7 +833,7 @@ pub fn fd_seek(
// TODO: handle case if fd is a dir?
match whence {
__WASI_WHENCE_CUR => fd_entry.offset = (fd_entry.offset as i64 + offset) as u64,
__WASI_WHENCE_END => unimplemented!(),
__WASI_WHENCE_END => unimplemented!("__WASI__WHENCE_END in wasi::fd_seek"),
__WASI_WHENCE_SET => fd_entry.offset = offset as u64,
_ => return __WASI_EINVAL,
}
@ -855,7 +855,7 @@ pub fn fd_seek(
pub fn fd_sync(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t {
debug!("wasi::fd_sync");
// TODO: check __WASI_RIGHT_FD_SYNC
unimplemented!()
unimplemented!("wasi::fd_sync")
}
/// ### `fd_tell()`
@ -950,7 +950,7 @@ pub fn fd_write(
// TODO: verify
return __WASI_EISDIR;
}
Kind::Symlink { .. } => unimplemented!(),
Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"),
Kind::Buffer { buffer } => {
wasi_try!(write_bytes(&mut buffer[offset..], memory, iovs_arr_cell))
}
@ -987,8 +987,62 @@ pub fn path_create_directory(
path_len: u32,
) -> __wasi_errno_t {
debug!("wasi::path_create_directory");
// check __WASI_RIGHT_PATH_CREATE_DIRECTORY
unimplemented!()
let memory = ctx.memory(0);
let state = get_wasi_state(ctx);
let working_dir = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF));
if !has_rights(working_dir.rights, __WASI_RIGHT_PATH_CREATE_DIRECTORY) {
return __WASI_EACCES;
}
let path_cells = wasi_try!(path.deref(memory, 0, path_len));
let path_string =
wasi_try!(
std::str::from_utf8(unsafe { &*(path_cells as *const [_] as *const [u8]) })
.map_err(|_| __WASI_EINVAL)
);
debug!("=> path: {}", &path_string);
let path = std::path::PathBuf::from(path_string);
let path_vec = wasi_try!(path
.components()
.map(|comp| {
comp.as_os_str()
.to_str()
.map(|inner_str| inner_str.to_string())
.ok_or(__WASI_EINVAL)
})
.collect::<Result<Vec<String>, __wasi_errno_t>>());
if path_vec.is_empty() {
return __WASI_EINVAL;
}
assert!(
path_vec.len() == 1,
"path_create_directory for paths greater than depth 1 has not been implemented because our WASI FS abstractions are a work in progress. We apologize for the inconvenience"
);
debug!("Path vec: {:#?}", path_vec);
wasi_try!(std::fs::create_dir(&path).map_err(|_| __WASI_EIO));
let kind = Kind::Dir {
//parent: Some(working_dir.inode),
path: path.clone(),
entries: Default::default(),
};
let new_inode = state.fs.inodes.insert(InodeVal {
stat: __wasi_filestat_t::default(),
is_preopened: false,
name: path_vec[0].clone(),
kind,
});
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
entries.insert(path_vec[0].clone(), new_inode);
} else {
return __WASI_ENOTDIR;
}
__WASI_ESUCCESS
}
/// ### `path_filestat_get()`
@ -1023,32 +1077,71 @@ pub fn path_filestat_get(
return __WASI_EACCES;
}
let path_vec = wasi_try!(::std::str::from_utf8(unsafe {
let path_string = wasi_try!(::std::str::from_utf8(unsafe {
&*(wasi_try!(path.deref(memory, 0, path_len)) as *const [_] as *const [u8])
})
.map_err(|_| __WASI_EINVAL))
.split('/')
.map(|str| str.to_string())
.collect::<Vec<String>>();
.map_err(|_| __WASI_EINVAL));
debug!("=> path: {}", &path_string);
let path = std::path::PathBuf::from(path_string);
let path_vec = path
.components()
.map(|comp| comp.as_os_str().to_string_lossy().to_string())
.collect::<Vec<String>>();
let buf_cell = wasi_try!(buf.deref(memory));
if path_vec.is_empty() {
return __WASI_EINVAL;
}
let mut cumulative_path = std::path::PathBuf::new();
debug!("=> Path vec: {:?}:", &path_vec);
// find the inode by traversing the path
let mut inode = root_dir.inode;
'outer: for segment in path_vec {
'outer: for segment in &path_vec[..(path_vec.len() - 1)] {
// loop to traverse symlinks
// TODO: proper cycle detection
let mut sym_count = 0;
loop {
match &state.fs.inodes[inode].kind {
Kind::Dir { entries, .. } => {
if let Some(entry) = entries.get(&segment) {
cumulative_path.push(&segment);
if let Some(entry) = entries.get(segment) {
debug!("Entry {:?} found", &segment);
inode = entry.clone();
continue 'outer;
} else {
return __WASI_ENOENT;
// lazily load
debug!("Lazily loading entry {:?}", &segment);
let path_metadata =
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_ENOENT));
if !path_metadata.is_dir() {
// TODO: should this just return invalid arg?
return __WASI_ENOTDIR;
}
let kind = Kind::Dir {
path: std::path::PathBuf::from(&segment),
entries: Default::default(),
};
let inode_val = InodeVal::from_file_metadata(
&path_metadata,
segment.clone(),
false,
kind,
);
let new_inode = state.fs.inodes.insert(inode_val);
let inode_idx = state.fs.inode_counter.get();
state.fs.inode_counter.replace(inode_idx + 1);
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[inode].kind {
// check that we're not displacing any entries
assert!(entries.insert(segment.clone(), new_inode).is_none());
state.fs.inodes[new_inode].stat.st_ino = state.fs.inode_counter.get();
inode = new_inode;
}
debug!("Directory {:#?} lazily loaded", &cumulative_path);
}
continue 'outer;
}
Kind::Symlink { forwarded } => {
// TODO: updated cumulative path
sym_count += 1;
inode = forwarded.clone();
if sym_count > MAX_SYMLINKS {
@ -1062,7 +1155,62 @@ pub fn path_filestat_get(
}
}
let stat = state.fs.inodes[inode].stat;
let final_inode = match &state.fs.inodes[inode].kind {
Kind::Dir { path, entries, .. } => {
// TODO: fail earlier if size 0
let last_segment = path_vec.last().unwrap();
cumulative_path.push(last_segment);
if entries.contains_key(last_segment) {
entries[last_segment]
} else {
// lazily load it if we can
if !cumulative_path.exists() {
return __WASI_ENOENT;
}
let final_path_metadata =
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EIO));
let new_inode = if final_path_metadata.is_dir() {
debug!("Opening host directory {:#?}", &cumulative_path);
state.fs.inodes.insert(InodeVal {
stat: __wasi_filestat_t::default(),
is_preopened: false, // is this correct?
name: last_segment.clone(),
kind: Kind::Dir {
path: std::path::PathBuf::from(&last_segment),
entries: Default::default(),
},
})
} else {
debug!("Opening host file {:#?}", &cumulative_path);
let real_open_file = wasi_try!(std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(&cumulative_path)
.map_err(|_| __WASI_ENOENT));
state.fs.inodes.insert(InodeVal {
stat: __wasi_filestat_t::default(),
is_preopened: false, // is this correct?
name: last_segment.clone(),
kind: Kind::File {
handle: WasiFile::HostFile(real_open_file),
},
})
};
// reborrow to insert entry
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[inode].kind {
entries.insert(last_segment.clone(), new_inode);
}
new_inode
}
}
_ => {
return __WASI_ENOTDIR;
}
};
let stat = state.fs.inodes[final_inode].stat;
buf_cell.set(stat);
@ -1097,7 +1245,7 @@ pub fn path_filestat_set_times(
fst_flags: __wasi_fstflags_t,
) -> __wasi_errno_t {
debug!("wasi::path_filestat_set_times");
unimplemented!()
unimplemented!("wasi::path_filestat_set_times")
}
/// ### `path_link()`
@ -1128,7 +1276,7 @@ pub fn path_link(
new_path_len: u32,
) -> __wasi_errno_t {
debug!("wasi::path_link");
unimplemented!()
unimplemented!("wasi::path_link")
}
/// ### `path_open()`
@ -1221,6 +1369,7 @@ pub fn path_open(
match &state.fs.inodes[cur_dir_inode].kind {
Kind::Dir { entries, .. } => {
if let Some(child) = entries.get(path_segment) {
cumulative_path.push(path_segment);
let inode_val = *child;
cur_dir_inode = inode_val;
} else {
@ -1376,7 +1525,7 @@ pub fn path_readlink(
bufused: WasmPtr<u32>,
) -> __wasi_errno_t {
debug!("wasi::path_readlink");
unimplemented!()
unimplemented!("wasi::path_readlink")
}
pub fn path_remove_directory(
ctx: &mut Ctx,
@ -1385,7 +1534,7 @@ pub fn path_remove_directory(
path_len: u32,
) -> __wasi_errno_t {
debug!("wasi::path_remove_directory");
unimplemented!()
unimplemented!("wasi::path_remove_directory")
}
pub fn path_rename(
ctx: &mut Ctx,
@ -1397,7 +1546,7 @@ pub fn path_rename(
new_path_len: u32,
) -> __wasi_errno_t {
debug!("wasi::path_rename");
unimplemented!()
unimplemented!("wasi::path_rename")
}
pub fn path_symlink(
ctx: &mut Ctx,
@ -1408,7 +1557,7 @@ pub fn path_symlink(
new_path_len: u32,
) -> __wasi_errno_t {
debug!("wasi::path_symlink");
unimplemented!()
unimplemented!("wasi::path_symlink")
}
pub fn path_unlink_file(
ctx: &mut Ctx,
@ -1417,7 +1566,7 @@ pub fn path_unlink_file(
path_len: u32,
) -> __wasi_errno_t {
debug!("wasi::path_unlink_file");
unimplemented!()
unimplemented!("wasi::path_unlink_file")
}
pub fn poll_oneoff(
ctx: &mut Ctx,
@ -1427,7 +1576,7 @@ pub fn poll_oneoff(
nevents: WasmPtr<u32>,
) -> __wasi_errno_t {
debug!("wasi::poll_oneoff");
unimplemented!()
unimplemented!("wasi::poll_oneoff")
}
pub fn proc_exit(ctx: &mut Ctx, code: __wasi_exitcode_t) -> Result<Infallible, ExitCode> {
debug!("wasi::proc_exit, {}", code);
@ -1435,7 +1584,7 @@ pub fn proc_exit(ctx: &mut Ctx, code: __wasi_exitcode_t) -> Result<Infallible, E
}
pub fn proc_raise(ctx: &mut Ctx, sig: __wasi_signal_t) -> __wasi_errno_t {
debug!("wasi::proc_raise");
unimplemented!()
unimplemented!("wasi::proc_raise")
}
/// ### `random_get()`
@ -1478,7 +1627,7 @@ pub fn sock_recv(
ro_flags: WasmPtr<__wasi_roflags_t>,
) -> __wasi_errno_t {
debug!("wasi::sock_recv");
unimplemented!()
unimplemented!("wasi::sock_recv")
}
pub fn sock_send(
ctx: &mut Ctx,
@ -1489,9 +1638,9 @@ pub fn sock_send(
so_datalen: WasmPtr<u32>,
) -> __wasi_errno_t {
debug!("wasi::sock_send");
unimplemented!()
unimplemented!("wasi::sock_send")
}
pub fn sock_shutdown(ctx: &mut Ctx, sock: __wasi_fd_t, how: __wasi_sdflags_t) -> __wasi_errno_t {
debug!("wasi::sock_shutdown");
unimplemented!()
unimplemented!("wasi::sock_shutdown")
}

View File

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

View File

@ -5,6 +5,7 @@
#define CALL_FIRST 1
__declspec(thread) jmp_buf jmpBuf;
__declspec(thread) DWORD caughtExceptionCode;
__declspec(thread) PVOID caughtExceptionAddress;
__declspec(thread) DWORD64 caughtInstructionPointer;
__declspec(thread) PVOID savedStackPointer;
@ -25,6 +26,7 @@ static LONG WINAPI
exceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) {
EXCEPTION_RECORD* pExceptionRecord = ExceptionInfo->ExceptionRecord;
PCONTEXT pCONTEXT = ExceptionInfo->ContextRecord;
caughtExceptionCode = pExceptionRecord->ExceptionCode;
caughtExceptionAddress = pExceptionRecord->ExceptionAddress;
caughtInstructionPointer = pCONTEXT->Rip;
if (alreadyHandlingException == TRUE) {
@ -61,8 +63,9 @@ uint8_t callProtected(trampoline_t trampoline,
}
// jmp jmp jmp!
int signum = setjmp(jmpBuf);
if (signum == 0) {
int status = setjmp(jmpBuf);
if (status == 0) // 0 means the original call
{
// save the stack pointer
savedStackPointer = get_callee_frame_address();
trampoline(ctx, func, param_vec, return_vec);
@ -74,7 +77,7 @@ uint8_t callProtected(trampoline_t trampoline,
return TRUE;
}
out_result->code = (uint64_t)signum;
out_result->code = (uint64_t)caughtExceptionCode;
out_result->exception_address = (uint64_t)caughtExceptionAddress;
out_result->instruction_pointer = caughtInstructionPointer;
@ -83,4 +86,4 @@ uint8_t callProtected(trampoline_t trampoline,
removeExceptionHandler();
return FALSE;
}
}

View File

@ -1,4 +1,3 @@
use std::ffi::c_void;
use std::ptr::NonNull;
use wasmer_runtime_core::vm::{Ctx, Func};

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#[cfg(windows)]
mod exception_handling;

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
extern crate structopt;
use std::env;
@ -87,6 +89,10 @@ struct Run {
#[structopt(long = "em-symbol-map", parse(from_os_str), group = "emscripten")]
em_symbol_map: Option<PathBuf>,
/// Begin execution at the specified symbol
#[structopt(long = "em-entrypoint", group = "emscripten")]
em_entrypoint: Option<String>,
/// WASI pre-opened directory
#[structopt(long = "dir", multiple = true, group = "wasi")]
pre_opened_directories: Vec<String>,
@ -394,6 +400,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
options.path.to_str().unwrap()
},
options.args.iter().map(|arg| arg.as_str()).collect(),
options.em_entrypoint.clone(),
)
.map_err(|e| format!("{:?}", e))?;
} else {

View File

@ -18,6 +18,9 @@ DisableWelcomePage=no
Source: "..\..\target\release\wasmer.exe"; DestDir: "{app}\bin"
Source: "..\..\wapm-cli\target\release\wapm.exe"; DestDir: "{app}\bin"
[Dirs]
Name: "{%USERPROFILE}\.wasmer"
[Code]
const EnvironmentKey = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
@ -68,7 +71,7 @@ begin
if CurStep = ssPostInstall
then begin
EnvAddPath(ExpandConstant('{app}') +'\bin');
EnvAddPath(ExpandConstant('{app}') +'\globals\wapm_packages\.bin');
EnvAddPath(ExpandConstant('{%USERPROFILE}') +'\globals\wapm_packages\.bin');
end
end;
@ -77,6 +80,6 @@ begin
if CurUninstallStep = usPostUninstall
then begin
EnvRemovePath(ExpandConstant('{app}') +'\bin');
EnvAddPath(ExpandConstant('{app}') +'\globals\wapm_packages\.bin');
EnvAddPath(ExpandConstant('{%USERPROFILE}') +'\globals\wapm_packages\.bin');
end
end;

View File

@ -1,3 +1,5 @@
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
#[macro_use]
extern crate wasmer_runtime_core;
// extern crate wasmer_emscripten;

View File

@ -1,5 +1,5 @@
PREVIOUS_VERSION='0.2.1'
NEXT_VERSION='0.3.0'
PREVIOUS_VERSION='0.4.0'
NEXT_VERSION='0.4.1'
# quick hack
fd Cargo.toml --exec sed -i '' "s/version = \"$PREVIOUS_VERSION\"/version = \"$NEXT_VERSION\"/"