Merge branch 'master' into wasmer-c-api-error-visibility

This commit is contained in:
Brandon Fish 2019-07-31 19:58:23 -06:00 committed by GitHub
commit a832a4c787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 1494 additions and 618 deletions

View File

@ -18,24 +18,22 @@ environment:
cache:
- 'C:\Users\appveyor\.cargo'
- target
- wapm-cli-target
install:
# # Install LLVM
# - mkdir C:\projects\deps
# - cd C:\projects\deps
# - appveyor DownloadFile https://prereleases.llvm.org/win-snapshots/LLVM-8.0.0-r351033-win64.exe -FileName llvm.exe
# - 7z x llvm.exe -oC:\projects\deps\llvm
# # - set "PATH=%PATH%;C:\projects\deps\llvm\bin"
# - set "LLD_LINK=C:\projects\deps\llvm\bin\lld-link.exe"
# - set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm"
# - cd "%APPVEYOR_BUILD_FOLDER%"
# Install LLVM
- mkdir C:\projects\deps
- cd C:\projects\deps
- appveyor DownloadFile https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip -FileName llvm-8.0.0-install.zip
- 7z x llvm-8.0.0-install.zip
- C:\projects\deps\llvm-8.0.0-install\bin\llvm-config.exe --version
- set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm-8.0.0-install"
- cd "%APPVEYOR_BUILD_FOLDER%"
# Install Rust
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
# - rustup-init.exe -yv --default-host %target%
- set PATH=%PATH%;C:\\Libraries\\llvm-5.0.0\\bin;%USERPROFILE%\.cargo\bin
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init.exe -yv --default-host %target%
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
- rustup default stable-%target%
- rustup update
- rustc -vV
@ -49,25 +47,17 @@ install:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
build_script:
- cargo build --release --verbose
- git submodule init
- git submodule update
# Cache wapm cli target in dir above to prevent breaking git submodule on windows
- if not exist wapm-cli-target mkdir wapm-cli-target
- move wapm-cli-target wapm-cli
- cd wapm-cli
- rename wapm-cli-target target
- cd ..
- cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
- cd wapm-cli
- cd ..
- xcopy wapm-cli\target wapm-cli-target\ /i /y
- cargo build --release --verbose --features backend-llvm
- cargo build --release --manifest-path lib/runtime-c-api/Cargo.toml
test_script:
- cargo test --manifest-path lib/spectests/Cargo.toml --features clif
before_deploy:
- appveyor PushArtifact target\release\wasmer_runtime_c_api.dll
- git submodule init
- git submodule update
- cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
- cd ./src/installer
- iscc wasmer.iss
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe

View File

@ -115,6 +115,8 @@ jobs:
name: Check
command: |
make check
make compile-bench-singlepass
# TODO: add compile-bench-llvm and compile-bench-clif when they work
- run:
name: Release
command: make release-fast
@ -129,6 +131,26 @@ jobs:
- target/release/deps
key: v8-test-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
test-rust-example:
docker:
- image: circleci/rust:latest
<<: *run_with_build_env_vars
steps:
- checkout
- run:
name: "Check Wasmer Rust example"
command: |
git clone https://github.com/wasmerio/wasmer-rust-example
rustup default stable
rustup target add wasm32-unknown-unknown
cd wasmer-rust-example
cd wasm-sample-app
cargo build --release
cd ..
sed -i 's/wasmer-runtime.*/wasmer-runtime = \{ path = "..\/lib\/runtime" \}/g' Cargo.toml
cargo run
cargo test
test-macos:
macos:
xcode: "9.0"
@ -383,6 +405,12 @@ workflows:
only:
- trying
- staging
- test-rust-example:
filters:
branches:
only:
- trying
- staging
- test-macos:
filters:
branches:

View File

