mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 06:01:33 +00:00
Merge branch 'master' into feature/clif-cgapi
This commit is contained in:
@ -6,6 +6,7 @@ branches:
|
|||||||
only:
|
only:
|
||||||
- staging
|
- staging
|
||||||
- trying
|
- trying
|
||||||
|
- master
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
@ -17,6 +18,7 @@ environment:
|
|||||||
cache:
|
cache:
|
||||||
- 'C:\Users\appveyor\.cargo'
|
- 'C:\Users\appveyor\.cargo'
|
||||||
- target
|
- target
|
||||||
|
- wapm-cli-target
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# # Install LLVM
|
# # Install LLVM
|
||||||
@ -47,7 +49,21 @@ install:
|
|||||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- cargo build --release --verbose
|
- cargo build --release --verbose
|
||||||
|
# Now we build wapm
|
||||||
|
- 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
|
||||||
|
- cd wapm-cli
|
||||||
|
- rename target wapm-cli-target
|
||||||
|
- cd ..
|
||||||
|
- move wapm-cli\wapm-cli-target wapm-cli-target
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
- cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||||
@ -66,7 +82,7 @@ deploy:
|
|||||||
description: 'WasmerInstaller'
|
description: 'WasmerInstaller'
|
||||||
artifact: /.*\.exe/
|
artifact: /.*\.exe/
|
||||||
auth_token:
|
auth_token:
|
||||||
secure: CaKtncy7S1PWxzDUQ0p2264pe3HwxzDn5VIyRizDaa72/SVfskNcoMjwwRh0ut22
|
secure: BbreGNDJy20922za7OhJG5TERzfX+dJSBQwttNTJkLvszbqMov6hhAtRb3P45hpf
|
||||||
provider: GitHub
|
provider: GitHub
|
||||||
on:
|
on:
|
||||||
branch: master
|
branch: master
|
||||||
|
@ -30,7 +30,6 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-lint-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- v8-lint-{{ arch }}
|
|
||||||
- <<: *run_install_dependencies
|
- <<: *run_install_dependencies
|
||||||
- run:
|
- run:
|
||||||
name: Install lint deps
|
name: Install lint deps
|
||||||
@ -60,7 +59,6 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-test-cargo-cache-linux-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- v8-test-cargo-cache-linux-stable-{{ arch }}
|
|
||||||
- <<: *run_install_dependencies
|
- <<: *run_install_dependencies
|
||||||
- run:
|
- run:
|
||||||
name: Tests
|
name: Tests
|
||||||
@ -89,7 +87,6 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-cargo-cache-darwin-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-cargo-cache-darwin-stable-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- v8-cargo-cache-darwin-stable-{{ arch }}
|
|
||||||
- run:
|
- run:
|
||||||
name: Install crate dependencies
|
name: Install crate dependencies
|
||||||
command: |
|
command: |
|
||||||
@ -154,11 +151,10 @@ jobs:
|
|||||||
name: "Pull dependencies"
|
name: "Pull dependencies"
|
||||||
command: |
|
command: |
|
||||||
git submodule init
|
git submodule init
|
||||||
git submodule update --remote
|
git submodule update
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- v8-cargo-cache-linux-nightly-{{ arch }}
|
|
||||||
- run:
|
- run:
|
||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
command: |
|
command: |
|
||||||
@ -178,6 +174,10 @@ jobs:
|
|||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
make test-emscripten-clif
|
make test-emscripten-clif
|
||||||
make test-emscripten-llvm
|
make test-emscripten-llvm
|
||||||
|
- run:
|
||||||
|
name: Debug flag checked
|
||||||
|
command: |
|
||||||
|
cargo check --features "debug"
|
||||||
- run:
|
- run:
|
||||||
name: Release Build
|
name: Release Build
|
||||||
command: |
|
command: |
|
||||||
@ -191,10 +191,6 @@ jobs:
|
|||||||
echo "${CIRCLE_TAG}" >> artifacts/git_version
|
echo "${CIRCLE_TAG}" >> artifacts/git_version
|
||||||
make build-install
|
make build-install
|
||||||
cp ./wasmer.tar.gz ./artifacts/$(./binary-name.sh)
|
cp ./wasmer.tar.gz ./artifacts/$(./binary-name.sh)
|
||||||
- run:
|
|
||||||
name: Debug flag checked
|
|
||||||
command: |
|
|
||||||
cargo check --features "debug"
|
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: .
|
root: .
|
||||||
paths:
|
paths:
|
||||||
@ -222,11 +218,10 @@ jobs:
|
|||||||
name: "Pull dependencies"
|
name: "Pull dependencies"
|
||||||
command: |
|
command: |
|
||||||
git submodule init
|
git submodule init
|
||||||
git submodule update --remote
|
git submodule update
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-cargo-cache-darwin-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-cargo-cache-darwin-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- v8-cargo-cache-darwin-nightly-{{ arch }}
|
|
||||||
- run:
|
- run:
|
||||||
name: Install crate dependencies
|
name: Install crate dependencies
|
||||||
command: |
|
command: |
|
||||||
@ -309,13 +304,18 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
- v8-cargo-cache-linux-nightly-{{ arch }}-{{ checksum "Cargo.lock" }}
|
||||||
- v8-cargo-cache-linux-nightly-{{ arch }}
|
|
||||||
- run:
|
- run:
|
||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
command: |
|
command: |
|
||||||
sudo apt-get install -y cmake
|
sudo apt-get install -y cmake
|
||||||
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
|
rustup toolchain install nightly
|
||||||
|
rustup target add wasm32-wasi --toolchain nightly
|
||||||
|
- run: |
|
||||||
|
rustup default nightly
|
||||||
|
make test-wasi-singlepass
|
||||||
|
make test-wasi-clif
|
||||||
- run: rustup default nightly-2019-04-11
|
- run: rustup default nightly-2019-04-11
|
||||||
- run: |
|
- run: |
|
||||||
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
@ -372,7 +372,6 @@ jobs:
|
|||||||
-d build_parameters[CIRCLE_JOB]=bench \
|
-d build_parameters[CIRCLE_JOB]=bench \
|
||||||
https://circleci.com/api/v1.1/project/github/wasmerio/wasmer-bench/tree/master
|
https://circleci.com/api/v1.1/project/github/wasmerio/wasmer-bench/tree/master
|
||||||
fi
|
fi
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
main:
|
main:
|
||||||
|
18
CHANGELOG.md
18
CHANGELOG.md
@ -6,6 +6,18 @@ Blocks of changes will separated by version increments.
|
|||||||
|
|
||||||
## **[Unreleased]**
|
## **[Unreleased]**
|
||||||
|
|
||||||
|
- [#467](https://github.com/wasmerio/wasmer/pull/467) `wasmer_instantiate` returns better error messages in the runtime C API
|
||||||
|
- [#463](https://github.com/wasmerio/wasmer/pull/463) Fix bug in WASI path_open allowing one level above preopened dir to be accessed
|
||||||
|
- [#461](https://github.com/wasmerio/wasmer/pull/461) Prevent passing negative lengths in various places in the runtime C API
|
||||||
|
- [#459](https://github.com/wasmerio/wasmer/pull/459) Add monotonic and real time clocks for wasi on windows
|
||||||
|
- [#447](https://github.com/wasmerio/wasmer/pull/447) Add trace macro (`--features trace`) for more verbose debug statements
|
||||||
|
- [#451](https://github.com/wasmerio/wasmer/pull/451) Add `--mapdir=src:dest` flag to rename host directories in the guest context
|
||||||
|
- [#457](https://github.com/wasmerio/wasmer/pull/457) Implement file metadata for WASI, fix bugs in WASI clock code for Unix platforms
|
||||||
|
|
||||||
|
## 0.4.2 - 2019-05-16
|
||||||
|
|
||||||
|
- [#416](https://github.com/wasmerio/wasmer/pull/416) Remote code loading framework
|
||||||
|
- [#449](https://github.com/wasmerio/wasmer/pull/449) Fix bugs: opening host files in filestat and opening with write permissions unconditionally in path_open
|
||||||
- [#442](https://github.com/wasmerio/wasmer/pull/442) Misc. WASI FS fixes and implement readdir
|
- [#442](https://github.com/wasmerio/wasmer/pull/442) Misc. WASI FS fixes and implement readdir
|
||||||
- [#440](https://github.com/wasmerio/wasmer/pull/440) Fix type mismatch between `wasmer_instance_call` and `wasmer_export_func_*_arity` functions in the runtime C API.
|
- [#440](https://github.com/wasmerio/wasmer/pull/440) Fix type mismatch between `wasmer_instance_call` and `wasmer_export_func_*_arity` functions in the runtime C API.
|
||||||
- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs
|
- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs
|
||||||
@ -13,7 +25,7 @@ Blocks of changes will separated by version increments.
|
|||||||
- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements
|
- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements
|
||||||
- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits
|
- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits
|
||||||
|
|
||||||
## 0.4.1 - 2018-05-06
|
## 0.4.1 - 2019-05-06
|
||||||
|
|
||||||
- [#426](https://github.com/wasmerio/wasmer/pull/426) Update wapm-cli submodule, bump version to 0.4.1
|
- [#426](https://github.com/wasmerio/wasmer/pull/426) Update wapm-cli submodule, bump version to 0.4.1
|
||||||
- [#422](https://github.com/wasmerio/wasmer/pull/422) Improved Emscripten functions to run optipng and pngquant compiled to wasm
|
- [#422](https://github.com/wasmerio/wasmer/pull/422) Improved Emscripten functions to run optipng and pngquant compiled to wasm
|
||||||
@ -23,7 +35,7 @@ Blocks of changes will separated by version increments.
|
|||||||
- [#390](https://github.com/wasmerio/wasmer/pull/390) Pin released wapm version and add it as a git submodule
|
- [#390](https://github.com/wasmerio/wasmer/pull/390) Pin released wapm version and add it as a git submodule
|
||||||
- [#408](https://github.com/wasmerio/wasmer/pull/408) Add images to windows installer and update installer to add wapm bin directory to path
|
- [#408](https://github.com/wasmerio/wasmer/pull/408) Add images to windows installer and update installer to add wapm bin directory to path
|
||||||
|
|
||||||
## 0.4.0 - 2018-04-23
|
## 0.4.0 - 2019-04-23
|
||||||
|
|
||||||
- [#383](https://github.com/wasmerio/wasmer/pull/383) Hook up wasi exit code to wasmer cli.
|
- [#383](https://github.com/wasmerio/wasmer/pull/383) Hook up wasi exit code to wasmer cli.
|
||||||
- [#382](https://github.com/wasmerio/wasmer/pull/382) Improve error message on `--backend` flag to only suggest currently enabled backends
|
- [#382](https://github.com/wasmerio/wasmer/pull/382) Improve error message on `--backend` flag to only suggest currently enabled backends
|
||||||
@ -41,7 +53,7 @@ Blocks of changes will separated by version increments.
|
|||||||
- [#350](https://github.com/wasmerio/wasmer/pull/350) Enforce that CHANGELOG.md is updated through CI.
|
- [#350](https://github.com/wasmerio/wasmer/pull/350) Enforce that CHANGELOG.md is updated through CI.
|
||||||
- [#349](https://github.com/wasmerio/wasmer/pull/349) Add [CHANGELOG.md](https://github.com/wasmerio/wasmer/blob/master/CHANGELOG.md).
|
- [#349](https://github.com/wasmerio/wasmer/pull/349) Add [CHANGELOG.md](https://github.com/wasmerio/wasmer/blob/master/CHANGELOG.md).
|
||||||
|
|
||||||
## 0.3.0 - 2018-04-12
|
## 0.3.0 - 2019-04-12
|
||||||
|
|
||||||
- [#276](https://github.com/wasmerio/wasmer/pull/276) [#288](https://github.com/wasmerio/wasmer/pull/288) [#344](https://github.com/wasmerio/wasmer/pull/344) Use new singlepass backend (with the `--backend=singlepass` when running Wasmer)
|
- [#276](https://github.com/wasmerio/wasmer/pull/276) [#288](https://github.com/wasmerio/wasmer/pull/288) [#344](https://github.com/wasmerio/wasmer/pull/344) Use new singlepass backend (with the `--backend=singlepass` when running Wasmer)
|
||||||
- [#338](https://github.com/wasmerio/wasmer/pull/338) Actually catch traps/panics/etc when using a typed func.
|
- [#338](https://github.com/wasmerio/wasmer/pull/338) Actually catch traps/panics/etc when using a typed func.
|
||||||
|
1521
Cargo.lock
generated
1521
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
30
Cargo.toml
30
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer"
|
name = "wasmer"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
@ -19,6 +19,7 @@ include = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
byteorder = "1.3.1"
|
||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
structopt = "0.2.11"
|
structopt = "0.2.11"
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
@ -27,14 +28,33 @@ wasmer-clif-backend = { path = "lib/clif-backend" }
|
|||||||
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
|
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true }
|
||||||
wasmer-middleware-common = { path = "lib/middleware-common" }
|
wasmer-middleware-common = { path = "lib/middleware-common" }
|
||||||
wasmer-runtime = { path = "lib/runtime" }
|
wasmer-runtime = { path = "lib/runtime" }
|
||||||
wasmer-runtime-abi = { path = "lib/runtime-abi", optional = true }
|
# wasmer-runtime-abi = { path = "lib/runtime-abi", optional = true }
|
||||||
wasmer-runtime-core = { path = "lib/runtime-core" }
|
wasmer-runtime-core = { path = "lib/runtime-core" }
|
||||||
wasmer-emscripten = { path = "lib/emscripten" }
|
wasmer-emscripten = { path = "lib/emscripten" }
|
||||||
wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
|
wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
|
||||||
wasmer-wasi = { path = "lib/wasi", optional = true }
|
wasmer-wasi = { path = "lib/wasi", optional = true }
|
||||||
|
wasmer-kernel-loader = { path = "lib/kernel-loader", optional = true }
|
||||||
|
wasmer-dev-utils = { path = "lib/dev-utils", optional = true }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["lib/clif-backend", "lib/singlepass-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi", "lib/middleware-common", "examples/plugin-for-example"]
|
members = [
|
||||||
|
"lib/clif-backend",
|
||||||
|
"lib/singlepass-backend",
|
||||||
|
"lib/runtime",
|
||||||
|
# "lib/runtime-abi",
|
||||||
|
"lib/runtime-core",
|
||||||
|
"lib/emscripten",
|
||||||
|
"lib/spectests",
|
||||||
|
"lib/win-exception-handler",
|
||||||
|
"lib/runtime-c-api",
|
||||||
|
"lib/llvm-backend",
|
||||||
|
"lib/wasi",
|
||||||
|
"lib/middleware-common",
|
||||||
|
"lib/kernel-loader",
|
||||||
|
"lib/kernel-net",
|
||||||
|
"lib/dev-utils",
|
||||||
|
"examples/plugin-for-example"
|
||||||
|
]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
@ -43,14 +63,16 @@ rustc_version = "0.2.3"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fast-tests", "wasi"]
|
default = ["fast-tests", "wasi"]
|
||||||
|
"loader:kernel" = ["wasmer-kernel-loader"]
|
||||||
debug = ["wasmer-runtime-core/debug"]
|
debug = ["wasmer-runtime-core/debug"]
|
||||||
|
trace = ["wasmer-runtime-core/trace"]
|
||||||
extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||||
# This feature will allow cargo test to run much faster
|
# This feature will allow cargo test to run much faster
|
||||||
fast-tests = []
|
fast-tests = []
|
||||||
"backend:llvm" = ["wasmer-llvm-backend"]
|
"backend:llvm" = ["wasmer-llvm-backend"]
|
||||||
"backend:singlepass" = ["wasmer-singlepass-backend"]
|
"backend:singlepass" = ["wasmer-singlepass-backend"]
|
||||||
wasi = ["wasmer-wasi"]
|
wasi = ["wasmer-wasi"]
|
||||||
vfs = ["wasmer-runtime-abi"]
|
# vfs = ["wasmer-runtime-abi"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "plugin"
|
name = "plugin"
|
||||||
|
23
Makefile
23
Makefile
@ -12,6 +12,9 @@ spectests:
|
|||||||
emtests:
|
emtests:
|
||||||
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten
|
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten
|
||||||
|
|
||||||
|
wasitests:
|
||||||
|
WASM_WASI_GENERATE_WASITESTS=1 cargo build -p wasmer-wasi
|
||||||
|
|
||||||
# clean:
|
# clean:
|
||||||
# rm -rf artifacts
|
# rm -rf artifacts
|
||||||
|
|
||||||
@ -45,7 +48,7 @@ do-install:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
# We use one thread so the emscripten stdouts doesn't collide
|
# We use one thread so the emscripten stdouts doesn't collide
|
||||||
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-singlepass-backend -- $(runargs)
|
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-singlepass-backend --exclude wasmer-wasi -- $(runargs)
|
||||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
||||||
@ -66,14 +69,20 @@ test-emscripten-clif:
|
|||||||
test-emscripten-singlepass:
|
test-emscripten-singlepass:
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features singlepass -- --test-threads=1 $(runargs)
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features singlepass -- --test-threads=1 $(runargs)
|
||||||
|
|
||||||
|
test-wasi-clif:
|
||||||
|
cargo test --manifest-path lib/wasi/Cargo.toml --features "clif" -- --test-threads=1 $(runargs)
|
||||||
|
|
||||||
|
test-wasi-singlepass:
|
||||||
|
cargo test --manifest-path lib/wasi/Cargo.toml --features "singlepass" -- --test-threads=1 $(runargs)
|
||||||
|
|
||||||
singlepass-debug-release:
|
singlepass-debug-release:
|
||||||
cargo +nightly build --features "backend:singlepass debug" --release
|
cargo +nightly build --features backend:singlepass,debug --release
|
||||||
|
|
||||||
singlepass-release:
|
singlepass-release:
|
||||||
cargo +nightly build --features "backend:singlepass" --release
|
cargo +nightly build --features backend:singlepass --release
|
||||||
|
|
||||||
singlepass-build:
|
singlepass-build:
|
||||||
cargo +nightly build --features "backend:singlepass debug"
|
cargo +nightly build --features backend:singlepass,debug
|
||||||
|
|
||||||
release:
|
release:
|
||||||
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
# If you are in OS-X, you will need mingw-w64 for cross compiling to windows
|
||||||
@ -81,13 +90,13 @@ release:
|
|||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
production-release:
|
production-release:
|
||||||
cargo build --release --features backend:singlepass,backend:llvm
|
cargo build --release --features backend:singlepass,backend:llvm,loader:kernel
|
||||||
|
|
||||||
debug-release:
|
debug-release:
|
||||||
cargo build --release --features "debug"
|
cargo build --release --features debug
|
||||||
|
|
||||||
extra-debug-release:
|
extra-debug-release:
|
||||||
cargo build --release --features "extra-debug"
|
cargo build --release --features extra-debug
|
||||||
|
|
||||||
publish-release:
|
publish-release:
|
||||||
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/
|
ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
[Wasmer](https://wasmer.io/) is a standalone JIT WebAssembly runtime, aiming to be fully compatible with [WASI](https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/) and [Emscripten](https://emscripten.org/).
|
[Wasmer](https://wasmer.io/) is a standalone JIT WebAssembly runtime, aiming to be fully compatible with [WASI](https://github.com/WebAssembly/WASI) and [Emscripten](https://emscripten.org/).
|
||||||
|
|
||||||
Install Wasmer with:
|
Install Wasmer with:
|
||||||
|
|
||||||
|
13
examples/echo-server/Cargo.lock
generated
Normal file
13
examples/echo-server/Cargo.lock
generated
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "echo-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"kernel-net 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel-net"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
10
examples/echo-server/Cargo.toml
Normal file
10
examples/echo-server/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "echo-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
kernel-net = { path = "../../lib/kernel-net" }
|
49
examples/echo-server/src/main.rs
Normal file
49
examples/echo-server/src/main.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#![feature(wasi_ext)]
|
||||||
|
|
||||||
|
use kernel_net::{schedule, Epoll, Tcp4Listener, TcpStream};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
fn do_echo(stream: Arc<TcpStream>, buf: Vec<u8>) {
|
||||||
|
let stream2 = stream.clone();
|
||||||
|
stream.read_async(buf, move |result| match result {
|
||||||
|
Ok(buf) => {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let stream = stream2.clone();
|
||||||
|
stream2.write_all_async(buf, move |result| match result {
|
||||||
|
Ok(buf) => {
|
||||||
|
schedule(|| {
|
||||||
|
do_echo(stream, buf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
println!("failed to write; code = {}", code);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
println!("failed to read; code = {}", code);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let epoll = Arc::new(Epoll::new());
|
||||||
|
let listener = Arc::new(Tcp4Listener::new("0.0.0.0", 2001, 128).unwrap());
|
||||||
|
|
||||||
|
listener.accept_async(epoll.clone(), |stream| match stream {
|
||||||
|
Ok(stream) => {
|
||||||
|
do_echo(stream, Vec::with_capacity(16384));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
println!("failed to accept; code = {}", code);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
println!("start epoll");
|
||||||
|
unsafe {
|
||||||
|
epoll.run();
|
||||||
|
}
|
||||||
|
}
|
13
examples/http-server/Cargo.lock
generated
Normal file
13
examples/http-server/Cargo.lock
generated
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "http-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"kernel-net 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel-net"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
12
examples/http-server/Cargo.toml
Normal file
12
examples/http-server/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "http-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
kernel-net = { path = "../../lib/kernel-net" }
|
72
examples/http-server/src/main.rs
Normal file
72
examples/http-server/src/main.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#![feature(wasi_ext)]
|
||||||
|
|
||||||
|
use kernel_net::{schedule, Epoll, Tcp4Listener, TcpStream};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
fn serve(stream: Arc<TcpStream>, mut all: Vec<u8>) {
|
||||||
|
let stream2 = stream.clone();
|
||||||
|
stream.read_async(
|
||||||
|
Vec::with_capacity(512),
|
||||||
|
move |result| {
|
||||||
|
match result {
|
||||||
|
Ok(buf) => {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
all.extend_from_slice(&buf);
|
||||||
|
if all.len() > 4096 {
|
||||||
|
println!("header too large");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let s = match ::std::str::from_utf8(&all) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
println!("not utf8: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(_pos) = s.find("\r\n\r\n") {
|
||||||
|
let body = format!(
|
||||||
|
"Hello, world!\n",
|
||||||
|
).into_bytes();
|
||||||
|
let stream = stream2.clone();
|
||||||
|
stream2.write_all_async(
|
||||||
|
format!(
|
||||||
|
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: {}\r\n\r\n",
|
||||||
|
body.len()
|
||||||
|
).into_bytes(),
|
||||||
|
|_| {
|
||||||
|
stream.write_all_async(body, |_| {});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
schedule(|| serve(stream2, all));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
println!("failed to read; code = {}", code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let epoll = Arc::new(Epoll::new());
|
||||||
|
let listener = Arc::new(Tcp4Listener::new("0.0.0.0", 2011, 128).unwrap());
|
||||||
|
|
||||||
|
listener.accept_async(epoll.clone(), |stream| match stream {
|
||||||
|
Ok(stream) => {
|
||||||
|
serve(stream, vec![]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
println!("failed to accept; code = {}", code);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
println!("start epoll");
|
||||||
|
unsafe {
|
||||||
|
epoll.run();
|
||||||
|
}
|
||||||
|
}
|
9
examples/pipe/Cargo.toml
Normal file
9
examples/pipe/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "pipe"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
13
examples/pipe/src/main.rs
Normal file
13
examples/pipe/src/main.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut stdin = ::std::io::stdin();
|
||||||
|
let mut stdout = ::std::io::stdout();
|
||||||
|
let mut buf: Vec<u8> = vec![0; 512];
|
||||||
|
let mut total: u64 = 0;
|
||||||
|
while total < 1048576u64 * 2048 {
|
||||||
|
let n = stdin.read(&mut buf).unwrap();
|
||||||
|
stdout.write_all(&buf[..n]).unwrap();
|
||||||
|
total += n as u64;
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ fn main() {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// WASI imports
|
// WASI imports
|
||||||
let mut base_imports = generate_import_object(vec![], vec![], vec![]);
|
let mut base_imports = generate_import_object(vec![], vec![], vec![], vec![]);
|
||||||
// env is the default namespace for extern functions
|
// env is the default namespace for extern functions
|
||||||
let custom_imports = imports! {
|
let custom_imports = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-clif-backend"
|
name = "wasmer-clif-backend"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer runtime Cranelift compiler backend"
|
description = "Wasmer runtime Cranelift compiler backend"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -8,19 +8,12 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
# cranelift-native = { path = "../../../cranelift/cranelift-native" }
|
|
||||||
# cranelift-codegen = { path = "../../../cranelift/cranelift-codegen" }
|
|
||||||
# cranelift-entity = { path = "../../../cranelift/cranelift-entity" }
|
|
||||||
# cranelift-frontend = { path = "../../../cranelift/cranelift-frontend" }
|
|
||||||
# cranelift-wasm = { path = "../../../cranelift/cranelift-wasm" }
|
|
||||||
cranelift-native = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
cranelift-native = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
||||||
cranelift-codegen = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
cranelift-codegen = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
||||||
cranelift-entity = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
cranelift-entity = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
||||||
cranelift-frontend = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
cranelift-frontend = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
||||||
cranelift-wasm = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
cranelift-wasm = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" }
|
||||||
|
|
||||||
|
|
||||||
hashbrown = "0.1"
|
hashbrown = "0.1"
|
||||||
target-lexicon = "0.4.0"
|
target-lexicon = "0.4.0"
|
||||||
wasmparser = "0.29.2"
|
wasmparser = "0.29.2"
|
||||||
@ -41,7 +34,7 @@ version = "0.0.7"
|
|||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||||
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.4.1" }
|
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.4.2" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = ["wasmer-runtime-core/debug"]
|
debug = ["wasmer-runtime-core/debug"]
|
||||||
|
11
lib/dev-utils/Cargo.toml
Normal file
11
lib/dev-utils/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasmer-dev-utils"
|
||||||
|
version = "0.4.2"
|
||||||
|
description = "Wasmer runtime core library"
|
||||||
|
license = "MIT"
|
||||||
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2.49"
|
3
lib/dev-utils/README.md
Normal file
3
lib/dev-utils/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Dev Utils
|
||||||
|
|
||||||
|
This is shared code between the modules for testing and development only. Code in this crate will not be shipped.
|
2
lib/dev-utils/src/lib.rs
Normal file
2
lib/dev-utils/src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod file_descriptor;
|
||||||
|
pub mod stdio;
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-emscripten"
|
name = "wasmer-emscripten"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer runtime emscripten implementation library"
|
description = "Wasmer runtime emscripten implementation library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,20 +9,21 @@ edition = "2018"
|
|||||||
build = "build/mod.rs"
|
build = "build/mod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
libc = "0.2.49"
|
libc = "0.2.49"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
time = "0.1.41"
|
time = "0.1.41"
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.1" }
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" }
|
||||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.1", optional = true }
|
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
|
||||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.1", optional = true }
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.2", optional = true }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
rand = "0.6"
|
rand = "0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
wasmer-dev-utils = { path = "../dev-utils", version = "0.4.2"}
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
glob = "0.2.11"
|
glob = "0.2.11"
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
//! - Generate the test that will compare the output of running the .wasm file
|
//! - Generate the test that will compare the output of running the .wasm file
|
||||||
//! with wasmer with the expected output
|
//! with wasmer with the expected output
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -20,7 +21,7 @@ static BANNER: &str = "// Rust test file autogenerated with cargo build (build/e
|
|||||||
const EXTENSIONS: [&str; 2] = ["c", "cpp"];
|
const EXTENSIONS: [&str; 2] = ["c", "cpp"];
|
||||||
const EXCLUDES: [&str; 0] = [];
|
const EXCLUDES: [&str; 0] = [];
|
||||||
|
|
||||||
pub fn compile(file: &str, ignores: &Vec<String>) -> Option<String> {
|
pub fn compile(file: &str, ignores: &HashSet<String>) -> Option<String> {
|
||||||
let mut output_path = PathBuf::from(file);
|
let mut output_path = PathBuf::from(file);
|
||||||
output_path.set_extension("out");
|
output_path.set_extension("out");
|
||||||
// let output_str = output_path.to_str().unwrap();
|
// let output_str = output_path.to_str().unwrap();
|
||||||
@ -49,11 +50,7 @@ pub fn compile(file: &str, ignores: &Vec<String>) -> Option<String> {
|
|||||||
let wasm_file_metadata = {
|
let wasm_file_metadata = {
|
||||||
let mut wasm_file_path = PathBuf::from(file);
|
let mut wasm_file_path = PathBuf::from(file);
|
||||||
wasm_file_path.set_extension("wasm");
|
wasm_file_path.set_extension("wasm");
|
||||||
if let Ok(wasm_file) = File::open(wasm_file_path) {
|
File::open(wasm_file_path).and_then(|wf| wf.metadata()).ok()
|
||||||
Some(wasm_file.metadata().unwrap())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let real_file = File::open(file).unwrap();
|
let real_file = File::open(file).unwrap();
|
||||||
@ -111,10 +108,7 @@ pub fn compile(file: &str, ignores: &Vec<String>) -> Option<String> {
|
|||||||
"txt"
|
"txt"
|
||||||
};
|
};
|
||||||
|
|
||||||
let ignored = if ignores
|
let ignored = if ignores.contains(&module_name.to_lowercase()) {
|
||||||
.iter()
|
|
||||||
.any(|i| &i.to_lowercase() == &module_name.to_lowercase())
|
|
||||||
{
|
|
||||||
"\n#[ignore]"
|
"\n#[ignore]"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
@ -193,8 +187,11 @@ pub fn build() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_ignore_list() -> Vec<String> {
|
fn read_ignore_list() -> HashSet<String> {
|
||||||
let f = File::open("emtests/ignores.txt").unwrap();
|
let f = File::open("emtests/ignores.txt").unwrap();
|
||||||
let f = BufReader::new(f);
|
let f = BufReader::new(f);
|
||||||
f.lines().filter_map(Result::ok).collect()
|
f.lines()
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.map(|v| v.to_lowercase())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,18 @@
|
|||||||
- **\_pthread_key_create** [:top:](#host-apis)
|
- **\_pthread_key_create** [:top:](#host-apis)
|
||||||
```rust
|
```rust
|
||||||
|
|
||||||
|
```
|
||||||
|
- **\_pthread_rwlock_destroy** [:top:](#host-apis)
|
||||||
|
```rust
|
||||||
|
|
||||||
|
```
|
||||||
|
- **\_pthread_rwlock_init** [:top:](#host-apis)
|
||||||
|
```rust
|
||||||
|
|
||||||
|
```
|
||||||
|
- **\_pthread_rwlock_wrlock** [:top:](#host-apis)
|
||||||
|
```rust
|
||||||
|
|
||||||
```
|
```
|
||||||
- **\_pthread_setspecific** [:top:](#host-apis)
|
- **\_pthread_setspecific** [:top:](#host-apis)
|
||||||
```rust
|
```rust
|
||||||
|
@ -15,6 +15,11 @@ pub fn getTempRet0(ctx: &mut Ctx) -> i32 {
|
|||||||
get_emscripten_data(ctx).temp_ret_0
|
get_emscripten_data(ctx).temp_ret_0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn _alarm(_ctx: &mut Ctx, _seconds: u32) -> i32 {
|
||||||
|
debug!("emscripten::_alarm({})", _seconds);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
pub fn _atexit(_ctx: &mut Ctx, _func: i32) -> i32 {
|
pub fn _atexit(_ctx: &mut Ctx, _func: i32) -> i32 {
|
||||||
debug!("emscripten::_atexit");
|
debug!("emscripten::_atexit");
|
||||||
// TODO: implement atexit properly
|
// TODO: implement atexit properly
|
||||||
@ -105,6 +110,18 @@ pub fn _pthread_key_create(_ctx: &mut Ctx, _a: i32, _b: i32) -> i32 {
|
|||||||
debug!("emscripten::_pthread_key_create");
|
debug!("emscripten::_pthread_key_create");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
pub fn _pthread_rwlock_destroy(_ctx: &mut Ctx, _rwlock: i32) -> i32 {
|
||||||
|
debug!("emscripten::_pthread_rwlock_destroy({})", _rwlock);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
pub fn _pthread_rwlock_init(_ctx: &mut Ctx, _rwlock: i32, _attr: i32) -> i32 {
|
||||||
|
debug!("emscripten::_pthread_rwlock_init({}, {})", _rwlock, _attr);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
pub fn _pthread_rwlock_wrlock(_ctx: &mut Ctx, _rwlock: i32) -> i32 {
|
||||||
|
debug!("emscripten::_pthread_rwlock_wrlock({})", _rwlock);
|
||||||
|
0
|
||||||
|
}
|
||||||
pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
|
pub fn _pthread_create(_ctx: &mut Ctx, _a: i32, _b: i32, _c: i32, _d: i32) -> i32 {
|
||||||
debug!("emscripten::_pthread_create");
|
debug!("emscripten::_pthread_create");
|
||||||
0
|
0
|
||||||
@ -185,6 +202,12 @@ pub fn ___gxx_personality_v0(
|
|||||||
debug!("emscripten::___gxx_personality_v0");
|
debug!("emscripten::___gxx_personality_v0");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn _gai_strerror(_ctx: &mut Ctx, _ecode: i32) -> i32 {
|
||||||
|
debug!("emscripten::_gai_strerror({})", _ecode);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 {
|
pub fn _getdtablesize(_ctx: &mut Ctx) -> i32 {
|
||||||
debug!("emscripten::getdtablesize");
|
debug!("emscripten::getdtablesize");
|
||||||
@ -216,6 +239,22 @@ pub fn _getloadavg(_ctx: &mut Ctx, _loadavg: i32, _nelem: i32) -> i32 {
|
|||||||
debug!("emscripten::getloadavg");
|
debug!("emscripten::getloadavg");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
pub fn _getnameinfo(
|
||||||
|
_ctx: &mut Ctx,
|
||||||
|
_addr: i32,
|
||||||
|
_addrlen: i32,
|
||||||
|
_host: i32,
|
||||||
|
_hostlen: i32,
|
||||||
|
_serv: i32,
|
||||||
|
_servlen: i32,
|
||||||
|
_flags: i32,
|
||||||
|
) -> i32 {
|
||||||
|
debug!(
|
||||||
|
"emscripten::_getnameinfo({}, {}, {}, {}, {}, {}, {})",
|
||||||
|
_addr, _addrlen, _host, _hostlen, _serv, _servlen, _flags
|
||||||
|
);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke functions
|
// Invoke functions
|
||||||
// They save the stack to allow unwinding
|
// They save the stack to allow unwinding
|
||||||
|
@ -24,9 +24,6 @@ use wasmer_runtime_core::{
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
//#[cfg(test)]
|
|
||||||
mod file_descriptor;
|
|
||||||
pub mod stdio;
|
|
||||||
|
|
||||||
// EMSCRIPTEN APIS
|
// EMSCRIPTEN APIS
|
||||||
mod bitwise;
|
mod bitwise;
|
||||||
@ -47,6 +44,7 @@ mod signal;
|
|||||||
mod storage;
|
mod storage;
|
||||||
mod syscalls;
|
mod syscalls;
|
||||||
mod time;
|
mod time;
|
||||||
|
mod ucontext;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod varargs;
|
mod varargs;
|
||||||
|
|
||||||
@ -725,6 +723,7 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
|||||||
"_dlsym" => func!(crate::linking::_dlsym),
|
"_dlsym" => func!(crate::linking::_dlsym),
|
||||||
|
|
||||||
// wasm32-unknown-emscripten
|
// wasm32-unknown-emscripten
|
||||||
|
"_alarm" => func!(crate::emscripten_target::_alarm),
|
||||||
"_atexit" => func!(crate::emscripten_target::_atexit),
|
"_atexit" => func!(crate::emscripten_target::_atexit),
|
||||||
"setTempRet0" => func!(crate::emscripten_target::setTempRet0),
|
"setTempRet0" => func!(crate::emscripten_target::setTempRet0),
|
||||||
"getTempRet0" => func!(crate::emscripten_target::getTempRet0),
|
"getTempRet0" => func!(crate::emscripten_target::getTempRet0),
|
||||||
@ -775,11 +774,16 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
|||||||
"_pthread_setspecific" => func!(crate::emscripten_target::_pthread_setspecific),
|
"_pthread_setspecific" => func!(crate::emscripten_target::_pthread_setspecific),
|
||||||
"_pthread_once" => func!(crate::emscripten_target::_pthread_once),
|
"_pthread_once" => func!(crate::emscripten_target::_pthread_once),
|
||||||
"_pthread_key_create" => func!(crate::emscripten_target::_pthread_key_create),
|
"_pthread_key_create" => func!(crate::emscripten_target::_pthread_key_create),
|
||||||
|
"_pthread_rwlock_destroy" => func!(crate::emscripten_target::_pthread_rwlock_destroy),
|
||||||
|
"_pthread_rwlock_init" => func!(crate::emscripten_target::_pthread_rwlock_init),
|
||||||
|
"_pthread_rwlock_wrlock" => func!(crate::emscripten_target::_pthread_rwlock_wrlock),
|
||||||
"___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0),
|
"___gxx_personality_v0" => func!(crate::emscripten_target::___gxx_personality_v0),
|
||||||
|
"_gai_strerror" => func!(crate::emscripten_target::_gai_strerror),
|
||||||
"_getdtablesize" => func!(crate::emscripten_target::_getdtablesize),
|
"_getdtablesize" => func!(crate::emscripten_target::_getdtablesize),
|
||||||
"_gethostbyaddr" => func!(crate::emscripten_target::_gethostbyaddr),
|
"_gethostbyaddr" => func!(crate::emscripten_target::_gethostbyaddr),
|
||||||
"_gethostbyname_r" => func!(crate::emscripten_target::_gethostbyname_r),
|
"_gethostbyname_r" => func!(crate::emscripten_target::_gethostbyname_r),
|
||||||
"_getloadavg" => func!(crate::emscripten_target::_getloadavg),
|
"_getloadavg" => func!(crate::emscripten_target::_getloadavg),
|
||||||
|
"_getnameinfo" => func!(crate::emscripten_target::_getnameinfo),
|
||||||
"invoke_dii" => func!(crate::emscripten_target::invoke_dii),
|
"invoke_dii" => func!(crate::emscripten_target::invoke_dii),
|
||||||
"invoke_diiii" => func!(crate::emscripten_target::invoke_diiii),
|
"invoke_diiii" => func!(crate::emscripten_target::invoke_diiii),
|
||||||
"invoke_iiiii" => func!(crate::emscripten_target::invoke_iiiii),
|
"invoke_iiiii" => func!(crate::emscripten_target::invoke_iiiii),
|
||||||
@ -819,6 +823,12 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject
|
|||||||
"invoke_viid" => func!(crate::emscripten_target::invoke_viid),
|
"invoke_viid" => func!(crate::emscripten_target::invoke_viid),
|
||||||
"invoke_viidii" => func!(crate::emscripten_target::invoke_viidii),
|
"invoke_viidii" => func!(crate::emscripten_target::invoke_viidii),
|
||||||
"invoke_viidddddddd" => func!(crate::emscripten_target::invoke_viidddddddd),
|
"invoke_viidddddddd" => func!(crate::emscripten_target::invoke_viidddddddd),
|
||||||
|
|
||||||
|
// ucontext
|
||||||
|
"_getcontext" => func!(crate::ucontext::_getcontext),
|
||||||
|
"_makecontext" => func!(crate::ucontext::_makecontext),
|
||||||
|
"_setcontext" => func!(crate::ucontext::_setcontext),
|
||||||
|
"_swapcontext" => func!(crate::ucontext::_swapcontext),
|
||||||
};
|
};
|
||||||
|
|
||||||
for null_func_name in globals.null_func_names.iter() {
|
for null_func_name in globals.null_func_names.iter() {
|
||||||
|
20
lib/emscripten/src/ucontext.rs
Normal file
20
lib/emscripten/src/ucontext.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
|
||||||
|
pub fn _getcontext(_ctx: &mut Ctx, _ucp: i32) -> i32 {
|
||||||
|
debug!("emscripten::_getcontext({})", _ucp);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
pub fn _makecontext(_ctx: &mut Ctx, _ucp: i32, _func: i32, _argc: i32, _argv: i32) {
|
||||||
|
debug!(
|
||||||
|
"emscripten::_makecontext({}, {}, {}, {})",
|
||||||
|
_ucp, _func, _argc, _argv
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn _setcontext(_ctx: &mut Ctx, _ucp: i32) -> i32 {
|
||||||
|
debug!("emscripten::_setcontext({})", _ucp);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
pub fn _swapcontext(_ctx: &mut Ctx, _oucp: i32, _ucp: i32) -> i32 {
|
||||||
|
debug!("emscripten::_swapcontext({}, {})", _oucp, _ucp);
|
||||||
|
0
|
||||||
|
}
|
@ -4,9 +4,11 @@ macro_rules! assert_emscripten_output {
|
|||||||
use wasmer_emscripten::{
|
use wasmer_emscripten::{
|
||||||
EmscriptenGlobals,
|
EmscriptenGlobals,
|
||||||
generate_emscripten_env,
|
generate_emscripten_env,
|
||||||
stdio::StdioCapturer
|
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::backend::Compiler;
|
use wasmer_runtime_core::{
|
||||||
|
backend::Compiler,
|
||||||
|
};
|
||||||
|
use wasmer_dev_utils::stdio::StdioCapturer;
|
||||||
|
|
||||||
#[cfg(feature = "clif")]
|
#[cfg(feature = "clif")]
|
||||||
fn get_compiler() -> impl Compiler {
|
fn get_compiler() -> impl Compiler {
|
||||||
|
9
lib/kernel-loader/Cargo.toml
Normal file
9
lib/kernel-loader/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasmer-kernel-loader"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2.49"
|
||||||
|
wasmer-runtime-core = { path = "../runtime-core" }
|
168
lib/kernel-loader/src/lib.rs
Normal file
168
lib/kernel-loader/src/lib.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
pub mod service;
|
||||||
|
|
||||||
|
use service::{ImportInfo, LoadProfile, RunProfile, ServiceContext, TableEntryRequest};
|
||||||
|
use wasmer_runtime_core::{
|
||||||
|
backend::RunnableModule,
|
||||||
|
loader::{Instance, Loader},
|
||||||
|
module::ModuleInfo,
|
||||||
|
structures::TypedIndex,
|
||||||
|
types::{
|
||||||
|
FuncIndex, ImportedMemoryIndex, ImportedTableIndex, LocalMemoryIndex, LocalTableIndex,
|
||||||
|
Value,
|
||||||
|
},
|
||||||
|
vm::{Anyfunc, Ctx, LocalGlobal, SigId},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct KernelLoader;
|
||||||
|
|
||||||
|
impl Loader for KernelLoader {
|
||||||
|
type Instance = KernelInstance;
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
rm: &dyn RunnableModule,
|
||||||
|
module: &ModuleInfo,
|
||||||
|
full_ctx: &Ctx,
|
||||||
|
) -> Result<Self::Instance, Self::Error> {
|
||||||
|
let ctx = &full_ctx.internal;
|
||||||
|
let code = rm.get_code().unwrap();
|
||||||
|
let memory = if let Some(_) = module.memories.get(LocalMemoryIndex::new(0)) {
|
||||||
|
Some(unsafe {
|
||||||
|
::std::slice::from_raw_parts((**ctx.memories).base, (**ctx.memories).bound)
|
||||||
|
})
|
||||||
|
} else if let Some(_) = module.imported_memories.get(ImportedMemoryIndex::new(0)) {
|
||||||
|
return Err("imported memory is not supported".into());
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let table: Option<Vec<TableEntryRequest>> =
|
||||||
|
if let Some(_) = module.tables.get(LocalTableIndex::new(0)) {
|
||||||
|
Some(unsafe {
|
||||||
|
let table = &**ctx.tables;
|
||||||
|
let elements: &[Anyfunc];
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
{
|
||||||
|
elements =
|
||||||
|
::std::slice::from_raw_parts(table.base as *const Anyfunc, table.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
let base_addr = code.as_ptr() as usize;
|
||||||
|
let end_addr = base_addr + code.len();
|
||||||
|
elements
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
let func_addr = x.func as usize;
|
||||||
|
TableEntryRequest {
|
||||||
|
offset: if x.func.is_null()
|
||||||
|
|| func_addr < base_addr
|
||||||
|
|| func_addr >= end_addr
|
||||||
|
{
|
||||||
|
::std::usize::MAX
|
||||||
|
} else {
|
||||||
|
x.func as usize - base_addr
|
||||||
|
},
|
||||||
|
sig_id: x.sig_id.0,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
} else if let Some(_) = module.imported_tables.get(ImportedTableIndex::new(0)) {
|
||||||
|
return Err("imported table is not supported".into());
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if module.imported_globals.len() > 0 {
|
||||||
|
return Err("imported globals are not supported".into());
|
||||||
|
}
|
||||||
|
let globals: Vec<u64> = unsafe {
|
||||||
|
let globals: &[*mut LocalGlobal] =
|
||||||
|
::std::slice::from_raw_parts(ctx.globals, module.globals.len());
|
||||||
|
globals.iter().map(|x| (**x).data).collect()
|
||||||
|
};
|
||||||
|
let mut import_names: Vec<ImportInfo> = vec![];
|
||||||
|
for (idx, import) in &module.imported_functions {
|
||||||
|
let name = format!(
|
||||||
|
"{}##{}",
|
||||||
|
module.namespace_table.get(import.namespace_index),
|
||||||
|
module.name_table.get(import.name_index)
|
||||||
|
);
|
||||||
|
let sig = module
|
||||||
|
.signatures
|
||||||
|
.get(*module.func_assoc.get(FuncIndex::new(idx.index())).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
import_names.push(ImportInfo {
|
||||||
|
name: name,
|
||||||
|
param_count: sig.params().len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let dynamic_sigindices: &[u32] = unsafe {
|
||||||
|
::std::mem::transmute::<&[SigId], &[u32]>(::std::slice::from_raw_parts(
|
||||||
|
ctx.dynamic_sigindices,
|
||||||
|
full_ctx.dynamic_sigindice_count(),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
let param_counts: Vec<usize> = (0..module.func_assoc.len())
|
||||||
|
.map(|x| {
|
||||||
|
module
|
||||||
|
.signatures
|
||||||
|
.get(*module.func_assoc.get(FuncIndex::new(x)).unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.params()
|
||||||
|
.len()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let profile = LoadProfile {
|
||||||
|
code: code,
|
||||||
|
memory: memory,
|
||||||
|
memory_max: 0,
|
||||||
|
globals: &globals,
|
||||||
|
imports: &import_names,
|
||||||
|
dynamic_sigindices: dynamic_sigindices,
|
||||||
|
table: table.as_ref().map(|x| x.as_slice()),
|
||||||
|
};
|
||||||
|
let sc = ServiceContext::new(profile).map_err(|x| format!("{:?}", x))?;
|
||||||
|
Ok(KernelInstance {
|
||||||
|
context: sc,
|
||||||
|
offsets: rm.get_offsets().unwrap(),
|
||||||
|
param_counts: param_counts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KernelInstance {
|
||||||
|
context: ServiceContext,
|
||||||
|
offsets: Vec<usize>,
|
||||||
|
param_counts: Vec<usize>, // FIXME: Full signature check
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for KernelInstance {
|
||||||
|
type Error = String;
|
||||||
|
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, String> {
|
||||||
|
if args.len() != self.param_counts[id] {
|
||||||
|
return Err("param count mismatch".into());
|
||||||
|
}
|
||||||
|
let args: Vec<u64> = args.iter().map(|x| x.to_u64()).collect();
|
||||||
|
|
||||||
|
let ret = self
|
||||||
|
.context
|
||||||
|
.run_code(RunProfile {
|
||||||
|
entry_offset: self.offsets[id] as u32,
|
||||||
|
params: &args,
|
||||||
|
})
|
||||||
|
.map_err(|x| format!("{:?}", x))?;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_memory(&mut self, offset: u32, len: u32) -> Result<Vec<u8>, String> {
|
||||||
|
self.context
|
||||||
|
.read_memory(offset, len)
|
||||||
|
.map_err(|x| format!("{:?}", x))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> Result<(), String> {
|
||||||
|
self.context
|
||||||
|
.write_memory(offset, len, buf)
|
||||||
|
.map_err(|x| format!("{:?}", x))
|
||||||
|
}
|
||||||
|
}
|
255
lib/kernel-loader/src/service.rs
Normal file
255
lib/kernel-loader/src/service.rs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
macro_rules! impl_debug_display {
|
||||||
|
($target:ident) => {
|
||||||
|
impl ::std::fmt::Display for $target {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
<Self as ::std::fmt::Debug>::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum Command {
|
||||||
|
LoadCode = 0x1001,
|
||||||
|
RunCode = 0x1002,
|
||||||
|
ReadMemory = 0x1003,
|
||||||
|
WriteMemory = 0x1004,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ServiceError {
|
||||||
|
Io(io::Error),
|
||||||
|
Code(i32),
|
||||||
|
InvalidInput,
|
||||||
|
Rejected,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ServiceResult<T> = Result<T, ServiceError>;
|
||||||
|
|
||||||
|
impl_debug_display!(ServiceError);
|
||||||
|
|
||||||
|
impl Error for ServiceError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"ServiceError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for ServiceError {
|
||||||
|
fn from(other: io::Error) -> ServiceError {
|
||||||
|
ServiceError::Io(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct LoadCodeRequest {
|
||||||
|
code: *const u8,
|
||||||
|
code_len: u32,
|
||||||
|
memory: *const u8,
|
||||||
|
memory_len: u32,
|
||||||
|
memory_max: u32,
|
||||||
|
table: *const TableEntryRequest,
|
||||||
|
table_count: u32,
|
||||||
|
globals: *const u64,
|
||||||
|
global_count: u32,
|
||||||
|
|
||||||
|
imported_funcs: *const ImportRequest,
|
||||||
|
imported_func_count: u32,
|
||||||
|
|
||||||
|
dynamic_sigindices: *const u32,
|
||||||
|
dynamic_sigindice_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct RunCodeRequest {
|
||||||
|
entry_offset: u32,
|
||||||
|
params: *const u64,
|
||||||
|
param_count: u32,
|
||||||
|
result: *mut RunCodeResult,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct RunCodeResult {
|
||||||
|
success: u32,
|
||||||
|
retval: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct ReadMemoryRequest {
|
||||||
|
out: *mut u8,
|
||||||
|
offset: u32,
|
||||||
|
len: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct WriteMemoryRequest {
|
||||||
|
_in: *const u8,
|
||||||
|
offset: u32,
|
||||||
|
len: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct ImportRequest {
|
||||||
|
name: [u8; 64],
|
||||||
|
param_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TableEntryRequest {
|
||||||
|
pub offset: usize,
|
||||||
|
pub sig_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoadProfile<'a> {
|
||||||
|
pub code: &'a [u8],
|
||||||
|
pub memory: Option<&'a [u8]>,
|
||||||
|
pub memory_max: usize,
|
||||||
|
pub globals: &'a [u64],
|
||||||
|
pub imports: &'a [ImportInfo],
|
||||||
|
pub dynamic_sigindices: &'a [u32],
|
||||||
|
pub table: Option<&'a [TableEntryRequest]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImportInfo {
|
||||||
|
pub name: String,
|
||||||
|
pub param_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunProfile<'a> {
|
||||||
|
pub entry_offset: u32,
|
||||||
|
pub params: &'a [u64],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ServiceContext {
|
||||||
|
dev: File,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServiceContext {
|
||||||
|
pub fn new(load: LoadProfile) -> ServiceResult<ServiceContext> {
|
||||||
|
let dev = File::open("/dev/wasmctl")?;
|
||||||
|
let imports: Vec<ImportRequest> = load
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
let mut req = ImportRequest {
|
||||||
|
name: [0u8; 64],
|
||||||
|
param_count: x.param_count as u32,
|
||||||
|
};
|
||||||
|
let name = x.name.as_bytes();
|
||||||
|
let mut count = req.name.len() - 1;
|
||||||
|
if name.len() < count {
|
||||||
|
count = name.len();
|
||||||
|
}
|
||||||
|
req.name[..count].copy_from_slice(&name[..count]);
|
||||||
|
req
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let req = LoadCodeRequest {
|
||||||
|
code: load.code.as_ptr(),
|
||||||
|
code_len: load.code.len() as u32,
|
||||||
|
memory: load
|
||||||
|
.memory
|
||||||
|
.map(|x| x.as_ptr())
|
||||||
|
.unwrap_or(::std::ptr::null()),
|
||||||
|
memory_len: load.memory.map(|x| x.len() as u32).unwrap_or(0),
|
||||||
|
memory_max: load.memory_max as u32,
|
||||||
|
table: load.table.map(|x| x.as_ptr()).unwrap_or(::std::ptr::null()),
|
||||||
|
table_count: load.table.map(|x| x.len() as u32).unwrap_or(0),
|
||||||
|
globals: load.globals.as_ptr(),
|
||||||
|
global_count: load.globals.len() as u32,
|
||||||
|
imported_funcs: imports.as_ptr(),
|
||||||
|
imported_func_count: imports.len() as u32,
|
||||||
|
dynamic_sigindices: load.dynamic_sigindices.as_ptr(),
|
||||||
|
dynamic_sigindice_count: load.dynamic_sigindices.len() as u32,
|
||||||
|
};
|
||||||
|
let fd = dev.as_raw_fd();
|
||||||
|
let ret = unsafe {
|
||||||
|
::libc::ioctl(
|
||||||
|
fd,
|
||||||
|
Command::LoadCode as i32 as ::libc::c_ulong,
|
||||||
|
&req as *const _ as ::libc::c_ulong,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret != 0 {
|
||||||
|
Err(ServiceError::Code(ret))
|
||||||
|
} else {
|
||||||
|
Ok(ServiceContext { dev: dev })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_code(&mut self, run: RunProfile) -> ServiceResult<u64> {
|
||||||
|
let mut result: RunCodeResult = unsafe { ::std::mem::zeroed() };
|
||||||
|
let mut req = RunCodeRequest {
|
||||||
|
entry_offset: run.entry_offset,
|
||||||
|
params: run.params.as_ptr(),
|
||||||
|
param_count: run.params.len() as u32,
|
||||||
|
result: &mut result,
|
||||||
|
};
|
||||||
|
let fd = self.dev.as_raw_fd();
|
||||||
|
let err = unsafe {
|
||||||
|
::libc::ioctl(
|
||||||
|
fd,
|
||||||
|
Command::RunCode as i32 as ::libc::c_ulong,
|
||||||
|
&mut req as *mut _ as ::libc::c_ulong,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if err < 0 {
|
||||||
|
Err(ServiceError::Code(err))
|
||||||
|
} else if result.success == 0 {
|
||||||
|
println!("Rejected {} {}", result.success, result.retval);
|
||||||
|
Err(ServiceError::Rejected)
|
||||||
|
} else {
|
||||||
|
Ok(result.retval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_memory(&mut self, offset: u32, len: u32) -> ServiceResult<Vec<u8>> {
|
||||||
|
let fd = self.dev.as_raw_fd();
|
||||||
|
let mut ret = Vec::with_capacity(len as usize);
|
||||||
|
unsafe {
|
||||||
|
ret.set_len(len as usize);
|
||||||
|
}
|
||||||
|
let req = ReadMemoryRequest {
|
||||||
|
out: ret.as_mut_ptr(),
|
||||||
|
offset: offset,
|
||||||
|
len: len,
|
||||||
|
};
|
||||||
|
let err = unsafe {
|
||||||
|
::libc::ioctl(
|
||||||
|
fd,
|
||||||
|
Command::ReadMemory as i32 as ::libc::c_ulong,
|
||||||
|
&req as *const _ as ::libc::c_ulong,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if err < 0 {
|
||||||
|
Err(ServiceError::Code(err))
|
||||||
|
} else {
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_memory(&mut self, offset: u32, len: u32, buf: &[u8]) -> ServiceResult<()> {
|
||||||
|
let fd = self.dev.as_raw_fd();
|
||||||
|
let req = WriteMemoryRequest {
|
||||||
|
_in: buf.as_ptr(),
|
||||||
|
offset: offset,
|
||||||
|
len: len,
|
||||||
|
};
|
||||||
|
let err = unsafe {
|
||||||
|
::libc::ioctl(
|
||||||
|
fd,
|
||||||
|
Command::WriteMemory as i32 as ::libc::c_ulong,
|
||||||
|
&req as *const _ as ::libc::c_ulong,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if err < 0 {
|
||||||
|
Err(ServiceError::Code(err))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
lib/kernel-net/Cargo.toml
Normal file
9
lib/kernel-net/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "kernel-net"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Heyang Zhou <zhy20000919@hotmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
#runtime = "0.3.0-alpha.4"
|
||||||
|
#runtime-raw = "0.3.0-alpha.3"
|
466
lib/kernel-net/src/lib.rs
Normal file
466
lib/kernel-net/src/lib.rs
Normal file
@ -0,0 +1,466 @@
|
|||||||
|
#![cfg(all(target_arch = "wasm32", target_os = "wasi"))]
|
||||||
|
#![feature(wasi_ext)]
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::net::{AddrParseError, Ipv4Addr};
|
||||||
|
use std::os::wasi::io::FromRawFd;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
const AF_INET: i32 = 2;
|
||||||
|
const SOCK_STREAM: i32 = 1;
|
||||||
|
const O_NONBLOCK: u32 = 2048;
|
||||||
|
const F_GETFL: i32 = 3;
|
||||||
|
const F_SETFL: i32 = 4;
|
||||||
|
const EPOLLIN: u32 = 1u32;
|
||||||
|
const EPOLLOUT: u32 = 4u32;
|
||||||
|
const EPOLLONESHOT: u32 = 1u32 << 30;
|
||||||
|
const EPOLLET: u32 = 1u32 << 31;
|
||||||
|
const EAGAIN: i32 = 11;
|
||||||
|
const EWOULDBLOCK: i32 = EAGAIN;
|
||||||
|
const EPOLL_CTL_ADD: i32 = 1;
|
||||||
|
const EPOLL_CTL_DEL: i32 = 2;
|
||||||
|
|
||||||
|
#[link(wasm_import_module = "net")]
|
||||||
|
extern "C" {
|
||||||
|
fn _socket(family: i32, _type: i32, proto: i32) -> i32;
|
||||||
|
fn _bind(fd: i32, sa: *const SockaddrIn, sa_len: usize) -> i32;
|
||||||
|
fn _listen(fd: i32, backlog: i32) -> i32;
|
||||||
|
fn _accept4(fd: i32, sa: *mut SockaddrIn, sa_len: *mut usize, flags: u32) -> i32;
|
||||||
|
fn _sendto(
|
||||||
|
fd: i32,
|
||||||
|
buf: *const u8,
|
||||||
|
buf_len: usize,
|
||||||
|
flags: u32,
|
||||||
|
addr: *const SockaddrIn,
|
||||||
|
addr_len: usize,
|
||||||
|
) -> i32;
|
||||||
|
fn _recvfrom(
|
||||||
|
fd: i32,
|
||||||
|
buf: *mut u8,
|
||||||
|
buf_len: usize,
|
||||||
|
flags: u32,
|
||||||
|
addr: *mut SockaddrIn,
|
||||||
|
addr_len: *mut usize,
|
||||||
|
) -> i32;
|
||||||
|
fn _eventfd_sem(initial: u32) -> i32;
|
||||||
|
fn _epoll_create() -> i32;
|
||||||
|
fn _epoll_ctl(epfd: i32, op: i32, fd: i32, event: *const EpollEvent) -> i32;
|
||||||
|
fn _epoll_wait(epfd: i32, events: *mut EpollEvent, maxevents: usize, timeout: i32) -> i32;
|
||||||
|
fn _fcntl(fd: i32, cmd: i32, arg: u32) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static GLOBAL_EPOLL: RefCell<Option<Arc<Epoll>>> = RefCell::new(None);
|
||||||
|
static ASYNC_STATE_POOL: RefCell<Vec<Box<AsyncState>>> = RefCell::new(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct AsyncState {
|
||||||
|
callback: Option<Box<FnOnce()>>,
|
||||||
|
_epoll: Option<Arc<Epoll>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Epoll {
|
||||||
|
fd: i32,
|
||||||
|
imm_queue: Mutex<Vec<Box<FnOnce()>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Epoll {
|
||||||
|
pub fn new() -> Epoll {
|
||||||
|
let fd = unsafe { _epoll_create() };
|
||||||
|
assert!(fd >= 0);
|
||||||
|
Epoll {
|
||||||
|
fd: fd,
|
||||||
|
imm_queue: Mutex::new(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn schedule<F: FnOnce() + 'static>(&self, f: F) {
|
||||||
|
self.imm_queue.lock().unwrap().push(Box::new(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn run(self: Arc<Self>) -> ! {
|
||||||
|
GLOBAL_EPOLL.with(|x| {
|
||||||
|
*x.borrow_mut() = Some(self.clone());
|
||||||
|
});
|
||||||
|
let mut events: Vec<EpollEvent> = vec![EpollEvent::default(); 32];
|
||||||
|
loop {
|
||||||
|
loop {
|
||||||
|
let imm_queue =
|
||||||
|
::std::mem::replace(&mut *self.imm_queue.lock().unwrap(), Vec::new());
|
||||||
|
if imm_queue.len() == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for f in imm_queue {
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let events_len = events.len();
|
||||||
|
let n_ready = _epoll_wait(self.fd, events.as_mut_ptr(), events_len, -1);
|
||||||
|
assert!(n_ready >= 0);
|
||||||
|
/*if n_ready > 1 {
|
||||||
|
println!("n_ready = {}", n_ready);
|
||||||
|
}*/
|
||||||
|
for ev in &events[..n_ready as usize] {
|
||||||
|
if ev.events & (EPOLLIN | EPOLLOUT) != 0 {
|
||||||
|
//println!("Free event {:x} {:?}", ev.events, ev.data as usize as *mut AsyncState);
|
||||||
|
let mut state = Box::from_raw(ev.data as usize as *mut AsyncState);
|
||||||
|
(state.callback.take().unwrap())();
|
||||||
|
put_async_state(state);
|
||||||
|
//println!("After callback");
|
||||||
|
} else {
|
||||||
|
println!("unknown event(s): 0x{:x}", ev.events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Epoll {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
File::from_raw_fd(self.fd as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum EpollDirection {
|
||||||
|
In,
|
||||||
|
Out,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_async_state() -> Box<AsyncState> {
|
||||||
|
ASYNC_STATE_POOL.with(|pool| {
|
||||||
|
pool.borrow_mut()
|
||||||
|
.pop()
|
||||||
|
.unwrap_or_else(|| Box::new(AsyncState::default()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_async_state(mut x: Box<AsyncState>) {
|
||||||
|
x.callback = None;
|
||||||
|
x._epoll = None;
|
||||||
|
ASYNC_STATE_POOL.with(|pool| pool.borrow_mut().push(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn schedule<F: FnOnce() + 'static>(f: F) {
|
||||||
|
//println!("schedule");
|
||||||
|
let epoll = GLOBAL_EPOLL.with(|x| x.borrow().as_ref().unwrap().clone());
|
||||||
|
epoll.schedule(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_async_io_payload<
|
||||||
|
T: 'static,
|
||||||
|
P: FnMut(i32) -> Result<T, i32> + 'static,
|
||||||
|
F: FnOnce(Result<T, i32>) + 'static,
|
||||||
|
>(
|
||||||
|
epoll: Arc<Epoll>,
|
||||||
|
fd: i32,
|
||||||
|
direction: EpollDirection,
|
||||||
|
poll_action: P,
|
||||||
|
on_ready: F,
|
||||||
|
) -> Box<FnOnce()> {
|
||||||
|
__get_async_io_payload(epoll, fd, direction, poll_action, on_ready, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __get_async_io_payload<
|
||||||
|
T: 'static,
|
||||||
|
P: FnMut(i32) -> Result<T, i32> + 'static,
|
||||||
|
F: FnOnce(Result<T, i32>) + 'static,
|
||||||
|
>(
|
||||||
|
epoll: Arc<Epoll>,
|
||||||
|
fd: i32,
|
||||||
|
direction: EpollDirection,
|
||||||
|
mut poll_action: P,
|
||||||
|
on_ready: F,
|
||||||
|
registered: bool,
|
||||||
|
) -> Box<FnOnce()> {
|
||||||
|
let epfd = epoll.fd;
|
||||||
|
Box::new(move || {
|
||||||
|
//println!("async io payload");
|
||||||
|
let ret = poll_action(fd);
|
||||||
|
//println!("async io payload (after poll_action)");
|
||||||
|
match ret {
|
||||||
|
Err(x) if x == -EAGAIN || x == -EWOULDBLOCK => {
|
||||||
|
let mut state = get_async_state();
|
||||||
|
state.callback = Some(__get_async_io_payload(
|
||||||
|
epoll.clone(),
|
||||||
|
fd,
|
||||||
|
direction,
|
||||||
|
poll_action,
|
||||||
|
on_ready,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
state._epoll = Some(epoll);
|
||||||
|
let direction_flag = match direction {
|
||||||
|
EpollDirection::In => EPOLLIN,
|
||||||
|
EpollDirection::Out => EPOLLOUT,
|
||||||
|
};
|
||||||
|
let ev = EpollEvent {
|
||||||
|
events: direction_flag | EPOLLET | EPOLLONESHOT,
|
||||||
|
data: Box::into_raw(state) as usize as _,
|
||||||
|
};
|
||||||
|
//println!("Alloc event {:?}", ev.data as usize as *mut AsyncState);
|
||||||
|
let ret = unsafe { _epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) };
|
||||||
|
assert!(ret >= 0);
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
if registered {
|
||||||
|
assert!(
|
||||||
|
unsafe { _epoll_ctl(epfd, EPOLL_CTL_DEL, fd, ::std::ptr::null(),) } >= 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
on_ready(x); // fast path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct SockaddrIn {
|
||||||
|
sin_family: u16, // e.g. AF_INET
|
||||||
|
sin_port: u16, // e.g. htons(3490)
|
||||||
|
sin_addr: InAddr,
|
||||||
|
sin_zero: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct InAddr {
|
||||||
|
s_addr: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
struct EpollEvent {
|
||||||
|
events: u32,
|
||||||
|
data: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invert_byteorder_u16(x: u16) -> u16 {
|
||||||
|
unsafe {
|
||||||
|
use std::mem::transmute;
|
||||||
|
let buf: [u8; 2] = transmute(x);
|
||||||
|
let out: [u8; 2] = [buf[1], buf[0]];
|
||||||
|
transmute(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SocketError {
|
||||||
|
AddrParse(AddrParseError),
|
||||||
|
SocketCreate,
|
||||||
|
Bind,
|
||||||
|
Listen,
|
||||||
|
Accept,
|
||||||
|
Message(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Tcp4Listener {
|
||||||
|
_addr: Ipv4Addr,
|
||||||
|
_port: u16,
|
||||||
|
fd: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tcp4Listener {
|
||||||
|
pub fn new<A: AsRef<str>>(
|
||||||
|
addr: A,
|
||||||
|
port: u16,
|
||||||
|
backlog: u32,
|
||||||
|
) -> Result<Tcp4Listener, SocketError> {
|
||||||
|
let addr: Ipv4Addr = addr.as_ref().parse().map_err(SocketError::AddrParse)?;
|
||||||
|
let sa = SockaddrIn {
|
||||||
|
sin_family: AF_INET as _,
|
||||||
|
sin_port: invert_byteorder_u16(port),
|
||||||
|
sin_addr: InAddr {
|
||||||
|
s_addr: unsafe { ::std::mem::transmute(addr.octets()) },
|
||||||
|
},
|
||||||
|
sin_zero: [0; 8],
|
||||||
|
};
|
||||||
|
let fd = unsafe { _socket(AF_INET, SOCK_STREAM, 0) };
|
||||||
|
if fd < 0 {
|
||||||
|
return Err(SocketError::SocketCreate);
|
||||||
|
}
|
||||||
|
if unsafe { _bind(fd, &sa, ::std::mem::size_of::<SockaddrIn>()) } < 0 {
|
||||||
|
return Err(SocketError::Bind);
|
||||||
|
}
|
||||||
|
if unsafe { _listen(fd, backlog as _) } < 0 {
|
||||||
|
return Err(SocketError::Listen);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut socket_flags = _fcntl(fd, F_GETFL, 0) as u32;
|
||||||
|
socket_flags |= O_NONBLOCK;
|
||||||
|
assert!(_fcntl(fd, F_SETFL, socket_flags) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Tcp4Listener {
|
||||||
|
_addr: addr,
|
||||||
|
_port: port,
|
||||||
|
fd: fd,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept_async<F: Fn(Result<Arc<TcpStream>, i32>) -> Result<(), ()> + 'static>(
|
||||||
|
self: Arc<Self>,
|
||||||
|
ep: Arc<Epoll>,
|
||||||
|
cb: F,
|
||||||
|
) {
|
||||||
|
let ep2 = ep.clone();
|
||||||
|
(get_async_io_payload(
|
||||||
|
ep.clone(),
|
||||||
|
self.fd,
|
||||||
|
EpollDirection::In,
|
||||||
|
move |fd| -> Result<Arc<TcpStream>, i32> {
|
||||||
|
let mut incoming_sa: SockaddrIn = unsafe { ::std::mem::uninitialized() };
|
||||||
|
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 {
|
||||||
|
unsafe {
|
||||||
|
let mut socket_flags = _fcntl(conn, F_GETFL, 0) as u32;
|
||||||
|
socket_flags |= O_NONBLOCK;
|
||||||
|
assert!(_fcntl(conn, F_SETFL, socket_flags) >= 0);
|
||||||
|
}
|
||||||
|
Ok(Arc::new(TcpStream {
|
||||||
|
fd: conn,
|
||||||
|
epoll: ep.clone(),
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Err(conn)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
move |x| {
|
||||||
|
schedule(|| {
|
||||||
|
if let Ok(()) = cb(x) {
|
||||||
|
self.accept_async(ep2, cb);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
))();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TcpStream {
|
||||||
|
fd: i32,
|
||||||
|
epoll: Arc<Epoll>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TcpStream {
|
||||||
|
pub fn __write_async(
|
||||||
|
self: Arc<Self>,
|
||||||
|
data: Vec<u8>,
|
||||||
|
offset: usize,
|
||||||
|
cb: impl FnOnce(Result<(usize, Vec<u8>), i32>) + 'static,
|
||||||
|
) {
|
||||||
|
let mut data = Some(data);
|
||||||
|
|
||||||
|
(get_async_io_payload(
|
||||||
|
self.epoll.clone(),
|
||||||
|
self.fd,
|
||||||
|
EpollDirection::Out,
|
||||||
|
move |fd| -> Result<(usize, Vec<u8>), i32> {
|
||||||
|
let _data = data.as_ref().unwrap();
|
||||||
|
let _data = &_data[offset..];
|
||||||
|
let ret =
|
||||||
|
unsafe { _sendto(fd, _data.as_ptr(), _data.len(), 0, ::std::ptr::null(), 0) };
|
||||||
|
if ret >= 0 {
|
||||||
|
Ok((ret as usize, data.take().unwrap()))
|
||||||
|
} else {
|
||||||
|
Err(ret)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
move |x| {
|
||||||
|
drop(self);
|
||||||
|
cb(x);
|
||||||
|
},
|
||||||
|
))();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_async(
|
||||||
|
self: Arc<Self>,
|
||||||
|
data: Vec<u8>,
|
||||||
|
cb: impl FnOnce(Result<(usize, Vec<u8>), i32>) + 'static,
|
||||||
|
) {
|
||||||
|
self.__write_async(data, 0, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_all_async(
|
||||||
|
self: Arc<Self>,
|
||||||
|
data: Vec<u8>,
|
||||||
|
cb: impl FnOnce(Result<Vec<u8>, i32>) + 'static,
|
||||||
|
) {
|
||||||
|
fn inner(
|
||||||
|
me: Arc<TcpStream>,
|
||||||
|
data: Vec<u8>,
|
||||||
|
offset: usize,
|
||||||
|
cb: impl FnOnce(Result<Vec<u8>, i32>) + 'static,
|
||||||
|
) {
|
||||||
|
let me2 = me.clone();
|
||||||
|
me.__write_async(data, offset, move |result| match result {
|
||||||
|
Ok((len, data)) => {
|
||||||
|
let new_offset = offset + len;
|
||||||
|
if new_offset == data.len() {
|
||||||
|
cb(Ok(data));
|
||||||
|
} else {
|
||||||
|
inner(me2, data, new_offset, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(code) => {
|
||||||
|
cb(Err(code));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
inner(self, data, 0, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_async(
|
||||||
|
self: Arc<Self>,
|
||||||
|
out: Vec<u8>,
|
||||||
|
cb: impl FnOnce(Result<Vec<u8>, i32>) + 'static,
|
||||||
|
) {
|
||||||
|
let mut out = Some(out);
|
||||||
|
(get_async_io_payload(
|
||||||
|
self.epoll.clone(),
|
||||||
|
self.fd,
|
||||||
|
EpollDirection::In,
|
||||||
|
move |fd| -> Result<Vec<u8>, i32> {
|
||||||
|
let _out = out.as_mut().unwrap();
|
||||||
|
let out_cap = _out.capacity();
|
||||||
|
let ret = unsafe {
|
||||||
|
_recvfrom(
|
||||||
|
fd,
|
||||||
|
_out.as_mut_ptr(),
|
||||||
|
out_cap,
|
||||||
|
0,
|
||||||
|
::std::ptr::null_mut(),
|
||||||
|
::std::ptr::null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret >= 0 {
|
||||||
|
assert!(ret as usize <= out_cap);
|
||||||
|
unsafe {
|
||||||
|
_out.set_len(ret as usize);
|
||||||
|
}
|
||||||
|
Ok(out.take().unwrap())
|
||||||
|
} else {
|
||||||
|
Err(ret)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
move |x| {
|
||||||
|
drop(self);
|
||||||
|
cb(x);
|
||||||
|
},
|
||||||
|
))();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TcpStream {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
File::from_raw_fd(self.fd as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-llvm-backend"
|
name = "wasmer-llvm-backend"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
|
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm7-0" }
|
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm7-0" }
|
||||||
wasmparser = "0.29.2"
|
wasmparser = "0.29.2"
|
||||||
hashbrown = "0.1.8"
|
hashbrown = "0.1.8"
|
||||||
|
@ -285,13 +285,16 @@ fn resolve_memory_ptr(
|
|||||||
ctx: &mut CtxType,
|
ctx: &mut CtxType,
|
||||||
memarg: &MemoryImmediate,
|
memarg: &MemoryImmediate,
|
||||||
ptr_ty: PointerType,
|
ptr_ty: PointerType,
|
||||||
|
value_size: usize,
|
||||||
) -> Result<PointerValue, BinaryReaderError> {
|
) -> Result<PointerValue, BinaryReaderError> {
|
||||||
// Ignore alignment hint for the time being.
|
// Ignore alignment hint for the time being.
|
||||||
let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false);
|
let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false);
|
||||||
|
let value_size_v = intrinsics.i64_ty.const_int(value_size as u64, false);
|
||||||
let var_offset_i32 = state.pop1()?.into_int_value();
|
let var_offset_i32 = state.pop1()?.into_int_value();
|
||||||
let var_offset =
|
let var_offset =
|
||||||
builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name());
|
builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name());
|
||||||
let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name());
|
let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name());
|
||||||
|
let end_offset = builder.build_int_add(effective_offset, value_size_v, &state.var_name());
|
||||||
let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics);
|
let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics);
|
||||||
|
|
||||||
let mem_base_int = match memory_cache {
|
let mem_base_int = match memory_cache {
|
||||||
@ -306,12 +309,20 @@ fn resolve_memory_ptr(
|
|||||||
|
|
||||||
let base_as_int = builder.build_ptr_to_int(base, intrinsics.i64_ty, "base_as_int");
|
let base_as_int = builder.build_ptr_to_int(base, intrinsics.i64_ty, "base_as_int");
|
||||||
|
|
||||||
let base_in_bounds = builder.build_int_compare(
|
let base_in_bounds_1 = builder.build_int_compare(
|
||||||
|
IntPredicate::ULE,
|
||||||
|
end_offset,
|
||||||
|
bounds,
|
||||||
|
"base_in_bounds_1",
|
||||||
|
);
|
||||||
|
let base_in_bounds_2 = builder.build_int_compare(
|
||||||
IntPredicate::ULT,
|
IntPredicate::ULT,
|
||||||
effective_offset,
|
effective_offset,
|
||||||
bounds,
|
end_offset,
|
||||||
"base_in_bounds",
|
"base_in_bounds_2",
|
||||||
);
|
);
|
||||||
|
let base_in_bounds =
|
||||||
|
builder.build_and(base_in_bounds_1, base_in_bounds_2, "base_in_bounds");
|
||||||
|
|
||||||
let base_in_bounds = builder
|
let base_in_bounds = builder
|
||||||
.build_call(
|
.build_call(
|
||||||
@ -2000,6 +2011,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i32_ptr_ty,
|
intrinsics.i32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
let result = builder.build_load(effective_address, &state.var_name());
|
let result = builder.build_load(effective_address, &state.var_name());
|
||||||
state.push1(result);
|
state.push1(result);
|
||||||
@ -2014,6 +2026,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i64_ptr_ty,
|
intrinsics.i64_ptr_ty,
|
||||||
|
8,
|
||||||
)?;
|
)?;
|
||||||
let result = builder.build_load(effective_address, &state.var_name());
|
let result = builder.build_load(effective_address, &state.var_name());
|
||||||
state.push1(result);
|
state.push1(result);
|
||||||
@ -2028,6 +2041,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.f32_ptr_ty,
|
intrinsics.f32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
let result = builder.build_load(effective_address, &state.var_name());
|
let result = builder.build_load(effective_address, &state.var_name());
|
||||||
state.push1(result);
|
state.push1(result);
|
||||||
@ -2042,6 +2056,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.f64_ptr_ty,
|
intrinsics.f64_ptr_ty,
|
||||||
|
8,
|
||||||
)?;
|
)?;
|
||||||
let result = builder.build_load(effective_address, &state.var_name());
|
let result = builder.build_load(effective_address, &state.var_name());
|
||||||
state.push1(result);
|
state.push1(result);
|
||||||
@ -2058,6 +2073,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i32_ptr_ty,
|
intrinsics.i32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
builder.build_store(effective_address, value);
|
builder.build_store(effective_address, value);
|
||||||
}
|
}
|
||||||
@ -2072,6 +2088,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i64_ptr_ty,
|
intrinsics.i64_ptr_ty,
|
||||||
|
8,
|
||||||
)?;
|
)?;
|
||||||
builder.build_store(effective_address, value);
|
builder.build_store(effective_address, value);
|
||||||
}
|
}
|
||||||
@ -2086,6 +2103,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.f32_ptr_ty,
|
intrinsics.f32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
builder.build_store(effective_address, value);
|
builder.build_store(effective_address, value);
|
||||||
}
|
}
|
||||||
@ -2100,6 +2118,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.f64_ptr_ty,
|
intrinsics.f64_ptr_ty,
|
||||||
|
8,
|
||||||
)?;
|
)?;
|
||||||
builder.build_store(effective_address, value);
|
builder.build_store(effective_address, value);
|
||||||
}
|
}
|
||||||
@ -2114,6 +2133,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i8_ptr_ty,
|
intrinsics.i8_ptr_ty,
|
||||||
|
1,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2132,6 +2152,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i16_ptr_ty,
|
intrinsics.i16_ptr_ty,
|
||||||
|
2,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2150,6 +2171,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i8_ptr_ty,
|
intrinsics.i8_ptr_ty,
|
||||||
|
1,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2168,6 +2190,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i16_ptr_ty,
|
intrinsics.i16_ptr_ty,
|
||||||
|
2,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2186,6 +2209,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i32_ptr_ty,
|
intrinsics.i32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2205,6 +2229,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i8_ptr_ty,
|
intrinsics.i8_ptr_ty,
|
||||||
|
1,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2223,6 +2248,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i16_ptr_ty,
|
intrinsics.i16_ptr_ty,
|
||||||
|
2,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2241,6 +2267,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i8_ptr_ty,
|
intrinsics.i8_ptr_ty,
|
||||||
|
1,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2259,6 +2286,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i16_ptr_ty,
|
intrinsics.i16_ptr_ty,
|
||||||
|
2,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2277,6 +2305,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i32_ptr_ty,
|
intrinsics.i32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
let narrow_result = builder
|
let narrow_result = builder
|
||||||
.build_load(effective_address, &state.var_name())
|
.build_load(effective_address, &state.var_name())
|
||||||
@ -2297,6 +2326,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i8_ptr_ty,
|
intrinsics.i8_ptr_ty,
|
||||||
|
1,
|
||||||
)?;
|
)?;
|
||||||
let narrow_value =
|
let narrow_value =
|
||||||
builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name());
|
builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name());
|
||||||
@ -2313,6 +2343,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i16_ptr_ty,
|
intrinsics.i16_ptr_ty,
|
||||||
|
2,
|
||||||
)?;
|
)?;
|
||||||
let narrow_value =
|
let narrow_value =
|
||||||
builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name());
|
builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name());
|
||||||
@ -2329,6 +2360,7 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
&mut ctx,
|
&mut ctx,
|
||||||
memarg,
|
memarg,
|
||||||
intrinsics.i32_ptr_ty,
|
intrinsics.i32_ptr_ty,
|
||||||
|
4,
|
||||||
)?;
|
)?;
|
||||||
let narrow_value =
|
let narrow_value =
|
||||||
builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name());
|
builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name());
|
||||||
|
@ -16,6 +16,7 @@ use wasmer_runtime_core::{
|
|||||||
GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
|
GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
|
||||||
TableIndex, Type,
|
TableIndex, Type,
|
||||||
},
|
},
|
||||||
|
vm::Ctx,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType {
|
fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType {
|
||||||
@ -158,6 +159,10 @@ impl Intrinsics {
|
|||||||
let imported_func_ty =
|
let imported_func_ty =
|
||||||
context.struct_type(&[i8_ptr_ty_basic, ctx_ptr_ty.as_basic_type_enum()], false);
|
context.struct_type(&[i8_ptr_ty_basic, ctx_ptr_ty.as_basic_type_enum()], false);
|
||||||
let sigindex_ty = i32_ty;
|
let sigindex_ty = i32_ty;
|
||||||
|
let rt_intrinsics_ty = void_ty;
|
||||||
|
let stack_lower_bound_ty = i8_ty;
|
||||||
|
let memory_base_ty = i8_ty;
|
||||||
|
let memory_bound_ty = void_ty;
|
||||||
let local_function_ty = i8_ptr_ty;
|
let local_function_ty = i8_ptr_ty;
|
||||||
|
|
||||||
let anyfunc_ty = context.struct_type(
|
let anyfunc_ty = context.struct_type(
|
||||||
@ -201,6 +206,18 @@ impl Intrinsics {
|
|||||||
sigindex_ty
|
sigindex_ty
|
||||||
.ptr_type(AddressSpace::Generic)
|
.ptr_type(AddressSpace::Generic)
|
||||||
.as_basic_type_enum(),
|
.as_basic_type_enum(),
|
||||||
|
rt_intrinsics_ty
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.as_basic_type_enum(),
|
||||||
|
stack_lower_bound_ty
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.as_basic_type_enum(),
|
||||||
|
memory_base_ty
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.as_basic_type_enum(),
|
||||||
|
memory_bound_ty
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.as_basic_type_enum(),
|
||||||
local_function_ty
|
local_function_ty
|
||||||
.ptr_type(AddressSpace::Generic)
|
.ptr_type(AddressSpace::Generic)
|
||||||
.as_basic_type_enum(),
|
.as_basic_type_enum(),
|
||||||
@ -416,6 +433,10 @@ pub struct CtxType<'a> {
|
|||||||
_phantom: PhantomData<&'a FunctionValue>,
|
_phantom: PhantomData<&'a FunctionValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn offset_to_index(offset: u8) -> u32 {
|
||||||
|
(offset as usize / ::std::mem::size_of::<usize>()) as u32
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> CtxType<'a> {
|
impl<'a> CtxType<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
info: &'a ModuleInfo,
|
info: &'a ModuleInfo,
|
||||||
@ -454,14 +475,22 @@ impl<'a> CtxType<'a> {
|
|||||||
let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) {
|
let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) {
|
||||||
LocalOrImport::Local(local_mem_index) => (
|
LocalOrImport::Local(local_mem_index) => (
|
||||||
unsafe {
|
unsafe {
|
||||||
cache_builder.build_struct_gep(ctx_ptr_value, 0, "memory_array_ptr_ptr")
|
cache_builder.build_struct_gep(
|
||||||
|
ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_memories()),
|
||||||
|
"memory_array_ptr_ptr",
|
||||||
|
)
|
||||||
},
|
},
|
||||||
local_mem_index.index() as u64,
|
local_mem_index.index() as u64,
|
||||||
info.memories[local_mem_index].memory_type(),
|
info.memories[local_mem_index].memory_type(),
|
||||||
),
|
),
|
||||||
LocalOrImport::Import(import_mem_index) => (
|
LocalOrImport::Import(import_mem_index) => (
|
||||||
unsafe {
|
unsafe {
|
||||||
cache_builder.build_struct_gep(ctx_ptr_value, 3, "memory_array_ptr_ptr")
|
cache_builder.build_struct_gep(
|
||||||
|
ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_imported_memories()),
|
||||||
|
"memory_array_ptr_ptr",
|
||||||
|
)
|
||||||
},
|
},
|
||||||
import_mem_index.index() as u64,
|
import_mem_index.index() as u64,
|
||||||
info.imported_memories[import_mem_index].1.memory_type(),
|
info.imported_memories[import_mem_index].1.memory_type(),
|
||||||
@ -527,13 +556,21 @@ impl<'a> CtxType<'a> {
|
|||||||
let (table_array_ptr_ptr, index) = match index.local_or_import(info) {
|
let (table_array_ptr_ptr, index) = match index.local_or_import(info) {
|
||||||
LocalOrImport::Local(local_table_index) => (
|
LocalOrImport::Local(local_table_index) => (
|
||||||
unsafe {
|
unsafe {
|
||||||
cache_builder.build_struct_gep(ctx_ptr_value, 1, "table_array_ptr_ptr")
|
cache_builder.build_struct_gep(
|
||||||
|
ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_tables()),
|
||||||
|
"table_array_ptr_ptr",
|
||||||
|
)
|
||||||
},
|
},
|
||||||
local_table_index.index() as u64,
|
local_table_index.index() as u64,
|
||||||
),
|
),
|
||||||
LocalOrImport::Import(import_table_index) => (
|
LocalOrImport::Import(import_table_index) => (
|
||||||
unsafe {
|
unsafe {
|
||||||
cache_builder.build_struct_gep(ctx_ptr_value, 4, "table_array_ptr_ptr")
|
cache_builder.build_struct_gep(
|
||||||
|
ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_imported_tables()),
|
||||||
|
"table_array_ptr_ptr",
|
||||||
|
)
|
||||||
},
|
},
|
||||||
import_table_index.index() as u64,
|
import_table_index.index() as u64,
|
||||||
),
|
),
|
||||||
@ -578,8 +615,13 @@ impl<'a> CtxType<'a> {
|
|||||||
intrinsics: &Intrinsics,
|
intrinsics: &Intrinsics,
|
||||||
builder: &Builder,
|
builder: &Builder,
|
||||||
) -> PointerValue {
|
) -> PointerValue {
|
||||||
let local_func_array_ptr_ptr =
|
let local_func_array_ptr_ptr = unsafe {
|
||||||
unsafe { builder.build_struct_gep(self.ctx_ptr_value, 8, "local_func_array_ptr_ptr") };
|
builder.build_struct_gep(
|
||||||
|
self.ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_local_functions()),
|
||||||
|
"local_func_array_ptr_ptr",
|
||||||
|
)
|
||||||
|
};
|
||||||
let local_func_array_ptr = builder
|
let local_func_array_ptr = builder
|
||||||
.build_load(local_func_array_ptr_ptr, "local_func_array_ptr")
|
.build_load(local_func_array_ptr_ptr, "local_func_array_ptr")
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
@ -609,7 +651,11 @@ impl<'a> CtxType<'a> {
|
|||||||
|
|
||||||
*cached_sigindices.entry(index).or_insert_with(|| {
|
*cached_sigindices.entry(index).or_insert_with(|| {
|
||||||
let sigindex_array_ptr_ptr = unsafe {
|
let sigindex_array_ptr_ptr = unsafe {
|
||||||
cache_builder.build_struct_gep(ctx_ptr_value, 7, "sigindex_array_ptr_ptr")
|
cache_builder.build_struct_gep(
|
||||||
|
ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_signatures()),
|
||||||
|
"sigindex_array_ptr_ptr",
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let sigindex_array_ptr = cache_builder
|
let sigindex_array_ptr = cache_builder
|
||||||
.build_load(sigindex_array_ptr_ptr, "sigindex_array_ptr")
|
.build_load(sigindex_array_ptr_ptr, "sigindex_array_ptr")
|
||||||
@ -647,7 +693,7 @@ impl<'a> CtxType<'a> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
cache_builder.build_struct_gep(
|
cache_builder.build_struct_gep(
|
||||||
ctx_ptr_value,
|
ctx_ptr_value,
|
||||||
2,
|
offset_to_index(Ctx::offset_globals()),
|
||||||
"globals_array_ptr_ptr",
|
"globals_array_ptr_ptr",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -662,7 +708,7 @@ impl<'a> CtxType<'a> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
cache_builder.build_struct_gep(
|
cache_builder.build_struct_gep(
|
||||||
ctx_ptr_value,
|
ctx_ptr_value,
|
||||||
5,
|
offset_to_index(Ctx::offset_imported_globals()),
|
||||||
"globals_array_ptr_ptr",
|
"globals_array_ptr_ptr",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -718,7 +764,11 @@ impl<'a> CtxType<'a> {
|
|||||||
|
|
||||||
let imported_func_cache = cached_imported_functions.entry(index).or_insert_with(|| {
|
let imported_func_cache = cached_imported_functions.entry(index).or_insert_with(|| {
|
||||||
let func_array_ptr_ptr = unsafe {
|
let func_array_ptr_ptr = unsafe {
|
||||||
cache_builder.build_struct_gep(ctx_ptr_value, 6, "imported_func_array_ptr_ptr")
|
cache_builder.build_struct_gep(
|
||||||
|
ctx_ptr_value,
|
||||||
|
offset_to_index(Ctx::offset_imported_funcs()),
|
||||||
|
"imported_func_array_ptr_ptr",
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let func_array_ptr = cache_builder
|
let func_array_ptr = cache_builder
|
||||||
.build_load(func_array_ptr_ptr, "func_array_ptr")
|
.build_load(func_array_ptr_ptr, "func_array_ptr")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-middleware-common"
|
name = "wasmer-middleware-common"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
description = "Wasmer runtime common middlewares"
|
description = "Wasmer runtime common middlewares"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@ -8,4 +8,4 @@ authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-runtime-abi"
|
name = "wasmer-runtime-abi"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer runtime core library"
|
description = "Wasmer runtime core library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -16,10 +16,10 @@ tar = "0.4"
|
|||||||
wasmparser = "0.29.2"
|
wasmparser = "0.29.2"
|
||||||
zstd = "0.4"
|
zstd = "0.4"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies.zbox]
|
# [target.'cfg(unix)'.dependencies.zbox]
|
||||||
git = "https://github.com/wasmerio/zbox"
|
# git = "https://github.com/wasmerio/zbox"
|
||||||
branch = "bundle-libsodium"
|
# branch = "bundle-libsodium"
|
||||||
features = ["libsodium-bundled"]
|
# features = ["libsodium-bundled"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-runtime-c-api"
|
name = "wasmer-runtime-c-api"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer C API library"
|
description = "Wasmer C API library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -16,11 +16,11 @@ libc = "0.2"
|
|||||||
|
|
||||||
[dependencies.wasmer-runtime]
|
[dependencies.wasmer-runtime]
|
||||||
path = "../runtime"
|
path = "../runtime"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
|
|
||||||
[dependencies.wasmer-runtime-core]
|
[dependencies.wasmer-runtime-core]
|
||||||
path = "../runtime-core"
|
path = "../runtime-core"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = ["wasmer-runtime/debug"]
|
debug = ["wasmer-runtime/debug"]
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
value::wasmer_value_tag,
|
value::wasmer_value_tag,
|
||||||
wasmer_byte_array, wasmer_result_t,
|
wasmer_byte_array, wasmer_result_t,
|
||||||
};
|
};
|
||||||
use libc::{c_int, uint32_t};
|
use libc::{c_uint, uint32_t};
|
||||||
use std::{ffi::c_void, ptr, slice, sync::Arc};
|
use std::{ffi::c_void, ptr, slice, sync::Arc};
|
||||||
use wasmer_runtime::Module;
|
use wasmer_runtime::Module;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
@ -154,11 +154,11 @@ pub extern "C" fn wasmer_import_descriptors_destroy(
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasmer_import_descriptors_len(
|
pub unsafe extern "C" fn wasmer_import_descriptors_len(
|
||||||
exports: *mut wasmer_import_descriptors_t,
|
exports: *mut wasmer_import_descriptors_t,
|
||||||
) -> c_int {
|
) -> c_uint {
|
||||||
if exports.is_null() {
|
if exports.is_null() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
(*(exports as *mut NamedImportDescriptors)).0.len() as c_int
|
(*(exports as *mut NamedImportDescriptors)).0.len() as c_uint
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets import descriptor by index
|
/// Gets import descriptor by index
|
||||||
@ -166,7 +166,7 @@ pub unsafe extern "C" fn wasmer_import_descriptors_len(
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasmer_import_descriptors_get(
|
pub unsafe extern "C" fn wasmer_import_descriptors_get(
|
||||||
import_descriptors: *mut wasmer_import_descriptors_t,
|
import_descriptors: *mut wasmer_import_descriptors_t,
|
||||||
idx: c_int,
|
idx: c_uint,
|
||||||
) -> *mut wasmer_import_descriptor_t {
|
) -> *mut wasmer_import_descriptor_t {
|
||||||
if import_descriptors.is_null() {
|
if import_descriptors.is_null() {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
@ -244,9 +244,9 @@ pub unsafe extern "C" fn wasmer_import_func_params_arity(
|
|||||||
pub unsafe extern "C" fn wasmer_import_func_new(
|
pub unsafe extern "C" fn wasmer_import_func_new(
|
||||||
func: extern "C" fn(data: *mut c_void),
|
func: extern "C" fn(data: *mut c_void),
|
||||||
params: *const wasmer_value_tag,
|
params: *const wasmer_value_tag,
|
||||||
params_len: c_int,
|
params_len: c_uint,
|
||||||
returns: *const wasmer_value_tag,
|
returns: *const wasmer_value_tag,
|
||||||
returns_len: c_int,
|
returns_len: c_uint,
|
||||||
) -> *mut wasmer_import_func_t {
|
) -> *mut wasmer_import_func_t {
|
||||||
let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize);
|
let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize);
|
||||||
let params: Vec<Type> = params.iter().cloned().map(|x| x.into()).collect();
|
let params: Vec<Type> = params.iter().cloned().map(|x| x.into()).collect();
|
||||||
@ -272,7 +272,7 @@ pub unsafe extern "C" fn wasmer_import_func_new(
|
|||||||
pub unsafe extern "C" fn wasmer_import_func_params(
|
pub unsafe extern "C" fn wasmer_import_func_params(
|
||||||
func: *const wasmer_import_func_t,
|
func: *const wasmer_import_func_t,
|
||||||
params: *mut wasmer_value_tag,
|
params: *mut wasmer_value_tag,
|
||||||
params_len: c_int,
|
params_len: c_uint,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let export = &*(func as *const Export);
|
let export = &*(func as *const Export);
|
||||||
if let Export::Function { ref signature, .. } = *export {
|
if let Export::Function { ref signature, .. } = *export {
|
||||||
@ -301,7 +301,7 @@ pub unsafe extern "C" fn wasmer_import_func_params(
|
|||||||
pub unsafe extern "C" fn wasmer_import_func_returns(
|
pub unsafe extern "C" fn wasmer_import_func_returns(
|
||||||
func: *const wasmer_import_func_t,
|
func: *const wasmer_import_func_t,
|
||||||
returns: *mut wasmer_value_tag,
|
returns: *mut wasmer_value_tag,
|
||||||
returns_len: c_int,
|
returns_len: c_uint,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let export = &*(func as *const Export);
|
let export = &*(func as *const Export);
|
||||||
if let Export::Function { ref signature, .. } = *export {
|
if let Export::Function { ref signature, .. } = *export {
|
||||||
|
@ -99,12 +99,8 @@ pub unsafe extern "C" fn wasmer_instantiate(
|
|||||||
let result = wasmer_runtime::instantiate(bytes, &import_object);
|
let result = wasmer_runtime::instantiate(bytes, &import_object);
|
||||||
let new_instance = match result {
|
let new_instance = match result {
|
||||||
Ok(instance) => instance,
|
Ok(instance) => instance,
|
||||||
Err(_error) => {
|
Err(error) => {
|
||||||
// TODO the trait bound `wasmer_runtime::error::Error: std::error::Error` is not satisfied
|
update_last_error(error);
|
||||||
//update_last_error(error);
|
|
||||||
update_last_error(CApiError {
|
|
||||||
msg: "error instantiating".to_string(),
|
|
||||||
});
|
|
||||||
return wasmer_result_t::WASMER_ERROR;
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -321,12 +321,12 @@ void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descr
|
|||||||
* Gets import descriptor by index
|
* Gets import descriptor by index
|
||||||
*/
|
*/
|
||||||
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
|
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
|
||||||
int idx);
|
unsigned int idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the length of the import descriptors
|
* Gets the length of the import descriptors
|
||||||
*/
|
*/
|
||||||
int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
|
unsigned int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees memory for the given Func
|
* Frees memory for the given Func
|
||||||
@ -339,9 +339,9 @@ void wasmer_import_func_destroy(wasmer_import_func_t *func);
|
|||||||
*/
|
*/
|
||||||
wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
||||||
const wasmer_value_tag *params,
|
const wasmer_value_tag *params,
|
||||||
int params_len,
|
unsigned int params_len,
|
||||||
const wasmer_value_tag *returns,
|
const wasmer_value_tag *returns,
|
||||||
int returns_len);
|
unsigned int returns_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
* Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
||||||
@ -351,7 +351,7 @@ wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
|||||||
*/
|
*/
|
||||||
wasmer_result_t wasmer_import_func_params(const wasmer_import_func_t *func,
|
wasmer_result_t wasmer_import_func_params(const wasmer_import_func_t *func,
|
||||||
wasmer_value_tag *params,
|
wasmer_value_tag *params,
|
||||||
int params_len);
|
unsigned int params_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
* Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
||||||
@ -369,7 +369,7 @@ wasmer_result_t wasmer_import_func_params_arity(const wasmer_import_func_t *func
|
|||||||
*/
|
*/
|
||||||
wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
||||||
wasmer_value_tag *returns,
|
wasmer_value_tag *returns,
|
||||||
int returns_len);
|
unsigned int returns_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
* Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
enum class wasmer_import_export_kind : uint32_t {
|
enum class wasmer_import_export_kind : uint32_t {
|
||||||
WASM_FUNCTION,
|
WASM_FUNCTION,
|
||||||
@ -260,10 +261,10 @@ void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descr
|
|||||||
|
|
||||||
/// Gets import descriptor by index
|
/// Gets import descriptor by index
|
||||||
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
|
wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors,
|
||||||
int idx);
|
unsigned int idx);
|
||||||
|
|
||||||
/// Gets the length of the import descriptors
|
/// Gets the length of the import descriptors
|
||||||
int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
|
unsigned int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports);
|
||||||
|
|
||||||
/// Frees memory for the given Func
|
/// Frees memory for the given Func
|
||||||
void wasmer_import_func_destroy(wasmer_import_func_t *func);
|
void wasmer_import_func_destroy(wasmer_import_func_t *func);
|
||||||
@ -272,9 +273,9 @@ void wasmer_import_func_destroy(wasmer_import_func_t *func);
|
|||||||
/// The caller owns the object and should call `wasmer_import_func_destroy` to free it.
|
/// The caller owns the object and should call `wasmer_import_func_destroy` to free it.
|
||||||
wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
||||||
const wasmer_value_tag *params,
|
const wasmer_value_tag *params,
|
||||||
int params_len,
|
unsigned int params_len,
|
||||||
const wasmer_value_tag *returns,
|
const wasmer_value_tag *returns,
|
||||||
int returns_len);
|
unsigned int returns_len);
|
||||||
|
|
||||||
/// Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
/// Sets the params buffer to the parameter types of the given wasmer_import_func_t
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
@ -282,7 +283,7 @@ wasmer_import_func_t *wasmer_import_func_new(void (*func)(void *data),
|
|||||||
/// and `wasmer_last_error_message` to get an error message.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
wasmer_result_t wasmer_import_func_params(const wasmer_import_func_t *func,
|
wasmer_result_t wasmer_import_func_params(const wasmer_import_func_t *func,
|
||||||
wasmer_value_tag *params,
|
wasmer_value_tag *params,
|
||||||
int params_len);
|
unsigned int params_len);
|
||||||
|
|
||||||
/// Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
/// Sets the result parameter to the arity of the params of the wasmer_import_func_t
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
@ -296,7 +297,7 @@ wasmer_result_t wasmer_import_func_params_arity(const wasmer_import_func_t *func
|
|||||||
/// and `wasmer_last_error_message` to get an error message.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
wasmer_result_t wasmer_import_func_returns(const wasmer_import_func_t *func,
|
||||||
wasmer_value_tag *returns,
|
wasmer_value_tag *returns,
|
||||||
int returns_len);
|
unsigned int returns_len);
|
||||||
|
|
||||||
/// Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
/// Sets the result parameter to the arity of the returns of the wasmer_import_func_t
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-runtime-core"
|
name = "wasmer-runtime-core"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer runtime core library"
|
description = "Wasmer runtime core library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -50,3 +50,4 @@ rustc_version = "0.2.3"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
|
trace = ["debug"]
|
@ -39,16 +39,26 @@ impl Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum MemoryBoundCheckMode {
|
||||||
|
Default,
|
||||||
|
Enable,
|
||||||
|
Disable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MemoryBoundCheckMode {
|
||||||
|
fn default() -> MemoryBoundCheckMode {
|
||||||
|
MemoryBoundCheckMode::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration data for the compiler
|
/// Configuration data for the compiler
|
||||||
|
#[derive(Default)]
|
||||||
pub struct CompilerConfig {
|
pub struct CompilerConfig {
|
||||||
/// Symbol information generated from emscripten; used for more detailed debug messages
|
/// Symbol information generated from emscripten; used for more detailed debug messages
|
||||||
pub symbol_map: Option<HashMap<u32, String>>,
|
pub symbol_map: Option<HashMap<u32, String>>,
|
||||||
}
|
pub memory_bound_check_mode: MemoryBoundCheckMode,
|
||||||
|
pub enforce_stack_check: bool,
|
||||||
impl Default for CompilerConfig {
|
|
||||||
fn default() -> CompilerConfig {
|
|
||||||
CompilerConfig { symbol_map: None }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Compiler {
|
pub trait Compiler {
|
||||||
@ -80,6 +90,16 @@ pub trait RunnableModule: Send + Sync {
|
|||||||
fn get_trampoline(&self, info: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm>;
|
fn get_trampoline(&self, info: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm>;
|
||||||
|
|
||||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
|
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
|
||||||
|
|
||||||
|
/// Returns the machine code associated with this module.
|
||||||
|
fn get_code(&self) -> Option<&[u8]> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the beginning offsets of all functions, including import trampolines.
|
||||||
|
fn get_offsets(&self) -> Option<Vec<usize>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CacheGen: Send + Sync {
|
pub trait CacheGen: Send + Sync {
|
||||||
|
@ -456,10 +456,17 @@ fn import_functions(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
link_errors.push(LinkError::ImportNotFound {
|
if imports.allow_missing_functions {
|
||||||
namespace: namespace.to_string(),
|
functions.push(vm::ImportedFunc {
|
||||||
name: name.to_string(),
|
func: ::std::ptr::null(),
|
||||||
});
|
vmctx: ::std::ptr::null_mut(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
link_errors.push(LinkError::ImportNotFound {
|
||||||
|
namespace: namespace.to_string(),
|
||||||
|
name: name.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,21 +44,30 @@ impl fmt::Debug for InternalEvent {
|
|||||||
pub struct BkptInfo {}
|
pub struct BkptInfo {}
|
||||||
|
|
||||||
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
|
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
|
||||||
|
/// Creates a new module code generator.
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
|
|
||||||
|
/// Returns the backend id associated with this MCG.
|
||||||
fn backend_id() -> Backend;
|
fn backend_id() -> Backend;
|
||||||
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
|
|
||||||
|
|
||||||
/// Creates a new function and returns the function-scope code generator for it.
|
|
||||||
fn next_function(&mut self, module_info: Arc<RwLock<ModuleInfo>>) -> Result<&mut FCG, E>;
|
|
||||||
fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box<dyn CacheGen>), E>;
|
|
||||||
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
|
|
||||||
|
|
||||||
/// Sets function signatures.
|
|
||||||
fn feed_function_signatures(&mut self, assoc: Map<FuncIndex, SigIndex>) -> Result<(), E>;
|
|
||||||
|
|
||||||
|
/// Feeds the compiler config.
|
||||||
|
fn feed_compiler_config(&mut self, _config: &CompilerConfig) -> Result<(), E> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
/// Adds an import function.
|
/// Adds an import function.
|
||||||
fn feed_import_function(&mut self) -> Result<(), E>;
|
fn feed_import_function(&mut self) -> Result<(), E>;
|
||||||
|
|
||||||
|
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
|
||||||
|
/// Sets function signatures.
|
||||||
|
fn feed_function_signatures(&mut self, assoc: Map<FuncIndex, SigIndex>) -> Result<(), E>;
|
||||||
|
/// Checks the precondition for a module.
|
||||||
|
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
|
||||||
|
/// Creates a new function and returns the function-scope code generator for it.
|
||||||
|
fn next_function(&mut self, module_info: Arc<RwLock<ModuleInfo>>) -> Result<&mut FCG, E>;
|
||||||
|
/// Finalizes this module.
|
||||||
|
fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box<dyn CacheGen>), E>;
|
||||||
|
|
||||||
|
/// Creates a module from cache.
|
||||||
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ impl IsExport for Export {
|
|||||||
pub struct ImportObject {
|
pub struct ImportObject {
|
||||||
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
|
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
|
||||||
state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
|
||||||
|
pub allow_missing_functions: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportObject {
|
impl ImportObject {
|
||||||
@ -55,6 +56,7 @@ impl ImportObject {
|
|||||||
Self {
|
Self {
|
||||||
map: Rc::new(RefCell::new(HashMap::new())),
|
map: Rc::new(RefCell::new(HashMap::new())),
|
||||||
state_creator: None,
|
state_creator: None,
|
||||||
|
allow_missing_functions: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +67,7 @@ impl ImportObject {
|
|||||||
Self {
|
Self {
|
||||||
map: Rc::new(RefCell::new(HashMap::new())),
|
map: Rc::new(RefCell::new(HashMap::new())),
|
||||||
state_creator: Some(Rc::new(state_creator)),
|
state_creator: Some(Rc::new(state_creator)),
|
||||||
|
allow_missing_functions: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +119,7 @@ impl ImportObject {
|
|||||||
Self {
|
Self {
|
||||||
map: Rc::clone(&self.map),
|
map: Rc::clone(&self.map),
|
||||||
state_creator: self.state_creator.clone(),
|
state_creator: self.state_creator.clone(),
|
||||||
|
allow_missing_functions: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,11 @@ use crate::{
|
|||||||
export::{Context, Export, ExportIter, FuncPointer},
|
export::{Context, Export, ExportIter, FuncPointer},
|
||||||
global::Global,
|
global::Global,
|
||||||
import::{ImportObject, LikeNamespace},
|
import::{ImportObject, LikeNamespace},
|
||||||
|
loader::Loader,
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
module::{ExportIndex, Module, ModuleInfo, ModuleInner},
|
module::{ExportIndex, Module, ModuleInfo, ModuleInner},
|
||||||
sig_registry::SigRegistry,
|
sig_registry::SigRegistry,
|
||||||
|
structures::TypedIndex,
|
||||||
table::Table,
|
table::Table,
|
||||||
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
|
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
|
||||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
|
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
|
||||||
@ -38,7 +40,7 @@ impl Drop for InstanceInner {
|
|||||||
///
|
///
|
||||||
/// [`ImportObject`]: struct.ImportObject.html
|
/// [`ImportObject`]: struct.ImportObject.html
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
module: Arc<ModuleInner>,
|
pub module: Arc<ModuleInner>,
|
||||||
inner: Box<InstanceInner>,
|
inner: Box<InstanceInner>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
import_object: ImportObject,
|
import_object: ImportObject,
|
||||||
@ -127,6 +129,12 @@ impl Instance {
|
|||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load<T: Loader>(&self, loader: T) -> ::std::result::Result<T::Instance, T::Error> {
|
||||||
|
loader.load(&*self.module.runnable_module, &self.module.info, unsafe {
|
||||||
|
&*self.inner.vmctx
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Through generic magic and the awe-inspiring power of traits, we bring you...
|
/// Through generic magic and the awe-inspiring power of traits, we bring you...
|
||||||
///
|
///
|
||||||
/// # "Func"
|
/// # "Func"
|
||||||
@ -214,6 +222,26 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_func(&self, name: &str) -> ResolveResult<usize> {
|
||||||
|
let export_index =
|
||||||
|
self.module
|
||||||
|
.info
|
||||||
|
.exports
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| ResolveError::ExportNotFound {
|
||||||
|
name: name.to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let ExportIndex::Func(func_index) = export_index {
|
||||||
|
Ok(func_index.index())
|
||||||
|
} else {
|
||||||
|
Err(ResolveError::ExportWrongType {
|
||||||
|
name: name.to_string(),
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This returns the representation of a function that can be called
|
/// This returns the representation of a function that can be called
|
||||||
/// safely.
|
/// safely.
|
||||||
///
|
///
|
||||||
|
@ -21,6 +21,7 @@ pub mod export;
|
|||||||
pub mod global;
|
pub mod global;
|
||||||
pub mod import;
|
pub mod import;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
|
pub mod loader;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
169
lib/runtime-core/src/loader.rs
Normal file
169
lib/runtime-core/src/loader.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use crate::{backend::RunnableModule, module::ModuleInfo, types::Value, vm::Ctx};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use libc::{mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE};
|
||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Loader {
|
||||||
|
type Instance: Instance;
|
||||||
|
type Error: Debug;
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
rm: &dyn RunnableModule,
|
||||||
|
module: &ModuleInfo,
|
||||||
|
ctx: &Ctx,
|
||||||
|
) -> Result<Self::Instance, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance {
|
||||||
|
type Error: Debug;
|
||||||
|
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, Self::Error>;
|
||||||
|
fn read_memory(&mut self, _offset: u32, _len: u32) -> Result<Vec<u8>, Self::Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LocalLoader;
|
||||||
|
|
||||||
|
impl Loader for LocalLoader {
|
||||||
|
type Instance = LocalInstance;
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
rm: &dyn RunnableModule,
|
||||||
|
_module: &ModuleInfo,
|
||||||
|
_ctx: &Ctx,
|
||||||
|
) -> Result<Self::Instance, Self::Error> {
|
||||||
|
let code = rm.get_code().unwrap();
|
||||||
|
let mut code_mem = CodeMemory::new(code.len());
|
||||||
|
code_mem[..code.len()].copy_from_slice(code);
|
||||||
|
code_mem.make_executable();
|
||||||
|
|
||||||
|
Ok(LocalInstance {
|
||||||
|
code: code_mem,
|
||||||
|
offsets: rm.get_offsets().unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LocalInstance {
|
||||||
|
code: CodeMemory,
|
||||||
|
offsets: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for LocalInstance {
|
||||||
|
type Error = String;
|
||||||
|
fn call(&mut self, id: usize, args: &[Value]) -> Result<u64, Self::Error> {
|
||||||
|
let offset = self.offsets[id];
|
||||||
|
let addr: *const u8 = unsafe { self.code.as_ptr().offset(offset as isize) };
|
||||||
|
use std::mem::transmute;
|
||||||
|
Ok(unsafe {
|
||||||
|
match args.len() {
|
||||||
|
0 => (transmute::<_, extern "C" fn() -> u64>(addr))(),
|
||||||
|
1 => (transmute::<_, extern "C" fn(u64) -> u64>(addr))(args[0].to_u64()),
|
||||||
|
2 => (transmute::<_, extern "C" fn(u64, u64) -> u64>(addr))(
|
||||||
|
args[0].to_u64(),
|
||||||
|
args[1].to_u64(),
|
||||||
|
),
|
||||||
|
3 => (transmute::<_, extern "C" fn(u64, u64, u64) -> u64>(addr))(
|
||||||
|
args[0].to_u64(),
|
||||||
|
args[1].to_u64(),
|
||||||
|
args[2].to_u64(),
|
||||||
|
),
|
||||||
|
4 => (transmute::<_, extern "C" fn(u64, u64, u64, u64) -> u64>(addr))(
|
||||||
|
args[0].to_u64(),
|
||||||
|
args[1].to_u64(),
|
||||||
|
args[2].to_u64(),
|
||||||
|
args[3].to_u64(),
|
||||||
|
),
|
||||||
|
5 => (transmute::<_, extern "C" fn(u64, u64, u64, u64, u64) -> u64>(addr))(
|
||||||
|
args[0].to_u64(),
|
||||||
|
args[1].to_u64(),
|
||||||
|
args[2].to_u64(),
|
||||||
|
args[3].to_u64(),
|
||||||
|
args[4].to_u64(),
|
||||||
|
),
|
||||||
|
_ => return Err("too many arguments".into()),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeMemory {
|
||||||
|
ptr: *mut u8,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
impl CodeMemory {
|
||||||
|
pub fn new(_size: usize) -> CodeMemory {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_executable(&mut self) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl CodeMemory {
|
||||||
|
pub fn new(size: usize) -> CodeMemory {
|
||||||
|
fn round_up_to_page_size(size: usize) -> usize {
|
||||||
|
(size + (4096 - 1)) & !(4096 - 1)
|
||||||
|
}
|
||||||
|
let size = round_up_to_page_size(size);
|
||||||
|
let ptr = unsafe {
|
||||||
|
mmap(
|
||||||
|
::std::ptr::null_mut(),
|
||||||
|
size,
|
||||||
|
PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANON,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ptr as isize == -1 {
|
||||||
|
panic!("cannot allocate code memory");
|
||||||
|
}
|
||||||
|
CodeMemory {
|
||||||
|
ptr: ptr as _,
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_executable(&mut self) {
|
||||||
|
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_EXEC) } != 0 {
|
||||||
|
panic!("cannot set code memory to executable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl Drop for CodeMemory {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
munmap(self.ptr as _, self.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for CodeMemory {
|
||||||
|
type Target = [u8];
|
||||||
|
fn deref(&self) -> &[u8] {
|
||||||
|
unsafe { ::std::slice::from_raw_parts(self.ptr, self.size) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for CodeMemory {
|
||||||
|
fn deref_mut(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { ::std::slice::from_raw_parts_mut(self.ptr, self.size) }
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,24 @@ macro_rules! debug {
|
|||||||
($fmt:expr, $($arg:tt)*) => {};
|
($fmt:expr, $($arg:tt)*) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
macro_rules! trace {
|
||||||
|
($fmt:expr) => {
|
||||||
|
debug!($fmt)
|
||||||
|
};
|
||||||
|
($fmt:expr, $($arg:tt)*) => {
|
||||||
|
debug!($fmt, $($arg)*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[cfg(not(feature = "trace"))]
|
||||||
|
macro_rules! trace {
|
||||||
|
($fmt:expr) => {};
|
||||||
|
($fmt:expr, $($arg:tt)*) => {};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! func {
|
macro_rules! func {
|
||||||
($func:path) => {{
|
($func:path) => {{
|
||||||
|
@ -54,6 +54,8 @@ pub fn read_module<
|
|||||||
middlewares: &mut MiddlewareChain,
|
middlewares: &mut MiddlewareChain,
|
||||||
compiler_config: &CompilerConfig,
|
compiler_config: &CompilerConfig,
|
||||||
) -> Result<Arc<RwLock<ModuleInfo>>, LoadError> {
|
) -> Result<Arc<RwLock<ModuleInfo>>, LoadError> {
|
||||||
|
mcg.feed_compiler_config(compiler_config)
|
||||||
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
let info = Arc::new(RwLock::new(ModuleInfo {
|
let info = Arc::new(RwLock::new(ModuleInfo {
|
||||||
memories: Map::new(),
|
memories: Map::new(),
|
||||||
globals: Map::new(),
|
globals: Map::new(),
|
||||||
|
@ -45,6 +45,15 @@ impl Value {
|
|||||||
Value::F64(_) => Type::F64,
|
Value::F64(_) => Type::F64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_u64(&self) -> u64 {
|
||||||
|
match *self {
|
||||||
|
Value::I32(x) => x as u32 as u64,
|
||||||
|
Value::I64(x) => x as u64,
|
||||||
|
Value::F32(x) => f32::to_bits(x) as u64,
|
||||||
|
Value::F64(x) => f64::to_bits(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i32> for Value {
|
impl From<i32> for Value {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
pub use crate::backing::{ImportBacking, LocalBacking};
|
pub use crate::backing::{ImportBacking, LocalBacking};
|
||||||
use crate::{
|
use crate::{
|
||||||
memory::Memory,
|
memory::{Memory, MemoryType},
|
||||||
module::ModuleInner,
|
module::{ModuleInfo, ModuleInner},
|
||||||
structures::TypedIndex,
|
structures::TypedIndex,
|
||||||
types::{LocalOrImport, MemoryIndex},
|
types::{LocalOrImport, MemoryIndex},
|
||||||
|
vmcalls,
|
||||||
};
|
};
|
||||||
use std::{ffi::c_void, mem, ptr};
|
use std::{ffi::c_void, mem, ptr};
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ use hashbrown::HashMap;
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Ctx {
|
pub struct Ctx {
|
||||||
// `internal` must be the first field of `Ctx`.
|
// `internal` must be the first field of `Ctx`.
|
||||||
pub(crate) internal: InternalCtx,
|
pub internal: InternalCtx,
|
||||||
|
|
||||||
pub(crate) local_functions: *const *const Func,
|
pub(crate) local_functions: *const *const Func,
|
||||||
|
|
||||||
@ -84,6 +85,83 @@ pub struct InternalCtx {
|
|||||||
/// signature id. This is used to allow call-indirect to other
|
/// signature id. This is used to allow call-indirect to other
|
||||||
/// modules safely.
|
/// modules safely.
|
||||||
pub dynamic_sigindices: *const SigId,
|
pub dynamic_sigindices: *const SigId,
|
||||||
|
|
||||||
|
pub intrinsics: *const Intrinsics,
|
||||||
|
|
||||||
|
pub stack_lower_bound: *mut u8,
|
||||||
|
|
||||||
|
pub memory_base: *mut u8,
|
||||||
|
pub memory_bound: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Intrinsics {
|
||||||
|
pub memory_grow: *const Func,
|
||||||
|
pub memory_size: *const Func,
|
||||||
|
/*pub memory_grow: unsafe extern "C" fn(
|
||||||
|
ctx: &mut Ctx,
|
||||||
|
memory_index: usize,
|
||||||
|
delta: Pages,
|
||||||
|
) -> i32,
|
||||||
|
pub memory_size: unsafe extern "C" fn(
|
||||||
|
ctx: &Ctx,
|
||||||
|
memory_index: usize,
|
||||||
|
) -> Pages,*/
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Intrinsics {}
|
||||||
|
unsafe impl Sync for Intrinsics {}
|
||||||
|
|
||||||
|
impl Intrinsics {
|
||||||
|
#[allow(clippy::erasing_op)]
|
||||||
|
pub fn offset_memory_grow() -> u8 {
|
||||||
|
(0 * ::std::mem::size_of::<usize>()) as u8
|
||||||
|
}
|
||||||
|
pub fn offset_memory_size() -> u8 {
|
||||||
|
(1 * ::std::mem::size_of::<usize>()) as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static INTRINSICS_LOCAL_STATIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
|
memory_grow: vmcalls::local_static_memory_grow as _,
|
||||||
|
memory_size: vmcalls::local_static_memory_size as _,
|
||||||
|
};
|
||||||
|
pub static INTRINSICS_LOCAL_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
|
memory_grow: vmcalls::local_dynamic_memory_grow as _,
|
||||||
|
memory_size: vmcalls::local_dynamic_memory_size as _,
|
||||||
|
};
|
||||||
|
pub static INTRINSICS_IMPORTED_STATIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
|
memory_grow: vmcalls::imported_static_memory_grow as _,
|
||||||
|
memory_size: vmcalls::imported_static_memory_size as _,
|
||||||
|
};
|
||||||
|
pub static INTRINSICS_IMPORTED_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
|
memory_grow: vmcalls::imported_dynamic_memory_grow as _,
|
||||||
|
memory_size: vmcalls::imported_dynamic_memory_size as _,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn get_intrinsics_for_module(m: &ModuleInfo) -> *const Intrinsics {
|
||||||
|
if m.memories.len() == 0 && m.imported_memories.len() == 0 {
|
||||||
|
::std::ptr::null()
|
||||||
|
} else {
|
||||||
|
match MemoryIndex::new(0).local_or_import(m) {
|
||||||
|
LocalOrImport::Local(local_mem_index) => {
|
||||||
|
let mem_desc = &m.memories[local_mem_index];
|
||||||
|
match mem_desc.memory_type() {
|
||||||
|
MemoryType::Dynamic => &INTRINSICS_LOCAL_DYNAMIC_MEMORY,
|
||||||
|
MemoryType::Static => &INTRINSICS_LOCAL_STATIC_MEMORY,
|
||||||
|
MemoryType::SharedStatic => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocalOrImport::Import(import_mem_index) => {
|
||||||
|
let mem_desc = &m.imported_memories[import_mem_index].1;
|
||||||
|
match mem_desc.memory_type() {
|
||||||
|
MemoryType::Dynamic => &INTRINSICS_IMPORTED_DYNAMIC_MEMORY,
|
||||||
|
MemoryType::Static => &INTRINSICS_IMPORTED_STATIC_MEMORY,
|
||||||
|
MemoryType::SharedStatic => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
@ -93,6 +171,16 @@ impl Ctx {
|
|||||||
import_backing: &mut ImportBacking,
|
import_backing: &mut ImportBacking,
|
||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let (mem_base, mem_bound): (*mut u8, usize) =
|
||||||
|
if module.info.memories.len() == 0 && module.info.imported_memories.len() == 0 {
|
||||||
|
(::std::ptr::null_mut(), 0)
|
||||||
|
} else {
|
||||||
|
let mem = match MemoryIndex::new(0).local_or_import(&module.info) {
|
||||||
|
LocalOrImport::Local(index) => local_backing.vm_memories[index],
|
||||||
|
LocalOrImport::Import(index) => import_backing.vm_memories[index],
|
||||||
|
};
|
||||||
|
((*mem).base, (*mem).bound)
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
internal: InternalCtx {
|
internal: InternalCtx {
|
||||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
@ -105,6 +193,13 @@ impl Ctx {
|
|||||||
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
||||||
|
|
||||||
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
||||||
|
|
||||||
|
intrinsics: get_intrinsics_for_module(&module.info),
|
||||||
|
|
||||||
|
stack_lower_bound: ::std::ptr::null_mut(),
|
||||||
|
|
||||||
|
memory_base: mem_base,
|
||||||
|
memory_bound: mem_bound,
|
||||||
},
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
@ -125,6 +220,16 @@ impl Ctx {
|
|||||||
data: *mut c_void,
|
data: *mut c_void,
|
||||||
data_finalizer: fn(*mut c_void),
|
data_finalizer: fn(*mut c_void),
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let (mem_base, mem_bound): (*mut u8, usize) =
|
||||||
|
if module.info.memories.len() == 0 && module.info.imported_memories.len() == 0 {
|
||||||
|
(::std::ptr::null_mut(), 0)
|
||||||
|
} else {
|
||||||
|
let mem = match MemoryIndex::new(0).local_or_import(&module.info) {
|
||||||
|
LocalOrImport::Local(index) => local_backing.vm_memories[index],
|
||||||
|
LocalOrImport::Import(index) => import_backing.vm_memories[index],
|
||||||
|
};
|
||||||
|
((*mem).base, (*mem).bound)
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
internal: InternalCtx {
|
internal: InternalCtx {
|
||||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
@ -137,6 +242,13 @@ impl Ctx {
|
|||||||
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
||||||
|
|
||||||
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
||||||
|
|
||||||
|
intrinsics: get_intrinsics_for_module(&module.info),
|
||||||
|
|
||||||
|
stack_lower_bound: ::std::ptr::null_mut(),
|
||||||
|
|
||||||
|
memory_base: mem_base,
|
||||||
|
memory_bound: mem_bound,
|
||||||
},
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
@ -186,6 +298,11 @@ impl Ctx {
|
|||||||
pub unsafe fn borrow_symbol_map(&self) -> &Option<HashMap<u32, String>> {
|
pub unsafe fn borrow_symbol_map(&self) -> &Option<HashMap<u32, String>> {
|
||||||
&(*self.module).info.em_symbol_map
|
&(*self.module).info.em_symbol_map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of dynamic sigindices.
|
||||||
|
pub fn dynamic_sigindice_count(&self) -> usize {
|
||||||
|
unsafe { (*self.local_backing).dynamic_sigindices.len() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -223,9 +340,25 @@ impl Ctx {
|
|||||||
7 * (mem::size_of::<usize>() as u8)
|
7 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset_local_functions() -> u8 {
|
pub fn offset_intrinsics() -> u8 {
|
||||||
8 * (mem::size_of::<usize>() as u8)
|
8 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset_stack_lower_bound() -> u8 {
|
||||||
|
9 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_memory_base() -> u8 {
|
||||||
|
10 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_memory_bound() -> u8 {
|
||||||
|
11 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_local_functions() -> u8 {
|
||||||
|
12 * (mem::size_of::<usize>() as u8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InnerFunc {}
|
enum InnerFunc {}
|
||||||
@ -419,6 +552,26 @@ mod vm_offset_tests {
|
|||||||
offset_of!(InternalCtx => imported_funcs).get_byte_offset(),
|
offset_of!(InternalCtx => imported_funcs).get_byte_offset(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_intrinsics() as usize,
|
||||||
|
offset_of!(InternalCtx => intrinsics).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_stack_lower_bound() as usize,
|
||||||
|
offset_of!(InternalCtx => stack_lower_bound).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_memory_base() as usize,
|
||||||
|
offset_of!(InternalCtx => memory_base).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ctx::offset_memory_bound() as usize,
|
||||||
|
offset_of!(InternalCtx => memory_bound).get_byte_offset(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ctx::offset_local_functions() as usize,
|
Ctx::offset_local_functions() as usize,
|
||||||
offset_of!(Ctx => local_functions).get_byte_offset(),
|
offset_of!(Ctx => local_functions).get_byte_offset(),
|
||||||
|
@ -20,10 +20,15 @@ pub unsafe extern "C" fn local_static_memory_grow(
|
|||||||
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
let ret = match (*memory).grow(delta, &mut *local_memory) {
|
||||||
Ok(old) => old.0 as i32,
|
Ok(old) => old.0 as i32,
|
||||||
Err(_) => -1,
|
Err(_) => -1,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ctx.internal.memory_base = (*local_memory).base;
|
||||||
|
ctx.internal.memory_bound = (*local_memory).bound;
|
||||||
|
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn local_static_memory_size(
|
pub unsafe extern "C" fn local_static_memory_size(
|
||||||
@ -44,10 +49,15 @@ pub unsafe extern "C" fn local_dynamic_memory_grow(
|
|||||||
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
let local_memory = *ctx.internal.memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
let ret = match (*memory).grow(delta, &mut *local_memory) {
|
||||||
Ok(old) => old.0 as i32,
|
Ok(old) => old.0 as i32,
|
||||||
Err(_) => -1,
|
Err(_) => -1,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ctx.internal.memory_base = (*local_memory).base;
|
||||||
|
ctx.internal.memory_bound = (*local_memory).bound;
|
||||||
|
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn local_dynamic_memory_size(
|
pub unsafe extern "C" fn local_dynamic_memory_size(
|
||||||
@ -75,10 +85,15 @@ pub unsafe extern "C" fn imported_static_memory_grow(
|
|||||||
.add(import_memory_index.index());
|
.add(import_memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut StaticMemory;
|
let memory = (*local_memory).memory as *mut StaticMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
let ret = match (*memory).grow(delta, &mut *local_memory) {
|
||||||
Ok(old) => old.0 as i32,
|
Ok(old) => old.0 as i32,
|
||||||
Err(_) => -1,
|
Err(_) => -1,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ctx.internal.memory_base = (*local_memory).base;
|
||||||
|
ctx.internal.memory_bound = (*local_memory).bound;
|
||||||
|
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn imported_static_memory_size(
|
pub unsafe extern "C" fn imported_static_memory_size(
|
||||||
@ -102,10 +117,15 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow(
|
|||||||
let local_memory = *ctx.internal.imported_memories.add(memory_index.index());
|
let local_memory = *ctx.internal.imported_memories.add(memory_index.index());
|
||||||
let memory = (*local_memory).memory as *mut DynamicMemory;
|
let memory = (*local_memory).memory as *mut DynamicMemory;
|
||||||
|
|
||||||
match (*memory).grow(delta, &mut *local_memory) {
|
let ret = match (*memory).grow(delta, &mut *local_memory) {
|
||||||
Ok(old) => old.0 as i32,
|
Ok(old) => old.0 as i32,
|
||||||
Err(_) => -1,
|
Err(_) => -1,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ctx.internal.memory_base = (*local_memory).base;
|
||||||
|
ctx.internal.memory_bound = (*local_memory).bound;
|
||||||
|
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn imported_dynamic_memory_size(
|
pub unsafe extern "C" fn imported_dynamic_memory_size(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-runtime"
|
name = "wasmer-runtime"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer runtime library"
|
description = "Wasmer runtime library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,17 +9,17 @@ edition = "2018"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.1", optional = true }
|
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
memmap = "0.7.0"
|
memmap = "0.7.0"
|
||||||
|
|
||||||
[dependencies.wasmer-runtime-core]
|
[dependencies.wasmer-runtime-core]
|
||||||
path = "../runtime-core"
|
path = "../runtime-core"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
|
|
||||||
[dependencies.wasmer-clif-backend]
|
[dependencies.wasmer-clif-backend]
|
||||||
path = "../clif-backend"
|
path = "../clif-backend"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-singlepass-backend"
|
name = "wasmer-singlepass-backend"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
description = "Wasmer runtime single pass compiler backend"
|
description = "Wasmer runtime single pass compiler backend"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@ -8,9 +8,9 @@ authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
wasmparser = "0.29.2"
|
wasmparser = "0.29.2"
|
||||||
dynasm = "0.3.1"
|
dynasm = "0.3.2"
|
||||||
dynasmrt = "0.3.1"
|
dynasmrt = "0.3.1"
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
|
@ -14,7 +14,9 @@ use std::{
|
|||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{sys::Memory, Backend, CacheGen, RunnableModule, Token},
|
backend::{
|
||||||
|
sys::Memory, Backend, CacheGen, CompilerConfig, MemoryBoundCheckMode, RunnableModule, Token,
|
||||||
|
},
|
||||||
cache::{Artifact, Error as CacheError},
|
cache::{Artifact, Error as CacheError},
|
||||||
codegen::*,
|
codegen::*,
|
||||||
memory::MemoryType,
|
memory::MemoryType,
|
||||||
@ -25,8 +27,7 @@ use wasmer_runtime_core::{
|
|||||||
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
|
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
|
||||||
TableIndex, Type,
|
TableIndex, Type,
|
||||||
},
|
},
|
||||||
vm::{self, LocalGlobal, LocalMemory, LocalTable},
|
vm::{self, LocalGlobal, LocalTable},
|
||||||
vmcalls,
|
|
||||||
};
|
};
|
||||||
use wasmparser::{Operator, Type as WpType};
|
use wasmparser::{Operator, Type as WpType};
|
||||||
|
|
||||||
@ -125,6 +126,8 @@ pub struct X64ModuleCodeGenerator {
|
|||||||
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
|
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
|
||||||
assembler: Option<Assembler>,
|
assembler: Option<Assembler>,
|
||||||
func_import_count: usize,
|
func_import_count: usize,
|
||||||
|
|
||||||
|
config: Option<Arc<CodegenConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
@ -139,7 +142,6 @@ pub struct X64FunctionCode {
|
|||||||
|
|
||||||
assembler: Option<Assembler>,
|
assembler: Option<Assembler>,
|
||||||
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
|
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
|
||||||
br_table_data: Option<Vec<Vec<usize>>>,
|
|
||||||
breakpoints: Option<HashMap<AssemblyOffset, Box<Fn(BkptInfo) + Send + Sync + 'static>>>,
|
breakpoints: Option<HashMap<AssemblyOffset, Box<Fn(BkptInfo) + Send + Sync + 'static>>>,
|
||||||
returns: SmallVec<[WpType; 1]>,
|
returns: SmallVec<[WpType; 1]>,
|
||||||
locals: Vec<Location>,
|
locals: Vec<Location>,
|
||||||
@ -149,6 +151,8 @@ pub struct X64FunctionCode {
|
|||||||
control_stack: Vec<ControlFrame>,
|
control_stack: Vec<ControlFrame>,
|
||||||
machine: Machine,
|
machine: Machine,
|
||||||
unreachable_depth: usize,
|
unreachable_depth: usize,
|
||||||
|
|
||||||
|
config: Arc<CodegenConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FuncPtrInner {}
|
enum FuncPtrInner {}
|
||||||
@ -164,8 +168,8 @@ pub struct X64ExecutionContext {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
functions: Vec<X64FunctionCode>,
|
functions: Vec<X64FunctionCode>,
|
||||||
function_pointers: Vec<FuncPtr>,
|
function_pointers: Vec<FuncPtr>,
|
||||||
|
function_offsets: Vec<AssemblyOffset>,
|
||||||
signatures: Arc<Map<SigIndex, FuncSig>>,
|
signatures: Arc<Map<SigIndex, FuncSig>>,
|
||||||
_br_table_data: Vec<Vec<usize>>,
|
|
||||||
breakpoints: Arc<HashMap<usize, Box<Fn(BkptInfo) + Send + Sync + 'static>>>,
|
breakpoints: Arc<HashMap<usize, Box<Fn(BkptInfo) + Send + Sync + 'static>>>,
|
||||||
func_import_count: usize,
|
func_import_count: usize,
|
||||||
}
|
}
|
||||||
@ -275,6 +279,14 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
protect_unix::TRAP_EARLY_DATA.with(|x| x.set(Some(data)));
|
protect_unix::TRAP_EARLY_DATA.with(|x| x.set(Some(data)));
|
||||||
protect_unix::trigger_trap();
|
protect_unix::trigger_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_code(&self) -> Option<&[u8]> {
|
||||||
|
Some(&self.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_offsets(&self) -> Option<Vec<usize>> {
|
||||||
|
Some(self.function_offsets.iter().map(|x| x.0).collect())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -282,6 +294,12 @@ pub struct CodegenError {
|
|||||||
pub message: &'static str,
|
pub message: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
struct CodegenConfig {
|
||||||
|
memory_bound_check_mode: MemoryBoundCheckMode,
|
||||||
|
enforce_stack_check: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
||||||
for X64ModuleCodeGenerator
|
for X64ModuleCodeGenerator
|
||||||
{
|
{
|
||||||
@ -293,6 +311,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
function_labels: Some(HashMap::new()),
|
function_labels: Some(HashMap::new()),
|
||||||
assembler: Some(Assembler::new().unwrap()),
|
assembler: Some(Assembler::new().unwrap()),
|
||||||
func_import_count: 0,
|
func_import_count: 0,
|
||||||
|
config: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,21 +327,19 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
&mut self,
|
&mut self,
|
||||||
_module_info: Arc<RwLock<ModuleInfo>>,
|
_module_info: Arc<RwLock<ModuleInfo>>,
|
||||||
) -> Result<&mut X64FunctionCode, CodegenError> {
|
) -> Result<&mut X64FunctionCode, CodegenError> {
|
||||||
let (mut assembler, mut function_labels, br_table_data, breakpoints) =
|
let (mut assembler, mut function_labels, breakpoints) = match self.functions.last_mut() {
|
||||||
match self.functions.last_mut() {
|
Some(x) => (
|
||||||
Some(x) => (
|
x.assembler.take().unwrap(),
|
||||||
x.assembler.take().unwrap(),
|
x.function_labels.take().unwrap(),
|
||||||
x.function_labels.take().unwrap(),
|
x.breakpoints.take().unwrap(),
|
||||||
x.br_table_data.take().unwrap(),
|
),
|
||||||
x.breakpoints.take().unwrap(),
|
None => (
|
||||||
),
|
self.assembler.take().unwrap(),
|
||||||
None => (
|
self.function_labels.take().unwrap(),
|
||||||
self.assembler.take().unwrap(),
|
HashMap::new(),
|
||||||
self.function_labels.take().unwrap(),
|
),
|
||||||
vec![],
|
};
|
||||||
HashMap::new(),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let begin_offset = assembler.offset();
|
let begin_offset = assembler.offset();
|
||||||
let begin_label_info = function_labels
|
let begin_label_info = function_labels
|
||||||
.entry(self.functions.len() + self.func_import_count)
|
.entry(self.functions.len() + self.func_import_count)
|
||||||
@ -342,7 +359,6 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
|
|
||||||
assembler: Some(assembler),
|
assembler: Some(assembler),
|
||||||
function_labels: Some(function_labels),
|
function_labels: Some(function_labels),
|
||||||
br_table_data: Some(br_table_data),
|
|
||||||
breakpoints: Some(breakpoints),
|
breakpoints: Some(breakpoints),
|
||||||
returns: smallvec![],
|
returns: smallvec![],
|
||||||
locals: vec![],
|
locals: vec![],
|
||||||
@ -352,6 +368,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
control_stack: vec![],
|
control_stack: vec![],
|
||||||
machine: Machine::new(),
|
machine: Machine::new(),
|
||||||
unreachable_depth: 0,
|
unreachable_depth: 0,
|
||||||
|
config: self.config.as_ref().unwrap().clone(),
|
||||||
};
|
};
|
||||||
self.functions.push(code);
|
self.functions.push(code);
|
||||||
Ok(self.functions.last_mut().unwrap())
|
Ok(self.functions.last_mut().unwrap())
|
||||||
@ -361,12 +378,8 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
mut self,
|
mut self,
|
||||||
_: &ModuleInfo,
|
_: &ModuleInfo,
|
||||||
) -> Result<(X64ExecutionContext, Box<dyn CacheGen>), CodegenError> {
|
) -> Result<(X64ExecutionContext, Box<dyn CacheGen>), CodegenError> {
|
||||||
let (assembler, mut br_table_data, breakpoints) = match self.functions.last_mut() {
|
let (assembler, breakpoints) = match self.functions.last_mut() {
|
||||||
Some(x) => (
|
Some(x) => (x.assembler.take().unwrap(), x.breakpoints.take().unwrap()),
|
||||||
x.assembler.take().unwrap(),
|
|
||||||
x.br_table_data.take().unwrap(),
|
|
||||||
x.breakpoints.take().unwrap(),
|
|
||||||
),
|
|
||||||
None => {
|
None => {
|
||||||
return Err(CodegenError {
|
return Err(CodegenError {
|
||||||
message: "no function",
|
message: "no function",
|
||||||
@ -375,18 +388,13 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
};
|
};
|
||||||
let output = assembler.finalize().unwrap();
|
let output = assembler.finalize().unwrap();
|
||||||
|
|
||||||
for table in &mut br_table_data {
|
|
||||||
for entry in table {
|
|
||||||
*entry = output.ptr(AssemblyOffset(*entry)) as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let function_labels = if let Some(x) = self.functions.last() {
|
let function_labels = if let Some(x) = self.functions.last() {
|
||||||
x.function_labels.as_ref().unwrap()
|
x.function_labels.as_ref().unwrap()
|
||||||
} else {
|
} else {
|
||||||
self.function_labels.as_ref().unwrap()
|
self.function_labels.as_ref().unwrap()
|
||||||
};
|
};
|
||||||
let mut out_labels: Vec<FuncPtr> = vec![];
|
let mut out_labels: Vec<FuncPtr> = vec![];
|
||||||
|
let mut out_offsets: Vec<AssemblyOffset> = vec![];
|
||||||
|
|
||||||
for i in 0..function_labels.len() {
|
for i in 0..function_labels.len() {
|
||||||
let (_, offset) = match function_labels.get(&i) {
|
let (_, offset) = match function_labels.get(&i) {
|
||||||
@ -406,6 +414,7 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
out_labels.push(FuncPtr(output.ptr(*offset) as _));
|
out_labels.push(FuncPtr(output.ptr(*offset) as _));
|
||||||
|
out_offsets.push(*offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
let breakpoints: Arc<HashMap<_, _>> = Arc::new(
|
let breakpoints: Arc<HashMap<_, _>> = Arc::new(
|
||||||
@ -423,16 +432,15 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
X64ExecutionContext {
|
X64ExecutionContext {
|
||||||
code: output,
|
code: output,
|
||||||
functions: self.functions,
|
functions: self.functions,
|
||||||
signatures: self.signatures.as_ref().unwrap().clone(),
|
signatures: self.signatures.as_ref().unwrap().clone(),
|
||||||
_br_table_data: br_table_data,
|
|
||||||
breakpoints: breakpoints,
|
breakpoints: breakpoints,
|
||||||
func_import_count: self.func_import_count,
|
func_import_count: self.func_import_count,
|
||||||
function_pointers: out_labels,
|
function_pointers: out_labels,
|
||||||
|
function_offsets: out_offsets,
|
||||||
},
|
},
|
||||||
Box::new(Placeholder),
|
Box::new(Placeholder),
|
||||||
))
|
))
|
||||||
@ -485,6 +493,13 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> {
|
||||||
|
self.config = Some(Arc::new(CodegenConfig {
|
||||||
|
memory_bound_check_mode: config.memory_bound_check_mode,
|
||||||
|
enforce_stack_check: config.enforce_stack_check,
|
||||||
|
}));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
unsafe fn from_cache(_artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
unsafe fn from_cache(_artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||||
Err(CacheError::Unknown(
|
Err(CacheError::Unknown(
|
||||||
"the singlepass compiler API doesn't support caching yet".to_string(),
|
"the singlepass compiler API doesn't support caching yet".to_string(),
|
||||||
@ -1203,6 +1218,7 @@ impl X64FunctionCode {
|
|||||||
/// Emits a memory operation.
|
/// Emits a memory operation.
|
||||||
fn emit_memory_op<F: FnOnce(&mut Assembler, &mut Machine, GPR)>(
|
fn emit_memory_op<F: FnOnce(&mut Assembler, &mut Machine, GPR)>(
|
||||||
module_info: &ModuleInfo,
|
module_info: &ModuleInfo,
|
||||||
|
config: &CodegenConfig,
|
||||||
a: &mut Assembler,
|
a: &mut Assembler,
|
||||||
m: &mut Machine,
|
m: &mut Machine,
|
||||||
addr: Location,
|
addr: Location,
|
||||||
@ -1210,41 +1226,6 @@ impl X64FunctionCode {
|
|||||||
value_size: usize,
|
value_size: usize,
|
||||||
cb: F,
|
cb: F,
|
||||||
) {
|
) {
|
||||||
let tmp_addr = m.acquire_temp_gpr().unwrap();
|
|
||||||
let tmp_base = m.acquire_temp_gpr().unwrap();
|
|
||||||
let tmp_bound = m.acquire_temp_gpr().unwrap();
|
|
||||||
|
|
||||||
// Loads both base and bound into temporary registers.
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::Memory(
|
|
||||||
Machine::get_vmctx_reg(),
|
|
||||||
match MemoryIndex::new(0).local_or_import(module_info) {
|
|
||||||
LocalOrImport::Local(_) => vm::Ctx::offset_memories(),
|
|
||||||
LocalOrImport::Import(_) => vm::Ctx::offset_imported_memories(),
|
|
||||||
} as i32,
|
|
||||||
),
|
|
||||||
Location::GPR(tmp_base),
|
|
||||||
);
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::Memory(tmp_base, 0),
|
|
||||||
Location::GPR(tmp_base),
|
|
||||||
);
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S32,
|
|
||||||
Location::Memory(tmp_base, LocalMemory::offset_bound() as i32),
|
|
||||||
Location::GPR(tmp_bound),
|
|
||||||
);
|
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::Memory(tmp_base, LocalMemory::offset_base() as i32),
|
|
||||||
Location::GPR(tmp_base),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Adds base to bound so `tmp_bound` now holds the end of linear memory.
|
|
||||||
a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_bound));
|
|
||||||
|
|
||||||
// If the memory is dynamic, we need to do bound checking at runtime.
|
// If the memory is dynamic, we need to do bound checking at runtime.
|
||||||
let mem_desc = match MemoryIndex::new(0).local_or_import(module_info) {
|
let mem_desc = match MemoryIndex::new(0).local_or_import(module_info) {
|
||||||
LocalOrImport::Local(local_mem_index) => &module_info.memories[local_mem_index],
|
LocalOrImport::Local(local_mem_index) => &module_info.memories[local_mem_index],
|
||||||
@ -1252,12 +1233,40 @@ impl X64FunctionCode {
|
|||||||
&module_info.imported_memories[import_mem_index].1
|
&module_info.imported_memories[import_mem_index].1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let need_check = match mem_desc.memory_type() {
|
let need_check = match config.memory_bound_check_mode {
|
||||||
MemoryType::Dynamic => true,
|
MemoryBoundCheckMode::Default => match mem_desc.memory_type() {
|
||||||
MemoryType::Static | MemoryType::SharedStatic => false,
|
MemoryType::Dynamic => true,
|
||||||
|
MemoryType::Static | MemoryType::SharedStatic => false,
|
||||||
|
},
|
||||||
|
MemoryBoundCheckMode::Enable => true,
|
||||||
|
MemoryBoundCheckMode::Disable => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let tmp_addr = m.acquire_temp_gpr().unwrap();
|
||||||
|
let tmp_base = m.acquire_temp_gpr().unwrap();
|
||||||
|
let tmp_bound = m.acquire_temp_gpr().unwrap();
|
||||||
|
|
||||||
|
// Load base into temporary register.
|
||||||
|
a.emit_mov(
|
||||||
|
Size::S64,
|
||||||
|
Location::Memory(
|
||||||
|
Machine::get_vmctx_reg(),
|
||||||
|
vm::Ctx::offset_memory_base() as i32,
|
||||||
|
),
|
||||||
|
Location::GPR(tmp_base),
|
||||||
|
);
|
||||||
|
|
||||||
if need_check {
|
if need_check {
|
||||||
|
a.emit_mov(
|
||||||
|
Size::S64,
|
||||||
|
Location::Memory(
|
||||||
|
Machine::get_vmctx_reg(),
|
||||||
|
vm::Ctx::offset_memory_bound() as i32,
|
||||||
|
),
|
||||||
|
Location::GPR(tmp_bound),
|
||||||
|
);
|
||||||
|
// Adds base to bound so `tmp_bound` now holds the end of linear memory.
|
||||||
|
a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_bound));
|
||||||
a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr));
|
a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr));
|
||||||
|
|
||||||
// This branch is used for emitting "faster" code for the special case of (offset + value_size) not exceeding u32 range.
|
// This branch is used for emitting "faster" code for the special case of (offset + value_size) not exceeding u32 range.
|
||||||
@ -1421,6 +1430,19 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
a.emit_push(Size::S64, Location::GPR(GPR::RBP));
|
a.emit_push(Size::S64, Location::GPR(GPR::RBP));
|
||||||
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP));
|
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP));
|
||||||
|
|
||||||
|
// Stack check.
|
||||||
|
if self.config.enforce_stack_check {
|
||||||
|
a.emit_cmp(
|
||||||
|
Size::S64,
|
||||||
|
Location::Memory(
|
||||||
|
GPR::RDI, // first parameter is vmctx
|
||||||
|
vm::Ctx::offset_stack_lower_bound() as i32,
|
||||||
|
),
|
||||||
|
Location::GPR(GPR::RSP),
|
||||||
|
);
|
||||||
|
a.emit_conditional_trap(Condition::Below);
|
||||||
|
}
|
||||||
|
|
||||||
self.locals = self
|
self.locals = self
|
||||||
.machine
|
.machine
|
||||||
.init_locals(a, self.num_locals, self.num_params);
|
.init_locals(a, self.num_locals, self.num_params);
|
||||||
@ -3314,33 +3336,23 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
Operator::Nop => {}
|
Operator::Nop => {}
|
||||||
Operator::MemorySize { reserved } => {
|
Operator::MemorySize { reserved } => {
|
||||||
let memory_index = MemoryIndex::new(reserved as usize);
|
let memory_index = MemoryIndex::new(reserved as usize);
|
||||||
let target: usize = match memory_index.local_or_import(module_info) {
|
a.emit_mov(
|
||||||
LocalOrImport::Local(local_mem_index) => {
|
Size::S64,
|
||||||
let mem_desc = &module_info.memories[local_mem_index];
|
Location::Memory(
|
||||||
match mem_desc.memory_type() {
|
Machine::get_vmctx_reg(),
|
||||||
MemoryType::Dynamic => vmcalls::local_dynamic_memory_size as usize,
|
vm::Ctx::offset_intrinsics() as i32,
|
||||||
MemoryType::Static => vmcalls::local_static_memory_size as usize,
|
),
|
||||||
MemoryType::SharedStatic => unimplemented!(),
|
Location::GPR(GPR::RAX),
|
||||||
}
|
);
|
||||||
}
|
a.emit_mov(
|
||||||
LocalOrImport::Import(import_mem_index) => {
|
Size::S64,
|
||||||
let mem_desc = &module_info.imported_memories[import_mem_index].1;
|
Location::Memory(GPR::RAX, vm::Intrinsics::offset_memory_size() as i32),
|
||||||
match mem_desc.memory_type() {
|
Location::GPR(GPR::RAX),
|
||||||
MemoryType::Dynamic => vmcalls::imported_dynamic_memory_size as usize,
|
);
|
||||||
MemoryType::Static => vmcalls::imported_static_memory_size as usize,
|
|
||||||
MemoryType::SharedStatic => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Self::emit_call_sysv(
|
Self::emit_call_sysv(
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
|a| {
|
|a| {
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::Imm64(target as u64),
|
|
||||||
Location::GPR(GPR::RAX),
|
|
||||||
);
|
|
||||||
a.emit_call_location(Location::GPR(GPR::RAX));
|
a.emit_call_location(Location::GPR(GPR::RAX));
|
||||||
},
|
},
|
||||||
::std::iter::once(Location::Imm32(memory_index.index() as u32)),
|
::std::iter::once(Location::Imm32(memory_index.index() as u32)),
|
||||||
@ -3351,40 +3363,30 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
}
|
}
|
||||||
Operator::MemoryGrow { reserved } => {
|
Operator::MemoryGrow { reserved } => {
|
||||||
let memory_index = MemoryIndex::new(reserved as usize);
|
let memory_index = MemoryIndex::new(reserved as usize);
|
||||||
let target: usize = match memory_index.local_or_import(module_info) {
|
|
||||||
LocalOrImport::Local(local_mem_index) => {
|
|
||||||
let mem_desc = &module_info.memories[local_mem_index];
|
|
||||||
match mem_desc.memory_type() {
|
|
||||||
MemoryType::Dynamic => vmcalls::local_dynamic_memory_grow as usize,
|
|
||||||
MemoryType::Static => vmcalls::local_static_memory_grow as usize,
|
|
||||||
MemoryType::SharedStatic => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LocalOrImport::Import(import_mem_index) => {
|
|
||||||
let mem_desc = &module_info.imported_memories[import_mem_index].1;
|
|
||||||
match mem_desc.memory_type() {
|
|
||||||
MemoryType::Dynamic => vmcalls::imported_dynamic_memory_grow as usize,
|
|
||||||
MemoryType::Static => vmcalls::imported_static_memory_grow as usize,
|
|
||||||
MemoryType::SharedStatic => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let (param_pages, param_pages_lot) = self.value_stack.pop().unwrap();
|
let (param_pages, param_pages_lot) = self.value_stack.pop().unwrap();
|
||||||
|
|
||||||
if param_pages_lot == LocalOrTemp::Temp {
|
if param_pages_lot == LocalOrTemp::Temp {
|
||||||
self.machine.release_locations_only_regs(&[param_pages]);
|
self.machine.release_locations_only_regs(&[param_pages]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.emit_mov(
|
||||||
|
Size::S64,
|
||||||
|
Location::Memory(
|
||||||
|
Machine::get_vmctx_reg(),
|
||||||
|
vm::Ctx::offset_intrinsics() as i32,
|
||||||
|
),
|
||||||
|
Location::GPR(GPR::RAX),
|
||||||
|
);
|
||||||
|
a.emit_mov(
|
||||||
|
Size::S64,
|
||||||
|
Location::Memory(GPR::RAX, vm::Intrinsics::offset_memory_grow() as i32),
|
||||||
|
Location::GPR(GPR::RAX),
|
||||||
|
);
|
||||||
|
|
||||||
Self::emit_call_sysv(
|
Self::emit_call_sysv(
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
|a| {
|
|a| {
|
||||||
a.emit_mov(
|
|
||||||
Size::S64,
|
|
||||||
Location::Imm64(target as u64),
|
|
||||||
Location::GPR(GPR::RAX),
|
|
||||||
);
|
|
||||||
a.emit_call_location(Location::GPR(GPR::RAX));
|
a.emit_call_location(Location::GPR(GPR::RAX));
|
||||||
},
|
},
|
||||||
::std::iter::once(Location::Imm32(memory_index.index() as u32))
|
::std::iter::once(Location::Imm32(memory_index.index() as u32))
|
||||||
@ -3407,6 +3409,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3432,6 +3435,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3457,6 +3461,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3483,6 +3488,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3509,6 +3515,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3535,6 +3542,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3561,6 +3569,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3586,6 +3595,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3611,6 +3621,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3636,6 +3647,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3661,6 +3673,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3686,6 +3699,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3711,6 +3725,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3737,6 +3752,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3763,6 +3779,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3789,6 +3806,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3815,6 +3833,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3846,6 +3865,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target,
|
target,
|
||||||
@ -3872,6 +3892,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3897,6 +3918,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3922,6 +3944,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3947,6 +3970,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -3972,6 +3996,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
|
|
||||||
Self::emit_memory_op(
|
Self::emit_memory_op(
|
||||||
module_info,
|
module_info,
|
||||||
|
&self.config,
|
||||||
a,
|
a,
|
||||||
&mut self.machine,
|
&mut self.machine,
|
||||||
target_addr,
|
target_addr,
|
||||||
@ -4068,7 +4093,8 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
let (targets, default_target) = table.read_table().unwrap();
|
let (targets, default_target) = table.read_table().unwrap();
|
||||||
let cond =
|
let cond =
|
||||||
get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
||||||
let mut table = vec![0usize; targets.len()];
|
let table_label = a.get_label();
|
||||||
|
let mut table: Vec<DynamicLabel> = vec![];
|
||||||
let default_br = a.get_label();
|
let default_br = a.get_label();
|
||||||
Self::emit_relaxed_binop(
|
Self::emit_relaxed_binop(
|
||||||
a,
|
a,
|
||||||
@ -4080,19 +4106,16 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
);
|
);
|
||||||
a.emit_jmp(Condition::AboveEqual, default_br);
|
a.emit_jmp(Condition::AboveEqual, default_br);
|
||||||
|
|
||||||
a.emit_mov(
|
a.emit_lea_label(table_label, Location::GPR(GPR::RCX));
|
||||||
Size::S64,
|
|
||||||
Location::Imm64(table.as_ptr() as usize as u64),
|
|
||||||
Location::GPR(GPR::RCX),
|
|
||||||
);
|
|
||||||
a.emit_mov(Size::S32, cond, Location::GPR(GPR::RDX));
|
a.emit_mov(Size::S32, cond, Location::GPR(GPR::RDX));
|
||||||
a.emit_shl(Size::S32, Location::Imm8(3), Location::GPR(GPR::RDX));
|
a.emit_imul_imm32_gpr64(5, GPR::RDX);
|
||||||
a.emit_add(Size::S64, Location::GPR(GPR::RCX), Location::GPR(GPR::RDX));
|
a.emit_add(Size::S64, Location::GPR(GPR::RCX), Location::GPR(GPR::RDX));
|
||||||
a.emit_jmp_location(Location::Memory(GPR::RDX, 0));
|
a.emit_jmp_location(Location::GPR(GPR::RDX));
|
||||||
|
|
||||||
for (i, target) in targets.iter().enumerate() {
|
for target in targets.iter() {
|
||||||
let AssemblyOffset(offset) = a.offset();
|
let label = a.get_label();
|
||||||
table[i] = offset;
|
a.emit_label(label);
|
||||||
|
table.push(label);
|
||||||
let frame =
|
let frame =
|
||||||
&self.control_stack[self.control_stack.len() - 1 - (*target as usize)];
|
&self.control_stack[self.control_stack.len() - 1 - (*target as usize)];
|
||||||
if !frame.loop_like && frame.returns.len() > 0 {
|
if !frame.loop_like && frame.returns.len() > 0 {
|
||||||
@ -4127,7 +4150,10 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
|
|||||||
a.emit_jmp(Condition::None, frame.label);
|
a.emit_jmp(Condition::None, frame.label);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.br_table_data.as_mut().unwrap().push(table);
|
a.emit_label(table_label);
|
||||||
|
for x in table {
|
||||||
|
a.emit_jmp(Condition::None, x);
|
||||||
|
}
|
||||||
self.unreachable_depth = 1;
|
self.unreachable_depth = 1;
|
||||||
}
|
}
|
||||||
Operator::Drop => {
|
Operator::Drop => {
|
||||||
|
@ -89,6 +89,8 @@ pub trait Emitter {
|
|||||||
fn get_label(&mut self) -> Self::Label;
|
fn get_label(&mut self) -> Self::Label;
|
||||||
fn get_offset(&mut self) -> Self::Offset;
|
fn get_offset(&mut self) -> Self::Offset;
|
||||||
|
|
||||||
|
fn emit_u64(&mut self, x: u64);
|
||||||
|
|
||||||
fn emit_label(&mut self, label: Self::Label);
|
fn emit_label(&mut self, label: Self::Label);
|
||||||
|
|
||||||
fn emit_mov(&mut self, sz: Size, src: Location, dst: Location);
|
fn emit_mov(&mut self, sz: Size, src: Location, dst: Location);
|
||||||
@ -490,6 +492,10 @@ impl Emitter for Assembler {
|
|||||||
self.offset()
|
self.offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_u64(&mut self, x: u64) {
|
||||||
|
self.push_u64(x);
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_label(&mut self, label: Self::Label) {
|
fn emit_label(&mut self, label: Self::Label) {
|
||||||
dynasm!(self ; => label);
|
dynasm!(self ; => label);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-spectests"
|
name = "wasmer-spectests"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer spectests library"
|
description = "Wasmer spectests library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,10 +9,10 @@ edition = "2018"
|
|||||||
build = "build/mod.rs"
|
build = "build/mod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.1" }
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" }
|
||||||
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.1", optional = true }
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.2", optional = true }
|
||||||
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.1", optional = true }
|
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-wasi"
|
name = "wasmer-wasi"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
description = "Wasmer runtime WASI implementation library"
|
description = "Wasmer runtime WASI implementation library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
build = "build/mod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" }
|
||||||
libc = "0.2.50"
|
libc = "0.2.50"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
# wasmer-runtime-abi = { path = "../runtime-abi" }
|
# wasmer-runtime-abi = { path = "../runtime-abi" }
|
||||||
@ -16,3 +17,19 @@ hashbrown = "0.1.8"
|
|||||||
generational-arena = "0.2.2"
|
generational-arena = "0.2.2"
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
byteorder = "1.3.1"
|
byteorder = "1.3.1"
|
||||||
|
# hack to get tests to work
|
||||||
|
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
winapi = "0.3"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
glob = "0.2.11"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" }
|
||||||
|
wasmer-dev-utils = { path = "../dev-utils", version = "0.4.2"}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
clif = []
|
||||||
|
singlepass = ["wasmer-singlepass-backend"]
|
||||||
|
11
lib/wasi/build/mod.rs
Normal file
11
lib/wasi/build/mod.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use std::env;
|
||||||
|
|
||||||
|
mod wasitests;
|
||||||
|
|
||||||
|
static WASITESTS_ENV_VAR: &str = "WASM_WASI_GENERATE_WASITESTS";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if env::var(WASITESTS_ENV_VAR).unwrap_or("0".to_string()) == "1" {
|
||||||
|
wasitests::build();
|
||||||
|
}
|
||||||
|
}
|
207
lib/wasi/build/wasitests.rs
Normal file
207
lib/wasi/build/wasitests.rs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
//! This file will run at build time to autogenerate the WASI regression tests
|
||||||
|
//! It will compile the files indicated in TESTS, to:executable and .wasm
|
||||||
|
//! - Compile with the native rust target to get the expected output
|
||||||
|
//! - Compile with the latest WASI target to get the wasm
|
||||||
|
//! - Generate the test that will compare the output of running the .wasm file
|
||||||
|
//! with wasmer with the expected output
|
||||||
|
|
||||||
|
use glob::glob;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
static BANNER: &str = "// !!! THIS IS A GENERATED FILE !!!
|
||||||
|
// ANY MANUAL EDITS MAY BE OVERWRITTEN AT ANY TIME
|
||||||
|
// Files autogenerated with cargo build (build/wasitests.rs).\n";
|
||||||
|
|
||||||
|
pub fn compile(file: &str, ignores: &HashSet<String>) -> Option<String> {
|
||||||
|
dbg!(file);
|
||||||
|
let mut output_path = PathBuf::from(file);
|
||||||
|
output_path.set_extension("out");
|
||||||
|
|
||||||
|
assert!(file.ends_with(".rs"));
|
||||||
|
let normalized_name = {
|
||||||
|
let mut nn = file.to_lowercase();
|
||||||
|
nn.truncate(file.len() - 3);
|
||||||
|
nn
|
||||||
|
};
|
||||||
|
|
||||||
|
Command::new("rustc")
|
||||||
|
.arg("+nightly")
|
||||||
|
.arg(file)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(&normalized_name)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to compile program to native code");
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
let normal_path = PathBuf::from(&normalized_name);
|
||||||
|
let mut perm = normal_path
|
||||||
|
.metadata()
|
||||||
|
.expect("native executable")
|
||||||
|
.permissions();
|
||||||
|
perm.set_mode(0o766);
|
||||||
|
fs::set_permissions(normal_path, perm).expect("set permissions");
|
||||||
|
}
|
||||||
|
let rs_module_name = {
|
||||||
|
let temp = PathBuf::from(&normalized_name);
|
||||||
|
temp.file_name().unwrap().to_string_lossy().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = Command::new(&normalized_name)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to execute native program");
|
||||||
|
let wasm_out_name = format!("{}.wasm", &normalized_name);
|
||||||
|
|
||||||
|
Command::new("rustc")
|
||||||
|
.arg("+nightly")
|
||||||
|
.arg("--target=wasm32-wasi")
|
||||||
|
.arg(file)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(&wasm_out_name)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to compile program to native code");
|
||||||
|
|
||||||
|
let ignored = if ignores.contains(&rs_module_name) {
|
||||||
|
"\n#[ignore]"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
let src_code = fs::read_to_string(file).expect("read src file");
|
||||||
|
let args = extract_args_from_source_file(&src_code);
|
||||||
|
|
||||||
|
let mapdir_args = if let Some(a) = args {
|
||||||
|
if !a.mapdir.is_empty() {
|
||||||
|
let mut out_str = String::new();
|
||||||
|
out_str.push_str("vec![");
|
||||||
|
for (alias, real_dir) in a.mapdir {
|
||||||
|
out_str.push_str(&format!(
|
||||||
|
"(\"{}\".to_string(), \"{}\".to_string()),",
|
||||||
|
alias, real_dir
|
||||||
|
));
|
||||||
|
}
|
||||||
|
out_str.push_str("]");
|
||||||
|
out_str
|
||||||
|
} else {
|
||||||
|
"vec![]".to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"vec![]".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let contents = format!(
|
||||||
|
"#[test]{ignore}
|
||||||
|
fn test_{rs_module_name}() {{
|
||||||
|
assert_wasi_output!(
|
||||||
|
\"../../{module_path}\",
|
||||||
|
\"{rs_module_name}\",
|
||||||
|
{mapdir_args},
|
||||||
|
\"../../{test_output_path}\"
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
ignore = ignored,
|
||||||
|
module_path = wasm_out_name,
|
||||||
|
rs_module_name = rs_module_name,
|
||||||
|
test_output_path = format!("{}.out", normalized_name),
|
||||||
|
mapdir_args = mapdir_args,
|
||||||
|
);
|
||||||
|
let rust_test_filepath = format!(
|
||||||
|
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/{}.rs"),
|
||||||
|
normalized_name,
|
||||||
|
);
|
||||||
|
fs::write(&rust_test_filepath, contents.as_bytes()).expect("writing test file");
|
||||||
|
fs::write(&output_path, result.stdout).expect("writing output to file");
|
||||||
|
|
||||||
|
Some(rs_module_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build() {
|
||||||
|
let rust_test_modpath = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/wasitests/mod.rs");
|
||||||
|
|
||||||
|
let mut modules: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
let ignores = read_ignore_list();
|
||||||
|
for entry in glob("wasitests/*.rs").unwrap() {
|
||||||
|
match entry {
|
||||||
|
Ok(path) => {
|
||||||
|
let test = path.to_str().unwrap();
|
||||||
|
if let Some(module_name) = compile(test, &ignores) {
|
||||||
|
modules.push(module_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => println!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modules.sort();
|
||||||
|
let mut modules: Vec<String> = modules.iter().map(|m| format!("mod {};", m)).collect();
|
||||||
|
assert!(modules.len() > 0, "Expected > 0 modules found");
|
||||||
|
|
||||||
|
modules.insert(0, BANNER.to_string());
|
||||||
|
modules.insert(1, "// The _common module is not autogenerated. It provides common macros for the wasitests\n#[macro_use]\nmod _common;".to_string());
|
||||||
|
// We add an empty line
|
||||||
|
modules.push("".to_string());
|
||||||
|
|
||||||
|
let modfile: String = modules.join("\n");
|
||||||
|
let source = fs::read(&rust_test_modpath).unwrap();
|
||||||
|
// We only modify the mod file if has changed
|
||||||
|
if source != modfile.as_bytes() {
|
||||||
|
fs::write(&rust_test_modpath, modfile.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_ignore_list() -> HashSet<String> {
|
||||||
|
let f = File::open("wasitests/ignores.txt").unwrap();
|
||||||
|
let f = BufReader::new(f);
|
||||||
|
f.lines()
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.map(|v| v.to_lowercase())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Args {
|
||||||
|
pub mapdir: Vec<(String, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pulls args to the program out of a comment at the top of the file starting with "// Args:"
|
||||||
|
fn extract_args_from_source_file(source_code: &str) -> Option<Args> {
|
||||||
|
if source_code.starts_with("// Args:") {
|
||||||
|
let mut args = Args { mapdir: vec![] };
|
||||||
|
for arg_line in source_code
|
||||||
|
.lines()
|
||||||
|
.skip(1)
|
||||||
|
.take_while(|line| line.starts_with("// "))
|
||||||
|
{
|
||||||
|
let tokenized = arg_line
|
||||||
|
.split_whitespace()
|
||||||
|
.skip(1)
|
||||||
|
.map(String::from)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
match tokenized[1].as_ref() {
|
||||||
|
"mapdir" => {
|
||||||
|
if let [alias, real_dir] = &tokenized[2].split(':').collect::<Vec<&str>>()[..] {
|
||||||
|
args.mapdir.push((alias.to_string(), real_dir.to_string()));
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Parse error in mapdir {} not parsed correctly",
|
||||||
|
&tokenized[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e => {
|
||||||
|
eprintln!("WARN: comment arg: {} is not supported", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(args);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
#[cfg(target = "windows")]
|
||||||
|
extern crate winapi;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
@ -14,6 +16,7 @@ use self::state::{WasiFs, WasiState};
|
|||||||
use self::syscalls::*;
|
use self::syscalls::*;
|
||||||
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub use self::utils::is_wasi_module;
|
pub use self::utils::is_wasi_module;
|
||||||
|
|
||||||
@ -29,6 +32,7 @@ pub fn generate_import_object(
|
|||||||
args: Vec<Vec<u8>>,
|
args: Vec<Vec<u8>>,
|
||||||
envs: Vec<Vec<u8>>,
|
envs: Vec<Vec<u8>>,
|
||||||
preopened_files: Vec<String>,
|
preopened_files: Vec<String>,
|
||||||
|
mapped_dirs: Vec<(String, PathBuf)>,
|
||||||
) -> ImportObject {
|
) -> ImportObject {
|
||||||
let state_gen = move || {
|
let state_gen = move || {
|
||||||
fn state_destructor(data: *mut c_void) {
|
fn state_destructor(data: *mut c_void) {
|
||||||
@ -38,7 +42,7 @@ pub fn generate_import_object(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let state = Box::new(WasiState {
|
let state = Box::new(WasiState {
|
||||||
fs: WasiFs::new(&preopened_files).unwrap(),
|
fs: WasiFs::new(&preopened_files, &mapped_dirs).unwrap(),
|
||||||
args: &args[..],
|
args: &args[..],
|
||||||
envs: &envs[..],
|
envs: &envs[..],
|
||||||
});
|
});
|
||||||
|
@ -3,11 +3,11 @@ macro_rules! wasi_try {
|
|||||||
let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr;
|
let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr;
|
||||||
match res {
|
match res {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
debug!("wasi::wasi_try::val: {:?}", val);
|
wasmer_runtime_core::trace!("wasi::wasi_try::val: {:?}", val);
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("wasi::wasi_try::err: {:?}", err);
|
wasmer_runtime_core::trace!("wasi::wasi_try::err: {:?}", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,21 +175,20 @@ pub struct WasiFs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WasiFs {
|
impl WasiFs {
|
||||||
pub fn new(preopened_dirs: &[String]) -> Result<Self, String> {
|
pub fn new(
|
||||||
/*let repo = RepoOpener::new()
|
preopened_dirs: &[String],
|
||||||
.create(true)
|
mapped_dirs: &[(String, PathBuf)],
|
||||||
.open("mem://wasmer-test-fs", "")
|
) -> Result<Self, String> {
|
||||||
.map_err(|e| e.to_string())?;*/
|
|
||||||
debug!("wasi::fs::inodes");
|
debug!("wasi::fs::inodes");
|
||||||
let inodes = Arena::new();
|
let inodes = Arena::new();
|
||||||
let mut wasi_fs = Self {
|
let mut wasi_fs = Self {
|
||||||
//repo: repo,
|
|
||||||
name_map: HashMap::new(),
|
name_map: HashMap::new(),
|
||||||
inodes: inodes,
|
inodes: inodes,
|
||||||
fd_map: HashMap::new(),
|
fd_map: HashMap::new(),
|
||||||
next_fd: Cell::new(3),
|
next_fd: Cell::new(3),
|
||||||
inode_counter: Cell::new(1000),
|
inode_counter: Cell::new(1000),
|
||||||
};
|
};
|
||||||
|
debug!("wasi::fs::preopen_dirs");
|
||||||
for dir in preopened_dirs {
|
for dir in preopened_dirs {
|
||||||
debug!("Attempting to preopen {}", &dir);
|
debug!("Attempting to preopen {}", &dir);
|
||||||
// TODO: think about this
|
// TODO: think about this
|
||||||
@ -218,6 +217,36 @@ impl WasiFs {
|
|||||||
.create_fd(default_rights, default_rights, 0, inode)
|
.create_fd(default_rights, default_rights, 0, inode)
|
||||||
.expect("Could not open fd");
|
.expect("Could not open fd");
|
||||||
}
|
}
|
||||||
|
debug!("wasi::fs::mapped_dirs");
|
||||||
|
for (alias, real_dir) in mapped_dirs {
|
||||||
|
debug!("Attempting to open {:?} at {}", real_dir, alias);
|
||||||
|
// TODO: think about this
|
||||||
|
let default_rights = 0x1FFFFFFF; // all rights
|
||||||
|
let cur_dir_metadata = real_dir
|
||||||
|
.metadata()
|
||||||
|
.expect("mapped dir not at previously verified location");
|
||||||
|
let kind = if cur_dir_metadata.is_dir() {
|
||||||
|
Kind::Dir {
|
||||||
|
parent: None,
|
||||||
|
path: real_dir.clone(),
|
||||||
|
entries: Default::default(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"WASI only supports pre-opened directories right now; found \"{:?}\"",
|
||||||
|
&real_dir,
|
||||||
|
));
|
||||||
|
};
|
||||||
|
// TODO: handle nested pats in `file`
|
||||||
|
let inode_val =
|
||||||
|
InodeVal::from_file_metadata(&cur_dir_metadata, alias.clone(), true, kind);
|
||||||
|
|
||||||
|
let inode = wasi_fs.inodes.insert(inode_val);
|
||||||
|
wasi_fs.inodes[inode].stat.st_ino = wasi_fs.inode_counter.get();
|
||||||
|
wasi_fs
|
||||||
|
.create_fd(default_rights, default_rights, 0, inode)
|
||||||
|
.expect("Could not open fd");
|
||||||
|
}
|
||||||
debug!("wasi::fs::end");
|
debug!("wasi::fs::end");
|
||||||
Ok(wasi_fs)
|
Ok(wasi_fs)
|
||||||
}
|
}
|
||||||
@ -419,29 +448,10 @@ impl WasiFs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_base_path_for_directory(&self, directory: Inode) -> Option<String> {
|
pub fn get_base_path_for_directory(&self, directory: Inode) -> Option<String> {
|
||||||
let mut path_segments = vec![];
|
if let Kind::Dir { path, .. } = &self.inodes[directory].kind {
|
||||||
let mut cur_inode = directory;
|
return Some(path.to_string_lossy().to_string());
|
||||||
loop {
|
|
||||||
path_segments.push(self.inodes[cur_inode].name.clone());
|
|
||||||
|
|
||||||
if let Kind::Dir { parent, .. } = &self.inodes[cur_inode].kind {
|
|
||||||
if let Some(p_inode) = parent {
|
|
||||||
cur_inode = *p_inode;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None
|
||||||
path_segments.reverse();
|
|
||||||
Some(
|
|
||||||
path_segments
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.fold(path_segments.first()?.clone(), |a, b| a + "/" + b),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,3 +461,77 @@ pub struct WasiState<'a> {
|
|||||||
pub args: &'a [Vec<u8>],
|
pub args: &'a [Vec<u8>],
|
||||||
pub envs: &'a [Vec<u8>],
|
pub envs: &'a [Vec<u8>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_file_type_to_wasi_file_type(file_type: fs::FileType) -> __wasi_filetype_t {
|
||||||
|
// TODO: handle other file types
|
||||||
|
if file_type.is_dir() {
|
||||||
|
__WASI_FILETYPE_DIRECTORY
|
||||||
|
} else if file_type.is_file() {
|
||||||
|
__WASI_FILETYPE_REGULAR_FILE
|
||||||
|
} else if file_type.is_symlink() {
|
||||||
|
__WASI_FILETYPE_SYMBOLIC_LINK
|
||||||
|
} else {
|
||||||
|
__WASI_FILETYPE_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_stat_for_kind(kind: &Kind) -> Option<__wasi_filestat_t> {
|
||||||
|
match kind {
|
||||||
|
Kind::File { handle } => match handle {
|
||||||
|
WasiFile::HostFile(hf) => {
|
||||||
|
let md = hf.metadata().ok()?;
|
||||||
|
|
||||||
|
Some(__wasi_filestat_t {
|
||||||
|
st_filetype: host_file_type_to_wasi_file_type(md.file_type()),
|
||||||
|
st_size: md.len(),
|
||||||
|
st_atim: md
|
||||||
|
.accessed()
|
||||||
|
.ok()?
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.ok()?
|
||||||
|
.as_nanos() as u64,
|
||||||
|
st_mtim: md
|
||||||
|
.modified()
|
||||||
|
.ok()?
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.ok()?
|
||||||
|
.as_nanos() as u64,
|
||||||
|
st_ctim: md
|
||||||
|
.created()
|
||||||
|
.ok()
|
||||||
|
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
|
||||||
|
.map(|ct| ct.as_nanos() as u64)
|
||||||
|
.unwrap_or(0),
|
||||||
|
..__wasi_filestat_t::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Kind::Dir { path, .. } => {
|
||||||
|
let md = path.metadata().ok()?;
|
||||||
|
Some(__wasi_filestat_t {
|
||||||
|
st_filetype: host_file_type_to_wasi_file_type(md.file_type()),
|
||||||
|
st_size: md.len(),
|
||||||
|
st_atim: md
|
||||||
|
.accessed()
|
||||||
|
.ok()?
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.ok()?
|
||||||
|
.as_nanos() as u64,
|
||||||
|
st_mtim: md
|
||||||
|
.modified()
|
||||||
|
.ok()?
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.ok()?
|
||||||
|
.as_nanos() as u64,
|
||||||
|
st_ctim: md
|
||||||
|
.created()
|
||||||
|
.ok()
|
||||||
|
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
|
||||||
|
.map(|ct| ct.as_nanos() as u64)
|
||||||
|
.unwrap_or(0),
|
||||||
|
..__wasi_filestat_t::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,10 @@ pub mod windows;
|
|||||||
use self::types::*;
|
use self::types::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
ptr::{Array, WasmPtr},
|
ptr::{Array, WasmPtr},
|
||||||
state::{Fd, InodeVal, Kind, WasiFile, WasiState, MAX_SYMLINKS},
|
state::{
|
||||||
|
get_stat_for_kind, host_file_type_to_wasi_file_type, Fd, InodeVal, Kind, WasiFile,
|
||||||
|
WasiState, MAX_SYMLINKS,
|
||||||
|
},
|
||||||
ExitCode,
|
ExitCode,
|
||||||
};
|
};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
@ -185,7 +188,10 @@ pub fn clock_time_get(
|
|||||||
precision: __wasi_timestamp_t,
|
precision: __wasi_timestamp_t,
|
||||||
time: WasmPtr<__wasi_timestamp_t>,
|
time: WasmPtr<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
debug!("wasi::clock_time_get");
|
debug!(
|
||||||
|
"wasi::clock_time_get clock_id: {}, precision: {}",
|
||||||
|
clock_id, precision
|
||||||
|
);
|
||||||
let memory = ctx.memory(0);
|
let memory = ctx.memory(0);
|
||||||
|
|
||||||
let out_addr = wasi_try!(time.deref(memory));
|
let out_addr = wasi_try!(time.deref(memory));
|
||||||
@ -789,25 +795,17 @@ pub fn fd_readdir(
|
|||||||
for entry in entries.iter().skip(cookie as usize) {
|
for entry in entries.iter().skip(cookie as usize) {
|
||||||
cur_cookie += 1;
|
cur_cookie += 1;
|
||||||
let entry_path = entry.path();
|
let entry_path = entry.path();
|
||||||
|
let entry_path = wasi_try!(entry_path.file_name().ok_or(__WASI_EIO));
|
||||||
let entry_path_str = entry_path.to_string_lossy();
|
let entry_path_str = entry_path.to_string_lossy();
|
||||||
let namlen = entry_path_str.len();
|
let namlen = entry_path_str.len();
|
||||||
|
debug!("Returning dirent for {}", entry_path_str);
|
||||||
let dirent = __wasi_dirent_t {
|
let dirent = __wasi_dirent_t {
|
||||||
d_next: cur_cookie,
|
d_next: cur_cookie,
|
||||||
d_ino: 0, // TODO: inode
|
d_ino: 0, // TODO: inode
|
||||||
d_namlen: namlen as u32,
|
d_namlen: namlen as u32,
|
||||||
d_type: {
|
d_type: host_file_type_to_wasi_file_type(wasi_try!(entry
|
||||||
let file_type = wasi_try!(entry.file_type().map_err(|_| __WASI_EIO));
|
.file_type()
|
||||||
// TODO: handle other file types
|
.map_err(|_| __WASI_EIO))),
|
||||||
if file_type.is_dir() {
|
|
||||||
__WASI_FILETYPE_DIRECTORY
|
|
||||||
} else if file_type.is_file() {
|
|
||||||
__WASI_FILETYPE_REGULAR_FILE
|
|
||||||
} else if file_type.is_symlink() {
|
|
||||||
__WASI_FILETYPE_SYMBOLIC_LINK
|
|
||||||
} else {
|
|
||||||
__WASI_FILETYPE_UNKNOWN
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
let dirent_bytes = dirent_to_le_bytes(&dirent);
|
let dirent_bytes = dirent_to_le_bytes(&dirent);
|
||||||
let upper_limit = std::cmp::min(
|
let upper_limit = std::cmp::min(
|
||||||
@ -1089,7 +1087,7 @@ pub fn path_create_directory(
|
|||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
};
|
};
|
||||||
let new_inode = state.fs.inodes.insert(InodeVal {
|
let new_inode = state.fs.inodes.insert(InodeVal {
|
||||||
stat: __wasi_filestat_t::default(),
|
stat: wasi_try!(get_stat_for_kind(&kind).ok_or(__WASI_EIO)),
|
||||||
is_preopened: false,
|
is_preopened: false,
|
||||||
name: path_vec[0].clone(),
|
name: path_vec[0].clone(),
|
||||||
kind,
|
kind,
|
||||||
@ -1151,7 +1149,10 @@ pub fn path_filestat_get(
|
|||||||
if path_vec.is_empty() {
|
if path_vec.is_empty() {
|
||||||
return __WASI_EINVAL;
|
return __WASI_EINVAL;
|
||||||
}
|
}
|
||||||
let mut cumulative_path = std::path::PathBuf::new();
|
let mut cumulative_path = std::path::PathBuf::from(wasi_try!(state
|
||||||
|
.fs
|
||||||
|
.get_base_path_for_directory(root_dir.inode)
|
||||||
|
.ok_or(__WASI_EIO)));
|
||||||
|
|
||||||
debug!("=> Path vec: {:?}:", &path_vec);
|
debug!("=> Path vec: {:?}:", &path_vec);
|
||||||
// find the inode by traversing the path
|
// find the inode by traversing the path
|
||||||
@ -1215,64 +1216,28 @@ pub fn path_filestat_get(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_inode = match &state.fs.inodes[inode].kind {
|
let stat = match &state.fs.inodes[inode].kind {
|
||||||
Kind::Dir { path, entries, .. } => {
|
Kind::Dir { path, entries, .. } => {
|
||||||
// TODO: fail earlier if size 0
|
// read it from internal data structures if we can
|
||||||
let last_segment = path_vec.last().unwrap();
|
let last_segment = path_vec.last().unwrap();
|
||||||
cumulative_path.push(last_segment);
|
cumulative_path.push(last_segment);
|
||||||
|
|
||||||
if entries.contains_key(last_segment) {
|
if entries.contains_key(last_segment) {
|
||||||
entries[last_segment]
|
state.fs.inodes[entries[last_segment]].stat
|
||||||
} else {
|
} else {
|
||||||
// lazily load it if we can
|
// otherwise read it from the host FS
|
||||||
if !cumulative_path.exists() {
|
if !cumulative_path.exists() {
|
||||||
return __WASI_ENOENT;
|
return __WASI_ENOENT;
|
||||||
}
|
}
|
||||||
let final_path_metadata =
|
let final_path_metadata =
|
||||||
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EIO));
|
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EIO));
|
||||||
let new_inode = if final_path_metadata.is_dir() {
|
wasi_try!(get_stat_for_kind(&state.fs.inodes[inode].kind).ok_or(__WASI_EIO))
|
||||||
debug!("Opening host directory {:#?}", &cumulative_path);
|
|
||||||
state.fs.inodes.insert(InodeVal {
|
|
||||||
stat: __wasi_filestat_t::default(),
|
|
||||||
is_preopened: false, // is this correct?
|
|
||||||
name: last_segment.clone(),
|
|
||||||
kind: Kind::Dir {
|
|
||||||
parent: Some(inode),
|
|
||||||
path: std::path::PathBuf::from(&last_segment),
|
|
||||||
entries: Default::default(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
debug!("Opening host file {:#?}", &cumulative_path);
|
|
||||||
let real_open_file = wasi_try!(std::fs::OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.open(&cumulative_path)
|
|
||||||
.map_err(|_| __WASI_ENOENT));
|
|
||||||
|
|
||||||
state.fs.inodes.insert(InodeVal {
|
|
||||||
stat: __wasi_filestat_t::default(),
|
|
||||||
is_preopened: false, // is this correct?
|
|
||||||
name: last_segment.clone(),
|
|
||||||
kind: Kind::File {
|
|
||||||
handle: WasiFile::HostFile(real_open_file),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
};
|
|
||||||
// reborrow to insert entry
|
|
||||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[inode].kind {
|
|
||||||
entries.insert(last_segment.clone(), new_inode);
|
|
||||||
}
|
|
||||||
new_inode
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return __WASI_ENOTDIR;
|
return __WASI_ENOTDIR;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let stat = state.fs.inodes[final_inode].stat;
|
|
||||||
|
|
||||||
buf_cell.set(stat);
|
buf_cell.set(stat);
|
||||||
|
|
||||||
__WASI_ESUCCESS
|
__WASI_ESUCCESS
|
||||||
@ -1455,7 +1420,6 @@ pub fn path_open(
|
|||||||
};
|
};
|
||||||
// TODO: handle __WASI_O_TRUNC on directories
|
// TODO: handle __WASI_O_TRUNC on directories
|
||||||
|
|
||||||
dbg!(&cumulative_path);
|
|
||||||
// TODO: refactor and reuse
|
// TODO: refactor and reuse
|
||||||
let cur_file_metadata =
|
let cur_file_metadata =
|
||||||
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EINVAL));
|
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EINVAL));
|
||||||
@ -1499,93 +1463,117 @@ pub fn path_open(
|
|||||||
"Looking for file {} in directory {:#?}",
|
"Looking for file {} in directory {:#?}",
|
||||||
file_name, cumulative_path
|
file_name, cumulative_path
|
||||||
);
|
);
|
||||||
|
|
||||||
cumulative_path.push(file_name);
|
cumulative_path.push(file_name);
|
||||||
let file_path = cumulative_path;
|
let file_path = cumulative_path;
|
||||||
|
|
||||||
let out_fd = if let Kind::Dir { entries, .. } = &mut state.fs.inodes[cur_dir_inode].kind {
|
let out_fd = if let Kind::Dir {
|
||||||
if let Some(child) = entries.get(file_name).cloned() {
|
entries, parent, ..
|
||||||
let child_inode_val = &state.fs.inodes[child];
|
} = &mut state.fs.inodes[cur_dir_inode].kind
|
||||||
// early return based on flags
|
{
|
||||||
if o_flags & __WASI_O_EXCL != 0 {
|
// short circuit logic if attempting to get parent
|
||||||
return __WASI_EEXIST;
|
if file_name == ".." {
|
||||||
}
|
if let Some(p) = parent {
|
||||||
if o_flags & __WASI_O_DIRECTORY != 0 {
|
let parent_inode = *p;
|
||||||
match &child_inode_val.kind {
|
wasi_try!(state.fs.create_fd(
|
||||||
Kind::Dir { .. } => (),
|
fs_rights_base,
|
||||||
Kind::Symlink { .. } => {
|
fs_rights_inheriting,
|
||||||
unimplemented!("Symlinks not yet supported in path_open")
|
fs_flags,
|
||||||
}
|
parent_inode
|
||||||
_ => return __WASI_ENOTDIR,
|
))
|
||||||
}
|
|
||||||
}
|
|
||||||
// do logic on child
|
|
||||||
wasi_try!(state
|
|
||||||
.fs
|
|
||||||
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
|
||||||
} else {
|
|
||||||
let file_metadata = wasi_try!(file_path.metadata().map_err(|_| __WASI_ENOENT));
|
|
||||||
// if entry does not exist in parent directory, try to lazily
|
|
||||||
// load it; possibly creating or truncating it if flags set
|
|
||||||
let kind = if file_metadata.is_dir() {
|
|
||||||
// special dir logic
|
|
||||||
Kind::Dir {
|
|
||||||
parent: Some(cur_dir_inode),
|
|
||||||
path: file_path.clone(),
|
|
||||||
entries: Default::default(),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// file is not a dir
|
return __WASI_EACCES;
|
||||||
let real_opened_file = {
|
|
||||||
let mut open_options = std::fs::OpenOptions::new();
|
|
||||||
let open_options = open_options.read(true).write(true);
|
|
||||||
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
|
||||||
debug!(
|
|
||||||
"File {:?} may be created when opened if it does not exist",
|
|
||||||
&file_path
|
|
||||||
);
|
|
||||||
open_options.create(true)
|
|
||||||
} else {
|
|
||||||
open_options
|
|
||||||
};
|
|
||||||
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
|
||||||
debug!("File {:?} will be truncated when opened", &file_path);
|
|
||||||
open_options.truncate(true)
|
|
||||||
} else {
|
|
||||||
open_options
|
|
||||||
};
|
|
||||||
debug!("Opening host file {:?}", &file_path);
|
|
||||||
let real_open_file = wasi_try!(open_options.open(&file_path).map_err(|e| {
|
|
||||||
dbg!(e);
|
|
||||||
__WASI_EIO
|
|
||||||
}));
|
|
||||||
|
|
||||||
real_open_file
|
|
||||||
};
|
|
||||||
Kind::File {
|
|
||||||
handle: WasiFile::HostFile(real_opened_file),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// record lazily loaded or newly created fd
|
|
||||||
let new_inode = state.fs.inodes.insert(InodeVal {
|
|
||||||
stat: __wasi_filestat_t::default(),
|
|
||||||
is_preopened: false,
|
|
||||||
name: file_name.clone(),
|
|
||||||
kind,
|
|
||||||
});
|
|
||||||
|
|
||||||
// reborrow to insert entry
|
|
||||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
|
|
||||||
entries.insert(file_name.clone(), new_inode);
|
|
||||||
}
|
}
|
||||||
let new_fd = wasi_try!(state.fs.create_fd(
|
} else {
|
||||||
fs_rights_base,
|
if let Some(child) = entries.get(file_name).cloned() {
|
||||||
fs_rights_inheriting,
|
let child_inode_val = &state.fs.inodes[child];
|
||||||
fs_flags,
|
// early return based on flags
|
||||||
new_inode,
|
if o_flags & __WASI_O_EXCL != 0 {
|
||||||
));
|
return __WASI_EEXIST;
|
||||||
|
}
|
||||||
|
if o_flags & __WASI_O_DIRECTORY != 0 {
|
||||||
|
match &child_inode_val.kind {
|
||||||
|
Kind::Dir { .. } => (),
|
||||||
|
Kind::Symlink { .. } => {
|
||||||
|
unimplemented!("Symlinks not yet supported in path_open")
|
||||||
|
}
|
||||||
|
_ => return __WASI_ENOTDIR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// do logic on child
|
||||||
|
wasi_try!(state
|
||||||
|
.fs
|
||||||
|
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
||||||
|
} else {
|
||||||
|
debug!("Attempting to load file from host system");
|
||||||
|
|
||||||
new_fd
|
let file_metadata = file_path.metadata();
|
||||||
|
// if entry does not exist in parent directory, try to lazily
|
||||||
|
// load it; possibly creating or truncating it if flags set
|
||||||
|
let kind = if file_metadata.is_ok() && file_metadata.unwrap().is_dir() {
|
||||||
|
// special dir logic
|
||||||
|
Kind::Dir {
|
||||||
|
parent: Some(cur_dir_inode),
|
||||||
|
path: file_path.clone(),
|
||||||
|
entries: Default::default(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// file is not a dir
|
||||||
|
let real_opened_file = {
|
||||||
|
let mut open_options = std::fs::OpenOptions::new();
|
||||||
|
let open_options = open_options.read(true);
|
||||||
|
let open_options = if fs_rights_base & __WASI_RIGHT_FD_WRITE != 0 {
|
||||||
|
open_options.write(true)
|
||||||
|
} else {
|
||||||
|
open_options
|
||||||
|
};
|
||||||
|
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
||||||
|
debug!(
|
||||||
|
"File {:?} may be created when opened if it does not exist",
|
||||||
|
&file_path
|
||||||
|
);
|
||||||
|
open_options.create(true)
|
||||||
|
} else {
|
||||||
|
open_options
|
||||||
|
};
|
||||||
|
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
||||||
|
debug!("File {:?} will be truncated when opened", &file_path);
|
||||||
|
open_options.truncate(true)
|
||||||
|
} else {
|
||||||
|
open_options
|
||||||
|
};
|
||||||
|
debug!("Opening host file {:?}", &file_path);
|
||||||
|
let real_open_file =
|
||||||
|
wasi_try!(open_options.open(&file_path).map_err(|_| __WASI_EIO));
|
||||||
|
|
||||||
|
real_open_file
|
||||||
|
};
|
||||||
|
Kind::File {
|
||||||
|
handle: WasiFile::HostFile(real_opened_file),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// record lazily loaded or newly created fd
|
||||||
|
let new_inode = state.fs.inodes.insert(InodeVal {
|
||||||
|
stat: wasi_try!(get_stat_for_kind(&kind).ok_or(__WASI_EIO)),
|
||||||
|
is_preopened: false,
|
||||||
|
name: file_name.clone(),
|
||||||
|
kind,
|
||||||
|
});
|
||||||
|
|
||||||
|
// reborrow to insert entry
|
||||||
|
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
|
||||||
|
entries.insert(file_name.clone(), new_inode);
|
||||||
|
}
|
||||||
|
let new_fd = wasi_try!(state.fs.create_fd(
|
||||||
|
fs_rights_base,
|
||||||
|
fs_rights_inheriting,
|
||||||
|
fs_flags,
|
||||||
|
new_inode,
|
||||||
|
));
|
||||||
|
|
||||||
|
new_fd
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// working_dir did not match on Kind::Dir
|
// working_dir did not match on Kind::Dir
|
||||||
|
@ -24,9 +24,9 @@ pub struct __wasi_ciovec_t {
|
|||||||
unsafe impl ValueType for __wasi_ciovec_t {}
|
unsafe impl ValueType for __wasi_ciovec_t {}
|
||||||
|
|
||||||
pub type __wasi_clockid_t = u32;
|
pub type __wasi_clockid_t = u32;
|
||||||
pub const __WASI_CLOCK_MONOTONIC: u32 = 0;
|
pub const __WASI_CLOCK_REALTIME: u32 = 0;
|
||||||
pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 1;
|
pub const __WASI_CLOCK_MONOTONIC: u32 = 1;
|
||||||
pub const __WASI_CLOCK_REALTIME: u32 = 2;
|
pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2;
|
||||||
pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3;
|
pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3;
|
||||||
|
|
||||||
pub type __wasi_device_t = u64;
|
pub type __wasi_device_t = u64;
|
||||||
|
@ -23,7 +23,8 @@ pub fn platform_clock_res_get(
|
|||||||
(clock_getres(unix_clock_id, &mut timespec_out), timespec_out)
|
(clock_getres(unix_clock_id, &mut timespec_out), timespec_out)
|
||||||
};
|
};
|
||||||
|
|
||||||
resolution.set(timespec_out.tv_nsec as __wasi_timestamp_t);
|
let t_out = (timespec_out.tv_sec * 1_000_000_000).wrapping_add(timespec_out.tv_nsec);
|
||||||
|
resolution.set(t_out as __wasi_timestamp_t);
|
||||||
|
|
||||||
// TODO: map output of clock_getres to __wasi_errno_t
|
// TODO: map output of clock_getres to __wasi_errno_t
|
||||||
__WASI_ESUCCESS
|
__WASI_ESUCCESS
|
||||||
@ -50,9 +51,8 @@ pub fn platform_clock_time_get(
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: adjust output by precision...
|
let t_out = (timespec_out.tv_sec * 1_000_000_000).wrapping_add(timespec_out.tv_nsec);
|
||||||
|
time.set(t_out as __wasi_timestamp_t);
|
||||||
time.set(timespec_out.tv_nsec as __wasi_timestamp_t);
|
|
||||||
|
|
||||||
// TODO: map output of clock_gettime to __wasi_errno_t
|
// TODO: map output of clock_gettime to __wasi_errno_t
|
||||||
__WASI_ESUCCESS
|
__WASI_ESUCCESS
|
||||||
|
@ -5,7 +5,22 @@ pub fn platform_clock_res_get(
|
|||||||
clock_id: __wasi_clockid_t,
|
clock_id: __wasi_clockid_t,
|
||||||
resolution: &Cell<__wasi_timestamp_t>,
|
resolution: &Cell<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
__WASI_EINVAL
|
let resolution_val = match clock_id {
|
||||||
|
// resolution of monotonic clock at 10ms, from:
|
||||||
|
// https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-gettickcount64
|
||||||
|
__WASI_CLOCK_MONOTONIC => 10_000_000,
|
||||||
|
// TODO: verify or compute this
|
||||||
|
__WASI_CLOCK_REALTIME => 1,
|
||||||
|
__WASI_CLOCK_PROCESS_CPUTIME_ID => {
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
|
__WASI_CLOCK_THREAD_CPUTIME_ID => {
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
|
_ => return __WASI_EINVAL,
|
||||||
|
};
|
||||||
|
resolution.set(resolution_val);
|
||||||
|
__WASI_ESUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn platform_clock_time_get(
|
pub fn platform_clock_time_get(
|
||||||
@ -13,5 +28,28 @@ pub fn platform_clock_time_get(
|
|||||||
precision: __wasi_timestamp_t,
|
precision: __wasi_timestamp_t,
|
||||||
time: &Cell<__wasi_timestamp_t>,
|
time: &Cell<__wasi_timestamp_t>,
|
||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
unimplemented!()
|
let nanos = match clock_id {
|
||||||
|
__WASI_CLOCK_MONOTONIC => {
|
||||||
|
let tick_ms = unsafe { winapi::um::sysinfoapi::GetTickCount64() };
|
||||||
|
tick_ms * 1_000_000
|
||||||
|
}
|
||||||
|
__WASI_CLOCK_REALTIME => {
|
||||||
|
let duration = wasi_try!(std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.map_err(|e| {
|
||||||
|
debug!("Error in wasi::platform_clock_time_get: {:?}", e);
|
||||||
|
__WASI_EIO
|
||||||
|
}));
|
||||||
|
duration.as_nanos() as u64
|
||||||
|
}
|
||||||
|
__WASI_CLOCK_PROCESS_CPUTIME_ID => {
|
||||||
|
unimplemented!("wasi::platform_clock_time_get(__WASI_CLOCK_PROCESS_CPUTIME_ID, ..)")
|
||||||
|
}
|
||||||
|
__WASI_CLOCK_THREAD_CPUTIME_ID => {
|
||||||
|
unimplemented!("wasi::platform_clock_time_get(__WASI_CLOCK_THREAD_CPUTIME_ID, ..)")
|
||||||
|
}
|
||||||
|
_ => return __WASI_EINVAL,
|
||||||
|
};
|
||||||
|
time.set(nanos);
|
||||||
|
__WASI_ESUCCESS
|
||||||
}
|
}
|
||||||
|
1
lib/wasi/tests/wasitest.rs
Normal file
1
lib/wasi/tests/wasitest.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
mod wasitests;
|
62
lib/wasi/tests/wasitests/_common.rs
Normal file
62
lib/wasi/tests/wasitests/_common.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
macro_rules! assert_wasi_output {
|
||||||
|
($file:expr, $name:expr, $mapdir_args:expr, $expected:expr) => {{
|
||||||
|
use wasmer_dev_utils::stdio::StdioCapturer;
|
||||||
|
use wasmer_runtime_core::{backend::Compiler, Func};
|
||||||
|
use wasmer_wasi::generate_import_object;
|
||||||
|
|
||||||
|
#[cfg(feature = "clif")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
use wasmer_clif_backend::CraneliftCompiler;
|
||||||
|
CraneliftCompiler::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "llvm")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
compile_error!("LLVM compiler not supported right now");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "singlepass")]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
use wasmer_singlepass_backend::SinglePassCompiler;
|
||||||
|
SinglePassCompiler::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
|
||||||
|
fn get_compiler() -> impl Compiler {
|
||||||
|
compile_error!("compiler not specified, activate a compiler via features");
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
let wasm_bytes = include_bytes!($file);
|
||||||
|
|
||||||
|
let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &get_compiler())
|
||||||
|
.expect("WASM can't be compiled");
|
||||||
|
|
||||||
|
let import_object =
|
||||||
|
generate_import_object(vec![], vec![], vec![".".to_string()], $mapdir_args);
|
||||||
|
|
||||||
|
let instance = module
|
||||||
|
.instantiate(&import_object)
|
||||||
|
.map_err(|err| format!("Can't instantiate the WebAssembly module: {:?}", err))
|
||||||
|
.unwrap(); // NOTE: Need to figure what the unwrap is for ??
|
||||||
|
|
||||||
|
let capturer = StdioCapturer::new();
|
||||||
|
|
||||||
|
let start: Func<(), ()> = instance
|
||||||
|
.func("_start")
|
||||||
|
.map_err(|e| format!("{:?}", e))
|
||||||
|
.expect("start function in wasi module");
|
||||||
|
|
||||||
|
start.call().expect("execute the wasm");
|
||||||
|
|
||||||
|
let output = capturer.end().unwrap().0;
|
||||||
|
let expected_output = include_str!($expected);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.contains(expected_output),
|
||||||
|
"Output: `{}` does not contain expected output: `{}`",
|
||||||
|
output,
|
||||||
|
expected_output
|
||||||
|
);
|
||||||
|
}};
|
||||||
|
}
|
10
lib/wasi/tests/wasitests/create_dir.rs
Normal file
10
lib/wasi/tests/wasitests/create_dir.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_create_dir() {
|
||||||
|
assert_wasi_output!(
|
||||||
|
"../../wasitests/create_dir.wasm",
|
||||||
|
"create_dir",
|
||||||
|
vec![],
|
||||||
|
"../../wasitests/create_dir.out"
|
||||||
|
);
|
||||||
|
}
|
9
lib/wasi/tests/wasitests/file_metadata.rs
Normal file
9
lib/wasi/tests/wasitests/file_metadata.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_file_metadata() {
|
||||||
|
assert_wasi_output!(
|
||||||
|
"../../wasitests/file_metadata.wasm",
|
||||||
|
"file_metadata",
|
||||||
|
vec![],
|
||||||
|
"../../wasitests/file_metadata.out"
|
||||||
|
);
|
||||||
|
}
|
9
lib/wasi/tests/wasitests/fs_sandbox_test.rs
Normal file
9
lib/wasi/tests/wasitests/fs_sandbox_test.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_fs_sandbox_test() {
|
||||||
|
assert_wasi_output!(
|
||||||
|
"../../wasitests/fs_sandbox_test.wasm",
|
||||||
|
"fs_sandbox_test",
|
||||||
|
vec![],
|
||||||
|
"../../wasitests/fs_sandbox_test.out"
|
||||||
|
);
|
||||||
|
}
|
9
lib/wasi/tests/wasitests/hello.rs
Normal file
9
lib/wasi/tests/wasitests/hello.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_hello() {
|
||||||
|
assert_wasi_output!(
|
||||||
|
"../../wasitests/hello.wasm",
|
||||||
|
"hello",
|
||||||
|
vec![],
|
||||||
|
"../../wasitests/hello.out"
|
||||||
|
);
|
||||||
|
}
|
9
lib/wasi/tests/wasitests/mapdir.rs
Normal file
9
lib/wasi/tests/wasitests/mapdir.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_mapdir() {
|
||||||
|
assert_wasi_output!(
|
||||||
|
"../../wasitests/mapdir.wasm",
|
||||||
|
"mapdir",
|
||||||
|
vec![],
|
||||||
|
"../../wasitests/mapdir.out"
|
||||||
|
);
|
||||||
|
}
|
13
lib/wasi/tests/wasitests/mod.rs
Normal file
13
lib/wasi/tests/wasitests/mod.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// !!! THIS IS A GENERATED FILE !!!
|
||||||
|
// ANY MANUAL EDITS MAY BE OVERWRITTEN AT ANY TIME
|
||||||
|
// Files autogenerated with cargo build (build/wasitests.rs).
|
||||||
|
|
||||||
|
// The _common module is not autogenerated. It provides common macros for the wasitests
|
||||||
|
#[macro_use]
|
||||||
|
mod _common;
|
||||||
|
mod create_dir;
|
||||||
|
mod file_metadata;
|
||||||
|
mod fs_sandbox_test;
|
||||||
|
mod hello;
|
||||||
|
mod mapdir;
|
||||||
|
mod quine;
|
9
lib/wasi/tests/wasitests/quine.rs
Normal file
9
lib/wasi/tests/wasitests/quine.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#[test]
|
||||||
|
fn test_quine() {
|
||||||
|
assert_wasi_output!(
|
||||||
|
"../../wasitests/quine.wasm",
|
||||||
|
"quine",
|
||||||
|
vec![],
|
||||||
|
"../../wasitests/quine.out"
|
||||||
|
);
|
||||||
|
}
|
BIN
lib/wasi/wasitests/create_dir
Executable file
BIN
lib/wasi/wasitests/create_dir
Executable file
Binary file not shown.
5
lib/wasi/wasitests/create_dir.out
Normal file
5
lib/wasi/wasitests/create_dir.out
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Test file exists: false
|
||||||
|
Dir exists: false
|
||||||
|
Dir exists: false
|
||||||
|
Dir exists: false
|
||||||
|
Success
|
37
lib/wasi/wasitests/create_dir.rs
Normal file
37
lib/wasi/wasitests/create_dir.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
use std::path::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut path = PathBuf::from("wasitests/testing/nested/directories");
|
||||||
|
let test_file = path.join("test.file");
|
||||||
|
fs::create_dir_all(&path).unwrap();
|
||||||
|
{
|
||||||
|
let mut file = fs::OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&test_file)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(file.write(b"hello").unwrap(), 5);
|
||||||
|
|
||||||
|
file.flush().unwrap();
|
||||||
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
let mut in_str = String::new();
|
||||||
|
file.read_to_string(&mut in_str).unwrap();
|
||||||
|
assert_eq!(&in_str, "hello");
|
||||||
|
}
|
||||||
|
fs::remove_file(&test_file).unwrap();
|
||||||
|
println!("Test file exists: {}", test_file.exists());
|
||||||
|
assert!(!test_file.exists());
|
||||||
|
for _ in 0..3 {
|
||||||
|
fs::remove_dir_all(&path).unwrap();
|
||||||
|
println!("Dir exists: {}", path.exists());
|
||||||
|
assert!(!path.exists());
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Success");
|
||||||
|
}
|
BIN
lib/wasi/wasitests/create_dir.wasm
Executable file
BIN
lib/wasi/wasitests/create_dir.wasm
Executable file
Binary file not shown.
BIN
lib/wasi/wasitests/file_metadata
Executable file
BIN
lib/wasi/wasitests/file_metadata
Executable file
Binary file not shown.
3
lib/wasi/wasitests/file_metadata.out
Normal file
3
lib/wasi/wasitests/file_metadata.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
is dir: false
|
||||||
|
filetype: false true false
|
||||||
|
file info: 456
|
17
lib/wasi/wasitests/file_metadata.rs
Normal file
17
lib/wasi/wasitests/file_metadata.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut this_file =
|
||||||
|
fs::File::open("wasitests/file_metadata.rs").expect("could not find src file");
|
||||||
|
let md = this_file.metadata().unwrap();
|
||||||
|
println!("is dir: {}", md.is_dir());
|
||||||
|
let filetype = md.file_type();
|
||||||
|
println!(
|
||||||
|
"filetype: {} {} {}",
|
||||||
|
filetype.is_dir(),
|
||||||
|
filetype.is_file(),
|
||||||
|
filetype.is_symlink()
|
||||||
|
);
|
||||||
|
println!("file info: {}", md.len());
|
||||||
|
}
|
BIN
lib/wasi/wasitests/file_metadata.wasm
Executable file
BIN
lib/wasi/wasitests/file_metadata.wasm
Executable file
Binary file not shown.
BIN
lib/wasi/wasitests/fs_sandbox_test
Executable file
BIN
lib/wasi/wasitests/fs_sandbox_test
Executable file
Binary file not shown.
1
lib/wasi/wasitests/fs_sandbox_test.out
Normal file
1
lib/wasi/wasitests/fs_sandbox_test.out
Normal file
@ -0,0 +1 @@
|
|||||||
|
Reading the parent directory was okay? false
|
10
lib/wasi/wasitests/fs_sandbox_test.rs
Normal file
10
lib/wasi/wasitests/fs_sandbox_test.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
fn main() {
|
||||||
|
#[cfg(target = "wasi")]
|
||||||
|
let result = std::fs::read_dir("..");
|
||||||
|
#[cfg(not(target = "wasi"))]
|
||||||
|
let result: Result<(), String> = Err("placeholder".to_string());
|
||||||
|
println!(
|
||||||
|
"Reading the parent directory was okay? {:?}",
|
||||||
|
result.is_ok()
|
||||||
|
);
|
||||||
|
}
|
BIN
lib/wasi/wasitests/fs_sandbox_test.wasm
Executable file
BIN
lib/wasi/wasitests/fs_sandbox_test.wasm
Executable file
Binary file not shown.
BIN
lib/wasi/wasitests/hello
Executable file
BIN
lib/wasi/wasitests/hello
Executable file
Binary file not shown.
1
lib/wasi/wasitests/hello.out
Normal file
1
lib/wasi/wasitests/hello.out
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hello, world!
|
3
lib/wasi/wasitests/hello.rs
Normal file
3
lib/wasi/wasitests/hello.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
BIN
lib/wasi/wasitests/hello.wasm
Executable file
BIN
lib/wasi/wasitests/hello.wasm
Executable file
Binary file not shown.
1
lib/wasi/wasitests/ignores.txt
Normal file
1
lib/wasi/wasitests/ignores.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
create_dir
|
BIN
lib/wasi/wasitests/mapdir
Executable file
BIN
lib/wasi/wasitests/mapdir
Executable file
Binary file not shown.
6
lib/wasi/wasitests/mapdir.out
Normal file
6
lib/wasi/wasitests/mapdir.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
"wasitests/test_fs/hamlet/README.md"
|
||||||
|
"wasitests/test_fs/hamlet/act1"
|
||||||
|
"wasitests/test_fs/hamlet/act2"
|
||||||
|
"wasitests/test_fs/hamlet/act3"
|
||||||
|
"wasitests/test_fs/hamlet/act4"
|
||||||
|
"wasitests/test_fs/hamlet/act5"
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user