mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-12 22:05:33 +00:00
Merge branch 'master' into wasmer-c-api-error-visibility
This commit is contained in:
commit
a832a4c787
@ -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
|
||||
|
@ -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:
|
||||
|
12
CHANGELOG.md
12
CHANGELOG.md
@ -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
20
Cargo.lock
generated
@ -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"
|
||||
|
23
Cargo.toml
23
Cargo.toml
@ -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
13
Dockerfile.build
Normal 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"
|
16
Makefile
16
Makefile
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
79
build
Executable 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
BIN
examples/particle-repel-simd.wasm
Executable file
Binary file not shown.
BIN
examples/particle-repel.wasm
Executable file
BIN
examples/particle-repel.wasm
Executable file
Binary file not shown.
Binary file not shown.
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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"]
|
||||
|
@ -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(),
|
||||
)?;
|
||||
|
@ -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>"]
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
21
lib/emscripten/src/env/unix/mod.rs
vendored
21
lib/emscripten/src/env/unix/mod.rs
vendored
@ -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(),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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() };
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
// doesn’t 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);
|
||||
}
|
||||
|
@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<
|
||||
|
3
lib/llvm-backend/src/platform/common.rs
Normal file
3
lib/llvm-backend/src/platform/common.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub fn round_up_to_page_size(size: usize) -> usize {
|
||||
(size + (4096 - 1)) & !(4096 - 1)
|
||||
}
|
@ -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");
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
80
lib/llvm-backend/src/platform/win.rs
Normal file
80
lib/llvm-backend/src/platform/win.rs
Normal 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,
|
||||
}
|
||||
}
|
39
lib/llvm-backend/src/structs.rs
Normal file
39
lib/llvm-backend/src/structs.rs
Normal 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)),
|
||||
}
|
@ -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"
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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>"]
|
||||
|
@ -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"]
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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" = []
|
||||
|
@ -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 {
|
||||
|
@ -20,6 +20,7 @@ pub enum Error {
|
||||
Unknown(String),
|
||||
InvalidFile(InvalidFileType),
|
||||
InvalidatedCache,
|
||||
UnsupportedBackend(Backend),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
34
lib/spectests/spectests/simd_binaryen.wast
vendored
34
lib/spectests/spectests/simd_binaryen.wast
vendored
@ -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))
|
||||
|
@ -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 = []
|
||||
|
@ -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" }
|
||||
|
@ -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;
|
||||
|
@ -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()?,
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
)
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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;
|
||||
|
2
wapm-cli
2
wapm-cli
@ -1 +1 @@
|
||||
Subproject commit 62ec59a53ca3df84019092a750aeb56e08b9d556
|
||||
Subproject commit b157153568fc45f0d01ba8443c54fc3c2ce0cb23
|
Loading…
Reference in New Issue
Block a user