@ -5,6 +5,15 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.
## **[Unreleased]**
## 0.6.0 - 2019-07-31
- [#603](https://github.com/wasmerio/wasmer/pull/603) Update Wapm-cli, bump version numbers
- [#595](https://github.com/wasmerio/wasmer/pull/595) Add unstable public API for interfacing with the WASI file system in plugin-like usecases
- [#598](https://github.com/wasmerio/wasmer/pull/598) LLVM Backend is now supported in Windows
- [#599](https://github.com/wasmerio/wasmer/pull/599) Fix llvm backend failures in fat spec tests and simd_binaryen spec test.
- [#579](https://github.com/wasmerio/wasmer/pull/579) Fix bug in caching with LLVM and Singlepass backends.
Add `default-backend-singlepass`, `default-backend-llvm`, and `default-backend-cranelift` features to `wasmer-runtime`
to control the `default_compiler()` function (this is a breaking change). Add `compiler_for_backend` function in `wasmer-runtime`
- [#561](https://github.com/wasmerio/wasmer/pull/561) Call the `data_finalizer` field on the `Ctx`
- [#576](https://github.com/wasmerio/wasmer/pull/576) fix `Drop` of uninit `Ctx`
- [#542](https://github.com/wasmerio/wasmer/pull/542) Add SIMD support to Wasmer (LLVM backend only)
@ -25,6 +34,8 @@ Blocks of changes will separated by version increments.
- makes wasitests-generate output stdout/stderr by default & adds function to print stdout and stderr for a command if it fails
- compiles wasm with size optimizations & strips generated wasm with wasm-strip
- [#554](https://github.com/wasmerio/wasmer/pull/554) Finish implementation of `wasi::fd_seek`, fix bug in filestat
- [#550](https://github.com/wasmerio/wasmer/pull/550) Fix singlepass compilation error with `imul` instruction
## 0.5.5 - 2019-07-10
- [#541](https://github.com/wasmerio/wasmer/pull/541) Fix dependency graph by making separate test crates; ABI implementations should not depend on compilers. Add Cranelift fork as git submodule of clif-backend
@ -38,6 +49,7 @@ Blocks of changes will separated by version increments.
- [#523](https://github.com/wasmerio/wasmer/pull/523) Update wapm version to fix bug related to signed packages in the global namespace and locally-stored public keys
## 0.5.2 - 2019-07-02
- [#516](https://github.com/wasmerio/wasmer/pull/516) Add workaround for singlepass miscompilation on GetLocal
- [#521](https://github.com/wasmerio/wasmer/pull/521) Update Wapm-cli, bump version numbers
- [#518](https://github.com/wasmerio/wasmer/pull/518) Update Cranelift and WasmParser
- [#514](https://github.com/wasmerio/wasmer/pull/514) [#519](https://github.com/wasmerio/wasmer/pull/519) Improved Emscripten network related calls, added a null check to `WasmPtr`

20
Cargo.lock generated
View File

@ -565,19 +565,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "inkwell"
version = "0.1.0"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#f1775622b6d88fd30006b377042726854c9e0193"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#4c5359e507b8a3439c9e2c7fff5c336224069638"
dependencies = [
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)",
"libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)",
"llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inkwell_internal_macros"
version = "0.1.0"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#f1775622b6d88fd30006b377042726854c9e0193"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#4c5359e507b8a3439c9e2c7fff5c336224069638"
dependencies = [
"cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1429,8 +1430,8 @@ dependencies = [
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-fork-frontend 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-fork-wasm 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-fork-frontend 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-fork-wasm 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.5.7",
"wasmer-win-exception-handler 0.5.7",
"wasmparser 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1439,7 +1440,7 @@ dependencies = [
[[package]]
name = "wasmer-clif-fork-frontend"
version = "0.31.1"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cranelift-codegen 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1449,7 +1450,7 @@ dependencies = [
[[package]]
name = "wasmer-clif-fork-wasm"
version = "0.31.1"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cranelift-codegen 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1457,7 +1458,7 @@ dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-fork-frontend 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-clif-fork-frontend 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmparser 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1522,6 +1523,7 @@ dependencies = [
"wabt 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.5.7",
"wasmparser 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1893,8 +1895,8 @@ dependencies = [
"checksum wabt 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d07edd40d190ddcbd0113c2150ccb214f47a02ff36958630ba0e5b8138ece1c1"
"checksum wabt-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b064c81821100adb4b71923cecfc67fef083db21c3bbd454b0162c7ffe63eeaa"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum wasmer-clif-fork-frontend 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb483d085618e1ee40361a9b7ae815ef002012f9b165e8343cee4770dc28e9dc"
"checksum wasmer-clif-fork-wasm 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df494fd86c3b8b8f99f1f6d0f4d193efa824dd9221daec56176b36cb15925270"
"checksum wasmer-clif-fork-frontend 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be2e38b16377f93ac485b6045fdc135dd3f165d25d4992e7b67c5cbc3ca8c760"
"checksum wasmer-clif-fork-wasm 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88becfcf874d7587750e1a1c30c47a16ed220f28c433c4b81db4c4626455a6a1"
"checksum wasmparser 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8030ec5a7c242a91941947fdb752e9a7c0929aced954ea23c54dad1cd2611850"
"checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer"
version = "0.5.7"
version = "0.6.0"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
repository = "https://github.com/wasmerio/wasmer"
@ -66,15 +66,30 @@ glob = "0.2.11"
rustc_version = "0.2.3"
[features]
default = ["fast-tests", "wasi"]
default = ["fast-tests", "wasi", "backend-cranelift"]
"loader-kernel" = ["wasmer-kernel-loader"]
debug = ["wasmer-runtime-core/debug"]
trace = ["wasmer-runtime-core/trace"]
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", "wasmer-runtime-core/backend-llvm"]
"backend-singlepass" = ["wasmer-singlepass-backend", "wasmer-runtime-core/backend-singlepass"]
backend-cranelift = [
"wasmer-runtime-core/backend-cranelift",
"wasmer-runtime/cranelift",
"wasmer-middleware-common/clif"
]
backend-llvm = [
"wasmer-llvm-backend",
"wasmer-runtime-core/backend-llvm",
"wasmer-runtime/llvm",
"wasmer-middleware-common/llvm"
]
backend-singlepass = [
"wasmer-singlepass-backend",
"wasmer-runtime-core/backend-singlepass",
"wasmer-runtime/singlepass",
"wasmer-middleware-common/singlepass"
]
wasi = ["wasmer-wasi"]
# vfs = ["wasmer-runtime-abi"]

13
Dockerfile.build Normal file
View File

@ -0,0 +1,13 @@
FROM ubuntu:19.04
ARG RUST_TOOLCHAIN="nightly"
ENV CARGO_HOME=/usr/local/rust
ENV RUSTUP_HOME=/usr/local/rust
ENV PATH="$PATH:$CARGO_HOME/bin"
RUN apt-get update \
&& apt-get -y install sudo strace curl cmake pkg-config python libssl-dev llvm-dev libz-dev gnuplot-nox \
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
&& echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
&& curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN"

View File

@ -141,8 +141,20 @@ release-singlepass:
release-llvm:
cargo build --release --features backend-llvm
bench:
cargo bench --all
bench-singlepass:
cargo bench --all --no-default-features --features "backend-singlepass"
bench-clif:
cargo bench --all --no-default-features --features "backend-clif"
bench-llvm:
cargo bench --all --no-default-features --features "backend-llvm"
# compile but don't run the benchmarks
compile-bench-singlepass:
cargo bench --all --no-run --no-default-features --features "backend-singlepass"
compile-bench-clif:
cargo bench --all --no-run --no-default-features --features "backend-clif"
compile-bench-llvm:
cargo bench --all --no-run --no-default-features --features "backend-llvm"
# Build utils

View File

@ -220,7 +220,10 @@ Each integration can be tested separately:
Benchmarks can be run with:
```sh
make bench
make bench-[backend]
# for example
make bench-singlepass
```
## Roadmap

View File

@ -3,6 +3,7 @@ status = [
"ci/circleci: test",
"ci/circleci: test-macos",
"ci/circleci: test-stable",
"ci/circleci: test-rust-example",
"continuous-integration/appveyor/branch"
]
required_approvals = 1

79
build Executable file
View File

@ -0,0 +1,79 @@
#!/bin/bash
# Wasmer build tool
#
# This is a script to build Wasmer in a Docker sandbox.
#
# To use the script, first make sure Docker is installed. Then build the
# sandbox image with:
#
# docker build --file Dockerfile.build --tag wasmer-build .
#
# After the sandbox image is built successfully, you can run commands in it
# with this script.
#
# For example, to build Wasmer, run:
#
# ./build make
#
# To test Wasmer, run:
#
# ./build make test
#
# and so on.
docker_hostname="wasmer-build"
docker_img="wasmer-build"
docker_workdir="/wasmer"
docker_args=(
#
# General config.
#
--hostname=${docker_hostname}
--interactive
--network=host
--rm
--tty
#
# User and group config.
#
# Use the same user and group permissions as host to make integration
# between host and container simple.
#
--user "$(id --user):$(id --group)"
--volume "/etc/group:/etc/group:ro"
--volume "/etc/passwd:/etc/passwd:ro"
--volume "/etc/shadow:/etc/shadow:ro"
#
# Time zone config.
#
# Use the same time zone as the host.
#
--volume "/etc/localtime:/etc/localtime:ro"
#
# Linux capabilities.
#
# Add SYS_PTRACE capability to the container so that people can run
# `strace'.
#
--cap-add SYS_PTRACE
#
# Source directory.
#
--workdir=${docker_workdir}
--volume "$(pwd):${docker_workdir}:z"
#
# Environment variables.
#
--env "CARGO_HOME=${docker_workdir}/.cargo"
)
docker run ${docker_args[@]} ${docker_img} $*

BIN
examples/particle-repel-simd.wasm Executable file

Binary file not shown.

BIN
examples/particle-repel.wasm Executable file

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,10 @@
use wasmer_runtime::{func, imports, instantiate};
use wasmer_runtime_core::vm::Ctx;
use wasmer_wasi::generate_import_object;
use wasmer_wasi::{
generate_import_object,
state::{self, WasiFile},
types,
};
static PLUGIN_LOCATION: &'static str = "examples/plugin-for-example.wasm";
@ -9,6 +13,107 @@ fn it_works(_ctx: &mut Ctx) -> i32 {
5
}
#[derive(Debug)]
pub struct LoggingWrapper {
pub wasm_module_name: String,
}
// std io trait boiler plate so we can implement WasiFile
// LoggingWrapper is a write-only type so we just want to immediately
// fail when reading or Seeking
impl std::io::Read for LoggingWrapper {
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from logging wrapper",
))
}
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> std::io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from logging wrapper",
))
}
fn read_to_string(&mut self, _buf: &mut String) -> std::io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from logging wrapper",
))
}
fn read_exact(&mut self, _buf: &mut [u8]) -> std::io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from logging wrapper",
))
}
}
impl std::io::Seek for LoggingWrapper {
fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not seek logging wrapper",
))
}
}
impl std::io::Write for LoggingWrapper {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let stdout = std::io::stdout();
let mut out = stdout.lock();
out.write(b"[")?;
out.write(self.wasm_module_name.as_bytes())?;
out.write(b"]: ")?;
out.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
std::io::stdout().flush()
}
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
let stdout = std::io::stdout();
let mut out = stdout.lock();
out.write(b"[")?;
out.write(self.wasm_module_name.as_bytes())?;
out.write(b"]: ")?;
out.write_all(buf)
}
fn write_fmt(&mut self, fmt: std::fmt::Arguments) -> std::io::Result<()> {
let stdout = std::io::stdout();
let mut out = stdout.lock();
out.write(b"[")?;
out.write(self.wasm_module_name.as_bytes())?;
out.write(b"]: ")?;
out.write_fmt(fmt)
}
}
// the WasiFile methods aren't relevant for a write-only Stdout-like implementation
impl WasiFile for LoggingWrapper {
fn last_accessed(&self) -> u64 {
0
}
fn last_modified(&self) -> u64 {
0
}
fn created_time(&self) -> u64 {
0
}
fn size(&self) -> u64 {
0
}
}
/// Called by the program when it wants to set itself up
fn initialize(ctx: &mut Ctx) {
let state = unsafe { state::get_wasi_state(ctx) };
let wasi_file_inner = LoggingWrapper {
wasm_module_name: "example module name".to_string(),
};
// swap stdout with our new wasifile
let _old_stdout = state
.fs
.swap_file(types::__WASI_STDOUT_FILENO, Box::new(wasi_file_inner))
.unwrap();
}
fn main() {
// Load the plugin data
let wasm_bytes = std::fs::read(PLUGIN_LOCATION).expect(&format!(
@ -27,8 +132,10 @@ fn main() {
// The WASI imports object contains all required import functions for a WASI module to run.
// Extend this imports with our custom imports containing "it_works" function so that our custom wasm code may run.
base_imports.extend(custom_imports);
let instance =
let mut instance =
instantiate(&wasm_bytes[..], &base_imports).expect("failed to instantiate wasm module");
// set up logging by replacing stdout
initialize(instance.context_mut());
// get a reference to the function "plugin_entrypoint" which takes an i32 and returns an i32
let entry_point = instance.func::<(i32), i32>("plugin_entrypoint").unwrap();

View File

@ -33,6 +33,19 @@ INFO: seed corpus: files: 8 min: 1b max: 1b total: 8b rss: 133Mb
```
It will continue to generate random inputs forever, until it finds a bug or is terminated. The testcases for bugs it finds go into `fuzz/artifacts/simple_instantiate` and you can rerun the fuzzer on a single input by passing it on the command line `cargo fuzz run simple_instantiate my_testcase.wasm`.
## Seeding the corpus, optional
The fuzzer works best when it has examples of small Wasm files to start with. Using `wast2json` from [wabt](https://github.com/WebAssembly/wabt), we can easily produce `.wasm` files out of the WebAssembly spec tests.
```sh
mkdir spec-test-corpus
for i in lib/spectests/spectests/*.wast; do wast2json $i -o spec-test-corpus/$(basename $i).json; done
mv spec-test-corpus/*.wasm fuzz/corpus/simple_instantiate/
rm -r spec-test-corpus
```
The corpus directory is created on the first run of the fuzzer. If it doesn't exist, run it first and then seed the corpus. The fuzzer will pick up new files added to the corpus while it is running.
## Trophy case
- [x] https://github.com/wasmerio/wasmer/issues/558

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-clif-backend"
version = "0.5.7"
version = "0.6.0"
description = "Wasmer runtime Cranelift compiler backend"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,12 +9,12 @@ edition = "2018"
readme = "README.md"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
cranelift-native = { version = "0.31" }
cranelift-codegen = { version = "0.31" }
cranelift-entity = { version = "0.31" }
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.31.1" }
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.31.1" }
cranelift-frontend = { package = "wasmer-clif-fork-frontend", version = "0.32" }
cranelift-wasm = { package = "wasmer-clif-fork-wasm", version = "0.32" }
hashbrown = "0.1"
target-lexicon = "0.4.0"
wasmparser = "0.34.0"
@ -35,7 +35,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.5.7" }
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.6.0" }
[features]
debug = ["wasmer-runtime-core/debug"]

View File

@ -304,8 +304,15 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
let signatures_empty = Map::new();
let signatures = if self.signatures.is_some() {
&self.signatures.as_ref().unwrap()
} else {
&signatures_empty
};
let (func_resolver, backend_cache) = func_resolver_builder.finalize(
&self.signatures.as_ref().unwrap(),
signatures,
Arc::clone(&trampolines),
handler_data.clone(),
)?;

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-emscripten-tests"
version = "0.5.7"
version = "0.6.0"
description = "Tests for our Emscripten implementation"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,15 +9,15 @@ publish = false
build = "build/mod.rs"
[dependencies]
wasmer-emscripten = { path = "../emscripten", version = "0.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.5.7" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.7", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.7", optional = true }
wasmer-emscripten = { path = "../emscripten", version = "0.6.0" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
[dev-dependencies]
wabt = "0.9.0"
wasmer-dev-utils = { path = "../dev-utils", version = "0.5.7"}
wasmer-dev-utils = { path = "../dev-utils", version = "0.6.0"}
[build-dependencies]
glob = "0.2.11"

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-emscripten"
version = "0.5.7"
version = "0.6.0"
description = "Wasmer runtime emscripten implementation library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -13,7 +13,7 @@ hashbrown = "0.1"
lazy_static = "1.2.0"
libc = "0.2.49"
time = "0.1.41"
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
[target.'cfg(windows)'.dependencies]
rand = "0.6"

View File

@ -196,18 +196,15 @@ pub fn _getaddrinfo(
let hints = hints_ptr.deref(memory).map(|hints_memory| {
let hints_guest = hints_memory.get();
unsafe {
let mut hints_native: addrinfo = std::mem::uninitialized();
hints_native.ai_flags = hints_guest.ai_flags;
hints_native.ai_family = hints_guest.ai_family;
hints_native.ai_socktype = hints_guest.ai_socktype;
hints_native.ai_protocol = hints_guest.ai_protocol;
hints_native.ai_addrlen = 0;
hints_native.ai_addr = std::ptr::null_mut();
hints_native.ai_canonname = std::ptr::null_mut();
hints_native.ai_next = std::ptr::null_mut();
hints_native
addrinfo {
ai_flags: hints_guest.ai_flags,
ai_family: hints_guest.ai_family,
ai_socktype: hints_guest.ai_socktype,
ai_protocol: hints_guest.ai_protocol,
ai_addrlen: 0,
ai_addr: std::ptr::null_mut(),
ai_canonname: std::ptr::null_mut(),
ai_next: std::ptr::null_mut(),
}
});

View File

@ -71,7 +71,7 @@ pub fn sbrk(ctx: &mut Ctx, increment: i32) -> i32 {
debug!("emscripten::sbrk");
// let old_dynamic_top = 0;
// let new_dynamic_top = 0;
let mut globals = get_emscripten_data(ctx).globals;
let globals = get_emscripten_data(ctx).globals;
let dynamictop_ptr = (globals.dynamictop_ptr) as usize;
let old_dynamic_top = ctx.memory(0).view::<u32>()[dynamictop_ptr].get() as i32;
let new_dynamic_top: i32 = old_dynamic_top + increment;

View File

@ -617,13 +617,13 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
// let mut address_len_addr: socklen_t = 0;
let (fd, host_address) = unsafe {
let mut host_address: sockaddr = std::mem::uninitialized();
let fd = accept(socket, &mut host_address, address_len_addr);
(fd, host_address)
let mut host_address: sockaddr = sockaddr {
sa_family: Default::default(),
sa_data: Default::default(),
#[cfg(target_os = "macos")]
sa_len: Default::default(),
};
let fd = unsafe { accept(socket, &mut host_address, address_len_addr) };
let address_addr = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() };
address_addr.sa_family = host_address.sa_family as _;
@ -651,15 +651,18 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in
let address_len_addr =
unsafe { address_len.deref_mut(ctx.memory(0)).unwrap().get_mut() };
let (ret, sock_addr_host) = unsafe {
// read host data into new var
let mut address: sockaddr = std::mem::uninitialized();
let ret = getsockname(
let mut sock_addr_host: sockaddr = sockaddr {
sa_family: Default::default(),
sa_data: Default::default(),
#[cfg(target_os = "macos")]
sa_len: Default::default(),
};
let ret = unsafe {
getsockname(
socket,
&mut address as *mut sockaddr,
&mut sock_addr_host as *mut sockaddr,
address_len_addr as *mut u32,
);
(ret, address)
)
};
// translate from host data into emscripten data
let mut address_mut = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() };

View File

@ -219,7 +219,7 @@ fn __get_async_io_payload<
}
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Default, Copy, Clone)]
struct SockaddrIn {
sin_family: u16, // e.g. AF_INET
sin_port: u16, // e.g. htons(3490)
@ -315,7 +315,7 @@ impl Tcp4Listener {
self.fd,
EpollDirection::In,
move |fd| -> Result<Arc<TcpStream>, i32> {
let mut incoming_sa: SockaddrIn = unsafe { ::std::mem::uninitialized() };
let mut incoming_sa: SockaddrIn = SockaddrIn::default();
let mut real_len: usize = ::std::mem::size_of::<SockaddrIn>();
let conn = unsafe { _accept4(fd, &mut incoming_sa, &mut real_len, O_NONBLOCK) };
if conn >= 0 {

View File

@ -1,13 +1,12 @@
[package]
name = "wasmer-llvm-backend"
version = "0.5.7"
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
version = "0.6.0"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
readme = "README.md"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm8-0", features = ["llvm8-0"] }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmparser = "0.34.0"
hashbrown = "0.1.8"
smallvec = "0.6.8"
@ -16,6 +15,15 @@ libc = "0.2.49"
nix = "0.14.0"
capstone = { version = "0.5.0", optional = true }
[dependencies.inkwell]
git = "https://github.com/wasmerio/inkwell"
branch = "llvm8-0"
default-features = false
features = ["llvm8-0", "target-x86"]
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["memoryapi"] }
[build-dependencies]
cc = "1.0"
lazy_static = "1.2.0"

View File

@ -75,16 +75,24 @@ public:
}
virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override {
// We don't know yet how to do this on Windows, so we hide this on compilation
// so we can compile and pass spectests on unix systems
#ifndef _WIN32
eh_frame_ptr = addr;
eh_frame_size = size;
eh_frames_registered = true;
callbacks.visit_fde(addr, size, __register_frame);
#endif
}
virtual void deregisterEHFrames() override {
// We don't know yet how to do this on Windows, so we hide this on compilation
// so we can compile and pass spectests on unix systems
#ifndef _WIN32
if (eh_frames_registered) {
callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
}
#endif
}
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {

View File

@ -1,14 +1,12 @@
use crate::intrinsics::Intrinsics;
use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect};
use inkwell::{
memory_buffer::MemoryBuffer,
module::Module,
targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine},
OptimizationLevel,
};
use libc::{
c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ,
PROT_WRITE,
};
use libc::c_char;
use std::{
any::Any,
ffi::{c_void, CString},
@ -31,42 +29,6 @@ use wasmer_runtime_core::{
vm, vmcalls,
};
#[repr(C)]
struct LLVMModule {
_private: [u8; 0],
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
enum MemProtect {
NONE,
READ,
READ_WRITE,
READ_EXECUTE,
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
enum LLVMResult {
OK,
ALLOCATE_FAILURE,
PROTECT_FAILURE,
DEALLOC_FAILURE,
OBJECT_LOAD_FAILURE,
}
#[repr(C)]
struct Callbacks {
alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func,
visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)),
}
extern "C" {
fn module_load(
mem_ptr: *const u8,
@ -99,69 +61,21 @@ extern "C" {
}
fn get_callbacks() -> Callbacks {
fn round_up_to_page_size(size: usize) -> usize {
(size + (4096 - 1)) & !(4096 - 1)
}
extern "C" fn alloc_memory(
size: usize,
protect: MemProtect,
ptr_out: &mut *mut u8,
size_out: &mut usize,
) -> LLVMResult {
let size = round_up_to_page_size(size);
let ptr = unsafe {
mmap(
ptr::null_mut(),
size,
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
MAP_PRIVATE | MAP_ANON,
-1,
0,
)
};
if ptr as isize == -1 {
return LLVMResult::ALLOCATE_FAILURE;
}
*ptr_out = ptr as _;
*size_out = size;
LLVMResult::OK
unsafe { crate::platform::alloc_memory(size, protect, ptr_out, size_out) }
}
extern "C" fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
let res = unsafe {
mprotect(
ptr as _,
round_up_to_page_size(size),
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
)
};
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::PROTECT_FAILURE
}
unsafe { crate::platform::protect_memory(ptr, size, protect) }
}
extern "C" fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
let res = unsafe { munmap(ptr as _, round_up_to_page_size(size)) };
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::DEALLOC_FAILURE
}
unsafe { crate::platform::dealloc_memory(ptr, size) }
}
extern "C" fn lookup_vm_symbol(name_ptr: *const c_char, length: usize) -> *const vm::Func {

View File

@ -209,14 +209,23 @@ fn trap_if_not_representable_as_int(
intrinsics: &Intrinsics,
context: &Context,
function: &FunctionValue,
lower_bound: f64,
upper_bound: f64,
lower_bound: u64, // Inclusive (not a trapping value)
upper_bound: u64, // Inclusive (not a trapping value)
value: FloatValue,
) {
let float_ty = value.get_type();
let int_ty = if float_ty == intrinsics.f32_ty {
intrinsics.i32_ty
} else {
intrinsics.i64_ty
};
let lower_bound = float_ty.const_float(lower_bound);
let upper_bound = float_ty.const_float(upper_bound);
let lower_bound = builder
.build_bitcast(int_ty.const_int(lower_bound, false), float_ty, "")
.into_float_value();
let upper_bound = builder
.build_bitcast(int_ty.const_int(upper_bound, false), float_ty, "")
.into_float_value();
// The 'U' in the float predicate is short for "unordered" which means that
// the comparison will compare true if either operand is a NaN. Thus, NaNs
@ -351,6 +360,45 @@ fn trap_if_zero(
builder.position_at_end(&shouldnt_trap_block);
}
// Replaces any NaN with the canonical QNaN, otherwise leaves the value alone.
fn canonicalize_nans(
builder: &Builder,
intrinsics: &Intrinsics,
value: BasicValueEnum,
) -> BasicValueEnum {
let f_ty = value.get_type();
let canonicalized = if f_ty.is_vector_type() {
let value = value.into_vector_value();
let f_ty = f_ty.into_vector_type();
let zero = f_ty.const_zero();
let nan_cmp = builder.build_float_compare(FloatPredicate::UNO, value, zero, "nan");
let canonical_qnan = f_ty
.get_element_type()
.into_float_type()
.const_float(std::f64::NAN);
let canonical_qnan = splat_vector(
builder,
intrinsics,
canonical_qnan.as_basic_value_enum(),
f_ty,
"",
);
builder
.build_select(nan_cmp, canonical_qnan, value, "")
.as_basic_value_enum()
} else {
let value = value.into_float_value();
let f_ty = f_ty.into_float_type();
let zero = f_ty.const_zero();
let nan_cmp = builder.build_float_compare(FloatPredicate::UNO, value, zero, "nan");
let canonical_qnan = f_ty.const_float(std::f64::NAN);
builder
.build_select(nan_cmp, canonical_qnan, value, "")
.as_basic_value_enum()
};
canonicalized
}
fn resolve_memory_ptr(
builder: &Builder,
intrinsics: &Intrinsics,
@ -546,14 +594,6 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
}
fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> {
let op = match event {
Event::Wasm(x) => x,
Event::Internal(_x) => {
return Ok(());
}
Event::WasmOwned(ref x) => x,
};
let mut state = &mut self.state;
let builder = self.builder.as_ref().unwrap();
let context = self.context.as_ref().unwrap();
@ -564,6 +604,38 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
let signatures = &self.signatures;
let mut ctx = self.ctx.as_mut().unwrap();
let op = match event {
Event::Wasm(x) => x,
Event::WasmOwned(ref x) => x,
Event::Internal(x) => {
match x {
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
return Ok(());
}
InternalEvent::Breakpoint(_callback) => {
return Ok(());
}
InternalEvent::GetInternal(idx) => {
if state.reachable {
let idx = idx as usize;
let field_ptr = ctx.internal_field(idx, intrinsics, builder);
let result = builder.build_load(field_ptr, "get_internal");
state.push1(result);
}
}
InternalEvent::SetInternal(idx) => {
if state.reachable {
let idx = idx as usize;
let field_ptr = ctx.internal_field(idx, intrinsics, builder);
let v = state.pop1()?;
builder.build_store(field_ptr, v);
}
}
}
return Ok(());
}
};
if !state.reachable {
match *op {
Operator::Block { ty: _ } | Operator::Loop { ty: _ } | Operator::If { ty: _ } => {
@ -1577,9 +1649,45 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
Operator::I32RemS | Operator::I64RemS => {
let (v1, v2) = state.pop2()?;
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
let int_type = v1.get_type();
let (min_value, neg_one_value) = if int_type == intrinsics.i32_ty {
let min_value = int_type.const_int(i32::min_value() as u64, false);
let neg_one_value = int_type.const_int(-1i32 as u32 as u64, false);
(min_value, neg_one_value)
} else if int_type == intrinsics.i64_ty {
let min_value = int_type.const_int(i64::min_value() as u64, false);
let neg_one_value = int_type.const_int(-1i64 as u64, false);
(min_value, neg_one_value)
} else {
unreachable!()
};
trap_if_zero(builder, intrinsics, context, &function, v2);
// "Overflow also leads to undefined behavior; this is a rare
// case, but can occur, for example, by taking the remainder of
// a 32-bit division of -2147483648 by -1. (The remainder
// doesnt actually overflow, but this rule lets srem be
// implemented using instructions that return both the result
// of the division and the remainder.)"
// -- https://llvm.org/docs/LangRef.html#srem-instruction
//
// In Wasm, the i32.rem_s i32.const -2147483648 i32.const -1 is
// i32.const 0. We implement this by swapping out the left value
// for 0 in this case.
let will_overflow = builder.build_and(
builder.build_int_compare(IntPredicate::EQ, v1, min_value, "left_is_min"),
builder.build_int_compare(
IntPredicate::EQ,
v2,
neg_one_value,
"right_is_neg_one",
),
"srem_will_overflow",
);
let v1 = builder
.build_select(will_overflow, int_type.const_zero(), v1, "")
.into_int_value();
let res = builder.build_int_signed_rem(v1, v2, &state.var_name());
state.push1(res);
}
@ -2033,120 +2141,120 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
***************************/
Operator::F32Add | Operator::F64Add => {
let (v1, v2) = state.pop2()?;
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_float_value(), v2.into_float_value());
let res = builder.build_float_add(v1, v2, &state.var_name());
state.push1(res);
}
Operator::F32x4Add => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f32x4_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f32x4_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_add(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F64x2Add => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f64x2_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f64x2_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_add(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F32Sub | Operator::F64Sub => {
let (v1, v2) = state.pop2()?;
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_float_value(), v2.into_float_value());
let res = builder.build_float_sub(v1, v2, &state.var_name());
state.push1(res);
}
Operator::F32x4Sub => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f32x4_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f32x4_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_sub(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F64x2Sub => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f64x2_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f64x2_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_sub(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F32Mul | Operator::F64Mul => {
let (v1, v2) = state.pop2()?;
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_float_value(), v2.into_float_value());
let res = builder.build_float_mul(v1, v2, &state.var_name());
state.push1(res);
}
Operator::F32x4Mul => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f32x4_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f32x4_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_mul(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F64x2Mul => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f64x2_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f64x2_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_mul(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F32Div | Operator::F64Div => {
let (v1, v2) = state.pop2()?;
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_float_value(), v2.into_float_value());
let res = builder.build_float_div(v1, v2, &state.var_name());
state.push1(res);
}
Operator::F32x4Div => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f32x4_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f32x4_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_div(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
}
Operator::F64x2Div => {
let (v1, v2) = state.pop2()?;
let v1 = builder
.build_bitcast(v1, intrinsics.f64x2_ty, "")
.into_vector_value();
let v2 = builder
.build_bitcast(v2, intrinsics.f64x2_ty, "")
.into_vector_value();
let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, "");
let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, "");
let v1 = canonicalize_nans(builder, intrinsics, v1);
let v2 = canonicalize_nans(builder, intrinsics, v2);
let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value());
let res = builder.build_float_div(v1, v2, &state.var_name());
let res = builder.build_bitcast(res, intrinsics.i128_ty, "");
state.push1(res);
@ -3189,12 +3297,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
Operator::I32TruncSF32 => {
let v1 = state.pop1()?.into_float_value();
trap_if_not_representable_as_int(
builder,
intrinsics,
context,
&function,
-2147483904.0,
2147483648.0,
builder, intrinsics, context, &function, 0xcf000000, // -2147483600.0
0x4effffff, // 2147483500.0
v1,
);
let res =
@ -3208,8 +3312,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
intrinsics,
context,
&function,
-2147483649.0,
2147483648.0,
0xc1e00000001fffff, // -2147483648.9999995
0x41dfffffffffffff, // 2147483647.9999998
v1,
);
let res =
@ -3225,12 +3329,9 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
Operator::I64TruncSF32 => {
let v1 = state.pop1()?.into_float_value();
trap_if_not_representable_as_int(
builder,
intrinsics,
context,
&function,
-9223373136366403584.0,
9223372036854775808.0,
builder, intrinsics, context, &function,
0xdf000000, // -9223372000000000000.0
0x5effffff, // 9223371500000000000.0
v1,
);
let res =
@ -3244,8 +3345,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
intrinsics,
context,
&function,
-9223372036854777856.0,
9223372036854775808.0,
0xc3e0000000000000, // -9223372036854776000.0
0x43dfffffffffffff, // 9223372036854775000.0
v1,
);
let res =
@ -3261,12 +3362,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
Operator::I32TruncUF32 => {
let v1 = state.pop1()?.into_float_value();
trap_if_not_representable_as_int(
builder,
intrinsics,
context,
&function,
-1.0,
4294967296.0,
builder, intrinsics, context, &function, 0xbf7fffff, // -0.99999994
0x4f7fffff, // 4294967000.0
v1,
);
let res =
@ -3280,8 +3377,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
intrinsics,
context,
&function,
-1.0,
4294967296.0,
0xbfefffffffffffff, // -0.9999999999999999
0x41efffffffffffff, // 4294967295.9999995
v1,
);
let res =
@ -3297,12 +3394,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
Operator::I64TruncUF32 => {
let v1 = state.pop1()?.into_float_value();
trap_if_not_representable_as_int(
builder,
intrinsics,
context,
&function,
-1.0,
18446744073709551616.0,
builder, intrinsics, context, &function, 0xbf7fffff, // -0.99999994
0x5f7fffff, // 18446743000000000000.0
v1,
);
let res =
@ -3316,8 +3409,8 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
intrinsics,
context,
&function,
-1.0,
18446744073709551616.0,
0xbfefffffffffffff, // -0.9999999999999999
0x43efffffffffffff, // 18446744073709550000.0
v1,
);
let res =
@ -3331,12 +3424,14 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
state.push1(res);
}
Operator::F32DemoteF64 => {
let v1 = state.pop1()?.into_float_value();
let v1 = state.pop1()?;
let v1 = canonicalize_nans(builder, intrinsics, v1).into_float_value();
let res = builder.build_float_trunc(v1, intrinsics.f32_ty, &state.var_name());
state.push1(res);
}
Operator::F64PromoteF32 => {
let v1 = state.pop1()?.into_float_value();
let v1 = state.pop1()?;
let v1 = canonicalize_nans(builder, intrinsics, v1).into_float_value();
let res = builder.build_float_ext(v1, intrinsics.f64_ty, &state.var_name());
state.push1(res);
}

View File

@ -18,7 +18,7 @@ use wasmer_runtime_core::{
GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
TableIndex, Type,
},
vm::Ctx,
vm::{Ctx, INTERNALS_SIZE},
};
fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType {
@ -328,12 +328,12 @@ impl Intrinsics {
minimum_f32: module.add_function("llvm.minnum.f32", ret_f32_take_f32_f32, None),
minimum_f64: module.add_function("llvm.minnum.f64", ret_f64_take_f64_f64, None),
minimum_f32x4: module.add_function(
"llvm.minimum.v4f32",
"llvm.minnum.v4f32",
ret_f32x4_take_f32x4_f32x4,
None,
),
minimum_f64x2: module.add_function(
"llvm.minimum.v2f64",
"llvm.minnum.v2f64",
ret_f64x2_take_f64x2_f64x2,
None,
),
@ -341,12 +341,12 @@ impl Intrinsics {
maximum_f32: module.add_function("llvm.maxnum.f32", ret_f32_take_f32_f32, None),
maximum_f64: module.add_function("llvm.maxnum.f64", ret_f64_take_f64_f64, None),
maximum_f32x4: module.add_function(
"llvm.maximum.v4f32",
"llvm.maxnum.v4f32",
ret_f32x4_take_f32x4_f32x4,
None,
),
maximum_f64x2: module.add_function(
"llvm.maximum.v2f64",
"llvm.maxnum.v2f64",
ret_f64x2_take_f64x2_f64x2,
None,
),
@ -942,4 +942,31 @@ impl<'a> CtxType<'a> {
(imported_func_cache.func_ptr, imported_func_cache.ctx_ptr)
}
pub fn internal_field(
&mut self,
index: usize,
intrinsics: &Intrinsics,
builder: &Builder,
) -> PointerValue {
assert!(index < INTERNALS_SIZE);
let local_internals_ptr_ptr = unsafe {
builder.build_struct_gep(
self.ctx_ptr_value,
offset_to_index(Ctx::offset_internals()),
"local_internals_ptr_ptr",
)
};
let local_internals_ptr = builder
.build_load(local_internals_ptr_ptr, "local_internals_ptr")
.into_pointer_value();
unsafe {
builder.build_in_bounds_gep(
local_internals_ptr,
&[intrinsics.i32_ty.const_int(index as u64, false)],
"local_internal_field_ptr",
)
}
}
}

View File

@ -7,8 +7,12 @@ mod intrinsics;
mod platform;
mod read_info;
mod state;
mod structs;
mod trampolines;
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;
pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator;
use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen;
pub type LLVMCompiler = SimpleStreamingCompilerGen<

View File

@ -0,0 +1,3 @@
pub fn round_up_to_page_size(size: usize) -> usize {
(size + (4096 - 1)) & !(4096 - 1)
}

View File

@ -1,7 +1,14 @@
mod common;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use self::unix::*;
#[cfg(target_family = "windows")]
compile_error!("windows not yet supported for the llvm-based compiler backend");
mod win;
#[cfg(target_family = "windows")]
pub use self::win::*;
#[cfg(not(any(unix, target_family = "windows")))]
compile_error!("Your system is not yet supported for the llvm-based compiler backend");

View File

@ -1,5 +1,11 @@
use libc::{c_void, siginfo_t};
use super::common::round_up_to_page_size;
use crate::structs::{LLVMResult, MemProtect};
use libc::{
c_void, mmap, mprotect, munmap, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE,
PROT_READ, PROT_WRITE,
};
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV};
use std::ptr;
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
/// argument, so we need to parse the fde table here.
@ -68,3 +74,60 @@ extern "C" fn signal_trap_handler(
throw_trap(2);
}
}
pub unsafe fn alloc_memory(
size: usize,
protect: MemProtect,
ptr_out: &mut *mut u8,
size_out: &mut usize,
) -> LLVMResult {
let size = round_up_to_page_size(size);
let ptr = mmap(
ptr::null_mut(),
size,
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
MAP_PRIVATE | MAP_ANON,
-1,
0,
);
if ptr as isize == -1 {
return LLVMResult::ALLOCATE_FAILURE;
}
*ptr_out = ptr as _;
*size_out = size;
LLVMResult::OK
}
pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
let res = mprotect(
ptr as _,
round_up_to_page_size(size),
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
);
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::PROTECT_FAILURE
}
}
pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
let res = munmap(ptr as _, round_up_to_page_size(size));
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::DEALLOC_FAILURE
}
}

