mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-12 08:31:21 +00:00
Merge branch 'master' into feature/dynasm-backend
This commit is contained in:
@ -1,11 +1,12 @@
|
|||||||
branches:
|
|
||||||
except:
|
|
||||||
- master
|
|
||||||
|
|
||||||
version: "{build} ~ {branch}"
|
version: "{build} ~ {branch}"
|
||||||
|
|
||||||
os: Visual Studio 2017
|
os: Visual Studio 2017
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- staging
|
||||||
|
- trying
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- CHANNEL: stable
|
- CHANNEL: stable
|
||||||
@ -13,20 +14,60 @@ environment:
|
|||||||
ABI: msvc
|
ABI: msvc
|
||||||
TARGET: x86_64-pc-windows-msvc
|
TARGET: x86_64-pc-windows-msvc
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- 'C:\Users\appveyor\.cargo'
|
||||||
|
- target
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
# # Install LLVM
|
||||||
- rustup-init.exe -yv --default-host %target%
|
# - mkdir C:\projects\deps
|
||||||
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
# - cd C:\projects\deps
|
||||||
|
# - appveyor DownloadFile http://prereleases.llvm.org/win-snapshots/LLVM-7.0.0-r336178-win64.exe -FileName llvm.exe
|
||||||
|
# - 7z x llvm.exe -oC:\projects\deps\llvm
|
||||||
|
# # - set "PATH=%PATH%;C:\projects\deps\llvm\bin"
|
||||||
|
# - set "LLD_LINK=C:\projects\deps\llvm\bin\lld-link.exe"
|
||||||
|
# - set "LLVM_SYS_70_PREFIX=C:\projects\deps\llvm"
|
||||||
|
# - cd "%APPVEYOR_BUILD_FOLDER%"
|
||||||
|
|
||||||
|
# Install Rust
|
||||||
|
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
|
||||||
|
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||||
|
# - rustup-init.exe -yv --default-host %target%
|
||||||
|
- set PATH=%PATH%;C:\\Libraries\\llvm-5.0.0\\bin;%USERPROFILE%\.cargo\bin
|
||||||
|
- rustup default stable-%target%
|
||||||
|
- rustup update
|
||||||
- rustc -vV
|
- rustc -vV
|
||||||
- cargo -vV
|
- cargo -vV
|
||||||
|
|
||||||
artifacts:
|
# Install InnoSetup
|
||||||
- path: target\debug\wasmer.exe
|
- appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-08-22-is.exe
|
||||||
name: wasmer.exe
|
- 2017-08-22-is.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||||
|
- set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
|
||||||
|
# uncomment to RDP to appveyor
|
||||||
|
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- cargo build --verbose
|
- cargo build --release --verbose
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- set RUST_BACKTRACE=1
|
- cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||||
- cargo test --verbose
|
|
||||||
|
before_deploy:
|
||||||
|
- cd ./src/installer
|
||||||
|
- iscc wasmer.iss
|
||||||
|
- copy /y .\WasmerInstaller.exe ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||||
|
- appveyor PushArtifact ..\..\WasmerInstaller-%APPVEYOR_REPO_TAG_NAME%.exe
|
||||||
|
- cd ..\..\
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
description: 'WasmerInstaller'
|
||||||
|
artifact: /.*\.exe/
|
||||||
|
auth_token:
|
||||||
|
secure: CaKtncy7S1PWxzDUQ0p2264pe3HwxzDn5VIyRizDaa72/SVfskNcoMjwwRh0ut22
|
||||||
|
provider: GitHub
|
||||||
|
on:
|
||||||
|
branch: master
|
||||||
|
appveyor_repo_tag: true
|
||||||
|
@ -13,6 +13,8 @@ jobs:
|
|||||||
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
|
||||||
|
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
- run:
|
- run:
|
||||||
name: Install lint deps
|
name: Install lint deps
|
||||||
command: |
|
command: |
|
||||||
@ -20,7 +22,9 @@ jobs:
|
|||||||
rustup component add clippy
|
rustup component add clippy
|
||||||
- run:
|
- run:
|
||||||
name: Execute lints
|
name: Execute lints
|
||||||
command: make lint
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make lint
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
@ -41,8 +45,23 @@ jobs:
|
|||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
command: |
|
command: |
|
||||||
sudo apt-get install -y cmake
|
sudo apt-get install -y cmake
|
||||||
- run: make test
|
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
- run: make integration-tests
|
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
|
- run:
|
||||||
|
name: Tests
|
||||||
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make test
|
||||||
|
- run:
|
||||||
|
name: Emscripten Tests
|
||||||
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make test-emscripten
|
||||||
|
- run:
|
||||||
|
name: Integration Tests
|
||||||
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make integration-tests
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
@ -66,6 +85,9 @@ jobs:
|
|||||||
curl -O https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz
|
curl -O https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||||
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
|
# Installing LLVM outside of brew
|
||||||
|
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||||
|
tar xf clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||||
- run:
|
- run:
|
||||||
name: Install Rust
|
name: Install Rust
|
||||||
command: |
|
command: |
|
||||||
@ -73,19 +95,31 @@ jobs:
|
|||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
cargo --version
|
cargo --version
|
||||||
- run:
|
- run:
|
||||||
name: Execute tests
|
name: Tests
|
||||||
command: |
|
command: |
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
# We increase the ulimit for fixing cargo unclosed files in mac
|
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||||
ulimit -n 8000
|
ulimit -n 8000
|
||||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||||
make test
|
make test
|
||||||
- run:
|
- run:
|
||||||
name: Execute integration tests
|
name: Emscripten Tests
|
||||||
command: |
|
command: |
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
|
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||||
|
ulimit -n 8000
|
||||||
|
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||||
|
make test-emscripten
|
||||||
|
- run:
|
||||||
|
name: Integration Tests
|
||||||
|
command: |
|
||||||
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
make integration-tests
|
make integration-tests
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
@ -110,12 +144,22 @@ jobs:
|
|||||||
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
|
||||||
|
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
- run:
|
- run:
|
||||||
name: Execute tests
|
name: Tests
|
||||||
command: make test
|
|
||||||
- run:
|
|
||||||
name: Make release build
|
|
||||||
command: |
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make test
|
||||||
|
- run:
|
||||||
|
name: Emscripten Tests
|
||||||
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make test-emscripten
|
||||||
|
- run:
|
||||||
|
name: Release Build
|
||||||
|
command: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
make release
|
make release
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
||||||
@ -153,6 +197,9 @@ jobs:
|
|||||||
curl -O https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz
|
curl -O https://cmake.org/files/v3.4/cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||||
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
tar xf cmake-3.4.1-Darwin-x86_64.tar.gz
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
|
# Installing LLVM outside of brew
|
||||||
|
curl -O https://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||||
|
tar xf clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz
|
||||||
- run:
|
- run:
|
||||||
name: Install Rust
|
name: Install Rust
|
||||||
command: |
|
command: |
|
||||||
@ -160,19 +207,31 @@ jobs:
|
|||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
cargo --version
|
cargo --version
|
||||||
- run:
|
- run:
|
||||||
name: Execute tests
|
name: Tests
|
||||||
command: |
|
command: |
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
# We increase the ulimit for fixing cargo unclosed files in mac
|
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||||
ulimit -n 8000
|
ulimit -n 8000
|
||||||
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||||
make test
|
make test
|
||||||
- run:
|
- run:
|
||||||
name: Make release build
|
name: Emscripten Tests
|
||||||
command: |
|
command: |
|
||||||
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
|
# We increase the ulimit for fixing cargo unclosed files in mac
|
||||||
|
ulimit -n 8000
|
||||||
|
sudo sysctl -w kern.maxfiles=655360 kern.maxfilesperproc=327680
|
||||||
|
make test-emscripten
|
||||||
|
- run:
|
||||||
|
name: Release Build
|
||||||
|
command: |
|
||||||
|
export PATH="`pwd`/cmake-3.4.1-Darwin-x86_64/CMake.app/Contents/bin:$PATH"
|
||||||
|
export PATH="$HOME/.cargo/bin:$PATH"
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/"
|
||||||
make release
|
make release
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
# VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
# VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2)
|
||||||
@ -205,8 +264,12 @@ jobs:
|
|||||||
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
|
||||||
|
tar xf clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
|
||||||
- run: rustup default nightly
|
- run: rustup default nightly
|
||||||
- run: make test
|
- run: |
|
||||||
|
export LLVM_SYS_70_PREFIX="`pwd`/clang+llvm-7.0.0-x86_64-linux-gnu-ubuntu-16.04/"
|
||||||
|
make test
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- /usr/local/cargo/registry
|
- /usr/local/cargo/registry
|
||||||
@ -249,23 +312,31 @@ workflows:
|
|||||||
- test:
|
- test:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
ignore: master
|
only:
|
||||||
|
- trying
|
||||||
|
- staging
|
||||||
- test-macos:
|
- test-macos:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
ignore: master
|
only:
|
||||||
|
- trying
|
||||||
|
- staging
|
||||||
- test-and-build:
|
- test-and-build:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only:
|
||||||
|
- master
|
||||||
- test-and-build-macos:
|
- test-and-build-macos:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only:
|
||||||
|
- master
|
||||||
- test-rust-nightly:
|
- test-rust-nightly:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only:
|
||||||
|
- trying
|
||||||
|
- staging
|
||||||
- publish-github-release:
|
- publish-github-release:
|
||||||
requires:
|
requires:
|
||||||
- lint
|
- lint
|
||||||
|
43
.github/ISSUE_TEMPLATE/---bug-report.md
vendored
Normal file
43
.github/ISSUE_TEMPLATE/---bug-report.md
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F41E Bug report"
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: "\U0001F41E bug"
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Thanks for the bug report!
|
||||||
|
|
||||||
|
### Describe the bug
|
||||||
|
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
Copy and paste the result of executing the following in your shell, so we can know the version of wasmer, Rust (if available) and architecture of your environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "`wasmer -V` | `rustc -V` | `uname -m`"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Steps to reproduce
|
||||||
|
|
||||||
|
1. Go to '…'
|
||||||
|
2. Compile with '…'
|
||||||
|
3. Run '…'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
If applicable, add a link to a test case (as a zip file or link to a repository we can clone).
|
||||||
|
|
||||||
|
### Expected behavior
|
||||||
|
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
### Actual behavior
|
||||||
|
|
||||||
|
A clear and concise description of what actually happened.
|
||||||
|
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
### Additional context
|
||||||
|
|
||||||
|
Add any other context about the problem here.
|
26
.github/ISSUE_TEMPLATE/---feature-request.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/---feature-request.md
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F389 Feature request"
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: "\U0001F389 enhancement"
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Thanks for proposing a new feature!
|
||||||
|
|
||||||
|
### Motivation
|
||||||
|
|
||||||
|
A clear and concise description of what the motivation for the new feature is, and what problem it is solving.
|
||||||
|
|
||||||
|
### Proposed solution
|
||||||
|
|
||||||
|
A clear and concise description of the feature you would like to add, and how it solves the motivating problem.
|
||||||
|
|
||||||
|
### Alternatives
|
||||||
|
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered, and why you're proposed solution is better.
|
||||||
|
|
||||||
|
### Additional context
|
||||||
|
|
||||||
|
Add any other context or screenshots about the feature request here.
|
16
.github/ISSUE_TEMPLATE/--question.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/--question.md
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
name: "❓ Question"
|
||||||
|
about: Ask a question about this project
|
||||||
|
title: ''
|
||||||
|
labels: "❓ question"
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
A clear and concise summary of your question.
|
||||||
|
|
||||||
|
### Additional details
|
||||||
|
|
||||||
|
Provide any additional details here.
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
/artifacts
|
/artifacts
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea
|
.idea
|
||||||
|
**/.vscode
|
||||||
|
@ -2,19 +2,19 @@
|
|||||||
|
|
||||||
Wasmer uses the following components:
|
Wasmer uses the following components:
|
||||||
|
|
||||||
- [Cranelift](https://github.com/cranestation/cranelift): for compiling WASM function binaries into Machine IR
|
- [Cranelift](https://github.com/cranestation/cranelift): for compiling Wasm binaries to machine code
|
||||||
- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and also to run WebAssembly spectests
|
- [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and running WebAssembly spec tests
|
||||||
- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly Modules
|
- [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly modules
|
||||||
|
|
||||||
## How Wasmer works?
|
## How Wasmer works
|
||||||
|
|
||||||
The first time you run `wasmer run myfile.wasm`, wasmer will:
|
The first time you run `wasmer run myfile.wasm`, Wasmer will:
|
||||||
|
|
||||||
- Check if is a `.wast` file. If so, transform it to `.wasm`
|
- Check if is a `.wast` file, and if so, transform it to `.wasm`
|
||||||
- Check that the provided binary is a valid WebAssembly one. That means, that its binary format starts with `\0asm`.
|
- Check that the provided binary is a valid WebAssembly one, i.e. its binary format starts with `\0asm`.
|
||||||
- If it looks like a WebAssembly file, try to parse it with `wasmparser` and generate a `Module` from it
|
- Parse it with `wasmparser` and generate a `Module` from it
|
||||||
- Once a `Module` is generated, an `Instance` is created with the proper `import_object` (that means, if is detected as an emscripten file, it will add the emscripten expected imports)
|
- Generate an `Instance` with the proper `import_object` (that means, if is detected to be an Emscripten file, it will add the Emscripten expected imports)
|
||||||
- Try to call the WebAssembly start function, or if unexistent try to search for the one that is exported as `main`.
|
- Try to call the WebAssembly `start` function, or if it does not exist, try to search for the function that is exported as `main`
|
||||||
|
|
||||||
Find a more detailed explanation of the process below:
|
Find a more detailed explanation of the process below:
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ Find a more detailed explanation of the process below:
|
|||||||
|
|
||||||
As the WebAssembly file is being parsed, it will read the sections in the WebAssembly file (memory, table, function, global and element definitions) using the `Module` (or `ModuleEnvironment`) as the structure to hold this information.
|
As the WebAssembly file is being parsed, it will read the sections in the WebAssembly file (memory, table, function, global and element definitions) using the `Module` (or `ModuleEnvironment`) as the structure to hold this information.
|
||||||
|
|
||||||
However, the real IR initialization happens while a function body is being parsed/created. That means, when the parser reads the section `(func ...)`.
|
However, the real IR initialization happens while a function body is being parsed/created, i.e. when the parser reads the section `(func ...)`.
|
||||||
While the function body is being parsed the corresponding `FuncEnvironment` methods will be called.
|
While the function body is being parsed the corresponding `FuncEnvironment` methods will be called.
|
||||||
|
|
||||||
So for example, if the function is using a table, the `make_table` method within that `FuncEnvironment` will be called.
|
So for example, if the function is using a table, the `make_table` method within that `FuncEnvironment` will be called.
|
||||||
@ -41,15 +41,14 @@ Once we have the compiled values, we will push them to memory and mark them as e
|
|||||||
|
|
||||||
#### Relocations
|
#### Relocations
|
||||||
|
|
||||||
Sometimes the functions that we generated will need to call other functions.
|
Sometimes the functions that we generate will need to call other functions, but the generated code has no idea how to link these functions together.
|
||||||
However the generated code have no idea how to link this functions together.
|
|
||||||
|
|
||||||
For example, if a function `A` is calling function `B` (that means is having a `(call b)` on it's body) while compiling `A` we will have no idea where the function `B` lives on memory (as `B` is not yet compiled nor pushed into memory).
|
For example, if a function `A` is calling function `B` (that means is having a `(call b)` on its body) while compiling `A` we will have no idea where the function `B` lives on memory (as `B` is not yet compiled nor pushed into memory).
|
||||||
|
|
||||||
For that reason, we will start collecting all the calls that function `A` will need to do under the hood, and save it's offsets.
|
For that reason, we will start collecting all the calls that function `A` will need to do under the hood, and save it's offsets.
|
||||||
We do that, so we can patch the function calls after compilation, to point to the correct memory address.
|
We do that, so we can patch the function calls after compilation, to point to the correct memory address.
|
||||||
|
|
||||||
Note: Sometimes this functions rather than living in the same WebAssembly module, they will be provided as import values.
|
Note: sometimes this functions rather than living in the same WebAssembly module, they will be provided as import values.
|
||||||
|
|
||||||
#### Traps
|
#### Traps
|
||||||
|
|
||||||
@ -66,5 +65,5 @@ Once that's finished, we will have a `Instance` function that will be ready to e
|
|||||||
|
|
||||||
## Emscripten
|
## Emscripten
|
||||||
|
|
||||||
The Wasmer Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs.
|
Wasmer's Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs.
|
||||||
We provide this integration by filling the `import_object` with the emscripten functions, while instantiating the WebAssembly Instance.
|
We provide this integration by filling the `import_object` with the Emscripten functions, while instantiating the WebAssembly Instance.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Wasmer is a community effort.
|
Wasmer is a community effort.
|
||||||
In order to build the best WebAssembly runtime it's our duty to see how other runtimes are approaching the same space
|
In order to build the best WebAssembly runtime it's our duty to see how other runtimes are approaching the same space
|
||||||
and get inspired from them on the things that they got right, so wasmer and its community can benefit from a solid
|
and get inspired from them on the things that they got right, so Wasmer and its community can benefit from a solid
|
||||||
foundation.
|
foundation.
|
||||||
|
|
||||||
These are the different project that we used as inspiration:
|
These are the different project that we used as inspiration:
|
||||||
@ -10,9 +10,9 @@ These are the different project that we used as inspiration:
|
|||||||
- [Nebulet](https://github.com/nebulet/nebulet): as the base for creating a great Rust WebAssembly runtime
|
- [Nebulet](https://github.com/nebulet/nebulet): as the base for creating a great Rust WebAssembly runtime
|
||||||
- [WAVM](https://github.com/wavm/wavm): for their great integration and testing framework
|
- [WAVM](https://github.com/wavm/wavm): for their great integration and testing framework
|
||||||
- [greenwasm](https://github.com/Kimundi/greenwasm): for their [spectests framework](https://github.com/Kimundi/greenwasm/tree/master/greenwasm-spectest)
|
- [greenwasm](https://github.com/Kimundi/greenwasm): for their [spectests framework](https://github.com/Kimundi/greenwasm/tree/master/greenwasm-spectest)
|
||||||
- [wasmtime](/wasmtime): on their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs).
|
- [wasmtime](https://github.com/CraneStation/wasmtime): for their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs)
|
||||||
- [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys.
|
- [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys
|
||||||
- [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility.
|
- [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility
|
||||||
|
|
||||||
We would love to hear from you if you think we can take inspiration from other projects that we haven't covered here.
|
We would love to hear from you if you think we can take inspiration from other projects that we haven't covered here.
|
||||||
😊
|
😊
|
||||||
@ -21,7 +21,7 @@ We would love to hear from you if you think we can take inspiration from other p
|
|||||||
|
|
||||||
### Nebulet
|
### Nebulet
|
||||||
|
|
||||||
```
|
```text
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018
|
Copyright (c) 2018
|
||||||
@ -47,7 +47,7 @@ SOFTWARE.
|
|||||||
|
|
||||||
### WAVM
|
### WAVM
|
||||||
|
|
||||||
```
|
```text
|
||||||
Copyright (c) 2018, Andrew Scheidecker
|
Copyright (c) 2018, Andrew Scheidecker
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ The contents of [Test/spec](Test/spec) is covered by the license in [Test/spec/L
|
|||||||
|
|
||||||
### Greenwasm
|
### Greenwasm
|
||||||
|
|
||||||
```
|
```text
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
@ -275,7 +275,7 @@ limitations under the License.
|
|||||||
|
|
||||||
### Wasmtime
|
### Wasmtime
|
||||||
|
|
||||||
```
|
```text
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
@ -497,7 +497,7 @@ Software.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Emscripten
|
### Emscripten
|
||||||
```
|
```text
|
||||||
Emscripten is available under 2 licenses, the MIT license and the
|
Emscripten is available under 2 licenses, the MIT license and the
|
||||||
University of Illinois/NCSA Open Source License.
|
University of Illinois/NCSA Open Source License.
|
||||||
|
|
||||||
|
1011
Cargo.lock
generated
1011
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer"
|
name = "wasmer"
|
||||||
version = "0.1.4"
|
version = "0.2.1"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/wasmerio/wasmer"
|
repository = "https://github.com/wasmerio/wasmer"
|
||||||
@ -26,8 +26,11 @@ wasmer-runtime = { path = "lib/runtime" }
|
|||||||
wasmer-runtime-core = { path = "lib/runtime-core" }
|
wasmer-runtime-core = { path = "lib/runtime-core" }
|
||||||
wasmer-emscripten = { path = "lib/emscripten" }
|
wasmer-emscripten = { path = "lib/emscripten" }
|
||||||
|
|
||||||
|
[target.'cfg(not(windows))'.dependencies]
|
||||||
|
wasmer-llvm-backend = { path = "lib/llvm-backend" }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["lib/clif-backend", "lib/dynasm-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests"]
|
members = ["lib/clif-backend", "lib/dynasm-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
@ -36,6 +39,6 @@ glob = "0.2.11"
|
|||||||
[features]
|
[features]
|
||||||
default = ["fast-tests"]
|
default = ["fast-tests"]
|
||||||
|
|
||||||
debug = []
|
debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
|
||||||
# This feature will allow cargo test to run much faster
|
# This feature will allow cargo test to run much faster
|
||||||
fast-tests = []
|
fast-tests = []
|
||||||
|
4
LICENSE
4
LICENSE
@ -1,6 +1,4 @@
|
|||||||
The MIT License (MIT)
|
Copyright (c) 2019 Syrus Akbary
|
||||||
|
|
||||||
Copyright (c) 2018-Present Syrus Akbary
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
16
Makefile
16
Makefile
@ -16,7 +16,7 @@ emtests:
|
|||||||
# rm -rf artifacts
|
# rm -rf artifacts
|
||||||
|
|
||||||
build:
|
build:
|
||||||
cargo build
|
cargo build --features debug
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cargo install --path .
|
cargo install --path .
|
||||||
@ -34,15 +34,25 @@ precommit: lint test
|
|||||||
|
|
||||||
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 -- --test-threads=1 $(runargs)
|
cargo test --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests -- $(runargs)
|
||||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
||||||
# cargo test -p wasmer-spectests -- --test-threads=1 $(runargs)
|
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||||
|
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
||||||
|
cargo build -p wasmer-runtime-c-api
|
||||||
|
cargo test -p wasmer-runtime-c-api -- --nocapture
|
||||||
|
|
||||||
|
test-emscripten:
|
||||||
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features clif -- --test-threads=1 $(runargs)
|
||||||
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
||||||
|
|
||||||
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
|
||||||
# brew install mingw-w64
|
# brew install mingw-w64
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
|
debug-release:
|
||||||
|
cargo build --release --features debug
|
||||||
|
|
||||||
debug-release:
|
debug-release:
|
||||||
cargo build --release --features "debug"
|
cargo build --release --features "debug"
|
||||||
|
|
||||||
|
82
README.md
82
README.md
@ -1,16 +1,24 @@
|
|||||||
<p align="center"><a href="https://wasmer.io" target="_blank" rel="noopener noreferrer"><img width="400" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo"></a></p>
|
<p align="center">
|
||||||
|
<a href="https://wasmer.io" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img width="400" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://circleci.com/gh/wasmerio/wasmer/"><img src="https://img.shields.io/circleci/project/github/wasmerio/wasmer/master.svg" alt="Build Status"></a>
|
<a href="https://circleci.com/gh/wasmerio/wasmer/">
|
||||||
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE"><img src="https://img.shields.io/github/license/wasmerio/wasmer.svg" alt="License"></a>
|
<img src="https://img.shields.io/circleci/project/github/wasmerio/wasmer/master.svg" alt="Build Status">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/wasmerio/wasmer.svg" alt="License">
|
||||||
|
</a>
|
||||||
<a href="https://spectrum.chat/wasmer">
|
<a href="https://spectrum.chat/wasmer">
|
||||||
<img alt="Join the Wasmer Community" src="https://withspectrum.github.io/badge/badge.svg" />
|
<img src="https://withspectrum.github.io/badge/badge.svg" alt="Join the Wasmer Community">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
[Wasmer](https://wasmer.io/) is a Standalone JIT WebAssembly runtime, aiming to be fully compatible with Emscripten, Rust and Go.
|
[Wasmer](https://wasmer.io/) is a standalone JIT WebAssembly runtime, aiming to be fully compatible with Emscripten, Rust and Go.
|
||||||
|
|
||||||
Install Wasmer with:
|
Install Wasmer with:
|
||||||
|
|
||||||
@ -18,20 +26,20 @@ Install Wasmer with:
|
|||||||
curl https://get.wasmer.io -sSfL | sh
|
curl https://get.wasmer.io -sSfL | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
_**NEW ✨**: Now you can also embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how to do it!_
|
_**NEW ✨**: You can now embed Wasmer in your Rust application, check our [example repo](https://github.com/wasmerio/wasmer-rust-example) to see how!_
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
`wasmer` can execute both the standard binary format (`.wasm`) and the text
|
Wasmer can execute both the standard binary format (`.wasm`) and the text
|
||||||
format defined by the WebAssembly reference interpreter (`.wat`).
|
format defined by the WebAssembly reference interpreter (`.wat`).
|
||||||
|
|
||||||
Once installed, you will be able to run any WebAssembly files (_including Nginx, and Lua!_):
|
Once installed, you will be able to run any WebAssembly files (_including nginx and Lua!_):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Run Lua
|
# Run Lua
|
||||||
wasmer run examples/lua.wasm
|
wasmer run examples/lua.wasm
|
||||||
|
|
||||||
# Run Nginx
|
# Run nginx
|
||||||
wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
|
wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -39,18 +47,18 @@ wasmer run examples/nginx/nginx.wasm -- -p examples/nginx -c nginx.conf
|
|||||||
|
|
||||||
Wasmer is structured into different directories:
|
Wasmer is structured into different directories:
|
||||||
|
|
||||||
- [`src`](./src): code related to the wasmer excutable binary itself
|
- [`src`](./src): code related to the Wasmer executable itself
|
||||||
- [`lib`](./lib): modularized libraries that Wasmer uses under the hood
|
- [`lib`](./lib): modularized libraries that Wasmer uses under the hood
|
||||||
- [`examples`](./examples): some useful examples to getting started with wasmer
|
- [`examples`](./examples): some useful examples to getting started with Wasmer
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Building wasmer requires [rustup](https://rustup.rs/).
|
Building Wasmer requires [rustup](https://rustup.rs/).
|
||||||
|
|
||||||
To install on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/)
|
To build on Windows, download and run [`rustup-init.exe`](https://win.rustup.rs/)
|
||||||
then follow the onscreen instructions.
|
then follow the onscreen instructions.
|
||||||
|
|
||||||
To install on other systems, run:
|
To build on other systems, run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl https://sh.rustup.rs -sSf | sh
|
curl https://sh.rustup.rs -sSf | sh
|
||||||
@ -66,13 +74,13 @@ Please select your operating system:
|
|||||||
|
|
||||||
#### macOS
|
#### macOS
|
||||||
|
|
||||||
If you have [homebrew](https://brew.sh/) installed:
|
If you have [Homebrew](https://brew.sh/) installed:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew install cmake
|
brew install cmake
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, in case you have [ports](https://www.macports.org/install.php):
|
Or, in case you have [MacPorts](https://www.macports.org/install.php):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo port install cmake
|
sudo port install cmake
|
||||||
@ -86,15 +94,23 @@ sudo apt install cmake
|
|||||||
|
|
||||||
#### Windows (MSVC)
|
#### Windows (MSVC)
|
||||||
|
|
||||||
Right now Windows support is _highly experimental_.
|
Windows support is _highly experimental_. Only simple Wasm programs may be run, and no syscalls are allowed. This means
|
||||||
We are working on this so Wasmer can soon be released for Windows.
|
nginx and Lua do not work on Windows. See [this issue](https://github.com/wasmerio/wasmer/issues/176) regarding Emscripten syscall polyfills for Windows.
|
||||||
|
|
||||||
1. Install Python for Windows (https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine.
|
1. Install [Visual Studio](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15)
|
||||||
You should change the installation to install the "Add python.exe to Path" feature.
|
|
||||||
|
|
||||||
2. Install Git for Windows (https://git-scm.com/download/win). DO allow it to add git.exe to the PATH (default
|
2. Install [Rust for Windows](https://win.rustup.rs)
|
||||||
|
|
||||||
|
3. Install [Python for Windows](https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine.
|
||||||
|
Make sure to enable "Add python.exe to Path" during installation.
|
||||||
|
|
||||||
|
4. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default
|
||||||
settings for the installer are fine).
|
settings for the installer are fine).
|
||||||
|
|
||||||
|
5. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH.
|
||||||
|
|
||||||
|
6. Install [LLVM 7.0](https://prereleases.llvm.org/win-snapshots/LLVM-7.0.0-r336178-win64.exe)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Wasmer is built with [Cargo](https://crates.io/), the Rust package manager.
|
Wasmer is built with [Cargo](https://crates.io/), the Rust package manager.
|
||||||
@ -111,7 +127,7 @@ cargo install --path .
|
|||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Thanks to [spectests](https://github.com/wasmerio/wasmer/tree/master/lib/runtime-core/spectests) we can assure 100% compatibility with the WebAssembly spec test suite.
|
Thanks to [spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) we can ensure 100% compatibility with the WebAssembly spec test suite.
|
||||||
|
|
||||||
Tests can be run with:
|
Tests can be run with:
|
||||||
|
|
||||||
@ -119,7 +135,7 @@ Tests can be run with:
|
|||||||
make test
|
make test
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need to re-generate the Rust tests from the spectests
|
If you need to regenerate the Rust tests from the spec tests
|
||||||
you can run:
|
you can run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@ -132,24 +148,32 @@ You can also run integration tests with:
|
|||||||
make integration-tests
|
make integration-tests
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Benchmarking
|
||||||
|
|
||||||
|
Benchmarks can be run with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo bench --all
|
||||||
|
```
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction.
|
Wasmer is an open project guided by strong principles, aiming to be modular, flexible and fast. It is open to the community to help set its direction.
|
||||||
|
|
||||||
Below are some of the goals (written with order) of this project:
|
Below are some of the goals of this project (in order of priority):
|
||||||
|
|
||||||
- [x] It should be 100% compatible with the [WebAssembly Spectest](https://github.com/wasmerio/wasmer/tree/master/spectests)
|
- [x] It should be 100% compatible with the [WebAssembly spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests)
|
||||||
- [x] It should be fast _(partially achieved)_
|
- [x] It should be fast _(partially achieved)_
|
||||||
- [ ] Support Emscripten calls _(in the works)_
|
- [ ] Support Emscripten calls _(in the works)_
|
||||||
- [ ] Support Rust ABI calls
|
- [ ] Support Rust ABI calls
|
||||||
- [ ] Support GO ABI calls
|
- [ ] Support Go ABI calls
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
If you would like to know how Wasmer works under the hood, please visit our [ARCHITECTURE](https://github.com/wasmerio/wasmer/blob/master/ARCHITECTURE.md) document.
|
If you would like to know how Wasmer works under the hood, please see [ARCHITECTURE.md](./ARCHITECTURE.md).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT/Apache-2.0
|
Wasmer is primarily distributed under the terms of the [MIT license](http://opensource.org/licenses/MIT) ([LICENSE](./LICENSE)).
|
||||||
|
|
||||||
<small>[Attributions](./ATTRIBUTIONS.md)</small>.
|
[ATTRIBUTIONS](./ATTRIBUTIONS.md)
|
||||||
|
9
bors.toml
Normal file
9
bors.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
status = [
|
||||||
|
"ci/circleci: lint",
|
||||||
|
"ci/circleci: test",
|
||||||
|
"ci/circleci: test-macos",
|
||||||
|
"continuous-integration/appveyor/branch"
|
||||||
|
]
|
||||||
|
required_approvals = 1
|
||||||
|
timeout_sec = 900
|
||||||
|
delete_merged_branches = true
|
26
examples/nginx/LICENSE
Normal file
26
examples/nginx/LICENSE
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2019 Igor Sysoev
|
||||||
|
* Copyright (C) 2011-2019 Nginx, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
@ -130,10 +130,10 @@ wasmer_link() {
|
|||||||
printf "$cyan> Adding to bash profile...$reset\n"
|
printf "$cyan> Adding to bash profile...$reset\n"
|
||||||
WASMER_PROFILE="$(wasmer_detect_profile)"
|
WASMER_PROFILE="$(wasmer_detect_profile)"
|
||||||
LOAD_STR="\n# Wasmer\nexport WASMER_DIR=\"\$HOME/.wasmer\"\n[ -s \"\$WASMER_DIR/wasmer.sh\" ] && source \"\$WASMER_DIR/wasmer.sh\" # This loads wasmer\n"
|
LOAD_STR="\n# Wasmer\nexport WASMER_DIR=\"\$HOME/.wasmer\"\n[ -s \"\$WASMER_DIR/wasmer.sh\" ] && source \"\$WASMER_DIR/wasmer.sh\" # This loads wasmer\n"
|
||||||
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"\$HOME/.wasmer\"\nexport PATH=\"\$HOME/.wasmer/bin:\$PATH\"\n"
|
SOURCE_STR="# Wasmer config\nexport WASMER_DIR=\"\$HOME/.wasmer\"\nexport WASMER_CACHE_DIR=\"\$WASMER_DIR/cache\"\nexport PATH=\"\$HOME/.wasmer/bin:\$PATH\"\n"
|
||||||
|
|
||||||
# We create the wasmer.sh file
|
# We create the wasmer.sh file
|
||||||
echo "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
|
printf "$SOURCE_STR" > "$HOME/.wasmer/wasmer.sh"
|
||||||
|
|
||||||
if [ -z "${WASMER_PROFILE-}" ] ; then
|
if [ -z "${WASMER_PROFILE-}" ] ; then
|
||||||
printf "${red}Profile not found. Tried:\n* ${WASMER_PROFILE} (as defined in \$PROFILE)\n* ~/.bashrc\n* ~/.bash_profile\n* ~/.zshrc\n* ~/.profile.\n"
|
printf "${red}Profile not found. Tried:\n* ${WASMER_PROFILE} (as defined in \$PROFILE)\n* ~/.bashrc\n* ~/.bash_profile\n* ~/.zshrc\n* ~/.profile.\n"
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# `lua` integration test
|
# `lua` integration test
|
||||||
|
|
||||||
|
|
||||||
This starts wasmer with the lua wasm file. The test asserts on
|
This starts Wasmer with the Lua Wasm file. The test makes assertions on
|
||||||
the output of wasmer. Run test with:
|
the output of Wasmer. Run test with:
|
||||||
|
|
||||||
```
|
```
|
||||||
> ./integration_tests/lua/test.sh
|
> ./integration_tests/lua/test.sh
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
nohup ./target/release/wasmer run examples/lua.wasm &
|
nohup ./target/release/wasmer run examples/lua.wasm --disable-cache -- -v
|
||||||
sleep 3s
|
|
||||||
|
|
||||||
if grep "Lua 5.4.0 Copyright (C) 1994-2018 Lua.org, PUC-Rio" ./nohup.out
|
if grep "Lua 5.4.0 Copyright (C) 1994-2018 Lua.org, PUC-Rio" ./nohup.out
|
||||||
then
|
then
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# `nginx` integration test
|
# `nginx` integration test
|
||||||
|
|
||||||
|
|
||||||
This starts wasmer with the nginx wasm file and serves an html
|
This starts Wasmer with the nginx Wasm file and serves an HTML
|
||||||
file with some simple text to assert on. The test script does
|
file with some simple text to assert on. The test script does
|
||||||
the assertion.
|
the assertion.
|
||||||
|
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
nohup ./target/release/wasmer run examples/nginx/nginx.wasm -- -p integration_tests/nginx/ -c nginx.conf &
|
nohup ./target/release/wasmer run examples/nginx/nginx.wasm --disable-cache -- -v
|
||||||
sleep 3s
|
|
||||||
|
|
||||||
curl localhost:8080 > ./nginx.out
|
if grep "nginx version: nginx/1.15.3" ./nohup.out
|
||||||
|
|
||||||
|
|
||||||
if grep "wasmer" ./nginx.out
|
|
||||||
then
|
then
|
||||||
echo "nginx integration test succeeded"
|
echo "nginx integration test succeeded"
|
||||||
rm ./nohup.out
|
rm ./nohup.out
|
||||||
rm ./nginx.out
|
|
||||||
rm -rf ./integration_tests/nginx/*_temp
|
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
echo "nginx integration test failed"
|
echo "nginx integration test failed"
|
||||||
rm ./nohup.out
|
rm ./nohup.out
|
||||||
rm ./nginx.out
|
|
||||||
rm -rf ./integration_tests/nginx/*_temp
|
|
||||||
exit -1
|
exit -1
|
||||||
fi
|
fi
|
||||||
|
@ -2,35 +2,36 @@
|
|||||||
|
|
||||||
Wasmer is modularized into different libraries, separated into three main sections:
|
Wasmer is modularized into different libraries, separated into three main sections:
|
||||||
|
|
||||||
- [Runtime](#Runtime)
|
- [Runtime](#runtime)
|
||||||
- [Integrations](#Integrations)
|
- [Integrations](#integrations)
|
||||||
- [Backends](#Backends)
|
- [Backends](#backends)
|
||||||
|
|
||||||
## Runtime
|
## Runtime
|
||||||
|
|
||||||
The core of Wasmer is the runtime, which provides the necessary
|
The core of Wasmer is the runtime, which provides the necessary
|
||||||
abstractions to create a good user-experience when embedding.
|
abstractions to create a good user experience when embedding.
|
||||||
|
|
||||||
The runtime is divided into two main libraries:
|
The runtime is divided into two main libraries:
|
||||||
|
|
||||||
- [runtime-core](./runtime-core/): The main implementation of the runtime.
|
- [runtime-core](./runtime-core/): The main implementation of the runtime.
|
||||||
- [runtime](./runtime/): Easy-to-use api on top of runtime-core.
|
- [runtime](./runtime/): Easy-to-use API on top of `runtime-core`.
|
||||||
|
|
||||||
## Integrations
|
## Integrations
|
||||||
|
|
||||||
The intergration run on-top of the Wasmer runtime and allow us to run WebAssembly files compiled for different environments.
|
The integration builds on the Wasmer runtime and allow us to run WebAssembly files compiled for different environments.
|
||||||
|
|
||||||
Wasmer intends to support different integrations:
|
Wasmer intends to support different integrations:
|
||||||
|
|
||||||
- [emscripten](./emscripten): run emscripten-generated WebAssembly files, such as [Lua](../examples/lua.wasm) or [Nginx](../examples/nginx/nginx.wasm).
|
- [emscripten](./emscripten): run Emscripten-generated WebAssembly files, such as [Lua](../examples/lua.wasm) or [nginx](../examples/nginx/nginx.wasm).
|
||||||
- Go ABI: _we will work on this soon! Want to give us a hand? ✋_
|
- Go ABI: _we will work on this soon! Want to give us a hand? ✋_
|
||||||
- Blazor: _researching period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_
|
- Blazor: _research period, see [tracking issue](https://github.com/wasmerio/wasmer/issues/97)_
|
||||||
|
|
||||||
## Backends
|
## Backends
|
||||||
|
|
||||||
The Wasmer [runtime](./runtime) is designed to support multiple compiler backends, allowing the user
|
The Wasmer [runtime](./runtime) is designed to support multiple compiler backends, allowing the user
|
||||||
to tune the codegen properties (compile speed, performance, etc) to fit your usecase best.
|
to tune the codegen properties (compile speed, performance, etc) to best fit their use case.
|
||||||
|
|
||||||
Currently, we support a Cranelift compiler backend:
|
Currently, we support multiple backends for compiling WebAssembly to machine code:
|
||||||
|
|
||||||
- [clif-backend](./clif-backend/): The integration of Wasmer with Cranelift
|
- [clif-backend](./clif-backend/): Cranelift backend
|
||||||
|
- [llvm-backend](./llvm-backend/): LLVM backend
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-clif-backend"
|
name = "wasmer-clif-backend"
|
||||||
version = "0.1.2"
|
version = "0.2.0"
|
||||||
description = "Wasmer runtime Cranelift compiler backend"
|
description = "Wasmer runtime Cranelift compiler backend"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.0" }
|
||||||
cranelift-native = "0.26.0"
|
cranelift-native = "0.26.0"
|
||||||
cranelift-codegen = "0.26.0"
|
cranelift-codegen = "0.26.0"
|
||||||
cranelift-entity = "0.26.0"
|
cranelift-entity = "0.26.0"
|
||||||
@ -18,25 +18,22 @@ target-lexicon = "0.2.0"
|
|||||||
wasmparser = "0.23.0"
|
wasmparser = "0.23.0"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
nix = "0.13.0"
|
nix = "0.13.0"
|
||||||
libc = "0.2.48"
|
libc = "0.2.49"
|
||||||
|
rayon = "1.0"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
optional = true
|
|
||||||
[dependencies.serde_derive]
|
[dependencies.serde_derive]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
optional = true
|
|
||||||
[dependencies.serde_bytes]
|
[dependencies.serde_bytes]
|
||||||
version = "0.10"
|
version = "0.10"
|
||||||
optional = true
|
|
||||||
# [dependencies.bincode]
|
|
||||||
# version = "1.0.1"
|
|
||||||
# optional = true
|
|
||||||
[dependencies.serde-bench]
|
[dependencies.serde-bench]
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
optional = true
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] }
|
||||||
|
wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.2.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
cache = ["serde", "serde_derive", "serde_bytes", "serde-bench", "wasmer-runtime-core/cache"]
|
|
||||||
debug = ["wasmer-runtime-core/debug"]
|
debug = ["wasmer-runtime-core/debug"]
|
@ -1,16 +1,50 @@
|
|||||||
use crate::relocation::{ExternalRelocation, TrapSink};
|
use crate::relocation::{ExternalRelocation, TrapSink};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::Memory,
|
backend::{sys::Memory, CacheGen},
|
||||||
cache::{Cache, Error},
|
cache::{Artifact, Error},
|
||||||
module::ModuleInfo,
|
module::{ModuleInfo, ModuleInner},
|
||||||
structures::Map,
|
structures::Map,
|
||||||
types::{LocalFuncIndex, SigIndex},
|
types::{LocalFuncIndex, SigIndex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde_bench::{deserialize, serialize};
|
use serde_bench::{deserialize, serialize};
|
||||||
|
|
||||||
|
pub struct CacheGenerator {
|
||||||
|
backend_cache: BackendCache,
|
||||||
|
memory: Arc<Memory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheGenerator {
|
||||||
|
pub fn new(backend_cache: BackendCache, memory: Arc<Memory>) -> Self {
|
||||||
|
Self {
|
||||||
|
backend_cache,
|
||||||
|
memory,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheGen for CacheGenerator {
|
||||||
|
fn generate_cache(
|
||||||
|
&self,
|
||||||
|
module: &ModuleInner,
|
||||||
|
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), Error> {
|
||||||
|
let info = Box::new(module.info.clone());
|
||||||
|
|
||||||
|
// Clone the memory to a new location. This could take a long time,
|
||||||
|
// depending on the throughput of your memcpy implementation.
|
||||||
|
let compiled_code = (*self.memory).clone();
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
info,
|
||||||
|
self.backend_cache.into_backend_data()?.into_boxed_slice(),
|
||||||
|
compiled_code,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct TrampolineCache {
|
pub struct TrampolineCache {
|
||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
@ -22,24 +56,24 @@ pub struct TrampolineCache {
|
|||||||
pub struct BackendCache {
|
pub struct BackendCache {
|
||||||
pub external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
pub external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
||||||
pub offsets: Map<LocalFuncIndex, usize>,
|
pub offsets: Map<LocalFuncIndex, usize>,
|
||||||
pub trap_sink: TrapSink,
|
pub trap_sink: Arc<TrapSink>,
|
||||||
pub trampolines: TrampolineCache,
|
pub trampolines: TrampolineCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackendCache {
|
impl BackendCache {
|
||||||
pub fn from_cache(cache: Cache) -> Result<(ModuleInfo, Memory, Self), Error> {
|
pub fn from_cache(cache: Artifact) -> Result<(ModuleInfo, Memory, Self), Error> {
|
||||||
let (info, backend_data, compiled_code) = cache.consume();
|
let (info, backend_data, compiled_code) = cache.consume();
|
||||||
|
|
||||||
let backend_cache = deserialize(backend_data.as_slice())
|
let backend_cache =
|
||||||
.map_err(|e| Error::DeserializeError(e.to_string()))?;
|
deserialize(&backend_data).map_err(|e| Error::DeserializeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((info, compiled_code, backend_cache))
|
Ok((info, compiled_code, backend_cache))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_backend_data(self) -> Result<Vec<u8>, Error> {
|
pub fn into_backend_data(&self) -> Result<Vec<u8>, Error> {
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
serialize(&mut buffer, &self).map_err(|e| Error::SerializeError(e.to_string()))?;
|
serialize(&mut buffer, self).map_err(|e| Error::SerializeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@ impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> {
|
|||||||
let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone();
|
let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone();
|
||||||
|
|
||||||
// Add the vmctx parameter type to it
|
// Add the vmctx parameter type to it
|
||||||
signature.params.push(ir::AbiParam::special(
|
signature.params.insert(
|
||||||
self.pointer_type(),
|
0,
|
||||||
ir::ArgumentPurpose::VMContext,
|
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||||
));
|
);
|
||||||
|
|
||||||
// Return signature
|
// Return signature
|
||||||
signature
|
signature
|
||||||
@ -75,7 +75,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
let ptr_type = self.pointer_type();
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
let local_global_addr = match global_index.local_or_import(self.env.module) {
|
let local_global_addr = match global_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(local_global_index) => {
|
LocalOrImport::Local(local_global_index) => {
|
||||||
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: vmctx,
|
base: vmctx,
|
||||||
@ -145,7 +145,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
let ptr_type = self.pointer_type();
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(self.env.module) {
|
let (local_memory_ptr_ptr, description) =
|
||||||
|
match mem_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(local_mem_index) => {
|
LocalOrImport::Local(local_mem_index) => {
|
||||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: vmctx,
|
base: vmctx,
|
||||||
@ -253,7 +254,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
let ptr_type = self.pointer_type();
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
let (table_struct_ptr_ptr, description) = match table_index.local_or_import(self.env.module)
|
let (table_struct_ptr_ptr, description) = match table_index
|
||||||
|
.local_or_import(&self.env.module.info)
|
||||||
{
|
{
|
||||||
LocalOrImport::Local(local_table_index) => {
|
LocalOrImport::Local(local_table_index) => {
|
||||||
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
@ -443,6 +445,12 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
|
|
||||||
pos.ins().symbol_value(ir::types::I64, sig_index_global)
|
pos.ins().symbol_value(ir::types::I64, sig_index_global)
|
||||||
|
|
||||||
|
// let dynamic_sigindices_array_ptr = pos.ins().load(
|
||||||
|
// ptr_type,
|
||||||
|
// mflags,
|
||||||
|
|
||||||
|
// )
|
||||||
|
|
||||||
// let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64);
|
// let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64);
|
||||||
|
|
||||||
// self.env.deduplicated[clif_sig_index]
|
// self.env.deduplicated[clif_sig_index]
|
||||||
@ -459,8 +467,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
// Build a value list for the indirect call instruction containing the call_args
|
// Build a value list for the indirect call instruction containing the call_args
|
||||||
// and the vmctx parameter.
|
// and the vmctx parameter.
|
||||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||||
args.extend(call_args.iter().cloned());
|
|
||||||
args.push(vmctx_ptr);
|
args.push(vmctx_ptr);
|
||||||
|
args.extend(call_args.iter().cloned());
|
||||||
|
|
||||||
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
|
Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args))
|
||||||
}
|
}
|
||||||
@ -475,9 +483,10 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
call_args: &[ir::Value],
|
call_args: &[ir::Value],
|
||||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||||
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
||||||
|
let ptr_type = self.pointer_type();
|
||||||
|
|
||||||
match callee_index.local_or_import(self.env.module) {
|
match callee_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(_) => {
|
LocalOrImport::Local(local_function_index) => {
|
||||||
// this is an internal function
|
// this is an internal function
|
||||||
let vmctx = pos
|
let vmctx = pos
|
||||||
.func
|
.func
|
||||||
@ -485,13 +494,31 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
.expect("missing vmctx parameter");
|
.expect("missing vmctx parameter");
|
||||||
|
|
||||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||||
args.extend(call_args.iter().cloned());
|
|
||||||
args.push(vmctx);
|
args.push(vmctx);
|
||||||
|
args.extend(call_args.iter().cloned());
|
||||||
|
|
||||||
Ok(pos.ins().call(callee, &args))
|
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
|
||||||
|
let function_ptr = {
|
||||||
|
let mflags = ir::MemFlags::trusted();
|
||||||
|
|
||||||
|
let function_array_ptr = pos.ins().load(
|
||||||
|
ptr_type,
|
||||||
|
mflags,
|
||||||
|
vmctx,
|
||||||
|
vm::Ctx::offset_local_functions() as i32,
|
||||||
|
);
|
||||||
|
|
||||||
|
pos.ins().load(
|
||||||
|
ptr_type,
|
||||||
|
mflags,
|
||||||
|
function_array_ptr,
|
||||||
|
(local_function_index.index() as i32) * 8,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(pos.ins().call_indirect(sig_ref, function_ptr, &args))
|
||||||
}
|
}
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
let ptr_type = self.pointer_type();
|
|
||||||
// this is an imported function
|
// this is an imported function
|
||||||
let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext);
|
let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext);
|
||||||
|
|
||||||
@ -532,8 +559,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
|
let sig_ref = pos.func.dfg.ext_funcs[callee].signature;
|
||||||
|
|
||||||
let mut args = Vec::with_capacity(call_args.len() + 1);
|
let mut args = Vec::with_capacity(call_args.len() + 1);
|
||||||
args.extend(call_args.iter().cloned());
|
|
||||||
args.push(imported_vmctx_addr);
|
args.push(imported_vmctx_addr);
|
||||||
|
args.extend(call_args.iter().cloned());
|
||||||
|
|
||||||
Ok(pos
|
Ok(pos
|
||||||
.ins()
|
.ins()
|
||||||
@ -559,16 +586,17 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::I32),
|
|
||||||
ir::AbiParam::new(ir::types::I32),
|
|
||||||
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::I32),
|
||||||
|
ir::AbiParam::new(ir::types::I32),
|
||||||
],
|
],
|
||||||
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||||
});
|
});
|
||||||
|
|
||||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||||
|
|
||||||
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
|
let (namespace, mem_index, description) =
|
||||||
|
match mem_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(local_mem_index) => (
|
LocalOrImport::Local(local_mem_index) => (
|
||||||
call_names::LOCAL_NAMESPACE,
|
call_names::LOCAL_NAMESPACE,
|
||||||
local_mem_index.index(),
|
local_mem_index.index(),
|
||||||
@ -604,7 +632,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
|
|
||||||
let call_inst = pos
|
let call_inst = pos
|
||||||
.ins()
|
.ins()
|
||||||
.call(mem_grow_func, &[const_mem_index, by_value, vmctx]);
|
.call(mem_grow_func, &[vmctx, const_mem_index, by_value]);
|
||||||
|
|
||||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||||
}
|
}
|
||||||
@ -623,15 +651,16 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::I32),
|
|
||||||
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::I32),
|
||||||
],
|
],
|
||||||
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
returns: vec![ir::AbiParam::new(ir::types::I32)],
|
||||||
});
|
});
|
||||||
|
|
||||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||||
|
|
||||||
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
|
let (namespace, mem_index, description) =
|
||||||
|
match mem_index.local_or_import(&self.env.module.info) {
|
||||||
LocalOrImport::Local(local_mem_index) => (
|
LocalOrImport::Local(local_mem_index) => (
|
||||||
call_names::LOCAL_NAMESPACE,
|
call_names::LOCAL_NAMESPACE,
|
||||||
local_mem_index.index(),
|
local_mem_index.index(),
|
||||||
@ -664,7 +693,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
|||||||
.special_param(ir::ArgumentPurpose::VMContext)
|
.special_param(ir::ArgumentPurpose::VMContext)
|
||||||
.expect("missing vmctx parameter");
|
.expect("missing vmctx parameter");
|
||||||
|
|
||||||
let call_inst = pos.ins().call(mem_grow_func, &[const_mem_index, vmctx]);
|
let call_inst = pos.ins().call(mem_grow_func, &[vmctx, const_mem_index]);
|
||||||
|
|
||||||
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#[cfg(feature = "cache")]
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod func_env;
|
mod func_env;
|
||||||
mod libcalls;
|
mod libcalls;
|
||||||
@ -14,21 +13,18 @@ use cranelift_codegen::{
|
|||||||
settings::{self, Configurable},
|
settings::{self, Configurable},
|
||||||
};
|
};
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
|
||||||
backend::sys::Memory,
|
|
||||||
cache::{Cache, Error as CacheError},
|
|
||||||
module::ModuleInfo,
|
|
||||||
};
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{Compiler, Token},
|
backend::{Compiler, Token},
|
||||||
error::{CompileError, CompileResult},
|
error::{CompileError, CompileResult},
|
||||||
module::ModuleInner,
|
module::ModuleInner,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
|
extern crate rayon;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
use wasmparser::{self, WasmDecoder};
|
use wasmparser::{self, WasmDecoder};
|
||||||
@ -48,7 +44,7 @@ impl Compiler for CraneliftCompiler {
|
|||||||
|
|
||||||
let isa = get_isa();
|
let isa = get_isa();
|
||||||
|
|
||||||
let mut module = module::Module::empty();
|
let mut module = module::Module::new();
|
||||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||||
|
|
||||||
let func_bodies = module_env.translate(wasm)?;
|
let func_bodies = module_env.translate(wasm)?;
|
||||||
@ -57,41 +53,41 @@ impl Compiler for CraneliftCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a wasmer Module from an already-compiled cache.
|
/// Create a wasmer Module from an already-compiled cache.
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
unsafe fn from_cache(&self, cache: Cache, _: Token) -> Result<ModuleInner, CacheError> {
|
unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||||
module::Module::from_cache(cache)
|
module::Module::from_cache(cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
//
|
||||||
fn compile_to_backend_cache_data(
|
// fn compile_to_backend_cache_data(
|
||||||
&self,
|
// &self,
|
||||||
wasm: &[u8],
|
// wasm: &[u8],
|
||||||
_: Token,
|
// _: Token,
|
||||||
) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
|
// ) -> CompileResult<(Box<ModuleInfo>, Vec<u8>, Memory)> {
|
||||||
validate(wasm)?;
|
// validate(wasm)?;
|
||||||
|
|
||||||
let isa = get_isa();
|
// let isa = get_isa();
|
||||||
|
|
||||||
let mut module = module::Module::empty();
|
// let mut module = module::Module::new(wasm);
|
||||||
let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
// let module_env = module_env::ModuleEnv::new(&mut module, &*isa);
|
||||||
|
|
||||||
let func_bodies = module_env.translate(wasm)?;
|
// let func_bodies = module_env.translate(wasm)?;
|
||||||
|
|
||||||
let (info, backend_cache, compiled_code) = module
|
// let (info, backend_cache, compiled_code) = module
|
||||||
.compile_to_backend_cache(&*isa, func_bodies)
|
// .compile_to_backend_cache(&*isa, func_bodies)
|
||||||
.map_err(|e| CompileError::InternalError {
|
// .map_err(|e| CompileError::InternalError {
|
||||||
msg: format!("{:?}", e),
|
// msg: format!("{:?}", e),
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
let buffer =
|
// let buffer =
|
||||||
backend_cache
|
// backend_cache
|
||||||
.into_backend_data()
|
// .into_backend_data()
|
||||||
.map_err(|e| CompileError::InternalError {
|
// .map_err(|e| CompileError::InternalError {
|
||||||
msg: format!("{:?}", e),
|
// msg: format!("{:?}", e),
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
Ok((Box::new(info), buffer, compiled_code))
|
// Ok((Box::new(info), buffer, compiled_code))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_isa() -> Box<isa::TargetIsa> {
|
fn get_isa() -> Box<isa::TargetIsa> {
|
||||||
|
@ -1,75 +1,32 @@
|
|||||||
#[cfg(feature = "cache")]
|
use crate::cache::{BackendCache, CacheGenerator};
|
||||||
use crate::cache::BackendCache;
|
|
||||||
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
|
use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines};
|
||||||
|
|
||||||
use cranelift_codegen::{ir, isa};
|
use cranelift_codegen::{ir, isa};
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
use cranelift_wasm;
|
use cranelift_wasm;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::{
|
use std::sync::Arc;
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
ptr::NonNull,
|
use wasmer_runtime_core::cache::{Artifact, Error as CacheError};
|
||||||
};
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::Memory,
|
backend::Backend,
|
||||||
cache::{Cache, Error as CacheError},
|
error::CompileResult,
|
||||||
};
|
|
||||||
use wasmer_runtime_core::{
|
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller, Token, UserTrapper},
|
|
||||||
error::{CompileResult, RuntimeResult},
|
|
||||||
module::{ModuleInfo, ModuleInner, StringTable},
|
module::{ModuleInfo, ModuleInner, StringTable},
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
types::{
|
types::{
|
||||||
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type,
|
||||||
Value,
|
|
||||||
},
|
},
|
||||||
vm::{self, ImportBacking},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Placeholder;
|
|
||||||
|
|
||||||
impl FuncResolver for Placeholder {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
_local_func_index: LocalFuncIndex,
|
|
||||||
) -> Option<NonNull<vm::Func>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProtectedCaller for Placeholder {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
_func_index: FuncIndex,
|
|
||||||
_params: &[Value],
|
|
||||||
_import_backing: &ImportBacking,
|
|
||||||
_vmctx: *mut vm::Ctx,
|
|
||||||
_: Token,
|
|
||||||
) -> RuntimeResult<Vec<Value>> {
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
/// This contains all of the items in a `ModuleInner` except the `func_resolver`.
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub module: ModuleInner,
|
pub info: ModuleInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn empty() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
module: ModuleInner {
|
|
||||||
// this is a placeholder
|
|
||||||
func_resolver: Box::new(Placeholder),
|
|
||||||
protected_caller: Box::new(Placeholder),
|
|
||||||
|
|
||||||
info: ModuleInfo {
|
info: ModuleInfo {
|
||||||
memories: Map::new(),
|
memories: Map::new(),
|
||||||
globals: Map::new(),
|
globals: Map::new(),
|
||||||
@ -94,85 +51,72 @@ impl Module {
|
|||||||
namespace_table: StringTable::new(),
|
namespace_table: StringTable::new(),
|
||||||
name_table: StringTable::new(),
|
name_table: StringTable::new(),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
mut self,
|
self,
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
functions: Map<LocalFuncIndex, ir::Function>,
|
functions: Map<LocalFuncIndex, ir::Function>,
|
||||||
) -> CompileResult<ModuleInner> {
|
) -> CompileResult<ModuleInner> {
|
||||||
let (func_resolver_builder, handler_data) =
|
let (func_resolver_builder, handler_data) =
|
||||||
FuncResolverBuilder::new(isa, functions, &self.module.info)?;
|
FuncResolverBuilder::new(isa, functions, &self.info)?;
|
||||||
|
|
||||||
self.module.func_resolver =
|
let trampolines = Arc::new(Trampolines::new(isa, &self.info));
|
||||||
Box::new(func_resolver_builder.finalize(&self.module.info.signatures)?);
|
|
||||||
|
|
||||||
let trampolines = Trampolines::new(isa, &self.module.info);
|
let (func_resolver, backend_cache) = func_resolver_builder.finalize(
|
||||||
|
&self.info.signatures,
|
||||||
|
Arc::clone(&trampolines),
|
||||||
|
handler_data.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
self.module.protected_caller =
|
let protected_caller = Caller::new(&self.info, handler_data, trampolines);
|
||||||
Box::new(Caller::new(&self.module.info, handler_data, trampolines));
|
|
||||||
|
|
||||||
Ok(self.module)
|
let cache_gen = Box::new(CacheGenerator::new(
|
||||||
|
backend_cache,
|
||||||
|
Arc::clone(&func_resolver.memory),
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(ModuleInner {
|
||||||
|
func_resolver: Box::new(func_resolver),
|
||||||
|
protected_caller: Box::new(protected_caller),
|
||||||
|
cache_gen,
|
||||||
|
|
||||||
|
info: self.info,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
pub fn from_cache(cache: Artifact) -> Result<ModuleInner, CacheError> {
|
||||||
pub fn compile_to_backend_cache(
|
|
||||||
self,
|
|
||||||
isa: &isa::TargetIsa,
|
|
||||||
functions: Map<LocalFuncIndex, ir::Function>,
|
|
||||||
) -> CompileResult<(ModuleInfo, BackendCache, Memory)> {
|
|
||||||
let (func_resolver_builder, handler_data) =
|
|
||||||
FuncResolverBuilder::new(isa, functions, &self.module.info)?;
|
|
||||||
|
|
||||||
let trampolines = Trampolines::new(isa, &self.module.info);
|
|
||||||
|
|
||||||
let trampoline_cache = trampolines.to_trampoline_cache();
|
|
||||||
|
|
||||||
let (backend_cache, compiled_code) =
|
|
||||||
func_resolver_builder.to_backend_cache(trampoline_cache, handler_data);
|
|
||||||
|
|
||||||
Ok((self.module.info, backend_cache, compiled_code))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn from_cache(cache: Cache) -> Result<ModuleInner, CacheError> {
|
|
||||||
let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?;
|
let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?;
|
||||||
|
|
||||||
let (func_resolver_builder, trampolines, handler_data) =
|
let (func_resolver_builder, trampolines, handler_data) =
|
||||||
FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?;
|
FuncResolverBuilder::new_from_backend_cache(backend_cache, compiled_code, &info)?;
|
||||||
|
|
||||||
let func_resolver = Box::new(
|
let (func_resolver, backend_cache) = func_resolver_builder
|
||||||
func_resolver_builder
|
.finalize(
|
||||||
.finalize(&info.signatures)
|
&info.signatures,
|
||||||
.map_err(|e| CacheError::Unknown(format!("{:?}", e)))?,
|
Arc::clone(&trampolines),
|
||||||
);
|
handler_data.clone(),
|
||||||
|
)
|
||||||
|
.map_err(|e| CacheError::Unknown(format!("{:?}", e)))?;
|
||||||
|
|
||||||
let protected_caller = Box::new(Caller::new(&info, handler_data, trampolines));
|
let protected_caller = Caller::new(&info, handler_data, trampolines);
|
||||||
|
|
||||||
|
let cache_gen = Box::new(CacheGenerator::new(
|
||||||
|
backend_cache,
|
||||||
|
Arc::clone(&func_resolver.memory),
|
||||||
|
));
|
||||||
|
|
||||||
Ok(ModuleInner {
|
Ok(ModuleInner {
|
||||||
func_resolver,
|
func_resolver: Box::new(func_resolver),
|
||||||
protected_caller,
|
protected_caller: Box::new(protected_caller),
|
||||||
|
cache_gen,
|
||||||
|
|
||||||
info,
|
info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Module {
|
|
||||||
type Target = ModuleInner;
|
|
||||||
|
|
||||||
fn deref(&self) -> &ModuleInner {
|
|
||||||
&self.module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Module {
|
|
||||||
fn deref_mut(&mut self) -> &mut ModuleInner {
|
|
||||||
&mut self.module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Converter<T>(pub T);
|
pub struct Converter<T>(pub T);
|
||||||
|
|
||||||
macro_rules! convert_clif_to_runtime_index {
|
macro_rules! convert_clif_to_runtime_index {
|
||||||
|
@ -4,7 +4,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use cranelift_codegen::{ir, isa};
|
use cranelift_codegen::{ir, isa};
|
||||||
use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment};
|
use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment};
|
||||||
use std::sync::Arc;
|
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
error::{CompileError, CompileResult},
|
error::{CompileError, CompileResult},
|
||||||
module::{
|
module::{
|
||||||
@ -62,10 +61,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
/// Declares a function signature to the environment.
|
/// Declares a function signature to the environment.
|
||||||
fn declare_signature(&mut self, sig: &ir::Signature) {
|
fn declare_signature(&mut self, sig: &ir::Signature) {
|
||||||
self.signatures.push(sig.clone());
|
self.signatures.push(sig.clone());
|
||||||
self.module
|
self.module.info.signatures.push(Converter(sig).into());
|
||||||
.info
|
|
||||||
.signatures
|
|
||||||
.push(Arc::new(Converter(sig).into()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the signature with the given index.
|
/// Return the signature with the given index.
|
||||||
@ -139,7 +135,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
// assert!(!desc.mutable);
|
// assert!(!desc.mutable);
|
||||||
let global_index: GlobalIndex = Converter(global_index).into();
|
let global_index: GlobalIndex = Converter(global_index).into();
|
||||||
let imported_global_index = global_index
|
let imported_global_index = global_index
|
||||||
.local_or_import(self.module)
|
.local_or_import(&self.module.info)
|
||||||
.import()
|
.import()
|
||||||
.expect("invalid global initializer when declaring an imported global");
|
.expect("invalid global initializer when declaring an imported global");
|
||||||
Initializer::GetGlobal(imported_global_index)
|
Initializer::GetGlobal(imported_global_index)
|
||||||
@ -249,7 +245,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let base = match base {
|
let base = match base {
|
||||||
Some(global_index) => {
|
Some(global_index) => {
|
||||||
let global_index: GlobalIndex = Converter(global_index).into();
|
let global_index: GlobalIndex = Converter(global_index).into();
|
||||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||||
LocalOrImport::Local(_) => {
|
LocalOrImport::Local(_) => {
|
||||||
panic!("invalid global initializer when declaring an imported global")
|
panic!("invalid global initializer when declaring an imported global")
|
||||||
@ -319,7 +315,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let base = match base {
|
let base = match base {
|
||||||
Some(global_index) => {
|
Some(global_index) => {
|
||||||
let global_index: GlobalIndex = Converter(global_index).into();
|
let global_index: GlobalIndex = Converter(global_index).into();
|
||||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||||
LocalOrImport::Local(_) => {
|
LocalOrImport::Local(_) => {
|
||||||
panic!("invalid global initializer when declaring an imported global")
|
panic!("invalid global initializer when declaring an imported global")
|
||||||
@ -389,7 +385,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let name = ir::ExternalName::user(0, func_index.index() as u32);
|
let name = ir::ExternalName::user(0, func_index.index() as u32);
|
||||||
|
|
||||||
let sig = func_env.generate_signature(
|
let sig = func_env.generate_signature(
|
||||||
self.get_func_type(Converter(func_index.convert_up(self.module)).into()),
|
self.get_func_type(Converter(func_index.convert_up(&self.module.info)).into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut func = ir::Function::with_name_signature(name, sig);
|
let mut func = ir::Function::with_name_signature(name, sig);
|
||||||
@ -419,8 +415,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::I32),
|
|
||||||
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::I32),
|
||||||
],
|
],
|
||||||
returns: vec![],
|
returns: vec![],
|
||||||
});
|
});
|
||||||
@ -457,8 +453,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::I32),
|
|
||||||
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::I32),
|
||||||
],
|
],
|
||||||
returns: vec![],
|
returns: vec![],
|
||||||
});
|
});
|
||||||
@ -476,8 +472,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::I64),
|
|
||||||
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::I64),
|
||||||
],
|
],
|
||||||
returns: vec![],
|
returns: vec![],
|
||||||
});
|
});
|
||||||
@ -495,8 +491,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::F32),
|
|
||||||
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::F32),
|
||||||
],
|
],
|
||||||
returns: vec![],
|
returns: vec![],
|
||||||
});
|
});
|
||||||
@ -514,8 +510,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
let signature = pos.func.import_signature(ir::Signature {
|
let signature = pos.func.import_signature(ir::Signature {
|
||||||
call_conv: self.target_config().default_call_conv,
|
call_conv: self.target_config().default_call_conv,
|
||||||
params: vec![
|
params: vec![
|
||||||
ir::AbiParam::new(ir::types::F64),
|
|
||||||
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext),
|
||||||
|
ir::AbiParam::new(ir::types::F64),
|
||||||
],
|
],
|
||||||
returns: vec![],
|
returns: vec![],
|
||||||
});
|
});
|
||||||
@ -536,14 +532,14 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
|||||||
|
|
||||||
let func_index = pos.ins().iconst(ir::types::I32, func_index.index() as i64);
|
let func_index = pos.ins().iconst(ir::types::I32, func_index.index() as i64);
|
||||||
|
|
||||||
pos.ins().call(start_debug, &[func_index, vmctx]);
|
pos.ins().call(start_debug, &[vmctx, func_index]);
|
||||||
|
|
||||||
for param in new_ebb_params.iter().cloned() {
|
for param in new_ebb_params.iter().cloned() {
|
||||||
match pos.func.dfg.value_type(param) {
|
match pos.func.dfg.value_type(param) {
|
||||||
ir::types::I32 => pos.ins().call(i32_print, &[param, vmctx]),
|
ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]),
|
||||||
ir::types::I64 => pos.ins().call(i64_print, &[param, vmctx]),
|
ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]),
|
||||||
ir::types::F32 => pos.ins().call(f32_print, &[param, vmctx]),
|
ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]),
|
||||||
ir::types::F64 => pos.ins().call(f64_print, &[param, vmctx]),
|
ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,14 @@ pub mod call_names {
|
|||||||
pub const DYNAMIC_MEM_SIZE: u32 = 5;
|
pub const DYNAMIC_MEM_SIZE: u32 = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Reloc {
|
pub enum Reloc {
|
||||||
Abs8,
|
Abs8,
|
||||||
X86PCRel4,
|
X86PCRel4,
|
||||||
X86CallPCRel4,
|
X86CallPCRel4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum LibCall {
|
pub enum LibCall {
|
||||||
Probestack,
|
Probestack,
|
||||||
CeilF32,
|
CeilF32,
|
||||||
@ -44,8 +42,7 @@ pub enum LibCall {
|
|||||||
NearestF64,
|
NearestF64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ExternalRelocation {
|
pub struct ExternalRelocation {
|
||||||
/// The relocation code.
|
/// The relocation code.
|
||||||
pub reloc: Reloc,
|
pub reloc: Reloc,
|
||||||
@ -66,8 +63,7 @@ pub struct LocalRelocation {
|
|||||||
pub target: FuncIndex,
|
pub target: FuncIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum VmCallKind {
|
pub enum VmCallKind {
|
||||||
StaticMemoryGrow,
|
StaticMemoryGrow,
|
||||||
StaticMemorySize,
|
StaticMemorySize,
|
||||||
@ -79,16 +75,14 @@ pub enum VmCallKind {
|
|||||||
DynamicMemorySize,
|
DynamicMemorySize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum VmCall {
|
pub enum VmCall {
|
||||||
Local(VmCallKind),
|
Local(VmCallKind),
|
||||||
Import(VmCallKind),
|
Import(VmCallKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify the type of relocation
|
/// Specify the type of relocation
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum RelocationType {
|
pub enum RelocationType {
|
||||||
Intrinsic(String),
|
Intrinsic(String),
|
||||||
LibCall(LibCall),
|
LibCall(LibCall),
|
||||||
@ -218,8 +212,7 @@ impl binemit::RelocSink for RelocSink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum TrapCode {
|
pub enum TrapCode {
|
||||||
StackOverflow,
|
StackOverflow,
|
||||||
HeapOutOfBounds,
|
HeapOutOfBounds,
|
||||||
@ -244,8 +237,7 @@ impl RelocSink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TrapData {
|
pub struct TrapData {
|
||||||
pub trapcode: TrapCode,
|
pub trapcode: TrapCode,
|
||||||
pub srcloc: u32,
|
pub srcloc: u32,
|
||||||
@ -253,7 +245,7 @@ pub struct TrapData {
|
|||||||
|
|
||||||
/// Simple implementation of a TrapSink
|
/// Simple implementation of a TrapSink
|
||||||
/// that saves the info for later.
|
/// that saves the info for later.
|
||||||
#[cfg_attr(feature = "cache", derive(Serialize, Deserialize))]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct TrapSink {
|
pub struct TrapSink {
|
||||||
trap_datas: Vec<(usize, TrapData)>,
|
trap_datas: Vec<(usize, TrapData)>,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
#[cfg(feature = "cache")]
|
use crate::{cache::BackendCache, trampoline::Trampolines};
|
||||||
use crate::{
|
|
||||||
cache::{BackendCache, TrampolineCache},
|
|
||||||
trampoline::Trampolines,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
libcalls,
|
libcalls,
|
||||||
relocation::{
|
relocation::{
|
||||||
@ -11,6 +7,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
signal::HandlerData,
|
signal::HandlerData,
|
||||||
};
|
};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use cranelift_codegen::{ir, isa, Context};
|
use cranelift_codegen::{ir, isa, Context};
|
||||||
@ -19,7 +16,7 @@ use std::{
|
|||||||
ptr::{write_unaligned, NonNull},
|
ptr::{write_unaligned, NonNull},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
use wasmer_runtime_core::cache::Error as CacheError;
|
use wasmer_runtime_core::cache::Error as CacheError;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
self,
|
self,
|
||||||
@ -42,21 +39,32 @@ extern "C" {
|
|||||||
pub fn __chkstk();
|
pub fn __chkstk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lookup_func(
|
||||||
|
map: &SliceMap<LocalFuncIndex, usize>,
|
||||||
|
memory: &Memory,
|
||||||
|
local_func_index: LocalFuncIndex,
|
||||||
|
) -> Option<NonNull<vm::Func>> {
|
||||||
|
let offset = *map.get(local_func_index)?;
|
||||||
|
let ptr = unsafe { memory.as_ptr().add(offset) };
|
||||||
|
|
||||||
|
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct FuncResolverBuilder {
|
pub struct FuncResolverBuilder {
|
||||||
resolver: FuncResolver,
|
map: Map<LocalFuncIndex, usize>,
|
||||||
|
memory: Memory,
|
||||||
local_relocs: Map<LocalFuncIndex, Box<[LocalRelocation]>>,
|
local_relocs: Map<LocalFuncIndex, Box<[LocalRelocation]>>,
|
||||||
external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
external_relocs: Map<LocalFuncIndex, Box<[ExternalRelocation]>>,
|
||||||
import_len: usize,
|
import_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncResolverBuilder {
|
impl FuncResolverBuilder {
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn new_from_backend_cache(
|
pub fn new_from_backend_cache(
|
||||||
backend_cache: BackendCache,
|
backend_cache: BackendCache,
|
||||||
mut code: Memory,
|
mut code: Memory,
|
||||||
info: &ModuleInfo,
|
info: &ModuleInfo,
|
||||||
) -> Result<(Self, Trampolines, HandlerData), CacheError> {
|
) -> Result<(Self, Arc<Trampolines>, HandlerData), CacheError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
code.protect(.., Protect::ReadWrite)
|
code.protect(.., Protect::ReadWrite)
|
||||||
.map_err(|e| CacheError::Unknown(e.to_string()))?;
|
.map_err(|e| CacheError::Unknown(e.to_string()))?;
|
||||||
@ -67,61 +75,62 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Self {
|
Self {
|
||||||
resolver: FuncResolver {
|
|
||||||
map: backend_cache.offsets,
|
map: backend_cache.offsets,
|
||||||
memory: code,
|
memory: code,
|
||||||
},
|
|
||||||
local_relocs: Map::new(),
|
local_relocs: Map::new(),
|
||||||
external_relocs: backend_cache.external_relocs,
|
external_relocs: backend_cache.external_relocs,
|
||||||
import_len: info.imported_functions.len(),
|
import_len: info.imported_functions.len(),
|
||||||
},
|
},
|
||||||
Trampolines::from_trampoline_cache(backend_cache.trampolines),
|
Arc::new(Trampolines::from_trampoline_cache(
|
||||||
|
backend_cache.trampolines,
|
||||||
|
)),
|
||||||
handler_data,
|
handler_data,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn to_backend_cache(
|
|
||||||
mut self,
|
|
||||||
trampolines: TrampolineCache,
|
|
||||||
handler_data: HandlerData,
|
|
||||||
) -> (BackendCache, Memory) {
|
|
||||||
self.relocate_locals();
|
|
||||||
(
|
|
||||||
BackendCache {
|
|
||||||
external_relocs: self.external_relocs,
|
|
||||||
offsets: self.resolver.map,
|
|
||||||
trap_sink: handler_data.trap_data,
|
|
||||||
trampolines,
|
|
||||||
},
|
|
||||||
self.resolver.memory,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
isa: &isa::TargetIsa,
|
isa: &isa::TargetIsa,
|
||||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
||||||
info: &ModuleInfo,
|
info: &ModuleInfo,
|
||||||
) -> CompileResult<(Self, HandlerData)> {
|
) -> CompileResult<(Self, HandlerData)> {
|
||||||
let mut compiled_functions: Vec<Vec<u8>> = Vec::with_capacity(function_bodies.len());
|
let num_func_bodies = function_bodies.len();
|
||||||
let mut local_relocs = Map::with_capacity(function_bodies.len());
|
let mut local_relocs = Map::with_capacity(num_func_bodies);
|
||||||
let mut external_relocs = Map::new();
|
let mut external_relocs = Map::with_capacity(num_func_bodies);
|
||||||
|
|
||||||
let mut trap_sink = TrapSink::new();
|
let mut trap_sink = TrapSink::new();
|
||||||
|
|
||||||
|
let compiled_functions: Result<Vec<(Vec<u8>, (RelocSink, LocalTrapSink))>, CompileError> =
|
||||||
|
function_bodies
|
||||||
|
.into_vec()
|
||||||
|
.par_iter()
|
||||||
|
.map_init(
|
||||||
|
|| Context::new(),
|
||||||
|
|ctx, func| {
|
||||||
|
let mut code_buf = Vec::new();
|
||||||
|
ctx.func = func.to_owned();
|
||||||
|
let mut reloc_sink = RelocSink::new();
|
||||||
let mut local_trap_sink = LocalTrapSink::new();
|
let mut local_trap_sink = LocalTrapSink::new();
|
||||||
|
|
||||||
let mut ctx = Context::new();
|
ctx.compile_and_emit(
|
||||||
let mut total_size = 0;
|
isa,
|
||||||
|
&mut code_buf,
|
||||||
for (_, func) in function_bodies {
|
&mut reloc_sink,
|
||||||
ctx.func = func;
|
&mut local_trap_sink,
|
||||||
let mut code_buf = Vec::new();
|
)
|
||||||
let mut reloc_sink = RelocSink::new();
|
|
||||||
|
|
||||||
ctx.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut local_trap_sink)
|
|
||||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||||
ctx.clear();
|
ctx.clear();
|
||||||
|
Ok((code_buf, (reloc_sink, local_trap_sink)))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let compiled_functions = compiled_functions?;
|
||||||
|
let mut total_size = 0;
|
||||||
|
// We separate into two iterators, one iterable and one into iterable
|
||||||
|
let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
|
||||||
|
compiled_functions.into_iter().unzip();
|
||||||
|
for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
|
||||||
|
{
|
||||||
// Clear the local trap sink and consolidate all trap info
|
// Clear the local trap sink and consolidate all trap info
|
||||||
// into a single location.
|
// into a single location.
|
||||||
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
||||||
@ -129,7 +138,6 @@ impl FuncResolverBuilder {
|
|||||||
// Round up each function's size to pointer alignment.
|
// Round up each function's size to pointer alignment.
|
||||||
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
|
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
|
||||||
|
|
||||||
compiled_functions.push(code_buf);
|
|
||||||
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
|
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
|
||||||
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
|
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
|
||||||
}
|
}
|
||||||
@ -156,10 +164,10 @@ impl FuncResolverBuilder {
|
|||||||
*i = 0xCC;
|
*i = 0xCC;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut map = Map::with_capacity(compiled_functions.len());
|
let mut map = Map::with_capacity(num_func_bodies);
|
||||||
|
|
||||||
let mut previous_end = 0;
|
let mut previous_end = 0;
|
||||||
for compiled in compiled_functions.iter() {
|
for compiled in code_bufs.iter() {
|
||||||
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
|
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
|
||||||
unsafe {
|
unsafe {
|
||||||
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
||||||
@ -169,10 +177,12 @@ impl FuncResolverBuilder {
|
|||||||
previous_end = new_end;
|
previous_end = new_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
let handler_data = HandlerData::new(trap_sink, memory.as_ptr() as _, memory.size());
|
let handler_data =
|
||||||
|
HandlerData::new(Arc::new(trap_sink), memory.as_ptr() as _, memory.size());
|
||||||
|
|
||||||
let mut func_resolver_builder = Self {
|
let mut func_resolver_builder = Self {
|
||||||
resolver: FuncResolver { map, memory },
|
map,
|
||||||
|
memory,
|
||||||
local_relocs,
|
local_relocs,
|
||||||
external_relocs,
|
external_relocs,
|
||||||
import_len: info.imported_functions.len(),
|
import_len: info.imported_functions.len(),
|
||||||
@ -187,12 +197,15 @@ impl FuncResolverBuilder {
|
|||||||
for (index, relocs) in self.local_relocs.iter() {
|
for (index, relocs) in self.local_relocs.iter() {
|
||||||
for ref reloc in relocs.iter() {
|
for ref reloc in relocs.iter() {
|
||||||
let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len);
|
let local_func_index = LocalFuncIndex::new(reloc.target.index() - self.import_len);
|
||||||
let target_func_address =
|
let target_func_address = lookup_func(&self.map, &self.memory, local_func_index)
|
||||||
self.resolver.lookup(local_func_index).unwrap().as_ptr() as usize;
|
.unwrap()
|
||||||
|
.as_ptr() as usize;
|
||||||
|
|
||||||
// We need the address of the current function
|
// We need the address of the current function
|
||||||
// because these calls are relative.
|
// because these calls are relative.
|
||||||
let func_addr = self.resolver.lookup(index).unwrap().as_ptr() as usize;
|
let func_addr = lookup_func(&self.map, &self.memory, index)
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr() as usize;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let reloc_address = func_addr + reloc.offset as usize;
|
let reloc_address = func_addr + reloc.offset as usize;
|
||||||
@ -208,8 +221,10 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
pub fn finalize(
|
pub fn finalize(
|
||||||
mut self,
|
mut self,
|
||||||
signatures: &SliceMap<SigIndex, Arc<FuncSig>>,
|
signatures: &SliceMap<SigIndex, FuncSig>,
|
||||||
) -> CompileResult<FuncResolver> {
|
trampolines: Arc<Trampolines>,
|
||||||
|
handler_data: HandlerData,
|
||||||
|
) -> CompileResult<(FuncResolver, BackendCache)> {
|
||||||
for (index, relocs) in self.external_relocs.iter() {
|
for (index, relocs) in self.external_relocs.iter() {
|
||||||
for ref reloc in relocs.iter() {
|
for ref reloc in relocs.iter() {
|
||||||
let target_func_address: isize = match reloc.target {
|
let target_func_address: isize = match reloc.target {
|
||||||
@ -223,9 +238,9 @@ impl FuncResolverBuilder {
|
|||||||
LibCall::TruncF64 => libcalls::truncf64 as isize,
|
LibCall::TruncF64 => libcalls::truncf64 as isize,
|
||||||
LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
|
LibCall::NearestF64 => libcalls::nearbyintf64 as isize,
|
||||||
#[cfg(all(target_pointer_width = "64", target_os = "windows"))]
|
#[cfg(all(target_pointer_width = "64", target_os = "windows"))]
|
||||||
Probestack => __chkstk as isize,
|
LibCall::Probestack => __chkstk as isize,
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
Probestack => __rust_probestack as isize,
|
LibCall::Probestack => __rust_probestack as isize,
|
||||||
},
|
},
|
||||||
RelocationType::Intrinsic(ref name) => match name.as_str() {
|
RelocationType::Intrinsic(ref name) => match name.as_str() {
|
||||||
"i32print" => i32_print as isize,
|
"i32print" => i32_print as isize,
|
||||||
@ -273,15 +288,17 @@ impl FuncResolverBuilder {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
RelocationType::Signature(sig_index) => {
|
RelocationType::Signature(sig_index) => {
|
||||||
let sig_index =
|
let signature = SigRegistry.lookup_signature_ref(&signatures[sig_index]);
|
||||||
SigRegistry.lookup_sig_index(Arc::clone(&signatures[sig_index]));
|
let sig_index = SigRegistry.lookup_sig_index(signature);
|
||||||
sig_index.index() as _
|
sig_index.index() as _
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need the address of the current function
|
// We need the address of the current function
|
||||||
// because some of these calls are relative.
|
// because some of these calls are relative.
|
||||||
let func_addr = self.resolver.lookup(index).unwrap().as_ptr();
|
let func_addr = lookup_func(&self.map, &self.memory, index)
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr() as usize;
|
||||||
|
|
||||||
// Determine relocation type and apply relocation.
|
// Determine relocation type and apply relocation.
|
||||||
match reloc.reloc {
|
match reloc.reloc {
|
||||||
@ -289,9 +306,9 @@ impl FuncResolverBuilder {
|
|||||||
let ptr_to_write = (target_func_address as u64)
|
let ptr_to_write = (target_func_address as u64)
|
||||||
.checked_add(reloc.addend as u64)
|
.checked_add(reloc.addend as u64)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let empty_space_offset = self.resolver.map[index] + reloc.offset as usize;
|
let empty_space_offset = self.map[index] + reloc.offset as usize;
|
||||||
let ptr_slice = unsafe {
|
let ptr_slice = unsafe {
|
||||||
&mut self.resolver.memory.as_slice_mut()
|
&mut self.memory.as_slice_mut()
|
||||||
[empty_space_offset..empty_space_offset + 8]
|
[empty_space_offset..empty_space_offset + 8]
|
||||||
};
|
};
|
||||||
LittleEndian::write_u64(ptr_slice, ptr_to_write);
|
LittleEndian::write_u64(ptr_slice, ptr_to_write);
|
||||||
@ -309,29 +326,35 @@ impl FuncResolverBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.resolver
|
self.memory
|
||||||
.memory
|
|
||||||
.protect(.., Protect::ReadExec)
|
.protect(.., Protect::ReadExec)
|
||||||
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.resolver)
|
let backend_cache = BackendCache {
|
||||||
|
external_relocs: self.external_relocs.clone(),
|
||||||
|
offsets: self.map.clone(),
|
||||||
|
trap_sink: handler_data.trap_data,
|
||||||
|
trampolines: trampolines.to_trampoline_cache(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
FuncResolver {
|
||||||
|
map: self.map,
|
||||||
|
memory: Arc::new(self.memory),
|
||||||
|
},
|
||||||
|
backend_cache,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for FuncResolver {}
|
||||||
|
unsafe impl Send for FuncResolver {}
|
||||||
|
|
||||||
/// Resolves a function index to a function address.
|
/// Resolves a function index to a function address.
|
||||||
pub struct FuncResolver {
|
pub struct FuncResolver {
|
||||||
map: Map<LocalFuncIndex, usize>,
|
map: Map<LocalFuncIndex, usize>,
|
||||||
memory: Memory,
|
pub(crate) memory: Arc<Memory>,
|
||||||
}
|
|
||||||
|
|
||||||
impl FuncResolver {
|
|
||||||
fn lookup(&self, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
|
|
||||||
let offset = *self.map.get(local_func_index)?;
|
|
||||||
let ptr = unsafe { self.memory.as_ptr().add(offset) };
|
|
||||||
|
|
||||||
NonNull::new(ptr).map(|nonnull| nonnull.cast())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements FuncResolver trait.
|
// Implements FuncResolver trait.
|
||||||
@ -341,7 +364,7 @@ impl backend::FuncResolver for FuncResolver {
|
|||||||
_module: &wasmer_runtime_core::module::ModuleInner,
|
_module: &wasmer_runtime_core::module::ModuleInner,
|
||||||
index: LocalFuncIndex,
|
index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>> {
|
) -> Option<NonNull<vm::Func>> {
|
||||||
self.lookup(index)
|
lookup_func(&self.map, &self.memory, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,21 +373,21 @@ fn round_up(n: usize, multiple: usize) -> usize {
|
|||||||
(n + multiple - 1) & !(multiple - 1)
|
(n + multiple - 1) & !(multiple - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn i32_print(n: i32) {
|
extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) {
|
||||||
print!(" i32: {},", n);
|
print!(" i32: {},", n);
|
||||||
}
|
}
|
||||||
extern "C" fn i64_print(n: i64) {
|
extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) {
|
||||||
print!(" i64: {},", n);
|
print!(" i64: {},", n);
|
||||||
}
|
}
|
||||||
extern "C" fn f32_print(n: f32) {
|
extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) {
|
||||||
print!(" f32: {},", n);
|
print!(" f32: {},", n);
|
||||||
}
|
}
|
||||||
extern "C" fn f64_print(n: f64) {
|
extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) {
|
||||||
print!(" f64: {},", n);
|
print!(" f64: {},", n);
|
||||||
}
|
}
|
||||||
extern "C" fn start_debug(func_index: u32) {
|
extern "C" fn start_debug(_ctx: &mut vm::Ctx, func_index: u32) {
|
||||||
print!("func ({}), args: [", func_index);
|
print!("func ({}), args: [", func_index);
|
||||||
}
|
}
|
||||||
extern "C" fn end_debug() {
|
extern "C" fn end_debug(_ctx: &mut vm::Ctx) {
|
||||||
println!(" ]");
|
println!(" ]");
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::relocation::{TrapData, TrapSink};
|
|||||||
use crate::trampoline::Trampolines;
|
use crate::trampoline::Trampolines;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use std::{cell::Cell, sync::Arc};
|
use std::{any::Any, cell::Cell, sync::Arc};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::{ProtectedCaller, Token, UserTrapper},
|
backend::{ProtectedCaller, Token, UserTrapper},
|
||||||
error::RuntimeResult,
|
error::RuntimeResult,
|
||||||
@ -25,14 +25,14 @@ pub use self::unix::*;
|
|||||||
pub use self::windows::*;
|
pub use self::windows::*;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
pub static TRAP_EARLY_DATA: Cell<Option<String>> = Cell::new(None);
|
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Trapper;
|
pub struct Trapper;
|
||||||
|
|
||||||
impl UserTrapper for Trapper {
|
impl UserTrapper for Trapper {
|
||||||
unsafe fn do_early_trap(&self, msg: String) -> ! {
|
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
|
||||||
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg)));
|
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
|
||||||
trigger_trap()
|
trigger_trap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,11 +40,15 @@ impl UserTrapper for Trapper {
|
|||||||
pub struct Caller {
|
pub struct Caller {
|
||||||
func_export_set: HashSet<FuncIndex>,
|
func_export_set: HashSet<FuncIndex>,
|
||||||
handler_data: HandlerData,
|
handler_data: HandlerData,
|
||||||
trampolines: Trampolines,
|
trampolines: Arc<Trampolines>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Caller {
|
impl Caller {
|
||||||
pub fn new(module: &ModuleInfo, handler_data: HandlerData, trampolines: Trampolines) -> Self {
|
pub fn new(
|
||||||
|
module: &ModuleInfo,
|
||||||
|
handler_data: HandlerData,
|
||||||
|
trampolines: Arc<Trampolines>,
|
||||||
|
) -> Self {
|
||||||
let mut func_export_set = HashSet::new();
|
let mut func_export_set = HashSet::new();
|
||||||
for export_index in module.exports.values() {
|
for export_index in module.exports.values() {
|
||||||
if let ExportIndex::Func(func_index) = export_index {
|
if let ExportIndex::Func(func_index) = export_index {
|
||||||
@ -110,6 +114,7 @@ impl ProtectedCaller for Caller {
|
|||||||
.lookup(sig_index)
|
.lookup(sig_index)
|
||||||
.expect("that trampoline doesn't exist");
|
.expect("that trampoline doesn't exist");
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
call_protected(&self.handler_data, || unsafe {
|
call_protected(&self.handler_data, || unsafe {
|
||||||
// Leap of faith.
|
// Leap of faith.
|
||||||
trampoline(
|
trampoline(
|
||||||
@ -120,6 +125,17 @@ impl ProtectedCaller for Caller {
|
|||||||
);
|
);
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// the trampoline is called from C on windows
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
call_protected(
|
||||||
|
&self.handler_data,
|
||||||
|
trampoline,
|
||||||
|
vmctx_ptr,
|
||||||
|
func_ptr,
|
||||||
|
param_vec.as_ptr(),
|
||||||
|
return_vec.as_mut_ptr(),
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(return_vec
|
Ok(return_vec
|
||||||
.iter()
|
.iter()
|
||||||
.zip(signature.returns().iter())
|
.zip(signature.returns().iter())
|
||||||
@ -137,18 +153,18 @@ impl ProtectedCaller for Caller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_func_from_index(
|
fn get_func_from_index<'a>(
|
||||||
module: &ModuleInner,
|
module: &'a ModuleInner,
|
||||||
import_backing: &ImportBacking,
|
import_backing: &ImportBacking,
|
||||||
func_index: FuncIndex,
|
func_index: FuncIndex,
|
||||||
) -> (*const vm::Func, Context, Arc<FuncSig>, SigIndex) {
|
) -> (*const vm::Func, Context, &'a FuncSig, SigIndex) {
|
||||||
let sig_index = *module
|
let sig_index = *module
|
||||||
.info
|
.info
|
||||||
.func_assoc
|
.func_assoc
|
||||||
.get(func_index)
|
.get(func_index)
|
||||||
.expect("broken invariant, incorrect func index");
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.func_resolver
|
||||||
@ -167,7 +183,7 @@ fn get_func_from_index(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let signature = Arc::clone(&module.info.signatures[sig_index]);
|
let signature = &module.info.signatures[sig_index];
|
||||||
|
|
||||||
(func_ptr, ctx, signature, sig_index)
|
(func_ptr, ctx, signature, sig_index)
|
||||||
}
|
}
|
||||||
@ -175,15 +191,16 @@ fn get_func_from_index(
|
|||||||
unsafe impl Send for HandlerData {}
|
unsafe impl Send for HandlerData {}
|
||||||
unsafe impl Sync for HandlerData {}
|
unsafe impl Sync for HandlerData {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct HandlerData {
|
pub struct HandlerData {
|
||||||
pub trap_data: TrapSink,
|
pub trap_data: Arc<TrapSink>,
|
||||||
exec_buffer_ptr: *const c_void,
|
exec_buffer_ptr: *const c_void,
|
||||||
exec_buffer_size: usize,
|
exec_buffer_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HandlerData {
|
impl HandlerData {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
trap_data: TrapSink,
|
trap_data: Arc<TrapSink>,
|
||||||
exec_buffer_ptr: *const c_void,
|
exec_buffer_ptr: *const c_void,
|
||||||
exec_buffer_size: usize,
|
exec_buffer_size: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -18,11 +18,7 @@ use nix::sys::signal::{
|
|||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::{Cell, UnsafeCell};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
|
||||||
error::{RuntimeError, RuntimeResult},
|
|
||||||
structures::TypedIndex,
|
|
||||||
types::{MemoryIndex, TableIndex},
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" fn signal_trap_handler(
|
extern "C" fn signal_trap_handler(
|
||||||
signum: ::nix::libc::c_int,
|
signum: ::nix::libc::c_int,
|
||||||
@ -79,8 +75,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
|||||||
if signum != 0 {
|
if signum != 0 {
|
||||||
*jmp_buf = prev_jmp_buf;
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
|
||||||
if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||||
Err(RuntimeError::User { msg })
|
Err(RuntimeError::Panic { data })
|
||||||
} else {
|
} else {
|
||||||
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
|
||||||
|
|
||||||
@ -91,28 +87,28 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
|||||||
{
|
{
|
||||||
Err(match Signal::from_c_int(signum) {
|
Err(match Signal::from_c_int(signum) {
|
||||||
Ok(SIGILL) => match trapcode {
|
Ok(SIGILL) => match trapcode {
|
||||||
TrapCode::BadSignature => RuntimeError::IndirectCallSignature {
|
TrapCode::BadSignature => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "incorrect call_indirect signature".into(),
|
||||||
},
|
},
|
||||||
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull {
|
TrapCode::IndirectCallToNull => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "indirect call to null".into(),
|
||||||
},
|
},
|
||||||
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess {
|
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
|
||||||
memory: MemoryIndex::new(0),
|
msg: "memory out-of-bounds access".into(),
|
||||||
addr: None,
|
|
||||||
},
|
},
|
||||||
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds {
|
TrapCode::TableOutOfBounds => RuntimeError::Trap {
|
||||||
table: TableIndex::new(0),
|
msg: "table out-of-bounds access".into(),
|
||||||
},
|
},
|
||||||
_ => RuntimeError::Unknown {
|
_ => RuntimeError::Trap {
|
||||||
msg: "unknown trap".to_string(),
|
msg: "unknown trap".into(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess {
|
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap {
|
||||||
memory: MemoryIndex::new(0),
|
msg: "memory out-of-bounds access".into(),
|
||||||
addr: None,
|
},
|
||||||
|
Ok(SIGFPE) => RuntimeError::Trap {
|
||||||
|
msg: "illegal arithmetic operation".into(),
|
||||||
},
|
},
|
||||||
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
@ -126,8 +122,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
|
|||||||
_ => "unkown trapped signal",
|
_ => "unkown trapped signal",
|
||||||
};
|
};
|
||||||
// When the trap-handler is fully implemented, this will return more information.
|
// When the trap-handler is fully implemented, this will return more information.
|
||||||
Err(RuntimeError::Unknown {
|
Err(RuntimeError::Trap {
|
||||||
msg: format!("trap at {:p} - {}", faulting_addr, signal),
|
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,115 @@
|
|||||||
|
use crate::relocation::{TrapCode, TrapData};
|
||||||
use crate::signal::HandlerData;
|
use crate::signal::HandlerData;
|
||||||
use wasmer_runtime_core::error::RuntimeResult;
|
use crate::trampoline::Trampoline;
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::ptr;
|
||||||
|
use wasmer_runtime_core::vm::Ctx;
|
||||||
|
use wasmer_runtime_core::vm::Func;
|
||||||
|
use wasmer_runtime_core::{
|
||||||
|
error::{RuntimeError, RuntimeResult},
|
||||||
|
structures::TypedIndex,
|
||||||
|
types::{MemoryIndex, TableIndex},
|
||||||
|
};
|
||||||
|
use wasmer_win_exception_handler::CallProtectedData;
|
||||||
|
pub use wasmer_win_exception_handler::_call_protected;
|
||||||
|
use winapi::shared::minwindef::DWORD;
|
||||||
|
use winapi::um::minwinbase::{
|
||||||
|
EXCEPTION_ACCESS_VIOLATION, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
||||||
|
EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW,
|
||||||
|
EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_ILLEGAL_INSTRUCTION,
|
||||||
|
EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_STACK_OVERFLOW,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
|
thread_local! {
|
||||||
unimplemented!("TODO");
|
pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_protected(
|
||||||
|
handler_data: &HandlerData,
|
||||||
|
trampoline: Trampoline,
|
||||||
|
ctx: *mut Ctx,
|
||||||
|
func: *const Func,
|
||||||
|
param_vec: *const u64,
|
||||||
|
return_vec: *mut u64,
|
||||||
|
) -> RuntimeResult<()> {
|
||||||
|
// TODO: trap early
|
||||||
|
// user code error
|
||||||
|
// if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
|
||||||
|
// return Err(RuntimeError::User { msg });
|
||||||
|
// }
|
||||||
|
|
||||||
|
let result = _call_protected(trampoline, ctx, func, param_vec, return_vec);
|
||||||
|
|
||||||
|
if let Ok(_) = result {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let CallProtectedData {
|
||||||
|
code: signum,
|
||||||
|
exceptionAddress: exception_address,
|
||||||
|
instructionPointer: instruction_pointer,
|
||||||
|
} = result.unwrap_err();
|
||||||
|
|
||||||
|
if let Some(TrapData {
|
||||||
|
trapcode,
|
||||||
|
srcloc: _,
|
||||||
|
}) = handler_data.lookup(instruction_pointer as _)
|
||||||
|
{
|
||||||
|
Err(match signum as DWORD {
|
||||||
|
EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
|
||||||
|
msg: "memory out-of-bounds access".into(),
|
||||||
|
},
|
||||||
|
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
|
||||||
|
TrapCode::BadSignature => RuntimeError::Trap {
|
||||||
|
msg: "incorrect call_indirect signature".into(),
|
||||||
|
},
|
||||||
|
TrapCode::IndirectCallToNull => RuntimeError::Trap {
|
||||||
|
msg: "indirect call to null".into(),
|
||||||
|
},
|
||||||
|
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
|
||||||
|
msg: "memory out-of-bounds access".into(),
|
||||||
|
},
|
||||||
|
TrapCode::TableOutOfBounds => RuntimeError::Trap {
|
||||||
|
msg: "table out-of-bounds access".into(),
|
||||||
|
},
|
||||||
|
_ => RuntimeError::Trap {
|
||||||
|
msg: "unknown trap".into(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap {
|
||||||
|
msg: "stack overflow trap".into(),
|
||||||
|
},
|
||||||
|
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap {
|
||||||
|
msg: "illegal arithmetic operation".into(),
|
||||||
|
},
|
||||||
|
_ => RuntimeError::Trap {
|
||||||
|
msg: "unknown trap".into(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
} else {
|
||||||
|
let signal = match signum as DWORD {
|
||||||
|
EXCEPTION_FLT_DENORMAL_OPERAND
|
||||||
|
| EXCEPTION_FLT_DIVIDE_BY_ZERO
|
||||||
|
| EXCEPTION_FLT_INEXACT_RESULT
|
||||||
|
| EXCEPTION_FLT_INVALID_OPERATION
|
||||||
|
| EXCEPTION_FLT_OVERFLOW
|
||||||
|
| EXCEPTION_FLT_STACK_CHECK
|
||||||
|
| EXCEPTION_FLT_UNDERFLOW => "floating-point exception",
|
||||||
|
EXCEPTION_ILLEGAL_INSTRUCTION => "illegal instruction",
|
||||||
|
EXCEPTION_ACCESS_VIOLATION => "segmentation violation",
|
||||||
|
_ => "unkown trapped signal",
|
||||||
|
};
|
||||||
|
|
||||||
|
Err(RuntimeError::Trap {
|
||||||
|
msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn trigger_trap() -> ! {
|
pub unsafe fn trigger_trap() -> ! {
|
||||||
unimplemented!("TODO");
|
// TODO
|
||||||
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#[cfg(feature = "cache")]
|
|
||||||
use crate::cache::TrampolineCache;
|
use crate::cache::TrampolineCache;
|
||||||
use cranelift_codegen::{
|
use cranelift_codegen::{
|
||||||
binemit::{NullTrapSink, Reloc, RelocSink},
|
binemit::{NullTrapSink, Reloc, RelocSink},
|
||||||
@ -7,6 +6,7 @@ use cranelift_codegen::{
|
|||||||
isa, Context,
|
isa, Context,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use std::ffi::c_void;
|
||||||
use std::{iter, mem};
|
use std::{iter, mem};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::sys::{Memory, Protect},
|
backend::sys::{Memory, Protect},
|
||||||
@ -23,13 +23,15 @@ impl RelocSink for NullRelocSink {
|
|||||||
fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {}
|
fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Trampoline =
|
||||||
|
unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64) -> c_void;
|
||||||
|
|
||||||
pub struct Trampolines {
|
pub struct Trampolines {
|
||||||
memory: Memory,
|
memory: Memory,
|
||||||
offsets: HashMap<SigIndex, usize>,
|
offsets: HashMap<SigIndex, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trampolines {
|
impl Trampolines {
|
||||||
#[cfg(feature = "cache")]
|
|
||||||
pub fn from_trampoline_cache(cache: TrampolineCache) -> Self {
|
pub fn from_trampoline_cache(cache: TrampolineCache) -> Self {
|
||||||
// pub struct TrampolineCache {
|
// pub struct TrampolineCache {
|
||||||
// #[serde(with = "serde_bytes")]
|
// #[serde(with = "serde_bytes")]
|
||||||
@ -53,8 +55,7 @@ impl Trampolines {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
pub fn to_trampoline_cache(&self) -> TrampolineCache {
|
||||||
pub fn to_trampoline_cache(self) -> TrampolineCache {
|
|
||||||
let mut code = vec![0; self.memory.size()];
|
let mut code = vec![0; self.memory.size()];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -63,7 +64,7 @@ impl Trampolines {
|
|||||||
|
|
||||||
TrampolineCache {
|
TrampolineCache {
|
||||||
code,
|
code,
|
||||||
offsets: self.offsets,
|
offsets: self.offsets.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +139,7 @@ impl Trampolines {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(
|
pub fn lookup(&self, sig_index: SigIndex) -> Option<Trampoline> {
|
||||||
&self,
|
|
||||||
sig_index: SigIndex,
|
|
||||||
) -> Option<unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64)> {
|
|
||||||
let offset = *self.offsets.get(&sig_index)?;
|
let offset = *self.offsets.get(&sig_index)?;
|
||||||
let ptr = unsafe { self.memory.as_ptr().add(offset) };
|
let ptr = unsafe { self.memory.as_ptr().add(offset) };
|
||||||
|
|
||||||
@ -169,6 +167,7 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
|
|||||||
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(entry_ebb);
|
let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(entry_ebb);
|
||||||
|
|
||||||
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
|
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
|
||||||
|
args_vec.push(vmctx_ptr);
|
||||||
for (index, wasm_ty) in func_sig.params().iter().enumerate() {
|
for (index, wasm_ty) in func_sig.params().iter().enumerate() {
|
||||||
let mem_flags = ir::MemFlags::trusted();
|
let mem_flags = ir::MemFlags::trusted();
|
||||||
|
|
||||||
@ -180,7 +179,6 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function {
|
|||||||
);
|
);
|
||||||
args_vec.push(val);
|
args_vec.push(val);
|
||||||
}
|
}
|
||||||
args_vec.push(vmctx_ptr);
|
|
||||||
|
|
||||||
let call_inst = pos.ins().call_indirect(export_sig_ref, func_ptr, &args_vec);
|
let call_inst = pos.ins().call_indirect(export_sig_ref, func_ptr, &args_vec);
|
||||||
|
|
||||||
@ -212,7 +210,9 @@ fn wasm_ty_to_clif(ty: Type) -> ir::types::Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_trampoline_signature() -> ir::Signature {
|
fn generate_trampoline_signature() -> ir::Signature {
|
||||||
let mut sig = ir::Signature::new(isa::CallConv::SystemV);
|
let isa = super::get_isa();
|
||||||
|
let call_convention = isa.default_call_conv();
|
||||||
|
let mut sig = ir::Signature::new(call_convention);
|
||||||
|
|
||||||
let ptr_param = ir::AbiParam {
|
let ptr_param = ir::AbiParam {
|
||||||
value_type: ir::types::I64,
|
value_type: ir::types::I64,
|
||||||
@ -227,23 +227,24 @@ fn generate_trampoline_signature() -> ir::Signature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
|
fn generate_export_signature(func_sig: &FuncSig) -> ir::Signature {
|
||||||
let mut export_clif_sig = ir::Signature::new(isa::CallConv::SystemV);
|
let isa = super::get_isa();
|
||||||
|
let call_convention = isa.default_call_conv();
|
||||||
|
let mut export_clif_sig = ir::Signature::new(call_convention);
|
||||||
|
|
||||||
export_clif_sig.params = func_sig
|
let func_sig_iter = func_sig.params().iter().map(|wasm_ty| ir::AbiParam {
|
||||||
.params()
|
|
||||||
.iter()
|
|
||||||
.map(|wasm_ty| ir::AbiParam {
|
|
||||||
value_type: wasm_ty_to_clif(*wasm_ty),
|
value_type: wasm_ty_to_clif(*wasm_ty),
|
||||||
purpose: ir::ArgumentPurpose::Normal,
|
purpose: ir::ArgumentPurpose::Normal,
|
||||||
extension: ir::ArgumentExtension::None,
|
extension: ir::ArgumentExtension::None,
|
||||||
location: ir::ArgumentLoc::Unassigned,
|
location: ir::ArgumentLoc::Unassigned,
|
||||||
})
|
});
|
||||||
.chain(iter::once(ir::AbiParam {
|
|
||||||
|
export_clif_sig.params = iter::once(ir::AbiParam {
|
||||||
value_type: ir::types::I64,
|
value_type: ir::types::I64,
|
||||||
purpose: ir::ArgumentPurpose::VMContext,
|
purpose: ir::ArgumentPurpose::VMContext,
|
||||||
extension: ir::ArgumentExtension::None,
|
extension: ir::ArgumentExtension::None,
|
||||||
location: ir::ArgumentLoc::Unassigned,
|
location: ir::ArgumentLoc::Unassigned,
|
||||||
}))
|
})
|
||||||
|
.chain(func_sig_iter)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
export_clif_sig.returns = func_sig
|
export_clif_sig.returns = func_sig
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasmer-emscripten"
|
name = "wasmer-emscripten"
|
||||||
version = "0.1.0"
|
version = "0.2.1"
|
||||||
description = "Wasmer runtime emscripten implementation library"
|
description = "Wasmer runtime emscripten implementation library"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||||
@ -9,14 +9,25 @@ edition = "2018"
|
|||||||
build = "build/mod.rs"
|
build = "build/mod.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.0" }
|
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
|
||||||
libc = { git = "https://github.com/rust-lang/libc" }
|
lazy_static = "1.2.0"
|
||||||
|
libc = "0.2.49"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
time = "0.1.41"
|
time = "0.1.41"
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
rand = "0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasmer-clif-backend = { path = "../clif-backend", version = "0.1.0" }
|
wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" }
|
||||||
wabt = "0.7.2"
|
wabt = "0.7.2"
|
||||||
|
|
||||||
|
[target.'cfg(not(windows))'.dev-dependencies]
|
||||||
|
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.1.0" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
glob = "0.2.11"
|
glob = "0.2.11"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
clif = []
|
||||||
|
llvm = []
|
BIN
lib/emscripten/emtests/FS_exports.wasm
vendored
BIN
lib/emscripten/emtests/FS_exports.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/clock_gettime.wasm
vendored
BIN
lib/emscripten/emtests/clock_gettime.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/closebitcasts.wasm
vendored
BIN
lib/emscripten/emtests/closebitcasts.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/dyncall.wasm
vendored
BIN
lib/emscripten/emtests/dyncall.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/dyncall_specific.wasm
vendored
BIN
lib/emscripten/emtests/dyncall_specific.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/env.wasm
vendored
BIN
lib/emscripten/emtests/env.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/getValue_setValue.wasm
vendored
BIN
lib/emscripten/emtests/getValue_setValue.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/localtime.wasm
vendored
BIN
lib/emscripten/emtests/localtime.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/modularize_closure_pre.wasm
vendored
BIN
lib/emscripten/emtests/modularize_closure_pre.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/printf.wasm
vendored
BIN
lib/emscripten/emtests/printf.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/puts.wasm
vendored
BIN
lib/emscripten/emtests/puts.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/stackAlloc.wasm
vendored
BIN
lib/emscripten/emtests/stackAlloc.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/stack_overflow.wasm
vendored
BIN
lib/emscripten/emtests/stack_overflow.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_addr_of_stacked.wasm
vendored
BIN
lib/emscripten/emtests/test_addr_of_stacked.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_alloca.wasm
vendored
BIN
lib/emscripten/emtests/test_alloca.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_alloca_stack.wasm
vendored
BIN
lib/emscripten/emtests/test_alloca_stack.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_array2.wasm
vendored
BIN
lib/emscripten/emtests/test_array2.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_array2b.wasm
vendored
BIN
lib/emscripten/emtests/test_array2b.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_atoX.wasm
vendored
BIN
lib/emscripten/emtests/test_atoX.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_atomic.wasm
vendored
BIN
lib/emscripten/emtests/test_atomic.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_atomic_cxx.wasm
vendored
BIN
lib/emscripten/emtests/test_atomic_cxx.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_bsearch.wasm
vendored
BIN
lib/emscripten/emtests/test_bsearch.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_ccall.wasm
vendored
BIN
lib/emscripten/emtests/test_ccall.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_complex.wasm
vendored
BIN
lib/emscripten/emtests/test_complex.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_demangle_stacks.wasm
vendored
BIN
lib/emscripten/emtests/test_demangle_stacks.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_dlmalloc_partial_2.wasm
vendored
BIN
lib/emscripten/emtests/test_dlmalloc_partial_2.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_double_varargs.wasm
vendored
BIN
lib/emscripten/emtests/test_double_varargs.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_em_asm.wasm
vendored
BIN
lib/emscripten/emtests/test_em_asm.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_em_asm_2.wasm
vendored
BIN
lib/emscripten/emtests/test_em_asm_2.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_em_asm_signatures.wasm
vendored
BIN
lib/emscripten/emtests/test_em_asm_signatures.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_em_asm_unicode.wasm
vendored
BIN
lib/emscripten/emtests/test_em_asm_unicode.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_em_js.wasm
vendored
BIN
lib/emscripten/emtests/test_em_js.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_emscripten_api.wasm
vendored
BIN
lib/emscripten/emtests/test_emscripten_api.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_erf.wasm
vendored
BIN
lib/emscripten/emtests/test_erf.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_errar.wasm
vendored
BIN
lib/emscripten/emtests/test_errar.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_2.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_2.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_convert.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_convert.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_libcxx.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_libcxx.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_multi.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_multi.wasm
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_primary.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_primary.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_refcount.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_refcount.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_resume.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_resume.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_rethrow.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_rethrow.wasm
vendored
Binary file not shown.
Binary file not shown.
BIN
lib/emscripten/emtests/test_exceptions_std.wasm
vendored
BIN
lib/emscripten/emtests/test_exceptions_std.wasm
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
17
lib/emscripten/emtests/test_execvp.c
vendored
Normal file
17
lib/emscripten/emtests/test_execvp.c
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
char command[] = "touch";
|
||||||
|
char arg1[] = "foo.txt";
|
||||||
|
char* argv[3];
|
||||||
|
argv[0] = command;
|
||||||
|
argv[1] = arg1;
|
||||||
|
argv[2] = 0;
|
||||||
|
|
||||||
|
printf("_execvp\n");
|
||||||
|
int result = execvp(command, argv);
|
||||||
|
// should not return, and not print this message
|
||||||
|
printf("error");
|
||||||
|
return 0;
|
||||||
|
}
|
1
lib/emscripten/emtests/test_execvp.out
vendored
Normal file
1
lib/emscripten/emtests/test_execvp.out
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_execvp
|
BIN
lib/emscripten/emtests/test_execvp.wasm
vendored
Normal file
BIN
lib/emscripten/emtests/test_execvp.wasm
vendored
Normal file
Binary file not shown.
18
lib/emscripten/emtests/test_execvp_windows.c
vendored
Normal file
18
lib/emscripten/emtests/test_execvp_windows.c
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
char command[] = "C:\\Windows\\System32\\cmd.exe";
|
||||||
|
char arg1[] = "echo";
|
||||||
|
char arg2[] = "foo";
|
||||||
|
char* argv[4];
|
||||||
|
argv[0] = command;
|
||||||
|
argv[1] = arg1;
|
||||||
|
argv[2] = arg2;
|
||||||
|
argv[3] = 0;
|
||||||
|
printf("_execvp\n");
|
||||||
|
int result = execvp(command, argv);
|
||||||
|
// should not return, and not print this message
|
||||||
|
printf("error");
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
lib/emscripten/emtests/test_execvp_windows.wasm
vendored
Normal file
BIN
lib/emscripten/emtests/test_execvp_windows.wasm
vendored
Normal file
Binary file not shown.
BIN
lib/emscripten/emtests/test_fast_math.wasm
vendored
BIN
lib/emscripten/emtests/test_fast_math.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_flexarray_struct.wasm
vendored
BIN
lib/emscripten/emtests/test_flexarray_struct.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_float32_precise.wasm
vendored
BIN
lib/emscripten/emtests/test_float32_precise.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_float_builtins.wasm
vendored
BIN
lib/emscripten/emtests/test_float_builtins.wasm
vendored
Binary file not shown.
BIN
lib/emscripten/emtests/test_frexp.wasm
vendored
BIN
lib/emscripten/emtests/test_frexp.wasm
vendored
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user