View File

@ -0,0 +1,80 @@
use super::common::round_up_to_page_size;
use crate::structs::{LLVMResult, MemProtect};
use std::ptr;
use winapi::um::memoryapi::{VirtualAlloc, VirtualFree};
use winapi::um::winnt::{
MEM_COMMIT, MEM_DECOMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_NOACCESS, PAGE_READONLY,
PAGE_READWRITE,
};
pub unsafe fn visit_fde(_addr: *mut u8, _size: usize, _visitor: extern "C" fn(*mut u8)) {
// Do nothing on Windows
}
pub unsafe fn install_signal_handler() {
// Do nothing on Windows
}
pub unsafe fn alloc_memory(
size: usize,
protect: MemProtect,
ptr_out: &mut *mut u8,
size_out: &mut usize,
) -> LLVMResult {
let size = round_up_to_page_size(size);
let flags = if protect == MemProtect::NONE {
MEM_RESERVE
} else {
MEM_RESERVE | MEM_COMMIT
};
let ptr = VirtualAlloc(
ptr::null_mut(),
size,
flags,
memprotect_to_protect_const(protect),
);
if ptr.is_null() {
return LLVMResult::ALLOCATE_FAILURE;
}
*ptr_out = ptr as _;
*size_out = size;
LLVMResult::OK
}
pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
let size = round_up_to_page_size(size);
let ptr = VirtualAlloc(
ptr as _,
size,
MEM_COMMIT,
memprotect_to_protect_const(protect),
);
if ptr.is_null() {
LLVMResult::PROTECT_FAILURE
} else {
LLVMResult::OK
}
}
pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
let success = VirtualFree(ptr as _, size, MEM_DECOMMIT);
// If the function succeeds, the return value is nonzero.
if success == 1 {
LLVMResult::OK
} else {
LLVMResult::DEALLOC_FAILURE
}
}
fn memprotect_to_protect_const(protect: MemProtect) -> u32 {
match protect {
MemProtect::NONE => PAGE_NOACCESS,
MemProtect::READ => PAGE_READONLY,
MemProtect::READ_WRITE => PAGE_READWRITE,
MemProtect::READ_EXECUTE => PAGE_EXECUTE_READ,
}
}

View File

@ -0,0 +1,39 @@
use libc::c_char;
use wasmer_runtime_core::vm;
#[repr(C)]
pub struct LLVMModule {
_private: [u8; 0],
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub enum MemProtect {
NONE,
READ,
READ_WRITE,
READ_EXECUTE,
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub enum LLVMResult {
OK,
ALLOCATE_FAILURE,
PROTECT_FAILURE,
DEALLOC_FAILURE,
OBJECT_LOAD_FAILURE,
}
#[repr(C)]
pub struct Callbacks {
pub alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
pub protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
pub dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
pub lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func,
pub visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)),
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-middleware-common"
version = "0.5.7"
version = "0.6.0"
repository = "https://github.com/wasmerio/wasmer"
description = "Wasmer runtime common middlewares"
license = "MIT"
@ -9,9 +9,9 @@ edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.5.7" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.7", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.7", optional = true }
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
[dev-dependencies]
wabt = "0.9.0"

View File

@ -135,16 +135,15 @@ static WAT_GAS: &'static str = r#"
#[cfg(feature = "llvm")]
fn get_compiler(limit: u64, metering: bool) -> impl Compiler {
use wasmer_llvm_backend::code::LLVMModuleCodeGenerator;
use wasmer_llvm_backend::ModuleCodeGenerator;
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
let c: StreamingCompiler<LLVMModuleCodeGenerator, _, _, _, _> =
StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
if metering {
chain.push(Metering::new(limit));
}
chain
});
let c: StreamingCompiler<ModuleCodeGenerator, _, _, _, _> = StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
if metering {
chain.push(Metering::new(limit));
}
chain
});
c
}
@ -164,15 +163,11 @@ fn get_compiler(limit: u64, metering: bool) -> impl Compiler {
}
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
fn get_compiler(_limit: u64, metering: bool) -> impl Compiler {
panic!("compiler not specified, activate a compiler via features");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
compile_error!("compiler not specified, activate a compiler via features");
#[cfg(feature = "clif")]
fn get_compiler(_limit: u64, metering: bool) -> impl Compiler {
panic!("cranelift does not implement metering");
compile_error!("cranelift does not implement metering");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}

View File

@ -162,15 +162,11 @@ mod tests {
}
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
fn get_compiler(_limit: u64) -> impl Compiler {
panic!("compiler not specified, activate a compiler via features");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}
compile_error!("compiler not specified, activate a compiler via features");
#[cfg(feature = "clif")]
fn get_compiler(_limit: u64) -> impl Compiler {
panic!("cranelift does not implement metering");
compile_error!("cranelift does not implement metering");
use wasmer_clif_backend::CraneliftCompiler;
CraneliftCompiler::new()
}

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-c-api"
version = "0.5.7"
version = "0.6.0"
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.5.7"
version = "0.6.0"
[dependencies.wasmer-runtime-core]
path = "../runtime-core"
version = "0.5.7"
version = "0.6.0"
[features]
debug = ["wasmer-runtime/debug"]

View File

@ -118,6 +118,6 @@ pub struct wasmer_limit_option_t {
#[repr(C)]
pub struct wasmer_byte_array {
bytes: *const u8,
bytes_len: u32,
pub bytes: *const u8,
pub bytes_len: u32,
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime-core"
version = "0.5.7"
version = "0.6.0"
description = "Wasmer runtime core library"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -55,5 +55,6 @@ cc = "1.0"
debug = []
trace = ["debug"]
# backend flags used in conditional compilation of Backend::variants
"backend-cranelift" = []
"backend-singlepass" = []
"backend-llvm" = []

View File

@ -32,6 +32,7 @@ pub enum Backend {
impl Backend {
pub fn variants() -> &'static [&'static str] {
&[
#[cfg(feature = "backend-cranelift")]
"cranelift",
#[cfg(feature = "backend-singlepass")]
"singlepass",
@ -110,14 +111,20 @@ impl Default for MemoryBoundCheckMode {
}
}
#[derive(Debug, Default)]
pub struct Features {
pub simd: bool,
}
/// Configuration data for the compiler
#[derive(Default)]
#[derive(Debug, Default)]
pub struct CompilerConfig {
/// Symbol information generated from emscripten; used for more detailed debug messages
pub symbol_map: Option<HashMap<u32, String>>,
pub memory_bound_check_mode: MemoryBoundCheckMode,
pub enforce_stack_check: bool,
pub track_state: bool,
pub features: Features,
}
pub trait Compiler {

View File

@ -20,6 +20,7 @@ pub enum Error {
Unknown(String),
InvalidFile(InvalidFileType),
InvalidatedCache,
UnsupportedBackend(Backend),
}
impl From<io::Error> for Error {

View File

@ -1,6 +1,6 @@
use crate::{
backend::RunnableModule,
backend::{Backend, CacheGen, Compiler, CompilerConfig, Token},
backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token},
cache::{Artifact, Error as CacheError},
error::{CompileError, CompileResult},
module::{ModuleInfo, ModuleInner},
@ -137,12 +137,12 @@ impl<
}
}
pub fn default_validating_parser_config() -> wasmparser::ValidatingParserConfig {
pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingParserConfig {
wasmparser::ValidatingParserConfig {
operator_config: wasmparser::OperatorValidatorConfig {
enable_threads: false,
enable_reference_types: false,
enable_simd: true,
enable_simd: features.simd,
enable_bulk_memory: false,
enable_multi_value: false,
},
@ -150,9 +150,9 @@ pub fn default_validating_parser_config() -> wasmparser::ValidatingParserConfig
}
}
fn validate(bytes: &[u8]) -> CompileResult<()> {
fn validate_with_features(bytes: &[u8], features: &Features) -> CompileResult<()> {
let mut parser =
wasmparser::ValidatingParser::new(bytes, Some(default_validating_parser_config()));
wasmparser::ValidatingParser::new(bytes, Some(validating_parser_config(features)));
loop {
let state = parser.read();
match *state {
@ -180,7 +180,7 @@ impl<
_: Token,
) -> CompileResult<ModuleInner> {
if requires_pre_validation(MCG::backend_id()) {
validate(wasm)?;
validate_with_features(wasm, &compiler_config.features)?;
}
let mut mcg = MCG::new();

View File

@ -117,8 +117,26 @@ pub fn validate(wasm: &[u8]) -> bool {
/// The same as `validate` but with an Error message on failure
pub fn validate_and_report_errors(wasm: &[u8]) -> ::std::result::Result<(), String> {
validate_and_report_errors_with_features(wasm, Default::default())
}
/// The same as `validate_and_report_errors` but with a Features.
pub fn validate_and_report_errors_with_features(
wasm: &[u8],
features: backend::Features,
) -> ::std::result::Result<(), String> {
use wasmparser::WasmDecoder;
let mut parser = wasmparser::ValidatingParser::new(wasm, None);
let config = wasmparser::ValidatingParserConfig {
operator_config: wasmparser::OperatorValidatorConfig {
enable_simd: features.simd,
enable_bulk_memory: false,
enable_multi_value: false,
enable_reference_types: false,
enable_threads: false,
},
mutable_global_imports: false,
};
let mut parser = wasmparser::ValidatingParser::new(wasm, Some(config));
loop {
let state = parser.read();
match *state {

View File

@ -85,8 +85,10 @@ pub fn read_module<
custom_sections: HashMap::new(),
}));
let mut parser =
wasmparser::ValidatingParser::new(wasm, Some(default_validating_parser_config()));
let mut parser = wasmparser::ValidatingParser::new(
wasm,
Some(validating_parser_config(&compiler_config.features)),
);
let mut namespace_builder = Some(StringTableBuilder::new());
let mut name_builder = Some(StringTableBuilder::new());

View File

@ -1,4 +1,3 @@
#[derive(Debug, Clone)]
enum MonoVecInner<T> {
None,
@ -36,7 +35,7 @@ impl<T> MonoVec<T> {
}
pub fn push(&mut self, item: T) {
let uninit = unsafe { mem::uninitialized() };
let uninit = MonoVecInner::None;
let prev = mem::replace(&mut self.inner, uninit);
let next = match prev {
MonoVecInner::None => MonoVecInner::Inline(item),
@ -54,7 +53,7 @@ impl<T> MonoVec<T> {
match self.inner {
MonoVecInner::None => None,
MonoVecInner::Inline(ref mut item) => {
let uninit = unsafe { mem::uninitialized() };
let uninit = unsafe { mem::zeroed() };
let item = mem::replace(item, uninit);
let uninit = mem::replace(&mut self.inner, MonoVecInner::None);
mem::forget(uninit);

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-runtime"
version = "0.5.7"
version = "0.6.0"
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.5.7", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
lazy_static = "1.2.0"
memmap = "0.7.0"
[dependencies.wasmer-runtime-core]
path = "../runtime-core"
version = "0.5.7"
version = "0.6.0"
[dependencies.wasmer-clif-backend]
path = "../clif-backend"
version = "0.5.7"
version = "0.6.0"
optional = true
[dev-dependencies]
@ -27,17 +27,20 @@ tempfile = "3.0.7"
criterion = "0.2"
wabt = "0.9.0"
[target.'cfg(not(windows))'.dependencies.wasmer-llvm-backend]
[dependencies.wasmer-llvm-backend]
path = "../llvm-backend"
optional = true
[features]
default = ["default-compiler"]
default-compiler = ["wasmer-clif-backend"]
cache = ["default-compiler"]
default = ["cranelift", "default-backend-cranelift"]
cranelift = ["wasmer-clif-backend"]
cache = ["cranelift"]
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
llvm = ["wasmer-llvm-backend"]
singlepass = ["wasmer-singlepass-backend"]
default-backend-singlepass = ["singlepass"]
default-backend-llvm = ["llvm"]
default-backend-cranelift = ["cranelift"]
[[bench]]
name = "nginx"

View File

@ -9,7 +9,7 @@ use std::{
use wasmer_runtime_core::cache::Error as CacheError;
pub use wasmer_runtime_core::{
backend::Backend,
cache::{Artifact, Cache, WasmHash, WASMER_VERSION_HASH},
cache::{Artifact, Cache, WasmHash},
};
/// Representation of a directory that contains compiled wasm artifacts.
@ -49,12 +49,7 @@ impl FileSystemCache {
/// This method is unsafe because there's no way to ensure the artifacts
/// stored in this cache haven't been corrupted or tampered with.
pub unsafe fn new<P: Into<PathBuf>>(path: P) -> io::Result<Self> {
let path: PathBuf = {
let mut path = path.into();
path.push(WASMER_VERSION_HASH);
path
};
let path: PathBuf = path.into();
if path.exists() {
let metadata = path.metadata()?;
if metadata.is_dir() {
@ -103,7 +98,12 @@ impl Cache for FileSystemCache {
let serialized_cache = Artifact::deserialize(&mmap[..])?;
unsafe {
wasmer_runtime_core::load_cache_with(serialized_cache, &super::default_compiler())
wasmer_runtime_core::load_cache_with(
serialized_cache,
super::compiler_for_backend(backend)
.ok_or_else(|| CacheError::UnsupportedBackend(backend))?
.as_ref(),
)
}
}

View File

@ -76,6 +76,7 @@
//! [`wasmer-clif-backend`]: https://crates.io/crates/wasmer-clif-backend
//! [`compile_with`]: fn.compile_with.html
pub use wasmer_runtime_core::backend::Backend;
pub use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
pub use wasmer_runtime_core::export::Export;
pub use wasmer_runtime_core::global::Global;
@ -179,17 +180,56 @@ pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result<I
/// Get a single instance of the default compiler to use.
pub fn default_compiler() -> impl Compiler {
#[cfg(feature = "llvm")]
#[cfg(any(
all(
feature = "default-backend-llvm",
any(
feature = "default-backend-cranelift",
feature = "default-backend-singlepass"
)
),
all(
feature = "default-backend-cranelift",
feature = "default-backend-singlepass"
)
))]
compile_error!(
"The `default-backend-X` features are mutually exclusive. Please choose just one"
);
#[cfg(feature = "default-backend-llvm")]
use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler;
#[cfg(feature = "singlepass")]
#[cfg(feature = "default-backend-singlepass")]
use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler;
#[cfg(not(any(feature = "llvm", feature = "singlepass")))]
#[cfg(feature = "default-backend-cranelift")]
use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler;
DefaultCompiler::new()
}
pub fn compiler_for_backend(backend: Backend) -> Option<Box<dyn Compiler>> {
match backend {
#[cfg(feature = "cranelift")]
Backend::Cranelift => Some(Box::new(wasmer_clif_backend::CraneliftCompiler::new())),
#[cfg(feature = "singlepass")]
Backend::Singlepass => Some(Box::new(
wasmer_singlepass_backend::SinglePassCompiler::new(),
)),
#[cfg(feature = "llvm")]
Backend::LLVM => Some(Box::new(wasmer_llvm_backend::LLVMCompiler::new())),
#[cfg(any(
not(feature = "llvm"),
not(feature = "singlepass"),
not(feature = "cranelift")
))]
_ => None,
}
}
/// The current version of this crate
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-singlepass-backend"
version = "0.5.7"
version = "0.6.0"
repository = "https://github.com/wasmerio/wasmer"
description = "Wasmer runtime single pass compiler backend"
license = "MIT"
@ -9,7 +9,7 @@ edition = "2018"
readme = "README.md"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmparser = "0.34.0"
dynasm = "0.3.2"
dynasmrt = "0.3.1"

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-spectests"
version = "0.5.7"
version = "0.6.0"
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.5.7" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.5.7" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.7", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.7", optional = true }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
[build-dependencies]
wabt = "0.9.0"

View File

@ -86,7 +86,7 @@ use wasmer_runtime_core::types::Value;
use wasmer_runtime_core::{{Instance, module::Module}};
use wasmer_runtime_core::error::Result;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::backend::Compiler;
use wasmer_runtime_core::backend::{Compiler, CompilerConfig, Features};
static IMPORT_MODULE: &str = r#"
(module
@ -136,7 +136,7 @@ pub fn generate_imports() -> ImportObject {
let mut features = wabt::Features::new();
features.enable_simd();
let wasm_binary = wat2wasm_with_features(IMPORT_MODULE.as_bytes(), features).expect("WAST not valid or malformed");
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler())
let module = wasmer_runtime_core::compile_with_config(&wasm_binary[..], &get_compiler(), CompilerConfig { features: Features { simd: true }, ..Default::default() })
.expect("WASM can't be compiled");
let instance = module
.instantiate(&ImportObject::new())
@ -408,7 +408,7 @@ fn test_module_{}() {{
let module_str = \"{}\";
println!(\"{{}}\", module_str);
let wasm_binary = wat2wasm(module_str.as_bytes()).expect(\"WAST not valid or malformed\");
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler()).expect(\"WASM can't be compiled\");
let module = wasmer_runtime_core::compile_with_config(&wasm_binary[..], &get_compiler(), CompilerConfig {{ features: Features {{ simd: true }}, ..Default::default() }}).expect(\"WASM can't be compiled\");
module.instantiate(&generate_imports()).expect(\"WASM can't be instantiated\")
}}\n",
self.last_module,
@ -431,7 +431,7 @@ fn test_module_{}() {{
"#[test]
fn {}_assert_invalid() {{
let wasm_binary = {:?};
let module = wasmer_runtime_core::compile_with(&wasm_binary, &get_compiler());
let module = wasmer_runtime_core::compile_with_config(&wasm_binary, &get_compiler(), CompilerConfig {{ features: Features {{ simd: true }}, ..Default::default() }});
assert!(module.is_err(), \"WASM should not compile as is invalid\");
}}\n",
command_name,
@ -562,7 +562,7 @@ fn {}_assert_invalid() {{
"#[test]
fn {}_assert_malformed() {{
let wasm_binary = {:?};
let compilation = wasmer_runtime_core::compile_with(&wasm_binary, &get_compiler());
let compilation = wasmer_runtime_core::compile_with_config(&wasm_binary, &get_compiler(), CompilerConfig {{ features: Features {{ simd: true }}, ..Default::default() }});
assert!(compilation.is_err(), \"WASM should not compile as is malformed\");
}}\n",
command_name,

View File

@ -4,7 +4,9 @@
;; Distributed under the Apache License
;; https://github.com/WebAssembly/binaryen/blob/master/test/spec/LICENSE
;;
;; Modified by wasmer to work with the wabt parser.
;; Modified by wasmer to work with the wabt parser and to pass with wasmer.
;; * replaced result negative nans with positive nans
;; * disabled min and max tests pending an update to LLVM
(module
(memory 1)
@ -637,12 +639,14 @@
(assert_return (invoke "f32x4.abs" (v128.const f32x4 -0.0 nan -inf 5.0)) (v128.const f32x4 0.0 nan inf 5.0))
(assert_return (invoke "f32x4.neg" (v128.const f32x4 -0.0 nan -inf 5.0)) (v128.const f32x4 0.0 -nan inf -5.0))
(assert_return (invoke "f32x4.sqrt" (v128.const f32x4 -0.0 nan inf 4.0)) (v128.const f32x4 -0.0 nan inf 2.0))
(assert_return (invoke "f32x4.add" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf inf 1.0)) (v128.const f32x4 nan -nan inf 43.0))
(assert_return (invoke "f32x4.sub" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf -inf 1.0)) (v128.const f32x4 nan -nan inf 41.0))
(assert_return (invoke "f32x4.mul" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf inf 2.0)) (v128.const f32x4 nan -nan inf 84.0))
(assert_return (invoke "f32x4.div" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf 2.0 2.0)) (v128.const f32x4 nan -nan inf 21.0))
(assert_return (invoke "f32x4.min" (v128.const f32x4 -0.0 0.0 nan 5.0) (v128.const f32x4 0.0 -0.0 5.0 nan)) (v128.const f32x4 -0.0 -0.0 nan nan))
(assert_return (invoke "f32x4.max" (v128.const f32x4 -0.0 0.0 nan 5.0) (v128.const f32x4 0.0 -0.0 5.0 nan)) (v128.const f32x4 0.0 0.0 nan nan))
;; We canonicalize our NaNs to positive.
(assert_return (invoke "f32x4.add" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf inf 1.0)) (v128.const f32x4 nan nan inf 43.0))
(assert_return (invoke "f32x4.sub" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf -inf 1.0)) (v128.const f32x4 nan nan inf 41.0))
(assert_return (invoke "f32x4.mul" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf inf 2.0)) (v128.const f32x4 nan nan inf 84.0))
(assert_return (invoke "f32x4.div" (v128.const f32x4 nan -nan inf 42.0) (v128.const f32x4 42.0 inf 2.0 2.0)) (v128.const f32x4 nan nan inf 21.0))
;; min and max are known broken.
;;(assert_return (invoke "f32x4.min" (v128.const f32x4 -0.0 0.0 nan 5.0) (v128.const f32x4 0.0 -0.0 5.0 nan)) (v128.const f32x4 -0.0 -0.0 nan nan))
;;(assert_return (invoke "f32x4.max" (v128.const f32x4 -0.0 0.0 nan 5.0) (v128.const f32x4 0.0 -0.0 5.0 nan)) (v128.const f32x4 0.0 0.0 nan nan))
;; f64x2 arithmetic
(assert_return (invoke "f64x2.abs" (v128.const f64x2 -0.0 nan)) (v128.const f64x2 0.0 nan))
@ -651,18 +655,18 @@
(assert_return (invoke "f64x2.neg" (v128.const f64x2 -inf 5.0)) (v128.const f64x2 inf -5.0))
(assert_return (invoke "f64x2.sqrt" (v128.const f64x2 -0.0 nan)) (v128.const f64x2 -0.0 nan))
(assert_return (invoke "f64x2.sqrt" (v128.const f64x2 inf 4.0)) (v128.const f64x2 inf 2.0))
(assert_return (invoke "f64x2.add" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan -nan))
(assert_return (invoke "f64x2.add" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan nan))
(assert_return (invoke "f64x2.add" (v128.const f64x2 inf 42.0) (v128.const f64x2 inf 1.0)) (v128.const f64x2 inf 43.0))
(assert_return (invoke "f64x2.sub" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan -nan))
(assert_return (invoke "f64x2.sub" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan nan))
(assert_return (invoke "f64x2.sub" (v128.const f64x2 inf 42.0) (v128.const f64x2 -inf 1.0)) (v128.const f64x2 inf 41.0))
(assert_return (invoke "f64x2.mul" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan -nan))
(assert_return (invoke "f64x2.mul" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan nan))
(assert_return (invoke "f64x2.mul" (v128.const f64x2 inf 42.0) (v128.const f64x2 inf 2.0)) (v128.const f64x2 inf 84.0))
(assert_return (invoke "f64x2.div" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan -nan))
(assert_return (invoke "f64x2.div" (v128.const f64x2 nan -nan) (v128.const f64x2 42.0 inf)) (v128.const f64x2 nan nan))
(assert_return (invoke "f64x2.div" (v128.const f64x2 inf 42.0) (v128.const f64x2 2.0 2.0)) (v128.const f64x2 inf 21.0))
(assert_return (invoke "f64x2.min" (v128.const f64x2 -0.0 0.0) (v128.const f64x2 0.0 -0.0)) (v128.const f64x2 -0.0 -0.0))
(assert_return (invoke "f64x2.min" (v128.const f64x2 nan 5.0) (v128.const f64x2 5.0 nan)) (v128.const f64x2 nan nan))
(assert_return (invoke "f64x2.max" (v128.const f64x2 -0.0 0.0) (v128.const f64x2 0.0 -0.0)) (v128.const f64x2 0.0 0.0))
(assert_return (invoke "f64x2.max" (v128.const f64x2 nan 5.0) (v128.const f64x2 5.0 nan)) (v128.const f64x2 nan nan))
;;(assert_return (invoke "f64x2.min" (v128.const f64x2 -0.0 0.0) (v128.const f64x2 0.0 -0.0)) (v128.const f64x2 -0.0 -0.0))
;;(assert_return (invoke "f64x2.min" (v128.const f64x2 nan 5.0) (v128.const f64x2 5.0 nan)) (v128.const f64x2 nan nan))
;;(assert_return (invoke "f64x2.max" (v128.const f64x2 -0.0 0.0) (v128.const f64x2 0.0 -0.0)) (v128.const f64x2 0.0 0.0))
;;(assert_return (invoke "f64x2.max" (v128.const f64x2 nan 5.0) (v128.const f64x2 5.0 nan)) (v128.const f64x2 nan nan))
;; conversions
(assert_return (invoke "i32x4.trunc_sat_f32x4_s" (v128.const f32x4 42.0 nan inf -inf)) (v128.const i32x4 42 0 2147483647 -2147483648))

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-wasi-tests"
version = "0.5.7"
version = "0.6.0"
description = "Tests for our WASI implementation"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -9,19 +9,19 @@ publish = false
build = "build/mod.rs"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
wasmer-wasi = { path = "../wasi", version = "0.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
wasmer-wasi = { path = "../wasi", version = "0.6.0" }
# hack to get tests to work
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.5.7", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.5.7", optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.6.0", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.6.0", optional = true }
[build-dependencies]
glob = "0.2.11"
[dev-dependencies]
wasmer-clif-backend = { path = "../clif-backend", version = "0.5.7" }
wasmer-dev-utils = { path = "../dev-utils", version = "0.5.7"}
wasmer-clif-backend = { path = "../clif-backend", version = "0.6.0" }
wasmer-dev-utils = { path = "../dev-utils", version = "0.6.0"}
[features]
clif = []

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-wasi"
version = "0.5.7"
version = "0.6.0"
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.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
libc = "0.2.50"
rand = "0.6.5"
# wasmer-runtime-abi = { path = "../runtime-abi" }

View File

@ -6,11 +6,12 @@ extern crate winapi;
#[macro_use]
mod macros;
mod ptr;
mod state;
pub mod state;
mod syscalls;
mod utils;
use self::state::{WasiFs, WasiState};
pub use self::syscalls::types;
use self::syscalls::*;
use std::ffi::c_void;

View File

@ -1,3 +1,6 @@
//! WARNING: the API exposed here is unstable and very experimental. Certain thins will not
//! yet and may be broken in patch releases. If you're using this and have any specific needs,
//! please let us know here https://github.com/wasmerio/wasmer/issues/583 or by filing an issue.
// use wasmer_runtime_abi::vfs::{
// vfs::Vfs,
// file_like::{FileLike, Metadata};
@ -5,7 +8,7 @@
use crate::syscalls::types::*;
use generational_arena::Arena;
pub use generational_arena::Index as Inode;
use hashbrown::hash_map::{Entry, HashMap};
use hashbrown::hash_map::HashMap;
use std::{
borrow::Borrow,
cell::Cell,
@ -14,81 +17,312 @@ use std::{
path::{Path, PathBuf},
time::SystemTime,
};
use wasmer_runtime_core::debug;
use wasmer_runtime_core::{debug, vm::Ctx};
/// the fd value of the virtual root
pub const VIRTUAL_ROOT_FD: __wasi_fd_t = 4;
/// all the rights enabled
pub const ALL_RIGHTS: __wasi_rights_t = 0x1FFFFFFF;
/// Get WasiState from a Ctx
/// This function is unsafe because it must be called on a WASI Ctx
pub unsafe fn get_wasi_state(ctx: &mut Ctx) -> &mut WasiState {
&mut *(ctx.data as *mut WasiState)
}
/// A completely aribtrary "big enough" number used as the upper limit for
/// the number of symlinks that can be traversed when resolving a path
pub const MAX_SYMLINKS: u32 = 128;
/// Error type for external users
#[derive(Debug, PartialEq, Eq)]
#[allow(dead_code)]
// dead code beacuse this is for external use
pub enum WasiFsError {
/// The fd given as a base was not a directory so the operation was not possible
BaseNotDirectory,
/// Expected a file but found not a file
NotAFile,
/// The fd given was not usable
InvalidFd,
/// File exists
AlreadyExists,
/// Something failed when doing IO. These errors can generally not be handled.
/// It may work if tried again.
IOError,
/// A WASI error without an external name. If you encounter this it means
/// that there's probably a bug on our side (maybe as simple as forgetting to wrap
/// this error, but perhaps something broke)
UnknownError(__wasi_errno_t),
}
impl WasiFsError {
pub fn from_wasi_err(err: __wasi_errno_t) -> WasiFsError {
match err {
__WASI_EBADF => WasiFsError::InvalidFd,
__WASI_EEXIST => WasiFsError::AlreadyExists,
__WASI_EIO => WasiFsError::IOError,
_ => WasiFsError::UnknownError(err),
}
}
}
/// This trait relies on your file closing when it goes out of scope via `Drop`
pub trait WasiFile: std::fmt::Debug + Write + Read + Seek {
/// the last time the file was accessed in nanoseconds as a UNIX timestamp
fn last_accessed(&self) -> u64;
/// the last time the file was modified in nanoseconds as a UNIX timestamp
fn last_modified(&self) -> u64;
/// the time at which the file was created in nanoseconds as a UNIX timestamp
fn created_time(&self) -> u64;
/// the size of the file in bytes
fn size(&self) -> u64;
}
impl WasiFile for fs::File {
fn last_accessed(&self) -> u64 {
self.metadata()
.unwrap()
.accessed()
.ok()
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
.map(|ct| ct.as_nanos() as u64)
.unwrap_or(0)
}
fn last_modified(&self) -> u64 {
self.metadata()
.unwrap()
.modified()
.ok()
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
.map(|ct| ct.as_nanos() as u64)
.unwrap_or(0)
}
fn created_time(&self) -> u64 {
self.metadata()
.unwrap()
.created()
.ok()
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
.map(|ct| ct.as_nanos() as u64)
.unwrap_or(0)
}
fn size(&self) -> u64 {
self.metadata().unwrap().len()
}
}
#[derive(Debug)]
pub enum WasiFile {
HostFile(fs::File),
pub struct Stdout(std::io::Stdout);
impl Read for Stdout {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stdout",
))
}
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stdout",
))
}
fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stdout",
))
}
fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stdout",
))
}
}
impl WasiFile {
pub fn close(self) {}
impl Seek for Stdout {
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not seek stdout",
))
}
}
impl Write for WasiFile {
impl Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
WasiFile::HostFile(hf) => hf.write(buf),
}
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
match self {
WasiFile::HostFile(hf) => hf.flush(),
}
self.0.flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
match self {
WasiFile::HostFile(hf) => hf.write_all(buf),
}
self.0.write_all(buf)
}
fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
match self {
WasiFile::HostFile(hf) => hf.write_fmt(fmt),
}
self.0.write_fmt(fmt)
}
}
impl Read for WasiFile {
impl WasiFile for Stdout {
fn last_accessed(&self) -> u64 {
0
}
fn last_modified(&self) -> u64 {
0
}
fn created_time(&self) -> u64 {
0
}
fn size(&self) -> u64 {
0
}
}
#[derive(Debug)]
pub struct Stderr(std::io::Stderr);
impl Read for Stderr {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stderr",
))
}
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stderr",
))
}
fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stderr",
))
}
fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not read from stderr",
))
}
}
impl Seek for Stderr {
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not seek stderr",
))
}
}
impl Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.0.write_all(buf)
}
fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
self.0.write_fmt(fmt)
}
}
impl WasiFile for Stderr {
fn last_accessed(&self) -> u64 {
0
}
fn last_modified(&self) -> u64 {
0
}
fn created_time(&self) -> u64 {
0
}
fn size(&self) -> u64 {
0
}
}
#[derive(Debug)]
pub struct Stdin(std::io::Stdin);
impl Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
WasiFile::HostFile(hf) => hf.read(buf),
}
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
match self {
WasiFile::HostFile(hf) => hf.read_to_end(buf),
}
self.0.read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
match self {
WasiFile::HostFile(hf) => hf.read_to_string(buf),
}
self.0.read_to_string(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
match self {
WasiFile::HostFile(hf) => hf.read_exact(buf),
}
self.0.read_exact(buf)
}
}
impl Seek for Stdin {
fn seek(&mut self, _pos: io::SeekFrom) -> io::Result<u64> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not seek stdin",
))
}
}
impl Write for Stdin {
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not write to stdin",
))
}
fn flush(&mut self) -> io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not write to stdin",
))
}
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not write to stdin",
))
}
fn write_fmt(&mut self, _fmt: ::std::fmt::Arguments) -> io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"can not write to stdin",
))
}
}
impl Seek for WasiFile {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
match self {
WasiFile::HostFile(hf) => hf.seek(pos),
}
impl WasiFile for Stdin {
fn last_accessed(&self) -> u64 {
0
}
fn last_modified(&self) -> u64 {
0
}
fn created_time(&self) -> u64 {
0
}
fn size(&self) -> u64 {
0
}
}
/*
TODO: Think about using this
trait WasiFdBacking: std::fmt::Debug {
fn get_stat(&self) -> &__wasi_filestat_t;
fn get_stat_mut(&mut self) -> &mut __wasi_filestat_t;
fn is_preopened(&self) -> bool;
fn get_name(&self) -> &str;
}
*/
/// A file that Wasi knows about that may or may not be open
#[derive(Debug)]
pub struct InodeVal {
@ -98,12 +332,30 @@ pub struct InodeVal {
pub kind: Kind,
}
/*impl WasiFdBacking for InodeVal {
fn get_stat(&self) -> &__wasi_filestat_t {
&self.stat
}
fn get_stat_mut(&mut self) -> &mut __wasi_filestat_t {
&mut self.stat
}
fn is_preopened(&self) -> bool {
self.is_preopened
}
fn get_name(&self) -> &str {
self.name.as_ref()
}
}*/
#[allow(dead_code)]
#[derive(Debug)]
pub enum Kind {
File {
/// the open file, if it's open
handle: Option<WasiFile>,
handle: Option<Box<dyn WasiFile>>,
/// the path to the file
path: PathBuf,
},
@ -152,6 +404,8 @@ pub struct Fd {
}
#[derive(Debug)]
/// Warning, modifying these fields directly may cause invariants to break and
/// should be considered unsafe. These fields may be made private in a future release
pub struct WasiFs {
//pub repo: Repo,
pub preopen_fds: Vec<u32>,
@ -160,6 +414,10 @@ pub struct WasiFs {
pub fd_map: HashMap<u32, Fd>,
pub next_fd: Cell<u32>,
inode_counter: Cell<u64>,
pub stdout: Box<dyn WasiFile>,
pub stderr: Box<dyn WasiFile>,
pub stdin: Box<dyn WasiFile>,
}
impl WasiFs {
@ -176,6 +434,10 @@ impl WasiFs {
fd_map: HashMap::new(),
next_fd: Cell::new(3),
inode_counter: Cell::new(1024),
stdin: Box::new(Stdin(io::stdin())),
stdout: Box::new(Stdout(io::stdout())),
stderr: Box::new(Stderr(io::stderr())),
};
// create virtual root
let root_inode = {
@ -291,117 +553,97 @@ impl WasiFs {
next
}
/// Opens a user-supplied file in the directory specified with the
/// name and flags given
// dead code because this is an API for external use
#[allow(dead_code)]
fn get_inode(&mut self, path: &str) -> Option<Inode> {
Some(match self.name_map.entry(path.to_string()) {
Entry::Occupied(o) => *o.get(),
Entry::Vacant(_v) => {
return None;
// let file = if let Ok(file) = OpenOptions::new()
// .read(true)
// .write(true)
// .create(false)
// .open(&mut self.repo, path)
// {
// file
// } else {
// return None;
// };
pub fn open_file_at(
&mut self,
base: __wasi_fd_t,
file: Box<dyn WasiFile>,
name: String,
rights: __wasi_rights_t,
rights_inheriting: __wasi_rights_t,
flags: __wasi_fdflags_t,
) -> Result<__wasi_fd_t, WasiFsError> {
let base_fd = self.get_fd(base).map_err(WasiFsError::from_wasi_err)?;
// TODO: check permissions here? probably not, but this should be
// an explicit choice, so justify it in a comment when we remove this one
let base_inode = base_fd.inode;
// let metadata = file.metadata().unwrap();
// let inode_index = {
// let index = self.inode_counter.get();
// self.inode_counter.replace(index + 1)
// };
// let systime_to_nanos = |systime: SystemTime| {
// let duration = systime
// .duration_since(SystemTime::UNIX_EPOCH)
// .expect("should always be after unix epoch");
// duration.as_nanos() as u64
// };
// let inode = self.inodes.insert(InodeVal {
// stat: __wasi_filestat_t {
// st_dev: 0,
// st_ino: inode_index,
// st_filetype: match metadata.file_type() {
// FileType::File => __WASI_FILETYPE_REGULAR_FILE,
// FileType::Dir => __WASI_FILETYPE_DIRECTORY,
// },
// st_nlink: 0,
// st_size: metadata.content_len() as u64,
// st_atim: systime_to_nanos(SystemTime::now()),
// st_mtim: systime_to_nanos(metadata.modified_at()),
// st_ctim: systime_to_nanos(metadata.created_at()),
// },
// is_preopened: false,
// name: path.to_string(),
// kind: match metadata.file_type() {
// FileType::File => Kind::File { handle: file },
// FileType::Dir => Kind::Dir {
// handle: file,
// entries: HashMap::new(),
// },
// },
// });
// v.insert(inode);
// inode
}
})
}
/*
#[allow(dead_code)]
fn filestat_inode(
&self,
inode: Inode,
flags: __wasi_lookupflags_t,
) -> Result<__wasi_filestat_t, __wasi_errno_t> {
let inode_val = &self.inodes[inode];
if let (
true,
Kind::Symlink {
mut forwarded,
path,
},
) = (flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, &inode_val.kind)
{
// Time to follow the symlink.
let mut counter = 0;
while counter <= MAX_SYMLINKS {
let inode_val = &self.inodes[forwarded];
if let &Kind::Symlink {
forwarded: new_forwarded,
} = &inode_val.kind
{
counter += 1;
forwarded = new_forwarded;
} else {
return Ok(inode_val.stat);
match &self.inodes[base_inode].kind {
Kind::Dir { ref entries, .. } | Kind::Root { ref entries } => {
if let Some(_entry) = entries.get(&name) {
// TODO: eventually change the logic here to allow overwrites
return Err(WasiFsError::AlreadyExists);
}
}
Err(__WASI_EMLINK)
} else {
Ok(inode_val.stat)
let kind = Kind::File {
handle: Some(file),
path: PathBuf::from(""),
};
let inode = self
.create_inode(kind, false, name.clone())
.map_err(|_| WasiFsError::IOError)?;
// reborrow to insert
match &mut self.inodes[base_inode].kind {
Kind::Dir {
ref mut entries, ..
}
| Kind::Root { ref mut entries } => {
entries.insert(name, inode).ok_or(WasiFsError::IOError)?;
}
_ => unreachable!("Dir or Root became not Dir or Root"),
}
self.create_fd(rights, rights_inheriting, flags, inode)
.map_err(WasiFsError::from_wasi_err)
}
_ => Err(WasiFsError::BaseNotDirectory),
}
}
/// Change the backing of a given file descriptor
/// Returns the old backing
/// TODO: add examples
#[allow(dead_code)]
pub fn filestat_path(
pub fn swap_file(
&mut self,
preopened_fd: __wasi_fd_t,
flags: __wasi_lookupflags_t,
path: &str,
) -> Result<__wasi_filestat_t, __wasi_errno_t> {
warn!("Should use preopned_fd: {}", preopened_fd);
let inode = self.get_inode(path).ok_or(__WASI_EINVAL)?;
fd: __wasi_fd_t,
file: Box<dyn WasiFile>,
) -> Result<Option<Box<dyn WasiFile>>, WasiFsError> {
match fd {
__WASI_STDIN_FILENO => {
let mut ret = file;
std::mem::swap(&mut self.stdin, &mut ret);
Ok(Some(ret))
}
__WASI_STDOUT_FILENO => {
let mut ret = file;
std::mem::swap(&mut self.stdout, &mut ret);
Ok(Some(ret))
}
__WASI_STDERR_FILENO => {
let mut ret = file;
std::mem::swap(&mut self.stderr, &mut ret);
Ok(Some(ret))
}
_ => {
let base_fd = self.get_fd(fd).map_err(WasiFsError::from_wasi_err)?;
let base_inode = base_fd.inode;
self.filestat_inode(inode, flags)
match &mut self.inodes[base_inode].kind {
Kind::File { ref mut handle, .. } => {
let mut ret = Some(file);
std::mem::swap(handle, &mut ret);
Ok(ret)
}
_ => return Err(WasiFsError::NotAFile),
}
}
}
}
*/
fn get_inode_at_path_inner(
&mut self,
@ -666,9 +908,9 @@ impl WasiFs {
pub fn flush(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> {
match fd {
0 => (),
1 => io::stdout().flush().map_err(|_| __WASI_EIO)?,
2 => io::stderr().flush().map_err(|_| __WASI_EIO)?,
__WASI_STDIN_FILENO => (),
__WASI_STDOUT_FILENO => self.stdout.flush().map_err(|_| __WASI_EIO)?,
__WASI_STDERR_FILENO => self.stderr.flush().map_err(|_| __WASI_EIO)?,
_ => {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
if fd.rights & __WASI_RIGHT_FD_DATASYNC == 0 {
@ -717,7 +959,7 @@ impl WasiFs {
rights_inheriting: __wasi_rights_t,
flags: __wasi_fdflags_t,
inode: Inode,
) -> Result<u32, __wasi_errno_t> {
) -> Result<__wasi_fd_t, __wasi_errno_t> {
let idx = self.next_fd.get();
self.next_fd.set(idx + 1);
self.fd_map.insert(
@ -762,7 +1004,17 @@ impl WasiFs {
pub fn get_stat_for_kind(&self, kind: &Kind) -> Option<__wasi_filestat_t> {
let md = match kind {
Kind::File { handle, path } => match handle {
Some(WasiFile::HostFile(hf)) => hf.metadata().ok()?,
Some(wf) => {
return Some(__wasi_filestat_t {
st_filetype: __WASI_FILETYPE_REGULAR_FILE,
st_size: wf.size(),
st_atim: wf.last_accessed(),
st_mtim: wf.last_modified(),
st_ctim: wf.created_time(),
..__wasi_filestat_t::default()
})
}
None => path.metadata().ok()?,
},
Kind::Dir { path, .. } => path.metadata().ok()?,

View File

@ -9,7 +9,7 @@ use self::types::*;
use crate::{
ptr::{Array, WasmPtr},
state::{
host_file_type_to_wasi_file_type, Fd, Inode, InodeVal, Kind, WasiFile, WasiState,
self, host_file_type_to_wasi_file_type, Fd, Inode, InodeVal, Kind, WasiFile, WasiState,
MAX_SYMLINKS,
},
ExitCode,
@ -27,9 +27,10 @@ pub use unix::*;
#[cfg(any(target_os = "windows"))]
pub use windows::*;
/// This function is not safe
#[allow(clippy::mut_from_ref)]
fn get_wasi_state(ctx: &Ctx) -> &mut WasiState {
unsafe { &mut *(ctx.data as *mut WasiState) }
pub(crate) fn get_wasi_state(ctx: &Ctx) -> &mut WasiState {
unsafe { state::get_wasi_state(&mut *(ctx as *const Ctx as *mut Ctx)) }
}
fn write_bytes<T: Write>(
@ -327,11 +328,6 @@ pub fn fd_close(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t {
Kind::File { ref mut handle, .. } => {
let mut empty_handle = None;
std::mem::swap(handle, &mut empty_handle);
if let Some(handle_inner) = empty_handle {
handle_inner.close()
} else {
return __WASI_EINVAL;
}
}
Kind::Dir { .. } => return __WASI_EISDIR,
Kind::Root { .. } => return __WASI_EACCES,
@ -642,24 +638,13 @@ pub fn fd_pwrite(
let memory = ctx.memory(0);
let iovs_arr_cell = wasi_try!(iovs.deref(memory, 0, iovs_len));
let nwritten_cell = wasi_try!(nwritten.deref(memory));
let state = get_wasi_state(ctx);
let bytes_written = match fd {
0 => return __WASI_EINVAL,
1 => {
let stdout = io::stdout();
let mut handle = stdout.lock();
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
}
2 => {
let stderr = io::stderr();
let mut handle = stderr.lock();
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
}
__WASI_STDIN_FILENO => return __WASI_EINVAL,
__WASI_STDOUT_FILENO => wasi_try!(write_bytes(&mut state.fs.stdout, memory, iovs_arr_cell)),
__WASI_STDERR_FILENO => wasi_try!(write_bytes(&mut state.fs.stderr, memory, iovs_arr_cell)),
_ => {
let state = get_wasi_state(ctx);
let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF));
if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_WRITE) {
@ -740,17 +725,12 @@ pub fn fd_read(
}
Ok(bytes_read)
}
let state = get_wasi_state(ctx);
let bytes_read = match fd {
0 => {
let stdin = io::stdin();
let mut handle = stdin.lock();
wasi_try!(read_bytes(handle, memory, iovs_arr_cell))
}
1 | 2 => return __WASI_EINVAL,
__WASI_STDIN_FILENO => wasi_try!(read_bytes(&mut state.fs.stdin, memory, iovs_arr_cell)),
__WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return __WASI_EINVAL,
_ => {
let state = get_wasi_state(ctx);
let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF));
if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) {
@ -1062,22 +1042,12 @@ pub fn fd_write(
let memory = ctx.memory(0);
let iovs_arr_cell = wasi_try!(iovs.deref(memory, 0, iovs_len));
let nwritten_cell = wasi_try!(nwritten.deref(memory));
let state = get_wasi_state(ctx);
let bytes_written = match fd {
0 => return __WASI_EINVAL,
1 => {
let stdout = io::stdout();
let mut handle = stdout.lock();
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
}
2 => {
let stderr = io::stderr();
let mut handle = stderr.lock();
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
}
__WASI_STDIN_FILENO => return __WASI_EINVAL,
__WASI_STDOUT_FILENO => wasi_try!(write_bytes(&mut state.fs.stdout, memory, iovs_arr_cell)),
__WASI_STDERR_FILENO => wasi_try!(write_bytes(&mut state.fs.stderr, memory, iovs_arr_cell)),
_ => {
let state = get_wasi_state(ctx);
let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF));
@ -1436,7 +1406,7 @@ pub fn path_open(
.create(o_flags & __WASI_O_CREAT != 0)
.truncate(o_flags & __WASI_O_TRUNC != 0);
*handle = Some(WasiFile::HostFile(wasi_try!(open_options
*handle = Some(Box::new(wasi_try!(open_options
.open(&path)
.map_err(|_| __WASI_EIO))));
}
@ -1495,12 +1465,14 @@ pub fn path_open(
.write(true)
.create_new(true);
Some(WasiFile::HostFile(wasi_try!(open_options
.open(&new_file_host_path)
.map_err(|e| {
debug!("Error opening file {}", e);
__WASI_EIO
}))))
Some(
Box::new(wasi_try!(open_options.open(&new_file_host_path).map_err(
|e| {
debug!("Error opening file {}", e);
__WASI_EIO
}
))) as Box<dyn WasiFile>,
)
};
let new_inode = {

View File

@ -19,7 +19,10 @@ pub fn platform_clock_res_get(
};
let (output, timespec_out) = unsafe {
let mut timespec_out: timespec = mem::uninitialized();
let mut timespec_out: timespec = timespec {
tv_sec: 0,
tv_nsec: 0,
};
(clock_getres(unix_clock_id, &mut timespec_out), timespec_out)
};
@ -44,7 +47,10 @@ pub fn platform_clock_time_get(
};
let (output, timespec_out) = unsafe {
let mut timespec_out: timespec = mem::uninitialized();
let mut timespec_out: timespec = timespec {
tv_sec: 0,
tv_nsec: 0,
};
(
clock_gettime(unix_clock_id, &mut timespec_out),
timespec_out,

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-win-exception-handler"
version = "0.5.7"
version = "0.6.0"
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.5.7" }
wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" }
winapi = { version = "0.3", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] }
libc = "0.2.49"

View File

@ -1,10 +1,13 @@
PREVIOUS_VERSION='0.5.6'
NEXT_VERSION='0.5.7'
PREVIOUS_VERSION='0.5.7'
NEXT_VERSION='0.6.0'
# quick hack
fd Cargo.toml --exec sed -i '' "s/version = \"$PREVIOUS_VERSION\"/version = \"$NEXT_VERSION\"/"
echo "manually check changes to Cargo.toml"
fd wasmer.iss --exec sed -i '' "s/AppVersion=$PREVIOUS_VERSION/AppVersion=$NEXT_VERSION/"
echo "manually check changes to wasmer.iss"
# Order to upload packages in
## runtime-core
## win-exception-handler

View File

@ -55,6 +55,7 @@ fn handle_client(mut stream: UnixStream) {
memory_bound_check_mode: MemoryBoundCheckMode::Disable,
enforce_stack_check: true,
track_state: false,
features: Default::default(),
},
&SinglePassCompiler::new(),
)

View File

@ -18,12 +18,12 @@ use wasmer_clif_backend::CraneliftCompiler;
#[cfg(feature = "backend-llvm")]
use wasmer_llvm_backend::LLVMCompiler;
use wasmer_runtime::{
cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH},
Func, Value,
cache::{Cache as BaseCache, FileSystemCache, WasmHash},
Func, Value, VERSION,
};
use wasmer_runtime_core::{
self,
backend::{Backend, Compiler, CompilerConfig, MemoryBoundCheckMode},
backend::{Backend, Compiler, CompilerConfig, Features, MemoryBoundCheckMode},
debug,
loader::{Instance as LoadedInstance, LocalLoader},
};
@ -41,7 +41,12 @@ mod wasmer_wasi {
false
}
pub fn generate_import_object(_args: Vec<Vec<u8>>, _envs: Vec<Vec<u8>>) -> ImportObject {
pub fn generate_import_object(
_args: Vec<Vec<u8>>,
_envs: Vec<Vec<u8>>,
_preopened_files: Vec<String>,
_mapped_dirs: Vec<(String, std::path::PathBuf)>,
) -> ImportObject {
unimplemented!()
}
}
@ -67,6 +72,17 @@ enum CLIOptions {
SelfUpdate,
}
#[derive(Debug, StructOpt)]
struct PrestandardFeatures {
/// Enable support for the SIMD proposal.
#[structopt(long = "enable-simd")]
simd: bool,
/// Enable support for all pre-standard proposals.
#[structopt(long = "enable-all")]
all: bool,
}
#[derive(Debug, StructOpt)]
struct Run {
// Disable the cache
@ -134,6 +150,9 @@ struct Run {
#[structopt(long = "cache-key", hidden = true)]
cache_key: Option<String>,
#[structopt(flatten)]
features: PrestandardFeatures,
/// Application arguments
#[structopt(name = "--", raw(multiple = "true"))]
args: Vec<String>,
@ -185,6 +204,9 @@ struct Validate {
/// Input file
#[structopt(parse(from_os_str))]
path: PathBuf,
#[structopt(flatten)]
features: PrestandardFeatures,
}
/// Read the contents of a file
@ -199,12 +221,16 @@ fn read_file_contents(path: &PathBuf) -> Result<Vec<u8>, io::Error> {
fn get_cache_dir() -> PathBuf {
match env::var("WASMER_CACHE_DIR") {
Ok(dir) => PathBuf::from(dir),
Ok(dir) => {
let mut path = PathBuf::from(dir);
path.push(VERSION);
path
}
Err(_) => {
// We use a temporal directory for saving cache files
let mut temp_dir = env::temp_dir();
temp_dir.push("wasmer");
temp_dir.push(WASMER_VERSION_HASH);
temp_dir.push(VERSION);
temp_dir
}
}
@ -253,10 +279,6 @@ fn get_env_var_args(input: &[String]) -> Result<Vec<(&str, &str)>, String> {
/// Execute a wasm/wat file
fn execute_wasm(options: &Run) -> Result<(), String> {
// force disable caching on windows
#[cfg(target_os = "windows")]
let disable_cache = true;
#[cfg(not(target_os = "windows"))]
let disable_cache = options.disable_cache;
let mapped_dirs = get_mapped_dirs(&options.mapped_dirs[..])?;
@ -315,10 +337,14 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
None
};
// Don't error on --enable-all for other backends.
if options.features.simd && options.backend != Backend::LLVM {
return Err("SIMD is only supported in the LLVM backend for now".to_string());
}
if !utils::is_wasm_binary(&wasm_binary) {
let mut features = wabt::Features::new();
if options.backend == Backend::LLVM {
// SIMD is only supported in the LLVM backend for now
if options.features.simd || options.features.all {
features.enable_simd();
}
wasm_binary = wabt::wat2wasm_with_features(wasm_binary, features)
@ -357,6 +383,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
memory_bound_check_mode: MemoryBoundCheckMode::Disable,
enforce_stack_check: true,
track_state,
features: Features {
simd: options.features.simd || options.features.all,
},
},
&*compiler,
)
@ -367,6 +396,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
CompilerConfig {
symbol_map: em_symbol_map,
track_state,
features: Features {
simd: options.features.simd || options.features.all,
},
..Default::default()
},
&*compiler,
@ -374,7 +406,6 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
.map_err(|e| format!("Can't compile module: {:?}", e))?
} else {
// If we have cache enabled
let wasmer_cache_dir = get_cache_dir();
// We create a new cache instance.
@ -394,7 +425,6 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
return Ok(module);
}
}
// We generate a hash for the given binary, so we can use it as key
// for the Filesystem cache
let hash = WasmHash::generate(&wasm_binary);
@ -413,6 +443,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
CompilerConfig {
symbol_map: em_symbol_map,
track_state,
features: Features {
simd: options.features.simd || options.features.all,
},
..Default::default()
},
&*compiler,
@ -592,11 +625,14 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
if let Err(ref err) = result {
match err {
RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg),
#[cfg(feature = "wasi")]
RuntimeError::Error { data } => {
if let Some(error_code) = data.downcast_ref::<wasmer_wasi::ExitCode>() {
std::process::exit(error_code.code as i32)
}
}
#[cfg(not(feature = "wasi"))]
RuntimeError::Error { .. } => (),
}
panic!("error: {:?}", err)
}
@ -737,8 +773,13 @@ fn validate_wasm(validate: Validate) -> Result<(), String> {
));
}
wasmer_runtime_core::validate_and_report_errors(&wasm_binary)
.map_err(|err| format!("Validation failed: {}", err))?;
wasmer_runtime_core::validate_and_report_errors_with_features(
&wasm_binary,
Features {
simd: validate.features.simd || validate.features.all,
},
)
.map_err(|err| format!("Validation failed: {}", err))?;
Ok(())
}
@ -764,7 +805,6 @@ fn main() {
CLIOptions::SelfUpdate => {
println!("Self update is not supported on Windows. Use install instructions on the Wasmer homepage: https://wasmer.io");
}
#[cfg(not(target_os = "windows"))]
CLIOptions::Cache(cache) => match cache {
Cache::Clean => {
use std::fs;
@ -781,9 +821,14 @@ fn main() {
CLIOptions::Validate(validate_options) => {
validate(validate_options);
}
#[cfg(target_os = "windows")]
CLIOptions::Cache(_) => {
println!("Caching is disabled for Windows.");
}
}
}
#[test]
fn filesystem_cache_should_work() -> Result<(), String> {
let wasmer_cache_dir = get_cache_dir();
unsafe { FileSystemCache::new(wasmer_cache_dir).map_err(|e| format!("Cache error: {:?}", e))? };
Ok(())
}

View File

@ -1,6 +1,6 @@
[Setup]
AppName=Wasmer
AppVersion=0.4.0
AppVersion=0.6.0
DefaultDirName={pf}\Wasmer
DefaultGroupName=Wasmer
Compression=lzma2
@ -82,4 +82,4 @@ begin
EnvRemovePath(ExpandConstant('{app}') +'\bin');
EnvAddPath(ExpandConstant('{%USERPROFILE}') +'\globals\wapm_packages\.bin');
end
end;
end;

@ -1 +1 @@
Subproject commit 62ec59a53ca3df84019092a750aeb56e08b9d556
Subproject commit b157153568fc45f0d01ba8443c54fc3c2ce0cb23